KickJava   Java API By Example, From Geeks To Geeks.

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


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 org.joda.time.DateTimeZone;
19
20 /**
21  * Improves the performance of requesting time zone offsets and name keys by
22  * caching the results. Time zones that have simple rules or are fixed should
23  * not be cached, as it is unlikely to improve performance.
24  * <p>
25  * CachedDateTimeZone is thread-safe and immutable.
26  *
27  * @author Brian S O'Neill
28  * @since 1.0
29  */

30 public class CachedDateTimeZone extends DateTimeZone {
31
32     private static final long serialVersionUID = 5472298452022250685L;
33
34     private static final int cInfoCacheMask;
35
36     static {
37         Integer JavaDoc i;
38         try {
39             i = Integer.getInteger("org.joda.time.tz.CachedDateTimeZone.size");
40         } catch (SecurityException JavaDoc e) {
41             i = null;
42         }
43
44         int cacheSize;
45         if (i == null) {
46             // With a cache size of 512, dates that lie within any 69.7 year
47
// period have no cache collisions.
48
cacheSize = 512; // (1 << 9)
49
} else {
50             cacheSize = i.intValue();
51             // Ensure cache size is even power of 2.
52
cacheSize--;
53             int shift = 0;
54             while (cacheSize > 0) {
55                 shift++;
56                 cacheSize >>= 1;
57             }
58             cacheSize = 1 << shift;
59         }
60
61         cInfoCacheMask = cacheSize - 1;
62     }
63
64     /**
65      * Returns a new CachedDateTimeZone unless given zone is already cached.
66      */

67     public static CachedDateTimeZone forZone(DateTimeZone zone) {
68         if (zone instanceof CachedDateTimeZone) {
69             return (CachedDateTimeZone)zone;
70         }
71         return new CachedDateTimeZone(zone);
72     }
73
74     /*
75      * Caching is performed by breaking timeline down into periods of 2^32
76      * milliseconds, or about 49.7 days. A year has about 7.3 periods, usually
77      * with only 2 time zone offset periods. Most of the 49.7 day periods will
78      * have no transition, about one quarter have one transition, and very rare
79      * cases have multiple transitions.
80      */

81
82     private final DateTimeZone iZone;
83
84     private transient Info[] iInfoCache;
85
86     private CachedDateTimeZone(DateTimeZone zone) {
87         super(zone.getID());
88         iZone = zone;
89         iInfoCache = new Info[cInfoCacheMask + 1];
90     }
91
92     private void readObject(java.io.ObjectInputStream JavaDoc in)
93         throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc
94     {
95         in.defaultReadObject();
96         iInfoCache = new Info[cInfoCacheMask + 1];
97     }
98
99     /**
100      * Returns the DateTimeZone being wrapped.
101      */

102     public DateTimeZone getUncachedZone() {
103         return iZone;
104     }
105
106     public String JavaDoc getNameKey(long instant) {
107         return getInfo(instant).getNameKey(instant);
108     }
109
110     public int getOffset(long instant) {
111         return getInfo(instant).getOffset(instant);
112     }
113
114     public int getStandardOffset(long instant) {
115         return getInfo(instant).getStandardOffset(instant);
116     }
117
118     public boolean isFixed() {
119         return iZone.isFixed();
120     }
121
122     public long nextTransition(long instant) {
123         return iZone.nextTransition(instant);
124     }
125
126     public long previousTransition(long instant) {
127         return iZone.previousTransition(instant);
128     }
129
130     public int hashCode() {
131         return iZone.hashCode();
132     }
133
134     public boolean equals(Object JavaDoc obj) {
135         if (this == obj) {
136             return true;
137         }
138         if (obj instanceof CachedDateTimeZone) {
139             return iZone.equals(((CachedDateTimeZone)obj).iZone);
140         }
141         return false;
142     }
143
144     // Although accessed by multiple threads, this method doesn't need to be
145
// synchronized.
146

147     private Info getInfo(long millis) {
148         int period = (int)(millis >> 32);
149         Info[] cache = iInfoCache;
150         int index = period & cInfoCacheMask;
151         Info info = cache[index];
152         if (info == null || (int)((info.iPeriodStart >> 32)) != period) {
153             info = createInfo(millis);
154             cache[index] = info;
155         }
156         return info;
157     }
158
159     private Info createInfo(long millis) {
160         long periodStart = millis & (0xffffffffL << 32);
161         Info info = new Info(iZone, periodStart);
162         
163         long end = periodStart | 0xffffffffL;
164         Info chain = info;
165         while (true) {
166             long next = iZone.nextTransition(periodStart);
167             if (next == periodStart || next > end) {
168                 break;
169             }
170             periodStart = next;
171             chain = (chain.iNextInfo = new Info(iZone, periodStart));
172         }
173
174         return info;
175     }
176
177     private final static class Info {
178         // For first Info in chain, iPeriodStart's lower 32 bits are clear.
179
public final long iPeriodStart;
180         public final DateTimeZone iZoneRef;
181
182         Info iNextInfo;
183
184         private String JavaDoc iNameKey;
185         private int iOffset = Integer.MIN_VALUE;
186         private int iStandardOffset = Integer.MIN_VALUE;
187
188         Info(DateTimeZone zone, long periodStart) {
189             iPeriodStart = periodStart;
190             iZoneRef = zone;
191         }
192
193         public String JavaDoc getNameKey(long millis) {
194             if (iNextInfo == null || millis < iNextInfo.iPeriodStart) {
195                 if (iNameKey == null) {
196                     iNameKey = iZoneRef.getNameKey(iPeriodStart);
197                 }
198                 return iNameKey;
199             }
200             return iNextInfo.getNameKey(millis);
201         }
202
203         public int getOffset(long millis) {
204             if (iNextInfo == null || millis < iNextInfo.iPeriodStart) {
205                 if (iOffset == Integer.MIN_VALUE) {
206                     iOffset = iZoneRef.getOffset(iPeriodStart);
207                 }
208                 return iOffset;
209             }
210             return iNextInfo.getOffset(millis);
211         }
212
213         public int getStandardOffset(long millis) {
214             if (iNextInfo == null || millis < iNextInfo.iPeriodStart) {
215                 if (iStandardOffset == Integer.MIN_VALUE) {
216                     iStandardOffset = iZoneRef.getStandardOffset(iPeriodStart);
217                 }
218                 return iStandardOffset;
219             }
220             return iNextInfo.getStandardOffset(millis);
221         }
222     }
223 }
224
Popular Tags