001    // Copyright 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.multipart;
016    
017    import java.io.UnsupportedEncodingException;
018    import java.util.HashMap;
019    import java.util.Iterator;
020    import java.util.List;
021    import java.util.Map;
022    
023    import javax.servlet.http.HttpServletRequest;
024    
025    import org.apache.commons.fileupload.DiskFileUpload;
026    import org.apache.commons.fileupload.FileItem;
027    import org.apache.commons.fileupload.FileUploadException;
028    import org.apache.hivemind.ApplicationRuntimeException;
029    import org.apache.tapestry.request.IUploadFile;
030    
031    /**
032     * Implementation of {@link org.apache.tapestry.multipart.MultipartDecoder}that is based on <a
033     * href="http://jakarta.apache.org/commons/fileupload/">Jakarta FileUpload </a>.
034     * 
035     * @author Howard M. Lewis Ship
036     * @author Joe Panico
037     * @since 4.0
038     */
039    public class MultipartDecoderImpl implements MultipartDecoder
040    {
041        /**
042         * Map of UploadPart (which implements IUploadFile), keyed on parameter name.
043         */
044    
045        private Map _uploadParts = new HashMap();
046    
047        /**
048         * Map of ValuePart, keyed on parameter name.
049         */
050        private Map _valueParts = new HashMap();
051    
052        private int _maxSize = 10000000;
053    
054        private int _thresholdSize = 1024;
055    
056        private String _repositoryPath = System.getProperty("java.io.tmpdir");
057    
058        private String _encoding;
059    
060        public HttpServletRequest decode(HttpServletRequest request)
061        {
062            _encoding = request.getCharacterEncoding();
063    
064            DiskFileUpload upload = createUpload(request);
065    
066            try
067            {
068                List fileItems = upload
069                        .parseRequest(request, _thresholdSize, _maxSize, _repositoryPath);
070    
071                processFileItems(fileItems);
072            }
073            catch (FileUploadException ex)
074            {
075                throw new ApplicationRuntimeException(MultipartMessages.unableToDecode(ex), ex);
076            }
077    
078            Map parameterMap = buildParameterMap();
079    
080            return new UploadFormParametersWrapper(request, parameterMap);
081        }
082    
083        private Map buildParameterMap()
084        {
085            Map result = new HashMap();
086    
087            Iterator i = _valueParts.entrySet().iterator();
088            while (i.hasNext())
089            {
090                Map.Entry e = (Map.Entry) i.next();
091    
092                String name = (String) e.getKey();
093                ValuePart part = (ValuePart) e.getValue();
094    
095                result.put(name, part.getValues());
096            }
097    
098            return result;
099        }
100    
101        private void processFileItems(List parts)
102        {
103            if (parts == null)
104                return;
105    
106            Iterator i = parts.iterator();
107    
108            while (i.hasNext())
109            {
110                FileItem item = (FileItem) i.next();
111    
112                processFileItem(item);
113            }
114        }
115    
116        private void processFileItem(FileItem item)
117        {
118            if (item.isFormField())
119            {
120                processFormFieldItem(item);
121                return;
122            }
123    
124            processUploadFileItem(item);
125        }
126    
127        private void processUploadFileItem(FileItem item)
128        {
129            String name = item.getFieldName();
130    
131            UploadPart part = new UploadPart(item);
132    
133            _uploadParts.put(name, part);
134        }
135    
136        void processFormFieldItem(FileItem item)
137        {
138            String name = item.getFieldName();
139    
140            String value = extractFileItemValue(item);
141    
142            ValuePart part = (ValuePart) _valueParts.get(name);
143    
144            if (part == null)
145                _valueParts.put(name, new ValuePart(value));
146            else
147                part.add(value);
148        }
149    
150        private String extractFileItemValue(FileItem item)
151        {
152            try
153            {
154                return (_encoding == null) ? item.getString() : item.getString(_encoding);
155            }
156            catch (UnsupportedEncodingException ex)
157            {
158                throw new ApplicationRuntimeException(MultipartMessages.unsupportedEncoding(
159                        _encoding,
160                        ex), ex);
161            }
162        }
163    
164        protected DiskFileUpload createUpload(HttpServletRequest request)
165        {
166            DiskFileUpload upload = new DiskFileUpload();
167    
168            if (_encoding != null)
169                upload.setHeaderEncoding(_encoding);
170    
171            return upload;
172        }
173    
174        public IUploadFile getFileUpload(String parameterName)
175        {
176            return (IUploadFile) _uploadParts.get(parameterName);
177        }
178    
179        public void cleanup()
180        {
181            Iterator i = _uploadParts.values().iterator();
182    
183            while (i.hasNext())
184            {
185                UploadPart part = (UploadPart) i.next();
186    
187                part.cleanup();
188            }
189        }
190    
191    }