001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.pageflow;
020:
021: // java imports
022: import java.util.Enumeration;
023: import java.util.HashMap;
024: import java.util.Hashtable;
025: import java.util.Map;
026:
027: import javax.servlet.http.HttpServletRequest;
028: import javax.servlet.ServletException;
029: import javax.servlet.ServletContext;
030:
031: // internal imports
032: import org.apache.beehive.netui.util.logging.Logger;
033: import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
034: import org.apache.beehive.netui.pageflow.scoping.ScopedRequest;
035: import org.apache.beehive.netui.pageflow.internal.InternalUtils;
036: import org.apache.beehive.netui.pageflow.internal.InternalConstants;
037:
038: // external imports
039: import org.apache.struts.Globals;
040: import org.apache.struts.action.ActionForm;
041: import org.apache.struts.action.ActionMapping;
042: import org.apache.struts.action.ActionServletWrapper;
043: import org.apache.struts.config.ModuleConfig;
044: import org.apache.struts.upload.MultipartRequestHandler;
045: import org.apache.struts.upload.MultipartRequestWrapper;
046: import org.apache.struts.util.RequestUtils;
047:
048: /**
049: * <p>
050: * NetUI utility to wrap Struts logic for handling multipart requests.
051: * </p>
052: *
053: * @exclude
054: */
055: /* package */class MultipartRequestUtils {
056: private static final Logger _log = Logger
057: .getInstance(MultipartRequestUtils.class);
058:
059: private static final String PREHANDLED_MULTIPART_REQUEST_ATTR = InternalConstants.ATTR_PREFIX
060: + "handledMultipart";
061:
062: /**
063: * <p>
064: * Handle a multipart request. The return value of this method will be <code>null</code>
065: * if the following conditions are not satisfied:
066: * <ol>
067: * <li>request.getContentType() != null</li>
068: * <li>content type is "multipart/form-data"</li>
069: * <li>request method is "POST"</li>
070: * </ol>
071: * If these are satisfied, a Struts {@link MultipartRequestHandler} is created. This object is used
072: * to provide a mapping over both the regular {@link HttpServletRequest} parameters and the
073: * paramters that Struts creates to represent the file(s) that was uploaded. If file(s) were
074: * uploaded, the {@link java.util.Map} returned has key / value pairs of these two structures:
075: * <ul>
076: * <li><code>String / String[]</code></li>
077: * <li><code>String / {@link org.apache.commons.fileupload.FileItem}</code></li>
078: * </ul>
079: * <br/>
080: * Invokers of this method should be aware that in this case, not all types returned from
081: * what looks like <code>request.getParameterValues(String key)</code> will be <code>String[]</code>.
082: * </p>
083: *
084: * @param request the request object
085: * @param bean the current action's associated {@link ActionForm}
086: * @return <code>null</code> if the request is <i>not</i> multipart. Otherwise, a {@link java.util.Map}
087: * is returned that contains the key / value pairs of the parameters in the request and the uploaded
088: * files.
089: * @throws ServletException if an error occurs loading this file. These exception messages
090: * are not internationalized as Struts does not internationalize them either.
091: */
092: /* package */static final Map handleMultipartRequest(
093: HttpServletRequest request, ActionForm bean)
094: throws ServletException {
095: String contentType = request.getContentType();
096: String method = request.getMethod();
097: boolean isMultipart = false;
098:
099: Map multipartParameters = null;
100:
101: if (contentType != null
102: && contentType.startsWith("multipart/form-data")
103: && method.equalsIgnoreCase("POST")) {
104: if (!InternalUtils.isMultipartHandlingEnabled(request)) {
105: throw new ServletException(
106: "Received a multipart request, but multipart handling is not enabled.");
107: }
108:
109: ActionServletWrapper servlet;
110:
111: if (bean != null) {
112: servlet = bean.getServletWrapper();
113: } else {
114: ServletContext servletContext = InternalUtils
115: .getServletContext(request);
116: servlet = new ActionServletWrapper(InternalUtils
117: .getActionServlet(servletContext));
118: }
119:
120: // @struts: does this -- but we can't rely on the bean not being null.
121: // if(bean instanceof ActionForm)
122: // servlet = bean.getServletWrapper();
123: // else if ( ! ( bean instanceof ActionForm ) )
124: // throw new ServletException
125: // ("bean that's supposed to be populated from a multipart request is not of type " +
126: // "\"org.apache.struts.action.ActionForm\", but type \"" + bean.getClass().getName() + "\"");
127:
128: MultipartRequestHandler multipartHandler = getCachedMultipartHandler(request);
129: boolean preHandled = false;
130:
131: if (multipartHandler == null) {
132: multipartHandler = getMultipartHandler(request);
133: } else {
134: preHandled = true;
135: }
136:
137: if (bean != null) {
138: bean.setMultipartRequestHandler(multipartHandler);
139: }
140:
141: if (multipartHandler != null) {
142: isMultipart = true;
143:
144: servlet.setServletFor(multipartHandler);
145: multipartHandler.setMapping((ActionMapping) request
146: .getAttribute(Globals.MAPPING_KEY));
147:
148: if (!preHandled) {
149: multipartHandler.handleRequest(request);
150: }
151:
152: Boolean maxLengthExceeded = (Boolean) request
153: .getAttribute(MultipartRequestHandler.ATTRIBUTE_MAX_LENGTH_EXCEEDED);
154: if (maxLengthExceeded != null
155: && maxLengthExceeded.booleanValue()) {
156: // bail from RequestUtils.processPopulate
157: // @struts: semantics -- if this check fails, no values are updated into the form
158: return null;
159: }
160: multipartParameters = MultipartRequestUtils
161: .getAllParametersForMultipartRequest(request,
162: multipartHandler);
163:
164: // @struts: does this
165: //names = Collections.enumeration(multipartParameters.keySet());
166: }
167: }
168:
169: if (!isMultipart) {
170: // @struts: does this -- NetUI does not so that the ProcessPopulate method can be made faster; this way,
171: // ProcessPopulate doesn't care whether this is a MultipartRequest or not; it can just talk to a Map
172: // to get key / value pairs.
173: //names = request.getParameterNames();
174: return null;
175: } else {
176: ScopedRequest scopedRequest = ScopedServletUtils
177: .unwrapRequest(request);
178:
179: if (scopedRequest != null) {
180: multipartParameters = scopedRequest
181: .filterParameterMap(multipartParameters);
182: }
183: return multipartParameters;
184: }
185: }
186:
187: /**
188: * Can be called early in the request processing cycle to cache a single multipart handler for the request.
189: */
190: static void preHandleMultipartRequest(HttpServletRequest request)
191: throws ServletException {
192: MultipartRequestHandler multipartHandler = getCachedMultipartHandler(request);
193:
194: if (multipartHandler == null) {
195: multipartHandler = getMultipartHandler(request);
196:
197: if (multipartHandler != null) {
198: //
199: // Run the request through the handler, and cache the handler in the outer request.
200: //
201: multipartHandler.handleRequest(request);
202: HttpServletRequest outerRequest = ScopedServletUtils
203: .getOuterRequest(request);
204: outerRequest.setAttribute(
205: PREHANDLED_MULTIPART_REQUEST_ATTR,
206: multipartHandler);
207: }
208: }
209: }
210:
211: /**
212: * Create an implementation of a {@link MultipartRequestHandler} for this
213: * mulitpart request.
214: *
215: * @param request the current request object
216: * @return the handler
217: * @throws ServletException if an error occurs loading this file. These exception messages
218: * are not internationalized as Struts does not internationalize them either.
219: */
220: // @Struts: org.apache.struts.util.RequestUtils.getMultipartHandler
221: private static final MultipartRequestHandler getMultipartHandler(
222: HttpServletRequest request) throws ServletException {
223: MultipartRequestHandler multipartHandler = null;
224: String multipartClass = (String) request
225: .getAttribute(Globals.MULTIPART_KEY);
226: request.removeAttribute(Globals.MULTIPART_KEY);
227:
228: // Try to initialize the mapping specific request handler
229: if (multipartClass != null) {
230: try {
231: multipartHandler = (MultipartRequestHandler) RequestUtils
232: .applicationInstance(multipartClass);
233: } catch (ClassNotFoundException cnfe) {
234: _log.error("MultipartRequestHandler class \""
235: + multipartClass
236: + "\" in mapping class not found, "
237: + "defaulting to global multipart class");
238: } catch (InstantiationException ie) {
239: _log
240: .error("InstantiaionException when instantiating "
241: + "MultipartRequestHandler \""
242: + multipartClass
243: + "\", "
244: + "defaulting to global multipart class, exception: "
245: + ie.getMessage());
246: } catch (IllegalAccessException iae) {
247: _log
248: .error("IllegalAccessException when instantiating "
249: + "MultipartRequestHandler \""
250: + multipartClass
251: + "\", "
252: + "defaulting to global multipart class, exception: "
253: + iae.getMessage());
254: }
255:
256: if (multipartHandler != null)
257: return multipartHandler;
258: }
259:
260: ModuleConfig moduleConfig = (ModuleConfig) request
261: .getAttribute(Globals.MODULE_KEY);
262: multipartClass = moduleConfig.getControllerConfig()
263: .getMultipartClass();
264:
265: // Try to initialize the global request handler
266: if (multipartClass != null) {
267: try {
268: multipartHandler = (MultipartRequestHandler) RequestUtils
269: .applicationInstance(multipartClass);
270: } catch (ClassNotFoundException cnfe) {
271: throw new ServletException(
272: "Cannot find multipart class \""
273: + multipartClass + "\""
274: + ", exception: " + cnfe.getMessage());
275: } catch (InstantiationException ie) {
276: throw new ServletException(
277: "InstantiaionException when instantiating "
278: + "multipart class \"" + multipartClass
279: + "\", exception: " + ie.getMessage());
280: } catch (IllegalAccessException iae) {
281: throw new ServletException(
282: "IllegalAccessException when instantiating "
283: + "multipart class \"" + multipartClass
284: + "\", exception: " + iae.getMessage());
285: }
286:
287: if (multipartHandler != null)
288: return multipartHandler;
289: }
290:
291: return multipartHandler;
292: }
293:
294: /**
295: * Get a {@link java.util.Map} object that reprensents the request parameters for
296: * a multipart request. As described in {@link #handleMultipartRequest}, the
297: * Map returned here may contain either String[] or FileItem values. The former
298: * are regular request parameters and the latter are the Struts abstraction
299: * on top of an uploaded file
300: *
301: * @param request the request
302: * @param multipartHandler the multipart handler for this request
303: * @return a Map of the key / value pairs of parameters in this request and object
304: * representations of the uploaded files.
305: */
306: // @Struts: org.apache.struts.util.RequestUtils.getAllParametrsForMultipartRequest
307: private static final Map getAllParametersForMultipartRequest(
308: HttpServletRequest request,
309: MultipartRequestHandler multipartHandler) {
310: Map parameters = new HashMap();
311: Enumeration e;
312:
313: Hashtable elements = multipartHandler.getAllElements();
314: e = elements.keys();
315: while (e.hasMoreElements()) {
316: String key = (String) e.nextElement();
317: parameters.put(key, elements.get(key));
318: }
319:
320: if (request instanceof MultipartRequestWrapper) {
321: request = ((MultipartRequestWrapper) request).getRequest();
322: e = request.getParameterNames();
323: while (e.hasMoreElements()) {
324: String key = (String) e.nextElement();
325: parameters.put(key, request.getParameterValues(key));
326: }
327: } else {
328: _log
329: .debug("Gathering multipart parameters for unwrapped request");
330: }
331:
332: return parameters;
333: }
334:
335: static MultipartRequestHandler getCachedMultipartHandler(
336: HttpServletRequest request) {
337: HttpServletRequest req = ScopedServletUtils
338: .getOuterRequest(request);
339: return (MultipartRequestHandler) req
340: .getAttribute(MultipartRequestUtils.PREHANDLED_MULTIPART_REQUEST_ATTR);
341: }
342: }
|