Coverage Report - org.apache.shiro.codec.CodecSupport
 
Classes in this File Line Coverage Branch Coverage Complexity
CodecSupport
23%
16/68
35%
14/40
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  
 }