View Javadoc

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.util;
20  
21  import org.apache.shiro.codec.Base64;
22  import org.apache.shiro.codec.CodecSupport;
23  import org.apache.shiro.codec.Hex;
24  
25  import java.io.File;
26  import java.io.InputStream;
27  import java.util.Arrays;
28  
29  /**
30   * Very simple {@link ByteSource ByteSource} implementation that maintains an internal {@code byte[]} array and uses the
31   * {@link Hex Hex} and {@link Base64 Base64} codec classes to support the
32   * {@link #toHex() toHex()} and {@link #toBase64() toBase64()} implementations.
33   * <p/>
34   * The constructors on this class accept the following implicit byte-backed data types and will convert them to
35   * a byte-array automatically:
36   * <ul>
37   * <li>byte[]</li>
38   * <li>char[]</li>
39   * <li>String</li>
40   * <li>{@link ByteSource ByteSource}</li>
41   * <li>{@link File File}</li>
42   * <li>{@link InputStream InputStream}</li>
43   * </ul>
44   *
45   * @since 1.0
46   */
47  public class SimpleByteSource implements ByteSource {
48  
49      private final byte[] bytes;
50      private String cachedHex;
51      private String cachedBase64;
52  
53      public SimpleByteSource(byte[] bytes) {
54          this.bytes = bytes;
55      }
56  
57      /**
58       * Creates an instance by converting the characters to a byte array (assumes UTF-8 encoding).
59       *
60       * @param chars the source characters to use to create the underlying byte array.
61       * @since 1.1
62       */
63      public SimpleByteSource(char[] chars) {
64          this.bytes = CodecSupport.toBytes(chars);
65      }
66  
67      /**
68       * Creates an instance by converting the String to a byte array (assumes UTF-8 encoding).
69       *
70       * @param string the source string to convert to a byte array (assumes UTF-8 encoding).
71       * @since 1.1
72       */
73      public SimpleByteSource(String string) {
74          this.bytes = CodecSupport.toBytes(string);
75      }
76  
77      /**
78       * Creates an instance using the sources bytes directly - it does not create a copy of the
79       * argument's byte array.
80       *
81       * @param source the source to use to populate the underlying byte array.
82       * @since 1.1
83       */
84      public SimpleByteSource(ByteSource source) {
85          this.bytes = source.getBytes();
86      }
87  
88      /**
89       * Creates an instance by converting the file to a byte array.
90       *
91       * @param file the file from which to acquire bytes.
92       * @since 1.1
93       */
94      public SimpleByteSource(File file) {
95          this.bytes = new BytesHelper().getBytes(file);
96      }
97  
98      /**
99       * Creates an instance by converting the stream to a byte array.
100      *
101      * @param stream the stream from which to acquire bytes.
102      * @since 1.1
103      */
104     public SimpleByteSource(InputStream stream) {
105         this.bytes = new BytesHelper().getBytes(stream);
106     }
107 
108     /**
109      * Returns {@code true} if the specified object is a recognized data type that can be easily converted to
110      * bytes by instances of this class, {@code false} otherwise.
111      * <p/>
112      * This implementation returns {@code true} IFF the specified object is an instance of one of the following
113      * types:
114      * <ul>
115      * <li>{@code byte[]}</li>
116      * <li>{@code char[]}</li>
117      * <li>{@link ByteSource}</li>
118      * <li>{@link String}</li>
119      * <li>{@link File}</li>
120      * </li>{@link InputStream}</li>
121      * </ul>
122      *
123      * @param o the object to test to see if it can be easily converted to bytes by instances of this class.
124      * @return {@code true} if the specified object can be easily converted to bytes by instances of this class,
125      *         {@code false} otherwise.
126      * @since 1.2
127      */
128     public static boolean isCompatible(Object o) {
129         return o instanceof byte[] || o instanceof char[] || o instanceof String ||
130                 o instanceof ByteSource || o instanceof File || o instanceof InputStream;
131     }
132 
133     public byte[] getBytes() {
134         return this.bytes;
135     }
136 
137     public boolean isEmpty() {
138         return this.bytes == null || this.bytes.length == 0;
139     }
140 
141     public String toHex() {
142         if ( this.cachedHex == null ) {
143             this.cachedHex = Hex.encodeToString(getBytes());
144         }
145         return this.cachedHex;
146     }
147 
148     public String toBase64() {
149         if ( this.cachedBase64 == null ) {
150             this.cachedBase64 = Base64.encodeToString(getBytes());
151         }
152         return this.cachedBase64;
153     }
154 
155     public String toString() {
156         return toBase64();
157     }
158 
159     public int hashCode() {
160         if (this.bytes == null || this.bytes.length == 0) {
161             return 0;
162         }
163         return Arrays.hashCode(this.bytes);
164     }
165 
166     public boolean equals(Object o) {
167         if (o == this) {
168             return true;
169         }
170         if (o instanceof ByteSource) {
171             ByteSource bs = (ByteSource) o;
172             return Arrays.equals(getBytes(), bs.getBytes());
173         }
174         return false;
175     }
176 
177     //will probably be removed in Shiro 2.0.  See SHIRO-203:
178     //https://issues.apache.org/jira/browse/SHIRO-203
179     private static final class BytesHelper extends CodecSupport {
180         public byte[] getBytes(File file) {
181             return toBytes(file);
182         }
183 
184         public byte[] getBytes(InputStream stream) {
185             return toBytes(stream);
186         }
187     }
188 }