View Javadoc

1   /*
2    * Copyright 2006-2016 The JGUIraffe Team.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.jguiraffe.locators;
17  
18  import java.io.ByteArrayInputStream;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.net.MalformedURLException;
22  import java.net.URL;
23  import java.net.URLStreamHandler;
24  import java.util.Arrays;
25  
26  /**
27   * <p>
28   * A specialized {@link Locator} implementation that provides access to data
29   * stored in memory as a byte array.
30   * </p>
31   * <p>
32   * This locator can be initialized either with a byte array or with a string.
33   * This data is kept in memory. The locator returns a stream or an URL providing
34   * access to exactly this data.
35   * </p>
36   * <p>
37   * This class is especially useful for providing access to small amounts of data
38   * to clients that can deal with locators. It can also be of value for unit
39   * tests supporting an easy way of defining test data.
40   * </p>
41   * <p>
42   * Instances are created using one of the static <code>getInstance()</code>
43   * factory methods. This class is thread-safe and can be used concurrently by
44   * multiple threads. Each invocation of <code>getInputStream()</code> returns a
45   * new stream instance initialized with the data of this locator.
46   * </p>
47   *
48   * @author Oliver Heger
49   * @version $Id: ByteArrayLocator.java 205 2012-01-29 18:29:57Z oheger $
50   */
51  public final class ByteArrayLocator extends AbstractStreamLocator
52  {
53      /** Constant for the maximum number of elements printed by toString(). */
54      static final int MAX_ELEMENTS = 50;
55  
56      /** Constant for the protocol used for the URL. */
57      private static final String PROTOCOL = "data";
58  
59      /** Constant for the length factor for calculating the string buffer size. */
60      private static final int LENGTH_FACTOR = 5;
61  
62      /** Constant for the static size of the string buffer. */
63      private static final int BUF_SIZE = 8;
64  
65      /** Stores the data of this locator. */
66      private final byte[] data;
67  
68      /**
69       * Creates a new instance of <code>ByteArrayLocator</code> and initializes
70       * it with the data array. Clients use the static factory methods for
71       * creating instances.
72       *
73       * @param d the data array
74       */
75      private ByteArrayLocator(byte[] d)
76      {
77          data = d;
78      }
79  
80      /**
81       * Creates an instance of <code>ByteArrayLocator</code> that is initialized
82       * with the specified data.
83       *
84       * @param data the data for the locator (must not be <b>null</b>)
85       * @return the locator instance pointing to this data
86       * @throws IllegalArgumentException if the data is <b>null</b>
87       */
88      public static ByteArrayLocator getInstance(byte[] data)
89      {
90          if (data == null)
91          {
92              throw new IllegalArgumentException("Data must not be null!");
93          }
94  
95          return new ByteArrayLocator(data.clone());
96      }
97  
98      /**
99       * Creates an instance of <code>ByteArrayLocator</code> that is initialized
100      * with the data of the specified string.
101      *
102      * @param data the data for the locator (must not be <b>null</b>)
103      * @return the locator instance pointing to this data
104      * @throws IllegalArgumentException if the data is <b>null</b>
105      */
106     public static ByteArrayLocator getInstance(String data)
107     {
108         if (data == null)
109         {
110             throw new IllegalArgumentException("Data must not be null!");
111         }
112 
113         return new ByteArrayLocator(data.getBytes());
114     }
115 
116     /**
117      * Returns an input stream for the data of this locator. This implementation
118      * creates a stream that allows reading the data this locator points to in
119      * memory.
120      *
121      * @return the input stream for this locator
122      * @throws IOException if an error occurs
123      */
124     @Override
125     public InputStream getInputStream() throws IOException
126     {
127         return new ByteArrayInputStream(data);
128     }
129 
130     /**
131      * Compares this object with another one. Two instances of this class are
132      * considered equal if and only if the data arrays they point to are equal.
133      *
134      * @param obj the object to compare to
135      * @return a flag whether these objects are equal
136      */
137     @Override
138     public boolean equals(Object obj)
139     {
140         if (this == obj)
141         {
142             return true;
143         }
144         if (!(obj instanceof ByteArrayLocator))
145         {
146             return false;
147         }
148 
149         ByteArrayLocator c = (ByteArrayLocator) obj;
150         return Arrays.equals(data, c.data);
151     }
152 
153     /**
154      * Returns a hash code for this object.
155      *
156      * @return a hash code for this object
157      */
158     @Override
159     public int hashCode()
160     {
161         return Arrays.hashCode(data);
162     }
163 
164     /**
165      * Returns a string representation for this object. This string will contain
166      * (at least parts of) the data this locator points to. If the data array
167      * contains too many elements, only an excerpt of the data is printed out.
168      *
169      * @return a string for this object
170      */
171     @Override
172     public String toString()
173     {
174         StringBuilder buf = new StringBuilder(Math.min(MAX_ELEMENTS,
175                 data.length)
176                 * LENGTH_FACTOR + BUF_SIZE);
177         buf.append("data = ");
178 
179         // Obtain the data to be dumped. If the data array is small enough,
180         // dump it complete; otherwise fetch a subset.
181         byte[] d;
182         if (data.length <= MAX_ELEMENTS)
183         {
184             d = data;
185         }
186         else
187         {
188             d = new byte[MAX_ELEMENTS];
189             System.arraycopy(data, 0, d, 0, MAX_ELEMENTS);
190         }
191         buf.append(Arrays.toString(d));
192         if (d != data)
193         {
194             buf.append("...");
195         }
196 
197         return LocatorUtils.locatorToString(this, buf.toString());
198     }
199 
200     /**
201      * Creates a URL representing the data of this locator. This implementation
202      * creates a URL with the protocol 'data' and a hash value of the data as
203      * host.
204      *
205      * @param streamHandler the stream handler to use for this URL
206      * @return the URL representing the data of this locator
207      * @throws MalformedURLException if the URL cannot be created
208      */
209     @Override
210     protected URL createURL(URLStreamHandler streamHandler)
211             throws MalformedURLException
212     {
213         return new URL(PROTOCOL, String.valueOf(Arrays.hashCode(data)), -1, "",
214                 streamHandler);
215     }
216 }