blob: a7a07e2af8ffe9833cc56acfd922b5c9cab5f4e6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.treeprocessor;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.avalon.framework.activity.Initializable;
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.container.ContainerUtil;
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.parameters.Parameterizable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.avalon.framework.thread.ThreadSafe;
/**
* This is the selector used to select/create node builders.
*
* @version $Id$
* @since 2.2
*/
public class NodeBuilderSelector
extends AbstractLogEnabled
implements Serviceable,
Configurable,
Initializable,
Contextualizable {
/** The application context for components
*/
protected ServiceManager serviceManager;
/** The application context for components */
protected Context context;
/** Used to map roles to component infos. */
protected final Map componentInfos = Collections.synchronizedMap(new HashMap());
/** All singletons. */
protected final Map singletons = Collections.synchronizedMap(new HashMap());
/**
* @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
*/
public void contextualize( final Context avalonContext ) {
this.context = avalonContext;
}
/**
* @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
*/
public void service( final ServiceManager componentManager )
throws ServiceException {
this.serviceManager = componentManager;
}
public Object getBuilder( String name )
throws Exception {
Object component = this.singletons.get(name);
if ( component == null ) {
final BuilderInfo info = (BuilderInfo)this.componentInfos.get( name );
// Retrieve the instance of the requested component
if( null == info ) {
throw new Exception( "Node builder selector could not find builder for key [" + name + "]" );
}
try {
component = this.createComponent(info);
} catch (Exception e) {
throw new Exception("Unable to create new builder: " + name, e);
}
}
return component;
}
/**
* @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
*/
public void configure( final Configuration config )
throws ConfigurationException {
final Configuration[] instances = config.getChildren();
for (int i = 0; i < instances.length; i++) {
final Configuration instance = instances[i];
final String name = instance.getAttribute("name").trim();
final String className = instance.getAttribute("builder").trim();
try {
if( this.getLogger().isDebugEnabled() ) {
this.getLogger().debug( "Adding builder (" + name + " = " + className + ")" );
}
final Class clazz = this.getClass().getClassLoader().loadClass( className );
final BuilderInfo info = new BuilderInfo();
info.builderClass = clazz;
info.configuration = instance;
this.componentInfos.put( name, info );
} catch( final ClassNotFoundException cnfe ) {
final String message = "Could not get class (" + className + ") for builder "
+ name + " at " + instance.getLocation();
throw new ConfigurationException( message, cnfe );
} catch( final Exception e ) {
final String message = "Unexpected exception when setting up builder " + name + " at " + instance.getLocation();
throw new ConfigurationException( message, e );
}
}
}
/**
* Create a new component.
*/
protected Object createComponent(BuilderInfo info)
throws Exception {
final Object component = info.builderClass.newInstance();
ContainerUtil.enableLogging(component, this.getLogger());
ContainerUtil.contextualize(component, this.context);
ContainerUtil.service(component, this.serviceManager);
ContainerUtil.configure(component, info.configuration);
if ( component instanceof Parameterizable ) {
ContainerUtil.parameterize(component, Parameters.fromConfiguration(info.configuration));
}
ContainerUtil.initialize(component);
return component;
}
/**
* @see org.apache.avalon.framework.activity.Initializable#initialize()
*/
public void initialize()
throws Exception {
final Iterator i = this.componentInfos.entrySet().iterator();
while ( i.hasNext() ) {
final Map.Entry entry = (Map.Entry)i.next();
final BuilderInfo info = (BuilderInfo)entry.getValue();
if ( ThreadSafe.class.isAssignableFrom( info.builderClass ) ) {
this.singletons.put(entry.getKey(), this.createComponent(info));
}
}
}
protected static class BuilderInfo {
public Configuration configuration;
public Class builderClass;
}
}