Coverage Report - org.apache.turbine.services.BaseServiceBroker
 
Classes in this File Line Coverage Branch Coverage Complexity
BaseServiceBroker
75%
130/172
76%
60/78
3,76
 
 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.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  
  * 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 1854787 2019-03-04 18:30:25Z tv $
 57  
  */
 58  
 public abstract class BaseServiceBroker implements ServiceBroker
 59  
 {
 60  
     /**
 61  
      * Mapping of Service names to class names, keep order.
 62  
      */
 63  105
     private final Map<String, Class<?>> mapping = new LinkedHashMap<String, Class<?>>();
 64  
 
 65  
     /**
 66  
      * A repository of Service instances.
 67  
      */
 68  105
     private final ConcurrentHashMap<String, Service> services = new ConcurrentHashMap<String, Service>();
 69  
 
 70  
     /**
 71  
      * Lock access during service initialization
 72  
      */
 73  105
     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  105
     private final ConcurrentHashMap<String, Object> serviceObjects = new ConcurrentHashMap<String, Object>();
 106  
 
 107  
     /** Logging */
 108  105
     private static final Logger log = LogManager.getLogger(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  105
     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  105
     {
 128  
         // nothing to do
 129  105
     }
 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  138
         this.configuration = configuration;
 142  138
     }
 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  138
         initMapping();
 171  
 
 172  
         // Start services that have their 'earlyInit'
 173  
         // property set to 'true'.
 174  138
         initServices(false);
 175  138
     }
 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  6687
         for (Class<?> ifc : interfaces)
 212  
         {
 213  3051
             if (ifc == checkIfc)
 214  
             {
 215  105
                 return true;
 216  
             }
 217  
 
 218  2946
             Class<?>[] subInterfaces = ifc.getInterfaces();
 219  2946
             if (checkForInterface(checkIfc, subInterfaces))
 220  
             {
 221  105
                 return true;
 222  
             }
 223  
         }
 224  
 
 225  3636
         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  138
         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  138
         for (Iterator<String> keys = configuration.getKeys(); keys.hasNext();)
 257  
         {
 258  9813
             String key = keys.next();
 259  9813
             String[] keyParts = StringUtils.split(key, ".");
 260  
 
 261  9813
             if (keyParts.length == 3
 262  4812
                     && (keyParts[0] + ".").equals(SERVICE_PREFIX)
 263  2739
                     && ("." + keyParts[2]).equals(CLASSNAME_SUFFIX))
 264  
             {
 265  1128
                 String serviceKey = keyParts[1];
 266  1128
                 log.info("Added Mapping for Service: {}", serviceKey);
 267  
 
 268  1128
                 if (!mapping.containsKey(serviceKey))
 269  
                 {
 270  900
                     String className = configuration.getString(key);
 271  
                     try
 272  
                     {
 273  900
                         Class<?> clazz = Class.forName(className);
 274  900
                         mapping.put(serviceKey, clazz);
 275  
 
 276  
                         // detect TurbineServiceProviders
 277  900
                         if (checkForInterface(TurbineServiceProvider.class, clazz.getInterfaces()))
 278  
                         {
 279  105
                             log.info("Found a TurbineServiceProvider: {} - initializing it early", serviceKey);
 280  105
                             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 | NoClassDefFoundError e)
 293  
                     {
 294  0
                         throw new InitializationException("Class " + className +
 295  
                             " is unavailable. Check your jars and classes.", e);
 296  900
                     }
 297  
                 }
 298  
             }
 299  9813
         }
 300  
 
 301  138
         for (Map.Entry<String, String> entry : earlyInitFlags.entrySet())
 302  
         {
 303  105
             configuration.setProperty(entry.getKey(), entry.getValue());
 304  105
         }
 305  138
     }
 306  
 
 307  
     /**
 308  
      * Determines whether a service is registered in the configured
 309  
      * <code>TurbineResources.properties</code>.
 310  
      *
 311  
      * @param serviceName The name of the service whose existence to check.
 312  
      * @return Registration predicate for the desired services.
 313  
      */
 314  
     @Override
 315  
     public boolean isRegistered(String serviceName)
 316  
     {
 317  87
         return (services.get(serviceName) != null);
 318  
     }
 319  
 
 320  
     /**
 321  
      * Returns an Iterator over all known service names.
 322  
      *
 323  
      * @return An Iterator of service names.
 324  
      */
 325  
     public Iterator<String> getServiceNames()
 326  
     {
 327  300
         return mapping.keySet().iterator();
 328  
     }
 329  
 
 330  
     /**
 331  
      * Returns an Iterator over all known service names beginning with
 332  
      * the provided prefix.
 333  
      *
 334  
      * @param prefix The prefix against which to test.
 335  
      * @return An Iterator of service names which match the prefix.
 336  
      */
 337  
     public Iterator<String> getServiceNames(String prefix)
 338  
     {
 339  0
         Set<String> keys = new LinkedHashSet<String>(mapping.keySet());
 340  0
         for(Iterator<String> key = keys.iterator(); key.hasNext();)
 341  
         {
 342  0
             if (!key.next().startsWith(prefix))
 343  
             {
 344  0
                 key.remove();
 345  
             }
 346  
         }
 347  
 
 348  0
         return keys.iterator();
 349  
     }
 350  
 
 351  
     /**
 352  
      * Performs early initialization of specified service.
 353  
      *
 354  
      * @param name The name of the service (generally the
 355  
      * <code>SERVICE_NAME</code> constant of the service's interface
 356  
      * definition).
 357  
      * @throws InitializationException Initialization of this
 358  
      * service was not successful.
 359  
      */
 360  
     @Override
 361  
     public synchronized void initService(String name)
 362  
             throws InitializationException
 363  
     {
 364  
         // Calling getServiceInstance(name) assures that the Service
 365  
         // implementation has its name and broker reference set before
 366  
         // initialization.
 367  363
         Service instance = getServiceInstance(name);
 368  
 
 369  363
         if (!instance.getInit())
 370  
         {
 371  
             // this call might result in an indirect recursion
 372  276
             instance.init();
 373  
         }
 374  330
     }
 375  
 
 376  
     /**
 377  
      * Performs early initialization of all services.  Failed early
 378  
      * initialization of a Service may be non-fatal to the system,
 379  
      * thus any exceptions are logged and the initialization process
 380  
      * continues.
 381  
      */
 382  
     public void initServices()
 383  
     {
 384  
         try
 385  
         {
 386  0
             initServices(false);
 387  
         }
 388  0
         catch (InstantiationException | InitializationException notThrown)
 389  
         {
 390  0
             log.debug("Caught non fatal exception", notThrown);
 391  0
         }
 392  0
     }
 393  
 
 394  
     /**
 395  
      * Performs early initialization of all services. You can decide
 396  
      * to handle failed initializations if you wish, but then
 397  
      * after one service fails, the other will not have the chance
 398  
      * to initialize.
 399  
      *
 400  
      * @param report <code>true</code> if you want exceptions thrown.
 401  
      * @throws InstantiationException if the service could not be instantiated
 402  
      * @throws InitializationException if the service could not be initialized
 403  
      */
 404  
     public void initServices(boolean report)
 405  
             throws InstantiationException, InitializationException
 406  
     {
 407  138
         if (report)
 408  
         {
 409  
             // Throw exceptions
 410  0
             for (Iterator<String> names = getServiceNames(); names.hasNext();)
 411  
             {
 412  0
                 doInitService(names.next());
 413  
             }
 414  
         }
 415  
         else
 416  
         {
 417  
             // Eat exceptions
 418  138
             for (Iterator<String> names = getServiceNames(); names.hasNext();)
 419  
             {
 420  
                 try
 421  
                 {
 422  1149
                     doInitService(names.next());
 423  
                 }
 424  
                         // In case of an exception, file an error message; the
 425  
                         // system may be still functional, though.
 426  33
                 catch (InstantiationException | InitializationException e)
 427  
                 {
 428  33
                     log.error(e);
 429  1149
                 }
 430  
             }
 431  
         }
 432  138
         log.info("Finished initializing all services!");
 433  138
     }
 434  
 
 435  
     /**
 436  
      * Internal utility method for use in {@link #initServices(boolean)}
 437  
      * to prevent duplication of code.
 438  
      */
 439  
     private void doInitService(String name)
 440  
             throws InstantiationException, InitializationException
 441  
     {
 442  
         // Only start up services that have their earlyInit flag set.
 443  1149
         if (getConfiguration(name).getBoolean("earlyInit", false))
 444  
         {
 445  363
             log.info("Start Initializing service (early): {}", name);
 446  363
             initService(name);
 447  330
             log.info("Finish Initializing service (early): {}", name);
 448  
         }
 449  1116
     }
 450  
 
 451  
     /**
 452  
      * Shuts down a <code>Service</code>, releasing resources
 453  
      * allocated by an <code>Service</code>, and returns it to its
 454  
      * initial (uninitialized) state.
 455  
      *
 456  
      * @param name The name of the <code>Service</code> to be
 457  
      * uninitialized.
 458  
      */
 459  
     @Override
 460  
     public synchronized void shutdownService(String name)
 461  
     {
 462  
         try
 463  
         {
 464  1347
             Service service = getServiceInstance(name);
 465  1347
             if (service != null && service.getInit())
 466  
             {
 467  987
                 service.shutdown();
 468  
 
 469  987
                 if (service.getInit() && service instanceof BaseService)
 470  
                 {
 471  
                     // BaseService::shutdown() does this by default,
 472  
                     // but could've been overriden poorly.
 473  48
                     ((BaseService) service).setInit(false);
 474  
                 }
 475  
             }
 476  
         }
 477  0
         catch (InstantiationException e)
 478  
         {
 479  
             // Assuming harmless -- log the error and continue.
 480  0
             log.error("Shutdown of a nonexistent Service '"
 481  
                     + name + "' was requested", e);
 482  1347
         }
 483  1347
     }
 484  
 
 485  
     /**
 486  
      * Shuts down all Turbine services, releasing allocated resources and
 487  
      * returning them to their initial (uninitialized) state.
 488  
      */
 489  
     @Override
 490  
     public void shutdownServices()
 491  
     {
 492  159
         log.info("Shutting down all services!");
 493  
 
 494  159
         String serviceName = null;
 495  
 
 496  
         /*
 497  
          * Now we want to reverse the order of
 498  
          * this list. This functionality should be added to
 499  
          * the ExtendedProperties in the commons but
 500  
          * this will fix the problem for now.
 501  
          */
 502  
 
 503  159
         ArrayList<String> reverseServicesList = new ArrayList<String>();
 504  
 
 505  159
         for (Iterator<String> serviceNames = getServiceNames(); serviceNames.hasNext();)
 506  
         {
 507  1341
             serviceName = serviceNames.next();
 508  1341
             reverseServicesList.add(0, serviceName);
 509  
         }
 510  
 
 511  159
         for (Iterator<String> serviceNames = reverseServicesList.iterator(); serviceNames.hasNext();)
 512  
         {
 513  1341
             serviceName = serviceNames.next();
 514  1341
             log.info("Shutting down service: {}", serviceName);
 515  1341
             shutdownService(serviceName);
 516  
         }
 517  159
     }
 518  
 
 519  
     /**
 520  
      * Returns an instance of requested Service.
 521  
      *
 522  
      * @param name The name of the Service requested.
 523  
      * @return An instance of requested Service.
 524  
      * @throws InstantiationException if the service is unknown or
 525  
      * can't be initialized.
 526  
      */
 527  
     @Override
 528  
     public Object getService(String name) throws InstantiationException
 529  
     {
 530  
         Service service;
 531  
 
 532  8043
         if (this.isLocalService(name))
 533  
         {
 534  
                 try
 535  
                 {
 536  6351
                     service = getServiceInstance(name);
 537  6351
                     if (!service.getInit())
 538  
                     {
 539  720
                         synchronized (service.getClass())
 540  
                         {
 541  720
                             if (!service.getInit())
 542  
                             {
 543  720
                                 log.info("Start Initializing service (late): {}", name);
 544  720
                                 service.init();
 545  720
                                 log.info("Finish Initializing service (late): {}", name);
 546  
                             }
 547  720
                         }
 548  
                     }
 549  6351
                     if (!service.getInit())
 550  
                     {
 551  
                         // this exception will be caught & rethrown by this very method.
 552  
                         // getInit() returning false indicates some initialization issue,
 553  
                         // which in turn prevents the InitableBroker from passing a
 554  
                         // reference to a working instance of the initable to the client.
 555  0
                         throw new InitializationException(
 556  
                                 "init() failed to initialize service " + name);
 557  
                     }
 558  6351
                     return service;
 559  
                 }
 560  0
                 catch (InitializationException e)
 561  
                 {
 562  0
                     throw new InstantiationException("Service " + name +
 563  
                             " failed to initialize", e);
 564  
                 }
 565  
         }
 566  1692
         else if (this.isNonLocalService(name))
 567  
         {
 568  1656
             return this.getNonLocalService(name);
 569  
         }
 570  
         else
 571  
         {
 572  36
             throw new InstantiationException(
 573  
                 "ServiceBroker: unknown service " + name
 574  
                 + " requested");
 575  
         }
 576  
     }
 577  
 
 578  
     /**
 579  
      * Retrieves an instance of a Service without triggering late
 580  
      * initialization.
 581  
      *
 582  
      * Early initialization of a Service can require access to Service
 583  
      * properties.  The Service must have its name and serviceBroker
 584  
      * set by then.  Therefore, before calling
 585  
      * Initable.initClass(Object), the class must be instantiated with
 586  
      * InitableBroker.getInitableInstance(), and
 587  
      * Service.setServiceBroker() and Service.setName() must be
 588  
      * called.  This calls for two - level accessing the Services
 589  
      * instances.
 590  
      *
 591  
      * @param name The name of the service requested.
 592  
      *
 593  
      * @return the Service instance
 594  
      *
 595  
      * @throws InstantiationException The service is unknown or
 596  
      * can't be initialized.
 597  
      */
 598  
     protected Service getServiceInstance(String name)
 599  
             throws InstantiationException
 600  
     {
 601  8061
         Service service = services.get(name);
 602  
 
 603  8061
         if (service == null)
 604  
         {
 605  900
             serviceLock.lock();
 606  
 
 607  
             try
 608  
             {
 609  
                 // Double check
 610  900
                 service = services.get(name);
 611  
 
 612  900
                 if (service == null)
 613  
                 {
 614  900
                     if (!this.isLocalService(name))
 615  
                     {
 616  0
                         throw new InstantiationException(
 617  
                                 "ServiceBroker: unknown service " + name
 618  
                                 + " requested");
 619  
                     }
 620  
 
 621  
                     try
 622  
                     {
 623  900
                         Class<?> clazz = mapping.get(name);
 624  
 
 625  
                         try
 626  
                         {
 627  900
                             service = (Service) clazz.newInstance();
 628  
 
 629  
                             // check if the newly created service is also a
 630  
                             // service provider - if so then remember it
 631  900
                             if (service instanceof TurbineServiceProvider)
 632  
                             {
 633  105
                                 Service _service = this.serviceProviderInstanceMap.putIfAbsent(name,service);
 634  105
                                 if (_service != null)
 635  
                                 {
 636  0
                                     service = _service;
 637  
                                 }
 638  
                             }
 639  
                         }
 640  
                         // those two errors must be passed to the VM
 641  0
                         catch (ClassCastException e)
 642  
                         {
 643  0
                             throw new InstantiationException("Class " + clazz +
 644  
                                     " doesn't implement the Service interface", e);
 645  
                         }
 646  0
                         catch (ThreadDeath t)
 647  
                         {
 648  0
                             throw t;
 649  
                         }
 650  0
                         catch (OutOfMemoryError t)
 651  
                         {
 652  0
                             throw t;
 653  
                         }
 654  0
                         catch (Throwable t)
 655  
                         {
 656  0
                             throw new InstantiationException("Failed to instantiate " + clazz, t);
 657  900
                         }
 658  
                     }
 659  0
                     catch (InstantiationException e)
 660  
                     {
 661  0
                         throw new InstantiationException(
 662  
                                 "Failed to instantiate service " + name, e);
 663  900
                     }
 664  900
                     service.setServiceBroker(this);
 665  900
                     service.setName(name);
 666  900
                     Service _service = services.putIfAbsent(name, service);
 667  900
                     if (_service != null) // Unlikely
 668  
                     {
 669  0
                         service = _service;
 670  
                     }
 671  
                 }
 672  
             }
 673  
             finally
 674  
             {
 675  900
                 serviceLock.unlock();
 676  900
             }
 677  
         }
 678  
 
 679  8061
         return service;
 680  
     }
 681  
 
 682  
     /**
 683  
      * Returns the configuration for the specified service.
 684  
      *
 685  
      * @param name The name of the service.
 686  
      * @return Configuration of requested Service.
 687  
      */
 688  
     @Override
 689  
     public Configuration getConfiguration(String name)
 690  
     {
 691  1776
         return configuration.subset(SERVICE_PREFIX + name);
 692  
     }
 693  
 
 694  
     /**
 695  
      * Set the application root.
 696  
      *
 697  
      * @param applicationRoot application root
 698  
      */
 699  
     public void setApplicationRoot(String applicationRoot)
 700  
     {
 701  138
         this.applicationRoot = applicationRoot;
 702  138
     }
 703  
 
 704  
     /**
 705  
      * Get the application root as set by
 706  
      * the parent application.
 707  
      *
 708  
      * @return String application root
 709  
      */
 710  
     @Override
 711  
     public String getApplicationRoot()
 712  
     {
 713  138
         return applicationRoot;
 714  
     }
 715  
 
 716  
     /**
 717  
      * Determines if the requested service is managed by this
 718  
      * ServiceBroker.
 719  
      *
 720  
      * @param name The name of the Service requested.
 721  
      * @return true if the service is managed by the this ServiceBroker
 722  
      */
 723  
     protected boolean isLocalService(String name)
 724  
     {
 725  8943
         return this.mapping.containsKey(name);
 726  
     }
 727  
 
 728  
     /**
 729  
      * Determines if the requested service is managed by an initialized
 730  
      * TurbineServiceProvider. We use the service names to lookup
 731  
      * the TurbineServiceProvider to ensure that we get a fully
 732  
      * initialized service.
 733  
      *
 734  
      * @param name The name of the Service requested.
 735  
      * @return true if the service is managed by a TurbineServiceProvider
 736  
      */
 737  
     protected boolean isNonLocalService(String name)
 738  
     {
 739  1692
         TurbineServiceProvider turbineServiceProvider = null;
 740  
 
 741  1692
         for (Map.Entry<String, Service> entry : this.serviceProviderInstanceMap.entrySet())
 742  
         {
 743  1692
             turbineServiceProvider = (TurbineServiceProvider) this.getService(entry.getKey());
 744  
 
 745  1692
             if (turbineServiceProvider.exists(name))
 746  
             {
 747  1656
                 return true;
 748  
             }
 749  36
         }
 750  
 
 751  36
         return false;
 752  
     }
 753  
 
 754  
     /**
 755  
      * Get a non-local service managed by a TurbineServiceProvider.
 756  
      *
 757  
      * @param name The name of the Service requested.
 758  
      * @return the requested service
 759  
      * @throws InstantiationException the service couldn't be instantiated
 760  
      */
 761  
     protected Object getNonLocalService(String name)
 762  
             throws InstantiationException
 763  
     {
 764  1656
         TurbineServiceProvider turbineServiceProvider = null;
 765  
 
 766  1656
         for (Map.Entry<String, Service> entry : this.serviceProviderInstanceMap.entrySet())
 767  
         {
 768  1656
             turbineServiceProvider = (TurbineServiceProvider) this.getService(entry.getKey());
 769  
 
 770  1656
             if (turbineServiceProvider.exists(name))
 771  
             {
 772  1656
                 return turbineServiceProvider.get(name);
 773  
             }
 774  0
         }
 775  
 
 776  0
         throw new InstantiationException(
 777  
             "ServiceBroker: unknown non-local service " + name
 778  
             + " requested");
 779  
     }
 780  
 }