avalon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mcconn...@apache.org
Subject cvs commit: jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container Selector.java ResourceProvider.java DependencyGraph.java
Date Fri, 12 Jul 2002 16:05:06 GMT
mcconnell    2002/07/12 09:05:06

  Added:       assembly/src/java/org/apache/excalibur/merlin/container
                        Selector.java ResourceProvider.java
                        DependencyGraph.java
  Log:
  package rationalization
  
  Revision  Changes    Path
  1.1                  jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/Selector.java
  
  Index: Selector.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  
  package org.apache.excalibur.merlin.container;
  
  import org.apache.excalibur.merlin.model.Profile;
  
  
  /**
   * Interface implemented by a service selection implementation mechanism.  Classes 
   * implementing the selector interface may be activated during the selection of 
   * candidate service providers in an autom assembly process.  A selector my be
   * declared via inclusion a implemetation class nameed <code>&lt;service-type&gt;Selector</code>.
 
   * Alternatively, a component author may declare a selection class explicitly via a
   * service dependecy attribute with the attribute name of <code>avalon.service.selector</code>.
   *
   * @author <a href="mailto:mcconnell@apache.org">Stephen McConnell</a>
   * @version $Revision: 1.1 $ $Date: 2002/07/12 16:05:05 $
   */
  public interface Selector
  {
     /**
      * Returns the preferred profile form an available selection of candidate provider profiles.
      * @param facilities the set of profiles of potential service providers available in
the 
      *   container hierachy
      * @param profiles the set of profiles of potential service providers contained with
the 
      *   local container
      * @return the preferred provider or null if no satisfactory provider can be established

      *    from the supplied profiles.
      */
      Profile select( Profile[] facilities, Profile[] profiles );
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/ResourceProvider.java
  
  Index: ResourceProvider.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  
  package org.apache.excalibur.merlin.container;
  
  import java.io.InputStream;
  import java.io.File;
  import java.io.IOException;
  import java.net.URL;
  import java.net.JarURLConnection;
  import java.net.URLClassLoader;
  import java.util.Map;
  import java.util.List;
  import java.util.LinkedList;
  import java.util.Hashtable;
  import java.util.Properties;
  import java.util.Vector;
  import java.util.Iterator;
  import java.util.jar.Attributes;
  import java.util.jar.Manifest;
  import java.security.Policy;
  import java.io.FileInputStream;
  import java.util.HashMap;
  
  import org.apache.avalon.excalibur.i18n.ResourceManager;
  import org.apache.avalon.excalibur.i18n.Resources;
  import org.apache.excalibur.configuration.ConfigurationUtil;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.logger.AvalonFormatter;
  import org.apache.avalon.framework.logger.LogKitLogger;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.activity.Executable;
  import org.apache.avalon.framework.activity.Startable;
  import org.apache.avalon.framework.CascadingRuntimeException;
  import org.apache.avalon.framework.service.ServiceManager;
  import org.apache.avalon.framework.component.Component;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.DefaultComponentManager;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.context.Context;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.context.ContextException;
  import org.apache.avalon.framework.context.DefaultContext;
  import org.apache.avalon.framework.service.Serviceable;
  import org.apache.avalon.framework.service.ServiceManager;
  import org.apache.avalon.framework.service.DefaultServiceManager;
  import org.apache.avalon.framework.service.ServiceException;
  import org.apache.avalon.framework.Version;
  import org.apache.avalon.framework.ExceptionUtil;
  import org.apache.avalon.excalibur.extension.PackageRepository;
  import org.apache.avalon.excalibur.extension.Extension;
  import org.apache.avalon.excalibur.extension.OptionalPackage;
  import org.apache.avalon.excalibur.extension.DefaultPackageRepository;
  import org.apache.excalibur.meta.verifier.VerifyException;
  import org.apache.excalibur.meta.info.Type;
  import org.apache.excalibur.meta.info.DefaultType;
  import org.apache.excalibur.meta.info.ServiceDescriptor;
  import org.apache.excalibur.meta.info.DependencyDescriptor;
  import org.apache.excalibur.meta.info.ServiceDesignator;
  import org.apache.excalibur.merlin.model.Profile;
  import org.apache.excalibur.merlin.model.Association;
  import org.apache.excalibur.merlin.model.CategoryDescriptor;
  import org.apache.excalibur.merlin.kernel.DefaultLoggerManager;
  import org.apache.log.Hierarchy;
  import org.apache.log.Priority;
  import org.apache.log.output.io.StreamTarget;
  
  
  /**
   * Internal class that handles the establishment of component instances based on a supplied
   * type profile.
   *
   * @author <a href="mailto:mcconnell@apache.org">Stephen McConnell</a>
   * @version $Revision: 1.1 $ $Date: 2002/07/12 16:05:06 $
   */
  class ResourceProvider extends AbstractLogEnabled
  {
      //=======================================================================
      // state
      //=======================================================================
  
      private final static Resources REZ =
          ResourceManager.getPackageResources( ResourceProvider.class );
  
      //=======================================================================
      // state
      //=======================================================================
  
     /**
      * The classloader to use when servicing object creation requests.
      */
      private ClassLoader m_classloader;
  
     /**
      * A hashtable of service implemenentation object references keyed by profile.
      */
      private final Hashtable m_singletons = new Hashtable();
  
     /**
      * The log manager.
      */
      private DefaultLoggerManager m_logging;
  
      private Container m_locator;
  
      //=======================================================================
      // constructor
      //=======================================================================
  
      public ResourceProvider( ClassLoader loader, DefaultLoggerManager manager, Container
locator )
      {
          m_classloader = loader;
          m_logging = manager;
          m_locator = locator;
      }
  
      //=======================================================================
      // ResourceProvider
      //=======================================================================
  
      /**
       * Create an object specified by profile.
       *
       * @param profile the profile
       * @return the new object
       * @throws Exception if unable to resolve resource
       */
      public Object createObject( Profile profile )
          throws Exception
      {
          Object object = getSingletonInstance( profile );
          if( object == null )
          {
              Class clazz = null;
              String classname = null;
              try
              {
                  classname = profile.getType().getInfo().getImplementationKey();
                  clazz = m_classloader.loadClass( classname );
              }
              catch( Throwable e )
              {
                  final String error = 
                    "Unexpected exception while attempting to load class '" 
                    + classname + "' for the profile: " + profile;
                  throw new ContainerException( error, e );
              }
  
              try
              {
                  object = clazz.newInstance();
                  putSingletonInstance( profile, object );
              }
              catch( Throwable e )
              {
                  final String error = 
                    "Unexpected exception while attempting to instantiate an instance from
profile: " 
                      + profile;
                  throw new ContainerException( error, e );
              }
          }
          return object;
      }
  
      /**
       * Create a new Logger for component.
       *
       * @param profile the profile
       * @return a new Logger for service
       * @throws Exception if unable to create the logger
       */
      public Logger createLogger( Profile profile )
          throws Exception
      {
          final String name = profile.getName();
          CategoryDescriptor loggers = profile.getCategoryDescriptor();
          m_logging.addCategories( loggers );
          return m_logging.getLoggerForCategory( loggers );
      }
  
      /**
       * Create a new Context for component.
       *
       * @param profile the profile
       * @return a new Context for service
       * @throws Exception if unable to create context
       */
      public Context createContext( Profile profile )
          throws Exception
      {
          return profile.getContext();
      }
  
      /**
       * Create a new ComponentManager for component.
       *
       * @param profile the profile
       * @return a new ComponentManager for component
       * @throws Exception if unable to create the component manager
       */
      public ComponentManager createComponentManager( Profile profile )
          throws Exception
      {
          final Map services = getServices( profile );
          final DefaultComponentManager componentManager = new DefaultComponentManager();
          final Iterator keys = services.keySet().iterator();
          while( keys.hasNext() )
          {
              final String key = (String)keys.next();
              final Object service = services.get( key );
              if( !Component.class.isInstance( service ) )
              {
                  final String message =
                      REZ.getString( "resource.service-not-a-component.error",
                                     key,
                                     service.getClass().getName() );
                  throw new Exception( message );
              }
              componentManager.put( key, (Component)service );
          }
          componentManager.makeReadOnly();
          return componentManager;
      }
  
      /**
       * Create a new ServiceManager for component.
       *
       * @param entry the entry
       * @return a new ServiceManager for component
       * @throws Exception if unable to create resource
       */
      public ServiceManager createServiceManager( Profile profile )
          throws Exception
      {
          final Map services = getServices( profile );
          final DefaultServiceManager serviceManager = new DefaultServiceManager();
          final Iterator keys = services.keySet().iterator();
          while( keys.hasNext() )
          {
              final String key = (String)keys.next();
              final Object service = services.get( key );
              serviceManager.put( key, service );
          }
          serviceManager.makeReadOnly();
          return serviceManager;
      }
  
      /**
       * Create a new Configuration object for component.
       *
       * @param entry the entry
       * @return a new Configuration object for component
       * @throws Exception if unable to create resource
       */
      public Configuration createConfiguration( Profile profile )
          throws Exception
      {
          Configuration config = profile.getConfiguration();
          if( config == null ) 
            config = new DefaultConfiguration("configuration", null );
          return config;
      }
  
      /**
       * Create a new Parameters object for component.
       *
       * @param entry the entry
       * @return a new Parameters object for component
       * @throws Exception if unable to create resource
       */
      public Parameters createParameters( Profile profile )
          throws Exception
      {
          final Parameters parameters = profile.getParameters();
          if( null == parameters )
          {
              final String message =
                  REZ.getString( "resource.missing-parameters.error",
                                 profile.getName() );
              throw new Exception( message );
          }
          parameters.makeReadOnly();
          return parameters;
      }
  
      public Object getSingletonInstance( Profile profile )
      {
          return m_singletons.get( profile );
      }
  
      private void putSingletonInstance( Profile profile, Object object )
      {
          m_singletons.put( profile, object );
      }
  
     /**
      * Prepare a map of the dependent services keyed by role name.
      * @param profile the profile referencing a type declaring dependecies
      * @return a map of the services
      */
      private Map getServices( Profile profile ) throws Exception
      {
          final Type type = profile.getType();
          final DependencyDescriptor[] dependencies = type.getDependencies();
          final HashMap services = new HashMap();
          for( int i = 0; i < dependencies.length; i++ )
          {
              DependencyDescriptor dependency = dependencies[i];
              final String role = dependency.getRole();
              final Association association = profile.getAssociation( role );
              final Profile provider = association.getProvider();
              final boolean required = type.getDependency( role ).isRequired();
              final String classname = type.getDependency( role ).getService().getClassname();
  
              final Object service = lookup( provider, classname );
              if(( null == service ) && ( required ))
              {
                  final String message =
                      REZ.getString( "resource.missing-dependency.error",
                                     !required ? "1" : "2",
                                     role,
                                     profile.getName() );
                  throw new Exception( message );
              }
              services.put( role, service );
          }
          return services;
      }
  
     /**
      * Get a service instance for the supplied profile, and validate that the returned 
      * service instance implements the supplied service classname.
      * @param provider the key to the provider instance
      * @param service the classname of the service requested
      */
      private Object lookup( Profile provider, String service ) throws Exception
      {
          Object object = m_locator.lookup( provider );
          if( objectImplementsType( object, service ) )
             return object;
          final String error = 
             "Unable to locate an instantiated service instance implementing the interface:
"
                + service + ", from the provider: " + provider;
          throw new ContainerException( error );
      }
  
      /**
       * Check whether the specified value is compatible with specified type.
       *
       * @param value the value
       * @param type the desired type
       * @return true if value is compatible with type, false otherwise
       */
      private boolean objectImplementsType( final Object value, final String type ) throws
Exception
      {
          if( value == null ) 
            return false;
          try
          {
              final Class clazz = value.getClass();
              final ClassLoader classLoader = clazz.getClassLoader();
              final Class typeClass = classLoader.loadClass( type );
              if( typeClass.isAssignableFrom( clazz ) )
              {
                  return true;
              }
          }
          catch( final ClassNotFoundException cnfe )
          {
          }
          return false;
      }
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/DependencyGraph.java
  
  Index: DependencyGraph.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included  with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.excalibur.merlin.container;
  
  import java.util.ArrayList;
  import org.apache.excalibur.merlin.model.Profile;
  import org.apache.excalibur.merlin.model.Association;
  import org.apache.excalibur.meta.info.DependencyDescriptor;
  
  /**
   * <p>Utility class to help aquire a ordered graph of
   * consumers and providers for specific components.</p>
   * <p><b>UML</b></p>
   * <p><image src="doc-files/Map.gif" border="0"/></p>
   *
   * @author <a href="mailto:peter@apache.org">Peter Donald</a>
   * @author <a href="mailto:mcconnell@apache.org">Stephen McConnell</a>
   * @version $Revision: 1.1 $ $Date: 2002/07/12 16:05:06 $
   */
  public class DependencyGraph
  {
      /**
       * Parent Map. Components in parent
       * Map are potential Providers for services
       * if no profile in current assembly satisfies dependency.
       */
      private final DependencyGraph m_parent;
  
      /**
       * The set of components declared by the container as available.,
       * Used when searching for providers/consumers.
       */
      private final ArrayList m_components = new ArrayList();
  
      /**
       * The child {@link DependencyGraph} objects.
       * Possible consumers of services in this assembly.
       */
      private final ArrayList m_children = new ArrayList();
  
  
      public DependencyGraph()
      {
          this( null );
      }
  
      public DependencyGraph( final DependencyGraph parent )
      {
          m_parent = parent;
      }
  
      /**
       * Add child dependency graph.
       *
       * @param child the child map
       */
      public void addChild( final DependencyGraph child )
      {
          m_children.add( child );
      }
  
      /**
       * Remove child dependency graph.
       *
       * @param child the child map
       */
      public void removeChild( final DependencyGraph child )
      {
          m_children.remove( child );
      }
  
      /**
       * Add a profile to current dependency graph.
       *
       * @param profile the profile
       */
      public void add( final Profile profile )
      {
          if( !m_components.contains( profile ) )
            m_components.add( profile );
      }
  
      /**
       * Get the serilized graph of {@link Profile} objects
       * required when starting up all the components. This makes sure
       * that all providers occur before their coresponding
       * consumers in graph.
       *
       * @return the ordered list of components
       */
      public Profile[] getStartupGraph()
      {
          return walkGraph( true );
      }
  
      /**
       * Get the serilized graph of {@link Profile} objects
       * required when shutting down all the components. This makes
       * sure that all consumers occur before their coresponding
       * providers in graph.
       *
       * @return the ordered list of components
       */
      public Profile[] getShutdownGraph()
      {
          return walkGraph( false );
      }
  
      /**
       * Get the serilized graph of {@link Profile} objects
       * that use services of specified profile.
       *
       * @param profile the profile
       * @return the ordered list of consumers
       */
      public Profile[] getConsumerGraph( final Profile profile )
      {
          return referencedProfiles( profile, getComponentGraph( profile, false ));
      }
  
      /**
       * Get the serilized graph of {@link Profile} objects
       * that provide specified profile with services.
       *
       * @param profile the profile
       * @return the ordered list of providers
       */
      public Profile[] getProviderGraph( final Profile profile )
      {
          return referencedProfiles( profile, getComponentGraph( profile, true ));
      }
  
      /**
       * Return a profile array that does not include the provided profile.
       */
      private Profile[] referencedProfiles( final Profile profile, Profile[] profiles )
      {
          ArrayList list = new ArrayList();
          for( int i=0; i<profiles.length; i++ )
          {
              if( !profiles[i].equals( profile ) )
                list.add( profiles[i] );
          }
          return (Profile[]) list.toArray( new Profile[0] );
      }
  
      /**
       * Get the graph of a single profile.
       *
       * @param profile the profile
       * @param providers true if traversing providers, false if consumers
       * @return the list of components in graph
       */
      private Profile[] getComponentGraph( final Profile profile, final boolean providers
)
      {
          final ArrayList result = new ArrayList();
          visitcomponent( profile,
                          providers,
                          new ArrayList(),
                          result );
  
          final Profile[] returnValue = new Profile[ result.size() ];
          return (Profile[])result.toArray( returnValue );
      }
  
      /**
       * Method to generate an ordering of nodes to traverse.
       * It is expected that the specified components have passed
       * verification tests and are well formed.
       *
       * @param providers true if forward dependencys traced, false if dependencies reversed
       * @return the ordered node names
       */
      private Profile[] walkGraph( final boolean providers )
      {
          final ArrayList result = new ArrayList();
          final ArrayList done = new ArrayList();
  
          final int size = m_components.size();
          for( int i = 0; i < size; i++ )
          {
              final Profile profile =
                  (Profile)m_components.get( i );
  
              visitcomponent( profile,
                              providers,
                              done,
                              result );
          }
  
          final Profile[] returnValue = new Profile[ result.size() ];
          return (Profile[])result.toArray( returnValue );
      }
  
      /**
       * Visit a profile when traversing dependencies.
       *
       * @param profile the profile
       * @param providers true if walking tree looking for providers, else false
       * @param done those nodes already traversed
       * @param order the order in which nodes have already been
       *             traversed
       */
      private void visitcomponent( final Profile profile,
                                   final boolean providers,
                                   final ArrayList done,
                                   final ArrayList order )
      {
          //If already visited this profile then bug out early
          if( done.contains( profile ) )
          {
              return;
          }
          done.add( profile );
  
          if( providers )
          {
              visitProviders( profile, done, order );
          }
          else
          {
              visitConsumers( profile, done, order );
          }
  
          order.add( profile );
      }
  
      /**
       * Traverse graph of components that provide services to
       * the specified profile.
       *
       * @param profile the Profile
       */
      private void visitProviders( final Profile profile,
                                   final ArrayList done,
                                   final ArrayList order )
      {
          final DependencyDescriptor[] descriptors =
              profile.getType().getDependencies();
  
          for( int i = 0; i < descriptors.length; i++ )
          {
              final Association assignment =
                  profile.getAssociation( descriptors[ i ].getRole() );
  
              // added != null clause to catch cases where an optional 
              // dependency exists and the dependecy has not been bound 
              // to a provider
  
              if( assignment != null ) 
              {
                  final Profile provider = assignment.getProvider();
                  visitcomponent( provider, true, done, order );
              }
              else
              {
                  if( descriptors[i].isRequired() )
                    throw new IllegalStateException( 
                      "unresolved dependency for role: " + descriptors[i].getRole() 
                      + " in profile: " + profile );
              }
          }
      }
  
      /**
       * Traverse all Consumers of profile. ie Anyone that uses
       * service provided by profile.
       *
       * @param profile the Profile
       */
      private void visitConsumers( final Profile profile,
                                   final ArrayList done,
                                   final ArrayList order )
      {
  
          final String name = profile.getName();
  
          final int size = m_components.size();
          for( int i = 0; i < size; i++ )
          {
              final Profile other =
                  (Profile)m_components.get( i );
              final Association[] providers = other.getAssociations();
  
              for( int j = 0; j < providers.length; j++ )
              {
                  if( providers[ j ].getProvider().equals( profile ) )
                  {
                      visitcomponent( other, false, done, order );
                  }
              }
          }
  
          final int childCount = m_children.size();
          for( int i = 0; i < childCount; i++ )
          {
              final DependencyGraph map = (DependencyGraph)m_children.get( i );
              map.visitConsumers( profile, done, order );
          }
      }
  }
  
  
  

--
To unsubscribe, e-mail:   <mailto:avalon-cvs-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:avalon-cvs-help@jakarta.apache.org>


Mime
View raw message