View Javadoc

    1   package org.apache.turbine.services.rundata;
    2
    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  import java.util.HashMap;
    23  import java.util.Iterator;
    24  import java.util.Locale;
    25  import java.util.Map;
    26
    27  import javax.servlet.ServletConfig;
    28  import javax.servlet.http.HttpServletRequest;
    29  import javax.servlet.http.HttpServletResponse;
    30
    31  import org.apache.commons.configuration.Configuration;
    32  import org.apache.fulcrum.parser.CookieParser;
    33  import org.apache.fulcrum.parser.DefaultCookieParser;
    34  import org.apache.fulcrum.parser.DefaultParameterParser;
    35  import org.apache.fulcrum.parser.ParameterParser;
    36  import org.apache.fulcrum.parser.ParserService;
    37  import org.apache.fulcrum.pool.PoolException;
    38  import org.apache.fulcrum.pool.PoolService;
    39  import org.apache.turbine.Turbine;
    40  import org.apache.turbine.services.InitializationException;
    41  import org.apache.turbine.services.TurbineBaseService;
    42  import org.apache.turbine.services.TurbineServices;
    43  import org.apache.turbine.util.RunData;
    44  import org.apache.turbine.util.ServerData;
    45  import org.apache.turbine.util.TurbineException;
    46
    47  /**
    48   * The RunData Service provides the implementations for RunData and
    49   * related interfaces required by request processing. It supports
    50   * different configurations of implementations, which can be selected
    51   * by specifying a configuration key. It may use pooling, in which case
    52   * the implementations should implement the Recyclable interface.
    53   *
    54   * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
    55   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    56   * @version $Id: TurbineRunDataService.java 1078552 2011-03-06 19:58:46Z tv $
    57   */
    58  public class TurbineRunDataService
    59      extends TurbineBaseService
    60      implements RunDataService
    61  {
    62
    63      /** The default implementation of the RunData object*/
    64      private static final String DEFAULT_RUN_DATA =
    65          DefaultTurbineRunData.class.getName();
    66
    67      /** The default implementation of the Parameter Parser object */
    68      private static final String DEFAULT_PARAMETER_PARSER =
    69          DefaultParameterParser.class.getName();
    70
    71      /** The default implementation of the Cookie parser object */
    72      private static final String DEFAULT_COOKIE_PARSER =
    73          DefaultCookieParser.class.getName();
    74
    75      /** The map of configurations. */
    76      private final Map<String, Object> configurations = new HashMap<String, Object>();
    77
    78      /** Private reference to the pool service for object recycling */
    79      private PoolService pool = null;
    80
    81      /** Private reference to the parser service for parser recycling */
    82      private ParserService parserService = null;
    83
    84      /**
    85       * Constructs a RunData Service.
    86       */
    87      public TurbineRunDataService()
    88      {
    89          super();
    90      }
    91
    92      /**
    93       * Initializes the service by setting the pool capacity.
    94       *
    95       * @throws InitializationException if initialization fails.
    96       */
    97      @SuppressWarnings("unchecked")
    98      @Override
    99      public void init()
    100             throws InitializationException
    101     {
    102         // Create a default configuration.
    103         String[] def = new String[]
    104         {
    105             DEFAULT_RUN_DATA,
    106             DEFAULT_PARAMETER_PARSER,
    107             DEFAULT_COOKIE_PARSER
    108         };
    109         configurations.put(DEFAULT_CONFIG, def.clone());
    110
    111         // Check other configurations.
    112         Configuration conf = getConfiguration();
    113         if (conf != null)
    114         {
    115             String key,value;
    116             String[] config;
    117             String[] plist = new String[]
    118             {
    119                 RUN_DATA_KEY,
    120                 PARAMETER_PARSER_KEY,
    121                 COOKIE_PARSER_KEY
    122             };
    123             for (Iterator<String> i = conf.getKeys(); i.hasNext();)
    124             {
    125                 key = i.next();
    126                 value = conf.getString(key);
    127                 for (int j = 0; j < plist.length; j++)
    128                 {
    129                     if (key.endsWith(plist[j]) &&
    130                             (key.length() > (plist[j].length() + 1)))
    131                     {
    132                         key = key.substring(0, key.length() - plist[j].length() - 1);
    133                         config = (String[]) configurations.get(key);
    134                         if (config == null)
    135                         {
    136                             config = def.clone();
    137                             configurations.put(key, config);
    138                         }
    139                         config[j] = value;
    140                         break;
    141                     }
    142                 }
    143             }
    144         }
    145
    146 		pool = (PoolService)TurbineServices.getInstance().getService(PoolService.ROLE);
    147
    148         if (pool == null)
    149         {
    150             throw new InitializationException("RunData Service requires"
    151                 + " configured Pool Service!");
    152         }
    153
    154         parserService = (ParserService)TurbineServices.getInstance().getService(ParserService.ROLE);
    155
    156         if (parserService == null)
    157         {
    158             throw new InitializationException("RunData Service requires"
    159                 + " configured Parser Service!");
    160         }
    161
    162         setInit(true);
    163     }
    164
    165     /**
    166      * Gets a default RunData object.
    167      *
    168      * @param req a servlet request.
    169      * @param res a servlet response.
    170      * @param config a servlet config.
    171      * @return a new or recycled RunData object.
    172      * @throws TurbineException if the operation fails.
    173      */
    174     public RunData getRunData(HttpServletRequest req,
    175                               HttpServletResponse res,
    176                               ServletConfig config)
    177             throws TurbineException
    178     {
    179         return getRunData(DEFAULT_CONFIG, req, res, config);
    180     }
    181
    182     /**
    183      * Gets a RunData instance from a specific configuration.
    184      *
    185      * @param key a configuration key.
    186      * @param req a servlet request.
    187      * @param res a servlet response.
    188      * @param config a servlet config.
    189      * @return a new or recycled RunData object.
    190      * @throws TurbineException if the operation fails.
    191      * @throws IllegalArgumentException if any of the parameters are null.
    192      * @todo The "key" parameter should be removed in favor of just looking up what class via the roleConfig avalon file.
    193      */
    194     public RunData getRunData(String key,
    195                               HttpServletRequest req,
    196                               HttpServletResponse res,
    197                               ServletConfig config)
    198             throws TurbineException,
    199             IllegalArgumentException
    200     {
    201         // a map to hold information to be added to pipelineData
    202         Map<Class<?>, Object> pipelineDataMap = new HashMap<Class<?>, Object>();
    203         // The RunData object caches all the information that is needed for
    204         // the execution lifetime of a single request. A RunData object
    205         // is created/recycled for each and every request and is passed
    206         // to each and every module. Since each thread has its own RunData
    207         // object, it is not necessary to perform syncronization for
    208         // the data within this object.
    209         if ((req == null)
    210             || (res == null)
    211             || (config == null))
    212         {
    213             throw new IllegalArgumentException("HttpServletRequest, "
    214                 + "HttpServletResponse or ServletConfig was null.");
    215         }
    216
    217         // Get the specified configuration.
    218         String[] cfg = (String[]) configurations.get(key);
    219         if (cfg == null)
    220         {
    221             throw new TurbineException("RunTime configuration '" + key + "' is undefined");
    222         }
    223
    224         TurbineRunData data;
    225         try
    226         {
    227     		Class<?> runDataClazz = Class.forName(cfg[0]);
    228     		Class<?> parameterParserClazz = Class.forName(cfg[1]);
    229     		Class<?> cookieParserClazz = Class.forName(cfg[2]);
    230
    231             data = (TurbineRunData) pool.getInstance(runDataClazz);
    232             ParameterParser pp = (ParameterParser) parserService.getParser(parameterParserClazz);
    233             data.setParameterParser(pp);
    234             CookieParser cp = (CookieParser) parserService.getParser(cookieParserClazz);
    235             data.setCookieParser(cp);
    236             // also copy data directly into pipelineData
    237             pipelineDataMap.put(ParameterParser.class, pp);
    238             pipelineDataMap.put(CookieParser.class, cp);
    239
    240             Locale locale = req.getLocale();
    241
    242             if (locale == null)
    243             {
    244                 // get the default from the Turbine configuration
    245                 locale = data.getLocale();
    246             }
    247
    248             // set the locale detected and propagate it to the parsers
    249             data.setLocale(locale);
    250         }
    251         catch (PoolException pe)
    252         {
    253             throw new TurbineException("RunData configuration '" + key + "' is illegal caused a pool exception", pe);
    254         }
    255         catch (ClassNotFoundException x)
    256         {
    257             throw new TurbineException("RunData configuration '" + key + "' is illegal", x);
    258         }
    259         catch (ClassCastException x)
    260         {
    261             throw new TurbineException("RunData configuration '" + key + "' is illegal", x);
    262         }
    263         catch (InstantiationException e)
    264         {
    265             throw new TurbineException("RunData configuration '" + key + "' is illegal", e);
    266         }
    267
    268         // Set the request and response.
    269         data.setRequest(req);
    270         data.setResponse(res);
    271         // also copy data directly into pipelineData
    272         pipelineDataMap.put(HttpServletRequest.class, req);
    273         pipelineDataMap.put(HttpServletResponse.class, res);
    274
    275         // Set the servlet configuration.
    276         data.setServletConfig(config);
    277         // also copy data directly into pipelineData
    278         pipelineDataMap.put(ServletConfig.class, config);
    279
    280         // Set the ServerData.
    281         ServerData sd = new ServerData(req);
    282         data.setServerData(sd);
    283         // also copy data directly into pipelineData
    284         pipelineDataMap.put(ServerData.class, sd);
    285
    286         // finally put the pipelineDataMap into the pipelineData object
    287         data.put(Turbine.class, pipelineDataMap);
    288         return data;
    289     }
    290
    291     /**
    292      * Puts the used RunData object back to the factory for recycling.
    293      *
    294      * @param data the used RunData object.
    295      * @return true, if pooling is supported and the object was accepted.
    296      */
    297     public boolean putRunData(RunData data)
    298     {
    299         if (data instanceof TurbineRunData)
    300         {
    301             parserService.putParser(((TurbineRunData) data).getParameterParser());
    302             parserService.putParser(((TurbineRunData) data).getCookieParser());
    303
    304             return pool.putInstance(data);
    305         }
    306         else
    307         {
    308             return false;
    309         }
    310     }
    311 }