1 package org.apache.turbine.services.upload;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
94
95
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 }