KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > xml > UtilReader


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.util.xml;
11
12 import java.util.*;
13 import java.net.URL JavaDoc;
14 import java.io.IOException JavaDoc;
15 import org.mmbase.util.*;
16 import org.mmbase.util.logging.*;
17 import org.w3c.dom.Element JavaDoc;
18 /**
19  * This class reads configuration files for utilities, that are
20  * placed in /config/utils/.
21  *
22  * A typical way to use it may be like so:
23  <pre>
24     private UtilReader.PropertiesMap utilProperties = new UtilReader("myutil.xml", new Runnable() { public void run() { init();}}).getProperties();
25     private void init() {
26       // use utilProperties
27     }
28     {
29       init();
30     }
31  </pre>
32  * This produces a 'watched map' utilProperties. Every time the underlying config file(s) are changed 'init' is called. Init is called on instantation of the surrounding class too.
33  *
34  * @since MMBase-1.6.4
35  * @author Rob Vermeulen
36  * @author Michiel Meeuwissen
37  * @version $Id: UtilReader.java,v 1.25 2006/07/15 10:52:05 michiel Exp $
38  */

39 public class UtilReader {
40
41     private static final Logger log = Logging.getLoggerInstance(UtilReader.class);
42
43     public static final String JavaDoc CONFIG_UTILS = "utils";
44
45     /** Public ID of the Utilities config DTD version 1.0 */
46     public static final String JavaDoc PUBLIC_ID_UTIL_1_0 = "-//MMBase//DTD util config 1.0//EN";
47     /** DTD resource filename of the Utilities config DTD version 1.0 */
48     public static final String JavaDoc DTD_UTIL_1_0 = "util_1_0.dtd";
49
50     /** Public ID of the most recent Utilities config DTD */
51     public static final String JavaDoc PUBLIC_ID_UTIL = PUBLIC_ID_UTIL_1_0;
52     /** DTD respource filename of the most recent Utilities config DTD */
53     public static final String JavaDoc DTD_UTIL = DTD_UTIL_1_0;
54
55     /**
56      * Register the Public Ids for DTDs used by UtilReader
57      * This method is called by XMLEntityResolver.
58      */

59     public static void registerPublicIDs() {
60         XMLEntityResolver.registerPublicID(PUBLIC_ID_UTIL_1_0, DTD_UTIL_1_0, UtilReader.class);
61     }
62
63     private static final Map utilReaders = new HashMap(); // file-name -> utilreader
64

65     /**
66      * Returns a UtilReader for the given fileName. When you use this, the UtilReader instance will be cached.
67      *
68      * @since MMBase-1.8
69      */

70
71     public static UtilReader get(String JavaDoc fileName) {
72         UtilReader utilReader = (UtilReader) utilReaders.get(fileName);
73         if (utilReader == null) {
74             synchronized(utilReaders) {
75                 utilReader = new UtilReader(fileName);
76                 utilReaders.put(fileName, utilReader);
77             }
78         }
79         return utilReader;
80     }
81
82     static {
83         // doesnt startup, probably because of cyclic referecnes, if this happens in DocumentReader itself.
84
DocumentReader.utilProperties = UtilReader.get("documentreader.xml").getProperties();
85
86     }
87
88     private class UtilFileWatcher extends ResourceWatcher {
89         private ResourceWatcher wrappedWatcher;
90         public UtilFileWatcher(ResourceWatcher f) {
91             super(); // true: keep reading.
92
wrappedWatcher = f;
93         }
94
95         public void onChange(String JavaDoc f) {
96             readProperties(f);
97             if (wrappedWatcher != null) {
98                 wrappedWatcher.onChange(f);
99             }
100         }
101     }
102
103     private final Map properties = new HashMap();
104     private final ResourceWatcher watcher;
105     private final String JavaDoc file;
106
107
108     /**
109      * Instantiates a UtilReader for a given configuration file in <config>/utils. If the configuration file is used on more spots, then you may consider
110      * using the static method {@link #get(String)} in stead.
111      *
112      * @param fileName The name of the property file (e.g. httppost.xml).
113      */

114     public UtilReader(String JavaDoc fileName) {
115         file = CONFIG_UTILS + "/" + fileName;
116         readProperties(file);
117         watcher = new UtilFileWatcher(null);
118         watcher.add(file);
119         watcher.start();
120
121     }
122     /**
123      * Produces a UtilReader for the given resource name.
124      * @param fileName a Resource name relative to config/utils
125      * @param w A unstarted ResourceWatcher without files. (It will be only be called from the
126      * filewatcher in this reader). It defines what must happen if something changes in the util's
127      * configuration. Since you probably don't need the resource name for that any more, you
128      * can also simply use {@link #UtilReader(String, Runnable)}
129      * @since MMBase-1.8
130      */

131     public UtilReader(String JavaDoc fileName, ResourceWatcher w) {
132         file = CONFIG_UTILS + "/" + fileName;
133         readProperties(file);
134         watcher = new UtilFileWatcher(w);
135         watcher.add(file);
136         watcher.start();
137
138     }
139     /**
140      * Produces a UtilReader for the given resource name.
141      * @param resourceName a Resource name relative to config/utils
142      * @param onChange A Runnable defining what must happen if something changes.
143      * @since MMBase-1.8
144      */

145     public UtilReader(String JavaDoc resourceName, final Runnable JavaDoc onChange) {
146         this(resourceName, new ResourceWatcher() {
147                 public void onChange(String JavaDoc name) {
148                     onChange.run();
149                 }
150             }
151              );
152     }
153
154     public void finalize() {
155         if (watcher != null) watcher.exit();
156     }
157
158     /**
159      * Get the properties of this utility.
160      */

161     public PropertiesMap getProperties() {
162         return new PropertiesMap(properties);
163     }
164
165     /**
166      * Reports whether the configured resource (in the constructor) is actually backed. If not,
167      * getProperties will certainly return an empty Map.
168      * @since MMBase-1.8.1
169      */

170     public boolean resourceAvailable() {
171         try {
172             return ResourceLoader.getConfigurationRoot().getResource(file).openConnection().getDoInput();
173         } catch (IOException JavaDoc io) {
174             return false;
175         }
176     }
177
178     protected void readProperties(String JavaDoc s) {
179         properties.clear();
180
181         ResourceLoader configLoader = ResourceLoader.getConfigurationRoot();
182         List configList = configLoader.getResourceList(s);
183         Iterator configs = configList.iterator();
184         while (configs.hasNext()) {
185             URL JavaDoc url = (URL JavaDoc) configs.next();
186             org.xml.sax.InputSource JavaDoc is;
187             try {
188                 is = ResourceLoader.getInputSource(url);
189             } catch (IOException JavaDoc ioe) {
190                 // input source does not exist
191
log.debug(ioe.getMessage() + " for " + url);
192                 continue;
193             }
194             if (is != null) {
195                 log.debug("Reading " + url);
196                 DocumentReader reader = new DocumentReader(is, UtilReader.class);
197                 Element JavaDoc e = reader.getElementByPath("util.properties");
198                 if (e != null) {
199                     for (Iterator iter = reader.getChildElements(e, "property"); iter.hasNext();) {
200                         Element JavaDoc p = (Element JavaDoc) iter.next();
201                         String JavaDoc name = reader.getElementAttributeValue(p, "name");
202                         String JavaDoc type = reader.getElementAttributeValue(p, "type");
203                         if (type.equals("map")) {
204                             Collection entryList = new ArrayList();
205
206                             for (Iterator entriesIter = reader.getChildElements(p, "entry"); entriesIter.hasNext();) {
207                                 Element JavaDoc entry = (Element JavaDoc) entriesIter.next();
208                                 String JavaDoc key = null;
209                                 String JavaDoc value = null;
210
211                                 for (Iterator en = reader.getChildElements(entry, "*"); en.hasNext();) {
212                                     Element JavaDoc keyorvalue = (Element JavaDoc) en.next();
213                                     if (keyorvalue.getTagName().equals("key")) {
214                                         key = reader.getElementValue(keyorvalue);
215                                     } else {
216                                         value = reader.getElementValue(keyorvalue);
217                                     }
218                                 }
219                                 if (key != null && value != null) {
220                                     entryList.add(new Entry(key, value));
221                                 }
222                             }
223                             if (properties.containsKey(name)) {
224                                 log.service("Property '" + name + "'(" + entryList + "') of " + url + " is shadowed");
225                             } else {
226                                 properties.put(name, entryList);
227                             }
228                         } else {
229                             String JavaDoc value = reader.getElementValue(p);
230                             if (properties.containsKey(name)) {
231                                 log.service("Property '" + name + "'(" + value + "') of " + url + " is shadowed");
232                             } else {
233                                 properties.put(name, value);
234                             }
235                         }
236                     }
237                 }
238             } else {
239                 log.debug("Resource " + s + " does not exist");
240             }
241         }
242         if (properties.size() == 0) {
243             log.service("No properties read from " + configList);
244         } else {
245             log.service("Read " + properties.keySet() + " from " + configList);
246         }
247     }
248
249     /**
250      * A unmodifiable Map, with extra 'Properties'-like methods. The entries of this Map are
251      * typically backed by the resources of an UtilReader (and the Map dynamically changes if the
252      * resources change).
253      * @since MMBase-1.8
254      */

255
256     public static class PropertiesMap extends AbstractMap {
257
258         private final Map wrappedMap;
259
260         /**
261          * Creates an empty Map (not very useful since this Map is unmodifiable).
262          */

263         public PropertiesMap() {
264             wrappedMap = new HashMap();
265         }
266
267         /**
268          * Wrapping the given map.
269          */

270         public PropertiesMap(Map map) {
271             wrappedMap = map;
272         }
273         /**
274          * {@inheritDoc}
275          */

276         public Set entrySet() {
277             return new EntrySet();
278
279         }
280
281         /**
282          * Returns the object mapped with 'key', or defaultValue if there is none.
283          */

284         public Object JavaDoc getProperty(Object JavaDoc key, Object JavaDoc defaultValue) {
285             Object JavaDoc result = get(key);
286             return result == null ? defaultValue : result;
287         }
288
289         private class EntrySet extends AbstractSet {
290             EntrySet() {}
291             public int size() {
292                 return PropertiesMap.this.wrappedMap.size();
293             }
294             public Iterator iterator() {
295                 return new EntrySetIterator();
296             }
297         }
298         private class EntrySetIterator implements Iterator {
299             private Iterator i;
300             EntrySetIterator() {
301                 i = PropertiesMap.this.wrappedMap.entrySet().iterator();
302             }
303             public boolean hasNext() {
304                 return i.hasNext();
305             }
306             public Object JavaDoc next() {
307                 return i.next();
308             }
309             public void remove() {
310                 throw new UnsupportedOperationException JavaDoc("Unmodifiable");
311             }
312         }
313     }
314
315 }
316
Popular Tags