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.chain;
009
010 import java.io.InputStream;
011 import java.io.InputStreamReader;
012 import java.io.Reader;
013 import java.io.StringReader;
014
015 import javax.servlet.ServletContext;
016
017 import org.picocontainer.ComponentAdapter;
018 import org.picocontainer.MutablePicoContainer;
019 import org.picocontainer.Parameter;
020 import org.picocontainer.PicoContainer;
021 import org.picocontainer.parameters.ConstantParameter;
022 import org.picocontainer.classname.ClassName;
023 import org.picocontainer.script.ContainerBuilder;
024 import org.picocontainer.classname.DefaultClassLoadingPicoContainer;
025 import org.picocontainer.classname.ClassLoadingPicoContainer;
026
027 /**
028 * <p>
029 * ServletChainBuilder builds ContainerChains from servlet path and caches
030 * container recorders for later use.
031 * </p>
032 *
033 * @author Kontantin Pribluda
034 * @author Mauro Talevi
035 */
036 public final class ServletChainBuilder {
037
038 private final ServletContext context;
039 private final String containerBuilderClassName;
040 private final String containerScriptName;
041 private final String emptyContainerScript;
042
043 /**
044 * Constructor for the ServletChainBuilder object
045 *
046 * @param context the ServletContext
047 * @param containerBuilderClassName the class name of the ContainerBuilder
048 * @param containerScriptName the name of the container script resource
049 * @param emptyContainerScript the script for empty container if the
050 * container config is not found
051 */
052 public ServletChainBuilder(ServletContext context, String containerBuilderClassName, String containerScriptName,
053 String emptyContainerScript) {
054 this.context = context;
055 this.containerBuilderClassName = containerBuilderClassName;
056 this.containerScriptName = containerScriptName;
057 this.emptyContainerScript = emptyContainerScript;
058 }
059
060 /**
061 * populate container for given path. cache result in container recorders
062 *
063 * @param container the MutablePicoContainer used by the recorder
064 * @param path the String representing the servlet path used as key for the
065 * recorder cache
066 */
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(obtainReader(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
090
091
092 /**
093 * Obtain reader from servlet context path, by appending container script
094 * name to path. If not found, returns reader for empty container instead.
095 *
096 * @param path the String representing the path in servlet context
097 * @return A Reader for corresponding script or for empty container if
098 * script not found
099 */
100 private Reader obtainReader(String path) {
101 InputStream is = context.getResourceAsStream(path + containerScriptName);
102 if (is != null) {
103 return new InputStreamReader(is);
104 } else {
105 return new StringReader(emptyContainerScript);
106 }
107 }
108
109 private ClassLoader getClassLoader() {
110 return Thread.currentThread().getContextClassLoader();
111 }
112
113 }