View Javadoc

1   /**
2    * Copyright (C) 2005-2009 Alfresco Software Limited.
3    *
4    * This file is part of the Spring Surf Extension project.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * 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, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.springframework.extensions.webscripts.servlet;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.Serializable;
24  import java.io.UnsupportedEncodingException;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  import javax.servlet.http.HttpServletRequest;
30  
31  import org.apache.commons.fileupload.FileItem;
32  import org.apache.commons.fileupload.FileItemFactory;
33  import org.apache.commons.fileupload.FileUploadException;
34  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
35  import org.apache.commons.fileupload.servlet.ServletFileUpload;
36  import org.apache.commons.io.FilenameUtils;
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.springframework.extensions.surf.exception.WebScriptsPlatformException;
40  import org.springframework.extensions.surf.util.Content;
41  import org.springframework.extensions.surf.util.InputStreamContent;
42  
43  
44  /**
45   * Form Data
46   * 
47   * @author davidc
48   */
49  public class FormData implements Serializable
50  {
51      private static final long serialVersionUID = 1832644544828452385L;
52      
53      /** Logger */
54      private static Log logger = LogFactory.getLog(FormData.class);
55      
56      private HttpServletRequest req;
57      private String encoding = null;
58      private ServletFileUpload upload;
59      private FormField[] fields = null;
60      private Map<String, String[]> parameters = null;
61  
62      
63      /**
64       * Construct
65       * 
66       * @param req
67       */
68      public FormData(HttpServletRequest req)
69      {
70          this.req = req;
71      }
72  
73      /**
74       * Determine if multi-part form data has been provided
75       * 
76       * @return  true => multi-part
77       */
78      public boolean getIsMultiPart()
79      {
80          return upload.isMultipartContent(req);
81      }
82  
83      /**
84       * Determine if form data has specified field
85       * 
86       * @param name  field to look for
87       * @return  true => form data contains field
88       */
89      public boolean hasField(String name)
90      {
91          for (FormField field : fields)
92          {
93             if (field.getName().equals(name))
94             {
95                 return true;
96             }
97          }
98          return false;
99      }
100 
101     /**
102      * Helper to parse servlet request form data
103      * 
104      * @return  map of all form fields
105      */
106     public FormField[] getFields()
107     {
108         // NOTE: This class is not thread safe - it is expected to be constructed on each thread.
109         if (fields == null)
110         {
111             FileItemFactory factory = new DiskFileItemFactory();
112             upload = new ServletFileUpload(factory);
113             encoding = req.getCharacterEncoding();
114             upload.setHeaderEncoding(encoding);
115             
116             try
117             {
118                 List<FileItem> fileItems = upload.parseRequest(req);
119                 fields = new FormField[fileItems.size()];
120                 for (int i = 0; i < fileItems.size(); i++)
121                 {
122                     FormField formField = new FormField(fileItems.get(i));
123                     fields[i] = formField;
124                 }
125             }
126             catch(FileUploadException e)
127             {
128                 fields = new FormField[0];
129             }
130             
131         }
132         return fields;
133     }
134  
135     /**
136      * Gets parameters encoded in the form data
137      * 
138      * @return  map (name, value) of parameters
139      */
140     /*package*/ public Map<String, String[]> getParameters()
141     {
142         if (parameters == null)
143         {
144             FormField[] fields = getFields();
145             parameters = new HashMap<String, String[]>(fields.length);
146             for (FormField field : fields)
147             {
148                 String[] vals = parameters.get(field.getName());
149                 if (vals == null)
150                 {
151                     parameters.put(field.getName(), new String[] {field.getValue()});
152                 }
153                 else
154                 {
155                     String[] valsNew = new String[vals.length +1]; 
156                     System.arraycopy(vals, 0, valsNew, 0, vals.length);
157                     valsNew[vals.length] = field.getValue();
158                     parameters.put(field.getName(), valsNew);
159                 }
160             }
161         }
162         return parameters;
163     }
164     
165 
166     /**
167      * Form Field
168      * 
169      * @author davidc
170      */
171     public class FormField implements Serializable
172     {
173         private static final long serialVersionUID = -6061565518843862346L;
174         private FileItem file;
175 
176         /**
177          * Construct
178          * 
179          * @param file
180          */
181         public FormField(FileItem file)
182         {
183             this.file = file;
184         }
185         
186         /**
187          * @return  field name
188          */
189         public String getName()
190         {
191             return file.getFieldName();
192         }
193         
194         /**
195          * @return  true => field represents a file
196          */
197         public boolean getIsFile()
198         {
199             return !file.isFormField();
200         }
201         
202         /**
203          * @return field value (for form fields)
204          *         for file upload fields, the file name is returned - use getContent() instead.
205          */
206         public String getValue()
207         {
208             try
209             {
210                 String value;
211                 if (file.isFormField())
212                 {
213                     value = (encoding != null ? file.getString(encoding) : file.getString());
214                 }
215                 else
216                 {
217                     // For large/binary files etc. we never immediately load the content directly into memory!
218                     // This would be extremely bad for say large binary file uploads etc.
219                     value = file.getName();
220                 }
221                 return value;
222             }
223             catch (UnsupportedEncodingException e)
224             {
225                 throw new WebScriptsPlatformException("Unable to decode form field", e);
226             }
227         }
228         
229         /**
230          * @return  field as content
231          */
232         public Content getContent()
233         {
234             try
235             {
236                 return new InputStreamContent(file.getInputStream(), getMimetype(), null);
237             }
238             catch (IOException e)
239             {
240                 if (logger.isWarnEnabled())
241                     logger.warn("Failed to get content: " + e.getMessage());
242                 
243                 return null;
244             }
245         }
246         
247         /**
248          * @return InputStream to contents of file
249          */
250         public InputStream getInputStream()
251         {
252             try
253             {
254                 return file.getInputStream();
255             }
256             catch (IOException e)
257             {
258                 if (logger.isWarnEnabled())
259                     logger.warn("Failed to get input stream: " + e.getMessage());
260                 
261                 return null;
262             }
263         }
264 
265         /**
266          * @return  mimetype
267          */
268         public String getMimetype()
269         {
270             return file.getContentType();
271         }
272 
273         /**
274          * @return  filename (only for file fields, otherwise null)
275          */
276         public String getFilename()
277         {
278             // workaround a bug in IE where the full path is returned
279             return FilenameUtils.getName(file.getName());
280         }
281     }
282     
283 }