001    /*******************************************************************************
002     * Copyright (C) PicoContainer Organization. All rights reserved.
003     * --------------------------------------------------------------------------
004     * The software in this package is published under the terms of the BSD style
005     * license a copy of which has been included with this distribution in the
006     * LICENSE.txt file.
007     ******************************************************************************/
008    package org.picocontainer.web.script;
009    
010    import java.io.InputStream;
011    import java.io.InputStreamReader;
012    import java.io.Reader;
013    
014    import org.picocontainer.ComponentAdapter;
015    import org.picocontainer.MutablePicoContainer;
016    import org.picocontainer.Parameter;
017    import org.picocontainer.PicoCompositionException;
018    import org.picocontainer.PicoContainer;
019    import org.picocontainer.classname.ClassLoadingPicoContainer;
020    import org.picocontainer.parameters.ConstantParameter;
021    import org.picocontainer.classname.ClassName;
022    import org.picocontainer.script.ContainerBuilder;
023    import org.picocontainer.classname.DefaultClassLoadingPicoContainer;
024    import org.picocontainer.web.WebappComposer;
025    
026    import javax.servlet.ServletContext;
027    
028    /**
029     * Script-based webapp composer. Allows to build containers for each webapp
030     * scope from picocontainer scripts, using configurable builder and script
031     * resources, which default to XML scripts.
032     * 
033     * @author Mauro Talevi
034     */
035    public class ScriptedWebappComposer implements WebappComposer {
036    
037        public final static String DEFAULT_CONTAINER_BUILDER = "org.picocontainer.script.xml.XMLContainerBuilder";
038        public final static String DEFAULT_APPLICATION_SCRIPT = "pico-application.xml";
039        public final static String DEFAULT_SESSION_SCRIPT = "pico-session.xml";
040        public final static String DEFAULT_REQUEST_SCRIPT = "pico-request.xml";
041    
042        private String containerBuilderClassName;
043        private String applicationScript;
044        private String sessionScript;
045        private String requestScript;
046    
047        public ScriptedWebappComposer() {
048            this(DEFAULT_CONTAINER_BUILDER, DEFAULT_APPLICATION_SCRIPT, DEFAULT_SESSION_SCRIPT, DEFAULT_REQUEST_SCRIPT);
049        }
050    
051        public ScriptedWebappComposer(String containerBuilderClassName, String applicationScript, String sessionScript,
052                String requestScript) {
053            this.containerBuilderClassName = containerBuilderClassName;
054            this.applicationScript = applicationScript;
055            this.sessionScript = sessionScript;
056            this.requestScript = requestScript;
057        }
058    
059        public void composeApplication(MutablePicoContainer container, ServletContext context) {
060            populateContainer(applicationScript, container);
061        }
062    
063        public void composeSession(MutablePicoContainer container) {
064            populateContainer(sessionScript, container);
065        }
066    
067        public void composeRequest(MutablePicoContainer container) {
068            populateContainer(requestScript, container);
069        }
070    
071        private void populateContainer(String resourcePath, MutablePicoContainer container) {
072            PicoContainer buildContainer = buildContainer(resourcePath, container.getParent());
073            for (ComponentAdapter<?> adapter : buildContainer.getComponentAdapters()) {
074                container.addAdapter(adapter);
075            }
076        }
077    
078        private PicoContainer buildContainer(String resourcePath, PicoContainer parent) {
079            ContainerBuilder builder = createContainerBuilder(getResource(resourcePath));
080            return builder.buildContainer(parent, null, false);
081        }
082    
083        private ContainerBuilder createContainerBuilder(Reader reader) {
084            ClassLoadingPicoContainer scripted = new DefaultClassLoadingPicoContainer(getClassLoader());
085            Parameter[] parameters = new Parameter[] { new ConstantParameter(reader),
086                    new ConstantParameter(getClassLoader()) };
087            scripted.addComponent(containerBuilderClassName, new ClassName(containerBuilderClassName), parameters);
088            return scripted.getComponent(ContainerBuilder.class);
089        }
090    
091        private Reader getResource(String resource) {
092            ClassLoader classLoader = getClassLoader();
093            InputStream stream = classLoader.getResourceAsStream(resource);
094            if (stream == null) {
095                throw new PicoCompositionException("Resource " + resource + " not found in classloader " + classLoader);
096            }
097            return new InputStreamReader(stream);
098        }
099    
100        private ClassLoader getClassLoader() {
101            return Thread.currentThread().getContextClassLoader();
102        }
103    }