View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of Java-Common.
5    *
6    * Java-Common is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * Java-Common is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with Java-Common.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.util;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.net.MalformedURLException;
25  import java.net.URL;
26  import java.util.Enumeration;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.Map;
30  import java.util.Properties;
31  
32  
33  /**
34   * DOCUMENT ME!
35   *
36   * @version $id$
37   */
38  public class ExtendedProperties extends Properties
39  {
40      /**
41       * Suffix used to speficy a linked properties file. The key
42       * up to the string is used as the root for all the properties found in
43       * the referenced file.
44       * <p>e.g.: <code>icon.@link = gui/icons.properties</code> will look
45       * for a file "gui/icons.properties" and a property named <code>text.edit</code>
46       * from this file will be referenced in the parent properties as "icon.text.edit".
47       * <p>
48       * If multiple links are assigned to the same prefix, they should be numbered
49       * so that their property keys remain unique, e.g.:<br/>
50       * <code>icon.@link1 = gui/myIcons.properties</code>
51       * <code>icon.@link2 = gui/otherIcons.properties</code>
52       * </p>
53       * 
54       */
55      public static final String LINK_SUFFIX="@link";
56      
57  	/**
58  	 * The delimiter that is used to separate each part in the property name
59  	 * that makes the hierarchy. For example the property name 'windowX' under
60  	 * the property 'Panel1' becomes 'Panel1.windowX' and the dot between
61  	 * those names is the ExtendedProperties.DELIMITER
62  	 */
63  	public static final String DELIMITER = ".";
64  
65  	/**
66  	 * Creates a new ExtendedProperties object.
67  	 */
68  	public ExtendedProperties()
69  	{
70  		super();
71  	}
72  
73  	/**
74  	 * Creates a new ExtendedProperties object.
75  	 *
76  	 * @param defaults DOCUMENT ME!
77  	 */
78  	public ExtendedProperties(Properties defaults)
79  	{
80  		super(defaults);
81  	}
82  
83  	/**
84  	 * Convenience method that tries to return int value of property.
85  	 *
86  	 * @param key Name of key to query value for
87  	 *
88  	 * @return int type value of property
89  	 *
90  	 * @throws NumberFormatException
91  	 *
92  	 * @see #getProperty(String)
93  	 */
94  	public int getIntProperty(String key) throws NumberFormatException
95  	{
96  		String value = getProperty(key);
97  
98  		if (value == null) {
99  			throw new NumberFormatException("Cannot create int from null.");
100 		}
101 
102 		return Integer.parseInt(value);
103 	}
104 
105 	/**
106 	 * Convenience method that tries to return double value of property.
107 	 *
108 	 * @param key Name of key to query value for
109 	 *
110 	 * @return double type value of property
111 	 *
112 	 * @throws NumberFormatException
113 	 *
114 	 * @see #getProperty(String)
115 	 */
116 	public double getDoubleProperty(String key) throws NumberFormatException
117 	{
118 		String value = getProperty(key);
119 
120 		if (value == null) {
121 			throw new NumberFormatException("Cannot create double from null.");
122 		}
123 
124 		return Double.parseDouble(value);
125 	}
126 
127 	/**
128 	 * Convenience method that tries to return <code>Class</code> instace
129 	 * specified by fully qualified string.
130 	 *
131 	 * @param key Name of key associated with value.
132 	 *
133 	 * @return Instance of <code>Class</code> or null if not found.
134 	 *
135 	 * @see #getProperty(String)
136 	 */
137 	public Class getClassProperty(String key)
138 	{
139 		String value = getProperty(key);
140 
141 		if (value == null) {
142 			return null;
143 		}
144 
145 		Class c;
146 
147 		try {
148 			c = Class.forName(value);
149 		} catch (ClassNotFoundException e) {
150 			return null;
151 		}
152 
153 		return c;
154 	}
155 
156 	/**
157 	 * Returns an instance of the ExtendedProperties object which have only
158 	 * properties under the hierarchy given by <code>mementoName</code>. For
159 	 * example if this object has 'window.x', 'window.y' and  'something else'
160 	 * properties then invoking getProperties("window") will return
161 	 * ExtendedProperties with anly 'x' and 'y' properties.
162 	 *
163 	 * @param mementoName name to extract from this properties
164 	 *
165 	 * @return an ExtendedProperties object with properties matching
166 	 *         mementoName
167 	 */
168 	public ExtendedProperties getProperties(String mementoName)
169 	{
170 		assert (mementoName != null);
171 
172 		// calculate susbstring length that we will skip on ech key 
173 		int stripLen = mementoName.length() + DELIMITER.length();
174 		ExtendedProperties ep = new ExtendedProperties();
175 
176 		for (Enumeration e = keys(); e.hasMoreElements();) {
177 			String key = (String)e.nextElement();
178 
179 			if (!key.startsWith(mementoName)) {
180 				continue;
181 			}
182 
183 			ep.put(key.substring(stripLen), get(key));
184 		}
185 
186 		return ep;
187 	}
188 
189 	/**
190 	 * Inserts the content of the given ExtendedProperties to this properties
191 	 * by prefixing each key with given <code>mementoName</code>.
192 	 *
193 	 * @param mementoName
194 	 * @param ep
195 	 */
196 	public void setProperties(String mementoName, ExtendedProperties ep)
197 	{
198 		assert (ep != null);
199         
200         String prefix=mementoName+DELIMITER;
201         if (mementoName==null || mementoName.length()<1) {
202             prefix="";
203         }
204 
205 		for (Enumeration e = ep.keys(); e.hasMoreElements();) {
206 			String key = (String)e.nextElement();
207 			String newKey = prefix +  key;
208 			put(newKey, ep.get(key));
209 		}
210 	}
211     
212     /* (non-Javadoc)
213      * @see java.util.Properties#load(java.io.InputStream)
214      */
215     public synchronized void load(URL resource) throws IOException, MalformedURLException {
216         InputStream stream =resource.openStream();
217         super.load(stream);
218         checkForLinks(resource);
219         stream.close();
220     }
221     
222     /**
223      * @deprecated Use @link #load(URL) to process links properly
224      */
225     public synchronized void load(InputStream inStream) throws IOException {
226         super.load(inStream);
227     }
228     
229     public synchronized void checkForLinks(URL resource) throws IOException, MalformedURLException{
230             Map linksToAdd=null;
231             Iterator iter=entrySet().iterator();
232             while (iter.hasNext()) {
233                 Map.Entry entry = (Map.Entry) iter.next();
234                 String key=(String)entry.getKey();
235                 int lastDelIdx=key.lastIndexOf(ExtendedProperties.DELIMITER);
236                 String lastPart=key;
237                 if (lastDelIdx>=0) {
238                     lastPart=key.substring(lastDelIdx+1);
239                 }
240                 if (lastPart.startsWith(LINK_SUFFIX)) {
241                     String prefix="";
242                     if (lastDelIdx>0) {
243                         prefix=key.substring(0, lastDelIdx);
244                     }
245                 
246                     String linkPath=(String)entry.getValue();
247                     URL childURL=new URL(resource,linkPath);
248                     ExtendedProperties childProps=new ExtendedProperties();
249                     childProps.load(childURL);
250                     if (linksToAdd==null) {
251                         linksToAdd=new HashMap();
252                     }
253                     linksToAdd.put(prefix,childProps);
254                 }
255             }
256             if (linksToAdd!=null) {
257                 iter=linksToAdd.keySet().iterator();
258                 while(iter.hasNext()) {
259                     String prefix=(String)iter.next();
260                     ExtendedProperties childProps=(ExtendedProperties)linksToAdd.get(prefix);
261                     setProperties(prefix, childProps);
262                 }
263             }
264     }
265 }
266 
267 /* __oOo__ */