View Javadoc

1   /*
2    * $Id: VTimeZone.java [Apr 5, 2004]
3    *
4    * Copyright (c) 2004, Ben Fortuna
5    * All rights reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 	o Redistributions of source code must retain the above copyright
12   * notice, this list of conditions and the following disclaimer.
13   *
14   * 	o Redistributions in binary form must reproduce the above copyright
15   * notice, this list of conditions and the following disclaimer in the
16   * documentation and/or other materials provided with the distribution.
17   *
18   * 	o Neither the name of Ben Fortuna nor the names of any other contributors
19   * may be used to endorse or promote products derived from this software
20   * without specific prior written permission.
21   *
22   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25   * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
26   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   */
34  package net.fortuna.ical4j.model.component;
35  
36  import java.io.IOException;
37  import java.util.TimeZone;
38  
39  import net.fortuna.ical4j.data.BuilderException;
40  import net.fortuna.ical4j.data.CalendarBuilder;
41  import net.fortuna.ical4j.model.Calendar;
42  import net.fortuna.ical4j.model.Component;
43  import net.fortuna.ical4j.model.ComponentList;
44  import net.fortuna.ical4j.model.ParameterList;
45  import net.fortuna.ical4j.model.Property;
46  import net.fortuna.ical4j.model.PropertyList;
47  import net.fortuna.ical4j.model.ValidationException;
48  import net.fortuna.ical4j.model.property.DtStart;
49  import net.fortuna.ical4j.model.property.TzId;
50  import net.fortuna.ical4j.model.property.TzName;
51  import net.fortuna.ical4j.model.property.TzOffsetFrom;
52  import net.fortuna.ical4j.model.property.TzOffsetTo;
53  import net.fortuna.ical4j.util.PropertyValidator;
54  import net.fortuna.ical4j.util.TimeZoneUtils;
55  
56  import org.apache.commons.logging.Log;
57  import org.apache.commons.logging.LogFactory;
58  
59  /***
60   * Defines an iCalendar VTIMEZONE component.
61   *
62   * @author benf
63   */
64  public class VTimeZone extends Component {
65  
66      /***
67       * 'tzid' is required, but MUST NOT occur more than once
68       */
69      public static final String TZID = "TZID";
70  
71      /***
72       * 'last-mod' and 'tzurl' are optional, but MUST NOT occur more than once
73       */
74      public static final String LAST_MOD = "LAST-MOD";
75  
76      public static final String TZURL = "TZURL";
77  
78      private static Log log = LogFactory.getLog(VTimeZone.class);
79  
80      private ComponentList types;
81  
82      /***
83       * Constructor.
84       *
85       * @param aList
86       *            a list of properties
87       * @param cList
88       *            a list of timezone types
89       */
90      public VTimeZone(final PropertyList aList, final ComponentList cList) {
91  
92          super(VTIMEZONE, aList);
93  
94          this.types = cList;
95      }
96  
97      /***
98       * @see java.lang.Object#toString()
99       */
100     public final String toString() {
101 
102         return BEGIN + ":" + getName() + "\r\n" + getProperties() + types + END
103                 + ":" + getName() + "\r\n";
104     }
105 
106     /*
107      * (non-Javadoc)
108      *
109      * @see net.fortuna.ical4j.model.Component#validate(boolean)
110      */
111     public final void validate(boolean recurse) throws ValidationException {
112 
113         /*
114          * ; 'tzid' is required, but MUST NOT occur more ; than once
115          *
116          * tzid /
117          */
118         PropertyValidator.getInstance().validateOne(Property.TZID,
119                 getProperties());
120 
121         /*
122          * ; 'last-mod' and 'tzurl' are optional, but MUST NOT occur more than
123          * once last-mod / tzurl /
124          */
125         PropertyValidator.getInstance().validateOneOrLess(
126                 Property.LAST_MODIFIED, getProperties());
127         PropertyValidator.getInstance().validateOneOrLess(Property.TZURL,
128                 getProperties());
129 
130         /*
131          * ; one of 'standardc' or 'daylightc' MUST occur ..; and each MAY occur
132          * more than once.
133          *
134          * standardc / daylightc /
135          */
136         if (types.getComponent(Time.STANDARD) == null
137                 && types.getComponent(Time.DAYLIGHT) == null) { throw new ValidationException(
138                 "Sub-components [" + Time.STANDARD + "," + Time.DAYLIGHT
139                         + "] must be specified at least once"); }
140 
141         /*
142          * ; the following is optional, ; and MAY occur more than once
143          *
144          * x-prop
145          */
146         
147         if (recurse) {
148             validateProperties();
149         }
150     }
151 
152     /***
153      * Returns an instance of VTimeZone representing the user's default timezone.
154      * @return a VTimeZone
155      */
156     public static VTimeZone getDefault() {
157         return getVTimeZone(TimeZone.getDefault());
158     }
159 
160     /***
161      * Returns an instance of VTimeZone representing the specified Java timezone.
162      * @return a VTimeZone
163      */
164     public static VTimeZone getVTimeZone(final TimeZone timezone) {
165         try {
166             VTimeZone vTimezone = loadVTimeZone(timezone);
167 
168             if (vTimezone != null) {
169                 return vTimezone;
170             }
171         }
172         catch (Exception e) {
173             log.debug("Error loading VTimeZone", e);
174         }
175 
176 		return createVTimeZone(timezone);
177     }
178 
179     /***
180      * Loads an existing VTimeZone from the classpath corresponding
181      * to the specified Java timezone.
182      */
183     private static VTimeZone loadVTimeZone(final TimeZone timezone) throws IOException, BuilderException {
184         String resource = "/" + timezone.getID() + ".ics";
185 
186         CalendarBuilder builder = new CalendarBuilder();
187 
188         Calendar calendar = builder.build(VTimeZone.class.getResourceAsStream(resource));
189 
190         return (VTimeZone) calendar.getComponents().getComponent(Component.VTIMEZONE);
191 	}
192 
193     /***
194      * Creates a new VTimeZone based on the specified Java timezone.
195      */
196     private static VTimeZone createVTimeZone(final TimeZone timezone) {
197         TzId tzId = new TzId(null, timezone.getID());
198 
199         PropertyList tzProps = new PropertyList();
200         tzProps.add(tzId);
201 
202         ComponentList tzComponents = new ComponentList();
203 
204         TzName standardTzName = new TzName(new ParameterList(), timezone.getDisplayName());
205         DtStart standardTzStart = new DtStart(new ParameterList(), TimeZoneUtils.getDaylightEnd(timezone));
206         TzOffsetTo standardTzOffsetTo = new TzOffsetTo(new ParameterList(), timezone.getRawOffset());
207         TzOffsetFrom standardTzOffsetFrom = new TzOffsetFrom(null, timezone.getRawOffset() + timezone.getDSTSavings());
208 
209         PropertyList standardTzProps = new PropertyList();
210         standardTzProps.add(standardTzName);
211         standardTzProps.add(standardTzStart);
212         standardTzProps.add(standardTzOffsetTo);
213         standardTzProps.add(standardTzOffsetFrom);
214 
215         tzComponents.add(new Standard(standardTzProps));
216 
217         if (timezone.useDaylightTime()) {
218             TzName daylightTzName = new TzName(new ParameterList(), timezone.getDisplayName() + " (DST)");
219             DtStart daylightTzStart = new DtStart(new ParameterList(), TimeZoneUtils.getDaylightStart(timezone));
220             TzOffsetTo daylightTzOffsetTo = new TzOffsetTo(new ParameterList(), timezone.getRawOffset() + timezone.getDSTSavings());
221             TzOffsetFrom daylightTzOffsetFrom = new TzOffsetFrom(null, timezone.getRawOffset());
222 
223             PropertyList daylightTzProps = new PropertyList();
224             daylightTzProps.add(daylightTzName);
225             daylightTzProps.add(daylightTzStart);
226             daylightTzProps.add(daylightTzOffsetTo);
227             daylightTzProps.add(daylightTzOffsetFrom);
228 
229             tzComponents.add(new Daylight(daylightTzProps));
230         }
231 
232         return new VTimeZone(tzProps, tzComponents);
233 	}
234 }