View Javadoc

1   /*
2    * jSDP: A Java implementation of SDP protocol Copyright (C) 2007 Claudio Di
3    * Vita
4    */
5   package net.sourceforge.jsdp;
6   
7   import java.util.Date;
8   import java.util.Enumeration;
9   import java.util.Hashtable;
10  
11  import net.sourceforge.jsdp.util.TypedTime;
12  import net.sourceforge.jsdp.util.ZoneAdjustment;
13  
14  /**
15   * A <tt>TimeZone</tt> represents a <b>z=<i>&lt;field value&gt;</i></b>
16   * field contained in a SDP message. The timezone field allows the sender to
17   * specify a list of adjustment times and offsets from the base time.
18   * 
19   * @since 0.1.0
20   * 
21   * @version 1.0
22   * 
23   * @author <a href="mailto:cdivita@users.sourceforge.net">Claudio Di Vita</a>
24   */
25  public class TimeZone implements Field {
26  
27      /** The class Stream Unique Identifier, SUID */
28      private static final long serialVersionUID = -87926730273093503L;
29  
30      /** Indicates if the field will be output as a typed time or a number */
31      protected boolean isTyped;
32  
33      /** The map of timezone adjustments */
34      protected Hashtable adjustments;
35  
36      /**
37       * Creates a new <tt>TimeZone</tt>.
38       */
39      protected TimeZone() {
40  
41          super();
42  
43          adjustments = new Hashtable(3);
44      }
45  
46      /**
47       * Creates a new <tt>TimeZone</tt>.
48       * 
49       * @param time the adjustment time
50       * 
51       * @param offset the offset
52       * 
53       * @throws SDPException if the NTP representation of the adjustment time is
54       *         negative
55       */
56      public TimeZone(final Date time, final long offset) throws SDPException {
57  
58          this(new ZoneAdjustment(time, offset));
59      }
60  
61      /**
62       * Creates a new <tt>TimeZone</tt>.
63       * 
64       * @param adjustment the time zone adjustment
65       */
66      public TimeZone(final ZoneAdjustment adjustment) {
67  
68          this();
69  
70          addZoneAdjustment(adjustment);
71          this.isTyped = true;
72      }
73  
74      /**
75       * Parse an input string and constructs the equivalent timezone field.
76       * 
77       * @param field the string to parse
78       * 
79       * @return a new <tt>TimeZone</tt> instance
80       * 
81       * @throws SDPParseException if an error occurs while parsing
82       */
83      public static TimeZone parse(final String field) throws SDPParseException {
84  
85          if (!field.startsWith("z=")) {
86              throw new SDPParseException("The string \"" + field + "\" isn't a timezone field");
87          }
88  
89          String[] values = field.substring(2).split(" ");
90  
91          if (values.length < 2 || (values.length % 2 != 0)) {
92              throw new SDPParseException("The string \"" + field + "\" isn't a valid timezone field");
93          }
94  
95          TimeZone z = new TimeZone();
96  
97          for (int i = 0; i < values.length; i += 2) {
98              try {
99                  z.addZoneAdjustment(new ZoneAdjustment(Long.parseLong(values[i]), TypedTime.getTime(values[i + 1])));
100             }
101             catch (Exception parseException) {
102                 throw new SDPParseException("The string \"" + field + "\" isn't a valid timezone field", parseException);
103             }
104         }
105 
106         return z;
107     }
108 
109     /**
110      * Add a zone adjustment to the field.
111      * 
112      * @param time the adjustment time
113      * @param offset the offset
114      * 
115      * @throws SDPException if the NTP representation of the adjustment time is
116      *         negative
117      */
118     public void addZoneAdjustment(final Date time, final long offset) throws SDPException {
119 
120         adjustments.put(time, new ZoneAdjustment(time, offset));
121     }
122 
123     /**
124      * Add a zone adjustment to the field.
125      * 
126      * @param adjustment the time zone adjustment
127      */
128     public void addZoneAdjustment(final ZoneAdjustment adjustment) {
129 
130         adjustments.put(new Date(adjustment.getTime()), adjustment);
131     }
132 
133     /**
134      * Returns a clone of this field.
135      * 
136      * @return a clone of this field
137      */
138     public Object clone() {
139 
140         TimeZone field = new TimeZone();
141 
142         field.isTyped = this.isTyped;
143         field.adjustments = (Hashtable) this.adjustments.clone();
144 
145         return field;
146     }
147 
148     /**
149      * Returns the type character for the field.
150      * 
151      * @return the field type character: <tt>z</t>
152      */
153     public char getType() {
154 
155         return Field.TIMEZONE_FIELD;
156     }
157 
158     /*
159      * <p>Returns a Map of adjustment times, where :</p>
160      * 
161      * <ul> <li>key = {@link java.util.Date}</li> <li>value =
162      * {@link ZoneAdjustment}</li> </ul>
163      * 
164      * @return The time zone adjustments
165      */
166     /*
167      * public Map getZoneAdjustments() {
168      * 
169      * return adjustments; }
170      */
171 
172     /**
173      * Returns whether the field will be output as a typed time or a number.
174      * 
175      * <p>
176      * Typed time is formatted as an number followed by a unit character: the
177      * unit indicates an appropriate multiplier for the number. The following
178      * unit types are allowed:
179      * </p>
180      * <ul>
181      * <li><tt><b>d</b></tt> - days (86400 seconds)</li>
182      * <li><tt><b>h</b></tt> - hours (3600 seconds)</li>
183      * <li><tt><b>m</b></tt> - minutes (60 seconds)</li>
184      * <li><tt><b>s</b></tt> - seconds (1 second)</li>
185      * </ul>
186      * 
187      * @return <tt>true</tt> if the field will be output as a typed time,
188      *         <tt>false</tt> if as a number
189      */
190     public boolean isTypedTime() {
191 
192         return isTyped;
193     }
194 
195     /**
196      * Sets whether the field will be output as a typed time or a number.
197      * 
198      * <p>
199      * Typed time is formatted as an number followed by a unit character: the
200      * unit indicates an appropriate multiplier for the number. The following
201      * unit types are allowed:
202      * </p>
203      * <ul>
204      * <li><tt><b>d</b></tt> - days (86400 seconds)</li>
205      * <li><tt><b>h</b></tt> - hours (3600 seconds)</li>
206      * <li><tt><b>m</b></tt> - minutes (60 seconds)</li>
207      * <li><tt><b>s</b></tt> - seconds (1 second)</li>
208      * </ul>
209      */
210     public void setTypedTime(final boolean typedTime) {
211 
212         this.isTyped = typedTime;
213     }
214 
215     /**
216      * Returns a string representation of the field. The representation has the
217      * form: <b>z=<i>&lt;time&gt;</i> <i>&lt;offset&gt;</i>+
218      * 
219      * @return The string representation of the field
220      */
221     public String toString() {
222 
223         StringBuffer result = new StringBuffer(getType() + "=");
224         ZoneAdjustment adjustment;
225         Enumeration values = adjustments.elements();
226         while (values.hasMoreElements()) {
227 
228             adjustment = (ZoneAdjustment) values.nextElement();
229 
230             result.append(adjustment.getTime() + " ");
231             if (this.isTyped) {
232                 result.append(TypedTime.toString(adjustment.getOffset()) + " ");
233             }
234             else {
235                 result.append(adjustment.getOffset() + " ");
236             }
237         }
238         result.deleteCharAt(result.length() - 1);
239 
240         return result.toString();
241     }
242 }