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 }