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    /**
027     * Script-based webapp composer. Allows to build containers for each webapp
028     * scope from picocontainer scripts, using configurable builder and script
029     * resources, which default to XML scripts.
030     * 
031     * @author Mauro Talevi
032     */
033    public class ScriptedWebappComposer implements WebappComposer {
034    
035        public final static String DEFAULT_CONTAINER_BUILDER = "org.picocontainer.script.xml.XMLContainerBuilder";
036        public final static String DEFAULT_APPLICATION_SCRIPT = "pico-application.xml";
037        public final static String DEFAULT_SESSION_SCRIPT = "pico-session.xml";
038        public final static String DEFAULT_REQUEST_SCRIPT = "pico-request.xml";
039    
040        private String containerBuilderClassName;
041        private String applicationScript;
042        private String sessionScript;
043        private String requestScript;
044    
045        public ScriptedWebappComposer() {
046            this(DEFAULT_CONTAINER_BUILDER, DEFAULT_APPLICATION_SCRIPT, DEFAULT_SESSION_SCRIPT, DEFAULT_REQUEST_SCRIPT);
047        }
048    
049        public ScriptedWebappComposer(String containerBuilderClassName, String applicationScript, String sessionScript,
050                String requestScript) {
051            this.containerBuilderClassName = containerBuilderClassName;
052            this.applicationScript = applicationScript;
053            this.sessionScript = sessionScript;
054            this.requestScript = requestScript;
055        }
056    
057        public void composeApplication(MutablePicoContainer applicationContainer) {
058            populateContainer(applicationScript, applicationContainer);
059        }
060    
061        public void composeSession(MutablePicoContainer sessionContainer) {
062            populateContainer(sessionScript, sessionContainer);
063        }
064    
065        public void composeRequest(MutablePicoContainer requestContainer) {
066            populateContainer(requestScript, requestContainer);
067        }
068    
069        private void populateContainer(String resourcePath, MutablePicoContainer container) {
070            PicoContainer buildContainer = buildContainer(resourcePath, container.getParent());
071            for (ComponentAdapter<?> adapter : buildContainer.getComponentAdapters()) {
072                container.addAdapter(adapter);
073            }
074        }
075    
076        private PicoContainer buildContainer(String resourcePath, PicoContainer parent) {
077            ContainerBuilder builder = createContainerBuilder(getResource(resourcePath));
078            return builder.buildContainer(parent, null, false);
079        }
080    
081        private ContainerBuilder createContainerBuilder(Reader reader) {
082            ClassLoadingPicoContainer scripted = new DefaultClassLoadingPicoContainer(getClassLoader());
083            Parameter[] parameters = new Parameter[] { new ConstantParameter(reader),
084                    new ConstantParameter(getClassLoader()) };
085            scripted.addComponent(containerBuilderClassName, new ClassName(containerBuilderClassName), parameters);
086            return scripted.getComponent(ContainerBuilder.class);
087        }
088    
089        private Reader getResource(String resource) {
090            ClassLoader classLoader = getClassLoader();
091            InputStream stream = classLoader.getResourceAsStream(resource);
092            if (stream == null) {
093                throw new PicoCompositionException("Resource " + resource + " not found in classloader " + classLoader);
094            }
095            return new InputStreamReader(stream);
096        }
097    
098        private ClassLoader getClassLoader() {
099            return Thread.currentThread().getContextClassLoader();
100        }
101    }