mcconnell 2002/11/30 06:47:51 Modified: assembly/src/java/org/apache/avalon/assembly/engine DefaultEngine.java Engine.java assembly/src/test/org/apache/avalon/assembly/engine EngineTestCase.java Added: assembly/src/java/org/apache/avalon/assembly/lifecycle ContextHandler.java Log: Engine, Default engine and test case update to make the interfaces easier to deal with and more intative. Revision Changes Path 1.2 +39 -8 avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/DefaultEngine.java Index: DefaultEngine.java =================================================================== RCS file: /home/cvs/avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/DefaultEngine.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- DefaultEngine.java 29 Nov 2002 13:18:01 -0000 1.1 +++ DefaultEngine.java 30 Nov 2002 14:47:51 -0000 1.2 @@ -97,6 +97,7 @@ private ApplianceManager m_appliances; private ClassLoader m_classloader; + private Map m_map; //============================================================== // Contextualizable @@ -145,6 +146,15 @@ { // ignore } + + try + { + m_map = (Map) context.get( "assembly:system-map" ); + } + catch( ContextException ce ) + { + // ignore + } } //============================================================== @@ -184,7 +194,7 @@ * @param path the path to the appliance implementation class * @return the appliance */ - public void register( String path ) throws Exception + public void register( String path ) throws EngineRuntimeException { try { @@ -197,7 +207,7 @@ { final String error = "Failed to register one or more profiles."; - throw new EngineException( error, e ); + throw new EngineRuntimeException( error, e ); } } @@ -338,16 +348,22 @@ private ApplianceManager createApplianceManager( ClassLoader classloader ) throws Exception { DefaultApplianceManager manager = new DefaultApplianceManager(); + manager.enableLogging( getLogger() ); + DefaultContext context = new DefaultContext( getSystemContext() ); context.put( "assembly:classloader", classloader ); + context.put( "assembly:pool-manager", getPoolManager() ); context.makeReadOnly(); manager.contextualize( context ); + DefaultServiceManager services = new DefaultServiceManager(); services.put( "assembly:engine", this ); services.makeReadOnly(); manager.service( services ); + manager.initialize(); + return manager; } @@ -355,15 +371,30 @@ { if( m_context == null ) { - DefaultContext context = new DefaultContext(); - final File home = new File( System.getProperty( "user.dir" ) ); - context.put( "avalon:home", home ); - context.put( "assembly:pool-manager", getPoolManager() ); + DefaultContext context; + if( m_map != null ) + { + context = new DefaultContext( m_map ); + } + else + { + context = new DefaultContext(); + } + + try + { + context.get( "avalon:home" ); + } + catch( ContextException ce ) + { + final File home = new File( System.getProperty( "user.dir" ) ); + context.put( "avalon:home", home ); + } + m_context = context; } return m_context; } - private PoolManager getPoolManager() { 1.2 +3 -2 avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/Engine.java Index: Engine.java =================================================================== RCS file: /home/cvs/avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/engine/Engine.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- Engine.java 29 Nov 2002 13:18:01 -0000 1.1 +++ Engine.java 30 Nov 2002 14:47:51 -0000 1.2 @@ -71,8 +71,9 @@ * Register a type and associated profiles with the container. * @param path the path to the appliance implementation class * @return the appliance + * @exception EngineRuntimeException if a registration error occurs */ - void register( String path ) throws Exception; + void register( String path ) throws EngineRuntimeException; /** * Create a new appliance. 1.1 avalon-sandbox/assembly/src/java/org/apache/avalon/assembly/lifecycle/ContextHandler.java Index: ContextHandler.java =================================================================== /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.avalon.assembly.lifecycle; import java.util.Map; import java.lang.reflect.Constructor; import java.util.HashMap; import org.apache.avalon.framework.context.Contextualizable; import org.apache.avalon.framework.context.Context; import org.apache.avalon.framework.context.DefaultContext; import org.apache.avalon.framework.context.ContextException; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.assembly.appliance.Appliance; import org.apache.avalon.meta.model.Entry; import org.apache.avalon.meta.model.Import; import org.apache.avalon.meta.model.Profile; import org.apache.avalon.meta.model.ContextDirective; import org.apache.avalon.meta.info.ContextDescriptor; import org.apache.avalon.meta.info.EntryDescriptor; import org.apache.avalon.meta.info.ExtensionDescriptor; /** * The context service provides support for the contextualization of a * supplied component instance relative to the criteria establihsed under a * supplied appliance. * * @author <a href="mailto:avalon-dev@jakarta.apache.org">Avalon Development Team</a> * @version $Revision: 1.1 $ $Date: 2002/11/30 14:47:51 $ */ public class ContextHandler extends AbstractLogEnabled implements Contextualizable { //============================================================== // state //============================================================== private Context m_context; private ClassLoader m_classloader; //============================================================== // Contextualizable //============================================================== /** * <p>Application of a runtime context to this appliance. * The supplied context contains standard and container specific context * entries and may be used by the context service in establish the * context to apply to components.</p> * @param context the containerment context */ public void contextualize( Context context ) throws ContextException { m_context = context; m_classloader = (ClassLoader) context.get( "assembly:classloader" ); } //============================================================== // utilities //============================================================== /** * Internal utility to construct a context instance using a descriptor, directive and source * context instances. * * @param descriptors the descriptor containing the context dependency declarations * @param directive an optional context directive containing import and context value * creation parameters * @param context a supplimentary context object to used during value resolution * @return a context object containing only those context entries desribed under the * supplied descriptor * @exception Exception if a required context value cannot be resolved or an error * occurs during context value creation */ protected Context buildContext( ContextDescriptor descriptors, ContextDirective directive, Context context ) throws Exception { Map map = new HashMap(); Context result; if( directive != null ) { final String classname = directive.getClassname(); Class clazz; try { clazz = m_classloader.loadClass( classname ); } catch( ClassNotFoundException cnfe ) { throw new ContextException( "Could not find context class " + classname, cnfe ); } try { Constructor constructor = clazz.getConstructor( new Class[]{Map.class, Context.class} ); result = (Context)constructor.newInstance( new Object[]{map, null} ); } catch( Throwable e ) { throw new ContextException( "Unexpected exception while creating context form " + classname, e ); } } else { result = new DefaultContext( map ); } EntryDescriptor[] entries = descriptors.getEntrys(); for( int i = 0; i < entries.length; i++ ) { EntryDescriptor entry = entries[ i ]; String key = entry.getKey(); // // if the entry is already in the supplied context then use it // Object object = getContextValue( context, key ); // // If the context value is unresolved, try to handle resolution // using an import directive supplied under the directive // if( object == null ) { // // check if the profile declares an import directive // for the context // if( directive != null ) { Import imp = directive.getImport( key ); if( imp != null ) { String name = imp.getImportName(); object = getContextValue( context, name ); if( object == null ) { final String error = "Import directive for key: " + key + " via name: " + name + " cannot be resolved."; getLogger().warn( error ); } } // // if the context value is unresolved, try to construct a context // value using an entry constructor directive // if( object == null ) { // // check if the directive declares a context value constructor // Entry ent = directive.getEntry( key ); if( ent != null ) { object = ent.getValue( m_classloader, map ); } } } } // // finally, if the object is still null, and its not optional, then // throw an exception, otherwise, add the object to the context // if( object != null ) { try { boolean ok = objectImplementsType( object, entry.getType() ); if( ok ) { map.put( key, object ); } else { final String error = "Object resolved for the key '" + key + "' of class '" + object.getClass().getName() + "' does not implement the type '" + entry.getType(); throw new ContextException( error ); } } catch( ClassNotFoundException cnfe ) { final String error = "Context criteria for the key '" + key + "' specifies an unknown type '" + entry.getType() + "'."; throw new ContextException( error ); } } else { if( entry.isRequired() ) { final String error = "Unable to resolve a context value for the entry: '" + key + "' type: " + entry.getType(); throw new ContextException( error ); } } } if( result instanceof DefaultContext ) { ( (DefaultContext)result ).makeReadOnly(); } return result; } /** * Create a new Context for an extension. * * @param extension the extension descriptor * @param context a supplimentary context used during import resolution * @return a new Context for service * @throws Exception if unable to create context */ protected Context createContext( ExtensionDescriptor extension, Context context ) throws Exception { ContextDescriptor descriptor = extension.getContext(); return buildContext( descriptor, null, context ); } /** * Internal utility to get a context value or null if the context key * is unknown. * @param context the context object * @param key the context key to lookup * @return the context value derived from the key or null if the key is unknown */ protected Object getContextValue( Context context, String key ) { if( context == null ) { return null; } try { return context.get( key ); } catch( ContextException e ) { return null; } } /** * 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 */ protected boolean objectImplementsType( final Object value, final String type ) throws ClassNotFoundException { if( type == null ) { throw new NullPointerException( "type" ); } if( value == null ) { throw new NullPointerException( "value" ); } final Class clazz = value.getClass(); final Class typeClass = m_classloader.loadClass( type ); return typeClass.isAssignableFrom( clazz ); } } 1.2 +36 -18 avalon-sandbox/assembly/src/test/org/apache/avalon/assembly/engine/EngineTestCase.java Index: EngineTestCase.java =================================================================== RCS file: /home/cvs/avalon-sandbox/assembly/src/test/org/apache/avalon/assembly/engine/EngineTestCase.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- EngineTestCase.java 29 Nov 2002 13:24:45 -0000 1.1 +++ EngineTestCase.java 30 Nov 2002 14:47:51 -0000 1.2 @@ -51,25 +51,40 @@ } /** - * Test a component with custom context type and profile based import and entry creation directives. + * Test a component with custom context type and profile based import and + * entry creation directives and no service dependencies. */ public void testBasicComponent() { - final String classname = "org.apache.avalon.playground.BasicComponent"; + // + // register the component types with the engine - this will result in the + // automatic loading of the type defintion and the any packaged profiles + // - ReferenceDescriptor reference = - new ReferenceDescriptor( - "org.apache.avalon.playground.BasicService", - Version.getVersion( "1.1" ) ); + try + { + final String classname = "org.apache.avalon.playground.BasicComponent"; + m_engine.register( classname ); + assertTrue( true ); + } + catch( Throwable e ) + { + ExceptionHelper.printException( "Registration failure.", e, this, true ); + assertTrue( false ); + } + + // + // get a full assembled and verified appliance from the engine using + // a service classname and version + // + Appliance appliance = null; + final String servicename = "org.apache.avalon.playground.BasicService"; DependencyDescriptor dependency = - new DependencyDescriptor( "test", reference ); + new DependencyDescriptor( "test", servicename, Version.getVersion( "1.1" ) ); - Appliance appliance = null; try { - m_engine.register( classname ); - assertTrue( true ); appliance = m_engine.resolve( dependency ); assertTrue( appliance != null ); } @@ -79,6 +94,11 @@ assertTrue( false ); } + // + // request an instance of a service provided by the appliance + // that the engine returned to us + // + try { Object object = appliance.access( dependency ); @@ -92,7 +112,7 @@ } /** - * Test a component with custom context type and profile based import and entry creation directives. + * Test a component with service and extension depedencies. */ public void testSimpleComponent() { @@ -101,13 +121,10 @@ final String exploiter = "org.apache.avalon.playground.ExploitationManager"; final String demo = "org.apache.avalon.playground.DemoManager"; - ReferenceDescriptor reference = - new ReferenceDescriptor( - "org.apache.avalon.playground.SimpleService", - Version.getVersion( "1.1" ) ); + final String service = "org.apache.avalon.playground.SimpleService"; DependencyDescriptor dependency = - new DependencyDescriptor( "test", reference ); + new DependencyDescriptor( "test", service, Version.getVersion( "1.1" ) ); Appliance appliance = null; try @@ -117,12 +134,13 @@ m_engine.register( demo ); m_engine.register( simple ); assertTrue( true ); + appliance = m_engine.resolve( dependency ); assertTrue( appliance != null ); } catch( Throwable e ) { - System.out.println("failed to resolve : " + reference ); + System.out.println("failed to resolve : " + dependency ); ExceptionHelper.printException( "Resolution failure.", e, appliance, true ); assertTrue( false ); } @@ -134,7 +152,7 @@ } catch( Throwable e ) { - System.out.println("appliance access failure : " + reference ); + System.out.println("appliance access failure : " + dependency ); ExceptionHelper.printException( "Access failure.", e, appliance, true ); assertTrue( false ); }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>