##### Coverage Report - org.apache.turbine.services.rundata.TurbineRunDataService

Classes in this File | Line Coverage | Branch Coverage | Complexity
TurbineRunDataService |
80% | 68/84
67% | 23/34
| 6.0;6

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