001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.utils; 022 023import java.io.BufferedInputStream; 024import java.io.FileInputStream; 025import java.io.FileNotFoundException; 026import java.io.IOException; 027import java.io.InputStream; 028import java.util.ArrayList; 029import java.util.List; 030import java.util.Properties; 031import java.util.StringTokenizer; 032 033/** 034 * a sub-class of java.util.Properties that provides the same constructors, adds two convenient load methods to load 035 * the properties from files and, most importantly, adds getPropertyAsXXX() methods to get a property as an object of 036 * type XXX. 037 * 038 * @author <A href="mailto:Gerald.Loeffler@vienna.at">Gerald Loeffler</A> for the 039 * <A href="http://www.imp.univie.ac.at">IMP</A> 040 */ 041public class TypedProperties extends Properties { 042 /** 043 * the default string of delimiter characters used by getAsStringList() 044 */ 045 public static final String DEFAULT_DELIMITERS = ",;\t"; 046 047 /** 048 * Creates an empty property list with no default values. 049 */ 050 public TypedProperties() { 051 super(); 052 } 053 054 /** 055 * Creates an empty property list with the specified defaults. 056 * @param defaults the defaults. 057 */ 058 public TypedProperties(Properties defaults) { 059 super(defaults); 060 } 061 062 /** 063 * Reads a property list (key and element pairs) from the file with the given file name. 064 * @param fileName the file name. Not null. 065 * @exception FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some 066 * other reason cannot be opened for reading. 067 * @exception IOException if an error occurred when reading from the input stream created from the file with the given 068 * name. 069 */ 070 public void load(String fileName) throws FileNotFoundException, IOException { 071 if (fileName == null) { 072 throw new IllegalArgumentException("fileName not null"); 073 } 074 075 load(new BufferedInputStream(new FileInputStream(fileName))); 076 } 077 078 /** 079 * Reads a property list (key and element pairs) from the given 080 * file which is interpreted as a resource of the given class. The difference 081 * between a normal file and a resource file is the way in which the file is 082 * located: with a normal file, the filename is taken literally to load the 083 * file from the file system, whereas with a resource file, the given name is 084 * used to ask the class loader of the given class to load the file 085 * (see java.lang.Class.getResourceAsStream() and 086 * java.lang.ClassLoader.getSystemResourceAsStream()). 087 * 088 * @see java.lang.Class 089 * @see java.lang.ClassLoader 090 * 091 * @param clazz the class with which the resource identified by resourceName 092 * is taken to be associated with 093 * (java.lang.Class.getResourceAsStream() on this Class 094 * object is used to load the resource). If clazz is null, the 095 * resource is considered to be a system resource, and 096 * java.lang.ClassLoader.getSystemResourceAsStream() is used to 097 * load the resource. 098 * @param resourceName the name of the resource from which to load the properties. It is a precondition that the 099 * resource with this name exists (regardless whether it is interpreted as a system resource or a 100 * class resource), otherwise an IllegalArgumentException is thrown. 101 * @exception IOException if an error occurred when reading from the input stream created from the given resource. 102 */ 103 public void load(Class clazz, String resourceName) throws IOException { 104 InputStream is = null; 105 if (clazz == null) { 106 // load resource as system resource 107 is = ClassLoader.getSystemResourceAsStream(resourceName); 108 if (is == null) { 109 throw new IllegalArgumentException("system reource " + resourceName + " must exist"); 110 } 111 } else { 112 // load resource as class resource 113 is = clazz.getResourceAsStream(resourceName); 114 if (is == null) { 115 throw new IllegalArgumentException("resource " + resourceName + " associated with class " + clazz + " must exist"); 116 } 117 } 118 load(is); 119 } 120 121 /** 122 * Searches for the property with the specified key in this property list. If the key is not found in this property 123 * list, the default property list, and its defaults, recursively, are then checked. The method returns null if the 124 * property is not found. If the property is found its value is parsed as an integer and returned. If parsing the 125 * value fails, a NumberFormatException is thrown. 126 * 127 * @param key the property key. 128 * @return the integer value of the property with the given key or null if the given key is not associated with a 129 * property. 130 * @exception NumberFormatException if the property associated with the given key does not have an integer value. 131 */ 132 public Integer getPropertyAsInteger(String key) throws NumberFormatException { 133 String v = getProperty(key); 134 if (v == null) return null; 135 return new Integer(v); 136 } 137 138 /** 139 * Searches for the property with the specified key in this property list. If the key is not found in this property 140 * list, the default property list, and its defaults, recursively, are then checked. The method returns null if the 141 * property is not found. If the property is found its value is parsed as a long and returned. If parsing the 142 * value fails, a NumberFormatException is thrown. 143 * 144 * @param key the property key. 145 * @return the long value of the property with the given key or null if the given key is not associated with a 146 * property. 147 * @exception NumberFormatException if the property associated with the given key does not have an integer value. 148 */ 149 public Long getPropertyAsLong(String key) throws NumberFormatException { 150 String v = getProperty(key); 151 if (v == null) return null; 152 return new Long(v); 153 } 154 155 /** 156 * Searches for the property with the specified key in this property list. If the key is not found in this property 157 * list, the default property list, and its defaults, recursively, are then checked. The method returns null if the 158 * property is not found. If the property is found its value is parsed as a double and returned. If parsing the 159 * value fails, a NumberFormatException is thrown. 160 * 161 * @param key the property key. 162 * @return the double value of the property with the given key or null if the given key is not associated with a 163 * property. 164 * @exception NumberFormatException if the property associated with the given key does not have an integer value. 165 */ 166 public Double getPropertyAsDouble(String key) throws NumberFormatException { 167 String v = getProperty(key); 168 if (v == null) return null; 169 return new Double(v); 170 } 171 172 /** 173 * Searches for the property with the specified key in this property list. If the key is not found in this property 174 * list, the default property list, and its defaults, recursively, are then checked. The method returns null if the 175 * property is not found. If the property is found its value is parsed as an boolean and returned. If parsing the 176 * value fails, a RuntimeException is thrown. 177 * <p> 178 * If the property value is equal, ignoring case, to the string "true" or "yes" then the boolean value 179 * returned from this method is true. If the property value is equal, ignoring case, to the string 180 * "false" or "no" then the boolean value returned from this method is false. 181 * 182 * @param key the property key. 183 * @return the boolean value of the property with the given key or null if the given key is not associated with a 184 * property. 185 * @exception RuntimeException if the property associated with the given key does not have an integer value. 186 */ 187 public Boolean getPropertyAsBoolean(String key) throws RuntimeException { 188 String v = getProperty(key); 189 if (v == null) return null; 190 if (v.equalsIgnoreCase("true") || v.equalsIgnoreCase("yes")) return Boolean.TRUE; 191 else if (v.equalsIgnoreCase("false") || v.equalsIgnoreCase("no")) return Boolean.FALSE; 192 else throw new RuntimeException("property value " + v + " is not parseable as a boolean"); 193 } 194 195 /** 196 * Searches for the property with the specified key in this property list. If the key is not found in this property 197 * list, the default property list, and its defaults, recursively, are then checked. The method returns null if the 198 * property is not found. If the property is found its value is parsed as a list of strings and returned as a List 199 * object that contains only String objects. Parsing the property value as a list of strings can not fail and so this 200 * method does not throw an exception. 201 * <p> 202 * The property value is interpreted as String objects (tokens) separated by one or more (consecutive) separator 203 * characters taken from the delims string. Any of these characters separates the tokens and can hence not be part of 204 * any token! The tokens identified in this way are put into a List in the order in which they appear in the property 205 * value. White space at the beginning and end of each token are removed before storing the token as an element of the 206 * list (this includes white space at the beginning and end of the complete property value)! Empty strings are also 207 * never added to the list, i.e. if after removal of white space from a token a token is the empty string, it is not 208 * stored in the list! All this results in a very natural conversion of the property value into a list of strings: 209 * only "real" (non-white-space, non-white-space-bounded, non-delimiter-containing) sub-strings from the 210 * property value are put as string elements into the list. 211 * 212 * @param key the property key. 213 * @param delims the string of allowed delimiter characters (not null and not empty). 214 * @return the List of strings for the property with the given key or null if the given key is not associated with a 215 * property. An empty list is returned if a property with the given key exists but its value is empty or 216 * consists only of white space. 217 */ 218 public List getPropertyAsStringList(String key, String delims) { 219 if (delims == null || delims.length() == 0) { 220 throw new IllegalArgumentException("delims != null && delims.length() > 0"); 221 } 222 223 String v = getProperty(key); 224 if (v == null) return null; 225 226 List l = new ArrayList(); 227 228 v = v.trim(); 229 if (v.length() > 0) { 230 StringTokenizer st = new StringTokenizer(v, delims, false); 231 while (st.hasMoreTokens()) { 232 String token = (st.nextToken()).trim(); 233 if (token != null && token.length() > 0) l.add(token); // store only non-empty tokens 234 } 235 } 236 237 return l; 238 } 239 240 /** 241 * just like getPropertyAsStringList(String key, String delims) but uses ',' (comma), ';' (semicolon) and '\t' (tab) 242 * as the possible delimiters. 243 */ 244 public List getPropertyAsStringList(String key) { 245 return getPropertyAsStringList(key, DEFAULT_DELIMITERS); 246 } 247 248 public String toString() { 249 return "TypedProperties"; 250 } 251 252 public boolean equals(Object o) { 253 if (o == this) return true; 254 255 // this class extends another class than Object: 256 if (!super.equals(o)) return false; 257 258 // this and that are identical if we made it 'til here 259 return true; 260 } 261 262 public int hashCode() { 263 // this class extends another class than Object: 264 int hc = super.hashCode(); 265 266 return hc; 267 } 268 269 public Object clone() { 270 TypedProperties o = (TypedProperties) super.clone(); 271 272 return o; 273 } 274}