Author: niclas Date: Tue Sep 14 14:04:40 2004 New Revision: 46037 Added: avalon/trunk/runtime/composition/api/src/java/org/apache/avalon/composition/model/CyclicDependencyException.java (contents, props changed) avalon/trunk/runtime/composition/impl/etc/test/cyclicdeps.xml (contents, props changed) avalon/trunk/runtime/composition/impl/src/test/org/apache/avalon/composition/model/impl/CyclicDepsTestCase.java (contents, props changed) avalon/trunk/runtime/test/testcyclic/ avalon/trunk/runtime/test/testcyclic/build.properties (contents, props changed) avalon/trunk/runtime/test/testcyclic/build.xml (contents, props changed) avalon/trunk/runtime/test/testcyclic/src/ avalon/trunk/runtime/test/testcyclic/src/main/ avalon/trunk/runtime/test/testcyclic/src/main/org/ avalon/trunk/runtime/test/testcyclic/src/main/org/apache/ avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/ avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/ avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/ avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/A.java (contents, props changed) avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/B.java (contents, props changed) avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/TestCyclicA.java (contents, props changed) avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/TestCyclicB.java (contents, props changed) Modified: avalon/trunk/runtime/build.properties avalon/trunk/runtime/build.xml avalon/trunk/runtime/composition/api/src/java/org/apache/avalon/composition/model/DependencyGraph.java avalon/trunk/runtime/composition/impl/build.properties avalon/trunk/runtime/composition/impl/src/java/org/apache/avalon/composition/model/impl/DefaultContainmentModelAssemblyHelper.java avalon/trunk/runtime/composition/impl/src/test/org/apache/avalon/composition/model/test/AbstractTestCase.java avalon/trunk/runtime/index.xml Log: Patch sent in by Peter Neubauer that detects cyclic dependencies in the composition model.
Modified: avalon/trunk/runtime/build.properties ============================================================================== --- avalon/trunk/runtime/build.properties (original) +++ avalon/trunk/runtime/build.properties Tue Sep 14 14:04:40 2004 @@ -1,2 +1,2 @@ project.system = ../central/system -project.home = . \ No newline at end of file +project.home = . Modified: avalon/trunk/runtime/build.xml ============================================================================== --- avalon/trunk/runtime/build.xml (original) +++ avalon/trunk/runtime/build.xml Tue Sep 14 14:04:40 2004 @@ -1,5 +1,4 @@ <?xml version="1.0" encoding="UTF-8" ?> - <project name="runtime" default="default" basedir="." xmlns:x="antlib:org.apache.avalon.tools"> <property file="build.properties"/> Added: avalon/trunk/runtime/composition/api/src/java/org/apache/avalon/composition/model/CyclicDependencyException.java ============================================================================== --- (empty file) +++ avalon/trunk/runtime/composition/api/src/java/org/apache/avalon/composition/model/CyclicDependencyException.java Tue Sep 14 14:04:40 2004 @@ -0,0 +1,57 @@ +/* + * Copyright 2004 Apache Software Foundation + * 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.apache.avalon.composition.model; + +/** + * indicates a cyclic dependency problem in e.g. the assembly of models. + */ +public class CyclicDependencyException extends RuntimeException +{ + + /** + * Default contructor + */ + public CyclicDependencyException() + { + super(); + } + + /** + * @see RuntimeException + */ + public CyclicDependencyException( String arg0 ) + { + super( arg0 ); + } + + /** + * @see RuntimeException + */ + public CyclicDependencyException( Throwable arg0 ) + { + super( arg0 ); + } + + /** + * @see RuntimeException + */ + public CyclicDependencyException( String arg0, Throwable arg1 ) + { + super( arg0, arg1 ); + } + +} Modified: avalon/trunk/runtime/composition/api/src/java/org/apache/avalon/composition/model/DependencyGraph.java ============================================================================== --- avalon/trunk/runtime/composition/api/src/java/org/apache/avalon/composition/model/DependencyGraph.java (original) +++ avalon/trunk/runtime/composition/api/src/java/org/apache/avalon/composition/model/DependencyGraph.java Tue Sep 14 14:04:40 2004 @@ -29,25 +29,28 @@ public class DependencyGraph { /** - * Parent Map. Components in the parent - * Map are potential Providers for services - * if no model in the current graph satisfies - * a dependency. + * Parent Map. Components in the parent Map are potential Providers for + * services if no model in the current graph satisfies a dependency. */ private final DependencyGraph m_parent; /** - * The set of models declared by the container as available. - * Used when searching for providers/consumers. + * The set of models declared by the container as available. Used when + * searching for providers/consumers. */ private final ArrayList m_models = new ArrayList(); /** - * The child [EMAIL PROTECTED] DependencyGraph} objects. - * Possible consumers of services in this assembly. + * The child [EMAIL PROTECTED] DependencyGraph}objects. Possible consumers of services + * in this assembly. */ private final ArrayList m_children = new ArrayList(); + /** + * holds the models assembled in order to track circular deps etc. + */ + private ArrayList m_modelsInProgress = new ArrayList(); + /** * Creation of a new empty dependency graph. */ @@ -57,11 +60,12 @@ } /** - * Creation of a new dependecy graph holding a reference to a parent - * graph. DeploymentModel instances in the parent graph are potential providers - * for services if no model in current assembly satisfies a dependency. - * - * @param parent the parent graph + * Creation of a new dependecy graph holding a reference to a parent graph. + * DeploymentModel instances in the parent graph are potential providers for + * services if no model in current assembly satisfies a dependency. + * + * @param parent + * the parent graph */ public DependencyGraph( final DependencyGraph parent ) { @@ -70,8 +74,9 @@ /** * Addition of a consumer dependency graph. - * - * @param child the child map + * + * @param child + * the child map */ public void addChild( final DependencyGraph child ) { @@ -80,8 +85,9 @@ /** * Removal of a consumer dependency graph. - * - * @param child the child map + * + * @param child + * the child map */ public void removeChild( final DependencyGraph child ) { @@ -90,8 +96,9 @@ /** * Add a model to current dependency graph. - * - * @param model the model to add to the graph + * + * @param model + * the model to add to the graph */ public void add( final DeploymentModel model ) { @@ -103,8 +110,9 @@ /** * Remove a model from the dependency graph. - * - * @param model the model to remove + * + * @param model + * the model to remove */ public void remove( final DeploymentModel model ) { @@ -112,11 +120,10 @@ } /** - * Get the serilized graph of [EMAIL PROTECTED] DeploymentModel} objects - * required when starting up the target. This makes sure - * that all providers are established before their coresponding - * consumers in the graph. - * + * Get the serilized graph of [EMAIL PROTECTED] DeploymentModel}objects required when + * starting up the target. This makes sure that all providers are + * established before their coresponding consumers in the graph. + * * @return the ordered list of models */ public DeploymentModel[] getStartupGraph() @@ -125,20 +132,18 @@ { return walkGraph( true ); } - catch( Throwable e ) + catch ( Throwable e ) { - final String error = - "Unexpect error while resolving startup graph."; + final String error = "Unexpect error while resolving startup graph."; throw new ModelRuntimeException( error, e ); } } /** - * Get the serilized graph of [EMAIL PROTECTED] DeploymentModel} instances - * required when shutting down all the components. This makes - * sure that all consumer shutdown actions occur before their - * coresponding providers in graph. - * + * Get the serilized graph of [EMAIL PROTECTED] DeploymentModel}instances required + * when shutting down all the components. This makes sure that all consumer + * shutdown actions occur before their coresponding providers in graph. + * * @return the ordered list of model instances */ public DeploymentModel[] getShutdownGraph() @@ -146,8 +151,8 @@ try { return walkGraph( false ); - } - catch( Throwable e ) + } + catch ( Throwable e ) { final String error = "Unexpect error while resolving shutdown graph."; throw new ModelRuntimeException( error, e ); @@ -155,34 +160,38 @@ } /** - * Get the serilized graph of [EMAIL PROTECTED] DeploymentModel} instances - * that use services of the specified model. - * - * @param model the model + * Get the serilized graph of [EMAIL PROTECTED] DeploymentModel}instances that use + * services of the specified model. + * + * @param model + * the model * @return the ordered list of consumer model instances */ public DeploymentModel[] getConsumerGraph( final DeploymentModel model ) { - if( m_parent != null ) return m_parent.getConsumerGraph( model ); - + if( m_parent != null ) + { + return m_parent.getConsumerGraph( model ); + } try { DeploymentModel[] graph = getComponentGraph( model, false ); return referencedModels( model, graph ); - } - catch( Throwable e ) + } + catch ( Throwable e ) { - final String error = - "Unexpect error while resolving consumer graph for model: " + model; + final String error = "Unexpect error while resolving consumer graph for model: " + + model; throw new ModelRuntimeException( error, e ); } } /** - * Get the serilized graph of [EMAIL PROTECTED] DeploymentModel} istances - * that provide specified model with services. - * - * @param model the model + * Get the serilized graph of [EMAIL PROTECTED] DeploymentModel}istances that provide + * specified model with services. + * + * @param model + * the model * @return the ordered list of providers */ public DeploymentModel[] getProviderGraph( final DeploymentModel model ) @@ -190,11 +199,11 @@ try { return referencedModels( model, getComponentGraph( model, true ) ); - } - catch( Throwable e ) + } + catch ( Throwable e ) { - final String error = - "Unexpect error while resolving provider graph for: " + model; + final String error = "Unexpect error while resolving provider graph for: " + + model; throw new ModelRuntimeException( error, e ); } } @@ -202,11 +211,11 @@ /** * Return an model array that does not include the provided model. */ - private DeploymentModel[] referencedModels( - final DeploymentModel model, DeploymentModel[] models ) + private DeploymentModel[] referencedModels( final DeploymentModel model, + DeploymentModel[] models ) { ArrayList list = new ArrayList(); - for( int i = 0; i < models.length; i++ ) + for ( int i = 0; i < models.length; i++ ) { if( !models[i].equals( model ) ) { @@ -218,31 +227,31 @@ /** * Get the graph of a single model. - * - * @param model the target model - * @param providers true if traversing providers, false if consumers - * @return the list of models + * + * @param model + * the target model + * @param providers + * true if traversing providers, false if consumers + * @return the list of models */ - private DeploymentModel[] getComponentGraph( - final DeploymentModel model, final boolean providers ) + private DeploymentModel[] getComponentGraph( final DeploymentModel model, + final boolean providers ) { final ArrayList result = new ArrayList(); - visitcomponent( model, - providers, - new ArrayList(), - result ); + visitcomponent( model, providers, new ArrayList(), result ); final DeploymentModel[] returnValue = new DeploymentModel[result.size()]; return (DeploymentModel[]) 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 direction true if forward dependencys traced, false if - * dependencies reversed + * 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 direction + * true if forward dependencys traced, false if dependencies + * reversed * @return the ordered model list */ private DeploymentModel[] walkGraph( final boolean direction ) @@ -251,87 +260,109 @@ final ArrayList done = new ArrayList(); final int size = m_models.size(); - for( int i = 0; i < size; i++ ) + for ( int i = 0; i < size; i++ ) { - final DeploymentModel model = - (DeploymentModel) m_models.get( i ); + final DeploymentModel model = (DeploymentModel) m_models.get( i ); - visitcomponent( model, - direction, - done, - result ); + visitcomponent( model, direction, done, result ); } final DeploymentModel[] returnValue = new DeploymentModel[result.size()]; + if( m_modelsInProgress.size() != 0 ) + { + throw new RuntimeException( "there where non-assembled models: " + + m_modelsInProgress ); + } return (DeploymentModel[]) result.toArray( returnValue ); } /** * Visit a model when traversing dependencies. - * - * @param model the model - * @param direction 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 + * + * @param model + * the model + * @param direction + * 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 DeploymentModel model, - final boolean direction, - final ArrayList done, - final ArrayList order ) + final boolean direction, final ArrayList done, final ArrayList order ) { + //if circular dependency + if( ( model instanceof ComponentModel ) + && m_modelsInProgress.contains( model ) ) + { + throw new CyclicDependencyException( + "Cyclic dependency encoutered in assembly:" + model + + "is already in progress stack: " + + m_modelsInProgress ); + } //If already visited this model return - if( done.contains( model ) ) return; - + if( done.contains( model ) ) + { + return; + } done.add( model ); - + m_modelsInProgress.add( model ); if( direction ) { visitProviders( model, done, order ); - } + + } else { visitConsumers( model, done, order ); } + m_modelsInProgress.remove( model ); order.add( model ); } /** - * Traverse graph of components that provide services to - * the specified model. - * - * @param model the model + * Traverse graph of components that provide services to the specified + * model. + * + * @param model + * the model to be checked + * @param done + * the list of already checked models + * @param order + * the order */ private void visitProviders( final DeploymentModel model, - final ArrayList done, - final ArrayList order ) + final ArrayList done, final ArrayList order ) { DeploymentModel[] providers = model.getProviders(); - for( int i = (providers.length - 1); i > -1; i-- ) + for ( int i = ( providers.length - 1 ); i > -1; i-- ) { visitcomponent( providers[i], true, done, order ); } } /** - * Traverse all consumers of a model. I.e. all models that use - * service provided by the supplied model. - * - * @param model the DeploymentModel + * Traverse all consumers of a model. I.e. all models that use service + * provided by the supplied model. + * + * @param model + * the model to be checked + * @param done + * the list of already checked models + * @param order + * the order */ private void visitConsumers( final DeploymentModel model, - final ArrayList done, - final ArrayList order ) + final ArrayList done, final ArrayList order ) { final int size = m_models.size(); - for( int i = 0; i < size; i++ ) + for ( int i = 0; i < size; i++ ) { - final DeploymentModel other = - (DeploymentModel) m_models.get( i ); + final DeploymentModel other = (DeploymentModel) m_models.get( i ); final DeploymentModel[] providers = other.getProviders(); - for( int j = 0; j < providers.length; j++ ) + for ( int j = 0; j < providers.length; j++ ) { DeploymentModel provider = providers[j]; if( provider.equals( model ) ) @@ -341,7 +372,7 @@ } } final int childCount = m_children.size(); - for( int i = 0; i < childCount; i++ ) + for ( int i = 0; i < childCount; i++ ) { final DependencyGraph map = (DependencyGraph) m_children.get( i ); map.visitConsumers( model, done, order ); Modified: avalon/trunk/runtime/composition/impl/build.properties ============================================================================== --- avalon/trunk/runtime/composition/impl/build.properties (original) +++ avalon/trunk/runtime/composition/impl/build.properties Tue Sep 14 14:04:40 2004 @@ -1,4 +1,4 @@ project.name = avalon-composition-impl project.src.main = java project.home = ../.. -project.system = ../../../central/system +project.system = ../../../central/system \ No newline at end of file Added: avalon/trunk/runtime/composition/impl/etc/test/cyclicdeps.xml ============================================================================== --- (empty file) +++ avalon/trunk/runtime/composition/impl/etc/test/cyclicdeps.xml Tue Sep 14 14:04:40 2004 @@ -0,0 +1,11 @@ + +<container> +<classloader> + <classpath> + <artifact>artifact:jar:avalon/test/avalon-test-testcyclic</artifact> + </classpath> + </classloader> + <container name="sub"> + <component name="test-a" class="org.apache.avalon.test.testcyclic.TestCyclicA"/> + </container> +</container> Modified: avalon/trunk/runtime/composition/impl/src/java/org/apache/avalon/composition/model/impl/DefaultContainmentModelAssemblyHelper.java ============================================================================== --- avalon/trunk/runtime/composition/impl/src/java/org/apache/avalon/composition/model/impl/DefaultContainmentModelAssemblyHelper.java (original) +++ avalon/trunk/runtime/composition/impl/src/java/org/apache/avalon/composition/model/impl/DefaultContainmentModelAssemblyHelper.java Tue Sep 14 14:04:40 2004 @@ -17,6 +17,8 @@ package org.apache.avalon.composition.model.impl; +import java.util.HashMap; +import java.util.Hashtable; import java.util.List; import java.util.ArrayList; @@ -61,71 +63,30 @@ // static //------------------------------------------------------------------- - private static final Resources REZ = - ResourceManager.getPackageResources( - DefaultContainmentModelAssemblyHelper.class ); + private static final Resources REZ = ResourceManager + .getPackageResources( DefaultContainmentModelAssemblyHelper.class ); //------------------------------------------------------------------- // immutable state //------------------------------------------------------------------- private final ContainmentContext m_context; + private final DefaultContainmentModel m_model; //------------------------------------------------------------------- // constructor //------------------------------------------------------------------- - public DefaultContainmentModelAssemblyHelper( - ContainmentContext context, DefaultContainmentModel model ) + public DefaultContainmentModelAssemblyHelper( ContainmentContext context, + DefaultContainmentModel model ) { m_context = context; m_model = model; } - //------------------------------------------------------------------- - // implementation - //------------------------------------------------------------------- - - /** - * Assemble a target model during which all deployment and runtime - * dependencies are assigned a provider model. - * - * @param model the target model to be assembled - * @param subject the model requesting the assembly - */ - public void assembleModel( DeploymentModel model, List subjects ) - throws AssemblyException - { - if( null == model ) - { - throw new NullPointerException( "model" ); - } - if( null == subjects ) - { - throw new NullPointerException( "subjects" ); - } - if( subjects.contains( model ) ) - { - return; - } - if( model.isAssembled() ) - { - return; - } - - if( model instanceof ComponentModel ) - { - assembleComponent( (ComponentModel) model, subjects ); - } - else - { - ContainmentModel containment = (ContainmentModel) model; - containment.assemble( subjects ); - } - } - - private void assembleComponent( ComponentModel model, List subjects ) throws AssemblyException + private void assembleComponent( ComponentModel model, List subjects ) + throws AssemblyException { ModelRepository repository = m_context.getModelRepository(); @@ -141,25 +102,23 @@ { if( null == context.getProvider() ) { - StagedDeliveryDescriptor phased = - (StagedDeliveryDescriptor) delivery; + StagedDeliveryDescriptor phased = (StagedDeliveryDescriptor) delivery; Class clazz = phased.getDeliveryInterfaceClass(); try { subjects.add( model ); - StageDescriptor stage = - new StageDescriptor( clazz.getName() ); - DeploymentModel provider = - findExtensionProvider( repository, stage, subjects ); + StageDescriptor stage = new StageDescriptor( clazz + .getName() ); + DeploymentModel provider = findExtensionProvider( + repository, stage, subjects ); context.setProvider( provider ); } - catch( Throwable e ) + catch ( Throwable e ) { - final String error = - "Unable to assemble component: " - + model - + " due to a component context phase handler establishment failure."; + final String error = "Unable to assemble component: " + + model + + " due to a component context phase handler establishment failure."; throw new AssemblyException( error, e ); } finally @@ -175,7 +134,7 @@ // StageModel[] stages = model.getStageModels(); - for( int i=0; i<stages.length; i++ ) + for ( int i = 0; i < stages.length; i++ ) { StageModel stage = stages[i]; if( null == stage.getProvider() ) @@ -183,16 +142,15 @@ try { subjects.add( model ); - DeploymentModel provider = - findExtensionProvider( repository, stage, subjects ); + DeploymentModel provider = findExtensionProvider( + repository, stage, subjects ); stage.setProvider( provider ); } - catch( Throwable e ) + catch ( Throwable e ) { - final String error = - "Unable to assemble component: " - + model - + " due to a component extension handler establishment failure."; + final String error = "Unable to assemble component: " + + model + + " due to a component extension handler establishment failure."; throw new AssemblyException( error, e ); } finally @@ -207,7 +165,7 @@ // DependencyModel[] dependencies = model.getDependencyModels(); - for( int i=0; i < dependencies.length; i++ ) + for ( int i = 0; i < dependencies.length; i++ ) { DependencyModel dependency = dependencies[i]; if( null == dependency.getProvider() ) @@ -215,17 +173,17 @@ try { subjects.add( model ); - DeploymentModel provider = - findDependencyProvider( repository, dependency, subjects ); + DeploymentModel provider = findDependencyProvider( + repository, dependency, subjects ); dependency.setProvider( provider ); } - catch( Throwable e ) + catch ( Throwable e ) { if( dependency.getDependency().isRequired() ) { - final String error = - "Unable to assemble component: " + model - + " due to a service provider establishment failure."; + final String error = "Unable to assemble component: " + + model + + " due to a service provider establishment failure."; throw new AssemblyException( error, e ); } } @@ -237,47 +195,102 @@ } } - private DeploymentModel findDependencyProvider( - ModelRepository repository, DependencyModel dependency, List subjects ) - throws AssemblyException + //------------------------------------------------------------------- + // implementation + //------------------------------------------------------------------- + + /** + * Assemble a target model during which all deployment and runtime + * dependencies are assigned a provider model. + * + * @param model + * the target model to be assembled + * @param subject + * the model requesting the assembly + */ + public void assembleModel( DeploymentModel model, List subjects ) + throws AssemblyException { - String path = dependency.getPath(); - if( null != path ) + if( null == model ) { - DeploymentModel model = m_model.getModel( path ); - if( null == model ) - { - final String error = - "Could not locate a model at the address: [" - + path + "] in " + this + "."; - throw new AssemblyException( error ); - } - assembleModel( model, subjects ); - return model; + throw new NullPointerException( "model" ); + } + if( null == subjects ) + { + throw new NullPointerException( "subjects" ); + } + if( subjects.contains( model ) ) + { + return; + } + if( model.isAssembled() ) + { + return; + } + + if( model instanceof ComponentModel ) + { + assembleComponent( (ComponentModel) model, subjects ); } else { - return findDependencyProvider( - repository, dependency.getDependency(), subjects ); + ContainmentModel containment = (ContainmentModel) model; + containment.assemble( subjects ); + } + } + + /** + * @param dependency + * the dependency to check for + * @param subjects + * the subjects needing the dependency + * @throws AssemblyException + */ + private void checkCyclic( DeploymentModel dependency, List subjects ) + throws AssemblyException + { + if( subjects.contains( dependency ) ) + { + throw new AssemblyException( "Cyclic Dependency: " + dependency + + "is already in subject list " + subjects ); + } + } + + private DeploymentProfile[] findDependencyProfiles( + DependencyDescriptor dependency ) + { + TypeRepository repository = m_context.getClassLoaderModel() + .getTypeRepository(); + Type[] types = repository.getTypes( dependency ); + try + { + return getProfiles( repository, types ); + } + catch ( TypeUnknownException tue ) + { + // will not happen + final String error = "An irrational condition has occured."; + throw new ModelRuntimeException( error, tue ); } } DeploymentModel findDependencyProvider( DependencyDescriptor dependency ) - throws AssemblyException + throws AssemblyException { ArrayList list = new ArrayList(); ModelRepository repository = m_context.getModelRepository(); return findDependencyProvider( repository, dependency, list ); } - private DeploymentModel findDependencyProvider( - ModelRepository repository, DependencyDescriptor dependency, List subjects ) - throws AssemblyException + private DeploymentModel findDependencyProvider( ModelRepository repository, + DependencyDescriptor dependency, List subjects ) + throws AssemblyException { - DeploymentModel[] candidates = - repository.getCandidateProviders( dependency ); + DeploymentModel[] candidates = repository + .getCandidateProviders( dependency ); ModelSelector selector = new DefaultModelSelector(); DeploymentModel model = selector.select( candidates, dependency ); + //checkCyclic( model, subjects ); if( model != null ) { assembleModel( model, subjects ); @@ -285,64 +298,96 @@ } // - // otherwise, check for any packaged profiles that + // otherwise, check for any packaged profiles that // we could use to construct the model // DeploymentProfile[] profiles = findDependencyProfiles( dependency ); ProfileSelector profileSelector = new DefaultProfileSelector(); - DeploymentProfile profile = profileSelector.select( profiles, dependency ); - if( profile != null ) + DeploymentProfile profile = profileSelector.select( profiles, + dependency ); + if( profile != null ) { try { - DeploymentModel solution = m_model.createDeploymentModel( profile ); + DeploymentModel solution = m_model + .createDeploymentModel( profile ); assembleModel( solution, subjects ); m_model.addModel( solution ); return solution; } - catch( AssemblyException ae ) + catch ( AssemblyException ae ) { - final String error = - "Nested assembly failure while attempting to construct model" - + " for the profile: " + profile + " for the dependency: [" - + dependency + "]."; + final String error = "Nested assembly failure while attempting to construct model" + + " for the profile: " + + profile + + " for the dependency: [" + dependency + "]."; throw new AssemblyException( error, ae ); } - catch( ModelException me ) + catch ( ModelException me ) { - final String error = - "Nested model failure while attempting to add model" - + " for the profile: " + profile + " for the dependency: [" - + dependency + "]."; + final String error = "Nested model failure while attempting to add model" + + " for the profile: " + + profile + + " for the dependency: [" + dependency + "]."; throw new AssemblyException( error, me ); } } else { - final String error = - "Unable to locate a service provider for the dependency: [ " - + dependency + "]."; + final String error = "Unable to locate a service provider for the dependency: [ " + + dependency + "]."; throw new AssemblyException( error ); } } - DeploymentModel findServiceProvider( ReferenceDescriptor reference ) - throws AssemblyException + private DeploymentModel findDependencyProvider( ModelRepository repository, + DependencyModel dependency, List subjects ) + throws AssemblyException { - ArrayList list = new ArrayList(); - ModelRepository repository = m_context.getModelRepository(); - return findServiceProvider( repository, reference, list ); + String path = dependency.getPath(); + if( null != path ) + { + DeploymentModel model = m_model.getModel( path ); + if( null == model ) + { + final String error = "Could not locate a model at the address: [" + + path + "] in " + this + "."; + throw new AssemblyException( error ); + } + assembleModel( model, subjects ); + return model; + } + else + { + return findDependencyProvider( repository, dependency + .getDependency(), subjects ); + } + } + + private DeploymentProfile[] findExtensionProfiles( StageDescriptor stage ) + { + TypeRepository repository = m_context.getClassLoaderModel() + .getTypeRepository(); + Type[] types = repository.getTypes( stage ); + try + { + return getProfiles( repository, types ); + } + catch ( TypeUnknownException tue ) + { + // will not happen + final String error = "An irrational condition has occured."; + throw new ModelRuntimeException( error, tue ); + } } - private DeploymentModel findServiceProvider( - ModelRepository repository, ReferenceDescriptor reference, List subjects ) - throws AssemblyException + private DeploymentModel findExtensionProvider( ModelRepository repository, + StageDescriptor stage, List subjects ) throws AssemblyException { - DeploymentModel[] candidates = - repository.getCandidateProviders( reference ); + DeploymentModel[] candidates = repository.getCandidateProviders( stage ); ModelSelector selector = new DefaultModelSelector(); - DeploymentModel model = selector.select( candidates, reference ); + DeploymentModel model = selector.select( candidates, stage ); if( model != null ) { assembleModel( model, subjects ); @@ -350,52 +395,50 @@ } // - // otherwise, check for any packaged profiles that + // otherwise, check for any packaged profiles that // we could use to construct the model // - DeploymentProfile[] profiles = findServiceProfiles( reference ); + DeploymentProfile[] profiles = findExtensionProfiles( stage ); ProfileSelector profileSelector = new DefaultProfileSelector(); - DeploymentProfile profile = profileSelector.select( profiles, reference ); - if( profile != null ) + DeploymentProfile profile = profileSelector.select( profiles, stage ); + if( profile != null ) { try { - DeploymentModel solution = m_model.createDeploymentModel( profile ); + DeploymentModel solution = m_model + .createDeploymentModel( profile ); assembleModel( solution, subjects ); m_model.addModel( solution ); return solution; } - catch( AssemblyException ae ) + catch ( AssemblyException ae ) { - final String error = - "Nested assembly failure while attempting to construct model" - + " for the profile: [" + profile + "] for the reference: [" - + reference + "]."; + final String error = "Nested assembly failure while attempting to construct model" + + " for the extension profile: [" + + profile + + "] for the stage dependency: [" + stage + "]."; throw new AssemblyException( error, ae ); } - catch( ModelException me ) + catch ( ModelException me ) { - final String error = - "Nested model failure while attempting to add model" - + " for the profile: " + profile + " for the reference: [" - + reference + "]."; + final String error = "Nested model failure while attempting to add model" + + " for the extension profile: " + + profile + + " for the stage dependency: [" + stage + "]."; throw new AssemblyException( error, me ); } } else { - final String error = - "Unable to locate a service provider for the reference: [ " - + reference + "]."; + final String error = "Unable to locate a extension provider for the stage: [ " + + stage + "]."; throw new ProviderNotFoundException( error ); } } - - private DeploymentModel findExtensionProvider( - ModelRepository repository, StageModel stage, List subjects ) - throws AssemblyException + private DeploymentModel findExtensionProvider( ModelRepository repository, + StageModel stage, List subjects ) throws AssemblyException { String path = stage.getPath(); if( null != path ) @@ -403,9 +446,8 @@ DeploymentModel model = m_model.getModel( path ); if( null == model ) { - final String error = - "Could not locate a model at the address: [" - + path + "] in " + this + "."; + final String error = "Could not locate a model at the address: [" + + path + "] in " + this + "."; throw new AssemblyException( error ); } assembleModel( model, subjects ); @@ -413,18 +455,37 @@ } else { - return findExtensionProvider( repository, stage.getStage(), subjects ); + return findExtensionProvider( repository, stage.getStage(), + subjects ); + } + } + + private DeploymentProfile[] findServiceProfiles( + ReferenceDescriptor reference ) + { + TypeRepository repository = m_context.getClassLoaderModel() + .getTypeRepository(); + Type[] types = repository.getTypes( reference ); + try + { + return getProfiles( repository, types ); + } + catch ( TypeUnknownException tue ) + { + // will not happen + final String error = "An irrational condition has occured."; + throw new ModelRuntimeException( error, tue ); } } - private DeploymentModel findExtensionProvider( - ModelRepository repository, StageDescriptor stage, List subjects ) - throws AssemblyException + private DeploymentModel findServiceProvider( ModelRepository repository, + ReferenceDescriptor reference, List subjects ) + throws AssemblyException { - DeploymentModel[] candidates = - repository.getCandidateProviders( stage ); + DeploymentModel[] candidates = repository + .getCandidateProviders( reference ); ModelSelector selector = new DefaultModelSelector(); - DeploymentModel model = selector.select( candidates, stage ); + DeploymentModel model = selector.select( candidates, reference ); if( model != null ) { assembleModel( model, subjects ); @@ -432,107 +493,65 @@ } // - // otherwise, check for any packaged profiles that + // otherwise, check for any packaged profiles that // we could use to construct the model // - DeploymentProfile[] profiles = findExtensionProfiles( stage ); + DeploymentProfile[] profiles = findServiceProfiles( reference ); ProfileSelector profileSelector = new DefaultProfileSelector(); - DeploymentProfile profile = profileSelector.select( profiles, stage ); - if( profile != null ) + DeploymentProfile profile = profileSelector + .select( profiles, reference ); + if( profile != null ) { try { - DeploymentModel solution = m_model.createDeploymentModel( profile ); + DeploymentModel solution = m_model + .createDeploymentModel( profile ); assembleModel( solution, subjects ); m_model.addModel( solution ); return solution; } - catch( AssemblyException ae ) + catch ( AssemblyException ae ) { - final String error = - "Nested assembly failure while attempting to construct model" - + " for the extension profile: [" + profile - + "] for the stage dependency: [" - + stage + "]."; + final String error = "Nested assembly failure while attempting to construct model" + + " for the profile: [" + + profile + + "] for the reference: [" + reference + "]."; throw new AssemblyException( error, ae ); } - catch( ModelException me ) + catch ( ModelException me ) { - final String error = - "Nested model failure while attempting to add model" - + " for the extension profile: " + profile - + " for the stage dependency: [" - + stage + "]."; + final String error = "Nested model failure while attempting to add model" + + " for the profile: " + + profile + + " for the reference: [" + reference + "]."; throw new AssemblyException( error, me ); } } else { - final String error = - "Unable to locate a extension provider for the stage: [ " - + stage + "]."; + final String error = "Unable to locate a service provider for the reference: [ " + + reference + "]."; throw new ProviderNotFoundException( error ); } } - private DeploymentProfile[] findExtensionProfiles( StageDescriptor stage ) - { - TypeRepository repository = m_context.getClassLoaderModel().getTypeRepository(); - Type[] types = repository.getTypes( stage ); - try - { - return getProfiles( repository, types ); - } - catch( TypeUnknownException tue ) - { - // will not happen - final String error = "An irrational condition has occured."; - throw new ModelRuntimeException( error, tue ); - } - } - - private DeploymentProfile[] findDependencyProfiles( DependencyDescriptor dependency ) - { - TypeRepository repository = m_context.getClassLoaderModel().getTypeRepository(); - Type[] types = repository.getTypes( dependency ); - try - { - return getProfiles( repository, types ); - } - catch( TypeUnknownException tue ) - { - // will not happen - final String error = "An irrational condition has occured."; - throw new ModelRuntimeException( error, tue ); - } - } - - private DeploymentProfile[] findServiceProfiles( ReferenceDescriptor reference ) + DeploymentModel findServiceProvider( ReferenceDescriptor reference ) + throws AssemblyException { - TypeRepository repository = m_context.getClassLoaderModel().getTypeRepository(); - Type[] types = repository.getTypes( reference ); - try - { - return getProfiles( repository, types ); - } - catch( TypeUnknownException tue ) - { - // will not happen - final String error = "An irrational condition has occured."; - throw new ModelRuntimeException( error, tue ); - } + ArrayList list = new ArrayList(); + ModelRepository repository = m_context.getModelRepository(); + return findServiceProvider( repository, reference, list ); } - private DeploymentProfile[] getProfiles( TypeRepository repository, Type[] types ) - throws TypeUnknownException + private DeploymentProfile[] getProfiles( TypeRepository repository, + Type[] types ) throws TypeUnknownException { ArrayList list = new ArrayList(); - for( int i=0; i<types.length; i++ ) + for ( int i = 0; i < types.length; i++ ) { - DeploymentProfile[] profiles = - repository.getProfiles( types[i] ); - for( int j=0; j<profiles.length; j++ ) + DeploymentProfile[] profiles = repository.getProfiles( types[i] ); + for ( int j = 0; j < profiles.length; j++ ) { list.add( profiles[j] ); } Added: avalon/trunk/runtime/composition/impl/src/test/org/apache/avalon/composition/model/impl/CyclicDepsTestCase.java ============================================================================== --- (empty file) +++ avalon/trunk/runtime/composition/impl/src/test/org/apache/avalon/composition/model/impl/CyclicDepsTestCase.java Tue Sep 14 14:04:40 2004 @@ -0,0 +1,112 @@ +/* + * Copyright 2004 Apache Software Foundation + * 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.apache.avalon.composition.model.impl; + +import org.apache.avalon.composition.model.AssemblyException; +import org.apache.avalon.composition.model.ContainmentModel; +import org.apache.avalon.composition.model.CyclicDependencyException; +import org.apache.avalon.composition.model.DeploymentModel; +import org.apache.avalon.composition.model.ModelRuntimeException; +import org.apache.avalon.composition.model.test.AbstractTestCase; +import org.apache.avalon.framework.logger.ConsoleLogger; + +/** + * checks that cyclic dependencies in the service declarations are properlly + * found and notified. + */ +public class CyclicDepsTestCase extends AbstractTestCase +{ + //------------------------------------------------------- + // constructor + //------------------------------------------------------- + /** + * the contructor + */ + public CyclicDepsTestCase() + { + super(); + } + + /** + * @param container + * the container to be printed + */ + private void printStartup( ContainmentModel container ) + { + DeploymentModel[] startup = container.getStartupGraph(); + for ( int i = 0; i < startup.length; i++ ) + { + DeploymentModel current = startup[i]; + if( current instanceof ContainmentModel ) + { + ContainmentModel currentContainer = (ContainmentModel) current; + try + { + currentContainer.assemble(); + printStartup( currentContainer ); + } + catch ( AssemblyException e ) + { + e.printStackTrace(); + } + + } + System.out.println( current.getPath() + current.getName() ); + DeploymentModel[] deps = current.getProviders(); + + for ( int j = 0; j < deps.length; j++ ) + { + + System.out.println( "\tdep<-" + deps[j].getPath() + + deps[j].getName() ); + + } + } + } + + public void setUp() throws Exception + { + m_model = super.setUp( "cyclicdeps.xml" ); + ConsoleLogger logger = new ConsoleLogger( ConsoleLogger.LEVEL_INFO ); + } + + //------------------------------------------------------- + // tests + //------------------------------------------------------- + + /** + * Validate the the included block was created. + */ + public void testCyclicDependency() throws Throwable + { + try + { + + ContainmentModel root = (ContainmentModel) m_model.getModel( "/" ); + + root.assemble(); + printStartup( root ); + fail( "an exception should have been thrown" ); + + } + catch ( ModelRuntimeException e ) + { + //this should be thrown. + } + } +} \ No newline at end of file Modified: avalon/trunk/runtime/composition/impl/src/test/org/apache/avalon/composition/model/test/AbstractTestCase.java ============================================================================== --- avalon/trunk/runtime/composition/impl/src/test/org/apache/avalon/composition/model/test/AbstractTestCase.java (original) +++ avalon/trunk/runtime/composition/impl/src/test/org/apache/avalon/composition/model/test/AbstractTestCase.java Tue Sep 14 14:04:40 2004 @@ -74,7 +74,6 @@ BASEDIR = getWorkDir(); SYS_CONF = new File( BASEDIR, "system/kernel.xml" ).getAbsoluteFile(); SECURITY_BUILDER = new XMLSecurityProfileBuilder(); - System.out.println( "security.policy=" + System.getProperty( "java.security.policy" ) ); } private static File getWorkDir() @@ -84,12 +83,22 @@ { return new File( path ); } - else + path = System.getProperty( "basedir" ); + if( path != null ) { - path = System.getProperty( "basedir" ); File root = new File( path ); return new File( root, "target/test-classes" ); } + + //still no success resort to user.dir + if( !(path != null) ) + { + path = System.getProperty( "user.dir" ); + } + if( null != path ) + { + return new File( path ); + } return null; } //------------------------------------------------------- @@ -174,7 +183,7 @@ // File source = new File( BASEDIR, path ); - + System.out.println("loading " + source.toURL()); return modelFactory.createRootContainmentModel( source.toURL() ); } Modified: avalon/trunk/runtime/index.xml ============================================================================== --- avalon/trunk/runtime/index.xml (original) +++ avalon/trunk/runtime/index.xml Tue Sep 14 14:04:40 2004 @@ -389,6 +389,19 @@ </plugins> </project> + <project basedir="test/testcyclic"> + <info> + <group>avalon/test</group> + <name>avalon-test-testcyclic</name> + </info> + <dependencies> + <include key="avalon-framework-api"/> + </dependencies> + <plugins> + <include key="avalon-meta-tools"/> + </plugins> + </project> + <project basedir="test/includes"> <info> <group>avalon/test</group> @@ -689,9 +702,10 @@ <include key="avalon-util-extension-impl"/> <include key="avalon-util-lifecycle"/> <include key="avalon-logging-impl" build="false" test="true"/> - <include key="avalon-test-dynamics" build="false" test="false"/> - <include key="avalon-test-includes" build="false" test="true"/> - <include key="avalon-logging-test" build="false" test="false"/> + <include key="avalon-test-dynamics" build="false" runtime="false" test="false"/> + <include key="avalon-test-includes" build="false" runtime="false" test="true"/> + <include key="avalon-test-testcyclic" build="false" runtime="false" test="false"/> + <include key="avalon-logging-test" build="false" runtime="false" test="false"/> </dependencies> </project> Added: avalon/trunk/runtime/test/testcyclic/build.properties ============================================================================== --- (empty file) +++ avalon/trunk/runtime/test/testcyclic/build.properties Tue Sep 14 14:04:40 2004 @@ -0,0 +1,3 @@ + +project.home = ../.. +project.system = ../../../central/system Added: avalon/trunk/runtime/test/testcyclic/build.xml ============================================================================== --- (empty file) +++ avalon/trunk/runtime/test/testcyclic/build.xml Tue Sep 14 14:04:40 2004 @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<project name="avalon-test-testcyclic" default="install" basedir="." + xmlns:x="antlib:org.apache.avalon.tools" > + + <property file="build.properties"/> + <import file="${project.system}/build/standard.xml"/> + +</project> Added: avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/A.java ============================================================================== --- (empty file) +++ avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/A.java Tue Sep 14 14:04:40 2004 @@ -0,0 +1,22 @@ +/* + * Copyright 2004 Apache Software Foundation + * 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.apache.avalon.test.testcyclic; + +public interface A +{ +} Added: avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/B.java ============================================================================== --- (empty file) +++ avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/B.java Tue Sep 14 14:04:40 2004 @@ -0,0 +1,22 @@ +/* + * Copyright 2004 Apache Software Foundation + * 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.apache.avalon.test.testcyclic; + +public interface B +{ +} Added: avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/TestCyclicA.java ============================================================================== --- (empty file) +++ avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/TestCyclicA.java Tue Sep 14 14:04:40 2004 @@ -0,0 +1,43 @@ +/* + * Copyright 2004 Apache Software Foundation + * 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.apache.avalon.test.testcyclic; + +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.avalon.framework.logger.Logger; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; + +/** + * @avalon.component name="testcyclic" lifestyle="singleton" + * @avalon.service type="org.apache.avalon.test.testcyclic.A" + */ +public class TestCyclicA extends AbstractLogEnabled + implements A +{ + /** + * @avalon.dependency key="CyclicB" type="org.apache.avalon.test.testcyclic.B" + */ + public void service( ServiceManager manager ) throws ServiceException + { + getLogger().info( "service stage" ); + Logger logger = getLogger().getChildLogger( "service" ); + logger.info( "lookup B" ); + manager.lookup( "CyclicB" ); + logger.info( "ok" ); + } +} Added: avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/TestCyclicB.java ============================================================================== --- (empty file) +++ avalon/trunk/runtime/test/testcyclic/src/main/org/apache/avalon/test/testcyclic/TestCyclicB.java Tue Sep 14 14:04:40 2004 @@ -0,0 +1,43 @@ +/* + * Copyright 2004 Apache Software Foundation + * 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.apache.avalon.test.testcyclic; + +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.avalon.framework.logger.Logger; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; + +/** + * @avalon.component name="cyclic-b" lifestyle="singleton" + * @avalon.service type="org.apache.avalon.test.testcyclic.B" + */ +public class TestCyclicB extends AbstractLogEnabled + implements B +{ + /** + * @avalon.dependency key="CyclicA" type="org.apache.avalon.test.testcyclic.A" + */ + public void service( ServiceManager manager ) throws ServiceException + { + getLogger().info( "service stage" ); + Logger logger = getLogger().getChildLogger( "service" ); + logger.info( "lookup A" ); + manager.lookup( "CyclicA" ); + logger.info( "ok" ); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]