001: package com.sun.portal.app.filesharing.faces;
002:
003: import com.sun.portal.app.filesharing.util.ParameterCheck;
004: import com.sun.web.ui.component.Upload;
005: import com.sun.web.ui.util.MessageUtil;
006: import com.sun.faces.portlet.FacesPortlet;
007: import org.apache.commons.fileupload.FileItem;
008: import org.apache.commons.fileupload.FileUpload;
009: import org.apache.commons.fileupload.FileUploadException;
010: import org.apache.commons.fileupload.disk.DiskFileItemFactory;
011: import org.apache.commons.fileupload.portlet.PortletFileUpload;
012: import org.apache.commons.fileupload.portlet.PortletRequestContext;
013:
014: import javax.portlet.*;
015: import java.io.*;
016: import java.util.*;
017: import java.security.Principal;
018:
019: /**
020: * <p>Use the UploadFilter if your application contains an Upload component
021: * (<ui:upload> tag).</p>
022: * <p>Configure the filter by declaring the filter element in the web application's
023: * deployment descriptor.</p>
024: * <pre>
025: <filter>
026: <filter-name>UploadFilter</filter-name>
027: <filter-class>com.sun.web.ui.util.UploadFilter</filter-class>
028: </filter>
029: </pre>
030: *<p>Map the filter to the FacesServlet, for example</p>
031: *<pre>
032: <filter-mapping>
033: <filter-name>UploadFilter</filter-name>
034: <servlet-name>FacesServlet</servlet-name>
035: </filter-mapping>
036: </pre>
037: *<p>The UploadFilter uses the Apache commons fileupload package. You can
038: *configure the parameters of the DiskFileUpload class by specifying init
039: *parameters to the Filter. The following parameters are available:
040: *<ul>
041: *<li><code>maxSize</code> The maximum allowed upload size in bytes.
042: *If negative, there is no maximum. The default value is 1,000,000.</li>
043: *
044: *<li><code>sizeThreshold</code>The implementation of the uploading
045: * functionality uses temporary storage of the file contents before the
046: * Upload component stores them per its configuration. In the temporary
047: * storage, smaller files are stored in memory while larger files are
048: * written directly to disk . Use this parameter
049: * to specify an integer value of the cut-off where files should be
050: * written to disk. The default value is 4096 bytes.</li>
051: *<li><code>tmpDir</code> Use this directory to specify the directory to
052: *be used for temporary storage of files. The default behaviour is to use
053: *the directory specified in the system property "java.io.tmpdir". </li>
054: *</ul>
055:
056: */
057: public class LHUploadFacesPortlet implements Portlet {
058: private Portlet _facesPortlet;
059:
060: public LHUploadFacesPortlet() {
061: _facesPortlet = new FacesPortlet();
062: }
063:
064: /**
065: * The name of the filter init parameter used to specify the maximum
066: * allowable file upload size.
067: */
068: public static final String MAX_SIZE = "maxSize";
069: /**
070: * The name of the filter init parameter used to specify the byte
071: * size above which temporary storage of files is on disk.
072: */
073: public static final String SIZE_THRESHOLD = "sizeThreshold";
074: /**
075: * The name of the filter init parameter used to specify
076: * the directory to be used for temporary storage of
077: * uploaded files.
078: */
079: public static final String TMP_DIR = "tmpDir";
080:
081: private long maxSize = 1000000;
082: private int sizeThreshold = 4096;
083: private String tmpDir = System.getProperty("java.io.tmpdir");
084: private String messages = "com.sun.web.ui.resources.LogMessages";
085:
086: /**
087: * Initializes the Upload filter portlet by reading any init parameters.
088: * @param portletConfig the portlet configuration
089: */
090: public void init(PortletConfig portletConfig)
091: throws PortletException {
092: StringBuffer errorMessageBuffer = new StringBuffer(300);
093: String param = portletConfig.getInitParameter(MAX_SIZE);
094: if (param != null) {
095: try {
096: maxSize = Long.parseLong(param);
097: } catch (NumberFormatException nfe) {
098: Object[] params = { MAX_SIZE, param };
099: String msg = MessageUtil.getMessage(messages,
100: "Upload.invalidLong", params);
101: errorMessageBuffer.append(msg);
102: }
103: }
104: param = portletConfig.getInitParameter(SIZE_THRESHOLD);
105: if (param != null) {
106: try {
107: sizeThreshold = Integer.parseInt(param);
108: } catch (NumberFormatException nfe) {
109: Object[] params = { SIZE_THRESHOLD, param };
110: errorMessageBuffer.append(" ");
111: String msg = MessageUtil.getMessage(messages,
112: "Upload.invalidInt", params);
113: errorMessageBuffer.append(msg);
114: }
115: }
116: param = portletConfig.getInitParameter(TMP_DIR);
117: if (param != null) {
118: tmpDir = param;
119: File dir = new File(tmpDir);
120: if (!dir.canWrite()) {
121: Object[] params = { TMP_DIR, param };
122: errorMessageBuffer.append(" ");
123: String msg = MessageUtil.getMessage(messages,
124: "Upload.invalidDir", params);
125: errorMessageBuffer.append(msg);
126: }
127: }
128: String error = errorMessageBuffer.toString();
129: if (error.length() > 0) {
130: throw new RuntimeException(error);
131: }
132: _facesPortlet.init(portletConfig);
133: }
134:
135: public void destroy() {
136: _facesPortlet = null;
137: }
138:
139: /**
140: * <p>The upload filter checks if the incoming request has multipart content.
141: * If it doesn't, the request is passed on as is to the next filter in the chain.
142: * If it does, the filter processes the request for form components. If it finds
143: * input from an Upload component, the file contents are stored for access by the
144: * Upload component's decode method. </p>
145: * <p>For other form components, the input is processed and used to create a
146: * request parameter map. The original incoming request is wrapped, and the
147: * wrapped request is configured to use the created map. This means that
148: * subsequent filters in the chain (and Servlets, and JSPs) see the
149: * input from the other components as request parameters.</p>
150: *<p>For advanced users: the UploadFilter uses the Apache commons FileUpload
151: *package to process the file upload. When it detects input from an Upload
152: *component, a <code>org.apache.commons.fileupload.FileItem</code> is placed
153: * in a request attribute whose name is the ID of the HTML input element
154: * written by the Upload component.</p>
155: *
156: */
157: public void processAction(ActionRequest req, ActionResponse res)
158: throws PortletException, IOException {
159:
160: if (FileUpload
161: .isMultipartContent(new PortletRequestContext(req))) {
162:
163: DiskFileItemFactory factory = new DiskFileItemFactory();
164: // maximum size that will be stored in memory
165: factory.setSizeThreshold(sizeThreshold);
166: // the location for saving data that is larger than getSizeThreshold()
167: factory.setRepository(new File(tmpDir));
168:
169: PortletFileUpload fu = new PortletFileUpload(factory);
170: // maximum size before a FileUploadException will be thrown
171: // Store this in a context parameter perhaps?
172: fu.setSizeMax(maxSize);
173:
174: List fileItems;
175: Hashtable parameters = new Hashtable();
176: try {
177: fileItems = fu.parseRequest(req);
178: parameters = parseRequest(fileItems, req);
179: } catch (FileUploadException fue) {
180: req.getPortletSession().setAttribute(
181: "_upload_exception_", fue);
182: //throw new PortletException("Could not parse multi-part request parameters");
183: }
184:
185: //Hashtable parameters = parseRequest(fileItems,req);
186:
187: try {
188: _facesPortlet.processAction(new ActionRequestWrapper(
189: req, parameters), res);
190: } catch (PortletException ex) {
191: log("FacesPortlet.processAction() " + ex.getMessage());
192: } catch (IOException ex) {
193: log("FacesPortlet.processAction() " + ex.getMessage());
194: } finally {
195: Enumeration e = req.getAttributeNames();
196: while (e.hasMoreElements()) {
197: Object o = req.getAttribute(e.nextElement()
198: .toString());
199: if (o instanceof FileItem) {
200: ((FileItem) o).delete();
201: }
202: }
203: }
204: } else {
205: _facesPortlet.processAction(req, res);
206: }
207: }
208:
209: private static final boolean DEBUG = false;
210:
211: private void log(String s) {
212: System.out.println(getClass().getName() + "::" + s);
213: }
214:
215: private Hashtable parseRequest(List fileItems, ActionRequest request) {
216:
217: if (DEBUG)
218: log("parseRequest()");
219:
220: // Iterate over the FileItems to see if any of them correspond
221: // to the ID of an input type="file" that is rendered inside a
222: // a span. This happens if the component has a label attribute or
223: // a label facet, and in this case, the DOM id of the input
224: // element is created by the component in such a way that we
225: // can match it directly. If there is a match, a request attribute
226: // is added for the corresponding FileItem . If there is no match,
227: // add the fileItem to a map, with the fieldID as the key.
228:
229: Iterator iterator = fileItems.iterator();
230: String fieldID = null;
231: FileItem fileItem = null;
232: Map fileItemsMap = new TreeMap();
233: String charset = request.getCharacterEncoding();
234:
235: if (DEBUG)
236: log("\tFirst pass through the parameters which are");
237: while (iterator.hasNext()) {
238: fileItem = (FileItem) (iterator.next());
239: fieldID = fileItem.getFieldName();
240: if (DEBUG)
241: log("\t\t" + fieldID);
242: if (fieldID.endsWith(Upload.INPUT_ID)) {
243: request.setAttribute(fieldID, fileItem);
244: if (DEBUG)
245: log(fieldID + " added to the request parameters");
246: } else {
247: fileItemsMap.put(fieldID, fileItem);
248: }
249: }
250:
251: // Iterate over the FileItems to see if any of them correspond
252: // to a hidden field used to identify a FileUpload which does
253: // not have an associated label. (In that case, the ID of the
254: // input element is the same of the component ID, so we can't
255: // tell by looking at the ID directly.) If so, we take the value
256: // of the hidden ID, which is the ID of the input component and
257: // get the corresponding file item. Both the ID of the hidden
258: // component and that of the input itself are added to the
259: // parameters to be ignored.
260:
261: if (DEBUG)
262: log("\tSecond pass through the parameters");
263: ArrayList removes = new ArrayList();
264: ArrayList unlabeledUploads = new ArrayList();
265: iterator = fileItemsMap.keySet().iterator();
266: String param = null;
267: while (iterator.hasNext()) {
268: fieldID = (String) (iterator.next());
269: if (fieldID.endsWith(Upload.INPUT_PARAM_ID)) {
270: fileItem = (FileItem) (fileItemsMap.get(fieldID));
271: param = fileItem.getString();
272: unlabeledUploads.add(param);
273: removes.add(fieldID);
274: if (DEBUG)
275: log("\tFound other fileUpload for parameter "
276: + param);
277: }
278: }
279:
280: // If we found IDs of any unlabeled Uploads, we create request
281: // attributes for them too, and add their IDs to the list of IDs
282: // to remove.
283: if (!unlabeledUploads.isEmpty()) {
284: if (DEBUG)
285: log("\tFound unlabeledUploads ");
286: iterator = unlabeledUploads.iterator();
287: while (iterator.hasNext()) {
288: fieldID = iterator.next().toString();
289: fileItem = (FileItem) (fileItemsMap.get(fieldID));
290: request.setAttribute(fieldID.concat(Upload.INPUT_ID),
291: fileItem);
292: removes.add(fieldID);
293: if (DEBUG)
294: log("\tAdd FileItem for "
295: + fieldID.concat(Upload.INPUT_ID));
296: }
297: }
298:
299: // If we have any fields to be removed from the parameter map,
300: // we do so
301: if (!removes.isEmpty()) {
302: iterator = removes.iterator();
303: while (iterator.hasNext()) {
304: fileItemsMap.remove(iterator.next());
305: }
306: }
307:
308: // Create a hashtable to use for the parameters, and add the remaining
309: // fileItems
310: Hashtable parameters = new Hashtable();
311: iterator = fileItemsMap.keySet().iterator();
312: Object id = null;
313: if (DEBUG)
314: log("\tFinally, create regular parameters for ");
315: while (iterator.hasNext()) {
316: id = iterator.next();
317: parameters.put(ParameterCheck.decodeCharset((String) id,
318: charset), new String[] { ParameterCheck
319: .decodeCharset(((FileItem) fileItemsMap.get(id))
320: .getString(), charset) });
321: if (DEBUG)
322: log("\t\t " + id + ":"
323: + ((FileItem) fileItemsMap.get(id)).getString());
324: }
325:
326: return parameters;
327: }
328:
329: public void render(RenderRequest renderRequest,
330: RenderResponse renderResponse) throws PortletException,
331: IOException {
332: _facesPortlet.render(renderRequest, renderResponse);
333: }
334:
335: private static class ActionRequestWrapper implements ActionRequest {
336: private ActionRequest _req;
337: private Map _parameters;
338:
339: public ActionRequestWrapper(ActionRequest req, Map parameters) {
340: _req = req;
341: _parameters = Collections.unmodifiableMap(parameters);
342: }
343:
344: public Map getParameterMap() {
345: return _parameters;
346: }
347:
348: public InputStream getPortletInputStream() throws IOException {
349: return _req.getPortletInputStream();
350: }
351:
352: public void setCharacterEncoding(String s)
353: throws UnsupportedEncodingException {
354: _req.setCharacterEncoding(s);
355: }
356:
357: public BufferedReader getReader()
358: throws UnsupportedEncodingException, IOException {
359: return _req.getReader();
360: }
361:
362: public String getCharacterEncoding() {
363: return _req.getCharacterEncoding();
364: }
365:
366: public String getContentType() {
367: return _req.getContentType();
368: }
369:
370: public int getContentLength() {
371: return _req.getContentLength();
372: }
373:
374: public boolean isWindowStateAllowed(WindowState windowState) {
375: return _req.isWindowStateAllowed(windowState);
376: }
377:
378: public boolean isPortletModeAllowed(PortletMode portletMode) {
379: return _req.isPortletModeAllowed(portletMode);
380: }
381:
382: public PortletMode getPortletMode() {
383: return _req.getPortletMode();
384: }
385:
386: public WindowState getWindowState() {
387: return _req.getWindowState();
388: }
389:
390: public PortletPreferences getPreferences() {
391: return _req.getPreferences();
392: }
393:
394: public PortletSession getPortletSession() {
395: return _req.getPortletSession();
396: }
397:
398: public PortletSession getPortletSession(boolean b) {
399: return _req.getPortletSession(b);
400: }
401:
402: public String getProperty(String s) {
403: return _req.getProperty(s);
404: }
405:
406: public Enumeration getProperties(String s) {
407: return _req.getProperties(s);
408: }
409:
410: public Enumeration getPropertyNames() {
411: return _req.getPropertyNames();
412: }
413:
414: public PortalContext getPortalContext() {
415: return _req.getPortalContext();
416: }
417:
418: public String getAuthType() {
419: return _req.getAuthType();
420: }
421:
422: public String getContextPath() {
423: return _req.getContextPath();
424: }
425:
426: public String getRemoteUser() {
427: return _req.getRemoteUser();
428: }
429:
430: public Principal getUserPrincipal() {
431: return _req.getUserPrincipal();
432: }
433:
434: public boolean isUserInRole(String s) {
435: return _req.isUserInRole(s);
436: }
437:
438: public Object getAttribute(String s) {
439: return _req.getAttribute(s);
440: }
441:
442: public Enumeration getAttributeNames() {
443: return _req.getAttributeNames();
444: }
445:
446: public String getParameter(String s) {
447: String[] params = getParameterValues(s);
448: return (params != null && params.length > 0) ? params[0]
449: : null;
450: }
451:
452: public Enumeration getParameterNames() {
453: return Collections.enumeration(_parameters.keySet());
454: }
455:
456: public String[] getParameterValues(String s) {
457: return (String[]) _parameters.get(s);
458: }
459:
460: public boolean isSecure() {
461: return _req.isSecure();
462: }
463:
464: public void setAttribute(String s, Object o) {
465: _req.setAttribute(s, o);
466: }
467:
468: public void removeAttribute(String s) {
469: _req.removeAttribute(s);
470: }
471:
472: public String getRequestedSessionId() {
473: return _req.getRequestedSessionId();
474: }
475:
476: public boolean isRequestedSessionIdValid() {
477: return _req.isRequestedSessionIdValid();
478: }
479:
480: public String getResponseContentType() {
481: return _req.getResponseContentType();
482: }
483:
484: public Enumeration getResponseContentTypes() {
485: return _req.getResponseContentTypes();
486: }
487:
488: public Locale getLocale() {
489: return _req.getLocale();
490: }
491:
492: public Enumeration getLocales() {
493: return _req.getLocales();
494: }
495:
496: public String getScheme() {
497: return _req.getScheme();
498: }
499:
500: public String getServerName() {
501: return _req.getServerName();
502: }
503:
504: public int getServerPort() {
505: return _req.getServerPort();
506: }
507:
508: }
509: }
|