View Javadoc

    1   /*
    2    * $Id: ReloadableDefinitionsFactory.java 471754 2006-11-06 14:55:09Z husted $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
    10   * with the License.  You may obtain a copy of the License at
    11   *
    12   *  http://www.apache.org/licenses/LICENSE-2.0
    13   *
    14   * Unless required by applicable law or agreed to in writing,
    15   * software distributed under the License is distributed on an
    16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    17   * KIND, either express or implied.  See the License for the
    18   * specific language governing permissions and limitations
    19   * under the License.
    20   */
    21
    22  package org.apache.struts.tiles.definition;
    23
    24  import java.util.Enumeration;
    25  import java.util.HashMap;
    26  import java.util.Map;
    27
    28  import javax.servlet.ServletConfig;
    29  import javax.servlet.ServletContext;
    30  import javax.servlet.ServletRequest;
    31  import javax.servlet.http.HttpServletRequest;
    32
    33  import org.apache.struts.tiles.ComponentDefinition;
    34  import org.apache.struts.tiles.ComponentDefinitionsFactory;
    35  import org.apache.struts.tiles.DefinitionsFactoryException;
    36  import org.apache.struts.tiles.FactoryNotFoundException;
    37  import org.apache.struts.tiles.xmlDefinition.I18nFactorySet;
    38  import org.apache.struts.util.RequestUtils;
    39
    40  /**
    41   * A reloadable factory.
    42   * This factory is the main entrance to any factory implementation. It takes in
    43   * charge real implementation instance, and allows reloading by creating a new
    44   * instance.
    45   *
    46   * @since Struts 1.1
    47   * @version $Rev: 471754 $ $Date: 2006-11-06 08:55:09 -0600 (Mon, 06 Nov 2006) $
    48   */
    49  public class ReloadableDefinitionsFactory implements ComponentDefinitionsFactory {
    50
    51      /**
    52       * The real factory instance.
    53       */
    54      protected ComponentDefinitionsFactory factory = null;
    55
    56      /**
    57       * Initialization parameters.
    58       */
    59      protected Map properties = null;
    60
    61      /**
    62       * Name of init property carrying factory class name.
    63       */
    64      public static final String DEFINITIONS_FACTORY_CLASSNAME =
    65          "definitions-factory-class";
    66
    67      /**
    68       * Constructor.
    69       * Create a factory according to servlet settings.
    70       * @param servletContext Our servlet context.
    71       * @param servletConfig Our servlet config.
    72       * @throws DefinitionsFactoryException If factory creation fail.
    73       */
    74      public ReloadableDefinitionsFactory(
    75          ServletContext servletContext,
    76          ServletConfig servletConfig)
    77          throws DefinitionsFactoryException {
    78
    79          properties = new ServletPropertiesMap(servletConfig);
    80          factory = createFactory(servletContext, properties);
    81      }
    82
    83      /**
    84       * Constructor.
    85       * Create a factory according to servlet settings.
    86       * @param servletContext Our servlet context.
    87       * @param properties Map containing all properties.
    88       * @throws DefinitionsFactoryException If factory creation fail.
    89       */
    90      public ReloadableDefinitionsFactory(
    91          ServletContext servletContext,
    92          Map properties)
    93          throws DefinitionsFactoryException {
    94
    95          this.properties = properties;
    96          factory = createFactory(servletContext, properties);
    97      }
    98
    99      /**
    100     * Create Definition factory from provided classname.
    101     * If a factory class name is provided, a factory of this class is created. Otherwise,
    102     * a default factory is created.
    103     * Factory must have a constructor taking ServletContext and Map as parameter.
    104     * @param classname Class name of the factory to create.
    105     * @param servletContext Servlet Context passed to newly created factory.
    106     * @param properties Map of name/property passed to newly created factory.
    107     * @return newly created factory.
    108     * @throws DefinitionsFactoryException If an error occur while initializing factory
    109     */
    110     public ComponentDefinitionsFactory createFactoryFromClassname(
    111         ServletContext servletContext,
    112         Map properties,
    113         String classname)
    114         throws DefinitionsFactoryException {
    115
    116         if (classname == null) {
    117             return createFactory(servletContext, properties);
    118         }
    119
    120         // Try to create from classname
    121         try {
    122             Class factoryClass = RequestUtils.applicationClass(classname);
    123             ComponentDefinitionsFactory factory =
    124                 (ComponentDefinitionsFactory) factoryClass.newInstance();
    125             factory.initFactory(servletContext, properties);
    126             return factory;
    127
    128         } catch (ClassCastException ex) { // Bad classname
    129             throw new DefinitionsFactoryException(
    130                 "Error - createDefinitionsFactory : Factory class '"
    131                     + classname
    132                     + " must implements 'ComponentDefinitionsFactory'.",
    133                 ex);
    134
    135         } catch (ClassNotFoundException ex) { // Bad classname
    136             throw new DefinitionsFactoryException(
    137                 "Error - createDefinitionsFactory : Bad class name '"
    138                     + classname
    139                     + "'.",
    140                 ex);
    141
    142         } catch (InstantiationException ex) { // Bad constructor or error
    143             throw new DefinitionsFactoryException(ex);
    144
    145         } catch (IllegalAccessException ex) {
    146             throw new DefinitionsFactoryException(ex);
    147         }
    148
    149     }
    150
    151     /**
    152     * Create default Definition factory.
    153     * Factory must have a constructor taking ServletContext and Map as parameter.
    154     * In this implementation, default factory is of class I18nFactorySet
    155     * @param servletContext Servlet Context passed to newly created factory.
    156     * @param properties Map of name/property passed to newly created factory.
    157     * @return newly created factory.
    158     * @throws DefinitionsFactoryException If an error occur while initializing factory
    159     */
    160     public ComponentDefinitionsFactory createDefaultFactory(
    161         ServletContext servletContext,
    162         Map properties)
    163         throws DefinitionsFactoryException {
    164
    165         ComponentDefinitionsFactory factory =
    166             new I18nFactorySet(servletContext, properties);
    167
    168         return factory;
    169     }
    170
    171     /**
    172     * Create Definition factory.
    173     * Convenience method. ServletConfig is wrapped into a Map allowing retrieval
    174     * of init parameters. Factory classname is also retrieved, as well as debug level.
    175     * Finally, approriate createDefinitionsFactory() is called.
    176     * @param servletContext Servlet Context passed to newly created factory.
    177     * @param properties Map containing all properties.
    178     */
    179     public ComponentDefinitionsFactory createFactory(
    180         ServletContext servletContext,
    181         Map properties)
    182         throws DefinitionsFactoryException {
    183
    184         String classname = (String) properties.get(DEFINITIONS_FACTORY_CLASSNAME);
    185
    186         if (classname != null) {
    187             return createFactoryFromClassname(servletContext, properties, classname);
    188         }
    189
    190         return new I18nFactorySet(servletContext, properties);
    191     }
    192
    193     /**
    194      * Get a definition by its name.
    195      * Call appropriate method on underlying factory instance.
    196      * Throw appropriate exception if definition or definition factory is not found.
    197      * @param definitionName Name of requested definition.
    198      * @param request Current servlet request.
    199      * @param servletContext Current servlet context.
    200      * @throws FactoryNotFoundException Can't find definition factory.
    201      * @throws DefinitionsFactoryException General error in factory while getting definition.
    202      */
    203     public ComponentDefinition getDefinition(
    204         String definitionName,
    205         ServletRequest request,
    206         ServletContext servletContext)
    207         throws FactoryNotFoundException, DefinitionsFactoryException {
    208
    209         return factory.getDefinition(
    210             definitionName,
    211             (HttpServletRequest) request,
    212             servletContext);
    213     }
    214
    215     /**
    216      * Reload underlying factory.
    217      * Reload is done by creating a new factory instance, and replacing the old instance
    218      * with the new one.
    219      * @param servletContext Current servlet context.
    220      * @throws DefinitionsFactoryException If factory creation fails.
    221      */
    222     public void reload(ServletContext servletContext)
    223         throws DefinitionsFactoryException {
    224
    225         ComponentDefinitionsFactory newInstance =
    226             createFactory(servletContext, properties);
    227
    228         factory = newInstance;
    229     }
    230
    231     /**
    232      * Get underlying factory instance.
    233      * @return ComponentDefinitionsFactory
    234      */
    235     public ComponentDefinitionsFactory getFactory() {
    236         return factory;
    237     }
    238
    239     /**
    240       * Init factory.
    241       * This method is required by interface ComponentDefinitionsFactory. It is
    242       * not used in this implementation, as it manages itself the underlying creation
    243       * and initialization.
    244       * @param servletContext Servlet Context passed to newly created factory.
    245       * @param properties Map of name/property passed to newly created factory.
    246       * Map can contain more properties than requested.
    247       * @throws DefinitionsFactoryException An error occur during initialization.
    248     */
    249     public void initFactory(ServletContext servletContext, Map properties)
    250         throws DefinitionsFactoryException {
    251         // do nothing
    252     }
    253
    254     /**
    255      * Return String representation.
    256      * @return String representation.
    257      */
    258     public String toString() {
    259         return factory.toString();
    260     }
    261
    262     /**
    263      * Inner class.
    264      * Wrapper for ServletContext init parameters.
    265      * Object of this class is an HashMap containing parameters and values
    266      * defined in the servlet config file (web.xml).
    267      */
    268     class ServletPropertiesMap extends HashMap {
    269         /**
    270          * Constructor.
    271          */
    272         ServletPropertiesMap(ServletConfig config) {
    273             // This implementation is very simple.
    274             // It is possible to avoid creation of a new structure, but this would
    275             // imply writing all of the Map interface.
    276             Enumeration e = config.getInitParameterNames();
    277             while (e.hasMoreElements()) {
    278                 String key = (String) e.nextElement();
    279                 put(key, config.getInitParameter(key));
    280             }
    281         }
    282     } // end inner class
    283 }