View Javadoc

1   package org.apache.turbine.services.upload;
2   
3   /*
4    * Copyright 2001-2005 The Apache Software Foundation.
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  import java.io.File;
20  import java.io.UnsupportedEncodingException;
21  
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import javax.servlet.http.HttpServletRequest;
26  
27  import org.apache.commons.configuration.Configuration;
28  
29  import org.apache.commons.fileupload.DiskFileUpload;
30  import org.apache.commons.fileupload.FileItem;
31  import org.apache.commons.fileupload.FileUploadException;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  import org.apache.turbine.Turbine;
37  import org.apache.turbine.services.InitializationException;
38  import org.apache.turbine.services.TurbineBaseService;
39  import org.apache.turbine.util.TurbineException;
40  import org.apache.turbine.util.parser.ParameterParser;
41  
42  /***
43   * <p> This class is an implementation of {@link UploadService}.
44   *
45   * <p> Files will be stored in temporary disk storage on in memory,
46   * depending on request size, and will be available from the {@link
47   * org.apache.turbine.util.parser.ParameterParser} as {@link
48   * org.apache.commons.fileupload.FileItem}s.
49   *
50   * <p>This implementation of {@link UploadService} handles multiple
51   * files per single html widget, sent using multipar/mixed encoding
52   * type, as specified by RFC 1867.  Use {@link
53   * org.apache.turbine.util.parser.ParameterParser#getFileItems(String)} to
54   * acquire an array of {@link
55   * org.apache.commons.fileupload.FileItem}s associated with given
56   * html widget.
57   *
58   * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
59   * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
60   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
61   * @version $Id: TurbineUploadService.java 279820 2005-09-09 17:05:54Z henning $
62   */
63  public class TurbineUploadService
64          extends TurbineBaseService
65          implements UploadService
66  {
67      /*** Logging */
68      private static Log log = LogFactory.getLog(TurbineUploadService.class);
69  
70      /*** A File Upload object for the actual uploading */
71      protected DiskFileUpload fileUpload = null;
72  
73      /*** Auto Upload yes? */
74      private boolean automatic;
75  
76      /***
77       * Initializes the service.
78       *
79       * This method processes the repository path, to make it relative to the
80       * web application root, if neccessary
81       */
82      public void init()
83              throws InitializationException
84      {
85          Configuration conf = getConfiguration();
86  
87          String repoPath = conf.getString(
88                  UploadService.REPOSITORY_KEY,
89                  UploadService.REPOSITORY_DEFAULT);
90  
91          if (!repoPath.startsWith("/"))
92          {
93              // If our temporary directory is in the application
94              // space, try to create it. If this fails, throw
95              // an exception.
96              String testPath = Turbine.getRealPath(repoPath);
97              File testDir = new File(testPath);
98              if (!testDir.exists())
99              {
100                 if (!testDir.mkdirs())
101                 {
102                     throw new InitializationException(
103                             "Could not create target directory!");
104                 }
105             }
106             repoPath = testPath;
107             conf.setProperty(UploadService.REPOSITORY_KEY, repoPath);
108         }
109 
110         log.debug("Upload Path is now " + repoPath);
111 
112         long sizeMax = conf.getLong(
113                 UploadService.SIZE_MAX_KEY,
114                 UploadService.SIZE_MAX_DEFAULT);
115 
116         log.debug("Max Size " + sizeMax);
117 
118         int sizeThreshold = conf.getInt(
119                 UploadService.SIZE_THRESHOLD_KEY,
120                 UploadService.SIZE_THRESHOLD_DEFAULT);
121 
122         log.debug("Threshold Size " + sizeThreshold);
123 
124         automatic = conf.getBoolean(
125                 UploadService.AUTOMATIC_KEY,
126                 UploadService.AUTOMATIC_DEFAULT);
127 
128         log.debug("Auto Upload " + automatic);
129 
130         fileUpload = new DiskFileUpload();
131         fileUpload.setSizeMax(sizeMax);
132         fileUpload.setSizeThreshold(sizeThreshold);
133         fileUpload.setRepositoryPath(repoPath);
134 
135         setInit(true);
136     }
137 
138     /***
139      * <p> Retrieves the value of <code>size.max</code> property of the
140      * {@link org.apache.turbine.services.upload.UploadService}.
141      *
142      * @return The maximum upload size.
143      */
144     public long getSizeMax()
145     {
146         return fileUpload.getSizeMax();
147     }
148 
149     /***
150      * <p> Retrieves the value of <code>size.threshold</code> property of
151      * {@link org.apache.turbine.services.upload.UploadService}.
152      *
153      * @return The threshold beyond which files are written directly to disk.
154      */
155     public int getSizeThreshold()
156     {
157         return fileUpload.getSizeThreshold();
158     }
159 
160     /***
161      * Retrieves the value of the 'automatic' property of {@link
162      * UploadService}. This reports whether the Parameter parser
163      * should allow "automatic" uploads if it is submitted to
164      * Turbine.
165      *
166      * @return The value of 'automatic' property of {@link
167      * UploadService}.
168      */
169     public boolean getAutomatic()
170     {
171         return automatic;
172     }
173 
174     /***
175      * <p> Retrieves the value of the <code>repository</code> property of
176      * {@link org.apache.turbine.services.upload.UploadService}.
177      *
178      * @return The repository.
179      */
180     public String getRepository()
181     {
182         return fileUpload.getRepositoryPath();
183     }
184 
185     /***
186      * <p> Processes an <a href="http://rf.cx/rfc1867.html">RFC
187      * 1867</a> compliant <code>multipart/form-data</code> stream.
188      *
189      * @param req The servlet request to be parsed.
190      * @param params The ParameterParser instance to insert form
191      * fields into.
192      * @param path The location where the files should be stored.
193      * @exception TurbineException Problems reading/parsing the
194      * request or storing the uploaded file(s).
195      */
196     public void parseRequest(HttpServletRequest req,
197                              ParameterParser params,
198                              String path)
199             throws TurbineException
200     {
201         String contentType = req.getHeader(CONTENT_TYPE);
202         if (!contentType.startsWith(MULTIPART_FORM_DATA))
203         {
204             throw new TurbineException("the request doesn't contain a " +
205                     MULTIPART_FORM_DATA + " stream");
206         }
207         int requestSize = req.getContentLength();
208         if (requestSize == -1)
209         {
210             throw new TurbineException("the request was rejected because " +
211                     "it's size is unknown");
212         }
213         if (requestSize > getSizeMax())
214         {
215             throw new TurbineException("the request was rejected because " +
216                     "it's size exceeds allowed range");
217         }
218 
219         try
220         {
221             List fileList = fileUpload
222                     .parseRequest(req,
223                             getSizeThreshold(),
224                             getSizeMax(),
225                             path);
226 
227             if (fileList != null)
228             {
229                 for (Iterator it = fileList.iterator(); it.hasNext();)
230                 {
231                     FileItem fi = (FileItem) it.next();
232                     if (fi.isFormField())
233                     {
234                         log.debug("Found an simple form field: " + fi.getFieldName() +", adding value " + fi.getString());
235 
236                         String value = null;
237                         try
238                         {
239                             value = fi.getString(params.getCharacterEncoding());
240                         }
241                         catch (UnsupportedEncodingException e)
242                         {
243                             log.error(params.getCharacterEncoding()
244                                     + " encoding is not supported."
245                                     + "Used the default when reading form data.");
246                             value = fi.getString();
247                         }
248                         params.add(fi.getFieldName(), value);
249                     }
250                     else
251                     {
252                         log.debug("Found an uploaded file: " + fi.getFieldName());
253                         log.debug("It has " + fi.getSize() + " Bytes and is " + (fi.isInMemory() ? "" : "not ") + "in Memory");
254                         log.debug("Adding FileItem as " + fi.getFieldName() + " to the params");
255                         params.add(fi.getFieldName(), fi);
256                     }
257                 }
258             }
259         }
260         catch (FileUploadException e)
261         {
262             throw new TurbineException(e);
263         }
264     }
265 }