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