View Javadoc
1   package com.foxinmy.weixin4j.http;
2   
3   import java.io.Serializable;
4   import java.nio.charset.Charset;
5   import java.nio.charset.UnsupportedCharsetException;
6   import java.util.ArrayList;
7   import java.util.LinkedHashMap;
8   import java.util.List;
9   import java.util.Locale;
10  import java.util.Map;
11  
12  import com.foxinmy.weixin4j.util.CharArrayBuffer;
13  import com.foxinmy.weixin4j.util.Consts;
14  import com.foxinmy.weixin4j.util.NameValue;
15  import com.foxinmy.weixin4j.util.StringUtil;
16  
17  /**
18   * reference of apache pivot
19   * 
20   * @className ContentType
21   * @author jinyu(foxinmy@gmail.com)
22   * @date 2015年5月29日
23   * @since JDK 1.6
24   * @see
25   */
26  public final class ContentType implements Serializable {
27  
28  	private static final long serialVersionUID = 1544245878894784980L;
29  
30  	private final MimeType mimeType;
31  	private final Charset charset;
32  	private final NameValue[] params;
33  	private static final Charset DEFAULT_CHARSET = Consts.UTF_8;
34  
35  	public static final ContentType APPLICATION_JSON;
36  	public static final ContentType APPLICATION_FORM_URLENCODED;
37  	public static final ContentType MULTIPART_FORM_DATA;
38  	public static final ContentType DEFAULT_BINARY;
39  	public static final ContentType DEFAULT_TEXT;
40  
41  	static {
42  		APPLICATION_JSON = new ContentType(MimeType.APPLICATION_JSON);
43  		APPLICATION_FORM_URLENCODED = new ContentType(
44  				MimeType.APPLICATION_FORM_URLENCODED);
45  		MULTIPART_FORM_DATA = new ContentType(MimeType.MULTIPART_FORM_DATA);
46  		DEFAULT_BINARY = new ContentType(MimeType.APPLICATION_OCTET_STREAM);
47  		DEFAULT_TEXT = new ContentType(MimeType.TEXT_PLAIN);
48  	}
49  
50  	ContentType(final MimeType mimeType) {
51  		this(mimeType, DEFAULT_CHARSET);
52  	}
53  
54  	ContentType(final MimeType mimeType, final Charset charset) {
55  		this(mimeType, charset, null);
56  	}
57  
58  	ContentType(final MimeType mimeType, final Charset charset,
59  			final NameValue[] params) {
60  		this.mimeType = mimeType;
61  		this.charset = charset;
62  		this.params = params;
63  	}
64  
65  	public MimeType getMimeType() {
66  		return this.mimeType;
67  	}
68  
69  	public Charset getCharset() {
70  		return this.charset;
71  	}
72  
73  	/**
74  	 * @since 4.3
75  	 */
76  	public String getParameter(final String name) {
77  		if (this.params == null) {
78  			return null;
79  		}
80  		for (final NameValue param : this.params) {
81  			if (param.getName().equalsIgnoreCase(name)) {
82  				return param.getValue();
83  			}
84  		}
85  		return null;
86  	}
87  
88  	/**
89  	 * Generates textual representation of this content type which can be used
90  	 * as the value of a {@code Content-Type} header.
91  	 */
92  	@Override
93  	public String toString() {
94  		final CharArrayBuffer buf = new CharArrayBuffer(64);
95  		buf.append(this.mimeType);
96  		if (this.params != null) {
97  			buf.append("; ");
98  			HeaderValueFormatter.INSTANCE.formatParameters(buf,
99  					this.params, false);
100 		} else if (this.charset != null) {
101 			buf.append("; charset=");
102 			buf.append(this.charset.name());
103 		}
104 		return buf.toString();
105 	}
106 
107 	public static String toString(List<ContentType> contentTypes) {
108 		if (contentTypes == null || contentTypes.isEmpty()) {
109 			return null;
110 		}
111 		StringBuilder buf = new StringBuilder();
112 		for (ContentType contentType : contentTypes) {
113 			buf.append(contentType.toString()).append(",");
114 		}
115 		return buf.delete(buf.length() - 1, buf.length()).toString();
116 	}
117 
118 	private static boolean valid(final String s) {
119 		for (int i = 0; i < s.length(); i++) {
120 			char ch = s.charAt(i);
121 			if (ch == '"' || ch == ',' || ch == ';') {
122 				return false;
123 			}
124 		}
125 		return true;
126 	}
127 
128 	public static ContentType create(final MimeType mimeType,
129 			final Charset charset) {
130 		if (mimeType == null) {
131 			throw new IllegalArgumentException("MIME type may not be null");
132 		}
133 		return new ContentType(mimeType, charset);
134 	}
135 
136 	public static ContentType create(final String mimeType) {
137 		return create(MimeType.valueOf(mimeType), (Charset) null);
138 	}
139 
140 	public static ContentType create(final String mimeType, final String charset)
141 			throws UnsupportedCharsetException {
142 		return create(
143 				mimeType,
144 				(charset != null && charset.length() > 0) ? Charset
145 						.forName(charset) : null);
146 	}
147 
148 	public static ContentType create(final String mimeType,
149 			final Charset charset) {
150 		if (mimeType == null) {
151 			throw new IllegalArgumentException("MIME type may not be null");
152 		}
153 		String type = mimeType.trim().toLowerCase(Locale.US);
154 		if (type.length() == 0) {
155 			throw new IllegalArgumentException("MIME type may not be empty");
156 		}
157 		if (!valid(type)) {
158 			throw new IllegalArgumentException(
159 					"MIME type may not contain reserved characters");
160 		}
161 		return new ContentType(MimeType.valueOf(type), charset);
162 	}
163 
164 	private static ContentType create(final MimeType mimeType,
165 			final NameValue[] params, final boolean strict) {
166 		Charset charset = null;
167 		for (final NameValue param : params) {
168 			if (param.getName().equalsIgnoreCase("charset")) {
169 				final String s = param.getValue();
170 				if (StringUtil.isNotBlank(s)) {
171 					try {
172 						charset = Charset.forName(s);
173 					} catch (final UnsupportedCharsetException ex) {
174 						if (strict) {
175 							throw ex;
176 						}
177 					}
178 				}
179 				break;
180 			}
181 		}
182 		return new ContentType(mimeType, charset, params != null
183 				&& params.length > 0 ? params : null);
184 	}
185 
186 /**
187 	     * Creates a new instance of {@link ContentType} with the given parameters.
188 	     *
189 	     * @param mimeType MIME type. It may not be {@code null} or empty. It may not contain
190 	     *        characters {@code <">, <;>, <,>} reserved by the HTTP specification.
191 	     * @param params parameters.
192 	     * @return content type
193 	     *
194 	     * @since 4.4
195 	     */
196 	public static ContentType create(final String mimeType,
197 			final NameValue... params) throws UnsupportedCharsetException {
198 		final String type = mimeType.toLowerCase(Locale.ROOT);
199 		if (!valid(type)) {
200 			throw new IllegalArgumentException(
201 					"MIME type may not contain reserved characters");
202 		}
203 		return create(MimeType.valueOf(mimeType), params, true);
204 	}
205 
206 	/**
207 	 * Creates a new instance with this MIME type and the given parameters.
208 	 *
209 	 * @param params
210 	 * @return a new instance with this MIME type and the given parameters.
211 	 * @since 4.4
212 	 */
213 	public ContentType withParameters(final NameValue... params)
214 			throws UnsupportedCharsetException {
215 		if (params.length == 0) {
216 			return this;
217 		}
218 		final Map<String, String> paramMap = new LinkedHashMap<String, String>();
219 		if (this.params != null) {
220 			for (final NameValue param : this.params) {
221 				paramMap.put(param.getName(), param.getValue());
222 			}
223 		}
224 		for (final NameValue param : params) {
225 			paramMap.put(param.getName(), param.getValue());
226 		}
227 		final List<NameValue> newParams = new ArrayList<NameValue>(
228 				paramMap.size() + 1);
229 		if (this.charset != null && !paramMap.containsKey("charset")) {
230 			newParams.add(new NameValue("charset", this.charset.name()));
231 		}
232 		for (final Map.Entry<String, String> entry : paramMap.entrySet()) {
233 			newParams.add(new NameValue(entry.getKey(), entry.getValue()));
234 		}
235 		return create(this.getMimeType(),
236 				newParams.toArray(new NameValue[newParams.size()]), true);
237 	}
238 }