001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.chain.web;
018    
019    
020    import java.io.IOException;
021    import javax.servlet.ServletConfig;
022    import javax.servlet.ServletContext;
023    import javax.servlet.ServletException;
024    import javax.servlet.http.HttpServlet;
025    import javax.servlet.http.HttpServletRequest;
026    import javax.servlet.http.HttpServletResponse;
027    import org.apache.commons.chain.Catalog;
028    import org.apache.commons.chain.CatalogFactory;
029    import org.apache.commons.chain.config.ConfigParser;
030    import org.apache.commons.chain.impl.CatalogBase;
031    import org.apache.commons.digester.RuleSet;
032    import org.apache.commons.logging.Log;
033    import org.apache.commons.logging.LogFactory;
034    
035    
036    /**
037     * <p><code>Servlet</code> that automatically scans chain configuration files
038     * in the current web application at startup time, and exposes the result in a
039     * {@link Catalog} under a specified servlet context attribute.  The following
040     * <em>servlet</em> init parameters are utilized:</p>
041     * <ul>
042     * <li><strong>org.apache.commons.chain.CONFIG_CLASS_RESOURCE</strong> -
043     *     comma-delimited list of chain configuration resources to be loaded
044     *     via <code>ClassLoader.getResource()</code> calls.  If not specified,
045     *     no class loader resources will be loaded.</li>
046     * <li><strong>org.apache.commons.chain.CONFIG_WEB_RESOURCE</strong> -
047     *     comma-delimited list of chain configuration webapp resources
048     *     to be loaded.  If not specified, no web application resources
049     *     will be loaded.</li>
050     * <li><strong>org.apache.commons.chain.CONFIG_ATTR</strong> -
051     *     Name of the servlet context attribute under which the
052     *     resulting {@link Catalog} will be created or updated.
053     *     If not specified, it is expected that parsed resources will
054     *     contain <code>&lt;catalog&gt;</code> elements (which will
055     *     cause registration of the created {@link Catalog}s into
056     *     the {@link CatalogFactory} for this application, and no
057     *     servet context attribute will be created.
058     *     <strong>NOTE</strong> - This parameter is deprecated.</p>
059     * <li><strong>org.apache.commons.chain.RULE_SET</strong> -
060     *     Fully qualified class name of a Digester <code>RuleSet</code>
061     *     implementation to use for parsing configuration resources (this
062     *     class must have a public zero-args constructor).  If not defined,
063     *     the standard <code>RuleSet</code> implementation will be used.</li>
064     * </ul>
065     *
066     * <p>When a web application that has configured this servlet is
067     * started, it will acquire the {@link Catalog} under the specified servlet
068     * context attribute key, creating a new one if there is none already there.
069     * This {@link Catalog} will then be populated by scanning configuration
070     * resources from the following sources (loaded in this order):</p>
071     * <ul>
072     * <li>Resources loaded from specified resource paths from the
073     *     webapp's class loader (via <code>ClassLoader.getResource()</code>).</li>
074     * <li>Resources loaded from specified resource paths in the web application
075     *     archive (via <code>ServetContext.getResource()</code>).</li>
076     * </ul>
077     *
078     * <p>If no attribute key is specified, on the other hand, parsed configuration
079     * resources are expected to contain <code>&lt;catalog&gt;</code> elements,
080     * and the catalogs will be registered with the {@link CatalogFactory}
081     * for this web application.</p>
082     *
083     * <p>This class runs on Servlet 2.2 or later.  If you are running on a
084     * Servlet 2.3 or later system, you should also consider using
085     * {@link ChainListener} to initialize your {@link Catalog}.  Note that
086     * {@link ChainListener} uses parameters of the same names, but they are
087     * <em>context</em> init parameters instead of <em>servlet</em> init
088     * parameters. Because of this, you can use both facilities in the
089     * same application, if desired.</p>
090     *
091     * @author Matthew J. Sgarlata
092     * @author Craig R. McClanahan
093     * @author Ted Husted
094     */
095    
096    public class ChainServlet extends HttpServlet {
097    
098    
099        // ------------------------------------------------------ Manifest Constants
100    
101    
102        /**
103         * <p>The name of the context init parameter containing the name of the
104         * servlet context attribute under which our resulting {@link Catalog}
105         * will be stored.</p>
106         */
107        public static final String CONFIG_ATTR =
108            "org.apache.commons.chain.CONFIG_ATTR";
109    
110    
111        /**
112         * <p>The name of the context init parameter containing a comma-delimited
113         * list of class loader resources to be scanned.</p>
114         */
115        public static final String CONFIG_CLASS_RESOURCE =
116            "org.apache.commons.chain.CONFIG_CLASS_RESOURCE";
117    
118    
119        /**
120         * <p>The name of the context init parameter containing a comma-delimited
121         * list of web applicaton resources to be scanned.</p>
122         */
123        public static final String CONFIG_WEB_RESOURCE =
124            "org.apache.commons.chain.CONFIG_WEB_RESOURCE";
125    
126    
127        /**
128         * <p>The name of the context init parameter containing the fully
129         * qualified class name of the <code>RuleSet</code> implementation
130         * for configuring our {@link ConfigParser}.</p>
131         */
132        public static final String RULE_SET =
133            "org.apache.commons.chain.RULE_SET";
134    
135    
136        // --------------------------------------------------------- Servlet Methods
137    
138    
139        /**
140         * <p>Clean up after ourselves as this application shuts down.</p>
141         */
142        public void destroy() {
143    
144            ServletConfig config = getServletConfig();
145            ServletContext context = getServletContext();
146            String attr = config.getInitParameter(CONFIG_ATTR);
147            if (attr != null) {
148                context.removeAttribute(attr);
149            }
150            CatalogFactory.clear();
151    
152        }
153    
154    
155        /**
156         * <p>Create (if necessary) and configure a {@link Catalog} from the
157         * servlet init parameters that have been specified.</p>
158         *
159         * @throws ServletException if the servlet could not be initialized
160         */
161        public void init() throws ServletException {
162    
163            Log log = LogFactory.getLog(ChainServlet.class);
164            ServletConfig config = getServletConfig();
165            ServletContext context = getServletContext();
166            if (log.isInfoEnabled()) {
167                log.info("Initializing chain servlet '"
168                         + config.getServletName() + "'");
169            }
170    
171            // Retrieve servlet init parameters that we need
172            String attr = config.getInitParameter(CONFIG_ATTR);
173            String classResources =
174                context.getInitParameter(CONFIG_CLASS_RESOURCE);
175            String ruleSet = context.getInitParameter(RULE_SET);
176            String webResources = context.getInitParameter(CONFIG_WEB_RESOURCE);
177    
178            // Retrieve or create the Catalog instance we may be updating
179            Catalog catalog = null;
180            if (attr != null) {
181                catalog = (Catalog) context.getAttribute(attr);
182                if (catalog == null) {
183                    catalog = new CatalogBase();
184                }
185            }
186    
187            // Construct the configuration resource parser we will use
188            ConfigParser parser = new ConfigParser();
189            if (ruleSet != null) {
190                try {
191                    ClassLoader loader =
192                        Thread.currentThread().getContextClassLoader();
193                    if (loader == null) {
194                        loader = this.getClass().getClassLoader();
195                    }
196                    Class clazz = loader.loadClass(ruleSet);
197                    parser.setRuleSet((RuleSet) clazz.newInstance());
198                } catch (Exception e) {
199                    throw new ServletException("Exception initalizing RuleSet '"
200                                               + ruleSet + "' instance", e);
201                }
202            }
203    
204            // Parse the resources specified in our init parameters (if any)
205            if (attr == null) {
206                ChainResources.parseClassResources
207                    (classResources, parser);
208                ChainResources.parseWebResources
209                    (context, webResources, parser);
210            } else {
211                ChainResources.parseClassResources
212                    (catalog, classResources, parser);
213                ChainResources.parseWebResources
214                    (catalog, context, webResources, parser);
215            }
216    
217            // Expose the completed catalog (if requested)
218            if (attr != null) {
219                context.setAttribute(attr, catalog);
220            }
221    
222        }
223    
224    
225        /**
226         * <p>Does nothing; this servlet's only purpose is to initialize a Chain
227         * and store it in the servlet context.</p>
228         *
229         * @param request the request issued by the client
230         * @param response the response to be returned to the cliengt
231         *
232         * @throws javax.servlet.ServletException (this exception is never thrown)
233         * @throws java.io.IOException (this exception is never thrown)
234         */
235        public void service(HttpServletRequest request,
236                            HttpServletResponse response)
237            throws ServletException, IOException {
238    
239              // do nothing
240    
241        }
242    
243    
244    }