View Javadoc

    1   /*
    2    * $Id: JakartaMultiPartRequest.java 484695 2006-12-08 18:38:58Z mrdon $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
    10   * with the License.  You may obtain a copy of the License at
    11   *
    12   *  http://www.apache.org/licenses/LICENSE-2.0
    13   *
    14   * Unless required by applicable law or agreed to in writing,
    15   * software distributed under the License is distributed on an
    16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    17   * KIND, either express or implied.  See the License for the
    18   * specific language governing permissions and limitations
    19   * under the License.
    20   */
    21  package org.apache.struts2.dispatcher.multipart;
    22
    23  import java.io.File;
    24  import java.io.IOException;
    25  import java.io.InputStream;
    26  import java.util.ArrayList;
    27  import java.util.Collections;
    28  import java.util.Enumeration;
    29  import java.util.HashMap;
    30  import java.util.List;
    31  import java.util.Map;
    32
    33  import javax.servlet.http.HttpServletRequest;
    34
    35  import org.apache.commons.fileupload.FileItem;
    36  import org.apache.commons.fileupload.FileUploadException;
    37  import org.apache.commons.fileupload.RequestContext;
    38  import org.apache.commons.fileupload.disk.DiskFileItem;
    39  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    40  import org.apache.commons.fileupload.servlet.ServletFileUpload;
    41  import org.apache.commons.logging.Log;
    42  import org.apache.commons.logging.LogFactory;
    43  import org.apache.struts2.StrutsConstants;
    44
    45  import com.opensymphony.xwork2.inject.Inject;
    46
    47  /***
    48   * Multipart form data request adapter for Jakarta Commons Fileupload package.
    49   *
    50   */
    51  public class JakartaMultiPartRequest implements MultiPartRequest {
    52
    53      static final Log log = LogFactory.getLog(MultiPartRequest.class);
    54
    55      // maps parameter name -> List of FileItem objects
    56      private Map<String,List<FileItem>> files = new HashMap<String,List<FileItem>>();
    57      // maps parameter name -> List of param values
    58      private Map<String,List<String>> params = new HashMap<String,List<String>>();
    59      // any errors while processing this request
    60      private List<String> errors = new ArrayList<String>();
    61
    62      private long maxSize;
    63
    64      @Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
    65      public void setMaxSize(String maxSize) {
    66          this.maxSize = Long.parseLong(maxSize);
    67      }
    68
    69      /***
    70       * Creates a new request wrapper to handle multi-part data using methods adapted from Jason Pell's
    71       * multipart classes (see class description).
    72       *
    73       * @param saveDir        the directory to save off the file
    74       * @param servletRequest the request containing the multipart
    75       * @throws java.io.IOException  is thrown if encoding fails.
    76       */
    77      public void parse(HttpServletRequest servletRequest, String saveDir)
    78              throws IOException {
    79          DiskFileItemFactory fac = new DiskFileItemFactory();
    80          // Make sure that the data is written to file
    81          fac.setSizeThreshold(0);
    82          if (saveDir != null) {
    83              fac.setRepository(new File(saveDir));
    84          }
    85
    86          // Parse the request
    87          try {
    88              ServletFileUpload upload = new ServletFileUpload(fac);
    89              upload.setSizeMax(maxSize);
    90              List items = upload.parseRequest(createRequestContext(servletRequest));
    91
    92              for (Object item1 : items) {
    93                  FileItem item = (FileItem) item1;
    94                  if (log.isDebugEnabled()) log.debug("Found item " + item.getFieldName());
    95                  if (item.isFormField()) {
    96                      log.debug("Item is a normal form field");
    97                      List<String> values;
    98                      if (params.get(item.getFieldName()) != null) {
    99                          values = params.get(item.getFieldName());
    100                     } else {
    101                         values = new ArrayList<String>();
    102                     }
    103
    104                     // note: see http://jira.opensymphony.com/browse/WW-633
    105                     // basically, in some cases the charset may be null, so
    106                     // we're just going to try to "other" method (no idea if this
    107                     // will work)
    108                     String charset = servletRequest.getCharacterEncoding();
    109                     if (charset != null) {
    110                         values.add(item.getString(charset));
    111                     } else {
    112                         values.add(item.getString());
    113                     }
    114                     params.put(item.getFieldName(), values);
    115                 } else {
    116                     log.debug("Item is a file upload");
    117
    118                     List<FileItem> values;
    119                     if (files.get(item.getFieldName()) != null) {
    120                         values = files.get(item.getFieldName());
    121                     } else {
    122                         values = new ArrayList<FileItem>();
    123                     }
    124
    125                     values.add(item);
    126                     files.put(item.getFieldName(), values);
    127                 }
    128             }
    129         } catch (FileUploadException e) {
    130             log.error(e);
    131             errors.add(e.getMessage());
    132         }
    133     }
    134
    135     /* (non-Javadoc)
    136      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileParameterNames()
    137      */
    138     public Enumeration<String> getFileParameterNames() {
    139         return Collections.enumeration(files.keySet());
    140     }
    141
    142     /* (non-Javadoc)
    143      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getContentType(java.lang.String)
    144      */
    145     public String[] getContentType(String fieldName) {
    146         List items = (List) files.get(fieldName);
    147
    148         if (items == null) {
    149             return null;
    150         }
    151
    152         List<String> contentTypes = new ArrayList<String>(items.size());
    153         for (int i = 0; i < items.size(); i++) {
    154             FileItem fileItem = (FileItem) items.get(i);
    155             contentTypes.add(fileItem.getContentType());
    156         }
    157
    158         return (String[]) contentTypes.toArray(new String[contentTypes.size()]);
    159     }
    160
    161     /* (non-Javadoc)
    162      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFile(java.lang.String)
    163      */
    164     public File[] getFile(String fieldName) {
    165         List items = (List) files.get(fieldName);
    166
    167         if (items == null) {
    168             return null;
    169         }
    170
    171         List<File> fileList = new ArrayList<File>(items.size());
    172         for (int i = 0; i < items.size(); i++) {
    173             DiskFileItem fileItem = (DiskFileItem) items.get(i);
    174             fileList.add(fileItem.getStoreLocation());
    175         }
    176
    177         return (File[]) fileList.toArray(new File[fileList.size()]);
    178     }
    179
    180     /* (non-Javadoc)
    181      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFileNames(java.lang.String)
    182      */
    183     public String[] getFileNames(String fieldName) {
    184         List<FileItem> items = files.get(fieldName);
    185
    186         if (items == null) {
    187             return null;
    188         }
    189
    190         List<String> fileNames = new ArrayList<String>(items.size());
    191         for (int i = 0; i < items.size(); i++) {
    192             DiskFileItem fileItem = (DiskFileItem) items.get(i);
    193             fileNames.add(getCanonicalName(fileItem.getName()));
    194         }
    195
    196         return (String[]) fileNames.toArray(new String[fileNames.size()]);
    197     }
    198
    199     /* (non-Javadoc)
    200      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFilesystemName(java.lang.String)
    201      */
    202     public String[] getFilesystemName(String fieldName) {
    203         List items = (List) files.get(fieldName);
    204
    205         if (items == null) {
    206             return null;
    207         }
    208
    209         List<String> fileNames = new ArrayList<String>(items.size());
    210         for (int i = 0; i < items.size(); i++) {
    211             DiskFileItem fileItem = (DiskFileItem) items.get(i);
    212             fileNames.add(fileItem.getStoreLocation().getName());
    213         }
    214
    215         return (String[]) fileNames.toArray(new String[fileNames.size()]);
    216     }
    217
    218     /* (non-Javadoc)
    219      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameter(java.lang.String)
    220      */
    221     public String getParameter(String name) {
    222         List v = (List) params.get(name);
    223         if (v != null && v.size() > 0) {
    224             return (String) v.get(0);
    225         }
    226
    227         return null;
    228     }
    229
    230     /* (non-Javadoc)
    231      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterNames()
    232      */
    233     public Enumeration<String> getParameterNames() {
    234         return Collections.enumeration(params.keySet());
    235     }
    236
    237     /* (non-Javadoc)
    238      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getParameterValues(java.lang.String)
    239      */
    240     public String[] getParameterValues(String name) {
    241         List<String> v = params.get(name);
    242         if (v != null && v.size() > 0) {
    243             return (String[]) v.toArray(new String[v.size()]);
    244         }
    245
    246         return null;
    247     }
    248
    249     /* (non-Javadoc)
    250      * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getErrors()
    251      */
    252     public List getErrors() {
    253         return errors;
    254     }
    255
    256     /***
    257      * Returns the canonical name of the given file.
    258      *
    259      * @param filename  the given file
    260      * @return the canonical name of the given file
    261      */
    262     private String getCanonicalName(String filename) {
    263         int forwardSlash = filename.lastIndexOf("/");
    264         int backwardSlash = filename.lastIndexOf("//");
    265         if (forwardSlash != -1 && forwardSlash > backwardSlash) {
    266             filename = filename.substring(forwardSlash + 1, filename.length());
    267         } else if (backwardSlash != -1 && backwardSlash >= forwardSlash) {
    268             filename = filename.substring(backwardSlash + 1, filename.length());
    269         }
    270
    271         return filename;
    272     }
    273
    274     /***
    275      * Creates a RequestContext needed by Jakarta Commons Upload.
    276      *
    277      * @param req  the request.
    278      * @return a new request context.
    279      */
    280     private RequestContext createRequestContext(final HttpServletRequest req) {
    281         return new RequestContext() {
    282             public String getCharacterEncoding() {
    283                 return req.getCharacterEncoding();
    284             }
    285
    286             public String getContentType() {
    287                 return req.getContentType();
    288             }
    289
    290             public int getContentLength() {
    291                 return req.getContentLength();
    292             }
    293
    294             public InputStream getInputStream() throws IOException {
    295                 return req.getInputStream();
    296             }
    297         };
    298     }
    299
    300 }