EMMA Coverage Report (generated Tue Oct 28 00:01:11 GMT 2008)
[all classes][org.joda.time.tz]

COVERAGE SUMMARY FOR SOURCE FILE [CachedDateTimeZone.java]

nameclass, %method, %block, %line, %
CachedDateTimeZone.java100% (2/2)95%  (18/19)89%  (271/304)83%  (64/77)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class CachedDateTimeZone100% (1/1)93%  (14/15)84%  (173/206)77%  (43/56)
readObject (ObjectInputStream): void 0%   (0/1)0%   (0/9)0%   (0/3)
<static initializer> 100% (1/1)40%  (14/35)40%  (6/15)
forZone (DateTimeZone): CachedDateTimeZone 100% (1/1)73%  (8/11)67%  (2/3)
CachedDateTimeZone (DateTimeZone): void 100% (1/1)100% (14/14)100% (4/4)
createInfo (long): CachedDateTimeZone$Info 100% (1/1)100% (46/46)100% (10/10)
equals (Object): boolean 100% (1/1)100% (17/17)100% (5/5)
getInfo (long): CachedDateTimeZone$Info 100% (1/1)100% (35/35)100% (8/8)
getNameKey (long): String 100% (1/1)100% (6/6)100% (1/1)
getOffset (long): int 100% (1/1)100% (6/6)100% (1/1)
getStandardOffset (long): int 100% (1/1)100% (6/6)100% (1/1)
getUncachedZone (): DateTimeZone 100% (1/1)100% (3/3)100% (1/1)
hashCode (): int 100% (1/1)100% (4/4)100% (1/1)
isFixed (): boolean 100% (1/1)100% (4/4)100% (1/1)
nextTransition (long): long 100% (1/1)100% (5/5)100% (1/1)
previousTransition (long): long 100% (1/1)100% (5/5)100% (1/1)
     
class CachedDateTimeZone$Info100% (1/1)100% (4/4)100% (98/98)100% (21/21)
CachedDateTimeZone$Info (DateTimeZone, long): void 100% (1/1)100% (15/15)100% (6/6)
getNameKey (long): String 100% (1/1)100% (27/27)100% (5/5)
getOffset (long): int 100% (1/1)100% (28/28)100% (5/5)
getStandardOffset (long): int 100% (1/1)100% (28/28)100% (5/5)

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 */
16package org.joda.time.tz;
17 
18import 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 */
30public class CachedDateTimeZone extends DateTimeZone {
31 
32    private static final long serialVersionUID = 5472298452022250685L;
33 
34    private static final int cInfoCacheMask;
35 
36    static {
37        Integer i;
38        try {
39            i = Integer.getInteger("org.joda.time.tz.CachedDateTimeZone.size");
40        } catch (SecurityException 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 in)
93        throws java.io.IOException, ClassNotFoundException
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 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 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 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 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}

[all classes][org.joda.time.tz]
EMMA 2.0.5312 (C) Vladimir Roubtsov