001 package org.apache.fulcrum.upload; 002 003 004 /* 005 * Licensed to the Apache Software Foundation (ASF) under one 006 * or more contributor license agreements. See the NOTICE file 007 * distributed with this work for additional information 008 * regarding copyright ownership. The ASF licenses this file 009 * to you under the Apache License, Version 2.0 (the 010 * "License"); you may not use this file except in compliance 011 * with the License. You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, 016 * software distributed under the License is distributed on an 017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 018 * KIND, either express or implied. See the License for the 019 * specific language governing permissions and limitations 020 * under the License. 021 */ 022 023 024 import java.io.File; 025 import java.util.List; 026 027 import javax.servlet.http.HttpServletRequest; 028 029 import org.apache.avalon.framework.activity.Initializable; 030 import org.apache.avalon.framework.configuration.Configurable; 031 import org.apache.avalon.framework.configuration.Configuration; 032 import org.apache.avalon.framework.context.Context; 033 import org.apache.avalon.framework.context.ContextException; 034 import org.apache.avalon.framework.context.Contextualizable; 035 import org.apache.avalon.framework.logger.AbstractLogEnabled; 036 import org.apache.avalon.framework.service.ServiceException; 037 import org.apache.commons.fileupload.FileUploadException; 038 import org.apache.commons.fileupload.disk.DiskFileItemFactory; 039 import org.apache.commons.fileupload.servlet.ServletFileUpload; 040 041 /** 042 * <p> This class is an implementation of {@link UploadService}. 043 * 044 * <p> Files will be stored in temporary disk storage on in memory, 045 * depending on request size, and will be available from the {@link 046 * org.apache.fulcrum.util.parser.ParameterParser} as {@link 047 * org.apache.fulcrum.upload.FileItem}s. 048 * 049 * <p>This implementation of {@link UploadService} handles multiple 050 * files per single html widget, sent using multipar/mixed encoding 051 * type, as specified by RFC 1867. Use {@link 052 * org.apache.fulcrum.util.parser.ParameterParser#getFileItems(String)} to 053 * acquire an array of {@link 054 * org.apache.fulcrum.upload.FileItem}s associated with given 055 * html widget. 056 * 057 * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a> 058 * @author <a href="mailto:dlr@collab.net">Daniel Rall</a> 059 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> 060 * @version $Id: DefaultUploadService.java 732085 2009-01-06 19:58:22Z tv $ 061 */ 062 public class DefaultUploadService 063 extends AbstractLogEnabled 064 implements UploadService, Initializable, Configurable, Contextualizable 065 { 066 /** A File Item Factory object for the actual uploading */ 067 private DiskFileItemFactory itemFactory; 068 069 private int sizeThreshold; 070 private int sizeMax; 071 072 private String repositoryPath; 073 private String headerEncoding; 074 075 /** 076 * The application root 077 */ 078 private String applicationRoot; 079 080 /** 081 * The maximum allowed upload size 082 */ 083 public long getSizeMax() 084 { 085 return sizeMax; 086 } 087 088 /** 089 * The threshold beyond which files are written directly to disk. 090 */ 091 public long getSizeThreshold() 092 { 093 return itemFactory.getSizeThreshold(); 094 } 095 096 /** 097 * The location used to temporarily store files that are larger 098 * than the size threshold. 099 */ 100 public String getRepository() 101 { 102 return itemFactory.getRepository().getAbsolutePath(); 103 } 104 105 /** 106 * @return Returns the headerEncoding. 107 */ 108 public String getHeaderEncoding() 109 { 110 return headerEncoding; 111 } 112 113 /** 114 * <p>Parses a <a href="http://rf.cx/rfc1867.html">RFC 1867</a> 115 * compliant <code>multipart/form-data</code> stream.</p> 116 * 117 * @param req The servlet request to be parsed. 118 * @exception ServiceException Problems reading/parsing the 119 * request or storing the uploaded file(s). 120 */ 121 public List parseRequest(HttpServletRequest req) 122 throws ServiceException 123 { 124 return parseRequest(req, this.sizeMax, this.itemFactory); 125 } 126 127 /** 128 * <p>Parses a <a href="http://rf.cx/rfc1867.html">RFC 1867</a> 129 * compliant <code>multipart/form-data</code> stream.</p> 130 * 131 * @param req The servlet request to be parsed. 132 * @param path The location where the files should be stored. 133 * @exception ServiceException Problems reading/parsing the 134 * request or storing the uploaded file(s). 135 */ 136 public List parseRequest(HttpServletRequest req, String path) 137 throws ServiceException 138 { 139 return parseRequest(req, this.sizeThreshold, this.sizeMax, path); 140 } 141 142 /** 143 * <p>Parses a <a href="http://rf.cx/rfc1867.html">RFC 1867</a> 144 * compliant <code>multipart/form-data</code> stream.</p> 145 * 146 * @param req The servlet request to be parsed. 147 * @param sizeThreshold the max size in bytes to be stored in memory 148 * @param sizeMax the maximum allowed upload size in bytes 149 * @param path The location where the files should be stored. 150 * @exception ServiceException Problems reading/parsing the 151 * request or storing the uploaded file(s). 152 */ 153 public List parseRequest(HttpServletRequest req, int sizeThreshold, 154 int sizeMax, String path) 155 throws ServiceException 156 { 157 return parseRequest(req, sizeMax, new DiskFileItemFactory(sizeThreshold, new File(path))); 158 } 159 160 /** 161 * <p>Parses a <a href="http://rf.cx/rfc1867.html">RFC 1867</a> 162 * compliant <code>multipart/form-data</code> stream.</p> 163 * 164 * @param req The servlet request to be parsed. 165 * @param sizeMax the maximum allowed upload size in bytes 166 * @param factory the file item factory to use 167 * 168 * @exception ServiceException Problems reading/parsing the 169 * request or storing the uploaded file(s). 170 */ 171 private List parseRequest(HttpServletRequest req, int sizeMax, DiskFileItemFactory factory) 172 throws ServiceException 173 { 174 try 175 { 176 ServletFileUpload fileUpload = new ServletFileUpload(factory); 177 fileUpload.setSizeMax(sizeMax); 178 fileUpload.setHeaderEncoding(headerEncoding); 179 return fileUpload.parseRequest(req); 180 } 181 catch (FileUploadException e) 182 { 183 throw new ServiceException(UploadService.ROLE, e.getMessage(), e); 184 } 185 } 186 187 /** 188 * @see org.apache.fulcrum.ServiceBroker#getRealPath(String) 189 */ 190 private String getRealPath(String path) 191 { 192 String absolutePath = null; 193 if (applicationRoot == null) 194 { 195 absolutePath = new File(path).getAbsolutePath(); 196 } 197 else 198 { 199 absolutePath = new File(applicationRoot, path).getAbsolutePath(); 200 } 201 202 return absolutePath; 203 } 204 205 // ---------------- Avalon Lifecycle Methods --------------------- 206 /** 207 * Avalon component lifecycle method 208 */ 209 public void configure(Configuration conf) 210 { 211 repositoryPath = conf.getAttribute( 212 UploadService.REPOSITORY_KEY, 213 UploadService.REPOSITORY_DEFAULT); 214 215 headerEncoding = conf.getAttribute( 216 UploadService.HEADER_ENCODING_KEY, 217 UploadService.HEADER_ENCODING_DEFAULT); 218 219 sizeMax = conf.getAttributeAsInteger( 220 UploadService.SIZE_MAX_KEY, 221 UploadService.SIZE_MAX_DEFAULT); 222 223 sizeThreshold = conf.getAttributeAsInteger( 224 UploadService.SIZE_THRESHOLD_KEY, 225 UploadService.SIZE_THRESHOLD_DEFAULT); 226 } 227 228 /** 229 * Initializes the service. 230 * 231 * This method processes the repository path, to make it relative to the 232 * web application root, if necessary 233 */ 234 public void initialize() throws Exception 235 { 236 // test for the existence of the path within the webapp directory. 237 // if it does not exist, assume the path was to be used as is. 238 String testPath = getRealPath(repositoryPath); 239 File testDir = new File(testPath); 240 if ( testDir.exists() ) 241 { 242 repositoryPath = testPath; 243 } 244 245 getLogger().debug( 246 "Upload Service: REPOSITORY_KEY => " + repositoryPath); 247 248 itemFactory = new DiskFileItemFactory(sizeThreshold, new File(repositoryPath)); 249 } 250 251 public void contextualize(Context context) throws ContextException 252 { 253 this.applicationRoot = context.get( "urn:avalon:home" ).toString(); 254 } 255 }