View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.webapp.filter;
20  
21  import java.io.File;
22  import java.io.UnsupportedEncodingException;
23  import java.util.Collections;
24  import java.util.Enumeration;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  
30  import javax.portlet.ActionRequest;
31  
32  import org.apache.commons.fileupload.FileItem;
33  import org.apache.commons.fileupload.FileUploadBase;
34  import org.apache.commons.fileupload.FileUploadException;
35  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
36  import org.apache.commons.fileupload.portlet.PortletFileUpload;
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.apache.myfaces.webapp.filter.portlet.ActionRequestWrapper;
40  import org.apache.myfaces.webapp.filter.portlet.PortletChacheFileSizeErrorsFileUpload;
41  
42  /**
43   * @since 1.1.8
44   * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
45   * @version $Revision: 782515 $ $Date: 2009-06-07 22:28:42 -0500 (Sun, 07 Jun 2009) $
46   */
47  public class PortletMultipartRequestWrapper
48          extends ActionRequestWrapper
49  {
50      private static Log log = LogFactory.getLog(PortletMultipartRequestWrapper.class);
51      public static final String UPLOADED_FILES_ATTRIBUTE = "org.apache.myfaces.uploadedFiles";
52      public static final String WWW_FORM_URLENCODED_TYPE = "application/x-www-form-urlencoded";
53  
54      ActionRequest request = null;
55      HashMap parametersMap = null;
56      PortletFileUpload fileUpload = null;
57      HashMap fileItems = null;
58      int maxFileSize;
59      int maxSize;
60      int thresholdSize;
61      String repositoryPath;
62      boolean cacheFileSizeErrors;
63  
64      public PortletMultipartRequestWrapper(Object request,
65                                     int maxFileSize, int thresholdSize,
66                                     String repositoryPath){
67          super((ActionRequest) request );
68          this.request = (ActionRequest) request;
69          this.maxFileSize = maxFileSize;
70          this.thresholdSize = thresholdSize;
71          this.repositoryPath = repositoryPath;
72          //Default values
73          this.maxSize = maxFileSize;
74          this.cacheFileSizeErrors = false;
75      }
76      
77      public PortletMultipartRequestWrapper(Object request,
78              int maxFileSize, int thresholdSize,
79              String repositoryPath, int maxRequestSize, boolean cacheFileSizeErrors){
80          super((ActionRequest) request );
81          this.request = (ActionRequest) request;
82          this.maxFileSize = maxFileSize;
83          this.maxSize = maxRequestSize;
84          this.thresholdSize = thresholdSize;
85          this.repositoryPath = repositoryPath;
86          this.cacheFileSizeErrors = cacheFileSizeErrors;
87      }
88  
89  
90      private void parseRequest() {
91          if (cacheFileSizeErrors)
92          {
93              fileUpload = new PortletChacheFileSizeErrorsFileUpload();
94          }
95          else
96          {
97              fileUpload = new PortletFileUpload();
98          }
99  
100         fileUpload.setSizeMax(maxSize);
101         fileUpload.setFileSizeMax(maxFileSize);
102 
103         //fileUpload.setSizeThreshold(thresholdSize);
104 
105         if(repositoryPath != null && repositoryPath.trim().length()>0)
106         {
107             //fileUpload.setRepositoryPath(repositoryPath);
108             fileUpload.setFileItemFactory(
109                     new DiskFileItemFactory(thresholdSize,
110                             new File(repositoryPath)));
111         }
112         else
113         {
114             fileUpload.setFileItemFactory(
115                     new DiskFileItemFactory(thresholdSize,
116                             new File(System.getProperty("java.io.tmpdir"))));
117         }
118 
119         String charset = request.getCharacterEncoding();
120         fileUpload.setHeaderEncoding(charset);
121 
122 
123         List requestParameters = null;
124         
125         try
126         {
127             if (cacheFileSizeErrors)
128             {
129                 requestParameters = ((PortletChacheFileSizeErrorsFileUpload) fileUpload).
130                     parseRequestCatchingFileSizeErrors(request, fileUpload);
131             }
132             else
133             {
134                 requestParameters = fileUpload.parseRequest(request);
135             }
136         }
137         catch (FileUploadBase.FileSizeLimitExceededException e)
138         {
139             // Since commons-fileupload does not allow to continue processing files
140             // if this exception is thrown, we can't do anything else.
141             // So, the current request is rejected and we can't restore state, so 
142             // this request is dealt like a new request, but note that caching the params
143             // below it is possible to detect if the current request has been aborted
144             // or not.
145             // Note that if cacheFileSizeErrors is true, this is not thrown, so the request
146             // is not aborted unless other different error occur.
147             request.setAttribute(
148                     "org.apache.myfaces.custom.fileupload.exception","fileSizeLimitExceeded");
149             request.setAttribute("org.apache.myfaces.custom.fileupload.maxSize",
150                     new Integer((int)maxFileSize));
151             
152             if (log.isWarnEnabled())
153                 log.warn("FileSizeLimitExceededException while uploading file.", e);
154             
155             requestParameters = Collections.EMPTY_LIST;
156         }
157         catch (FileUploadBase.SizeLimitExceededException e)
158         {
159             // This exception is thrown when the max request size has been reached.
160             // In this case, the current request is rejected. The current 
161             // request is dealt like a new request, but note that caching the params below
162             // params it is possible to detect if the current request has been aborted
163             // or not.
164             request.setAttribute(
165                 "org.apache.myfaces.custom.fileupload.exception","sizeLimitExceeded");
166             request.setAttribute("org.apache.myfaces.custom.fileupload.maxSize",
167                 new Integer((int)maxSize));
168             
169             if (log.isWarnEnabled())
170                 log.warn("SizeLimitExceededException while uploading file.", e);
171             
172             requestParameters = Collections.EMPTY_LIST;
173         }
174         catch(FileUploadException fue)
175         {
176             if (log.isErrorEnabled())
177                 log.error("Exception while uploading file.", fue);
178             
179             requestParameters = Collections.EMPTY_LIST;
180         }        
181 
182         parametersMap = new HashMap( requestParameters.size() );
183         fileItems = new HashMap();
184 
185         for (Iterator iter = requestParameters.iterator(); iter.hasNext(); ){
186             FileItem fileItem = (FileItem) iter.next();
187 
188             if (fileItem.isFormField()) {
189                 String name = fileItem.getFieldName();
190 
191                 // The following code avoids commons-fileupload charset problem.
192                 // After fixing commons-fileupload, this code should be
193                 //
194                 //     String value = fileItem.getString();
195                 //
196                 String value = null;
197                 if ( charset == null) {
198                     value = fileItem.getString();
199                 } else {
200                     try {
201                         value = new String(fileItem.get(), charset);
202                     } catch (UnsupportedEncodingException e){
203                         value = fileItem.getString();
204                     }
205                 }
206 
207                 addTextParameter(name, value);
208             } else { // fileItem is a File
209                 if (fileItem.getName() != null) {
210                     fileItems.put(fileItem.getFieldName(), fileItem);
211                 }
212             }
213         }
214 
215         //Add the query string paramters
216         for (Iterator it = request.getParameterMap().entrySet().iterator(); it.hasNext(); )
217         {
218             Map.Entry entry = (Map.Entry)it.next();
219 
220             Object value = entry.getValue();
221 
222             if(value instanceof String[])
223             {
224                 String[] valuesArray = (String[])entry.getValue();
225                 for (int i = 0; i < valuesArray.length; i++)
226                 {
227                     addTextParameter((String)entry.getKey(), valuesArray[i]);
228                 }
229             }
230             else if(value instanceof String)
231             {
232                 String strValue = (String)entry.getValue();
233                 addTextParameter((String)entry.getKey(), strValue);
234             }
235             else if(value != null)
236                 throw new IllegalStateException("value of type : "+value.getClass()+" for key : "+
237                         entry.getKey()+" cannot be handled.");
238 
239         }
240     }
241 
242     private void addTextParameter(String name, String value){
243         if( ! parametersMap.containsKey( name ) ){
244             String[] valuesArray = {value};
245             parametersMap.put(name, valuesArray);
246         }else{
247             String[] storedValues = (String[])parametersMap.get( name );
248             int lengthSrc = storedValues.length;
249             String[] valuesArray = new String[lengthSrc+1];
250             System.arraycopy(storedValues, 0, valuesArray, 0, lengthSrc);
251             valuesArray[lengthSrc] = value;
252             parametersMap.put(name, valuesArray);
253         }
254     }
255 
256     public Enumeration getParameterNames() {
257         if( parametersMap == null ) parseRequest();
258 
259         return Collections.enumeration( parametersMap.keySet() );
260     }
261 
262     public String getParameter(String name) {
263         if( parametersMap == null ) parseRequest();
264 
265         String[] values = (String[])parametersMap.get( name );
266         if( values == null )
267             return null;
268         return values[0];
269     }
270 
271     public String[] getParameterValues(String name) {
272         if( parametersMap == null ) parseRequest();
273 
274         return (String[])parametersMap.get( name );
275     }
276 
277     public Map getParameterMap() {
278         if( parametersMap == null ) parseRequest();
279 
280         return parametersMap;
281     }
282 
283     // Hook for the x:inputFileUpload tag.
284     public FileItem getFileItem(String fieldName) {
285         if( fileItems == null ) parseRequest();
286 
287         return (FileItem) fileItems.get( fieldName );
288     }
289 
290     /**
291      * Not used internally by MyFaces, but provides a way to handle the uploaded files
292      * out of MyFaces.
293      */
294     public Map getFileItems(){
295         if( fileItems == null ) parseRequest();
296         return fileItems;
297     }
298 
299 
300     public Object getAttribute(String string) {
301         if (string.equals(UPLOADED_FILES_ATTRIBUTE)) {
302             return getFileItems();
303         }
304         return super.getAttribute(string);
305     }
306     
307     public String getContentType()
308     {
309       return WWW_FORM_URLENCODED_TYPE;
310     }     
311 }