Package org.jboss.weld.integration.deployer.env

Source Code of org.jboss.weld.integration.deployer.env.FlatDeployment$ServiceLoader

/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.weld.integration.deployer.env;

import static java.util.logging.Level.WARNING;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import javax.enterprise.inject.spi.Extension;

import org.jboss.weld.bootstrap.api.ServiceRegistry;
import org.jboss.weld.bootstrap.api.helpers.SimpleServiceRegistry;
import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive;
import org.jboss.weld.bootstrap.spi.Deployment;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.jboss.weld.ejb.spi.EjbDescriptor;

/**
* Initial (naive) implementation of Deployment for JBoss AS.
*
* This version simply flattens the entire deployment into a single
* BeanDeploymentArchive
*
* @author pmuir
* @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
*/
public class FlatDeployment implements Deployment
{
  

   /**
    * This class handles looking up service providers on the class path. It
    * implements the <a href="http://java.sun.com/javase/6/docs/technotes/guides/jar/jar.html#Service%20Provider"
    * >Service Provider section of the JAR File Specification</a>.
    *
    * The Service Provider programmatic lookup was not specified prior to Java 6 so
    * this interface allows use of the specification prior to Java 6.
    *
    * The API is copied from <a
    * href="http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html"
    * >java.util.ServiceLoader</a> and enhanced to support the {@link Metadata}
    * contract.
    *
    * @author Pete Muir
    * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
    * @author Nicklas Karlsson
    */
   private static class ServiceLoader<S> implements Iterable<Metadata<S>>
   {
     
      private static class ServiceLoaderMetadata<S> implements Metadata<S>
      {
        
         private final URL file;
         private final int lineNumber;
         private final S value;
         public ServiceLoaderMetadata(S value, URL file, int lineNumber)
         {
            this.file = file;
            this.lineNumber = lineNumber;
            this.value = value;
         }
        
         public String getLocation()
         {
            return file + "@" + lineNumber;
         }
        
         public S getValue()
         {
            return value;
         }

      }
     
      private static final String SERVICES = "META-INF/services";

      private static final Logger log = Logger.getLogger("ServiceLoader");

      /**
       * Creates a new service loader for the given service type, using the current
       * thread's context class loader.
       *
       * An invocation of this convenience method of the form
       *
       * {@code ServiceLoader.load(service)</code>}
       *
       * is equivalent to
       *
       * <code>ServiceLoader.load(service,
       *                   Thread.currentThread().getContextClassLoader())</code>
       *
       * @param service The interface or abstract class representing the service
       * @return A new service loader
       */
      public static <S> ServiceLoader<S> load(Class<S> service)
      {
         return load(service, Thread.currentThread().getContextClassLoader());
      }

      /**
       * Creates a new service loader for the given service type and class loader.
       *
       * @param service The interface or abstract class representing the service
       * @param loader The class loader to be used to load provider-configuration
       *           files and provider classes, or null if the system class loader
       *           (or, failing that, the bootstrap class loader) is to be used
       * @return A new service loader
       */
      public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)
      {
         if (loader == null)
         {
            loader = service.getClassLoader();
         }
         return new ServiceLoader<S>(service, loader);
      }

      /**
       * Creates a new service loader for the given service type, using the
       * extension class loader.
       *
       * This convenience method simply locates the extension class loader, call it
       * extClassLoader, and then returns
       *
       * <code>ServiceLoader.load(service, extClassLoader)</code>
       *
       * If the extension class loader cannot be found then the system class loader
       * is used; if there is no system class loader then the bootstrap class
       * loader is used.
       *
       * This method is intended for use when only installed providers are desired.
       * The resulting service will only find and load providers that have been
       * installed into the current Java virtual machine; providers on the
       * application's class path will be ignored.
       *
       * @param service The interface or abstract class representing the service
       * @return A new service loader
       */
      public static <S> ServiceLoader<S> loadInstalled(Class<S> service)
      {
         throw new UnsupportedOperationException("Not implemented");
      }

      private final String serviceFile;
      private Class<S> expectedType;
      private final ClassLoader loader;

      private Set<Metadata<S>> providers;

      private ServiceLoader(Class<S> service, ClassLoader loader)
      {
         this.loader = loader;
         this.serviceFile = SERVICES + "/" + service.getName();
         this.expectedType = service;
      }

      /**
       * Clear this loader's provider cache so that all providers will be reloaded.
       *
       * After invoking this method, subsequent invocations of the iterator method
       * will lazily look up and instantiate providers from scratch, just as is
       * done by a newly-created loader.
       *
       * This method is intended for use in situations in which new providers can
       * be installed into a running Java virtual machine.
       */
      public void reload()
      {
         providers = new HashSet<Metadata<S>>();

         for (URL serviceFile : loadServiceFiles())
         {
            loadServiceFile(serviceFile);
         }
      }

      private List<URL> loadServiceFiles()
      {
         List<URL> serviceFiles = new ArrayList<URL>();
         try
         {
            Enumeration<URL> serviceFileEnumerator = loader.getResources(serviceFile);
            while (serviceFileEnumerator.hasMoreElements())
            {
               serviceFiles.add(serviceFileEnumerator.nextElement());
            }
         }
         catch (IOException e)
         {
            throw new RuntimeException("Could not load resources from " + serviceFile, e);
         }
         return serviceFiles;
      }

      private void loadServiceFile(URL serviceFile)
      {
         InputStream is = null;
         try
         {
            is = serviceFile.openStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            String serviceClassName = null;
            int i = 0;
            while ((serviceClassName = reader.readLine()) != null)
            {
               i++;
               serviceClassName = trim(serviceClassName);
               if (serviceClassName.length() > 0)
               {
                  loadService(serviceClassName, serviceFile, i);
               }
            }
         }
         catch (IOException e)
         {
            // FIXME: correct exception
            throw new RuntimeException("Could not read services file " + serviceFile);
         }
         finally
         {
            if (is != null)
            {
               try
               {
                  is.close();
               }
               catch (IOException e)
               {
                  // FIXME: correct exception
                  throw new RuntimeException("Could not close services file " + serviceFile, e);
               }
            }
         }
      }

      private String trim(String line)
      {
         final int comment = line.indexOf('#');

         if (comment > -1)
         {
            line = line.substring(0, comment);
         }
         return line.trim();
      }

      private void loadService(String serviceClassName, URL file, int lineNumber)
      {
         Class<? extends S> serviceClass = loadClass(serviceClassName);
         if (serviceClass == null)
         {
            return;
         }
         S serviceInstance = prepareInstance(serviceClass);
         if (serviceInstance == null)
         {
            return;
         }
         providers.add(new ServiceLoaderMetadata<S>(serviceInstance, file, lineNumber));
      }

      private Class<? extends S> loadClass(String serviceClassName)
      {
         Class<?> clazz = null;
         Class<? extends S> serviceClass = null;
         try
         {
            clazz = loader.loadClass(serviceClassName);
            serviceClass = clazz.asSubclass(expectedType);
         }
         catch (ClassNotFoundException e)
         {
            log.warning("Could not load service class " + serviceClassName);
         }
         catch (ClassCastException e)
         {
            throw new RuntimeException("Service class " + serviceClassName + " didn't implement the Extension interface");
         }
         return serviceClass;
      }

      private S prepareInstance(Class<? extends S> serviceClass)
      {
         try
         {
            // TODO Support the SM
            Constructor<? extends S> constructor = serviceClass.getDeclaredConstructor();
            constructor.setAccessible(true);
            return constructor.newInstance();
         }
         catch (NoClassDefFoundError e)
         {
            log.log(WARNING, "Could not instantiate service class " + serviceClass.getName(), e);
            return null;
         }
         catch (InvocationTargetException e)
         {
            throw new RuntimeException("Error instantiating " + serviceClass, e.getCause());
         }
         catch (IllegalArgumentException e)
         {
            throw new RuntimeException("Error instantiating " + serviceClass, e);
         }
         catch (InstantiationException e)
         {
            throw new RuntimeException("Error instantiating " + serviceClass, e);
         }
         catch (IllegalAccessException e)
         {
            throw new RuntimeException("Error instantiating " + serviceClass, e);
         }
         catch (SecurityException e)
         {
            throw new RuntimeException("Error instantiating " + serviceClass, e);
         }
         catch (NoSuchMethodException e)
         {
            throw new RuntimeException("Error instantiating " + serviceClass, e);
         }
      }

      /**
       * Lazily loads the available providers of this loader's service.
       *
       * The iterator returned by this method first yields all of the elements of
       * the provider cache, in instantiation order. It then lazily loads and
       * instantiates any remaining providers, adding each one to the cache in
       * turn.
       *
       * To achieve laziness the actual work of parsing the available
       * provider-configuration files and instantiating providers must be done by
       * the iterator itself. Its hasNext and next methods can therefore throw a
       * ServiceConfigurationError if a provider-configuration file violates the
       * specified format, or if it names a provider class that cannot be found and
       * instantiated, or if the result of instantiating the class is not
       * assignable to the service type, or if any other kind of exception or error
       * is thrown as the next provider is located and instantiated. To write
       * robust code it is only necessary to catch ServiceConfigurationError when
       * using a service iterator.
       *
       * If such an error is thrown then subsequent invocations of the iterator
       * will make a best effort to locate and instantiate the next available
       * provider, but in general such recovery cannot be guaranteed.
       *
       * Design Note Throwing an error in these cases may seem extreme. The
       * rationale for this behavior is that a malformed provider-configuration
       * file, like a malformed class file, indicates a serious problem with the
       * way the Java virtual machine is configured or is being used. As such it is
       * preferable to throw an error rather than try to recover or, even worse,
       * fail silently.
       *
       * The iterator returned by this method does not support removal. Invoking
       * its remove method will cause an UnsupportedOperationException to be
       * thrown.
       *
       * @return An iterator that lazily loads providers for this loader's service
       */
      public Iterator<Metadata<S>> iterator()
      {
         if (providers == null)
         {
            reload();
         }
         return providers.iterator();
      }

      /**
       * Returns a string describing this service.
       *
       * @return A descriptive string
       */
      @Override
      public String toString()
      {
         return "Services for " + serviceFile;
      }
   }

  
  
   private final JBossBeanDeploymentArchive beanDeploymentArchive;
   private final List<BeanDeploymentArchive> beanDeploymentArchives;
   private final ServiceRegistry services;

   public FlatDeployment(WeldDiscoveryEnvironment environment, Collection<EjbDescriptor<?>> ejbDescriptors)
   {
      this.beanDeploymentArchive = new JBossBeanDeploymentArchive("flat" ,environment, ejbDescriptors);
      this.beanDeploymentArchives = Collections.<BeanDeploymentArchive>singletonList(beanDeploymentArchive);
      this.services = new SimpleServiceRegistry();
   }

   public List<BeanDeploymentArchive> getBeanDeploymentArchives()
   {
      return beanDeploymentArchives;
   }

   public BeanDeploymentArchive loadBeanDeploymentArchive(Class<?> beanClass)
   {
      return beanDeploymentArchive;
   }

   public JBossBeanDeploymentArchive getFlatBeanDeploymentArchive()
   {
      return beanDeploymentArchive;
   }

   public ServiceRegistry getServices()
   {
      return services;
   }
  
   public Iterable<Metadata<Extension>> getExtensions()
   {
      return ServiceLoader.load(Extension.class);
   }
}
TOP

Related Classes of org.jboss.weld.integration.deployer.env.FlatDeployment$ServiceLoader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.