View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package com.foxinmy.weixin4j.http.apache.mime;
29  
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.io.OutputStream;
33  import java.nio.charset.Charset;
34  import java.util.Random;
35  
36  import com.foxinmy.weixin4j.http.ContentType;
37  import com.foxinmy.weixin4j.http.apache.content.ContentBody;
38  import com.foxinmy.weixin4j.http.entity.HttpEntity;
39  
40  /**
41   * Multipart/form coded HTTP entity consisting of multiple body parts.
42   *
43   * @since 4.0
44   *
45   */
46  public class MultipartEntity implements HttpEntity {
47  
48      /**
49       * The pool of ASCII chars to be used for generating a multipart boundary.
50       */
51      private final static char[] MULTIPART_CHARS =
52          "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
53              .toCharArray();
54  
55      private final MultipartEntityBuilder builder;
56      private volatile MultipartFormEntity entity;
57  
58      /**
59       * Creates an instance using the specified parameters
60       * @param mode the mode to use, may be {@code null}, in which case {@link HttpMultipartMode#STRICT} is used
61       * @param boundary the boundary string, may be {@code null}, in which case {@link #generateBoundary()} is invoked to create the string
62       * @param charset the character set to use, may be {@code null}, in which case {@link MIME#DEFAULT_CHARSET} - i.e. US-ASCII - is used.
63       */
64      public MultipartEntity(
65              final HttpMultipartMode mode,
66              final String boundary,
67              final Charset charset) {
68          super();
69          this.builder = new MultipartEntityBuilder()
70                  .setMode(mode)
71                  .setCharset(charset != null ? charset : MIME.DEFAULT_CHARSET)
72                  .setBoundary(boundary);
73          this.entity = null;
74      }
75  
76      /**
77       * Creates an instance using the specified {@link HttpMultipartMode} mode.
78       * Boundary and charset are set to {@code null}.
79       * @param mode the desired mode
80       */
81      public MultipartEntity(final HttpMultipartMode mode) {
82          this(mode, null, null);
83      }
84  
85      /**
86       * Creates an instance using mode {@link HttpMultipartMode#STRICT}
87       */
88      public MultipartEntity() {
89          this(HttpMultipartMode.STRICT, null, null);
90      }
91  
92      protected String generateContentType(
93              final String boundary,
94              final Charset charset) {
95          final StringBuilder buffer = new StringBuilder();
96          buffer.append("multipart/form-data; boundary=");
97          buffer.append(boundary);
98          if (charset != null) {
99              buffer.append("; charset=");
100             buffer.append(charset.name());
101         }
102         return buffer.toString();
103     }
104 
105     protected String generateBoundary() {
106         final StringBuilder buffer = new StringBuilder();
107         final Random rand = new Random();
108         final int count = rand.nextInt(11) + 30; // a random size from 30 to 40
109         for (int i = 0; i < count; i++) {
110             buffer.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
111         }
112         return buffer.toString();
113     }
114 
115     private MultipartFormEntity getEntity() {
116         if (this.entity == null) {
117             this.entity = this.builder.buildEntity();
118         }
119         return this.entity;
120     }
121 
122     public void addPart(final FormBodyPart bodyPart) {
123         this.builder.addPart(bodyPart);
124         this.entity = null;
125     }
126 
127     public void addPart(final String name, final ContentBody contentBody) {
128         addPart(new FormBodyPart(name, contentBody));
129     }
130 
131     public boolean isRepeatable() {
132         return getEntity().isRepeatable();
133     }
134 
135     public boolean isChunked() {
136         return getEntity().isChunked();
137     }
138 
139     public boolean isStreaming() {
140         return getEntity().isStreaming();
141     }
142 
143     @Override
144     public long getContentLength() {
145         return getEntity().getContentLength();
146     }
147 
148     @Override
149     public ContentType getContentType() {
150         return getEntity().getContentType();
151     }
152 
153     @Override
154     public InputStream getContent() throws IOException, UnsupportedOperationException {
155         throw new UnsupportedOperationException(
156                     "Multipart form entity does not implement #getContent()");
157     }
158 
159     @Override
160     public void writeTo(final OutputStream outstream) throws IOException {
161         getEntity().writeTo(outstream);
162     }
163 }