1 package org.apache.turbine.services;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import java.util.ArrayList;
24 import java.util.Iterator;
25 import java.util.LinkedHashMap;
26 import java.util.LinkedHashSet;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.concurrent.ConcurrentHashMap;
30 import java.util.concurrent.locks.ReentrantLock;
31
32 import org.apache.commons.configuration2.Configuration;
33 import org.apache.commons.lang3.StringUtils;
34 import org.apache.logging.log4j.LogManager;
35 import org.apache.logging.log4j.Logger;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public abstract class BaseServiceBroker implements ServiceBroker
59 {
60
61
62
63 private final Map<String, Class<?>> mapping = new LinkedHashMap<>();
64
65
66
67
68 private final ConcurrentHashMap<String, Service> services = new ConcurrentHashMap<>();
69
70
71
72
73 private final ReentrantLock serviceLock = new ReentrantLock();
74
75
76
77
78
79
80 private Configuration configuration;
81
82
83
84
85
86 public static final String SERVICE_PREFIX = "services.";
87
88
89
90
91
92 public static final String CLASSNAME_SUFFIX = ".classname";
93
94
95
96
97
98
99
100
101
102
103
104
105 private final ConcurrentHashMap<String, Object> serviceObjects = new ConcurrentHashMap<>();
106
107
108 private static final Logger log = LogManager.getLogger(BaseServiceBroker.class);
109
110
111
112
113
114 private String applicationRoot;
115
116
117
118
119 private final ConcurrentHashMap<String, Service> serviceProviderInstanceMap = new ConcurrentHashMap<>();
120
121
122
123
124
125
126 protected BaseServiceBroker()
127 {
128
129 }
130
131
132
133
134
135
136
137
138
139 public void setConfiguration(Configuration configuration)
140 {
141 this.configuration = configuration;
142 }
143
144
145
146
147
148
149 public Configuration getConfiguration()
150 {
151 return configuration;
152 }
153
154
155
156
157
158 public void init() throws InitializationException
159 {
160
161
162
163
164
165
166
167
168
169
170 initMapping();
171
172
173
174 initServices(false);
175 }
176
177
178
179
180
181
182
183
184
185 public void setServiceObject(String name, Object value)
186 {
187 serviceObjects.put(name, value);
188 }
189
190
191
192
193
194
195
196 public Object getServiceObject(String name)
197 {
198 return serviceObjects.get(name);
199 }
200
201
202
203
204
205
206
207
208
209 private boolean checkForInterface(Class<?> checkIfc, Class<?>[] interfaces)
210 {
211 for (Class<?> ifc : interfaces)
212 {
213 if (ifc == checkIfc)
214 {
215 return true;
216 }
217
218 Class<?>[] subInterfaces = ifc.getInterfaces();
219 if (checkForInterface(checkIfc, subInterfaces))
220 {
221 return true;
222 }
223 }
224
225 return false;
226 }
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245 protected void initMapping() throws InitializationException
246 {
247
248
249 Map<String, String> earlyInitFlags = new LinkedHashMap<>();
250
251
252
253
254
255
256 for (Iterator<String> keys = configuration.getKeys(); keys.hasNext();)
257 {
258 String key = keys.next();
259 String[] keyParts = StringUtils.split(key, ".");
260
261 if (keyParts.length == 3
262 && (keyParts[0] + ".").equals(SERVICE_PREFIX)
263 && ("." + keyParts[2]).equals(CLASSNAME_SUFFIX))
264 {
265 String serviceKey = keyParts[1];
266 log.info("Added Mapping for Service: {}", serviceKey);
267
268 if (!mapping.containsKey(serviceKey))
269 {
270 String className = configuration.getString(key);
271 try
272 {
273 Class<?> clazz = Class.forName(className);
274 mapping.put(serviceKey, clazz);
275
276
277 if (checkForInterface(TurbineServiceProvider.class, clazz.getInterfaces()))
278 {
279 log.info("Found a TurbineServiceProvider: {} - initializing it early", serviceKey);
280 earlyInitFlags.put(SERVICE_PREFIX + serviceKey + ".earlyInit", "true");
281 }
282 }
283
284 catch (ThreadDeath t)
285 {
286 throw t;
287 }
288 catch (OutOfMemoryError t)
289 {
290 throw t;
291 }
292 catch (ClassNotFoundException | NoClassDefFoundError e)
293 {
294 throw new InitializationException("Class " + className +
295 " is unavailable. Check your jars and classes.", e);
296 }
297 }
298 }
299 }
300
301 for (Map.Entry<String, String> entry : earlyInitFlags.entrySet())
302 {
303 configuration.setProperty(entry.getKey(), entry.getValue());
304 }
305 }
306
307
308
309
310
311
312
313
314 @Override
315 public boolean isRegistered(String serviceName)
316 {
317 return (services.get(serviceName) != null);
318 }
319
320
321
322
323
324
325 public Iterator<String> getServiceNames()
326 {
327 return mapping.keySet().iterator();
328 }
329
330
331
332
333
334
335
336
337 public Iterator<String> getServiceNames(String prefix)
338 {
339 Set<String> keys = new LinkedHashSet<>(mapping.keySet());
340
341 keys.removeIf(key -> !key.startsWith(prefix));
342
343 return keys.iterator();
344 }
345
346
347
348
349
350
351
352
353
354
355 @Override
356 public synchronized void initService(String name)
357 throws InitializationException
358 {
359
360
361
362 Service instance = getServiceInstance(name);
363
364 if (!instance.getInit())
365 {
366
367 instance.init();
368 }
369 }
370
371
372
373
374
375
376
377 public void initServices()
378 {
379 try
380 {
381 initServices(false);
382 }
383 catch (InstantiationException | InitializationException notThrown)
384 {
385 log.debug("Caught non fatal exception", notThrown);
386 }
387 }
388
389
390
391
392
393
394
395
396
397
398
399 public void initServices(boolean report)
400 throws InstantiationException, InitializationException
401 {
402 if (report)
403 {
404
405 for (Iterator<String> names = getServiceNames(); names.hasNext();)
406 {
407 doInitService(names.next());
408 }
409 }
410 else
411 {
412
413 for (Iterator<String> names = getServiceNames(); names.hasNext();)
414 {
415 try
416 {
417 doInitService(names.next());
418 }
419
420
421 catch (InstantiationException | InitializationException e)
422 {
423 log.error(e);
424 }
425 }
426 }
427 log.info("Finished initializing all services!");
428 }
429
430
431
432
433
434 private void doInitService(String name)
435 throws InstantiationException, InitializationException
436 {
437
438 if (getConfiguration(name).getBoolean("earlyInit", false))
439 {
440 log.info("Start Initializing service (early): {}", name);
441 initService(name);
442 log.info("Finish Initializing service (early): {}", name);
443 }
444 }
445
446
447
448
449
450
451
452
453
454 @Override
455 public synchronized void shutdownService(String name)
456 {
457 try
458 {
459 Service service = getServiceInstance(name);
460 if (service != null && service.getInit())
461 {
462 service.shutdown();
463
464 if (service.getInit() && service instanceof BaseService)
465 {
466
467
468 ((BaseService) service).setInit(false);
469 }
470 }
471 }
472 catch (InstantiationException e)
473 {
474
475 log.error("Shutdown of a nonexistent Service '"
476 + name + "' was requested", e);
477 }
478 }
479
480
481
482
483
484 @Override
485 public void shutdownServices()
486 {
487 log.info("Shutting down all services!");
488
489 String serviceName = null;
490
491
492
493
494
495
496
497
498 ArrayList<String> reverseServicesList = new ArrayList<>();
499
500 for (Iterator<String> serviceNames = getServiceNames(); serviceNames.hasNext();)
501 {
502 serviceName = serviceNames.next();
503 reverseServicesList.add(0, serviceName);
504 }
505
506 for (String s : reverseServicesList)
507 {
508 serviceName = s;
509 log.info("Shutting down service: {}", serviceName);
510 shutdownService(serviceName);
511 }
512 }
513
514
515
516
517
518
519
520
521
522 @Override
523 public Object getService(String name) throws InstantiationException
524 {
525 Service service;
526
527 if (this.isLocalService(name))
528 {
529 try
530 {
531 service = getServiceInstance(name);
532 if (!service.getInit())
533 {
534 synchronized (service.getClass())
535 {
536 if (!service.getInit())
537 {
538 log.info("Start Initializing service (late): {}", name);
539 service.init();
540 log.info("Finish Initializing service (late): {}", name);
541 }
542 }
543 }
544 if (!service.getInit())
545 {
546
547
548
549
550 throw new InitializationException(
551 "init() failed to initialize service " + name);
552 }
553 return service;
554 }
555 catch (InitializationException e)
556 {
557 throw new InstantiationException("Service " + name +
558 " failed to initialize", e);
559 }
560 }
561 else if (this.isNonLocalService(name))
562 {
563 return this.getNonLocalService(name);
564 }
565 else
566 {
567 throw new InstantiationException(
568 "ServiceBroker: unknown service " + name
569 + " requested");
570 }
571 }
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593 protected Service getServiceInstance(String name)
594 throws InstantiationException
595 {
596 Service service = services.get(name);
597
598 if (service == null)
599 {
600 serviceLock.lock();
601
602 try
603 {
604
605 service = services.get(name);
606
607 if (service == null)
608 {
609 if (!this.isLocalService(name))
610 {
611 throw new InstantiationException(
612 "ServiceBroker: unknown service " + name
613 + " requested");
614 }
615
616 try
617 {
618 Class<?> clazz = mapping.get(name);
619
620 try
621 {
622 service = (Service) clazz.getDeclaredConstructor().newInstance();
623
624
625
626 if (service instanceof TurbineServiceProvider)
627 {
628 Service _service = this.serviceProviderInstanceMap.putIfAbsent(name,service);
629 if (_service != null)
630 {
631 service = _service;
632 }
633 }
634 }
635
636 catch (ClassCastException e)
637 {
638 throw new InstantiationException("Class " + clazz +
639 " doesn't implement the Service interface", e);
640 }
641 catch (ThreadDeath | OutOfMemoryError t)
642 {
643 throw t;
644 }
645 catch (Throwable t)
646 {
647 throw new InstantiationException("Failed to instantiate " + clazz, t);
648 }
649 }
650 catch (InstantiationException e)
651 {
652 throw new InstantiationException(
653 "Failed to instantiate service " + name, e);
654 }
655 service.setServiceBroker(this);
656 service.setName(name);
657 Service _service = services.putIfAbsent(name, service);
658 if (_service != null)
659 {
660 service = _service;
661 }
662 }
663 }
664 finally
665 {
666 serviceLock.unlock();
667 }
668 }
669
670 return service;
671 }
672
673
674
675
676
677
678
679 @Override
680 public Configuration getConfiguration(String name)
681 {
682 return configuration.subset(SERVICE_PREFIX + name);
683 }
684
685
686
687
688
689
690 public void setApplicationRoot(String applicationRoot)
691 {
692 this.applicationRoot = applicationRoot;
693 }
694
695
696
697
698
699
700
701 @Override
702 public String getApplicationRoot()
703 {
704 return applicationRoot;
705 }
706
707
708
709
710
711
712
713
714 protected boolean isLocalService(String name)
715 {
716 return this.mapping.containsKey(name);
717 }
718
719
720
721
722
723
724
725
726
727
728 protected boolean isNonLocalService(String name)
729 {
730 TurbineServiceProvider turbineServiceProvider = null;
731
732 for (Map.Entry<String, Service> entry : this.serviceProviderInstanceMap.entrySet())
733 {
734 turbineServiceProvider = (TurbineServiceProvider) this.getService(entry.getKey());
735
736 if (turbineServiceProvider.exists(name))
737 {
738 return true;
739 }
740 }
741
742 return false;
743 }
744
745
746
747
748
749
750
751
752 protected Object getNonLocalService(String name)
753 throws InstantiationException
754 {
755 TurbineServiceProvider turbineServiceProvider = null;
756
757 for (Map.Entry<String, Service> entry : this.serviceProviderInstanceMap.entrySet())
758 {
759 turbineServiceProvider = (TurbineServiceProvider) this.getService(entry.getKey());
760
761 if (turbineServiceProvider.exists(name))
762 {
763 return turbineServiceProvider.get(name);
764 }
765 }
766
767 throw new InstantiationException(
768 "ServiceBroker: unknown non-local service " + name
769 + " requested");
770 }
771 }