001 package org.apache.turbine.services.rundata; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import java.util.HashMap; 023 import java.util.Iterator; 024 import java.util.Locale; 025 import java.util.Map; 026 027 import javax.servlet.ServletConfig; 028 import javax.servlet.http.HttpServletRequest; 029 import javax.servlet.http.HttpServletResponse; 030 031 import org.apache.commons.configuration.Configuration; 032 import org.apache.fulcrum.parser.CookieParser; 033 import org.apache.fulcrum.parser.DefaultCookieParser; 034 import org.apache.fulcrum.parser.DefaultParameterParser; 035 import org.apache.fulcrum.parser.ParameterParser; 036 import org.apache.fulcrum.parser.ParserService; 037 import org.apache.fulcrum.pool.PoolException; 038 import org.apache.fulcrum.pool.PoolService; 039 import org.apache.turbine.Turbine; 040 import org.apache.turbine.services.InitializationException; 041 import org.apache.turbine.services.TurbineBaseService; 042 import org.apache.turbine.services.TurbineServices; 043 import org.apache.turbine.util.RunData; 044 import org.apache.turbine.util.ServerData; 045 import org.apache.turbine.util.TurbineException; 046 047 /** 048 * The RunData Service provides the implementations for RunData and 049 * related interfaces required by request processing. It supports 050 * different configurations of implementations, which can be selected 051 * by specifying a configuration key. It may use pooling, in which case 052 * the implementations should implement the Recyclable interface. 053 * 054 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a> 055 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> 056 * @version $Id: TurbineRunDataService.java 1078552 2011-03-06 19:58:46Z tv $ 057 */ 058 public class TurbineRunDataService 059 extends TurbineBaseService 060 implements RunDataService 061 { 062 063 /** The default implementation of the RunData object*/ 064 private static final String DEFAULT_RUN_DATA = 065 DefaultTurbineRunData.class.getName(); 066 067 /** The default implementation of the Parameter Parser object */ 068 private static final String DEFAULT_PARAMETER_PARSER = 069 DefaultParameterParser.class.getName(); 070 071 /** The default implementation of the Cookie parser object */ 072 private static final String DEFAULT_COOKIE_PARSER = 073 DefaultCookieParser.class.getName(); 074 075 /** The map of configurations. */ 076 private final Map<String, Object> configurations = new HashMap<String, Object>(); 077 078 /** Private reference to the pool service for object recycling */ 079 private PoolService pool = null; 080 081 /** Private reference to the parser service for parser recycling */ 082 private ParserService parserService = null; 083 084 /** 085 * Constructs a RunData Service. 086 */ 087 public TurbineRunDataService() 088 { 089 super(); 090 } 091 092 /** 093 * Initializes the service by setting the pool capacity. 094 * 095 * @throws InitializationException if initialization fails. 096 */ 097 @SuppressWarnings("unchecked") 098 @Override 099 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 }