View Javadoc

1   /*
2    * $Id: ResourcesBase.java 354330 2005-12-06 06:05:19Z niallp $
3    * $Revision: 354330 $
4    * $Date: 2005-12-06 06:05:19 +0000 (Tue, 06 Dec 2005) $
5    *
6    * ====================================================================
7    *
8    *  Copyright 2003-2005 The Apache Software Foundation
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   *
22   */
23  
24  package org.apache.commons.resources.impl;
25  
26  import java.io.ByteArrayInputStream;
27  import java.io.InputStream;
28  import java.io.InputStreamReader;
29  import java.io.Reader;
30  import java.io.StringReader;
31  import java.io.IOException;
32  import java.util.Iterator;
33  import java.util.Locale;
34  
35  import org.apache.commons.resources.Resources;
36  import org.apache.commons.resources.ResourcesException;
37  import org.apache.commons.resources.ResourcesKeyException; // for javadoc/checkstyle
38  
39  /**
40   * <p>Convenience base class for 
41   * {@link org.apache.commons.resources.Resources} implementations.</p>
42   *
43   * <p>Default implementations of the content retrieval methods are provided
44   * for all methods except <code>getObject()</code>.  The default methods for
45   * the other content retrieval methods are coded in terms of
46   * <code>getString()</code>, on the assumption that most uses of
47   * {@link org.apache.commons.resources.Resources} are of this type.  
48   * However, they can be easily overridden as needed.</p>
49   *
50   * @see org.apache.commons.resources.impl.CollectionResourcesBase
51   * @see org.apache.commons.resources.impl.JDBCResources
52   * @see org.apache.commons.resources.impl.PropertyResources
53   * @see org.apache.commons.resources.impl.ResourceBundleResources
54   * @see org.apache.commons.resources.impl.WebappPropertyResources
55   * @see org.apache.commons.resources.impl.WebappXMLResources
56   * @see org.apache.commons.resources.impl.XMLResources
57   */
58  public abstract class ResourcesBase implements Resources {
59  
60  
61      // ----------------------------------------------------------- Constructors
62  
63  
64      /**
65       * <p>Create a new {@link org.apache.commons.resources.Resources} instance 
66       * with no name.</p>
67       */
68      public ResourcesBase() {
69  
70          this(null);
71  
72      }
73  
74  
75      /**
76       * <p>Create a new {@link org.apache.commons.resources.Resources} instance 
77       * with the specified logical name.</p>
78       *
79       * @param name Logical name of the new instance
80       */
81      public ResourcesBase(String name) {
82  
83          this.name = name;
84  
85      }
86  
87  
88      // ----------------------------------------------------- Instance Variables
89  
90  
91      /**
92       * <p>The logical name of this {@link org.apache.commons.resources.Resources} 
93       * instance.</p>
94       */
95      private String name = null;
96  
97  
98      /**
99       * <p>Flag indicating whether resource getter methods should return
100      * <code>null</code> (instead of throwing an exception) on invalid
101      * key values.</p>
102      */
103     private boolean returnNull = true;
104 
105     /**
106      * Buffer size for creating char and byte arrays.
107      */
108     private int bufferSize = 500;
109 
110     // ------------------------------------------------------ Lifecycle Methods
111 
112 
113     /**
114      * <p>This must be called to initialize the data content of this
115      * {@link org.apache.commons.resources.Resources} instance, before 
116      * any of the <code>getXxx()</code> methods are called.</p>
117      *
118      * <p>The default implementation does nothing.</p>
119      *
120      * @exception ResourcesException if an error occurs during initialization
121      */
122     public void init() {
123 
124          // The default implementation does nothing
125 
126     }
127 
128 
129     /**
130      * <p>This method must be called when the manager of this resource
131      * decides that it's no longer needed.  After this method is called,
132      * no further calls to any of the <code>getXxx()</code> methods are
133      * allowed.</p>
134      *
135      * <p>The default implementation does nothing.</p>
136      *
137      * @exception ResourcesException if an error occurs during finalization
138      */
139     public void destroy() {
140 
141         // The default implementation does nothing
142 
143     }
144 
145 
146     // ------------------------------------------------------------- Properties
147 
148 
149     /**
150      * <p>Return an <code>Iterator</code> over the defined keys in this
151      * {@link org.apache.commons.resources.Resources} instance.</p>
152      *
153      * @return The keys contained in this resources instance.
154      */
155     public abstract Iterator getKeys();
156 
157 
158     /**
159      * <p>Return the logical name of this {@link org.apache.commons.resources.Resources} 
160      * instance.</p>
161      *
162      * @return The name of this resources instance.
163      */
164     public String getName() {
165 
166         return (this.name);
167 
168     }
169 
170 
171     /**
172      * <p>Return <code>true</code> if resource getter methods will return
173      * <code>null</code> instead of throwing an exception on invalid
174      * key values.</p>
175      * @return 'true' if null is returned for invalid key values.
176      */
177     public boolean isReturnNull() {
178 
179         return (this.returnNull);
180 
181     }
182 
183 
184     /**
185      * <p>Set a flag determining whether resource getter methods should
186      * return <code>null</code> instead of throwing an exception on
187      * invalid key values.</p>
188      *
189      * @param returnNull The new flag value
190      */
191     public void setReturnNull(boolean returnNull) {
192 
193         this.returnNull = returnNull;
194 
195     }
196 
197 
198     /**
199      * <p>Return the size of the buffer to use when converting
200      * InputStream or Reader objects.</p>
201      *
202      * @return The buffer size.
203      */
204     public int getBufferSize() {
205 
206         return bufferSize;
207 
208     }
209 
210     /**
211      * <p>Set the size of the buffer to use when converting
212      * InputStream or Reader objects.</p>
213      *
214      * @param bufferSize The buffer size.
215      */
216     public void setBufferSize(int bufferSize) {
217 
218         this.bufferSize = bufferSize;
219 
220     }
221 
222 
223     // ---------------------------------------------- Content Retrieval Methods
224 
225 
226     /**
227      * <p>Return the content for the specified <code>key</code> as a
228      * byte array, localized based on the specified <code>locale</code>.
229      * </p>
230      *
231      * <p>The default implementation calls <code>getString()</code> and
232      * converts the value to a byte array.</p>
233      *
234      * @param key Identifier for the requested content
235      * @param locale Locale with which to localize retrieval,
236      *  or <code>null</code> for the default Locale
237      * @return content for a specified key.
238      *
239      * @exception ResourcesException if an error occurs retrieving or
240      *  returning the requested content
241      * @exception ResourcesKeyException if the no value for the specified
242      *  key was found, and <code>isReturnNull()</code> returns
243      *  <code>false</code>
244      */
245     public byte[] getBytes(String key, Locale locale) {
246 
247         Object value = getObject(key, locale);
248         if (value == null) {
249             return (null);
250         } else if (value instanceof String) {
251             return ((String)value).getBytes();
252         } else if (value instanceof Reader) {
253             char[] chars = getChars((Reader)value);
254             if (chars == null) {
255                 return (byte[])checkThrow(key);
256             }
257             return new String(chars).getBytes();
258         } else if (value instanceof InputStream) {
259             byte[] bytes = getBytes((InputStream)value);
260             if (bytes == null) {
261                 return (byte[])checkThrow(key);
262             }
263             return bytes;
264         } else if (value instanceof byte[]) {
265             return (byte[])value;
266         } else {
267             return value.toString().getBytes();
268         }
269 
270     }
271 
272 
273     /**
274      * <p>Return the content for the specified <code>key</code> as an
275      * InputStream, localized based on the specified <code>locale</code>.
276      * </p>
277      *
278      * <p>The default implementation calls <code>getsBytes()</code>
279      * and returns an input stream over the resulting byte array.</p>
280      *
281      * @param key Identifier for the requested content
282      * @param locale Locale with which to localize retrieval,
283      *  or <code>null</code> for the default Locale
284      * @return content for a specified key.
285      *
286      * @exception ResourcesException if an error occurs retrieving or
287      *  returning the requested content
288      * @exception ResourcesKeyException if the no value for the specified
289      *  key was found, and <code>isReturnNull()</code> returns
290      *  <code>false</code>
291      */
292     public InputStream getInputStream(String key, Locale locale) {
293 
294         Object value = getObject(key, locale);
295         if (value == null) {
296             return (null);
297         } else if (value instanceof String) {
298             byte[] bytes = ((String)value).getBytes();
299             return new ByteArrayInputStream(bytes);
300         } else if (value instanceof Reader) {
301             char[] chars = getChars((Reader)value);
302             if (chars == null) {
303                 return (InputStream)checkThrow(key);
304             }
305             byte[] bytes = (new String(chars)).getBytes();
306             return new ByteArrayInputStream(bytes);
307         } else if (value instanceof InputStream) {
308             return (InputStream)value;
309         } else if (value instanceof byte[]) {
310             return new ByteArrayInputStream((byte[])value);
311         } else {
312             byte[] bytes = value.toString().getBytes();
313             return new ByteArrayInputStream(bytes);
314         }
315 
316     }
317 
318 
319     /**
320      * <p>Return the content for the specified <code>key</code> as an
321      * Object, localized based on the specified <code>locale</code>.
322      * </p>
323      *
324      * <p>There is no default implementation of this method.  Concrete
325      * subclasses must provide such an implementation.</p>
326      *
327      * @param key Identifier for the requested content
328      * @param locale Locale with which to localize retrieval,
329      *  or <code>null</code> for the default Locale
330      * @return content for a specified key.
331      *
332      * @exception ResourcesException if an error occurs retrieving or
333      *  returning the requested content
334      * @exception ResourcesKeyException if the no value for the specified
335      *  key was found, and <code>isReturnNull()</code> returns
336      *  <code>false</code>
337      */
338     public abstract Object getObject(String key, Locale locale);
339 
340 
341     /**
342      * <p>Return the content for the specified <code>key</code> as a
343      * Reader, localized based on the specified <code>locale</code>.
344      * </p>
345      *
346      * <p>The default implementation calls <code>getString()</code>
347      * and returns a reader over the resulting characters.</p>
348      *
349      * @param key Identifier for the requested content
350      * @param locale Locale with which to localize retrieval,
351      *  or <code>null</code> for the default Locale
352      * @return content for a specified key.
353      *
354      * @exception ResourcesException if an error occurs retrieving or
355      *  returning the requested content
356      * @exception ResourcesKeyException if the no value for the specified
357      *  key was found, and <code>isReturnNull()</code> returns
358      *  <code>false</code>
359      */
360     public Reader getReader(String key, Locale locale) {
361 
362         Object value = getObject(key, locale);
363         if (value == null) {
364             return (null);
365         } else if (value instanceof String) {
366             return new StringReader((String)value);
367         } else if (value instanceof Reader) {
368             return (Reader)value;
369         } else if (value instanceof InputStream) {
370             return new InputStreamReader((InputStream)value);
371         } else if (value instanceof byte[]) {
372             InputStream bais = new ByteArrayInputStream((byte[])value);
373             return new InputStreamReader(bais);
374         } else {
375             return new StringReader(value.toString());
376         }
377 
378     }
379 
380 
381     /**
382      * <p>Return the content for the specified <code>key</code> as a
383      * String, localized based on the specified <code>locale</code>.
384      * </p>
385      *
386      * <p>The default implementation calls <code>getObject()</code>
387      * and converts the result to a String if necessary.</p>
388      *
389      * @param key Identifier for the requested content
390      * @param locale Locale with which to localize retrieval,
391      *  or <code>null</code> for the default Locale
392      * @return content for a specified key.
393      *
394      * @exception ResourcesException if an error occurs retrieving or
395      *  returning the requested content
396      * @exception ResourcesKeyException if the no value for the specified
397      *  key was found, and <code>isReturnNull()</code> returns
398      *  <code>false</code>
399      */
400     public String getString(String key, Locale locale) {
401 
402         Object value = getObject(key, locale);
403         if (value == null) {
404             return (null);
405         } else if (value instanceof String) {
406             return ((String) value);
407         } else if (value instanceof Reader) {
408             char[] chars = getChars((Reader)value);
409             if (chars == null) {
410                 return (String)checkThrow(key);
411             }
412             return new String(chars);
413         } else if (value instanceof InputStream) {
414             byte[] bytes = getBytes((InputStream)value);
415             if (bytes == null) {
416                 return (String)checkThrow(key);
417             }
418             return new String(bytes);
419         } else if (value instanceof byte[]) {
420             return new String((byte[])value);
421         } else {
422             return (value.toString());
423         }
424 
425     }
426 
427 
428     /**
429      * Convert a Reader to a char array.
430      */
431     private char[] getChars(Reader reader) {
432 
433         char[] array = null;
434         int arrayLth = 0;
435         try {
436             while (true) {
437                 char[] buffer = new char[bufferSize]; 
438                 int bufferLth = reader.read(buffer);
439                 if (bufferLth < 0) {
440                     break;
441                 }
442                 if (array == null && bufferLth == buffer.length) {
443                     array = buffer;
444                 } else {
445                     char[] newArray = new char[arrayLth + bufferLth];
446                     if (array != null) {
447                         System.arraycopy(array, 0, newArray, 0, arrayLth);
448                     }
449                     System.arraycopy(buffer, 0, newArray, arrayLth, bufferLth);
450                     array = newArray;
451                 }
452                 arrayLth = array.length;
453             }
454         } catch(IOException e) {
455             throw new ResourcesException("Error reading Reader", e);
456         }
457 
458         return array;
459 
460     }
461 
462     /**
463      * Convert an InputStream to a byte array.
464      */
465     private byte[] getBytes(InputStream inputStream) {
466 
467         byte[] array = null;
468         int arrayLth = 0;
469         try {
470             while (true) {
471                 byte[] buffer = new byte[bufferSize]; 
472                 int bufferLth = inputStream.read(buffer);
473                 if (bufferLth < 0) {
474                     break;
475                 }
476                 if (array == null && bufferLth == buffer.length) {
477                     array = buffer;
478                 } else {
479                     byte[] newArray = new byte[arrayLth + bufferLth];
480                     if (array != null) {
481                         System.arraycopy(array, 0, newArray, 0, arrayLth);
482                     }
483                     System.arraycopy(buffer, 0, newArray, arrayLth, bufferLth);
484                     array = newArray;
485                 }
486                 arrayLth = array.length;
487             }
488         } catch(IOException e) {
489             throw new ResourcesException("Error reading InputStream", e);
490         }
491         return array;
492 
493     }
494 
495     /**
496      * Check whether this Resources instance is
497      * configured to return null or throw a ResourcesKeyException.
498      * @param key Identifier for the requested content
499      * @return 'null' if returnNull is 'true' otherwise throws
500      *        a ResourcesKeyException.
501      */
502     private Object checkThrow(String key) {
503         if (isReturnNull()) {
504             return (null);
505         } else {
506             throw new ResourcesKeyException(key);
507         }
508     }
509 
510 }