001 /* 002 * $Id: ResourcesBase.java 354330 2005-12-06 06:05:19Z niallp $ 003 * $Revision: 354330 $ 004 * $Date: 2005-12-06 06:05:19 +0000 (Tue, 06 Dec 2005) $ 005 * 006 * ==================================================================== 007 * 008 * Copyright 2003-2005 The Apache Software Foundation 009 * 010 * Licensed under the Apache License, Version 2.0 (the "License"); 011 * you may not use this file except in compliance with the License. 012 * You may obtain a copy of the License at 013 * 014 * http://www.apache.org/licenses/LICENSE-2.0 015 * 016 * Unless required by applicable law or agreed to in writing, software 017 * distributed under the License is distributed on an "AS IS" BASIS, 018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 019 * See the License for the specific language governing permissions and 020 * limitations under the License. 021 * 022 */ 023 024 package org.apache.commons.resources.impl; 025 026 import java.io.ByteArrayInputStream; 027 import java.io.InputStream; 028 import java.io.InputStreamReader; 029 import java.io.Reader; 030 import java.io.StringReader; 031 import java.io.IOException; 032 import java.util.Iterator; 033 import java.util.Locale; 034 035 import org.apache.commons.resources.Resources; 036 import org.apache.commons.resources.ResourcesException; 037 import org.apache.commons.resources.ResourcesKeyException; // for javadoc/checkstyle 038 039 /** 040 * <p>Convenience base class for 041 * {@link org.apache.commons.resources.Resources} implementations.</p> 042 * 043 * <p>Default implementations of the content retrieval methods are provided 044 * for all methods except <code>getObject()</code>. The default methods for 045 * the other content retrieval methods are coded in terms of 046 * <code>getString()</code>, on the assumption that most uses of 047 * {@link org.apache.commons.resources.Resources} are of this type. 048 * However, they can be easily overridden as needed.</p> 049 * 050 * @see org.apache.commons.resources.impl.CollectionResourcesBase 051 * @see org.apache.commons.resources.impl.JDBCResources 052 * @see org.apache.commons.resources.impl.PropertyResources 053 * @see org.apache.commons.resources.impl.ResourceBundleResources 054 * @see org.apache.commons.resources.impl.WebappPropertyResources 055 * @see org.apache.commons.resources.impl.WebappXMLResources 056 * @see org.apache.commons.resources.impl.XMLResources 057 */ 058 public abstract class ResourcesBase implements Resources { 059 060 061 // ----------------------------------------------------------- Constructors 062 063 064 /** 065 * <p>Create a new {@link org.apache.commons.resources.Resources} instance 066 * with no name.</p> 067 */ 068 public ResourcesBase() { 069 070 this(null); 071 072 } 073 074 075 /** 076 * <p>Create a new {@link org.apache.commons.resources.Resources} instance 077 * with the specified logical name.</p> 078 * 079 * @param name Logical name of the new instance 080 */ 081 public ResourcesBase(String name) { 082 083 this.name = name; 084 085 } 086 087 088 // ----------------------------------------------------- Instance Variables 089 090 091 /** 092 * <p>The logical name of this {@link org.apache.commons.resources.Resources} 093 * instance.</p> 094 */ 095 private String name = null; 096 097 098 /** 099 * <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 }