Author: vgritsenko Date: Thu Dec 30 06:16:00 2004 New Revision: 123716 URL: http://svn.apache.org/viewcvs?view=rev&rev=123716 Log: set properties!
Modified: cocoon/trunk/src/core/java/org/apache/cocoon/components/ServiceInfo.java (contents, props changed) cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractComponentHandler.java (contents, props changed) cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractServiceManager.java (contents, props changed) cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceManager.java (contents, props changed) cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceSelector.java (contents, props changed) cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentFactory.java (contents, props changed) cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentHandler.java (contents, props changed) cocoon/trunk/src/core/java/org/apache/cocoon/core/container/PoolableComponentHandler.java (contents, props changed) cocoon/trunk/src/core/java/org/apache/cocoon/core/container/RoleManager.java (contents, props changed) cocoon/trunk/src/core/java/org/apache/cocoon/core/container/SingleThreadedComponentHandler.java (contents, props changed) cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ThreadSafeComponentHandler.java (contents, props changed) cocoon/trunk/src/core/test/org/apache/cocoon/core/container/ContainerTestCase.java (contents, props changed) cocoon/trunk/src/core/test/org/apache/cocoon/core/container/RoleManagerTestCase.java (contents, props changed) cocoon/trunk/src/documentation/xdocs/userdocs/selectors/regular-expression-header-selector.xml (props changed) Modified: cocoon/trunk/src/core/java/org/apache/cocoon/components/ServiceInfo.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/components/ServiceInfo.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/components/ServiceInfo.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/components/ServiceInfo.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/components/ServiceInfo.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/components/ServiceInfo.java Thu Dec 30 06:16:00 2004 @@ -1,225 +1,225 @@ -/* - * Copyright 1999-2004 The 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.cocoon.components; - -import java.lang.reflect.Method; - -import org.apache.avalon.framework.configuration.Configuration; - -/** - * Meta-information about a service - * - * @version CVS $Id: LifecycleHelper.java 55255 2004-10-21 19:41:15Z cziegeler $ - */ -public class ServiceInfo { - - public static final int MODEL_PRIMITIVE = 0; - public static final int MODEL_SINGLETON = 1; - public static final int MODEL_POOLED = 2; - - private int model; - private String initMethodName; - private String destroyMethodName; - private String poolInMethodName; - private String poolOutMethodName; - private Class serviceClass; - private String serviceClassName; - private Method initMethod; - private Method destroyMethod; - private Method poolInMethod; - private Method poolOutMethod; - private Configuration configuration; - - public ServiceInfo() { - this.model = MODEL_PRIMITIVE; - } - - /** - * @return Returns the model. - */ - public int getModel() { - return model; - } - - /** - * @param model The model to set. - */ - public void setModel(int model) { - this.model = model; - } - - /** - * @return Returns the destroyMethod. - */ - public String getDestroyMethodName() { - return destroyMethodName; - } - - /** - * @param destroyMethod The destroyMethod to set. - */ - public void setDestroyMethodName(String destroyMethod) { - this.destroyMethodName = destroyMethod; - } - - /** - * @return Returns the initMethod. - */ - public String getInitMethodName() { - return initMethodName; - } - - /** - * @param initMethod The initMethod to set. - */ - public void setInitMethodName(String initMethod) { - this.initMethodName = initMethod; - } - - /** - * @return Returns the poolInMethodName - */ - public String getPoolInMethodName() { - return this.poolInMethodName; - } - - /** - * @param poolMethod The poolInMethod name to set. - */ - public void setPoolInMethodName(String poolMethod) { - this.poolInMethodName = poolMethod; - } - - /** - * @return Returns the poolOutMethodName - */ - public String getPoolOutMethodName() { - return this.poolOutMethodName; - } - - /** - * @param poolMethod The poolOutMethod name to set. - */ - public void setPoolOutMethodName(String poolMethod) { - this.poolOutMethodName = poolMethod; - } - - /** - * @return Returns the destroyMethod. - */ - public Method getDestroyMethod() throws Exception { - if ( this.destroyMethod == null && this.destroyMethodName != null ) { - this.destroyMethod = this.serviceClass.getMethod(this.destroyMethodName, null); - } - return destroyMethod; - } - - /** - * @return Returns the initMethod. - */ - public Method getInitMethod() throws Exception { - if ( this.initMethod == null && this.initMethodName != null ) { - this.initMethod = this.serviceClass.getMethod(this.initMethodName, null); - } - return initMethod; - } - - /** - * @return Returns the poolInMethod. - */ - public Method getPoolInMethod() throws Exception { - if ( this.poolInMethod == null && this.poolInMethodName != null ) { - this.poolInMethod = this.serviceClass.getMethod(this.poolInMethodName, null); - } - return poolInMethod; - } - - /** - * @return Returns the poolInMethod. - */ - public Method getPoolOutMethod() throws Exception { - if ( this.poolOutMethod == null && this.poolOutMethodName != null ) { - this.poolOutMethod = this.serviceClass.getMethod(this.poolOutMethodName, null); - } - return poolOutMethod; - } - - /** - * @return Returns the serviceClass. - */ - public Class getServiceClass() { - return serviceClass; - } - - /** - * @return Returns the serviceClassName. - */ - public String getServiceClassName() { - return serviceClassName; - } - - /** - * @param serviceClassName The serviceClassName to set. - */ - public void setServiceClassName(String serviceClassName) { - this.serviceClassName = serviceClassName; - } - - /** - * @param serviceClass The serviceClass to set. - */ - public void setServiceClass(Class serviceClass) { - this.serviceClass = serviceClass; - } - - /** - * @return Returns the configuration. - */ - public Configuration getConfiguration() { - return configuration; - } - /** - * @param configuration The configuration to set. - */ - public void setConfiguration(Configuration configuration) { - this.configuration = configuration; - } - - public String getLocation() { - return this.configuration.getLocation(); - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - public String toString() { - return "ServiceInfo: {class=" + this.getServiceClassName()+"}"; - } - - public void fill(Configuration attr) { - // test model - final String model = attr.getAttribute("model", null); - if ( "pooled".equals(model) ) { - this.setModel(ServiceInfo.MODEL_POOLED); - this.setPoolInMethodName(attr.getAttribute("pool-in", null)); - this.setPoolOutMethodName(attr.getAttribute("pool-out", null)); - } else if ( "singleton".equals(model) ) { - this.setModel(ServiceInfo.MODEL_SINGLETON); - } - this.setInitMethodName(attr.getAttribute("init", null)); - this.setDestroyMethodName(attr.getAttribute("destroy", null)); - } -} +/* + * Copyright 1999-2004 The 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.cocoon.components; + +import java.lang.reflect.Method; + +import org.apache.avalon.framework.configuration.Configuration; + +/** + * Meta-information about a service + * + * @version CVS $Id$ + */ +public class ServiceInfo { + + public static final int MODEL_PRIMITIVE = 0; + public static final int MODEL_SINGLETON = 1; + public static final int MODEL_POOLED = 2; + + private int model; + private String initMethodName; + private String destroyMethodName; + private String poolInMethodName; + private String poolOutMethodName; + private Class serviceClass; + private String serviceClassName; + private Method initMethod; + private Method destroyMethod; + private Method poolInMethod; + private Method poolOutMethod; + private Configuration configuration; + + public ServiceInfo() { + this.model = MODEL_PRIMITIVE; + } + + /** + * @return Returns the model. + */ + public int getModel() { + return model; + } + + /** + * @param model The model to set. + */ + public void setModel(int model) { + this.model = model; + } + + /** + * @return Returns the destroyMethod. + */ + public String getDestroyMethodName() { + return destroyMethodName; + } + + /** + * @param destroyMethod The destroyMethod to set. + */ + public void setDestroyMethodName(String destroyMethod) { + this.destroyMethodName = destroyMethod; + } + + /** + * @return Returns the initMethod. + */ + public String getInitMethodName() { + return initMethodName; + } + + /** + * @param initMethod The initMethod to set. + */ + public void setInitMethodName(String initMethod) { + this.initMethodName = initMethod; + } + + /** + * @return Returns the poolInMethodName + */ + public String getPoolInMethodName() { + return this.poolInMethodName; + } + + /** + * @param poolMethod The poolInMethod name to set. + */ + public void setPoolInMethodName(String poolMethod) { + this.poolInMethodName = poolMethod; + } + + /** + * @return Returns the poolOutMethodName + */ + public String getPoolOutMethodName() { + return this.poolOutMethodName; + } + + /** + * @param poolMethod The poolOutMethod name to set. + */ + public void setPoolOutMethodName(String poolMethod) { + this.poolOutMethodName = poolMethod; + } + + /** + * @return Returns the destroyMethod. + */ + public Method getDestroyMethod() throws Exception { + if ( this.destroyMethod == null && this.destroyMethodName != null ) { + this.destroyMethod = this.serviceClass.getMethod(this.destroyMethodName, null); + } + return destroyMethod; + } + + /** + * @return Returns the initMethod. + */ + public Method getInitMethod() throws Exception { + if ( this.initMethod == null && this.initMethodName != null ) { + this.initMethod = this.serviceClass.getMethod(this.initMethodName, null); + } + return initMethod; + } + + /** + * @return Returns the poolInMethod. + */ + public Method getPoolInMethod() throws Exception { + if ( this.poolInMethod == null && this.poolInMethodName != null ) { + this.poolInMethod = this.serviceClass.getMethod(this.poolInMethodName, null); + } + return poolInMethod; + } + + /** + * @return Returns the poolInMethod. + */ + public Method getPoolOutMethod() throws Exception { + if ( this.poolOutMethod == null && this.poolOutMethodName != null ) { + this.poolOutMethod = this.serviceClass.getMethod(this.poolOutMethodName, null); + } + return poolOutMethod; + } + + /** + * @return Returns the serviceClass. + */ + public Class getServiceClass() { + return serviceClass; + } + + /** + * @return Returns the serviceClassName. + */ + public String getServiceClassName() { + return serviceClassName; + } + + /** + * @param serviceClassName The serviceClassName to set. + */ + public void setServiceClassName(String serviceClassName) { + this.serviceClassName = serviceClassName; + } + + /** + * @param serviceClass The serviceClass to set. + */ + public void setServiceClass(Class serviceClass) { + this.serviceClass = serviceClass; + } + + /** + * @return Returns the configuration. + */ + public Configuration getConfiguration() { + return configuration; + } + /** + * @param configuration The configuration to set. + */ + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; + } + + public String getLocation() { + return this.configuration.getLocation(); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return "ServiceInfo: {class=" + this.getServiceClassName()+"}"; + } + + public void fill(Configuration attr) { + // test model + final String model = attr.getAttribute("model", null); + if ( "pooled".equals(model) ) { + this.setModel(ServiceInfo.MODEL_POOLED); + this.setPoolInMethodName(attr.getAttribute("pool-in", null)); + this.setPoolOutMethodName(attr.getAttribute("pool-out", null)); + } else if ( "singleton".equals(model) ) { + this.setModel(ServiceInfo.MODEL_SINGLETON); + } + this.setInitMethodName(attr.getAttribute("init", null)); + this.setDestroyMethodName(attr.getAttribute("destroy", null)); + } +} Modified: cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractComponentHandler.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractComponentHandler.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractComponentHandler.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractComponentHandler.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractComponentHandler.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractComponentHandler.java Thu Dec 30 06:16:00 2004 @@ -1,294 +1,294 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -import org.apache.avalon.excalibur.logger.LoggerManager; -import org.apache.avalon.excalibur.pool.Poolable; -import org.apache.avalon.framework.component.Composable; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.context.Context; -import org.apache.avalon.framework.logger.Logger; -import org.apache.avalon.framework.service.ServiceManager; -import org.apache.avalon.framework.thread.SingleThreaded; -import org.apache.avalon.framework.thread.ThreadSafe; -import org.apache.cocoon.components.ServiceInfo; - -/** - * This class acts like a Factory to instantiate the correct version - * of the component handler that you need. - * - * @version CVS $Id: AbstractComponentHandler.java 55144 2004-10-20 12:26:09Z ugo $ - */ -public abstract class AbstractComponentHandler -implements ComponentHandler { - - private final Object referenceSemaphore = new Object(); - private int references = 0; - - protected final Logger logger; - - /** This factory is used to created new objects */ - protected final ComponentFactory factory; - - /** State management boolean stating whether the Handler is disposed or not */ - protected boolean disposed = false; - - /** State management boolean stating whether the Handler is initialized or not */ - protected boolean initialized = false; - - private ServiceInfo info; - - /** - * Looks up and returns a component handler for a given component class. - * - * @param role the component's role. Can be <code>null</code> if the role isn't known. - * @param componentClass Class of the component for which the handle is - * being requested. - * @param configuration The configuration for this component. - * @param serviceManager The service manager which will be managing the service. - * @param context The current context object. - * @param logger The current logger - * @param loggerManager The current LoggerManager. - * - * @throws Exception If there were any problems obtaining a ComponentHandler - */ - public static ComponentHandler getComponentHandler( final String role, - final Class componentClass, - final Configuration configuration, - final ServiceManager serviceManager, - final Context context, - final Logger logger, - final LoggerManager loggerManager, - final RoleManager roleManager) - throws Exception { - int numInterfaces = 0; - - final ServiceInfo info = new ServiceInfo(); - info.setServiceClass(componentClass); - info.setServiceClassName(componentClass.getName()); - info.setConfiguration(configuration); - - // Early check for Composable - if ( Composable.class.isAssignableFrom( componentClass ) ) { - throw new Exception("Interface Composable is not supported anymore. Please change class " - + componentClass.getName() + " to use Serviceable instead."); - } - - if( SingleThreaded.class.isAssignableFrom( componentClass ) ) { - numInterfaces++; - info.setModel(ServiceInfo.MODEL_PRIMITIVE); - } - - if( ThreadSafe.class.isAssignableFrom( componentClass ) ) { - numInterfaces++; - info.setModel(ServiceInfo.MODEL_SINGLETON); - } - - if( Poolable.class.isAssignableFrom( componentClass ) ) { - numInterfaces++; - info.setModel(ServiceInfo.MODEL_POOLED); - } - - if( numInterfaces > 1 ) { - throw new Exception( "[CONFLICT] More than one lifecycle interface in " - + componentClass.getName() + " May implement no more than one of " - + "SingleThreaded, ThreadSafe, or Poolable" ); - } - - if ( numInterfaces == 0 ) { - // this component does not use avalon interfaces, so get the info from the configuration - info.fill(configuration); - } - - // Create the factory to use to create the instances of the Component. - ComponentFactory factory; - - if (DefaultServiceSelector.class.isAssignableFrom(componentClass)) { - // Special factory for DefaultServiceSelector - factory = new DefaultServiceSelector.Factory(serviceManager, context, logger, loggerManager, - roleManager, info, role); - - } else if (StandaloneServiceSelector.class.isAssignableFrom(componentClass)) { - // Special factory for StandaloneServiceSelector - factory = new StandaloneServiceSelector.Factory(serviceManager, context, logger, loggerManager, - roleManager, info); - - } else { - factory = new ComponentFactory(serviceManager, context, logger, loggerManager, - roleManager, info); - } - - AbstractComponentHandler handler; - - if( info.getModel() == ServiceInfo.MODEL_POOLED ) { - handler = new PoolableComponentHandler( info, logger, factory, configuration ); - } else if( info.getModel() == ServiceInfo.MODEL_SINGLETON ) { - handler = new ThreadSafeComponentHandler( info, logger, factory ); - } else { - // This is a SingleThreaded component - handler = new SingleThreadedComponentHandler( info, logger, factory ); - } - - return handler; - } - - /** - * Creates a new ComponentHandler. - */ - public AbstractComponentHandler(ServiceInfo info, Logger logger, ComponentFactory factory) { - this.info = info; - this.logger = logger; - this.factory = factory; - } - - public ServiceInfo getInfo() { - return this.info; - } - - /** - * Get an instance of the type of component handled by this handler. - * <p> - * Subclasses should not extend this method but rather the doGet method below otherwise - * reference counts will not be supported. - * <p> - * - * @return an instance - * @exception Exception if an error occurs - */ - public final Object get() throws Exception { - if( !this.initialized ) { - throw new IllegalStateException( - "You cannot get a component from an uninitialized handler." ); - } - if( this.disposed ) { - throw new IllegalStateException( "You cannot get a component from a disposed handler." ); - } - - final Object component = this.doGet(); - - synchronized( this.referenceSemaphore ) { - this.references++; - } - - return component; - } - - /** - * Put back an instance of the type of component handled by this handler. - * <p> - * Subclasses should not extend this method but rather the doPut method below otherwise - * reference counts will not be supported. - * <p> - * - * @param component a service - * @exception Exception if an error occurs - */ - public final void put( Object component ) - throws Exception { - if( !this.initialized ) { - throw new IllegalStateException( - "You cannot put a component to an uninitialized handler." ); - } - // The reference count must be decremented before any calls to doPut. - // If there is another thread blocking, then this thread could stay deep inside - // doPut for an undetermined amount of time until the thread scheduler gives it - // some cycles again. (It happened). All ComponentHandler state must therefor - // reflect the thread having left this method before the call to doPut to avoid - // warning messages from the dispose() cycle if that takes place before this - // thread has a chance to continue. - synchronized( this.referenceSemaphore ) { - this.references--; - } - - try { - this.doPut( component ); - } catch( Throwable t ) { - this.logger.error("Exception during putting back a component.", t); - } - } - - /** - * Concrete implementation of getting a component. - * - * @return a service - * @exception Exception if an error occurs - */ - protected abstract Object doGet() throws Exception; - - /** - * Concrete implementation of putting back a component. - * - * @param component a <code>Component</code> value - * @exception Exception if an error occurs - */ - protected abstract void doPut( Object component ) throws Exception; - - /** - * Default here is to return <code>false</code> - */ - public boolean isSingleton() { - return false; - } - - /** - * Returns <code>true</code> if this component handler can safely be - * disposed (i.e. none of the components it is handling are still - * being used). - * - * @return <code>true</code> if this component handler can safely be - * disposed; <code>false</code> otherwise - */ - public final boolean canBeDisposed() { - return ( this.references == 0 ); - } - - /* (non-Javadoc) - * @see org.apache.cocoon.core.container.ComponentHandler#dispose() - */ - public void dispose() { - this.disposed = true; - } - - /* (non-Javadoc) - * @see org.apache.cocoon.core.container.ComponentHandler#initialize() - */ - public void initialize() throws Exception { - if( this.initialized ) { - return; - } - this.initialized = true; - if( this.logger.isDebugEnabled() ) { - this.logger.debug( "ThreadSafeComponentHandler initialized for: " + this.factory.getCreatedClass().getName() ); - } - } - - /** - * Decommission a component - * @param component Object to be decommissioned - */ - protected void decommission( final Object component ) { - try { - this.factory.decommission( component ); - } catch( final Exception e ) { - if( this.logger.isWarnEnabled() ) { - this.logger.warn( "Error decommissioning component: " - + this.factory.getCreatedClass().getName(), e ); - } - } - } - -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +import org.apache.avalon.excalibur.logger.LoggerManager; +import org.apache.avalon.excalibur.pool.Poolable; +import org.apache.avalon.framework.component.Composable; +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.logger.Logger; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.avalon.framework.thread.SingleThreaded; +import org.apache.avalon.framework.thread.ThreadSafe; +import org.apache.cocoon.components.ServiceInfo; + +/** + * This class acts like a Factory to instantiate the correct version + * of the component handler that you need. + * + * @version CVS $Id$ + */ +public abstract class AbstractComponentHandler +implements ComponentHandler { + + private final Object referenceSemaphore = new Object(); + private int references = 0; + + protected final Logger logger; + + /** This factory is used to created new objects */ + protected final ComponentFactory factory; + + /** State management boolean stating whether the Handler is disposed or not */ + protected boolean disposed = false; + + /** State management boolean stating whether the Handler is initialized or not */ + protected boolean initialized = false; + + private ServiceInfo info; + + /** + * Looks up and returns a component handler for a given component class. + * + * @param role the component's role. Can be <code>null</code> if the role isn't known. + * @param componentClass Class of the component for which the handle is + * being requested. + * @param configuration The configuration for this component. + * @param serviceManager The service manager which will be managing the service. + * @param context The current context object. + * @param logger The current logger + * @param loggerManager The current LoggerManager. + * + * @throws Exception If there were any problems obtaining a ComponentHandler + */ + public static ComponentHandler getComponentHandler( final String role, + final Class componentClass, + final Configuration configuration, + final ServiceManager serviceManager, + final Context context, + final Logger logger, + final LoggerManager loggerManager, + final RoleManager roleManager) + throws Exception { + int numInterfaces = 0; + + final ServiceInfo info = new ServiceInfo(); + info.setServiceClass(componentClass); + info.setServiceClassName(componentClass.getName()); + info.setConfiguration(configuration); + + // Early check for Composable + if ( Composable.class.isAssignableFrom( componentClass ) ) { + throw new Exception("Interface Composable is not supported anymore. Please change class " + + componentClass.getName() + " to use Serviceable instead."); + } + + if( SingleThreaded.class.isAssignableFrom( componentClass ) ) { + numInterfaces++; + info.setModel(ServiceInfo.MODEL_PRIMITIVE); + } + + if( ThreadSafe.class.isAssignableFrom( componentClass ) ) { + numInterfaces++; + info.setModel(ServiceInfo.MODEL_SINGLETON); + } + + if( Poolable.class.isAssignableFrom( componentClass ) ) { + numInterfaces++; + info.setModel(ServiceInfo.MODEL_POOLED); + } + + if( numInterfaces > 1 ) { + throw new Exception( "[CONFLICT] More than one lifecycle interface in " + + componentClass.getName() + " May implement no more than one of " + + "SingleThreaded, ThreadSafe, or Poolable" ); + } + + if ( numInterfaces == 0 ) { + // this component does not use avalon interfaces, so get the info from the configuration + info.fill(configuration); + } + + // Create the factory to use to create the instances of the Component. + ComponentFactory factory; + + if (DefaultServiceSelector.class.isAssignableFrom(componentClass)) { + // Special factory for DefaultServiceSelector + factory = new DefaultServiceSelector.Factory(serviceManager, context, logger, loggerManager, + roleManager, info, role); + + } else if (StandaloneServiceSelector.class.isAssignableFrom(componentClass)) { + // Special factory for StandaloneServiceSelector + factory = new StandaloneServiceSelector.Factory(serviceManager, context, logger, loggerManager, + roleManager, info); + + } else { + factory = new ComponentFactory(serviceManager, context, logger, loggerManager, + roleManager, info); + } + + AbstractComponentHandler handler; + + if( info.getModel() == ServiceInfo.MODEL_POOLED ) { + handler = new PoolableComponentHandler( info, logger, factory, configuration ); + } else if( info.getModel() == ServiceInfo.MODEL_SINGLETON ) { + handler = new ThreadSafeComponentHandler( info, logger, factory ); + } else { + // This is a SingleThreaded component + handler = new SingleThreadedComponentHandler( info, logger, factory ); + } + + return handler; + } + + /** + * Creates a new ComponentHandler. + */ + public AbstractComponentHandler(ServiceInfo info, Logger logger, ComponentFactory factory) { + this.info = info; + this.logger = logger; + this.factory = factory; + } + + public ServiceInfo getInfo() { + return this.info; + } + + /** + * Get an instance of the type of component handled by this handler. + * <p> + * Subclasses should not extend this method but rather the doGet method below otherwise + * reference counts will not be supported. + * <p> + * + * @return an instance + * @exception Exception if an error occurs + */ + public final Object get() throws Exception { + if( !this.initialized ) { + throw new IllegalStateException( + "You cannot get a component from an uninitialized handler." ); + } + if( this.disposed ) { + throw new IllegalStateException( "You cannot get a component from a disposed handler." ); + } + + final Object component = this.doGet(); + + synchronized( this.referenceSemaphore ) { + this.references++; + } + + return component; + } + + /** + * Put back an instance of the type of component handled by this handler. + * <p> + * Subclasses should not extend this method but rather the doPut method below otherwise + * reference counts will not be supported. + * <p> + * + * @param component a service + * @exception Exception if an error occurs + */ + public final void put( Object component ) + throws Exception { + if( !this.initialized ) { + throw new IllegalStateException( + "You cannot put a component to an uninitialized handler." ); + } + // The reference count must be decremented before any calls to doPut. + // If there is another thread blocking, then this thread could stay deep inside + // doPut for an undetermined amount of time until the thread scheduler gives it + // some cycles again. (It happened). All ComponentHandler state must therefor + // reflect the thread having left this method before the call to doPut to avoid + // warning messages from the dispose() cycle if that takes place before this + // thread has a chance to continue. + synchronized( this.referenceSemaphore ) { + this.references--; + } + + try { + this.doPut( component ); + } catch( Throwable t ) { + this.logger.error("Exception during putting back a component.", t); + } + } + + /** + * Concrete implementation of getting a component. + * + * @return a service + * @exception Exception if an error occurs + */ + protected abstract Object doGet() throws Exception; + + /** + * Concrete implementation of putting back a component. + * + * @param component a <code>Component</code> value + * @exception Exception if an error occurs + */ + protected abstract void doPut( Object component ) throws Exception; + + /** + * Default here is to return <code>false</code> + */ + public boolean isSingleton() { + return false; + } + + /** + * Returns <code>true</code> if this component handler can safely be + * disposed (i.e. none of the components it is handling are still + * being used). + * + * @return <code>true</code> if this component handler can safely be + * disposed; <code>false</code> otherwise + */ + public final boolean canBeDisposed() { + return ( this.references == 0 ); + } + + /* (non-Javadoc) + * @see org.apache.cocoon.core.container.ComponentHandler#dispose() + */ + public void dispose() { + this.disposed = true; + } + + /* (non-Javadoc) + * @see org.apache.cocoon.core.container.ComponentHandler#initialize() + */ + public void initialize() throws Exception { + if( this.initialized ) { + return; + } + this.initialized = true; + if( this.logger.isDebugEnabled() ) { + this.logger.debug( "ThreadSafeComponentHandler initialized for: " + this.factory.getCreatedClass().getName() ); + } + } + + /** + * Decommission a component + * @param component Object to be decommissioned + */ + protected void decommission( final Object component ) { + try { + this.factory.decommission( component ); + } catch( final Exception e ) { + if( this.logger.isWarnEnabled() ) { + this.logger.warn( "Error decommissioning component: " + + this.factory.getCreatedClass().getName(), e ); + } + } + } + +} Modified: cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractServiceManager.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractServiceManager.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractServiceManager.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractServiceManager.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractServiceManager.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/core/container/AbstractServiceManager.java Thu Dec 30 06:16:00 2004 @@ -1,171 +1,171 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.avalon.excalibur.logger.LoggerManager; -import org.apache.avalon.framework.activity.Disposable; -import org.apache.avalon.framework.activity.Initializable; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; -import org.apache.avalon.framework.context.Context; -import org.apache.avalon.framework.context.Contextualizable; -import org.apache.avalon.framework.logger.AbstractLogEnabled; -import org.apache.avalon.framework.service.ServiceException; -import org.apache.avalon.framework.service.ServiceManager; -import org.apache.avalon.framework.thread.ThreadSafe; - -/** - * Base class for all service managers: ServiceManager and ServiceSelector - * - * @version CVS $Id: AbstractServiceManager.java 55144 2004-10-20 12:26:09Z ugo $ - */ -public abstract class AbstractServiceManager -extends AbstractLogEnabled -implements Contextualizable, ThreadSafe, Disposable, Initializable { - - /** The application context for components */ - protected Context context; - - /** Static component mapping handlers. */ - protected final Map componentMapping = Collections.synchronizedMap(new HashMap()); - - /** Used to map roles to ComponentHandlers. */ - protected final Map componentHandlers = Collections.synchronizedMap(new HashMap()); - - /** Is the Manager disposed or not? */ - protected boolean disposed; - - /** Is the Manager initialized? */ - protected boolean initialized; - - /** RoleInfos. */ - protected RoleManager roleManager; - - /** LoggerManager. */ - protected LoggerManager loggerManager; - - - /* (non-Javadoc) - * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) - */ - public void contextualize( final Context context ) { - this.context = context; - } - - public void setRoleManager( final RoleManager roles ) { - this.roleManager = roles; - } - - /** - * Configure the LoggerManager. - */ - public void setLoggerManager( final LoggerManager manager ) { - this.loggerManager = manager; - } - - /** - * Obtain a new ComponentHandler for the specified component. - * - * @param role the component's role. - * @param componentClass Class of the component for which the handle is - * being requested. - * @param configuration The configuration for this component. - * @param serviceManager The service manager which will be managing the Component. - * - * @throws Exception If there were any problems obtaining a ComponentHandler - */ - protected ComponentHandler getComponentHandler( final String role, - final Class componentClass, - final Configuration configuration, - final ServiceManager serviceManager) - throws Exception { - return AbstractComponentHandler.getComponentHandler(role, - componentClass, - configuration, - serviceManager, - this.context, - this.getLogger(), - this.loggerManager, - this.roleManager); - } - - protected void addComponent(String className, - String role, - Configuration configuration) - throws ConfigurationException { - // check for old excalibur class names - we only test against the selector - // implementation - if ( "org.apache.cocoon.components.ExtendedComponentSelector".equals(className)) { - className = DefaultServiceSelector.class.getName(); - } - - try { - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( "Adding component (" + role + " = " + className + ")" ); - } - - final Class clazz = this.getClass().getClassLoader().loadClass( className ); - this.addComponent( role, clazz, configuration ); - } catch( final ClassNotFoundException cnfe ) { - final String message = "Could not get class (" + className + ") for role " - + role + " at " + configuration.getLocation(); - - if( this.getLogger().isErrorEnabled() ) { - this.getLogger().error( message, cnfe ); - } - - throw new ConfigurationException( message, cnfe ); - } catch( final ServiceException ce ) { - final String message = "Cannot setup class "+ className + " for role " + role - + " at " + configuration.getLocation(); - - if( this.getLogger().isErrorEnabled() ) { - this.getLogger().error( message, ce ); - } - - throw new ConfigurationException( message, ce ); - } catch( final Exception e ) { - final String message = "Unexpected exception when setting up role " + role + " at " + configuration.getLocation(); - if( this.getLogger().isErrorEnabled() ) { - this.getLogger().error( message, e ); - } - throw new ConfigurationException( message, e ); - } - } - - protected abstract void addComponent(String role, Class clazz, Configuration config) - throws ServiceException; - - - /* (non-Javadoc) - * @see org.apache.avalon.framework.activity.Disposable#dispose() - */ - public void dispose() { - this.disposed = true; - } - - /* (non-Javadoc) - * @see org.apache.avalon.framework.activity.Initializable#initialize() - */ - public void initialize() throws Exception { - this.initialized = true; - } -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.avalon.excalibur.logger.LoggerManager; +import org.apache.avalon.framework.activity.Disposable; +import org.apache.avalon.framework.activity.Initializable; +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.context.Contextualizable; +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.avalon.framework.thread.ThreadSafe; + +/** + * Base class for all service managers: ServiceManager and ServiceSelector + * + * @version CVS $Id$ + */ +public abstract class AbstractServiceManager +extends AbstractLogEnabled +implements Contextualizable, ThreadSafe, Disposable, Initializable { + + /** The application context for components */ + protected Context context; + + /** Static component mapping handlers. */ + protected final Map componentMapping = Collections.synchronizedMap(new HashMap()); + + /** Used to map roles to ComponentHandlers. */ + protected final Map componentHandlers = Collections.synchronizedMap(new HashMap()); + + /** Is the Manager disposed or not? */ + protected boolean disposed; + + /** Is the Manager initialized? */ + protected boolean initialized; + + /** RoleInfos. */ + protected RoleManager roleManager; + + /** LoggerManager. */ + protected LoggerManager loggerManager; + + + /* (non-Javadoc) + * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) + */ + public void contextualize( final Context context ) { + this.context = context; + } + + public void setRoleManager( final RoleManager roles ) { + this.roleManager = roles; + } + + /** + * Configure the LoggerManager. + */ + public void setLoggerManager( final LoggerManager manager ) { + this.loggerManager = manager; + } + + /** + * Obtain a new ComponentHandler for the specified component. + * + * @param role the component's role. + * @param componentClass Class of the component for which the handle is + * being requested. + * @param configuration The configuration for this component. + * @param serviceManager The service manager which will be managing the Component. + * + * @throws Exception If there were any problems obtaining a ComponentHandler + */ + protected ComponentHandler getComponentHandler( final String role, + final Class componentClass, + final Configuration configuration, + final ServiceManager serviceManager) + throws Exception { + return AbstractComponentHandler.getComponentHandler(role, + componentClass, + configuration, + serviceManager, + this.context, + this.getLogger(), + this.loggerManager, + this.roleManager); + } + + protected void addComponent(String className, + String role, + Configuration configuration) + throws ConfigurationException { + // check for old excalibur class names - we only test against the selector + // implementation + if ( "org.apache.cocoon.components.ExtendedComponentSelector".equals(className)) { + className = DefaultServiceSelector.class.getName(); + } + + try { + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "Adding component (" + role + " = " + className + ")" ); + } + + final Class clazz = this.getClass().getClassLoader().loadClass( className ); + this.addComponent( role, clazz, configuration ); + } catch( final ClassNotFoundException cnfe ) { + final String message = "Could not get class (" + className + ") for role " + + role + " at " + configuration.getLocation(); + + if( this.getLogger().isErrorEnabled() ) { + this.getLogger().error( message, cnfe ); + } + + throw new ConfigurationException( message, cnfe ); + } catch( final ServiceException ce ) { + final String message = "Cannot setup class "+ className + " for role " + role + + " at " + configuration.getLocation(); + + if( this.getLogger().isErrorEnabled() ) { + this.getLogger().error( message, ce ); + } + + throw new ConfigurationException( message, ce ); + } catch( final Exception e ) { + final String message = "Unexpected exception when setting up role " + role + " at " + configuration.getLocation(); + if( this.getLogger().isErrorEnabled() ) { + this.getLogger().error( message, e ); + } + throw new ConfigurationException( message, e ); + } + } + + protected abstract void addComponent(String role, Class clazz, Configuration config) + throws ServiceException; + + + /* (non-Javadoc) + * @see org.apache.avalon.framework.activity.Disposable#dispose() + */ + public void dispose() { + this.disposed = true; + } + + /* (non-Javadoc) + * @see org.apache.avalon.framework.activity.Initializable#initialize() + */ + public void initialize() throws Exception { + this.initialized = true; + } +} Modified: cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceManager.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceManager.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceManager.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceManager.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceManager.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceManager.java Thu Dec 30 06:16:00 2004 @@ -1,639 +1,639 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import org.apache.avalon.framework.CascadingRuntimeException; -import org.apache.avalon.framework.configuration.Configurable; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; -import org.apache.avalon.framework.configuration.DefaultConfiguration; -import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; -import org.apache.avalon.framework.context.Context; -import org.apache.avalon.framework.context.ContextException; -import org.apache.avalon.framework.logger.Logger; -import org.apache.avalon.framework.service.ServiceException; -import org.apache.avalon.framework.service.ServiceManager; -import org.apache.cocoon.components.ServiceInfo; -import org.apache.cocoon.core.source.SimpleSourceResolver; -import org.apache.excalibur.source.Source; -import org.apache.excalibur.source.SourceResolver; - -/** - * Default service manager for Cocoon's components. - * - * @version SVN $Revision: 1.6 $Id: CocoonServiceManager.java 55165 2004-10-20 16:51:50Z cziegeler $ - */ -public class CocoonServiceManager -extends AbstractServiceManager -implements ServiceManager, Configurable { - - /** The location where this manager is defined */ - protected String location; - - /** The parent ServiceManager */ - protected ServiceManager parentManager; - - /** added component handlers before initialization to maintain - * the order of initialization - */ - private final List newComponentHandlers = new ArrayList(); - - /** Temporary list of parent-aware components. Will be null for most of - * our lifecycle. */ - private ArrayList parentAwareComponents = new ArrayList(); - - /** The resolver used to resolve includes. It is lazily loaded in [EMAIL PROTECTED] #getSourceResolver()}. */ - private SourceResolver cachedSourceResolver; - - /** Create the ServiceManager with a parent ServiceManager */ - public CocoonServiceManager( final ServiceManager parent ) { - this.parentManager = parent; - - RoleManager parentRoleManager = null; - // get role manager and logger manager - if ( parent instanceof CocoonServiceManager ) { - parentRoleManager = ((CocoonServiceManager)parent).roleManager; - this.loggerManager = ((CocoonServiceManager)parent).loggerManager; - } - - // Always create a role manager, it can be filled several times either through - // the root "roles" attribute or through loading of includes - this.roleManager = new RoleManager(parentRoleManager); - } - - /* (non-Javadoc) - * @see org.apache.avalon.framework.logger.LogEnabled#enableLogging(org.apache.avalon.framework.logger.Logger) - */ - public void enableLogging(Logger logger) { - super.enableLogging(logger); - this.roleManager.enableLogging(logger); - } - - /* (non-Javadoc) - * @see org.apache.avalon.framework.service.ServiceManager#lookup(java.lang.String) - */ - public Object lookup( final String role ) - throws ServiceException { - if( !this.initialized ) { - if( this.getLogger().isWarnEnabled() ) { - this.getLogger().warn( - "Looking up component on an uninitialized CocoonServiceManager [" + role + "]" ); - } - } - - if( this.disposed ) { - throw new IllegalStateException( - "You cannot lookup components on a disposed CocoonServiceManager" ); - } - - if( role == null ) { - final String message = - "CocoonServiceManager attempted to retrieve service with null role."; - - if( this.getLogger().isErrorEnabled() ) { - this.getLogger().error( message ); - } - throw new ServiceException( role, message ); - } - - ComponentHandler handler = (ComponentHandler)this.componentHandlers.get( role ); - - // Retrieve the instance of the requested component - if ( handler == null ) { - if( this.parentManager != null ) { - try { - return this.parentManager.lookup( role ); - } catch( Exception e ) { - if( this.getLogger().isWarnEnabled() ) { - final String message = - "ComponentLocator exception from parent SM during lookup."; - this.getLogger().warn( message, e ); - } - // ignore. If the exception is thrown, we try to - // create the component next - } - } - - if( this.roleManager != null ) { - final ServiceInfo info = this.roleManager.getDefaultServiceInfoForRole( role ); - - if( info != null ) { - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( "Could not find ComponentHandler, attempting to create " - + "one for role [" + role + "]" ); - } - - try { - final Class componentClass = this.getClass().getClassLoader().loadClass( info.getServiceClassName() ); - - final Configuration configuration = new DefaultConfiguration( "", "-" ); - - handler = this.getComponentHandler(role, - componentClass, - configuration, - this); - - handler.initialize(); - } catch (ServiceException se) { - throw se; - } catch( final Exception e ) { - final String message = "Could not find component for role [" + role + "]"; - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( message, e ); - } - throw new ServiceException( role, message, e ); - } - - this.componentHandlers.put( role, handler ); - } - } else { - this.getLogger().debug( "Component requested without a RoleManager set.\n" - + "That means setRoleManager() was not called during initialization." ); - } - } - - if( handler == null ) { - final String message = "Could not find component for role: [" + role + "]"; - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( message ); - } - throw new ServiceException( role, message ); - } - - Object component = null; - - try { - component = handler.get(); - } catch( final IllegalStateException ise ) { - try { - handler.initialize(); - component = handler.get(); - - } catch( final ServiceException ce ) { - // Rethrow instead of wrapping a ServiceException with another one - throw ce; - } catch( final Exception e ) { - final String message = "Could not access the component for role [" + role + "]"; - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( message, e ); - } - - throw new ServiceException( role, message, e ); - } - } catch ( ServiceException se) { - // Rethrow insteand of wrapping it again - throw se; - } catch( final Exception e ) { - final String message = "Could not access the component for role [" + role + "]"; - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( message, e ); - } - - throw new ServiceException( role, message, e ); - } - this.initialize( role, component ); - - // Add a mapping between the component and its handler. - // In the case of a ThreadSafeComponentHandler, the same component will be mapped - // multiple times but because each put will overwrite the last, this is not a - // problem. Checking to see if the put has already been done would be slower. - this.componentMapping.put( component, handler ); - - return component; - } - - /** - * Initialize the component - * @throws ServiceException - */ - protected void initialize(String role, Object component) - throws ServiceException { - // we do nothing here, can be used in subclasses - } - - /* (non-Javadoc) - * @see org.apache.avalon.framework.service.ServiceManager#hasService(java.lang.String) - */ - public boolean hasService( final String role ) { - if( !this.initialized ) return false; - if( this.disposed ) return false; - - boolean exists = this.componentHandlers.containsKey( role ); - - if( !exists && null != this.parentManager ) { - exists = this.parentManager.hasService( role ); - } - - return exists; - } - - /* (non-Javadoc) - * @see org.apache.avalon.framework.service.ServiceManager#release(java.lang.Object) - */ - public void release( final Object component ) { - if( null == component ) { - return; - } - - // The componentMapping StaticBucketMap itself is threadsafe, and because the same component - // will never be released by more than one thread, this method does not need any - // synchronization around the access to the map. - - final ComponentHandler handler = - (ComponentHandler)this.componentMapping.get( component ); - - if ( handler != null ) { - // ThreadSafe components will always be using a ThreadSafeComponentHandler, - // they will only have a single entry in the m_componentMapping map which - // should not be removed until the ComponentLocator is disposed. All - // other components have an entry for each instance which should be - // removed. - if( !handler.isSingleton() ) { - // Remove the component before calling put. This is critical to avoid the - // problem where another thread calls put on the same component before - // remove can be called. - this.componentMapping.remove( component ); - } - - try { - handler.put( component ); - } catch( Exception e ) { - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( "Error trying to release component.", e ); - } - } - } - else if( this.parentManager != null ) { - this.parentManager.release( component ); - } else { - this.getLogger().warn( "Attempted to release a " + component.getClass().getName() + - " but its handler could not be located." ); - } - } - - /* (non-Javadoc) - * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration) - */ - public void configure(Configuration configuration) throws ConfigurationException { - // Setup location - if (this.location == null) { - // First call to configure() - this.location = configuration.getLocation(); - } - - try { - // and load configuration with a empty list of loaded configurations - doConfigure(configuration, new HashSet()); - } finally { - // Release any source resolver that may have been created to load includes - releaseCachedSourceResolver(); - } - } - - private void doConfigure(final Configuration configuration, Set loadedURIs) throws ConfigurationException { - - // Read roles - String rolesURI = configuration.getAttribute("roles", null); - if (rolesURI != null) { - Configuration roles = loadConfiguration(rolesURI, configuration.getLocation()); - this.roleManager.configure(roles); - } - - // Set components - final Configuration[] configurations = configuration.getChildren(); - - for( int i = 0; i < configurations.length; i++ ) { - Configuration componentConfig = configurations[i]; - - String componentName = componentConfig.getName(); - - if ("include".equals(componentName)) { - String includeURI = componentConfig.getAttribute("src"); - if (loadedURIs.contains(includeURI)) { - // Already loaded: skip to next configuration element - continue; - } - // load it and store it in the read set - Configuration includeConfig = loadConfiguration(includeURI, componentConfig.getLocation()); - loadedURIs.add(includeURI); - - // what is it? - String includeKind = includeConfig.getName(); - if (includeKind.equals("components")) { - // more components - doConfigure(includeConfig, loadedURIs); - } else if (includeKind.equals("role-list")) { - // more roles - this.roleManager.configure(includeConfig); - } else { - throw new ConfigurationException("Unknow document '" + includeKind + "' included at " + - componentConfig.getLocation()); - } - - } else { - // Component declaration - // Find the role - String role = componentConfig.getAttribute("role", null); - if (role == null) { - // Get the role from the role manager if not explicitely specified - role = roleManager.getRoleForName(componentName); - if (role == null) { - // Unknown role - throw new ConfigurationException("Unknown component type '" + componentName + - "' at " + componentConfig.getLocation()); - } - } - - // Find the className - String className = componentConfig.getAttribute("class", null); - if (className == null) { - // Get the default class name for this role - final ServiceInfo info = roleManager.getDefaultServiceInfoForRole(role); - if (info == null) { - throw new ConfigurationException("Cannot find a class for role " + role + " at " + componentConfig.getLocation()); - } - className = info.getServiceClassName(); - } - - // If it has a "name" attribute, add it to the role (similar to the - // declaration within a service selector) - // Note: this has to be done *after* finding the className above as we change the role - String name = componentConfig.getAttribute("name", null); - if (name != null) { - role = role + "/" + name; - } - - this.addComponent(className, role, componentConfig); - } - } - } - - /* (non-Javadoc) - * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) - */ - public void contextualize( final Context context ) { - this.context = context; - } - - /* (non-Javadoc) - * @see org.apache.avalon.framework.activity.Initializable#initialize() - */ - public void initialize() - throws Exception { - super.initialize(); - - for( int i = 0; i < this.newComponentHandlers.size(); i++ ) { - final ComponentHandler handler = - (ComponentHandler)this.newComponentHandlers.get( i ); - try { - handler.initialize(); - } catch( Exception e ) { - if( this.getLogger().isErrorEnabled() ) - { - this.getLogger().error( "Caught an exception trying to initialize " - + "the component handler.", e ); - } - - // Rethrow the exception - throw e; - } - } - - List keys = new ArrayList( this.componentHandlers.keySet() ); - - for( int i = 0; i < keys.size(); i++ ) { - final Object key = keys.get( i ); - final ComponentHandler handler = - (ComponentHandler)this.componentHandlers.get( key ); - - if( !this.newComponentHandlers.contains( handler ) ) { - try { - handler.initialize(); - - } catch( Exception e ) { - if( this.getLogger().isErrorEnabled() ) { - this.getLogger().error( "Caught an exception trying to initialize " - + "the component handler.", e ); - - } - // Rethrow the exception - throw e; - } - } - } - this.newComponentHandlers.clear(); - - // Initialize parent aware components - if (this.parentAwareComponents == null) { - throw new ServiceException(null, "CocoonServiceManager already initialized"); - } - - // Set parents for parentAware components - Iterator iter = this.parentAwareComponents.iterator(); - while (iter.hasNext()) { - String role = (String)iter.next(); - if ( this.parentManager != null && this.parentManager.hasService( role ) ) { - // lookup new component - Object component = null; - try { - component = this.lookup( role ); - ((CocoonServiceSelector)component).setParentLocator( this.parentManager, role ); - } catch (ServiceException ignore) { - // we don't set the parent then - } finally { - this.release( component ); - } - } - } - this.parentAwareComponents = null; // null to save memory, and catch logic bugs. - -// Object[] keyArray = this.componentHandlers.keySet().toArray(); -// Arrays.sort(keyArray); -// for (int i = 0; i < keyArray.length; i++) { -// System.err.println("Component key = " + keyArray[i]); -// } - } - - /* (non-Javadoc) - * @see org.apache.avalon.framework.activity.Disposable#dispose() - */ - public void dispose() { - boolean forceDisposal = false; - - final List disposed = new ArrayList(); - - while( componentHandlers.size() > 0 ) { - for( Iterator iterator = componentHandlers.keySet().iterator(); - iterator.hasNext(); ) { - final Object role = iterator.next(); - - final ComponentHandler handler = - (ComponentHandler)componentHandlers.get( role ); - - if( forceDisposal || handler.canBeDisposed() ) { - if( forceDisposal && getLogger().isWarnEnabled() ) { - this.getLogger().warn - ( "disposing of handler for unreleased component." - + " role [" + role + "]" ); - } - - handler.dispose(); - disposed.add( role ); - } - } - - if( disposed.size() > 0 ) { - final Iterator i = disposed.iterator(); - while ( i.hasNext() ) { - this.componentHandlers.remove( i.next() ); - } - disposed.clear(); - } else { - // no more disposable handlers! - forceDisposal = true; - } - } - super.dispose(); - } - - /** - * Add a new component to the manager. - * - * @param role the role name for the new component. - * @param component the class of this component. - * @param configuration the configuration for this component. - */ - public void addComponent( final String role, - final Class component, - final Configuration configuration ) - throws ServiceException { - if( this.initialized ) { - throw new ServiceException( role, - "Cannot add components to an initialized CocoonServiceManager." ); - } - - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( "Attempting to get handler for role [" + role + "]" ); - } - - ComponentHandler handler = (ComponentHandler)this.componentHandlers.get(role); - if (handler != null) { - // Overloaded component: we only allow selectors to be overloaded - ServiceInfo info = handler.getInfo(); - if (!DefaultServiceSelector.class.isAssignableFrom(component) || - !DefaultServiceSelector.class.isAssignableFrom(info.getServiceClass())) { - throw new ServiceException(role, "Component declared at " + info.getLocation() + " is redefined at " + - configuration.getLocation()); - } - } - try { - handler = this.getComponentHandler(role, component, configuration, this); - - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( "Handler type = " + handler.getClass().getName() ); - } - - this.componentHandlers.put( role, handler ); - this.newComponentHandlers.add( handler ); - } catch ( final ServiceException se ) { - throw se; - } catch( final Exception e ) { - throw new ServiceException( role, "Could not set up component handler.", e ); - } - - if ( CocoonServiceSelector.class.isAssignableFrom( component ) ) { - this.parentAwareComponents.add(role); - } - // Initialize shadow selector now, it will feed this service manager - if ( DefaultServiceSelector.class.isAssignableFrom( component )) { - try { - handler.initialize(); - } catch(ServiceException se) { - throw se; - } catch(Exception e) { - throw new ServiceException(role, "Could not initialize selector", e); - } - } - } - - /** - * Load a Configuration from a given URI. If the parent manager does not exist or does not - * provide a source resolver, a simple one is created here to load the file. - * - * @param uri the configuration's URI - * @param location the location where the load occurs (used to raise meaningful errors) - * @return the configuration - * @throws ConfigurationException - */ - private Configuration loadConfiguration(String uri, String location) throws ConfigurationException { - - // First get a source resolver - if (this.cachedSourceResolver == null) { - - if (this.parentManager != null && this.parentManager.hasService(SourceResolver.ROLE)) { - try { - this.cachedSourceResolver = (SourceResolver)this.parentManager.lookup(SourceResolver.ROLE); - } catch(ServiceException se) { - // Unlikely to happen - throw new CascadingRuntimeException("Cannot get source resolver from parent, at " + location, se); - } - } else { - // Create our own - SimpleSourceResolver simpleSR = new SimpleSourceResolver(); - simpleSR.enableLogging(getLogger()); - try { - simpleSR.contextualize(this.context); - } catch (ContextException ce) { - throw new CascadingRuntimeException("Cannot setup source resolver, at " + location, ce); - } - this.cachedSourceResolver = simpleSR; - } - } - - Configuration result; - - try { - Source src = this.cachedSourceResolver.resolveURI(uri); - DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); - result = builder.build(src.getInputStream(), src.getURI()); - } catch (ConfigurationException ce) { - throw ce; - } catch (Exception e) { - throw new ConfigurationException("Cannot load '" + uri + "' at " + location, e); - } - - return result; - } - - /** - * Release the source resolver that may have been created by the first call to - * loadConfiguration(). - */ - private void releaseCachedSourceResolver() { - if (this.cachedSourceResolver != null && - this.parentManager != null && this.parentManager.hasService(SourceResolver.ROLE)) { - this.parentManager.release(this.cachedSourceResolver); - } - this.cachedSourceResolver = null; - } -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.avalon.framework.CascadingRuntimeException; +import org.apache.avalon.framework.configuration.Configurable; +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.avalon.framework.configuration.DefaultConfiguration; +import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.context.ContextException; +import org.apache.avalon.framework.logger.Logger; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.cocoon.components.ServiceInfo; +import org.apache.cocoon.core.source.SimpleSourceResolver; +import org.apache.excalibur.source.Source; +import org.apache.excalibur.source.SourceResolver; + +/** + * Default service manager for Cocoon's components. + * + * @version SVN $Revision: 1.6 $Id$ + */ +public class CocoonServiceManager +extends AbstractServiceManager +implements ServiceManager, Configurable { + + /** The location where this manager is defined */ + protected String location; + + /** The parent ServiceManager */ + protected ServiceManager parentManager; + + /** added component handlers before initialization to maintain + * the order of initialization + */ + private final List newComponentHandlers = new ArrayList(); + + /** Temporary list of parent-aware components. Will be null for most of + * our lifecycle. */ + private ArrayList parentAwareComponents = new ArrayList(); + + /** The resolver used to resolve includes. It is lazily loaded in [EMAIL PROTECTED] #getSourceResolver()}. */ + private SourceResolver cachedSourceResolver; + + /** Create the ServiceManager with a parent ServiceManager */ + public CocoonServiceManager( final ServiceManager parent ) { + this.parentManager = parent; + + RoleManager parentRoleManager = null; + // get role manager and logger manager + if ( parent instanceof CocoonServiceManager ) { + parentRoleManager = ((CocoonServiceManager)parent).roleManager; + this.loggerManager = ((CocoonServiceManager)parent).loggerManager; + } + + // Always create a role manager, it can be filled several times either through + // the root "roles" attribute or through loading of includes + this.roleManager = new RoleManager(parentRoleManager); + } + + /* (non-Javadoc) + * @see org.apache.avalon.framework.logger.LogEnabled#enableLogging(org.apache.avalon.framework.logger.Logger) + */ + public void enableLogging(Logger logger) { + super.enableLogging(logger); + this.roleManager.enableLogging(logger); + } + + /* (non-Javadoc) + * @see org.apache.avalon.framework.service.ServiceManager#lookup(java.lang.String) + */ + public Object lookup( final String role ) + throws ServiceException { + if( !this.initialized ) { + if( this.getLogger().isWarnEnabled() ) { + this.getLogger().warn( + "Looking up component on an uninitialized CocoonServiceManager [" + role + "]" ); + } + } + + if( this.disposed ) { + throw new IllegalStateException( + "You cannot lookup components on a disposed CocoonServiceManager" ); + } + + if( role == null ) { + final String message = + "CocoonServiceManager attempted to retrieve service with null role."; + + if( this.getLogger().isErrorEnabled() ) { + this.getLogger().error( message ); + } + throw new ServiceException( role, message ); + } + + ComponentHandler handler = (ComponentHandler)this.componentHandlers.get( role ); + + // Retrieve the instance of the requested component + if ( handler == null ) { + if( this.parentManager != null ) { + try { + return this.parentManager.lookup( role ); + } catch( Exception e ) { + if( this.getLogger().isWarnEnabled() ) { + final String message = + "ComponentLocator exception from parent SM during lookup."; + this.getLogger().warn( message, e ); + } + // ignore. If the exception is thrown, we try to + // create the component next + } + } + + if( this.roleManager != null ) { + final ServiceInfo info = this.roleManager.getDefaultServiceInfoForRole( role ); + + if( info != null ) { + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "Could not find ComponentHandler, attempting to create " + + "one for role [" + role + "]" ); + } + + try { + final Class componentClass = this.getClass().getClassLoader().loadClass( info.getServiceClassName() ); + + final Configuration configuration = new DefaultConfiguration( "", "-" ); + + handler = this.getComponentHandler(role, + componentClass, + configuration, + this); + + handler.initialize(); + } catch (ServiceException se) { + throw se; + } catch( final Exception e ) { + final String message = "Could not find component for role [" + role + "]"; + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( message, e ); + } + throw new ServiceException( role, message, e ); + } + + this.componentHandlers.put( role, handler ); + } + } else { + this.getLogger().debug( "Component requested without a RoleManager set.\n" + + "That means setRoleManager() was not called during initialization." ); + } + } + + if( handler == null ) { + final String message = "Could not find component for role: [" + role + "]"; + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( message ); + } + throw new ServiceException( role, message ); + } + + Object component = null; + + try { + component = handler.get(); + } catch( final IllegalStateException ise ) { + try { + handler.initialize(); + component = handler.get(); + + } catch( final ServiceException ce ) { + // Rethrow instead of wrapping a ServiceException with another one + throw ce; + } catch( final Exception e ) { + final String message = "Could not access the component for role [" + role + "]"; + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( message, e ); + } + + throw new ServiceException( role, message, e ); + } + } catch ( ServiceException se) { + // Rethrow insteand of wrapping it again + throw se; + } catch( final Exception e ) { + final String message = "Could not access the component for role [" + role + "]"; + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( message, e ); + } + + throw new ServiceException( role, message, e ); + } + this.initialize( role, component ); + + // Add a mapping between the component and its handler. + // In the case of a ThreadSafeComponentHandler, the same component will be mapped + // multiple times but because each put will overwrite the last, this is not a + // problem. Checking to see if the put has already been done would be slower. + this.componentMapping.put( component, handler ); + + return component; + } + + /** + * Initialize the component + * @throws ServiceException + */ + protected void initialize(String role, Object component) + throws ServiceException { + // we do nothing here, can be used in subclasses + } + + /* (non-Javadoc) + * @see org.apache.avalon.framework.service.ServiceManager#hasService(java.lang.String) + */ + public boolean hasService( final String role ) { + if( !this.initialized ) return false; + if( this.disposed ) return false; + + boolean exists = this.componentHandlers.containsKey( role ); + + if( !exists && null != this.parentManager ) { + exists = this.parentManager.hasService( role ); + } + + return exists; + } + + /* (non-Javadoc) + * @see org.apache.avalon.framework.service.ServiceManager#release(java.lang.Object) + */ + public void release( final Object component ) { + if( null == component ) { + return; + } + + // The componentMapping StaticBucketMap itself is threadsafe, and because the same component + // will never be released by more than one thread, this method does not need any + // synchronization around the access to the map. + + final ComponentHandler handler = + (ComponentHandler)this.componentMapping.get( component ); + + if ( handler != null ) { + // ThreadSafe components will always be using a ThreadSafeComponentHandler, + // they will only have a single entry in the m_componentMapping map which + // should not be removed until the ComponentLocator is disposed. All + // other components have an entry for each instance which should be + // removed. + if( !handler.isSingleton() ) { + // Remove the component before calling put. This is critical to avoid the + // problem where another thread calls put on the same component before + // remove can be called. + this.componentMapping.remove( component ); + } + + try { + handler.put( component ); + } catch( Exception e ) { + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "Error trying to release component.", e ); + } + } + } + else if( this.parentManager != null ) { + this.parentManager.release( component ); + } else { + this.getLogger().warn( "Attempted to release a " + component.getClass().getName() + + " but its handler could not be located." ); + } + } + + /* (non-Javadoc) + * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration) + */ + public void configure(Configuration configuration) throws ConfigurationException { + // Setup location + if (this.location == null) { + // First call to configure() + this.location = configuration.getLocation(); + } + + try { + // and load configuration with a empty list of loaded configurations + doConfigure(configuration, new HashSet()); + } finally { + // Release any source resolver that may have been created to load includes + releaseCachedSourceResolver(); + } + } + + private void doConfigure(final Configuration configuration, Set loadedURIs) throws ConfigurationException { + + // Read roles + String rolesURI = configuration.getAttribute("roles", null); + if (rolesURI != null) { + Configuration roles = loadConfiguration(rolesURI, configuration.getLocation()); + this.roleManager.configure(roles); + } + + // Set components + final Configuration[] configurations = configuration.getChildren(); + + for( int i = 0; i < configurations.length; i++ ) { + Configuration componentConfig = configurations[i]; + + String componentName = componentConfig.getName(); + + if ("include".equals(componentName)) { + String includeURI = componentConfig.getAttribute("src"); + if (loadedURIs.contains(includeURI)) { + // Already loaded: skip to next configuration element + continue; + } + // load it and store it in the read set + Configuration includeConfig = loadConfiguration(includeURI, componentConfig.getLocation()); + loadedURIs.add(includeURI); + + // what is it? + String includeKind = includeConfig.getName(); + if (includeKind.equals("components")) { + // more components + doConfigure(includeConfig, loadedURIs); + } else if (includeKind.equals("role-list")) { + // more roles + this.roleManager.configure(includeConfig); + } else { + throw new ConfigurationException("Unknow document '" + includeKind + "' included at " + + componentConfig.getLocation()); + } + + } else { + // Component declaration + // Find the role + String role = componentConfig.getAttribute("role", null); + if (role == null) { + // Get the role from the role manager if not explicitely specified + role = roleManager.getRoleForName(componentName); + if (role == null) { + // Unknown role + throw new ConfigurationException("Unknown component type '" + componentName + + "' at " + componentConfig.getLocation()); + } + } + + // Find the className + String className = componentConfig.getAttribute("class", null); + if (className == null) { + // Get the default class name for this role + final ServiceInfo info = roleManager.getDefaultServiceInfoForRole(role); + if (info == null) { + throw new ConfigurationException("Cannot find a class for role " + role + " at " + componentConfig.getLocation()); + } + className = info.getServiceClassName(); + } + + // If it has a "name" attribute, add it to the role (similar to the + // declaration within a service selector) + // Note: this has to be done *after* finding the className above as we change the role + String name = componentConfig.getAttribute("name", null); + if (name != null) { + role = role + "/" + name; + } + + this.addComponent(className, role, componentConfig); + } + } + } + + /* (non-Javadoc) + * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) + */ + public void contextualize( final Context context ) { + this.context = context; + } + + /* (non-Javadoc) + * @see org.apache.avalon.framework.activity.Initializable#initialize() + */ + public void initialize() + throws Exception { + super.initialize(); + + for( int i = 0; i < this.newComponentHandlers.size(); i++ ) { + final ComponentHandler handler = + (ComponentHandler)this.newComponentHandlers.get( i ); + try { + handler.initialize(); + } catch( Exception e ) { + if( this.getLogger().isErrorEnabled() ) + { + this.getLogger().error( "Caught an exception trying to initialize " + + "the component handler.", e ); + } + + // Rethrow the exception + throw e; + } + } + + List keys = new ArrayList( this.componentHandlers.keySet() ); + + for( int i = 0; i < keys.size(); i++ ) { + final Object key = keys.get( i ); + final ComponentHandler handler = + (ComponentHandler)this.componentHandlers.get( key ); + + if( !this.newComponentHandlers.contains( handler ) ) { + try { + handler.initialize(); + + } catch( Exception e ) { + if( this.getLogger().isErrorEnabled() ) { + this.getLogger().error( "Caught an exception trying to initialize " + + "the component handler.", e ); + + } + // Rethrow the exception + throw e; + } + } + } + this.newComponentHandlers.clear(); + + // Initialize parent aware components + if (this.parentAwareComponents == null) { + throw new ServiceException(null, "CocoonServiceManager already initialized"); + } + + // Set parents for parentAware components + Iterator iter = this.parentAwareComponents.iterator(); + while (iter.hasNext()) { + String role = (String)iter.next(); + if ( this.parentManager != null && this.parentManager.hasService( role ) ) { + // lookup new component + Object component = null; + try { + component = this.lookup( role ); + ((CocoonServiceSelector)component).setParentLocator( this.parentManager, role ); + } catch (ServiceException ignore) { + // we don't set the parent then + } finally { + this.release( component ); + } + } + } + this.parentAwareComponents = null; // null to save memory, and catch logic bugs. + +// Object[] keyArray = this.componentHandlers.keySet().toArray(); +// Arrays.sort(keyArray); +// for (int i = 0; i < keyArray.length; i++) { +// System.err.println("Component key = " + keyArray[i]); +// } + } + + /* (non-Javadoc) + * @see org.apache.avalon.framework.activity.Disposable#dispose() + */ + public void dispose() { + boolean forceDisposal = false; + + final List disposed = new ArrayList(); + + while( componentHandlers.size() > 0 ) { + for( Iterator iterator = componentHandlers.keySet().iterator(); + iterator.hasNext(); ) { + final Object role = iterator.next(); + + final ComponentHandler handler = + (ComponentHandler)componentHandlers.get( role ); + + if( forceDisposal || handler.canBeDisposed() ) { + if( forceDisposal && getLogger().isWarnEnabled() ) { + this.getLogger().warn + ( "disposing of handler for unreleased component." + + " role [" + role + "]" ); + } + + handler.dispose(); + disposed.add( role ); + } + } + + if( disposed.size() > 0 ) { + final Iterator i = disposed.iterator(); + while ( i.hasNext() ) { + this.componentHandlers.remove( i.next() ); + } + disposed.clear(); + } else { + // no more disposable handlers! + forceDisposal = true; + } + } + super.dispose(); + } + + /** + * Add a new component to the manager. + * + * @param role the role name for the new component. + * @param component the class of this component. + * @param configuration the configuration for this component. + */ + public void addComponent( final String role, + final Class component, + final Configuration configuration ) + throws ServiceException { + if( this.initialized ) { + throw new ServiceException( role, + "Cannot add components to an initialized CocoonServiceManager." ); + } + + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "Attempting to get handler for role [" + role + "]" ); + } + + ComponentHandler handler = (ComponentHandler)this.componentHandlers.get(role); + if (handler != null) { + // Overloaded component: we only allow selectors to be overloaded + ServiceInfo info = handler.getInfo(); + if (!DefaultServiceSelector.class.isAssignableFrom(component) || + !DefaultServiceSelector.class.isAssignableFrom(info.getServiceClass())) { + throw new ServiceException(role, "Component declared at " + info.getLocation() + " is redefined at " + + configuration.getLocation()); + } + } + try { + handler = this.getComponentHandler(role, component, configuration, this); + + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "Handler type = " + handler.getClass().getName() ); + } + + this.componentHandlers.put( role, handler ); + this.newComponentHandlers.add( handler ); + } catch ( final ServiceException se ) { + throw se; + } catch( final Exception e ) { + throw new ServiceException( role, "Could not set up component handler.", e ); + } + + if ( CocoonServiceSelector.class.isAssignableFrom( component ) ) { + this.parentAwareComponents.add(role); + } + // Initialize shadow selector now, it will feed this service manager + if ( DefaultServiceSelector.class.isAssignableFrom( component )) { + try { + handler.initialize(); + } catch(ServiceException se) { + throw se; + } catch(Exception e) { + throw new ServiceException(role, "Could not initialize selector", e); + } + } + } + + /** + * Load a Configuration from a given URI. If the parent manager does not exist or does not + * provide a source resolver, a simple one is created here to load the file. + * + * @param uri the configuration's URI + * @param location the location where the load occurs (used to raise meaningful errors) + * @return the configuration + * @throws ConfigurationException + */ + private Configuration loadConfiguration(String uri, String location) throws ConfigurationException { + + // First get a source resolver + if (this.cachedSourceResolver == null) { + + if (this.parentManager != null && this.parentManager.hasService(SourceResolver.ROLE)) { + try { + this.cachedSourceResolver = (SourceResolver)this.parentManager.lookup(SourceResolver.ROLE); + } catch(ServiceException se) { + // Unlikely to happen + throw new CascadingRuntimeException("Cannot get source resolver from parent, at " + location, se); + } + } else { + // Create our own + SimpleSourceResolver simpleSR = new SimpleSourceResolver(); + simpleSR.enableLogging(getLogger()); + try { + simpleSR.contextualize(this.context); + } catch (ContextException ce) { + throw new CascadingRuntimeException("Cannot setup source resolver, at " + location, ce); + } + this.cachedSourceResolver = simpleSR; + } + } + + Configuration result; + + try { + Source src = this.cachedSourceResolver.resolveURI(uri); + DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); + result = builder.build(src.getInputStream(), src.getURI()); + } catch (ConfigurationException ce) { + throw ce; + } catch (Exception e) { + throw new ConfigurationException("Cannot load '" + uri + "' at " + location, e); + } + + return result; + } + + /** + * Release the source resolver that may have been created by the first call to + * loadConfiguration(). + */ + private void releaseCachedSourceResolver() { + if (this.cachedSourceResolver != null && + this.parentManager != null && this.parentManager.hasService(SourceResolver.ROLE)) { + this.parentManager.release(this.cachedSourceResolver); + } + this.cachedSourceResolver = null; + } +} Modified: cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceSelector.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceSelector.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceSelector.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceSelector.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceSelector.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/core/container/CocoonServiceSelector.java Thu Dec 30 06:16:00 2004 @@ -1,28 +1,28 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -/** - * Default component selector for Cocoon's components. - * - * @version CVS $Id: CocoonServiceSelector.java 55144 2004-10-20 12:26:09Z ugo $ - */ -public class CocoonServiceSelector extends StandaloneServiceSelector { - - // TODO: Can we remove this? - -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +/** + * Default component selector for Cocoon's components. + * + * @version CVS $Id$ + */ +public class CocoonServiceSelector extends StandaloneServiceSelector { + + // TODO: Can we remove this? + +} Modified: cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentFactory.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentFactory.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentFactory.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentFactory.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentFactory.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentFactory.java Thu Dec 30 06:16:00 2004 @@ -1,174 +1,174 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -import java.lang.reflect.Method; - -import org.apache.avalon.excalibur.logger.LoggerManager; -import org.apache.avalon.excalibur.pool.Recyclable; -import org.apache.avalon.framework.container.ContainerUtil; -import org.apache.avalon.framework.context.Context; -import org.apache.avalon.framework.logger.Logger; -import org.apache.avalon.framework.parameters.Parameterizable; -import org.apache.avalon.framework.parameters.Parameters; -import org.apache.avalon.framework.service.ServiceManager; -import org.apache.cocoon.components.ServiceInfo; - -/** - * Factory for Avalon based components. - * - * @version CVS $Id: ComponentFactory.java 55172 2004-10-20 17:52:18Z cziegeler $ - */ -public class ComponentFactory { - - protected final ServiceInfo serviceInfo; - - /** The Context for the component - */ - protected final Context context; - - /** The service manager for this component - */ - protected final ServiceManager serviceManager; - - /** The parameters for this component - */ - protected Parameters parameters; - - protected final Logger logger; - - protected final LoggerManager loggerManager; - - protected final RoleManager roleManager; - - /** - * Construct a new component factory for the specified component. - * - * @param componentClass the class to instantiate (must have a default constructor). - * @param configuration the <code>Configuration</code> object to pass to new instances. - * @param seerviceManager the service manager to pass to <code>Serviceable</code>s. - * @param context the <code>Context</code> to pass to <code>Contexutalizable</code>s. - * - */ - public ComponentFactory( final ServiceManager serviceManager, - final Context context, - final Logger logger, - final LoggerManager loggerManager, - final RoleManager roleManager, - final ServiceInfo info) { - this.serviceManager = serviceManager; - this.context = context; - this.loggerManager = loggerManager; - this.roleManager = roleManager; - this.serviceInfo = info; - - Logger actualLogger = logger; - // If the handler is created "manually" (e.g. XSP engine), loggerManager can be null - if(loggerManager != null && this.serviceInfo.getConfiguration() != null) { - final String category = this.serviceInfo.getConfiguration().getAttribute("logger", null); - if(category != null) { - actualLogger = loggerManager.getLoggerForCategory(category); - } - } - this.logger = actualLogger; - } - - /** - * Create a new instance - */ - public Object newInstance() - throws Exception { - final Object component = this.serviceInfo.getServiceClass().newInstance(); - - if( this.logger.isDebugEnabled() ) { - this.logger.debug( "ComponentFactory creating new instance of " + - this.serviceInfo.getServiceClass().getName() + "." ); - } - - ContainerUtil.enableLogging(component, this.logger); - ContainerUtil.contextualize( component, this.context ); - ContainerUtil.service( component, this.serviceManager ); - ContainerUtil.configure( component, this.serviceInfo.getConfiguration() ); - - if( component instanceof Parameterizable ) { - if ( this.parameters == null ) { - this.parameters = Parameters.fromConfiguration( this.serviceInfo.getConfiguration() ); - } - ContainerUtil.parameterize( component, this.parameters ); - } - - ContainerUtil.initialize( component ); - - final Method method = this.serviceInfo.getInitMethod(); - if ( method != null ) { - method.invoke(component, null); - } - - ContainerUtil.start( component ); - - return component; - } - - public Class getCreatedClass() { - return this.serviceInfo.getServiceClass(); - } - - /** - * Destroy an instance - */ - public void decommission( final Object component ) - throws Exception { - if( this.logger.isDebugEnabled() ) { - this.logger.debug( "ComponentFactory decommissioning instance of " + - this.serviceInfo.getServiceClass().getName() + "." ); - } - - ContainerUtil.stop( component ); - ContainerUtil.dispose( component ); - - final Method method = this.serviceInfo.getDestroyMethod(); - if ( method != null ) { - method.invoke(component, null); - } - } - - /** - * Handle service specific methods for getting it out of the pool - */ - public void exitingPool( final Object component ) - throws Exception { - final Method method = this.serviceInfo.getPoolOutMethod(); - if ( method != null ) { - method.invoke(component, null); - } - } - - /** - * Handle service specific methods for putting it into the pool - */ - public void enteringPool( final Object component ) - throws Exception { - // Handle Recyclable objects - if( component instanceof Recyclable ) { - ( (Recyclable)component ).recycle(); - } - final Method method = this.serviceInfo.getPoolInMethod(); - if ( method != null ) { - method.invoke(component, null); - } - } -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +import java.lang.reflect.Method; + +import org.apache.avalon.excalibur.logger.LoggerManager; +import org.apache.avalon.excalibur.pool.Recyclable; +import org.apache.avalon.framework.container.ContainerUtil; +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.logger.Logger; +import org.apache.avalon.framework.parameters.Parameterizable; +import org.apache.avalon.framework.parameters.Parameters; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.cocoon.components.ServiceInfo; + +/** + * Factory for Avalon based components. + * + * @version CVS $Id$ + */ +public class ComponentFactory { + + protected final ServiceInfo serviceInfo; + + /** The Context for the component + */ + protected final Context context; + + /** The service manager for this component + */ + protected final ServiceManager serviceManager; + + /** The parameters for this component + */ + protected Parameters parameters; + + protected final Logger logger; + + protected final LoggerManager loggerManager; + + protected final RoleManager roleManager; + + /** + * Construct a new component factory for the specified component. + * + * @param componentClass the class to instantiate (must have a default constructor). + * @param configuration the <code>Configuration</code> object to pass to new instances. + * @param seerviceManager the service manager to pass to <code>Serviceable</code>s. + * @param context the <code>Context</code> to pass to <code>Contexutalizable</code>s. + * + */ + public ComponentFactory( final ServiceManager serviceManager, + final Context context, + final Logger logger, + final LoggerManager loggerManager, + final RoleManager roleManager, + final ServiceInfo info) { + this.serviceManager = serviceManager; + this.context = context; + this.loggerManager = loggerManager; + this.roleManager = roleManager; + this.serviceInfo = info; + + Logger actualLogger = logger; + // If the handler is created "manually" (e.g. XSP engine), loggerManager can be null + if(loggerManager != null && this.serviceInfo.getConfiguration() != null) { + final String category = this.serviceInfo.getConfiguration().getAttribute("logger", null); + if(category != null) { + actualLogger = loggerManager.getLoggerForCategory(category); + } + } + this.logger = actualLogger; + } + + /** + * Create a new instance + */ + public Object newInstance() + throws Exception { + final Object component = this.serviceInfo.getServiceClass().newInstance(); + + if( this.logger.isDebugEnabled() ) { + this.logger.debug( "ComponentFactory creating new instance of " + + this.serviceInfo.getServiceClass().getName() + "." ); + } + + ContainerUtil.enableLogging(component, this.logger); + ContainerUtil.contextualize( component, this.context ); + ContainerUtil.service( component, this.serviceManager ); + ContainerUtil.configure( component, this.serviceInfo.getConfiguration() ); + + if( component instanceof Parameterizable ) { + if ( this.parameters == null ) { + this.parameters = Parameters.fromConfiguration( this.serviceInfo.getConfiguration() ); + } + ContainerUtil.parameterize( component, this.parameters ); + } + + ContainerUtil.initialize( component ); + + final Method method = this.serviceInfo.getInitMethod(); + if ( method != null ) { + method.invoke(component, null); + } + + ContainerUtil.start( component ); + + return component; + } + + public Class getCreatedClass() { + return this.serviceInfo.getServiceClass(); + } + + /** + * Destroy an instance + */ + public void decommission( final Object component ) + throws Exception { + if( this.logger.isDebugEnabled() ) { + this.logger.debug( "ComponentFactory decommissioning instance of " + + this.serviceInfo.getServiceClass().getName() + "." ); + } + + ContainerUtil.stop( component ); + ContainerUtil.dispose( component ); + + final Method method = this.serviceInfo.getDestroyMethod(); + if ( method != null ) { + method.invoke(component, null); + } + } + + /** + * Handle service specific methods for getting it out of the pool + */ + public void exitingPool( final Object component ) + throws Exception { + final Method method = this.serviceInfo.getPoolOutMethod(); + if ( method != null ) { + method.invoke(component, null); + } + } + + /** + * Handle service specific methods for putting it into the pool + */ + public void enteringPool( final Object component ) + throws Exception { + // Handle Recyclable objects + if( component instanceof Recyclable ) { + ( (Recyclable)component ).recycle(); + } + final Method method = this.serviceInfo.getPoolInMethod(); + if ( method != null ) { + method.invoke(component, null); + } + } +} Modified: cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentHandler.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentHandler.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentHandler.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentHandler.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentHandler.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ComponentHandler.java Thu Dec 30 06:16:00 2004 @@ -1,79 +1,79 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -import org.apache.cocoon.components.ServiceInfo; - -/** - * This class acts like a Factory to instantiate the correct version - * of the component handler that you need. - * - * @version CVS $Id: AbstractComponentHandler.java 55144 2004-10-20 12:26:09Z ugo $ - */ -public interface ComponentHandler { - - /** - * Get an instance of the type of component handled by this handler. - * - * @return an instance - * @exception Exception if an error occurs - */ - Object get() throws Exception; - - /** - * Put back an instance of the type of component handled by this handler. - * - * @param component a service - * @exception Exception if an error occurs - */ - void put( Object component ) - throws Exception; - - /** - * Indicates if this handler manages a single object, i.e. all calls to [EMAIL PROTECTED] #get()} - * will return the same object. - * - * @return <code>true</code> if managed object is a singleton - */ - boolean isSingleton(); - - /** - * Returns <code>true</code> if this component handler can safely be - * disposed (i.e. none of the components it is handling are still - * being used). - * - * @return <code>true</code> if this component handler can safely be - * disposed; <code>false</code> otherwise - */ - boolean canBeDisposed(); - - /** - * Dispose of the component handler and any associated Pools and Factories. - */ - public void dispose(); - - /** - * Initialize this handler - */ - void initialize() throws Exception; - - /** - * Get the service metadata for this handler - */ - ServiceInfo getInfo(); - -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +import org.apache.cocoon.components.ServiceInfo; + +/** + * This class acts like a Factory to instantiate the correct version + * of the component handler that you need. + * + * @version CVS $Id$ + */ +public interface ComponentHandler { + + /** + * Get an instance of the type of component handled by this handler. + * + * @return an instance + * @exception Exception if an error occurs + */ + Object get() throws Exception; + + /** + * Put back an instance of the type of component handled by this handler. + * + * @param component a service + * @exception Exception if an error occurs + */ + void put( Object component ) + throws Exception; + + /** + * Indicates if this handler manages a single object, i.e. all calls to [EMAIL PROTECTED] #get()} + * will return the same object. + * + * @return <code>true</code> if managed object is a singleton + */ + boolean isSingleton(); + + /** + * Returns <code>true</code> if this component handler can safely be + * disposed (i.e. none of the components it is handling are still + * being used). + * + * @return <code>true</code> if this component handler can safely be + * disposed; <code>false</code> otherwise + */ + boolean canBeDisposed(); + + /** + * Dispose of the component handler and any associated Pools and Factories. + */ + public void dispose(); + + /** + * Initialize this handler + */ + void initialize() throws Exception; + + /** + * Get the service metadata for this handler + */ + ServiceInfo getInfo(); + +} Modified: cocoon/trunk/src/core/java/org/apache/cocoon/core/container/PoolableComponentHandler.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/core/container/PoolableComponentHandler.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/PoolableComponentHandler.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/PoolableComponentHandler.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/core/container/PoolableComponentHandler.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/core/container/PoolableComponentHandler.java Thu Dec 30 06:16:00 2004 @@ -1,228 +1,228 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -import java.util.Iterator; -import java.util.LinkedList; - -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.logger.Logger; -import org.apache.cocoon.components.ServiceInfo; - -/** - * The PoolableComponentHandler to make sure that poolable components are initialized - * destroyed and pooled correctly. - * <p> - * Components which implement Poolable may be configured to be pooled using the following - * example configuration. This example assumes that the user component class MyComp - * implements Poolable. - * <p> - * Configuration Example: - * <pre> - * <my-comp pool-max="8"/> - * </pre> - * <p> - * Roles Example: - * <pre> - * <role name="com.mypkg.MyComponent" - * shorthand="my-comp" - * default-class="com.mypkg.DefaultMyComponent"/> - * </pre> - * <p> - * Configuration Attributes: - * <ul> - * <li>The <code>pool-max</code> attribute is used to set the maximum number of components which - * will be pooled. (Defaults to "8") If additional instances are required, they're created, - * but not pooled.</li> - * </ul> - * - * @version CVS $Id: PoolableComponentHandler.java 55144 2004-10-20 12:26:09Z ugo $ - */ -public class PoolableComponentHandler -extends AbstractComponentHandler { - - /** The default max size of the pool */ - public static final int DEFAULT_MAX_POOL_SIZE = 8; - - /** - * Object used to synchronize access to the get and put methods - */ - protected final Object semaphore = new Object(); - - /** - * The maximum size of the pool. - */ - private final int max; - - /** - * List of the Poolable instances which are available for use. - */ - private LinkedList ready; - - /** - * Store the size of the ready list to optimize operations which require this value. - */ - private int readySize; - - /** - * Total number of Poolable instances in the pool - */ - private int size; - - /** - * Create a PoolableComponentHandler which manages a pool of Components - * created by the specified factory object. - * - * @param factory The factory object which is responsible for creating the components - * managed by the ComponentHandler. - * @param config The configuration to use to configure the pool. - */ - public PoolableComponentHandler( final ServiceInfo info, - final Logger logger, - final ComponentFactory factory, - final Configuration config ) - throws Exception { - super(info, logger, factory); - - final int poolMax = config.getAttributeAsInteger( "pool-max", DEFAULT_MAX_POOL_SIZE ); - this.max = ( poolMax <= 0 ? Integer.MAX_VALUE : poolMax ); - - // Create the pool lists. - this.ready = new LinkedList(); - } - - /** - * Dispose of the ComponentHandler and any associated Pools and Factories. - */ - public void dispose() { - super.dispose(); - - // Any Poolables in the m_ready list need to be disposed of - synchronized( this.semaphore ) { - // Remove objects in the ready list. - for( Iterator iter = this.ready.iterator(); iter.hasNext(); ) { - Object poolable = iter.next(); - iter.remove(); - this.readySize--; - this.permanentlyRemovePoolable( poolable ); - } - - if( ( this.size > 0 ) && this.logger.isDebugEnabled() ) { - this.logger.debug( "There were " + this.size - + " outstanding objects when the pool was disposed." ); - } - } - } - - /** - * Permanently removes a poolable from the pool's active list and - * destroys it so that it will not ever be reused. - * <p> - * This method is only called by threads that have m_semaphore locked. - */ - protected void permanentlyRemovePoolable( Object poolable ) { - this.size--; - this.decommission( poolable ); - } - - /** - * Gets a Poolable from the pool. If there is room in the pool, a new Poolable will be - * created. Depending on the parameters to the constructor, the method may block or throw - * an exception if a Poolable is not available on the pool. - * - * @return Always returns a Poolable. Contract requires that put must always be called with - * the Poolable returned. - * @throws Exception An exception may be thrown as described above or if there is an exception - * thrown by the ObjectFactory's newInstance() method. - */ - protected Object doGet() throws Exception { - Object poolable; - synchronized( this.semaphore ) { - // Look for a Poolable at the end of the m_ready list - if( this.readySize > 0 ){ - // A poolable is ready and waiting in the pool - poolable = this.ready.removeLast(); - this.readySize--; - } else { - // Create a new poolable. May throw an exception if the poolable can not be - // instantiated. - poolable = this.factory.newInstance(); - this.size++; - - if( this.logger.isDebugEnabled() ) { - this.logger.debug( "Created a new " + poolable.getClass().getName() - + " from the object factory." ); - } - } - } - - this.factory.exitingPool(poolable); - - if( this.logger.isDebugEnabled() ) { - this.logger.debug( "Got a " + poolable.getClass().getName() + " from the pool." ); - } - - return poolable; - } - - /** - * Returns a poolable to the pool - * - * @param poolable Poolable to return to the pool. - */ - protected void doPut( final Object poolable ) { - try { - this.factory.enteringPool(poolable); - } catch (Exception ignore) { - this.logger.warn("Exception during putting component back into the pool.", ignore); - } - - synchronized( this.semaphore ) { - if( this.size <= this.max ) { - if( this.disposed ) { - // The pool has already been disposed. - if( this.logger.isDebugEnabled() ) { - this.logger.debug( "Put called for a " + poolable.getClass().getName() - + " after the pool was disposed." ); - } - - this.permanentlyRemovePoolable( poolable ); - } else { - // There is room in the pool to keep this poolable. - if( this.logger.isDebugEnabled() ) { - this.logger.debug( "Put a " + poolable.getClass().getName() - + " back into the pool." ); - } - - this.ready.addLast( poolable ); - this.readySize++; - - } - } else { - // More Poolables were created than can be held in the pool, so remove. - if( this.logger.isDebugEnabled() ) { - this.logger.debug( "No room to put a " + poolable.getClass().getName() - + " back into the pool, so remove it." ); - } - - this.permanentlyRemovePoolable( poolable ); - } - } - } - - -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +import java.util.Iterator; +import java.util.LinkedList; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.logger.Logger; +import org.apache.cocoon.components.ServiceInfo; + +/** + * The PoolableComponentHandler to make sure that poolable components are initialized + * destroyed and pooled correctly. + * <p> + * Components which implement Poolable may be configured to be pooled using the following + * example configuration. This example assumes that the user component class MyComp + * implements Poolable. + * <p> + * Configuration Example: + * <pre> + * <my-comp pool-max="8"/> + * </pre> + * <p> + * Roles Example: + * <pre> + * <role name="com.mypkg.MyComponent" + * shorthand="my-comp" + * default-class="com.mypkg.DefaultMyComponent"/> + * </pre> + * <p> + * Configuration Attributes: + * <ul> + * <li>The <code>pool-max</code> attribute is used to set the maximum number of components which + * will be pooled. (Defaults to "8") If additional instances are required, they're created, + * but not pooled.</li> + * </ul> + * + * @version CVS $Id$ + */ +public class PoolableComponentHandler +extends AbstractComponentHandler { + + /** The default max size of the pool */ + public static final int DEFAULT_MAX_POOL_SIZE = 8; + + /** + * Object used to synchronize access to the get and put methods + */ + protected final Object semaphore = new Object(); + + /** + * The maximum size of the pool. + */ + private final int max; + + /** + * List of the Poolable instances which are available for use. + */ + private LinkedList ready; + + /** + * Store the size of the ready list to optimize operations which require this value. + */ + private int readySize; + + /** + * Total number of Poolable instances in the pool + */ + private int size; + + /** + * Create a PoolableComponentHandler which manages a pool of Components + * created by the specified factory object. + * + * @param factory The factory object which is responsible for creating the components + * managed by the ComponentHandler. + * @param config The configuration to use to configure the pool. + */ + public PoolableComponentHandler( final ServiceInfo info, + final Logger logger, + final ComponentFactory factory, + final Configuration config ) + throws Exception { + super(info, logger, factory); + + final int poolMax = config.getAttributeAsInteger( "pool-max", DEFAULT_MAX_POOL_SIZE ); + this.max = ( poolMax <= 0 ? Integer.MAX_VALUE : poolMax ); + + // Create the pool lists. + this.ready = new LinkedList(); + } + + /** + * Dispose of the ComponentHandler and any associated Pools and Factories. + */ + public void dispose() { + super.dispose(); + + // Any Poolables in the m_ready list need to be disposed of + synchronized( this.semaphore ) { + // Remove objects in the ready list. + for( Iterator iter = this.ready.iterator(); iter.hasNext(); ) { + Object poolable = iter.next(); + iter.remove(); + this.readySize--; + this.permanentlyRemovePoolable( poolable ); + } + + if( ( this.size > 0 ) && this.logger.isDebugEnabled() ) { + this.logger.debug( "There were " + this.size + + " outstanding objects when the pool was disposed." ); + } + } + } + + /** + * Permanently removes a poolable from the pool's active list and + * destroys it so that it will not ever be reused. + * <p> + * This method is only called by threads that have m_semaphore locked. + */ + protected void permanentlyRemovePoolable( Object poolable ) { + this.size--; + this.decommission( poolable ); + } + + /** + * Gets a Poolable from the pool. If there is room in the pool, a new Poolable will be + * created. Depending on the parameters to the constructor, the method may block or throw + * an exception if a Poolable is not available on the pool. + * + * @return Always returns a Poolable. Contract requires that put must always be called with + * the Poolable returned. + * @throws Exception An exception may be thrown as described above or if there is an exception + * thrown by the ObjectFactory's newInstance() method. + */ + protected Object doGet() throws Exception { + Object poolable; + synchronized( this.semaphore ) { + // Look for a Poolable at the end of the m_ready list + if( this.readySize > 0 ){ + // A poolable is ready and waiting in the pool + poolable = this.ready.removeLast(); + this.readySize--; + } else { + // Create a new poolable. May throw an exception if the poolable can not be + // instantiated. + poolable = this.factory.newInstance(); + this.size++; + + if( this.logger.isDebugEnabled() ) { + this.logger.debug( "Created a new " + poolable.getClass().getName() + + " from the object factory." ); + } + } + } + + this.factory.exitingPool(poolable); + + if( this.logger.isDebugEnabled() ) { + this.logger.debug( "Got a " + poolable.getClass().getName() + " from the pool." ); + } + + return poolable; + } + + /** + * Returns a poolable to the pool + * + * @param poolable Poolable to return to the pool. + */ + protected void doPut( final Object poolable ) { + try { + this.factory.enteringPool(poolable); + } catch (Exception ignore) { + this.logger.warn("Exception during putting component back into the pool.", ignore); + } + + synchronized( this.semaphore ) { + if( this.size <= this.max ) { + if( this.disposed ) { + // The pool has already been disposed. + if( this.logger.isDebugEnabled() ) { + this.logger.debug( "Put called for a " + poolable.getClass().getName() + + " after the pool was disposed." ); + } + + this.permanentlyRemovePoolable( poolable ); + } else { + // There is room in the pool to keep this poolable. + if( this.logger.isDebugEnabled() ) { + this.logger.debug( "Put a " + poolable.getClass().getName() + + " back into the pool." ); + } + + this.ready.addLast( poolable ); + this.readySize++; + + } + } else { + // More Poolables were created than can be held in the pool, so remove. + if( this.logger.isDebugEnabled() ) { + this.logger.debug( "No room to put a " + poolable.getClass().getName() + + " back into the pool, so remove it." ); + } + + this.permanentlyRemovePoolable( poolable ); + } + } + } + + +} Modified: cocoon/trunk/src/core/java/org/apache/cocoon/core/container/RoleManager.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/core/container/RoleManager.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/RoleManager.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/RoleManager.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/core/container/RoleManager.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/core/container/RoleManager.java Thu Dec 30 06:16:00 2004 @@ -1,283 +1,283 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -import java.net.URL; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.apache.avalon.framework.configuration.Configurable; -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; -import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; -import org.apache.avalon.framework.logger.AbstractLogEnabled; -import org.apache.cocoon.components.ServiceInfo; - -/** - * Default RoleManager implementation. It populates the RoleManager - * from a configuration file. - * - * @version CVS $Id: RoleManager.java 55144 2004-10-20 12:26:09Z ugo $ - */ -public class RoleManager -extends AbstractLogEnabled -implements Configurable { - - /** Map for shorthand to role mapping */ - private Map shorthands = new HashMap(); - - /** Map for role to default classname mapping */ - private Map classNames = new HashMap(); - - /** Map for role->key to classname mapping */ - private Map keyClassNames = new HashMap(); - - /** Parent role manager for nested resolution */ - private final RoleManager parent; - - /** - * Default constructor--this RoleManager has no parent. - */ - public RoleManager() { - this.parent = null; - } - - /** - * Alternate constructor--this RoleManager has the specified - * parent. - * - * @param parent The parent <code>RoleManager</code>. - */ - public RoleManager( RoleManager parent ) { - this.parent = parent; - } - - /** - * Retrieves the real role name from a shorthand name. Usually - * the shorthand name refers to a configuration element name. If - * this RoleManager does not have the match, and there is a parent - * RoleManager, the parent will be asked to resolve the role. - * - * @param shorthandName The shortname that is an alias for the role. - * @return the official role name. - */ - public final String getRoleForName( final String shorthandName ) { - final String role = (String)this.shorthands.get( shorthandName ); - - if( null == role && null != this.parent ) { - return this.parent.getRoleForName( shorthandName ); - } - - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( "looking up shorthand " + shorthandName + - ", returning " + role ); - } - - return role; - } - - /** - * Retrieves the default class name for the specified role. This - * is only called when the configuration does not specify the - * class explicitly. If this RoleManager does not have the match, - * and there is a parent RoleManager, the parent will be asked - * to resolve the class name. - * - * @param role The role that has a default implementation. - * @return the Fully Qualified Class Name (FQCN) for the role. - */ - public final ServiceInfo getDefaultServiceInfoForRole( final String role ) { - final ServiceInfo info = (ServiceInfo)this.classNames.get( role ); - - if( info == null && this.parent != null ) { - return this.parent.getDefaultServiceInfoForRole( role ); - } - - return info; - } - - /** - * Retrieves a default class name for a role/key combination. - * This is only called when a role is mapped to a - * CocoonServiceSelector, and the configuration elements use - * shorthand names for the type of component. If this RoleManager - * does not have the match, and there is a parent RoleManager, the - * parent will be asked to resolve the class name. - * - * @param role The role that this shorthand refers to. - * @param shorthand The shorthand name for the type of component - * @return the FQCN for the role/key combination. - */ - public final ServiceInfo getDefaultServiceInfoForKey( final String role, - final String shorthand ) { - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( "looking up keymap for role " + role ); - } - - final Map keyMap = (Map)this.keyClassNames.get( role ); - - if( null == keyMap ) { - if( null != this.parent ) { - return this.parent.getDefaultServiceInfoForKey( role, shorthand ); - } - return null; - } - - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( "looking up classname for key " + shorthand ); - } - - final ServiceInfo s = ( ServiceInfo ) keyMap.get( shorthand ); - - if( s == null && this.parent != null ) { - return this.parent.getDefaultServiceInfoForKey( role, shorthand ); - } - return s; - } - - /** - * Reads a configuration object and creates the role, shorthand, - * and class name mapping. - * - * @param configuration The configuration object. - * @throws ConfigurationException if the configuration is malformed - */ - public final void configure( final Configuration configuration ) - throws ConfigurationException { - - // When reading a roles file, we only want "role" elements. - boolean strictMode = "roles-list".equals(configuration.getName()); - - final Configuration[] roles = configuration.getChildren(); - - for( int i = 0; i < roles.length; i++ ) { - Configuration role = roles[i]; - - if (!"role".equals(role.getName())) { - if (strictMode) { - throw new ConfigurationException("Unexpected '" + role.getName() + "' element at " + role.getLocation()); - } - // Skip to next one - continue; - } - - final String roleName = role.getAttribute("name"); - final String shorthand = role.getAttribute("shorthand", null); - final String defaultClassName = role.getAttribute("default-class", null); - - if (shorthand != null) { - // Store the shorthand and check that its consistent with any previous one - Object previous = this.shorthands.put( shorthand, roleName ); - if (previous != null && !previous.equals(roleName)) { - throw new ConfigurationException("Shorthand '" + shorthand + "' already used for role " + - previous + ": inconsistent declaration at " + role.getLocation()); - } - } - - if( defaultClassName != null ) { - ServiceInfo info = (ServiceInfo)this.classNames.get(roleName); - if (info == null) { - // Create a new info and store it - info = new ServiceInfo(); - info.setServiceClassName(defaultClassName); - info.fill(role); - this.classNames.put(roleName, info); - } else { - // Check that it's consistent with the existing info - if (!defaultClassName.equals(info.getServiceClassName())) { - throw new ConfigurationException("Invalid redeclaration: default class already set to " + info.getServiceClassName() + - " for role " + roleName + " at " + role.getLocation()); - } - //FIXME: should check also other ServiceInfo members, but they're currently not used - } - } - - final Configuration[] keys = role.getChildren( "hint" ); - if( keys.length > 0 ) { - Map keyMap = (Map)this.keyClassNames.get(roleName); - if (keyMap == null) { - keyMap = new HashMap(); - this.keyClassNames.put(roleName, keyMap); - } - - for( int j = 0; j < keys.length; j++ ) { - Configuration key = keys[j]; - - final String shortHand = key.getAttribute( "shorthand" ).trim(); - final String className = key.getAttribute( "class" ).trim(); - - ServiceInfo info = (ServiceInfo)keyMap.get(shortHand); - if (info == null) { - info = new ServiceInfo(); - info.setServiceClassName(className); - info.fill(key); - - keyMap.put( shortHand, info ); - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( "Adding key type " + shortHand + - " associated with role " + roleName + - " and class " + className ); - } - } else { - // Check that it's consistent with the existing info - if (!className.equals(info.getServiceClassName())) { - throw new ConfigurationException("Invalid redeclaration: class already set to " + info.getServiceClassName() + - " for hint " + shortHand + " at " + key.getLocation()); - } - //FIXME: should check also other ServiceInfo members, but they're currently not used - } - } - } - - if( this.getLogger().isDebugEnabled() ) { - this.getLogger().debug( "added Role " + roleName + " with shorthand " + - shorthand + " for " + defaultClassName ); - } - } - } - - - - private Set loadedURLs = new HashSet(); - - public void loadFromClassPath() throws Exception { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - Enumeration resources = cl.getResources("/org/apache/cocoon/cocoon.roles"); - - while(resources.hasMoreElements()) { - URL url = (URL)resources.nextElement(); - loadURL(url.toExternalForm()); - } - } - - public void loadURL(String resource) throws Exception { - if (!hasLoaded(resource)) { - loadedURLs.add(resource); - - DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); - Configuration config = builder.build(resource); - configure(config); - } - } - - public boolean hasLoaded(String resource) { - return loadedURLs.contains(resource) || (parent != null && parent.hasLoaded(resource)); - } -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +import java.net.URL; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.avalon.framework.configuration.Configurable; +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.cocoon.components.ServiceInfo; + +/** + * Default RoleManager implementation. It populates the RoleManager + * from a configuration file. + * + * @version CVS $Id$ + */ +public class RoleManager +extends AbstractLogEnabled +implements Configurable { + + /** Map for shorthand to role mapping */ + private Map shorthands = new HashMap(); + + /** Map for role to default classname mapping */ + private Map classNames = new HashMap(); + + /** Map for role->key to classname mapping */ + private Map keyClassNames = new HashMap(); + + /** Parent role manager for nested resolution */ + private final RoleManager parent; + + /** + * Default constructor--this RoleManager has no parent. + */ + public RoleManager() { + this.parent = null; + } + + /** + * Alternate constructor--this RoleManager has the specified + * parent. + * + * @param parent The parent <code>RoleManager</code>. + */ + public RoleManager( RoleManager parent ) { + this.parent = parent; + } + + /** + * Retrieves the real role name from a shorthand name. Usually + * the shorthand name refers to a configuration element name. If + * this RoleManager does not have the match, and there is a parent + * RoleManager, the parent will be asked to resolve the role. + * + * @param shorthandName The shortname that is an alias for the role. + * @return the official role name. + */ + public final String getRoleForName( final String shorthandName ) { + final String role = (String)this.shorthands.get( shorthandName ); + + if( null == role && null != this.parent ) { + return this.parent.getRoleForName( shorthandName ); + } + + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "looking up shorthand " + shorthandName + + ", returning " + role ); + } + + return role; + } + + /** + * Retrieves the default class name for the specified role. This + * is only called when the configuration does not specify the + * class explicitly. If this RoleManager does not have the match, + * and there is a parent RoleManager, the parent will be asked + * to resolve the class name. + * + * @param role The role that has a default implementation. + * @return the Fully Qualified Class Name (FQCN) for the role. + */ + public final ServiceInfo getDefaultServiceInfoForRole( final String role ) { + final ServiceInfo info = (ServiceInfo)this.classNames.get( role ); + + if( info == null && this.parent != null ) { + return this.parent.getDefaultServiceInfoForRole( role ); + } + + return info; + } + + /** + * Retrieves a default class name for a role/key combination. + * This is only called when a role is mapped to a + * CocoonServiceSelector, and the configuration elements use + * shorthand names for the type of component. If this RoleManager + * does not have the match, and there is a parent RoleManager, the + * parent will be asked to resolve the class name. + * + * @param role The role that this shorthand refers to. + * @param shorthand The shorthand name for the type of component + * @return the FQCN for the role/key combination. + */ + public final ServiceInfo getDefaultServiceInfoForKey( final String role, + final String shorthand ) { + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "looking up keymap for role " + role ); + } + + final Map keyMap = (Map)this.keyClassNames.get( role ); + + if( null == keyMap ) { + if( null != this.parent ) { + return this.parent.getDefaultServiceInfoForKey( role, shorthand ); + } + return null; + } + + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "looking up classname for key " + shorthand ); + } + + final ServiceInfo s = ( ServiceInfo ) keyMap.get( shorthand ); + + if( s == null && this.parent != null ) { + return this.parent.getDefaultServiceInfoForKey( role, shorthand ); + } + return s; + } + + /** + * Reads a configuration object and creates the role, shorthand, + * and class name mapping. + * + * @param configuration The configuration object. + * @throws ConfigurationException if the configuration is malformed + */ + public final void configure( final Configuration configuration ) + throws ConfigurationException { + + // When reading a roles file, we only want "role" elements. + boolean strictMode = "roles-list".equals(configuration.getName()); + + final Configuration[] roles = configuration.getChildren(); + + for( int i = 0; i < roles.length; i++ ) { + Configuration role = roles[i]; + + if (!"role".equals(role.getName())) { + if (strictMode) { + throw new ConfigurationException("Unexpected '" + role.getName() + "' element at " + role.getLocation()); + } + // Skip to next one + continue; + } + + final String roleName = role.getAttribute("name"); + final String shorthand = role.getAttribute("shorthand", null); + final String defaultClassName = role.getAttribute("default-class", null); + + if (shorthand != null) { + // Store the shorthand and check that its consistent with any previous one + Object previous = this.shorthands.put( shorthand, roleName ); + if (previous != null && !previous.equals(roleName)) { + throw new ConfigurationException("Shorthand '" + shorthand + "' already used for role " + + previous + ": inconsistent declaration at " + role.getLocation()); + } + } + + if( defaultClassName != null ) { + ServiceInfo info = (ServiceInfo)this.classNames.get(roleName); + if (info == null) { + // Create a new info and store it + info = new ServiceInfo(); + info.setServiceClassName(defaultClassName); + info.fill(role); + this.classNames.put(roleName, info); + } else { + // Check that it's consistent with the existing info + if (!defaultClassName.equals(info.getServiceClassName())) { + throw new ConfigurationException("Invalid redeclaration: default class already set to " + info.getServiceClassName() + + " for role " + roleName + " at " + role.getLocation()); + } + //FIXME: should check also other ServiceInfo members, but they're currently not used + } + } + + final Configuration[] keys = role.getChildren( "hint" ); + if( keys.length > 0 ) { + Map keyMap = (Map)this.keyClassNames.get(roleName); + if (keyMap == null) { + keyMap = new HashMap(); + this.keyClassNames.put(roleName, keyMap); + } + + for( int j = 0; j < keys.length; j++ ) { + Configuration key = keys[j]; + + final String shortHand = key.getAttribute( "shorthand" ).trim(); + final String className = key.getAttribute( "class" ).trim(); + + ServiceInfo info = (ServiceInfo)keyMap.get(shortHand); + if (info == null) { + info = new ServiceInfo(); + info.setServiceClassName(className); + info.fill(key); + + keyMap.put( shortHand, info ); + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "Adding key type " + shortHand + + " associated with role " + roleName + + " and class " + className ); + } + } else { + // Check that it's consistent with the existing info + if (!className.equals(info.getServiceClassName())) { + throw new ConfigurationException("Invalid redeclaration: class already set to " + info.getServiceClassName() + + " for hint " + shortHand + " at " + key.getLocation()); + } + //FIXME: should check also other ServiceInfo members, but they're currently not used + } + } + } + + if( this.getLogger().isDebugEnabled() ) { + this.getLogger().debug( "added Role " + roleName + " with shorthand " + + shorthand + " for " + defaultClassName ); + } + } + } + + + + private Set loadedURLs = new HashSet(); + + public void loadFromClassPath() throws Exception { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + Enumeration resources = cl.getResources("/org/apache/cocoon/cocoon.roles"); + + while(resources.hasMoreElements()) { + URL url = (URL)resources.nextElement(); + loadURL(url.toExternalForm()); + } + } + + public void loadURL(String resource) throws Exception { + if (!hasLoaded(resource)) { + loadedURLs.add(resource); + + DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); + Configuration config = builder.build(resource); + configure(config); + } + } + + public boolean hasLoaded(String resource) { + return loadedURLs.contains(resource) || (parent != null && parent.hasLoaded(resource)); + } +} Modified: cocoon/trunk/src/core/java/org/apache/cocoon/core/container/SingleThreadedComponentHandler.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/core/container/SingleThreadedComponentHandler.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/SingleThreadedComponentHandler.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/SingleThreadedComponentHandler.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/core/container/SingleThreadedComponentHandler.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/core/container/SingleThreadedComponentHandler.java Thu Dec 30 06:16:00 2004 @@ -1,67 +1,67 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -import org.apache.avalon.framework.logger.Logger; -import org.apache.cocoon.components.ServiceInfo; - -/** - * The DefaultComponentHandler to make sure components are initialized - * and destroyed correctly. - * - * @version CVS $Id: SingleThreadedComponentHandler.java 55144 2004-10-20 12:26:09Z ugo $ - */ -public class SingleThreadedComponentHandler -extends AbstractComponentHandler { - - /** - * Create a SingleThreadedComponentHandler which manages a pool of Components - * created by the specified factory object. - * - * @param logger The logger to use - * @param factory The factory object which is responsible for creating the components - * managed by the handler. - */ - public SingleThreadedComponentHandler( final ServiceInfo info, - final Logger logger, - final ComponentFactory factory ) { - super(info, logger, factory); - } - - /** - * Get a reference of the desired Component - * - * @return A component instance. - * - * @throws Exception If there are any problems encountered acquiring a - * component instance. - */ - protected Object doGet() - throws Exception { - return this.factory.newInstance(); - } - - /** - * Return a reference of the desired Component - * - * @param component Component to be be put/released back to the handler. - */ - protected void doPut( final Object component ) { - this.decommission( component ); - } - -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +import org.apache.avalon.framework.logger.Logger; +import org.apache.cocoon.components.ServiceInfo; + +/** + * The DefaultComponentHandler to make sure components are initialized + * and destroyed correctly. + * + * @version CVS $Id$ + */ +public class SingleThreadedComponentHandler +extends AbstractComponentHandler { + + /** + * Create a SingleThreadedComponentHandler which manages a pool of Components + * created by the specified factory object. + * + * @param logger The logger to use + * @param factory The factory object which is responsible for creating the components + * managed by the handler. + */ + public SingleThreadedComponentHandler( final ServiceInfo info, + final Logger logger, + final ComponentFactory factory ) { + super(info, logger, factory); + } + + /** + * Get a reference of the desired Component + * + * @return A component instance. + * + * @throws Exception If there are any problems encountered acquiring a + * component instance. + */ + protected Object doGet() + throws Exception { + return this.factory.newInstance(); + } + + /** + * Return a reference of the desired Component + * + * @param component Component to be be put/released back to the handler. + */ + protected void doPut( final Object component ) { + this.decommission( component ); + } + +} Modified: cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ThreadSafeComponentHandler.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ThreadSafeComponentHandler.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ThreadSafeComponentHandler.java&r1=123715&p2=cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ThreadSafeComponentHandler.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ThreadSafeComponentHandler.java (original) +++ cocoon/trunk/src/core/java/org/apache/cocoon/core/container/ThreadSafeComponentHandler.java Thu Dec 30 06:16:00 2004 @@ -1,85 +1,85 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -import org.apache.avalon.framework.logger.Logger; -import org.apache.cocoon.components.ServiceInfo; - -/** - * The ThreadSafeComponentHandler to make sure components are initialized - * and destroyed correctly. - * - * @version CVS $Id: ThreadSafeComponentHandler.java 55144 2004-10-20 12:26:09Z ugo $ - */ -public class ThreadSafeComponentHandler -extends AbstractComponentHandler { - - private Object instance; - - /** - * Create a ThreadSafeComponentHandler which manages a single instance - * of an object return by the component factory. - * @param logger The logger to use - * @param factory The factory object which is responsible for creating the components - * managed by the handler. - */ - public ThreadSafeComponentHandler( final ServiceInfo info, - final Logger logger, - final ComponentFactory factory ) { - super(info, logger, factory); - } - - public boolean isSingleton() { - return true; - } - - public void initialize() - throws Exception { - if( this.initialized ) { - return; - } - if( this.instance == null ) { - this.instance = this.factory.newInstance(); - } - super.initialize(); - } - - /** - * Get a reference of the desired Component - */ - protected Object doGet() - throws Exception { - return this.instance; - } - - /** - * Return a reference of the desired Component - */ - protected void doPut( final Object component ) { - // nothing to do - } - - /** - * Dispose of the ComponentHandler and any associated Pools and Factories. - */ - public void dispose() { - this.decommission( this.instance ); - this.instance = null; - - super.dispose(); - } -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +import org.apache.avalon.framework.logger.Logger; +import org.apache.cocoon.components.ServiceInfo; + +/** + * The ThreadSafeComponentHandler to make sure components are initialized + * and destroyed correctly. + * + * @version CVS $Id$ + */ +public class ThreadSafeComponentHandler +extends AbstractComponentHandler { + + private Object instance; + + /** + * Create a ThreadSafeComponentHandler which manages a single instance + * of an object return by the component factory. + * @param logger The logger to use + * @param factory The factory object which is responsible for creating the components + * managed by the handler. + */ + public ThreadSafeComponentHandler( final ServiceInfo info, + final Logger logger, + final ComponentFactory factory ) { + super(info, logger, factory); + } + + public boolean isSingleton() { + return true; + } + + public void initialize() + throws Exception { + if( this.initialized ) { + return; + } + if( this.instance == null ) { + this.instance = this.factory.newInstance(); + } + super.initialize(); + } + + /** + * Get a reference of the desired Component + */ + protected Object doGet() + throws Exception { + return this.instance; + } + + /** + * Return a reference of the desired Component + */ + protected void doPut( final Object component ) { + // nothing to do + } + + /** + * Dispose of the ComponentHandler and any associated Pools and Factories. + */ + public void dispose() { + this.decommission( this.instance ); + this.instance = null; + + super.dispose(); + } +} Modified: cocoon/trunk/src/core/test/org/apache/cocoon/core/container/ContainerTestCase.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/test/org/apache/cocoon/core/container/ContainerTestCase.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/test/org/apache/cocoon/core/container/ContainerTestCase.java&r1=123715&p2=cocoon/trunk/src/core/test/org/apache/cocoon/core/container/ContainerTestCase.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/test/org/apache/cocoon/core/container/ContainerTestCase.java (original) +++ cocoon/trunk/src/core/test/org/apache/cocoon/core/container/ContainerTestCase.java Thu Dec 30 06:16:00 2004 @@ -1,361 +1,361 @@ -/* - * Copyright 2002-2004 The 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.cocoon.core.container; - -import java.io.InputStream; -import java.net.URL; - -import junit.framework.TestCase; - -import org.apache.avalon.excalibur.logger.LoggerManager; -import org.apache.avalon.framework.configuration.Configurable; -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.container.ContainerUtil; -import org.apache.avalon.framework.context.Context; -import org.apache.avalon.framework.context.DefaultContext; -import org.apache.avalon.framework.logger.ConsoleLogger; -import org.apache.avalon.framework.logger.Logger; -import org.apache.avalon.framework.parameters.Parameterizable; -import org.apache.avalon.framework.parameters.Parameters; -import org.apache.avalon.framework.service.ServiceException; -import org.apache.avalon.framework.service.ServiceManager; - -/** - * JUnit TestCase for Cocoon Components. - * <p> - * This class extends the JUnit TestCase class to setup an environment which - * makes it possible to easily test Cocoon Components. The following methods - * and instance variables are exposed for convenience testing: - * </p> - * <dl> - * <dt>getManager()</dt> - * <dd> - * This instance variable contains an initialized service manager which - * can be used to lookup components configured in the test configuration - * file. (see below) - * </dd> - * <dt>getLogger()</dt> - * <dd> - * This method returns a logger for this test case. By default this - * logger logs with log level DEBUG. - * </dd> - * </dl> - * <p> - * The following test case configuration can be used as a basis for new tests. - * Detailed explanations of the configuration elements can be found after - * the example. - * </p> - * <pre> - * <testcase> - * <context> - * <entry name="foo" value="bar"/> - * <entry name="baz" class="my.context.Class"/> - * </context> - * - * <roles> - * <role name="org.apache.avalon.excalibur.datasource.DataSourceComponentSelector" - * shorthand="datasources" - * default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"> - * <hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/> - * </role> - * </roles> - * - * <components> - * <datasources> - * <jdbc name="personell"> - * <pool-controller min="5" max="10"/> - * <jdbc name="personnel"/> - * <dburl>jdbc:odbc:test</dburl> - * <user>test</user> - * <password>test</password> - * <driver>sun.jdbc.odbc.JdbcOdbcDriver</driver> - * </jdbc> - * </datasources> - * </components> - * </testcase> - * </pre> - * <p> - * Element Explanation: - * <dl> - * <dt>testcase</dt> - * <dd>Defines a test case configuration. Must contain one each of the - * following elements: - * <code>context</code>, <code>roles</code>, and <code>components</code> - * </dd>. - * - * <dt>context</dt> - * <dd>Allows context properties to be set in the context passed to any - * Contextualizable components.</dd> - * - * <dt>roles</dt> - * <dd>Roles configuration for the components configured in the - * <code>components</code> element. - * </dd> - * - * <dt>components</dt> - * <dd>Used to configure any Components used by the test cases. - * </dd> - * - * </dl> - * - * @version $Id: $ - */ -public class ContainerTestCase extends TestCase { - - /** The default logger */ - private Logger logger = new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG); - - /** The service manager to use */ - private ServiceManager manager; - - /** The context */ - private Context context; - - /** Return the logger */ - protected Logger getLogger() { - return logger; - } - - /** Return the service manager */ - protected ServiceManager getManager() { - return this.manager; - } - - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ - protected void setUp() throws Exception { - super.setUp(); - this.prepare(); - } - - /** - * Initializes the ComponentLocator - * - * The configuration file is determined by the class name plus .xtest appended, - * all '.' replaced by '/' and loaded as a resource via classpath - */ - protected void prepare() - throws Exception { - final String resourceName = getClass().getName().replace( '.', '/' ) + ".xtest"; - URL resource = getClass().getClassLoader().getResource( resourceName ); - - if( resource != null ) { - getLogger().debug( "Loading resource " + resourceName ); - this.prepare( resource.openStream() ); - } else { - getLogger().debug( "Resource not found " + resourceName ); - this.prepare( null ); - } - } - - /** - * Initializes the ComponentLocator - * - * @param testconf The configuration file is passed as a <code>InputStream</code> - * - * A common way to supply a InputStream is to overwrite the initialize() method - * in the sub class, do there whatever is needed to get the right InputStream object - * supplying a conformant xtest configuartion and pass it to this initialize method. - * the mentioned initialize method is also the place to set a different logging priority - * to the member variable m_logPriority. - */ - protected final void prepare( final InputStream testconf ) - throws Exception { - if ( getLogger().isDebugEnabled() ) { - getLogger().debug( "Initializing " + this.getName() ); - } - - final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); - final Configuration conf; - if ( testconf != null ) { - conf = builder.build( testconf ); - } else { - conf = new DefaultConfiguration("", "-"); - } - - this.context = this.setupContext( conf.getChild( "context" ) ); - - this.setupManagers( conf.getChild( "components" ), - conf.getChild( "roles" )); - } - - /* (non-Javadoc) - * @see junit.framework.TestCase#tearDown() - */ - protected void tearDown() throws Exception { - this.done(); - super.tearDown(); - } - - /** - * Disposes the <code>ComponentLocator</code> - */ - final private void done() { - if( manager != null ) { - ContainerUtil.dispose(manager); - manager = null; - } - } - - /** - * set up a context according to the xtest configuration specifications context - * element. - * - * A method addContext(DefaultContext context) is called here to enable subclasses - * to put additional objects into the context programmatically. - */ - final private Context setupContext( final Configuration conf ) - throws Exception { - final DefaultContext context = new DefaultContext(); - final Configuration[] confs = conf.getChildren( "entry" ); - for( int i = 0; i < confs.length; i++ ) { - final String key = confs[ i ].getAttribute( "name" ); - final String value = confs[ i ].getAttribute( "value", null ); - if( value == null ) { - String clazz = confs[ i ].getAttribute( "class" ); - Object obj = getClass().getClassLoader().loadClass( clazz ).newInstance(); - context.put( key, obj ); - if( getLogger().isInfoEnabled() ) { - getLogger().info( "ContainerTestCase: added an instance of class " + clazz + " to context entry " + key ); - } - } else { - context.put( key, value ); - if( getLogger().isInfoEnabled() ) { - getLogger().info( "ContainerTestCase: added value \"" + value + "\" to context entry " + key ); - } - } - } - this.addContext( context ); - return context ; - } - - /** - * This method may be overwritten by subclasses to put additional objects - * into the context programmatically. - */ - protected void addContext( DefaultContext context ) { - // nothing to add here - } - - /** - * This method may be overwritten by subclasses to add aditional - * components. - */ - protected void addComponents( CocoonServiceManager manager) - throws ServiceException { - // subclasses can add components here - } - - final private void setupManagers( final Configuration confCM, - final Configuration confRM) - throws Exception { - // Setup the RoleManager - RoleManager roleManager = new RoleManager(); - roleManager.enableLogging( this.getLogger() ); - roleManager.configure( confRM ); - - // Set up the ComponentLocator - CocoonServiceManager ecManager = new CocoonServiceManager(null); - ecManager.enableLogging( this.getLogger() ); - ecManager.contextualize( this.context ); - ecManager.setRoleManager( roleManager ); - ecManager.setLoggerManager( new DefaultLoggerManager(this.logger)); - ecManager.configure( confCM ); - this.addComponents( ecManager ); - ecManager.initialize(); - this.manager = ecManager; - } - - protected final Object lookup( final String key ) - throws ServiceException { - return manager.lookup( key ); - } - - protected final void release( final Object object ) { - manager.release( object ); - } - - private Object getComponent(String classname, - Configuration conf, - Parameters p) - throws Exception { - final Object instance = Class.forName(classname).newInstance(); - ContainerUtil.enableLogging(instance, getLogger()); - ContainerUtil.contextualize(instance, this.context); - ContainerUtil.service(instance, getManager()); - if ( instance instanceof Configurable ) { - // default configuration to invoke method! - if ( conf == null ) { - conf = new DefaultConfiguration("", "-"); - } - ContainerUtil.configure(instance, conf); - } - if ( instance instanceof Parameterizable ) { - // default configuration to invoke method! - if ( p == null ) { - p = new Parameters(); - } - ContainerUtil.parameterize(instance, p); - } - ContainerUtil.initialize(instance); - return instance; - } - - protected Object getComponent(String classname, - Configuration conf) - throws Exception { - return this.getComponent(classname, conf, null); - } - - protected Object getComponent(String classname, - Parameters p) - throws Exception { - return this.getComponent(classname, null, p); - } - - protected Object getComponent(String classname) - throws Exception { - return this.getComponent(classname, null, null); - } - - /** - * We use this simple logger manager that sends all output to the console (logger) - */ - protected static class DefaultLoggerManager implements LoggerManager { - - private Logger logger; - - public DefaultLoggerManager(Logger logger) { - this.logger = logger; - } - /* (non-Javadoc) - * @see org.apache.avalon.excalibur.logger.LoggerManager#getDefaultLogger() - */ - public Logger getDefaultLogger() { - return this.logger; - } - /* (non-Javadoc) - * @see org.apache.avalon.excalibur.logger.LoggerManager#getLoggerForCategory(java.lang.String) - */ - public Logger getLoggerForCategory(String arg0) { - return this.logger; - } - } -} +/* + * Copyright 2002-2004 The 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.cocoon.core.container; + +import java.io.InputStream; +import java.net.URL; + +import junit.framework.TestCase; + +import org.apache.avalon.excalibur.logger.LoggerManager; +import org.apache.avalon.framework.configuration.Configurable; +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.container.ContainerUtil; +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.context.DefaultContext; +import org.apache.avalon.framework.logger.ConsoleLogger; +import org.apache.avalon.framework.logger.Logger; +import org.apache.avalon.framework.parameters.Parameterizable; +import org.apache.avalon.framework.parameters.Parameters; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; + +/** + * JUnit TestCase for Cocoon Components. + * <p> + * This class extends the JUnit TestCase class to setup an environment which + * makes it possible to easily test Cocoon Components. The following methods + * and instance variables are exposed for convenience testing: + * </p> + * <dl> + * <dt>getManager()</dt> + * <dd> + * This instance variable contains an initialized service manager which + * can be used to lookup components configured in the test configuration + * file. (see below) + * </dd> + * <dt>getLogger()</dt> + * <dd> + * This method returns a logger for this test case. By default this + * logger logs with log level DEBUG. + * </dd> + * </dl> + * <p> + * The following test case configuration can be used as a basis for new tests. + * Detailed explanations of the configuration elements can be found after + * the example. + * </p> + * <pre> + * <testcase> + * <context> + * <entry name="foo" value="bar"/> + * <entry name="baz" class="my.context.Class"/> + * </context> + * + * <roles> + * <role name="org.apache.avalon.excalibur.datasource.DataSourceComponentSelector" + * shorthand="datasources" + * default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"> + * <hint shorthand="jdbc" class="org.apache.avalon.excalibur.datasource.JdbcDataSource"/> + * </role> + * </roles> + * + * <components> + * <datasources> + * <jdbc name="personell"> + * <pool-controller min="5" max="10"/> + * <jdbc name="personnel"/> + * <dburl>jdbc:odbc:test</dburl> + * <user>test</user> + * <password>test</password> + * <driver>sun.jdbc.odbc.JdbcOdbcDriver</driver> + * </jdbc> + * </datasources> + * </components> + * </testcase> + * </pre> + * <p> + * Element Explanation: + * <dl> + * <dt>testcase</dt> + * <dd>Defines a test case configuration. Must contain one each of the + * following elements: + * <code>context</code>, <code>roles</code>, and <code>components</code> + * </dd>. + * + * <dt>context</dt> + * <dd>Allows context properties to be set in the context passed to any + * Contextualizable components.</dd> + * + * <dt>roles</dt> + * <dd>Roles configuration for the components configured in the + * <code>components</code> element. + * </dd> + * + * <dt>components</dt> + * <dd>Used to configure any Components used by the test cases. + * </dd> + * + * </dl> + * + * @version $Id$ + */ +public class ContainerTestCase extends TestCase { + + /** The default logger */ + private Logger logger = new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG); + + /** The service manager to use */ + private ServiceManager manager; + + /** The context */ + private Context context; + + /** Return the logger */ + protected Logger getLogger() { + return logger; + } + + /** Return the service manager */ + protected ServiceManager getManager() { + return this.manager; + } + + /* (non-Javadoc) + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + super.setUp(); + this.prepare(); + } + + /** + * Initializes the ComponentLocator + * + * The configuration file is determined by the class name plus .xtest appended, + * all '.' replaced by '/' and loaded as a resource via classpath + */ + protected void prepare() + throws Exception { + final String resourceName = getClass().getName().replace( '.', '/' ) + ".xtest"; + URL resource = getClass().getClassLoader().getResource( resourceName ); + + if( resource != null ) { + getLogger().debug( "Loading resource " + resourceName ); + this.prepare( resource.openStream() ); + } else { + getLogger().debug( "Resource not found " + resourceName ); + this.prepare( null ); + } + } + + /** + * Initializes the ComponentLocator + * + * @param testconf The configuration file is passed as a <code>InputStream</code> + * + * A common way to supply a InputStream is to overwrite the initialize() method + * in the sub class, do there whatever is needed to get the right InputStream object + * supplying a conformant xtest configuartion and pass it to this initialize method. + * the mentioned initialize method is also the place to set a different logging priority + * to the member variable m_logPriority. + */ + protected final void prepare( final InputStream testconf ) + throws Exception { + if ( getLogger().isDebugEnabled() ) { + getLogger().debug( "Initializing " + this.getName() ); + } + + final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); + final Configuration conf; + if ( testconf != null ) { + conf = builder.build( testconf ); + } else { + conf = new DefaultConfiguration("", "-"); + } + + this.context = this.setupContext( conf.getChild( "context" ) ); + + this.setupManagers( conf.getChild( "components" ), + conf.getChild( "roles" )); + } + + /* (non-Javadoc) + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + this.done(); + super.tearDown(); + } + + /** + * Disposes the <code>ComponentLocator</code> + */ + final private void done() { + if( manager != null ) { + ContainerUtil.dispose(manager); + manager = null; + } + } + + /** + * set up a context according to the xtest configuration specifications context + * element. + * + * A method addContext(DefaultContext context) is called here to enable subclasses + * to put additional objects into the context programmatically. + */ + final private Context setupContext( final Configuration conf ) + throws Exception { + final DefaultContext context = new DefaultContext(); + final Configuration[] confs = conf.getChildren( "entry" ); + for( int i = 0; i < confs.length; i++ ) { + final String key = confs[ i ].getAttribute( "name" ); + final String value = confs[ i ].getAttribute( "value", null ); + if( value == null ) { + String clazz = confs[ i ].getAttribute( "class" ); + Object obj = getClass().getClassLoader().loadClass( clazz ).newInstance(); + context.put( key, obj ); + if( getLogger().isInfoEnabled() ) { + getLogger().info( "ContainerTestCase: added an instance of class " + clazz + " to context entry " + key ); + } + } else { + context.put( key, value ); + if( getLogger().isInfoEnabled() ) { + getLogger().info( "ContainerTestCase: added value \"" + value + "\" to context entry " + key ); + } + } + } + this.addContext( context ); + return context ; + } + + /** + * This method may be overwritten by subclasses to put additional objects + * into the context programmatically. + */ + protected void addContext( DefaultContext context ) { + // nothing to add here + } + + /** + * This method may be overwritten by subclasses to add aditional + * components. + */ + protected void addComponents( CocoonServiceManager manager) + throws ServiceException { + // subclasses can add components here + } + + final private void setupManagers( final Configuration confCM, + final Configuration confRM) + throws Exception { + // Setup the RoleManager + RoleManager roleManager = new RoleManager(); + roleManager.enableLogging( this.getLogger() ); + roleManager.configure( confRM ); + + // Set up the ComponentLocator + CocoonServiceManager ecManager = new CocoonServiceManager(null); + ecManager.enableLogging( this.getLogger() ); + ecManager.contextualize( this.context ); + ecManager.setRoleManager( roleManager ); + ecManager.setLoggerManager( new DefaultLoggerManager(this.logger)); + ecManager.configure( confCM ); + this.addComponents( ecManager ); + ecManager.initialize(); + this.manager = ecManager; + } + + protected final Object lookup( final String key ) + throws ServiceException { + return manager.lookup( key ); + } + + protected final void release( final Object object ) { + manager.release( object ); + } + + private Object getComponent(String classname, + Configuration conf, + Parameters p) + throws Exception { + final Object instance = Class.forName(classname).newInstance(); + ContainerUtil.enableLogging(instance, getLogger()); + ContainerUtil.contextualize(instance, this.context); + ContainerUtil.service(instance, getManager()); + if ( instance instanceof Configurable ) { + // default configuration to invoke method! + if ( conf == null ) { + conf = new DefaultConfiguration("", "-"); + } + ContainerUtil.configure(instance, conf); + } + if ( instance instanceof Parameterizable ) { + // default configuration to invoke method! + if ( p == null ) { + p = new Parameters(); + } + ContainerUtil.parameterize(instance, p); + } + ContainerUtil.initialize(instance); + return instance; + } + + protected Object getComponent(String classname, + Configuration conf) + throws Exception { + return this.getComponent(classname, conf, null); + } + + protected Object getComponent(String classname, + Parameters p) + throws Exception { + return this.getComponent(classname, null, p); + } + + protected Object getComponent(String classname) + throws Exception { + return this.getComponent(classname, null, null); + } + + /** + * We use this simple logger manager that sends all output to the console (logger) + */ + protected static class DefaultLoggerManager implements LoggerManager { + + private Logger logger; + + public DefaultLoggerManager(Logger logger) { + this.logger = logger; + } + /* (non-Javadoc) + * @see org.apache.avalon.excalibur.logger.LoggerManager#getDefaultLogger() + */ + public Logger getDefaultLogger() { + return this.logger; + } + /* (non-Javadoc) + * @see org.apache.avalon.excalibur.logger.LoggerManager#getLoggerForCategory(java.lang.String) + */ + public Logger getLoggerForCategory(String arg0) { + return this.logger; + } + } +} Modified: cocoon/trunk/src/core/test/org/apache/cocoon/core/container/RoleManagerTestCase.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/core/test/org/apache/cocoon/core/container/RoleManagerTestCase.java?view=diff&rev=123716&p1=cocoon/trunk/src/core/test/org/apache/cocoon/core/container/RoleManagerTestCase.java&r1=123715&p2=cocoon/trunk/src/core/test/org/apache/cocoon/core/container/RoleManagerTestCase.java&r2=123716 ============================================================================== --- cocoon/trunk/src/core/test/org/apache/cocoon/core/container/RoleManagerTestCase.java (original) +++ cocoon/trunk/src/core/test/org/apache/cocoon/core/container/RoleManagerTestCase.java Thu Dec 30 06:16:00 2004 @@ -26,7 +26,7 @@ /** * Test cases for [EMAIL PROTECTED] RoleManager}. * - * @version CVS $Id: RoleManagerTestCase.java 55163 2004-10-20 16:41:11Z ugo $ + * @version CVS $Id$ */ public class RoleManagerTestCase extends MockObjectTestCase {