##### Coverage Report - org.seasar.cubby.controller.impl.MultipartRequestParser

Classes in this File | Line Coverage | Branch Coverage | Complexity
MultipartRequestParser |
80% | 44/55
81% | 13/16
| 0.0;0

1 |  |
     /*
2 |  |
      * Copyright 2004-2009 the Seasar Foundation and the Others.
3 |  |
      *
4 |  |
      * Licensed under the Apache License, Version 2.0 (the "License");
5 |  |
      * you may not use this file except in compliance with the License.
6 |  |
      * You may obtain a copy of the License at
7 |  |
      *
8 |  |
      *     http://www.apache.org/licenses/LICENSE-2.0
9 |  |
      *
10 |  |
      * Unless required by applicable law or agreed to in writing, software
11 |  |
      * distributed under the License is distributed on an "AS IS" BASIS,
12 |  |
      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 |  |
      * either express or implied. See the License for the specific language
14 |  |
      * governing permissions and limitations under the License.
15 |  |
      */
16 |  |
     package org.seasar.cubby.controller.impl;
17 |  |
18 |  |
     import static org.seasar.cubby.internal.util.LogMessages.format;
19 |  |
20 |  |
     import java.io.IOException;
21 |  |
     import java.io.UnsupportedEncodingException;
22 |  |
     import java.util.ArrayList;
23 |  |
     import java.util.HashMap;
24 |  |
     import java.util.LinkedHashMap;
25 |  |
     import java.util.List;
26 |  |
     import java.util.Map;
27 |  |
     import java.util.Map.Entry;
28 |  |
29 |  |
     import javax.servlet.http.HttpServletRequest;
30 |  |
31 |  |
     import org.apache.commons.fileupload.FileItem;
32 |  |
     import org.apache.commons.fileupload.FileUpload;
33 |  |
     import org.apache.commons.fileupload.FileUploadBase;
34 |  |
     import org.apache.commons.fileupload.FileUploadException;
35 |  |
     import org.apache.commons.fileupload.RequestContext;
36 |  |
     import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
37 |  |
     import org.seasar.cubby.controller.RequestParseException;
38 |  |
     import org.seasar.cubby.controller.RequestParser;
39 |  |
     import org.seasar.cubby.internal.util.StringUtils;
40 |  |
     import org.seasar.cubby.spi.ContainerProvider;
41 |  |
     import org.seasar.cubby.spi.ProviderFactory;
42 |  |
     import org.seasar.cubby.spi.container.Container;
43 |  |
     import org.seasar.cubby.spi.container.LookupException;
44 |  |
45 |  |
     /**
46 |  |
      * マルチパートの要求に対応した解析器です。
47 |  |
      * <p>
48 |  |
      * 要求の解析には <a href="http://commons.apache.org/fileupload/">Commons
49 |  |
      * FileUpload</a> を使用します。
50 |  |
      * </p>
51 |  |
      *
52 |  |
      * @author baba
53 |  |
      * @see <a href="http://commons.apache.org/fileupload/">Commons FileUpload</a>
54 |  |
      */
55 | 4 |
     public class MultipartRequestParser implements RequestParser {
56 |  |
57 |  |
             /**
58 |  |
              * {@inheritDoc}
59 |  |
              * <p>
60 |  |
              * 指定された要求がマルチパートの要求 (contentType が "multipart/" で始まる) であれば、コンテナに登録された
61 |  |
              * {@link FileUpload} と {@link RequestContext} を使用して要求を解析します。
62 |  |
              * <p>
63 |  |
              * 要求パラメータを戻り値の {@link Map} に格納する際には以下のように変換します。
64 |  |
              * <ul>
65 |  |
              * <li>フォームのフィールド
66 |  |
              * <p>
67 |  |
              * 文字列に変換
68 |  |
              * </p>
69 |  |
              * </li>
70 |  |
              * <li>フォームのフィールド以外(アップロードされたファイル)
71 |  |
              * <p>
72 |  |
              * {@link FileItem} に変換
73 |  |
              * </p>
74 |  |
              * </li>
75 |  |
              * </ul>
76 |  |
              * </p>
77 |  |
              * </p>
78 |  |
              *
79 |  |
              * @throws RequestParseException
80 |  |
              *             指定された要求がマルチパートではなかった場合
81 |  |
              * @see FileUpload#parseRequest(RequestContext)
82 |  |
              */
83 |  |
             @SuppressWarnings("unchecked")
84 |  |
             public Map<String, Object[]> getParameterMap(
85 |  |
                             final HttpServletRequest request) {
86 | 3 |
                     final Map<String, Object[]> parameterMap = new HashMap<String, Object[]>(
87 |  |
                                     request.getParameterMap());
88 | 3 |
                     final Container container = ProviderFactory
89 |  |
                                     .get(ContainerProvider.class).getContainer();
90 |  |
                     try {
91 | 3 |
                             final RequestContext requestContext = container
92 |  |
                                             .lookup(RequestContext.class);
93 | 3 |
                             final FileUpload fileUpload = container.lookup(FileUpload.class);
94 | 3 |
                             final Map<String, Object[]> multipartParameterMap = getMultipartParameterMap(
95 |  |
                                             fileUpload, requestContext);
96 | 2 |
                             parameterMap.putAll(multipartParameterMap);
97 | 2 |
                             return parameterMap;
98 | 0 |
                     } catch (final LookupException e) {
99 | 0 |
                             throw new IllegalStateException(e);
100 |  |
                     }
101 |  |
             }
102 |  |
103 |  |
             @SuppressWarnings("unchecked")
104 |  |
             Map<String, Object[]> getMultipartParameterMap(final FileUpload fileUpload,
105 |  |
                             final RequestContext requestContext) {
106 |  |
                     try {
107 | 3 |
                             final String encoding = requestContext.getCharacterEncoding();
108 | 3 |
                             fileUpload.setHeaderEncoding(encoding);
109 | 3 |
                             final List<FileItem> items = fileUpload
110 |  |
                                             .parseRequest(requestContext);
111 |  |
112 |  |
                             // Fieldごとにパラメータを集める
113 | 2 |
                             final Map<String, Object[]> parameterMap = toParameterMap(encoding,
114 |  |
                                             items);
115 |  |
116 | 2 |
                             return parameterMap;
117 | 1 |
                     } catch (final FileUploadException e) {
118 |  |
                             final String messageCode;
119 |  |
                             final Object[] args;
120 | 1 |
                             if (e instanceof SizeLimitExceededException) {
121 | 0 |
                                     final SizeLimitExceededException sle = (SizeLimitExceededException) e;
122 | 0 |
                                     messageCode = "ECUB0202";
123 | 0 |
                                     args = new Object[] { sle.getPermittedSize(),
124 |  |
                                                     sle.getActualSize() };
125 | 0 |
                             } else {
126 | 1 |
                                     messageCode = "ECUB0201";
127 | 1 |
                                     args = new Object[] { e };
128 |  |
                             }
129 | 1 |
                             throw new RequestParseException(format(messageCode, args), e);
130 | 0 |
                     } catch (final IOException e) {
131 | 0 |
                             throw new RequestParseException(e);
132 |  |
                     }
133 |  |
             }
134 |  |
135 |  |
             Map<String, Object[]> toParameterMap(final String encoding,
136 |  |
                             final List<FileItem> items) throws UnsupportedEncodingException {
137 | 2 |
                     final Map<String, List<Object>> valueListParameterMap = new LinkedHashMap<String, List<Object>>();
138 | 2 |
                     for (final FileItem item : items) {
139 |  |
                             final Object value;
140 | 4 |
                             if (item.isFormField()) {
141 | 3 |
                                     value = item.getString(encoding);
142 |  |
                             } else {
143 | 1 |
                                     if (StringUtils.isEmpty(item.getName()) || item.getSize() == 0) {
144 |  |
                                             // ファイル名無し、あるいは０バイトのファイル
145 | 0 |
                                             value = null;
146 |  |
                                     } else {
147 | 1 |
                                             value = item;
148 |  |
                                     }
149 |  |
                             }
150 |  |
                             final List<Object> values;
151 | 4 |
                             if (valueListParameterMap.containsKey(item.getFieldName())) {
152 | 1 |
                                     values = valueListParameterMap.get(item.getFieldName());
153 |  |
                             } else {
154 | 3 |
                                     values = new ArrayList<Object>();
155 | 3 |
                                     valueListParameterMap.put(item.getFieldName(), values);
156 |  |
                             }
157 | 4 |
                             values.add(value);
158 | 4 |
                     }
159 |  |
160 | 2 |
                     final Map<String, Object[]> parameterMap = fromValueListMapToValueArrayMap(valueListParameterMap);
161 | 2 |
                     return parameterMap;
162 |  |
             }
163 |  |
164 |  |
             Map<String, Object[]> fromValueListMapToValueArrayMap(
165 |  |
                             final Map<String, List<Object>> valueListMap) {
166 |  |
                     // 配列でパラメータMapを構築
167 | 2 |
                     final Map<String, Object[]> parameterMap = new HashMap<String, Object[]>();
168 | 2 |
                     for (final Entry<String, List<Object>> entry : valueListMap.entrySet()) {
169 | 3 |
                             final List<Object> values = entry.getValue();
170 |  |
                             final Object[] valueArray;
171 | 3 |
                             if (values.get(0) instanceof String) {
172 | 2 |
                                     valueArray = new String[values.size()];
173 |  |
                             } else {
174 | 1 |
                                     valueArray = new FileItem[values.size()];
175 |  |
                             }
176 | 3 |
                             parameterMap.put(entry.getKey(), values.toArray(valueArray));
177 | 3 |
                     }
178 | 2 |
                     return parameterMap;
179 |  |
             }
180 |  |
181 |  |
             /**
182 |  |
              * {@inheritDoc}
183 |  |
              * <p>
184 |  |
              * 指定された要求がマルチパートの要求 (contentType が "multipart/" で始まる) の場合に
185 |  |
              * <code>true</code> を返します。
186 |  |
              * </p>
187 |  |
              *
188 |  |
              * @see FileUpload#isMultipartContent(RequestContext)
189 |  |
              */
190 |  |
             public boolean isParsable(final HttpServletRequest request) {
191 | 3 |
                     final Container container = ProviderFactory
192 |  |
                                     .get(ContainerProvider.class).getContainer();
193 |  |
                     try {
194 | 3 |
                             final RequestContext requestContext = container
195 |  |
                                             .lookup(RequestContext.class);
196 | 3 |
                             return FileUploadBase.isMultipartContent(requestContext);
197 | 0 |
                     } catch (final LookupException e) {
198 | 0 |
                             return false;
199 |  |
                     }
200 |  |
             }
201 |  |
202 |  |
     }