Coverage Report - org.apache.turbine.services.rundata.TurbineRunDataService
 
Classes in this File Line Coverage Branch Coverage Complexity
TurbineRunDataService
79%
63/79
60%
17/28
6,4
 
 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  58
     private static final String DEFAULT_RUN_DATA =
 65  
         DefaultTurbineRunData.class.getName();
 66  
 
 67  
     /** The default implementation of the Parameter Parser object */
 68  58
     private static final String DEFAULT_PARAMETER_PARSER =
 69  
         DefaultParameterParser.class.getName();
 70  
 
 71  
     /** The default implementation of the Cookie parser object */
 72  58
     private static final String DEFAULT_COOKIE_PARSER =
 73  
         DefaultCookieParser.class.getName();
 74  
 
 75  
     /** The map of configurations. */
 76  58
     private final Map<String, Object> configurations = new HashMap<String, Object>();
 77  
 
 78  
     /** Private reference to the pool service for object recycling */
 79  58
     private PoolService pool = null;
 80  
 
 81  
     /** Private reference to the parser service for parser recycling */
 82  58
     private ParserService parserService = null;
 83  
 
 84  
     /**
 85  
      * Constructs a RunData Service.
 86  
      */
 87  
     public TurbineRunDataService()
 88  
     {
 89  58
         super();
 90  58
     }
 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  94
         String[] def = new String[]
 104  
         {
 105  
             DEFAULT_RUN_DATA,
 106  
             DEFAULT_PARAMETER_PARSER,
 107  
             DEFAULT_COOKIE_PARSER
 108  
         };
 109  94
         configurations.put(DEFAULT_CONFIG, def.clone());
 110  
 
 111  
         // Check other configurations.
 112  94
         Configuration conf = getConfiguration();
 113  94
         if (conf != null)
 114  
         {
 115  
             String key,value;
 116  
             String[] config;
 117  94
             String[] plist = new String[]
 118  
             {
 119  
                 RUN_DATA_KEY,
 120  
                 PARAMETER_PARSER_KEY,
 121  
                 COOKIE_PARSER_KEY
 122  
             };
 123  94
             for (Iterator<String> i = conf.getKeys(); i.hasNext();)
 124  
             {
 125  328
                 key = i.next();
 126  328
                 value = conf.getString(key);
 127  844
                 for (int j = 0; j < plist.length; j++)
 128  
                 {
 129  750
                     if (key.endsWith(plist[j]) &&
 130  
                             (key.length() > (plist[j].length() + 1)))
 131  
                     {
 132  234
                         key = key.substring(0, key.length() - plist[j].length() - 1);
 133  234
                         config = (String[]) configurations.get(key);
 134  234
                         if (config == null)
 135  
                         {
 136  0
                             config = def.clone();
 137  0
                             configurations.put(key, config);
 138  
                         }
 139  234
                         config[j] = value;
 140  234
                         break;
 141  
                     }
 142  
                 }
 143  
             }
 144  
         }
 145  
 
 146  94
                 pool = (PoolService)TurbineServices.getInstance().getService(PoolService.ROLE);
 147  
 
 148  94
         if (pool == null)
 149  
         {
 150  0
             throw new InitializationException("RunData Service requires"
 151  
                 + " configured Pool Service!");
 152  
         }
 153  
 
 154  94
         parserService = (ParserService)TurbineServices.getInstance().getService(ParserService.ROLE);
 155  
 
 156  94
         if (parserService == null)
 157  
         {
 158  0
             throw new InitializationException("RunData Service requires"
 159  
                 + " configured Parser Service!");
 160  
         }
 161  
 
 162  94
         setInit(true);
 163  94
     }
 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  52
         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  52
         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  52
         if ((req == null)
 210  
             || (res == null)
 211  
             || (config == null))
 212  
         {
 213  0
             throw new IllegalArgumentException("HttpServletRequest, "
 214  
                 + "HttpServletResponse or ServletConfig was null.");
 215  
         }
 216  
 
 217  
         // Get the specified configuration.
 218  52
         String[] cfg = (String[]) configurations.get(key);
 219  52
         if (cfg == null)
 220  
         {
 221  0
             throw new TurbineException("RunTime configuration '" + key + "' is undefined");
 222  
         }
 223  
 
 224  
         TurbineRunData data;
 225  
         try
 226  
         {
 227  52
                     Class<?> runDataClazz = Class.forName(cfg[0]);
 228  52
                     Class<?> parameterParserClazz = Class.forName(cfg[1]);
 229  52
                     Class<?> cookieParserClazz = Class.forName(cfg[2]);
 230  
 
 231  52
             data = (TurbineRunData) pool.getInstance(runDataClazz);
 232  52
             ParameterParser pp = (ParameterParser) parserService.getParser(parameterParserClazz);
 233  52
             data.setParameterParser(pp);
 234  52
             CookieParser cp = (CookieParser) parserService.getParser(cookieParserClazz);
 235  52
             data.setCookieParser(cp);
 236  
             // also copy data directly into pipelineData
 237  52
             pipelineDataMap.put(ParameterParser.class, pp);
 238  52
             pipelineDataMap.put(CookieParser.class, cp);
 239  
 
 240  52
             Locale locale = req.getLocale();
 241  
 
 242  52
             if (locale == null)
 243  
             {
 244  
                 // get the default from the Turbine configuration
 245  0
                 locale = data.getLocale();
 246  
             }
 247  
 
 248  
             // set the locale detected and propagate it to the parsers
 249  52
             data.setLocale(locale);
 250  
         }
 251  0
         catch (PoolException pe)
 252  
         {
 253  0
             throw new TurbineException("RunData configuration '" + key + "' is illegal caused a pool exception", pe);
 254  
         }
 255  0
         catch (ClassNotFoundException x)
 256  
         {
 257  0
             throw new TurbineException("RunData configuration '" + key + "' is illegal", x);
 258  
         }
 259  0
         catch (ClassCastException x)
 260  
         {
 261  0
             throw new TurbineException("RunData configuration '" + key + "' is illegal", x);
 262  
         }
 263  0
         catch (InstantiationException e)
 264  
         {
 265  0
             throw new TurbineException("RunData configuration '" + key + "' is illegal", e);
 266  52
         }
 267  
 
 268  
         // Set the request and response.
 269  52
         data.setRequest(req);
 270  52
         data.setResponse(res);
 271  
         // also copy data directly into pipelineData
 272  52
         pipelineDataMap.put(HttpServletRequest.class, req);
 273  52
         pipelineDataMap.put(HttpServletResponse.class, res);
 274  
 
 275  
         // Set the servlet configuration.
 276  52
         data.setServletConfig(config);
 277  
         // also copy data directly into pipelineData
 278  52
         pipelineDataMap.put(ServletConfig.class, config);
 279  
 
 280  
         // Set the ServerData.
 281  52
         ServerData sd = new ServerData(req);
 282  52
         data.setServerData(sd);
 283  
         // also copy data directly into pipelineData
 284  52
         pipelineDataMap.put(ServerData.class, sd);
 285  
 
 286  
         // finally put the pipelineDataMap into the pipelineData object
 287  52
         data.put(Turbine.class, pipelineDataMap);
 288  52
         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  2
         if (data instanceof TurbineRunData)
 300  
         {
 301  2
             parserService.putParser(((TurbineRunData) data).getParameterParser());
 302  2
             parserService.putParser(((TurbineRunData) data).getCookieParser());
 303  
 
 304  2
             return pool.putInstance(data);
 305  
         }
 306  
         else
 307  
         {
 308  0
             return false;
 309  
         }
 310  
     }
 311  
 }