##### Coverage Report - org.apache.turbine.services.BaseServiceBroker

Classes in this File | Line Coverage | Branch Coverage | Complexity
BaseServiceBroker |
72% | 124/170
79% | 57/72
| 3.8;3,8

1 |  |
     package org.apache.turbine.services;
2 |  |
3 |  |
     /*
4 |  |
      * Licensed to the Apache Software Foundation (ASF) under one
5 |  |
      * or more contributor license agreements.  See the NOTICE file
6 |  |
      * distributed with this work for additional information
7 |  |
      * regarding copyright ownership.  The ASF licenses this file
8 |  |
      * to you under the Apache License, Version 2.0 (the
9 |  |
      * "License"); you may not use this file except in compliance
10 |  |
      * with the License.  You may obtain a copy of the License at
11 |  |
      *
12 |  |
      *   http://www.apache.org/licenses/LICENSE-2.0
13 |  |
      *
14 |  |
      * Unless required by applicable law or agreed to in writing,
15 |  |
      * software distributed under the License is distributed on an
16 |  |
      * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 |  |
      * KIND, either express or implied.  See the License for the
18 |  |
      * specific language governing permissions and limitations
19 |  |
      * under the License.
20 |  |
      */
21 |  |
22 |  |
23 |  |
     import java.util.ArrayList;
24 |  |
     import java.util.Enumeration;
25 |  |
     import java.util.Hashtable;
26 |  |
     import java.util.Iterator;
27 |  |
     import java.util.LinkedHashMap;
28 |  |
     import java.util.LinkedHashSet;
29 |  |
     import java.util.Map;
30 |  |
     import java.util.Set;
31 |  |
32 |  |
     import org.apache.commons.configuration.Configuration;
33 |  |
     import org.apache.commons.lang.StringUtils;
34 |  |
     import org.apache.commons.logging.Log;
35 |  |
     import org.apache.commons.logging.LogFactory;
36 |  |
37 |  |
     /**
38 |  |
      * A generic implementation of a <code>ServiceBroker</code> which
39 |  |
      * provides:
40 |  |
      *
41 |  |
      * <ul>
42 |  |
      * <li>Maintaining service name to class name mapping, allowing
43 |  |
      * pluggable service implementations.</li>
44 |  |
      * <li>Providing <code>Services</code> with a configuration based on
45 |  |
      * system wide configuration mechanism.</li>
46 |  |
      * </ul>
47 |  |
      * <li>Integration of TurbineServiceProviders for looking up
48 |  |
      * non-local services
49 |  |
      * </ul>
50 |  |
      *
51 |  |
      * @author <a href="mailto:burton@apache.org">Kevin Burton</a>
52 |  |
      * @author <a href="mailto:krzewski@e-point.pl">Rafal Krzewski</a>
53 |  |
      * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
54 |  |
      * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
55 |  |
      * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
56 |  |
      * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
57 |  |
      * @version $Id: BaseServiceBroker.java 1706239 2015-10-01 13:18:35Z tv $
58 |  |
      */
59 |  |
     public abstract class BaseServiceBroker implements ServiceBroker
60 |  |
     {
61 |  |
         /**
62 |  |
          * Mapping of Service names to class names, keep order.
63 |  |
          */
64 | 32 |
         private final Map<String, Class<?>> mapping = new LinkedHashMap<String, Class<?>>();
65 |  |
66 |  |
         /**
67 |  |
          * A repository of Service instances.
68 |  |
          */
69 | 32 |
         private final Hashtable<String, Service> services = new Hashtable<String, Service>();
70 |  |
71 |  |
         /**
72 |  |
          * Configuration for the services broker.
73 |  |
          * The configuration should be set by the application
74 |  |
          * in which the services framework is running.
75 |  |
          */
76 |  |
         private Configuration configuration;
77 |  |
78 |  |
         /**
79 |  |
          * A prefix for <code>Service</code> properties in
80 |  |
          * TurbineResource.properties.
81 |  |
          */
82 |  |
         public static final String SERVICE_PREFIX = "services.";
83 |  |
84 |  |
         /**
85 |  |
          * A <code>Service</code> property determining its implementing
86 |  |
          * class name .
87 |  |
          */
88 |  |
         public static final String CLASSNAME_SUFFIX = ".classname";
89 |  |
90 |  |
         /**
91 |  |
          * These are objects that the parent application
92 |  |
          * can provide so that application specific
93 |  |
          * services have a mechanism to retrieve specialized
94 |  |
          * information. For example, in Turbine there are services
95 |  |
          * that require the RunData object: these services can
96 |  |
          * retrieve the RunData object that Turbine has placed
97 |  |
          * in the service manager. This alleviates us of
98 |  |
          * the requirement of having init(Object) all
99 |  |
          * together.
100 |  |
          */
101 | 32 |
         private final Hashtable<String, Object> serviceObjects = new Hashtable<String, Object>();
102 |  |
103 |  |
         /** Logging */
104 | 32 |
         private static Log log = LogFactory.getLog(BaseServiceBroker.class);
105 |  |
106 |  |
         /**
107 |  |
          * Application root path as set by the
108 |  |
          * parent application.
109 |  |
          */
110 |  |
         private String applicationRoot;
111 |  |
112 |  |
         /**
113 |  |
          * mapping from service names to instances of TurbineServiceProviders
114 |  |
          */
115 | 32 |
         private final Hashtable<String, Service> serviceProviderInstanceMap = new Hashtable<String, Service>();
116 |  |
117 |  |
         /**
118 |  |
          * Default constructor, protected as to only be usable by subclasses.
119 |  |
          *
120 |  |
          * This constructor does nothing.
121 |  |
          */
122 |  |
         protected BaseServiceBroker()
123 | 32 |
         {
124 |  |
             // nothing to do
125 | 32 |
         }
126 |  |
127 |  |
         /**
128 |  |
          * Set the configuration object for the services broker.
129 |  |
          * This is the configuration that contains information
130 |  |
          * about all services in the care of this service
131 |  |
          * manager.
132 |  |
          *
133 |  |
          * @param configuration Broker configuration.
134 |  |
          */
135 |  |
         public void setConfiguration(Configuration configuration)
136 |  |
         {
137 | 42 |
             this.configuration = configuration;
138 | 42 |
         }
139 |  |
140 |  |
         /**
141 |  |
          * Get the configuration for this service manager.
142 |  |
          *
143 |  |
          * @return Broker configuration.
144 |  |
          */
145 |  |
         public Configuration getConfiguration()
146 |  |
         {
147 | 0 |
             return configuration;
148 |  |
         }
149 |  |
150 |  |
         /**
151 |  |
          * Initialize this service manager.
152 |  |
          * @throws InitializationException if the initialization fails
153 |  |
          */
154 |  |
         public void init() throws InitializationException
155 |  |
         {
156 |  |
             // Check:
157 |  |
             //
158 |  |
             // 1. The configuration has been set.
159 |  |
             // 2. Make sure the application root has been set.
160 |  |
161 |  |
             // FIXME: Make some service framework exceptions to throw in
162 |  |
             // the event these requirements aren't satisfied.
163 |  |
164 |  |
             // Create the mapping between service names
165 |  |
             // and their classes.
166 | 42 |
             initMapping();
167 |  |
168 |  |
             // Start services that have their 'earlyInit'
169 |  |
             // property set to 'true'.
170 | 42 |
             initServices(false);
171 | 42 |
         }
172 |  |
173 |  |
         /**
174 |  |
          * Set an application specific service object
175 |  |
          * that can be used by application specific
176 |  |
          * services.
177 |  |
          *
178 |  |
          * @param name name of service object
179 |  |
          * @param value value of service object
180 |  |
          */
181 |  |
         public void setServiceObject(String name, Object value)
182 |  |
         {
183 | 0 |
             serviceObjects.put(name, value);
184 | 0 |
         }
185 |  |
186 |  |
         /**
187 |  |
          * Get an application specific service object.
188 |  |
          *
189 |  |
          * @param name the name of the service object
190 |  |
          * @return Object application specific service object
191 |  |
          */
192 |  |
         public Object getServiceObject(String name)
193 |  |
         {
194 | 0 |
             return serviceObjects.get(name);
195 |  |
         }
196 |  |
197 |  |
         /**
198 |  |
          * Check recursively if the given checkIfc interface is among the implemented
199 |  |
          * interfaces
200 |  |
          *
201 |  |
          * @param checkIfc interface to check for
202 |  |
          * @param interfaces interfaces to scan
203 |  |
          * @return true if the interface is implemented
204 |  |
          */
205 |  |
         private boolean checkForInterface(Class<?> checkIfc, Class<?>[] interfaces)
206 |  |
         {
207 | 2399 |
             for (Class<?> ifc : interfaces)
208 |  |
             {
209 | 1117 |
                 if (ifc == checkIfc)
210 |  |
                 {
211 | 32 |
                     return true;
212 |  |
                 }
213 |  |
214 | 1085 |
                 Class<?>[] subInterfaces = ifc.getInterfaces();
215 | 1085 |
                 if (checkForInterface(checkIfc, subInterfaces))
216 |  |
                 {
217 | 32 |
                     return true;
218 |  |
                 }
219 |  |
             }
220 |  |
221 | 1282 |
             return false;
222 |  |
         }
223 |  |
224 |  |
         /**
225 |  |
          * Creates a mapping between Service names and class names.
226 |  |
          *
227 |  |
          * The mapping is built according to settings present in
228 |  |
          * TurbineResources.properties.  The entries should have the
229 |  |
          * following form:
230 |  |
          *
231 |  |
          * <pre>
232 |  |
          * services.MyService.classname=com.mycompany.MyServiceImpl
233 |  |
          * services.MyOtherService.classname=com.mycompany.MyOtherServiceImpl
234 |  |
          * </pre>
235 |  |
          *
236 |  |
          * <br>
237 |  |
          *
238 |  |
          * Generic ServiceBroker provides no Services.
239 |  |
          * @throws InitializationException if a service class could not be found
240 |  |
          */
241 |  |
         protected void initMapping() throws InitializationException
242 |  |
         {
243 |  |
             // we need to temporarily store the earlyInit flags to avoid
244 |  |
             // ConcurrentModificationExceptions
245 | 42 |
             Map<String, String> earlyInitFlags = new LinkedHashMap<String, String>();
246 |  |
247 |  |
             /*
248 |  |
              * These keys returned in an order that corresponds
249 |  |
              * to the order the services are listed in
250 |  |
              * the TR.props.
251 |  |
              */
252 | 42 |
             for (Iterator<String> keys = configuration.getKeys(); keys.hasNext();)
253 |  |
             {
254 | 2873 |
                 String key = keys.next();
255 | 2873 |
                 String[] keyParts = StringUtils.split(key, ".");
256 |  |
257 | 2873 |
                 if ((keyParts.length == 3)
258 |  |
                         && (keyParts[0] + ".").equals(SERVICE_PREFIX)
259 |  |
                         && ("." + keyParts[2]).equals(CLASSNAME_SUFFIX))
260 |  |
                 {
261 | 331 |
                     String serviceKey = keyParts[1];
262 | 331 |
                     log.info("Added Mapping for Service: " + serviceKey);
263 |  |
264 | 331 |
                     if (!mapping.containsKey(serviceKey))
265 |  |
                     {
266 | 261 |
                         String className = configuration.getString(key);
267 |  |
                         try
268 |  |
                         {
269 | 261 |
                             Class<?> clazz = Class.forName(className);
270 | 261 |
                             mapping.put(serviceKey, clazz);
271 |  |
272 |  |
                             // detect TurbineServiceProviders
273 | 261 |
                             if (checkForInterface(TurbineServiceProvider.class, clazz.getInterfaces()))
274 |  |
                             {
275 | 32 |
                                 log.info("Found a TurbineServiceProvider: " + serviceKey + " - initializing it early");
276 | 32 |
                                 earlyInitFlags.put(SERVICE_PREFIX + serviceKey + ".earlyInit", "true");
277 |  |
                             }
278 |  |
                         }
279 |  |
                         // those two errors must be passed to the VM
280 | 0 |
                         catch (ThreadDeath t)
281 |  |
                         {
282 | 0 |
                             throw t;
283 |  |
                         }
284 | 0 |
                         catch (OutOfMemoryError t)
285 |  |
                         {
286 | 0 |
                             throw t;
287 |  |
                         }
288 | 0 |
                         catch (ClassNotFoundException e)
289 |  |
                         {
290 | 0 |
                             throw new InitializationException("Class " + className +
291 |  |
                                 " is unavailable. Check your jars and classes.", e);
292 |  |
                         }
293 | 0 |
                         catch (NoClassDefFoundError e)
294 |  |
                         {
295 | 0 |
                             throw new InitializationException("Class " + className +
296 |  |
                                 " is unavailable. Check your jars and classes.", e);
297 | 261 |
                         }
298 |  |
                     }
299 |  |
                 }
300 | 2873 |
             }
301 |  |
302 | 42 |
             for (Map.Entry<String, String> entry : earlyInitFlags.entrySet())
303 |  |
             {
304 | 32 |
                 configuration.setProperty(entry.getKey(), entry.getValue());
305 | 32 |
             }
306 | 42 |
         }
307 |  |
308 |  |
         /**
309 |  |
          * Determines whether a service is registered in the configured
310 |  |
          * <code>TurbineResources.properties</code>.
311 |  |
          *
312 |  |
          * @param serviceName The name of the service whose existence to check.
313 |  |
          * @return Registration predicate for the desired services.
314 |  |
          */
315 |  |
         @Override
316 |  |
         public boolean isRegistered(String serviceName)
317 |  |
         {
318 | 26 |
             return (services.get(serviceName) != null);
319 |  |
         }
320 |  |
321 |  |
         /**
322 |  |
          * Returns an Iterator over all known service names.
323 |  |
          *
324 |  |
          * @return An Iterator of service names.
325 |  |
          */
326 |  |
         public Iterator<String> getServiceNames()
327 |  |
         {
328 | 88 |
             return mapping.keySet().iterator();
329 |  |
         }
330 |  |
331 |  |
         /**
332 |  |
          * Returns an Iterator over all known service names beginning with
333 |  |
          * the provided prefix.
334 |  |
          *
335 |  |
          * @param prefix The prefix against which to test.
336 |  |
          * @return An Iterator of service names which match the prefix.
337 |  |
          */
338 |  |
         public Iterator<String> getServiceNames(String prefix)
339 |  |
         {
340 | 0 |
             Set<String> keys = new LinkedHashSet<String>(mapping.keySet());
341 | 0 |
             for(Iterator<String> key = keys.iterator(); key.hasNext();)
342 |  |
             {
343 | 0 |
                 if (!key.next().startsWith(prefix))
344 |  |
                 {
345 | 0 |
                     key.remove();
346 |  |
                 }
347 |  |
             }
348 |  |
349 | 0 |
             return keys.iterator();
350 |  |
         }
351 |  |
352 |  |
         /**
353 |  |
          * Performs early initialization of specified service.
354 |  |
          *
355 |  |
          * @param name The name of the service (generally the
356 |  |
          * <code>SERVICE_NAME</code> constant of the service's interface
357 |  |
          * definition).
358 |  |
          * @exception InitializationException Initialization of this
359 |  |
          * service was not successful.
360 |  |
          */
361 |  |
         @Override
362 |  |
         public synchronized void initService(String name)
363 |  |
                 throws InitializationException
364 |  |
         {
365 |  |
             // Calling getServiceInstance(name) assures that the Service
366 |  |
             // implementation has its name and broker reference set before
367 |  |
             // initialization.
368 | 112 |
             Service instance = getServiceInstance(name);
369 |  |
370 | 112 |
             if (!instance.getInit())
371 |  |
             {
372 |  |
                 // this call might result in an indirect recursion
373 | 86 |
                 instance.init();
374 |  |
             }
375 | 101 |
         }
376 |  |
377 |  |
         /**
378 |  |
          * Performs early initialization of all services.  Failed early
379 |  |
          * initialization of a Service may be non-fatal to the system,
380 |  |
          * thus any exceptions are logged and the initialization process
381 |  |
          * continues.
382 |  |
          */
383 |  |
         public void initServices()
384 |  |
         {
385 |  |
             try
386 |  |
             {
387 | 0 |
                 initServices(false);
388 |  |
             }
389 | 0 |
             catch (InstantiationException notThrown)
390 |  |
             {
391 | 0 |
                 log.debug("Caught non fatal exception", notThrown);
392 |  |
             }
393 | 0 |
             catch (InitializationException notThrown)
394 |  |
             {
395 | 0 |
                 log.debug("Caught non fatal exception", notThrown);
396 | 0 |
             }
397 | 0 |
         }
398 |  |
399 |  |
         /**
400 |  |
          * Performs early initialization of all services. You can decide
401 |  |
          * to handle failed initializations if you wish, but then
402 |  |
          * after one service fails, the other will not have the chance
403 |  |
          * to initialize.
404 |  |
          *
405 |  |
          * @param report <code>true</code> if you want exceptions thrown.
406 |  |
          * @throws InstantiationException if the service could not be instantiated
407 |  |
          * @throws InitializationException if the service could not be initialized
408 |  |
          */
409 |  |
         public void initServices(boolean report)
410 |  |
                 throws InstantiationException, InitializationException
411 |  |
         {
412 | 42 |
             if (report)
413 |  |
             {
414 |  |
                 // Throw exceptions
415 | 0 |
                 for (Iterator<String> names = getServiceNames(); names.hasNext();)
416 |  |
                 {
417 | 0 |
                     doInitService(names.next());
418 |  |
                 }
419 |  |
             }
420 |  |
             else
421 |  |
             {
422 |  |
                 // Eat exceptions
423 | 42 |
                 for (Iterator<String> names = getServiceNames(); names.hasNext();)
424 |  |
                 {
425 |  |
                     try
426 |  |
                     {
427 | 331 |
                         doInitService(names.next());
428 |  |
                     }
429 |  |
                             // In case of an exception, file an error message; the
430 |  |
                             // system may be still functional, though.
431 | 0 |
                     catch (InstantiationException e)
432 |  |
                     {
433 | 0 |
                         log.error(e);
434 |  |
                     }
435 | 11 |
                     catch (InitializationException e)
436 |  |
                     {
437 | 11 |
                         log.error(e);
438 | 331 |
                     }
439 |  |
                 }
440 |  |
             }
441 | 42 |
             log.info("Finished initializing all services!");
442 | 42 |
         }
443 |  |
444 |  |
         /**
445 |  |
          * Internal utility method for use in {@link #initServices(boolean)}
446 |  |
          * to prevent duplication of code.
447 |  |
          */
448 |  |
         private void doInitService(String name)
449 |  |
                 throws InstantiationException, InitializationException
450 |  |
         {
451 |  |
             // Only start up services that have their earlyInit flag set.
452 | 331 |
             if (getConfiguration(name).getBoolean("earlyInit", false))
453 |  |
             {
454 | 112 |
                 log.info("Start Initializing service (early): " + name);
455 | 112 |
                 initService(name);
456 | 101 |
                 log.info("Finish Initializing service (early): " + name);
457 |  |
             }
458 | 320 |
         }
459 |  |
460 |  |
         /**
461 |  |
          * Shuts down a <code>Service</code>, releasing resources
462 |  |
          * allocated by an <code>Service</code>, and returns it to its
463 |  |
          * initial (uninitialized) state.
464 |  |
          *
465 |  |
          * @param name The name of the <code>Service</code> to be
466 |  |
          * uninitialized.
467 |  |
          */
468 |  |
         @Override
469 |  |
         public synchronized void shutdownService(String name)
470 |  |
         {
471 |  |
             try
472 |  |
             {
473 | 368 |
                 Service service = getServiceInstance(name);
474 | 368 |
                 if (service != null && service.getInit())
475 |  |
                 {
476 | 264 |
                     service.shutdown();
477 |  |
478 | 264 |
                     if (service.getInit() && service instanceof BaseService)
479 |  |
                     {
480 |  |
                         // BaseService::shutdown() does this by default,
481 |  |
                         // but could've been overriden poorly.
482 | 16 |
                         ((BaseService) service).setInit(false);
483 |  |
                     }
484 |  |
                 }
485 |  |
             }
486 | 0 |
             catch (InstantiationException e)
487 |  |
             {
488 |  |
                 // Assuming harmless -- log the error and continue.
489 | 0 |
                 log.error("Shutdown of a nonexistent Service '"
490 |  |
                         + name + "' was requested", e);
491 | 368 |
             }
492 | 368 |
         }
493 |  |
494 |  |
         /**
495 |  |
          * Shuts down all Turbine services, releasing allocated resources and
496 |  |
          * returning them to their initial (uninitialized) state.
497 |  |
          */
498 |  |
         @Override
499 |  |
         public void shutdownServices()
500 |  |
         {
501 | 45 |
             log.info("Shutting down all services!");
502 |  |
503 | 45 |
             String serviceName = null;
504 |  |
505 |  |
             /*
506 |  |
              * Now we want to reverse the order of
507 |  |
              * this list. This functionality should be added to
508 |  |
              * the ExtendedProperties in the commons but
509 |  |
              * this will fix the problem for now.
510 |  |
              */
511 |  |
512 | 45 |
             ArrayList<String> reverseServicesList = new ArrayList<String>();
513 |  |
514 | 45 |
             for (Iterator<String> serviceNames = getServiceNames(); serviceNames.hasNext();)
515 |  |
             {
516 | 367 |
                 serviceName = serviceNames.next();
517 | 367 |
                 reverseServicesList.add(0, serviceName);
518 |  |
             }
519 |  |
520 | 45 |
             for (Iterator<String> serviceNames = reverseServicesList.iterator(); serviceNames.hasNext();)
521 |  |
             {
522 | 367 |
                 serviceName = serviceNames.next();
523 | 367 |
                 log.info("Shutting down service: " + serviceName);
524 | 367 |
                 shutdownService(serviceName);
525 |  |
             }
526 | 45 |
         }
527 |  |
528 |  |
         /**
529 |  |
          * Returns an instance of requested Service.
530 |  |
          *
531 |  |
          * @param name The name of the Service requested.
532 |  |
          * @return An instance of requested Service.
533 |  |
          * @exception InstantiationException if the service is unknown or
534 |  |
          * can't be initialized.
535 |  |
          */
536 |  |
         @Override
537 |  |
         public Object getService(String name) throws InstantiationException
538 |  |
         {
539 |  |
             Service service;
540 |  |
541 | 2494 |
             if (this.isLocalService(name))
542 |  |
             {
543 |  |
                     try
544 |  |
                     {
545 | 1977 |
                         service = getServiceInstance(name);
546 | 1977 |
                         if (!service.getInit())
547 |  |
                         {
548 | 182 |
                             synchronized (service.getClass())
549 |  |
                             {
550 | 182 |
                                 if (!service.getInit())
551 |  |
                                 {
552 | 182 |
                                     log.info("Start Initializing service (late): " + name);
553 | 182 |
                                     service.init();
554 | 181 |
                                     log.info("Finish Initializing service (late): " + name);
555 |  |
                                 }
556 | 181 |
                             }
557 |  |
                         }
558 | 1976 |
                         if (!service.getInit())
559 |  |
                         {
560 |  |
                             // this exception will be caught & rethrown by this very method.
561 |  |
                             // getInit() returning false indicates some initialization issue,
562 |  |
                             // which in turn prevents the InitableBroker from passing a
563 |  |
                             // reference to a working instance of the initable to the client.
564 | 0 |
                             throw new InitializationException(
565 |  |
                                     "init() failed to initialize service " + name);
566 |  |
                         }
567 | 1976 |
                         return service;
568 |  |
                     }
569 | 0 |
                     catch (InitializationException e)
570 |  |
                     {
571 | 0 |
                         throw new InstantiationException("Service " + name +
572 |  |
                                 " failed to initialize", e);
573 |  |
                     }
574 |  |
             }
575 | 517 |
             else if (this.isNonLocalService(name))
576 |  |
             {
577 | 505 |
                 return this.getNonLocalService(name);
578 |  |
             }
579 |  |
             else
580 |  |
             {
581 | 12 |
                 throw new InstantiationException(
582 |  |
                     "ServiceBroker: unknown service " + name
583 |  |
                     + " requested");
584 |  |
             }
585 |  |
         }
586 |  |
587 |  |
         /**
588 |  |
          * Retrieves an instance of a Service without triggering late
589 |  |
          * initialization.
590 |  |
          *
591 |  |
          * Early initialization of a Service can require access to Service
592 |  |
          * properties.  The Service must have its name and serviceBroker
593 |  |
          * set by then.  Therefore, before calling
594 |  |
          * Initable.initClass(Object), the class must be instantiated with
595 |  |
          * InitableBroker.getInitableInstance(), and
596 |  |
          * Service.setServiceBroker() and Service.setName() must be
597 |  |
          * called.  This calls for two - level accessing the Services
598 |  |
          * instances.
599 |  |
          *
600 |  |
          * @param name The name of the service requested.
601 |  |
          * @exception InstantiationException The service is unknown or
602 |  |
          * can't be initialized.
603 |  |
          */
604 |  |
         protected Service getServiceInstance(String name)
605 |  |
                 throws InstantiationException
606 |  |
         {
607 | 2457 |
             Service service = services.get(name);
608 |  |
609 | 2457 |
             if (service == null)
610 |  |
             {
611 | 261 |
                 if (!this.isLocalService(name))
612 |  |
                 {
613 | 0 |
                     throw new InstantiationException(
614 |  |
                             "ServiceBroker: unknown service " + name
615 |  |
                             + " requested");
616 |  |
                 }
617 |  |
618 |  |
                 try
619 |  |
                 {
620 | 261 |
                     Class<?> clazz = mapping.get(name);
621 |  |
622 |  |
                     try
623 |  |
                     {
624 | 261 |
                         service = (Service) clazz.newInstance();
625 |  |
626 |  |
                         // check if the newly created service is also a
627 |  |
                         // service provider - if so then remember it
628 | 261 |
                         if (service instanceof TurbineServiceProvider)
629 |  |
                         {
630 | 32 |
                             this.serviceProviderInstanceMap.put(name,service);
631 |  |
                         }
632 |  |
                     }
633 |  |
                     // those two errors must be passed to the VM
634 | 0 |
                     catch (ClassCastException e)
635 |  |
                     {
636 | 0 |
                         throw new InstantiationException("Class " + clazz +
637 |  |
                                 " doesn't implement the Service interface", e);
638 |  |
                     }
639 | 0 |
                     catch (ThreadDeath t)
640 |  |
                     {
641 | 0 |
                         throw t;
642 |  |
                     }
643 | 0 |
                     catch (OutOfMemoryError t)
644 |  |
                     {
645 | 0 |
                         throw t;
646 |  |
                     }
647 | 0 |
                     catch (Throwable t)
648 |  |
                     {
649 | 0 |
                         throw new InstantiationException("Failed to instantiate " + clazz, t);
650 | 261 |
                     }
651 |  |
                 }
652 | 0 |
                 catch (InstantiationException e)
653 |  |
                 {
654 | 0 |
                     throw new InstantiationException(
655 |  |
                             "Failed to instantiate service " + name, e);
656 | 261 |
                 }
657 | 261 |
                 service.setServiceBroker(this);
658 | 261 |
                 service.setName(name);
659 | 261 |
                 services.put(name, service);
660 |  |
             }
661 |  |
662 | 2457 |
             return service;
663 |  |
         }
664 |  |
665 |  |
         /**
666 |  |
          * Returns the configuration for the specified service.
667 |  |
          *
668 |  |
          * @param name The name of the service.
669 |  |
          * @return Configuration of requested Service.
670 |  |
          */
671 |  |
         @Override
672 |  |
         public Configuration getConfiguration(String name)
673 |  |
         {
674 | 521 |
             return configuration.subset(SERVICE_PREFIX + name);
675 |  |
         }
676 |  |
677 |  |
         /**
678 |  |
          * Set the application root.
679 |  |
          *
680 |  |
          * @param applicationRoot application root
681 |  |
          */
682 |  |
         public void setApplicationRoot(String applicationRoot)
683 |  |
         {
684 | 42 |
             this.applicationRoot = applicationRoot;
685 | 42 |
         }
686 |  |
687 |  |
         /**
688 |  |
          * Get the application root as set by
689 |  |
          * the parent application.
690 |  |
          *
691 |  |
          * @return String application root
692 |  |
          */
693 |  |
         public String getApplicationRoot()
694 |  |
         {
695 | 0 |
             return applicationRoot;
696 |  |
         }
697 |  |
698 |  |
         /**
699 |  |
          * Determines if the requested service is managed by this
700 |  |
          * ServiceBroker.
701 |  |
          *
702 |  |
          * @param name The name of the Service requested.
703 |  |
          * @return true if the service is managed by the this ServiceBroker
704 |  |
          */
705 |  |
         protected boolean isLocalService(String name)
706 |  |
         {
707 | 2755 |
             return this.mapping.containsKey(name);
708 |  |
         }
709 |  |
710 |  |
         /**
711 |  |
          * Determines if the requested service is managed by an initialized
712 |  |
          * TurbineServiceProvider. We use the service names to lookup
713 |  |
          * the TurbineServiceProvider to ensure that we get a fully
714 |  |
          * inititialized service.
715 |  |
          *
716 |  |
          * @param name The name of the Service requested.
717 |  |
          * @return true if the service is managed by a TurbineServiceProvider
718 |  |
          */
719 |  |
         protected boolean isNonLocalService(String name)
720 |  |
         {
721 | 517 |
             String serviceName = null;
722 | 517 |
             TurbineServiceProvider turbineServiceProvider = null;
723 | 517 |
             Enumeration<String> list = this.serviceProviderInstanceMap.keys();
724 |  |
725 | 529 |
             while (list.hasMoreElements())
726 |  |
             {
727 | 517 |
                 serviceName = list.nextElement();
728 | 517 |
                 turbineServiceProvider = (TurbineServiceProvider) this.getService(serviceName);
729 |  |
730 | 517 |
                 if (turbineServiceProvider.exists(name))
731 |  |
                 {
732 | 505 |
                     return true;
733 |  |
                 }
734 |  |
             }
735 |  |
736 | 12 |
             return false;
737 |  |
         }
738 |  |
739 |  |
         /**
740 |  |
          * Get a non-local service managed by a TurbineServiceProvider.
741 |  |
          *
742 |  |
          * @param name The name of the Service requested.
743 |  |
          * @return the requested service
744 |  |
          * @throws InstantiationException the service couldn't be instantiated
745 |  |
          */
746 |  |
         protected Object getNonLocalService(String name)
747 |  |
                 throws InstantiationException
748 |  |
         {
749 | 505 |
             String serviceName = null;
750 | 505 |
             TurbineServiceProvider turbineServiceProvider = null;
751 | 505 |
             Enumeration<String> list = this.serviceProviderInstanceMap.keys();
752 |  |
753 | 505 |
             while (list.hasMoreElements())
754 |  |
             {
755 | 505 |
                 serviceName = list.nextElement();
756 | 505 |
                 turbineServiceProvider = (TurbineServiceProvider) this.getService(serviceName);
757 |  |
758 | 505 |
                 if (turbineServiceProvider.exists(name))
759 |  |
                 {
760 | 505 |
                     return turbineServiceProvider.get(name);
761 |  |
                 }
762 |  |
             }
763 |  |
764 | 0 |
             throw new InstantiationException(
765 |  |
                 "ServiceBroker: unknown non-local service " + name
766 |  |
                 + " requested");
767 |  |
         }
768 |  |
     }