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><service-type>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:[EMAIL PROTECTED]">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:[EMAIL PROTECTED]">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:[EMAIL PROTECTED]">Peter Donald</a>
* @author <a href="mailto:[EMAIL PROTECTED]">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:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>