KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > joda > time > tz > ZoneInfoProvider


1 /*
2  * Copyright 2001-2005 Stephen Colebourne
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.joda.time.tz;
17
18 import java.io.DataInputStream JavaDoc;
19 import java.io.File JavaDoc;
20 import java.io.FileInputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.lang.ref.SoftReference JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.Set JavaDoc;
27 import java.util.TreeMap JavaDoc;
28
29 import org.joda.time.DateTimeZone;
30
31 /**
32  * ZoneInfoProvider loads compiled data files as generated by
33  * {@link ZoneInfoCompiler}.
34  * <p>
35  * ZoneInfoProvider is thread-safe and publicly immutable.
36  *
37  * @author Brian S O'Neill
38  * @since 1.0
39  */

40 public class ZoneInfoProvider implements Provider {
41
42     /** The directory where the files are held. */
43     private final File JavaDoc iFileDir;
44     /** The resource path. */
45     private final String JavaDoc iResourcePath;
46     /** The class loader to use. */
47     private final ClassLoader JavaDoc iLoader;
48     /** Maps ids to strings or SoftReferences to DateTimeZones. */
49     private final Map JavaDoc iZoneInfoMap;
50
51     /**
52      * ZoneInfoProvider searches the given directory for compiled data files.
53      *
54      * @throws IOException if directory or map file cannot be read
55      */

56     public ZoneInfoProvider(File JavaDoc fileDir) throws IOException JavaDoc {
57         if (fileDir == null) {
58             throw new IllegalArgumentException JavaDoc("No file directory provided");
59         }
60         if (!fileDir.exists()) {
61             throw new IOException JavaDoc("File directory doesn't exist: " + fileDir);
62         }
63         if (!fileDir.isDirectory()) {
64             throw new IOException JavaDoc("File doesn't refer to a directory: " + fileDir);
65         }
66
67         iFileDir = fileDir;
68         iResourcePath = null;
69         iLoader = null;
70
71         iZoneInfoMap = loadZoneInfoMap(openResource("ZoneInfoMap"));
72     }
73
74     /**
75      * ZoneInfoProvider searches the given ClassLoader resource path for
76      * compiled data files. Resources are loaded from the ClassLoader that
77      * loaded this class.
78      *
79      * @throws IOException if directory or map file cannot be read
80      */

81     public ZoneInfoProvider(String JavaDoc resourcePath) throws IOException JavaDoc {
82         this(resourcePath, null, false);
83     }
84
85     /**
86      * ZoneInfoProvider searches the given ClassLoader resource path for
87      * compiled data files.
88      *
89      * @param loader ClassLoader to load compiled data files from. If null,
90      * use system ClassLoader.
91      * @throws IOException if directory or map file cannot be read
92      */

93     public ZoneInfoProvider(String JavaDoc resourcePath, ClassLoader JavaDoc loader)
94         throws IOException JavaDoc
95     {
96         this(resourcePath, loader, true);
97     }
98
99     /**
100      * @param favorSystemLoader when true, use the system class loader if
101      * loader null. When false, use the current class loader if loader is null.
102      */

103     private ZoneInfoProvider(String JavaDoc resourcePath,
104                              ClassLoader JavaDoc loader, boolean favorSystemLoader)
105         throws IOException JavaDoc
106     {
107         if (resourcePath == null) {
108             throw new IllegalArgumentException JavaDoc("No resource path provided");
109         }
110         if (!resourcePath.endsWith("/")) {
111             resourcePath += '/';
112         }
113
114         iFileDir = null;
115         iResourcePath = resourcePath;
116
117         if (loader == null && !favorSystemLoader) {
118             loader = getClass().getClassLoader();
119         }
120
121         iLoader = loader;
122
123         iZoneInfoMap = loadZoneInfoMap(openResource("ZoneInfoMap"));
124     }
125
126     //-----------------------------------------------------------------------
127
/**
128      * If an error is thrown while loading zone data, uncaughtException is
129      * called to log the error and null is returned for this and all future
130      * requests.
131      *
132      * @param id the id to load
133      * @return the loaded zone
134      */

135     public synchronized DateTimeZone getZone(String JavaDoc id) {
136         if (id == null) {
137             return null;
138         }
139
140         Object JavaDoc obj = iZoneInfoMap.get(id);
141         if (obj == null) {
142             return null;
143         }
144
145         if (id.equals(obj)) {
146             // Load zone data for the first time.
147
return loadZoneData(id);
148         }
149
150         if (obj instanceof SoftReference JavaDoc) {
151             DateTimeZone tz = (DateTimeZone)((SoftReference JavaDoc)obj).get();
152             if (tz != null) {
153                 return tz;
154             }
155             // Reference cleared; load data again.
156
return loadZoneData(id);
157         }
158
159         // If this point is reached, mapping must link to another.
160
return getZone((String JavaDoc)obj);
161     }
162
163     /**
164      * Gets a list of all the available zone ids.
165      *
166      * @return the zone ids
167      */

168     public synchronized Set JavaDoc getAvailableIDs() {
169         return Collections.unmodifiableSet(iZoneInfoMap.keySet());
170     }
171
172     /**
173      * Called if an exception is thrown from getZone while loading zone data.
174      *
175      * @param ex the exception
176      */

177     protected void uncaughtException(Exception JavaDoc ex) {
178         Thread JavaDoc t = Thread.currentThread();
179         t.getThreadGroup().uncaughtException(t, ex);
180     }
181
182     /**
183      * Opens a resource from file or classpath.
184      *
185      * @param name the name to open
186      * @return the input stream
187      * @throws IOException if an error occurs
188      */

189     private InputStream JavaDoc openResource(String JavaDoc name) throws IOException JavaDoc {
190         InputStream JavaDoc in;
191         if (iFileDir != null) {
192             in = new FileInputStream JavaDoc(new File JavaDoc(iFileDir, name));
193         } else {
194             String JavaDoc path = iResourcePath.concat(name);
195             if (iLoader != null) {
196                 in = iLoader.getResourceAsStream(path);
197             } else {
198                 in = ClassLoader.getSystemResourceAsStream(path);
199             }
200             if (in == null) {
201                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc(40)
202                     .append("Resource not found: \"")
203                     .append(path)
204                     .append("\" ClassLoader: ")
205                     .append(iLoader != null ? iLoader.toString() : "system");
206                 throw new IOException JavaDoc(buf.toString());
207             }
208         }
209         return in;
210     }
211
212     /**
213      * Loads the time zone data for one id.
214      *
215      * @param id the id to load
216      * @return the zone
217      */

218     private DateTimeZone loadZoneData(String JavaDoc id) {
219         InputStream JavaDoc in = null;
220         try {
221             in = openResource(id);
222             DateTimeZone tz = DateTimeZoneBuilder.readFrom(in, id);
223             iZoneInfoMap.put(id, new SoftReference JavaDoc(tz));
224             return tz;
225         } catch (IOException JavaDoc e) {
226             uncaughtException(e);
227             iZoneInfoMap.remove(id);
228             return null;
229         } finally {
230             try {
231                 if (in != null) {
232                     in.close();
233                 }
234             } catch (IOException JavaDoc e) {
235             }
236         }
237     }
238
239     //-----------------------------------------------------------------------
240
/**
241      * Loads the zone info map.
242      *
243      * @param in the input stream
244      * @return the map
245      */

246     private static Map JavaDoc loadZoneInfoMap(InputStream JavaDoc in) throws IOException JavaDoc {
247         Map JavaDoc map = new TreeMap JavaDoc(String.CASE_INSENSITIVE_ORDER);
248         DataInputStream JavaDoc din = new DataInputStream JavaDoc(in);
249         try {
250             readZoneInfoMap(din, map);
251         } finally {
252             try {
253                 din.close();
254             } catch (IOException JavaDoc e) {
255             }
256         }
257         map.put("UTC", new SoftReference JavaDoc(DateTimeZone.UTC));
258         return map;
259     }
260
261     /**
262      * Reads the zone info map from file.
263      *
264      * @param din the input stream
265      * @param zimap gets filled with string id to string id mappings
266      */

267     private static void readZoneInfoMap(DataInputStream JavaDoc din, Map JavaDoc zimap) throws IOException JavaDoc {
268         // Read the string pool.
269
int size = din.readUnsignedShort();
270         String JavaDoc[] pool = new String JavaDoc[size];
271         for (int i=0; i<size; i++) {
272             pool[i] = din.readUTF().intern();
273         }
274
275         // Read the mappings.
276
size = din.readUnsignedShort();
277         for (int i=0; i<size; i++) {
278             try {
279                 zimap.put(pool[din.readUnsignedShort()], pool[din.readUnsignedShort()]);
280             } catch (ArrayIndexOutOfBoundsException JavaDoc e) {
281                 throw new IOException JavaDoc("Corrupt zone info map");
282             }
283         }
284     }
285
286 }
287
Popular Tags