Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
CodecSupport |
|
| 4.133333333333334;4.133 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one | |
3 | * or more contributor license agreements. See the NOTICE file | |
4 | * distributed with this work for additional information | |
5 | * regarding copyright ownership. The ASF licenses this file | |
6 | * to you under the Apache License, Version 2.0 (the | |
7 | * "License"); you may not use this file except in compliance | |
8 | * with the License. You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | */ | |
19 | package org.apache.shiro.codec; | |
20 | ||
21 | import org.apache.shiro.util.ByteSource; | |
22 | ||
23 | import java.io.*; | |
24 | ||
25 | /** | |
26 | * Base abstract class that provides useful encoding and decoding operations, especially for character data. | |
27 | * | |
28 | * @since 0.9 | |
29 | */ | |
30 | 237 | public abstract class CodecSupport { |
31 | ||
32 | /** | |
33 | * Shiro's default preferred character encoding, equal to <b><code>UTF-8</code></b>. | |
34 | */ | |
35 | public static final String PREFERRED_ENCODING = "UTF-8"; | |
36 | ||
37 | /** | |
38 | * Converts the specified character array to a byte array using the Shiro's preferred encoding (UTF-8). | |
39 | * <p/> | |
40 | * This is a convenience method equivalent to calling the {@link #toBytes(String,String)} method with a | |
41 | * a wrapping String and {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}, i.e. | |
42 | * <p/> | |
43 | * <code>toBytes( new String(chars), {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING} );</code> | |
44 | * | |
45 | * @param chars the character array to be converted to a byte array. | |
46 | * @return the byte array of the UTF-8 encoded character array. | |
47 | */ | |
48 | public static byte[] toBytes(char[] chars) { | |
49 | 39 | return toBytes(new String(chars), PREFERRED_ENCODING); |
50 | } | |
51 | ||
52 | /** | |
53 | * Converts the specified character array into a byte array using the specified character encoding. | |
54 | * <p/> | |
55 | * This is a convenience method equivalent to calling the {@link #toBytes(String,String)} method with a | |
56 | * a wrapping String and the specified encoding, i.e. | |
57 | * <p/> | |
58 | * <code>toBytes( new String(chars), encoding );</code> | |
59 | * | |
60 | * @param chars the character array to be converted to a byte array | |
61 | * @param encoding the character encoding to use to when converting to bytes. | |
62 | * @return the bytes of the specified character array under the specified encoding. | |
63 | * @throws CodecException if the JVM does not support the specified encoding. | |
64 | */ | |
65 | public static byte[] toBytes(char[] chars, String encoding) throws CodecException { | |
66 | 0 | return toBytes(new String(chars), encoding); |
67 | } | |
68 | ||
69 | /** | |
70 | * Converts the specified source argument to a byte array with Shiro's | |
71 | * {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}. | |
72 | * | |
73 | * @param source the string to convert to a byte array. | |
74 | * @return the bytes representing the specified string under the {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}. | |
75 | * @see #toBytes(String, String) | |
76 | */ | |
77 | public static byte[] toBytes(String source) { | |
78 | 118 | return toBytes(source, PREFERRED_ENCODING); |
79 | } | |
80 | ||
81 | /** | |
82 | * Converts the specified source to a byte array via the specified encoding, throwing a | |
83 | * {@link CodecException CodecException} if the encoding fails. | |
84 | * | |
85 | * @param source the source string to convert to a byte array. | |
86 | * @param encoding the encoding to use to use. | |
87 | * @return the byte array of the specified source with the given encoding. | |
88 | * @throws CodecException if the JVM does not support the specified encoding. | |
89 | */ | |
90 | public static byte[] toBytes(String source, String encoding) throws CodecException { | |
91 | try { | |
92 | 157 | return source.getBytes(encoding); |
93 | 0 | } catch (UnsupportedEncodingException e) { |
94 | 0 | String msg = "Unable to convert source [" + source + "] to byte array using " + |
95 | "encoding '" + encoding + "'"; | |
96 | 0 | throw new CodecException(msg, e); |
97 | } | |
98 | } | |
99 | ||
100 | /** | |
101 | * Converts the specified byte array to a String using the {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}. | |
102 | * | |
103 | * @param bytes the byte array to turn into a String. | |
104 | * @return the specified byte array as an encoded String ({@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}). | |
105 | * @see #toString(byte[], String) | |
106 | */ | |
107 | public static String toString(byte[] bytes) { | |
108 | 35 | return toString(bytes, PREFERRED_ENCODING); |
109 | } | |
110 | ||
111 | /** | |
112 | * Converts the specified byte array to a String using the specified character encoding. This implementation | |
113 | * does the same thing as <code>new {@link String#String(byte[], String) String(byte[], encoding)}</code>, but will | |
114 | * wrap any {@link UnsupportedEncodingException} with a nicer runtime {@link CodecException}, allowing you to | |
115 | * decide whether or not you want to catch the exception or let it propagate. | |
116 | * | |
117 | * @param bytes the byte array to convert to a String | |
118 | * @param encoding the character encoding used to encode the String. | |
119 | * @return the specified byte array as an encoded String | |
120 | * @throws CodecException if the JVM does not support the specified encoding. | |
121 | */ | |
122 | public static String toString(byte[] bytes, String encoding) throws CodecException { | |
123 | try { | |
124 | 35 | return new String(bytes, encoding); |
125 | 0 | } catch (UnsupportedEncodingException e) { |
126 | 0 | String msg = "Unable to convert byte array to String with encoding '" + encoding + "'."; |
127 | 0 | throw new CodecException(msg, e); |
128 | } | |
129 | } | |
130 | ||
131 | /** | |
132 | * Returns the specified byte array as a character array using the | |
133 | * {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}. | |
134 | * | |
135 | * @param bytes the byte array to convert to a char array | |
136 | * @return the specified byte array encoded as a character array ({@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}). | |
137 | * @see #toChars(byte[], String) | |
138 | */ | |
139 | public static char[] toChars(byte[] bytes) { | |
140 | 0 | return toChars(bytes, PREFERRED_ENCODING); |
141 | } | |
142 | ||
143 | /** | |
144 | * Converts the specified byte array to a character array using the specified character encoding. | |
145 | * <p/> | |
146 | * Effectively calls <code>{@link #toString(byte[], String) toString(bytes,encoding)}.{@link String#toCharArray() toCharArray()};</code> | |
147 | * | |
148 | * @param bytes the byte array to convert to a String | |
149 | * @param encoding the character encoding used to encode the bytes. | |
150 | * @return the specified byte array as an encoded char array | |
151 | * @throws CodecException if the JVM does not support the specified encoding. | |
152 | */ | |
153 | public static char[] toChars(byte[] bytes, String encoding) throws CodecException { | |
154 | 0 | return toString(bytes, encoding).toCharArray(); |
155 | } | |
156 | ||
157 | /** | |
158 | * Returns {@code true} if the specified object can be easily converted to bytes by instances of this class, | |
159 | * {@code false} otherwise. | |
160 | * <p/> | |
161 | * The default implementation returns {@code true} IFF the specified object is an instance of one of the following | |
162 | * types: | |
163 | * <ul> | |
164 | * <li>{@code byte[]}</li> | |
165 | * <li>{@code char[]}</li> | |
166 | * <li>{@link ByteSource}</li> | |
167 | * <li>{@link String}</li> | |
168 | * <li>{@link File}</li> | |
169 | * </li>{@link InputStream}</li> | |
170 | * </ul> | |
171 | * | |
172 | * @param o the object to test to see if it can be easily converted to a byte array | |
173 | * @return {@code true} if the specified object can be easily converted to bytes by instances of this class, | |
174 | * {@code false} otherwise. | |
175 | * @since 1.0 | |
176 | */ | |
177 | protected boolean isByteSource(Object o) { | |
178 | 64 | return o instanceof byte[] || o instanceof char[] || o instanceof String || |
179 | o instanceof ByteSource || o instanceof File || o instanceof InputStream; | |
180 | } | |
181 | ||
182 | /** | |
183 | * Converts the specified Object into a byte array. | |
184 | * <p/> | |
185 | * If the argument is a {@code byte[]}, {@code char[]}, {@link ByteSource}, {@link String}, {@link File}, or | |
186 | * {@link InputStream}, it will be converted automatically and returned.} | |
187 | * <p/> | |
188 | * If the argument is anything other than these types, it is passed to the | |
189 | * {@link #objectToBytes(Object) objectToBytes} method which must be overridden by subclasses. | |
190 | * | |
191 | * @param o the Object to convert into a byte array | |
192 | * @return a byte array representation of the Object argument. | |
193 | */ | |
194 | protected byte[] toBytes(Object o) { | |
195 | 140 | if (o == null) { |
196 | 0 | String msg = "Argument for byte conversion cannot be null."; |
197 | 0 | throw new IllegalArgumentException(msg); |
198 | } | |
199 | 140 | if (o instanceof byte[]) { |
200 | 8 | return (byte[]) o; |
201 | 132 | } else if (o instanceof ByteSource) { |
202 | 41 | return ((ByteSource) o).getBytes(); |
203 | 91 | } else if (o instanceof char[]) { |
204 | 39 | return toBytes((char[]) o); |
205 | 52 | } else if (o instanceof String) { |
206 | 52 | return toBytes((String) o); |
207 | 0 | } else if (o instanceof File) { |
208 | 0 | return toBytes((File) o); |
209 | 0 | } else if (o instanceof InputStream) { |
210 | 0 | return toBytes((InputStream) o); |
211 | } else { | |
212 | 0 | return objectToBytes(o); |
213 | } | |
214 | } | |
215 | ||
216 | /** | |
217 | * Converts the specified Object into a String. | |
218 | * <p/> | |
219 | * If the argument is a {@code byte[]} or {@code char[]} it will be converted to a String using the | |
220 | * {@link #PREFERRED_ENCODING}. If a String, it will be returned as is. | |
221 | * <p/> | |
222 | * If the argument is anything other than these three types, it is passed to the | |
223 | * {@link #objectToString(Object) objectToString} method. | |
224 | * | |
225 | * @param o the Object to convert into a byte array | |
226 | * @return a byte array representation of the Object argument. | |
227 | */ | |
228 | protected String toString(Object o) { | |
229 | 0 | if (o == null) { |
230 | 0 | String msg = "Argument for String conversion cannot be null."; |
231 | 0 | throw new IllegalArgumentException(msg); |
232 | } | |
233 | 0 | if (o instanceof byte[]) { |
234 | 0 | return toString((byte[]) o); |
235 | 0 | } else if (o instanceof char[]) { |
236 | 0 | return new String((char[]) o); |
237 | 0 | } else if (o instanceof String) { |
238 | 0 | return (String) o; |
239 | } else { | |
240 | 0 | return objectToString(o); |
241 | } | |
242 | } | |
243 | ||
244 | protected byte[] toBytes(File file) { | |
245 | 0 | if (file == null) { |
246 | 0 | throw new IllegalArgumentException("File argument cannot be null."); |
247 | } | |
248 | try { | |
249 | 0 | return toBytes(new FileInputStream(file)); |
250 | 0 | } catch (FileNotFoundException e) { |
251 | 0 | String msg = "Unable to acquire InputStream for file [" + file + "]"; |
252 | 0 | throw new CodecException(msg, e); |
253 | } | |
254 | } | |
255 | ||
256 | /** | |
257 | * Converts the specified {@link InputStream InputStream} into a byte array. | |
258 | * | |
259 | * @param in the InputStream to convert to a byte array | |
260 | * @return the bytes of the input stream | |
261 | * @throws IllegalArgumentException if the {@code InputStream} argument is {@code null}. | |
262 | * @throws CodecException if there is any problem reading from the {@link InputStream}. | |
263 | * @since 1.0 | |
264 | */ | |
265 | protected byte[] toBytes(InputStream in) { | |
266 | 0 | if (in == null) { |
267 | 0 | throw new IllegalArgumentException("InputStream argument cannot be null."); |
268 | } | |
269 | 0 | final int BUFFER_SIZE = 512; |
270 | 0 | ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE); |
271 | 0 | byte[] buffer = new byte[BUFFER_SIZE]; |
272 | int bytesRead; | |
273 | try { | |
274 | 0 | while ((bytesRead = in.read(buffer)) != -1) { |
275 | 0 | out.write(buffer, 0, bytesRead); |
276 | } | |
277 | 0 | return out.toByteArray(); |
278 | 0 | } catch (IOException ioe) { |
279 | 0 | throw new CodecException(ioe); |
280 | } finally { | |
281 | 0 | try { |
282 | 0 | in.close(); |
283 | 0 | } catch (IOException ignored) { |
284 | 0 | } |
285 | try { | |
286 | 0 | out.close(); |
287 | 0 | } catch (IOException ignored) { |
288 | 0 | } |
289 | } | |
290 | } | |
291 | ||
292 | /** | |
293 | * Default implementation throws a CodecException immediately since it can't infer how to convert the Object | |
294 | * to a byte array. This method must be overridden by subclasses if anything other than the three default | |
295 | * types (listed in the {@link #toBytes(Object) toBytes(Object)} JavaDoc) are to be converted to a byte array. | |
296 | * | |
297 | * @param o the Object to convert to a byte array. | |
298 | * @return a byte array representation of the Object argument. | |
299 | */ | |
300 | protected byte[] objectToBytes(Object o) { | |
301 | 0 | String msg = "The " + getClass().getName() + " implementation only supports conversion to " + |
302 | "byte[] if the source is of type byte[], char[], String, " + ByteSource.class.getName() + | |
303 | " File or InputStream. The instance provided as a method " + | |
304 | "argument is of type [" + o.getClass().getName() + "]. If you would like to convert " + | |
305 | "this argument type to a byte[], you can 1) convert the argument to one of the supported types " + | |
306 | "yourself and then use that as the method argument or 2) subclass " + getClass().getName() + | |
307 | "and override the objectToBytes(Object o) method."; | |
308 | 0 | throw new CodecException(msg); |
309 | } | |
310 | ||
311 | /** | |
312 | * Default implementation merely returns <code>objectArgument.toString()</code>. Subclasses can override this | |
313 | * method for different mechanisms of converting an object to a String. | |
314 | * | |
315 | * @param o the Object to convert to a byte array. | |
316 | * @return a String representation of the Object argument. | |
317 | */ | |
318 | protected String objectToString(Object o) { | |
319 | 0 | return o.toString(); |
320 | } | |
321 | } |