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