All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.hk2.internal.ServiceLocatorFactoryImpl Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package org.glassfish.hk2.internal;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.ServiceConfigurationError;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.ServiceLocatorFactory;
import org.glassfish.hk2.api.ServiceLocatorListener;
import org.glassfish.hk2.extension.ServiceLocatorGenerator;
import org.glassfish.hk2.osgiresourcelocator.ServiceLoader;

/**
 * The implementation of the {@link ServiceLocatorFactory} that looks
 * in the OSGi service registry or the META-INF/services for the implementation
 * to use.  Failing those things, it uses the standard default locator
 * generator, which is found in auto-depends, which is the 99.9% case
 * 
 * @author jwells
 */
public class ServiceLocatorFactoryImpl extends ServiceLocatorFactory {
    private static final Object sLock = new Object();
    private static int name_count = 0;
    private static final String GENERATED_NAME_PREFIX = "__HK2_Generated_";
    
  private final ServiceLocatorGenerator defaultGenerator;
  private final Object lock = new Object();
  private final HashMap serviceLocators = new HashMap();
  private final HashSet listeners = new HashSet();
  

  private static Logger logger = Logger.getLogger(ServiceLocatorFactoryImpl.class.getPackage().getName());

    /**
   * This will create a new set of name to locator mappings
   */
  public ServiceLocatorFactoryImpl() {
      defaultGenerator = AccessController.doPrivileged(new PrivilegedAction() {

        @Override
        public ServiceLocatorGenerator run() {
            try {
                return getGenerator();
            }
            catch (Throwable th) {
                Logger.getLogger(ServiceLocatorFactoryImpl.class.getName()).warning("Error finding implementation of hk2: " + th.getMessage());
                // th.printStackTrace();
                // Thread.dumpStack();
                return null;
            }
        }
          
      });
  }
  
  private static Iterable getOSGiSafeGenerators() {
      try {
          return ServiceLoader.lookupProviderInstances(ServiceLocatorGenerator.class);
      }
      catch (Throwable th) {
          // The bundle providing ServiceLoader need not be on the classpath
          return null;
      }
  }
  
  private static ServiceLocatorGenerator getGenerator() {
      Iterable generators = getOSGiSafeGenerators();
      if (generators != null) {
          // non-null indicates we are in OSGi environment
          // So, we will return whatever we find. If we don't find anything here, then we assume it is a
          // configuration error and return null.
          // Since org.glassfish.hk2.osgiresourcelocator.ServiceLoader never throws ServiceConfigurationError,
          // there is no need to catch it and try next item in the iterator.
          final Iterator iterator = generators.iterator();
          return iterator.hasNext() ? iterator.next() : null;
      }
      
      // We are in non-OSGi environment, let's use JDK ServiceLoader instead.
      // Make sure we use our current loader to locate the service as opposed to some arbitrary TCL
      final ClassLoader classLoader = ServiceLocatorFactoryImpl.class.getClassLoader();
      Iterator providers = java.util.ServiceLoader.load(ServiceLocatorGenerator.class,
              classLoader).iterator();
      while (providers.hasNext()) {
          try {
              return providers.next();
          } catch (ServiceConfigurationError sce) {
              // This can happen. See the exception javadoc for more details.
              logger.logp(Level.FINE, "ServiceLocatorFactoryImpl", "getGenerator",
                      "Exception while looking up service locator generator", sce);
                  // We will try the next one
          }
      }
      
      logger.warning("Cannot find a default implementation of the HK2 ServiceLocatorGenerator");
      return null;
  }

  /* (non-Javadoc)
   * @see org.glassfish.hk2.api.ServiceLocatorFactory#create(java.lang.String, org.glassfish.hk2.api.Module)
   */
  @Override
  public ServiceLocator create(String name) {
      return create(name, null, null, CreatePolicy.RETURN);
  }

  /* (non-Javadoc)
   * @see org.glassfish.hk2.api.ServiceLocatorFactory#find(java.lang.String)
   */
  @Override
  public ServiceLocator find(String name) {
    synchronized (lock) {
      return serviceLocators.get(name);
    }
  }

  /* (non-Javadoc)
   * @see org.glassfish.hk2.api.ServiceLocatorFactory#destroy(java.lang.String)
   */
  @Override
  public void destroy(String name) {
      ServiceLocator killMe = null;
    
      synchronized (lock) {
          killMe = serviceLocators.remove(name);
          
          if (killMe != null) {
              for (ServiceLocatorListener listener : listeners) {
                  try {
                      listener.listenerDestroyed(killMe);
                  }
                  catch (Throwable th) {
                      logger.log(Level.FINE, "Exception thrown from listenerDestroyed method of " + listener, th);
                  }
              }
          }
      }
    
      if (killMe != null) {
          killMe.shutdown();
      }
  }
  
  public void destroy(ServiceLocator locator) {
      if (locator == null) return;
      
      locator.shutdown();
      
      destroy(locator.getName());  // Removes it from our DB
  }

    /* (non-Javadoc)
     * @see org.glassfish.hk2.api.ServiceLocatorFactory#create(java.lang.String, org.glassfish.hk2.api.Module, org.glassfish.hk2.api.ServiceLocator)
     */
    @Override
    public ServiceLocator create(String name,
            ServiceLocator parent) {
        return create(name, parent, null, CreatePolicy.RETURN);
    }
    
    private static String getGeneratedName() {
        synchronized (sLock) {
            return GENERATED_NAME_PREFIX + name_count++;
        }
        
    }

    /* (non-Javadoc)
     * @see org.glassfish.hk2.api.ServiceLocatorFactory#create(java.lang.String, org.glassfish.hk2.api.ServiceLocator, org.glassfish.hk2.extension.ServiceLocatorGenerator)
     */
    @Override
    public ServiceLocator create(String name, ServiceLocator parent,
            ServiceLocatorGenerator generator) {
 
        return create(name, parent, generator, CreatePolicy.RETURN);
    }
    
    @Override
    public ServiceLocator create(String name, ServiceLocator parent,
            ServiceLocatorGenerator generator, CreatePolicy policy) {
        synchronized (lock) {
            ServiceLocator retVal;

            if (name == null) {
                name = getGeneratedName();
                return internalCreate(name, parent, generator);
            }

            retVal = serviceLocators.get(name);
            if (retVal != null) {
                if (policy == null || CreatePolicy.RETURN.equals(policy)) {
                    return retVal;
                }
                
                if (policy.equals(CreatePolicy.DESTROY)) {
                    destroy(retVal);
                }
                else {
                    throw new IllegalStateException(
                            "A ServiceLocator named " + name + " already exists");
                }
            }
            retVal = internalCreate(name, parent, generator);
            serviceLocators.put(name, retVal);
            
            for (ServiceLocatorListener listener : listeners) {
                try {
                    listener.listenerAdded(retVal);
                }
                catch (Throwable th) {
                    logger.log(Level.FINE, "Exception thrown from listenerAdded method of " + listener, th);
                }
            }

            return retVal;
        }
    }

    private ServiceLocator internalCreate(String name, ServiceLocator parent, ServiceLocatorGenerator generator) {
        if (generator == null) {
            if (defaultGenerator == null) {
                throw new IllegalStateException("No generator was provided and there is no default generator registered");
            }
            generator = defaultGenerator;
        }
        return generator.create(name, parent);
    }

    @Override
    public void addListener(ServiceLocatorListener listener) {
        if (listener == null) throw new IllegalArgumentException();
        
        synchronized (lock) {
            if (listeners.contains(listener)) return;
            
            try {
                HashSet currentLocators = new HashSet(serviceLocators.values());
                listener.initialize(Collections.unmodifiableSet(currentLocators));
            }
            catch (Throwable th) {
                // Not added to the set of listeners
                logger.log(Level.FINE, "Exception thrown from init method of " + listener, th);
                return;
            }
            
            listeners.add(listener);
        }
        
    }

    @Override
    public void removeListener(ServiceLocatorListener listener) {
        if (listener == null) throw new IllegalArgumentException();
        
        synchronized (lock) {
            listeners.remove(listener);
        }
        
    }

    

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy