|
1 /** |
|
2 * Copyright (c) 2012, Ben Fortuna |
|
3 * All rights reserved. |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions |
|
7 * are met: |
|
8 * |
|
9 * o Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * |
|
12 * o Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * o Neither the name of Ben Fortuna nor the names of any other contributors |
|
17 * may be used to endorse or promote products derived from this software |
|
18 * without specific prior written permission. |
|
19 * |
|
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
31 */ |
|
32 package net.fortuna.ical4j.model; |
|
33 |
|
34 import java.io.IOException; |
|
35 import java.io.Serializable; |
|
36 import java.net.URISyntaxException; |
|
37 import java.text.ParseException; |
|
38 import java.util.Iterator; |
|
39 |
|
40 import net.fortuna.ical4j.model.component.CalendarComponent; |
|
41 import net.fortuna.ical4j.model.property.CalScale; |
|
42 import net.fortuna.ical4j.model.property.Method; |
|
43 import net.fortuna.ical4j.model.property.ProdId; |
|
44 import net.fortuna.ical4j.model.property.Version; |
|
45 import net.fortuna.ical4j.model.property.XProperty; |
|
46 import net.fortuna.ical4j.util.CompatibilityHints; |
|
47 import net.fortuna.ical4j.util.ComponentValidator; |
|
48 import net.fortuna.ical4j.util.PropertyValidator; |
|
49 import net.fortuna.ical4j.util.Strings; |
|
50 |
|
51 import org.apache.commons.lang.builder.EqualsBuilder; |
|
52 import org.apache.commons.lang.builder.HashCodeBuilder; |
|
53 |
|
54 /** |
|
55 * $Id$ [Apr 5, 2004] |
|
56 * |
|
57 * Defines an iCalendar calendar. |
|
58 * |
|
59 * <pre> |
|
60 * 4.6 Calendar Components |
|
61 * |
|
62 * The body of the iCalendar object consists of a sequence of calendar |
|
63 * properties and one or more calendar components. The calendar |
|
64 * properties are attributes that apply to the calendar as a whole. The |
|
65 * calendar components are collections of properties that express a |
|
66 * particular calendar semantic. For example, the calendar component can |
|
67 * specify an event, a to-do, a journal entry, time zone information, or |
|
68 * free/busy time information, or an alarm. |
|
69 * |
|
70 * The body of the iCalendar object is defined by the following |
|
71 * notation: |
|
72 * |
|
73 * icalbody = calprops component |
|
74 * |
|
75 * calprops = 2*( |
|
76 * |
|
77 * ; 'prodid' and 'version' are both REQUIRED, |
|
78 * ; but MUST NOT occur more than once |
|
79 * |
|
80 * prodid /version / |
|
81 * |
|
82 * ; 'calscale' and 'method' are optional, |
|
83 * ; but MUST NOT occur more than once |
|
84 * |
|
85 * calscale / |
|
86 * method / |
|
87 * |
|
88 * x-prop |
|
89 * |
|
90 * ) |
|
91 * |
|
92 * component = 1*(eventc / todoc / journalc / freebusyc / |
|
93 * / timezonec / iana-comp / x-comp) |
|
94 * |
|
95 * iana-comp = "BEGIN" ":" iana-token CRLF |
|
96 * |
|
97 * 1*contentline |
|
98 * |
|
99 * "END" ":" iana-token CRLF |
|
100 * |
|
101 * x-comp = "BEGIN" ":" x-name CRLF |
|
102 * |
|
103 * 1*contentline |
|
104 * |
|
105 * "END" ":" x-name CRLF |
|
106 * </pre> |
|
107 * |
|
108 * Example 1 - Creating a new calendar: |
|
109 * |
|
110 * <pre><code> |
|
111 * Calendar calendar = new Calendar(); |
|
112 * calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN")); |
|
113 * calendar.getProperties().add(Version.VERSION_2_0); |
|
114 * calendar.getProperties().add(CalScale.GREGORIAN); |
|
115 * |
|
116 * // Add events, etc.. |
|
117 * </code></pre> |
|
118 * |
|
119 * @author Ben Fortuna |
|
120 */ |
|
121 public class Calendar implements Serializable { |
|
122 |
|
123 private static final long serialVersionUID = -1654118204678581940L; |
|
124 |
|
125 /** |
|
126 * Begin token. |
|
127 */ |
|
128 public static final String BEGIN = "BEGIN"; |
|
129 |
|
130 /** |
|
131 * Calendar token. |
|
132 */ |
|
133 public static final String VCALENDAR = "VCALENDAR"; |
|
134 |
|
135 /** |
|
136 * End token. |
|
137 */ |
|
138 public static final String END = "END"; |
|
139 |
|
140 private PropertyList properties; |
|
141 |
|
142 private ComponentList components; |
|
143 |
|
144 /** |
|
145 * Default constructor. |
|
146 */ |
|
147 public Calendar() { |
|
148 this(new PropertyList(), new ComponentList()); |
|
149 } |
|
150 |
|
151 /** |
|
152 * Constructs a new calendar with no properties and the specified components. |
|
153 * @param components a list of components to add to the calendar |
|
154 */ |
|
155 public Calendar(final ComponentList components) { |
|
156 this(new PropertyList(), components); |
|
157 } |
|
158 |
|
159 /** |
|
160 * Constructor. |
|
161 * @param p a list of properties |
|
162 * @param c a list of components |
|
163 */ |
|
164 public Calendar(final PropertyList p, final ComponentList c) { |
|
165 this.properties = p; |
|
166 this.components = c; |
|
167 } |
|
168 |
|
169 /** |
|
170 * Creates a deep copy of the specified calendar. |
|
171 * @param c the calendar to copy |
|
172 * @throws IOException where an error occurs reading calendar data |
|
173 * @throws ParseException where calendar parsing fails |
|
174 * @throws URISyntaxException where an invalid URI string is encountered |
|
175 */ |
|
176 public Calendar(Calendar c) throws ParseException, IOException, |
|
177 URISyntaxException { |
|
178 |
|
179 this(new PropertyList(c.getProperties()), new ComponentList(c |
|
180 .getComponents())); |
|
181 } |
|
182 |
|
183 /** |
|
184 * {@inheritDoc} |
|
185 */ |
|
186 public final String toString() { |
|
187 final StringBuffer buffer = new StringBuffer(); |
|
188 buffer.append(BEGIN); |
|
189 buffer.append(':'); |
|
190 buffer.append(VCALENDAR); |
|
191 buffer.append(Strings.LINE_SEPARATOR); |
|
192 buffer.append(getProperties()); |
|
193 buffer.append(getComponents()); |
|
194 buffer.append(END); |
|
195 buffer.append(':'); |
|
196 buffer.append(VCALENDAR); |
|
197 buffer.append(Strings.LINE_SEPARATOR); |
|
198 |
|
199 return buffer.toString(); |
|
200 } |
|
201 |
|
202 /** |
|
203 * @return Returns the components. |
|
204 */ |
|
205 public final ComponentList getComponents() { |
|
206 return components; |
|
207 } |
|
208 |
|
209 /** |
|
210 * Convenience method for retrieving a list of named components. |
|
211 * @param name name of components to retrieve |
|
212 * @return a component list containing only components with the specified name |
|
213 */ |
|
214 public final ComponentList getComponents(final String name) { |
|
215 return getComponents().getComponents(name); |
|
216 } |
|
217 |
|
218 /** |
|
219 * Convenience method for retrieving a named component. |
|
220 * @param name name of the component to retrieve |
|
221 * @return the first matching component in the component list with the specified name |
|
222 */ |
|
223 public final Component getComponent(final String name) { |
|
224 return getComponents().getComponent(name); |
|
225 } |
|
226 |
|
227 /** |
|
228 * @return Returns the properties. |
|
229 */ |
|
230 public final PropertyList getProperties() { |
|
231 return properties; |
|
232 } |
|
233 |
|
234 /** |
|
235 * Convenience method for retrieving a list of named properties. |
|
236 * @param name name of properties to retrieve |
|
237 * @return a property list containing only properties with the specified name |
|
238 */ |
|
239 public final PropertyList getProperties(final String name) { |
|
240 return getProperties().getProperties(name); |
|
241 } |
|
242 |
|
243 /** |
|
244 * Convenience method for retrieving a named property. |
|
245 * @param name name of the property to retrieve |
|
246 * @return the first matching property in the property list with the specified name |
|
247 */ |
|
248 public final Property getProperty(final String name) { |
|
249 return getProperties().getProperty(name); |
|
250 } |
|
251 |
|
252 /** |
|
253 * Perform validation on the calendar, its properties and its components in its current state. |
|
254 * @throws ValidationException where the calendar is not in a valid state |
|
255 */ |
|
256 public final void validate() throws ValidationException { |
|
257 validate(true); |
|
258 } |
|
259 |
|
260 /** |
|
261 * Perform validation on the calendar in its current state. |
|
262 * @param recurse indicates whether to validate the calendar's properties and components |
|
263 * @throws ValidationException where the calendar is not in a valid state |
|
264 */ |
|
265 public void validate(final boolean recurse) throws ValidationException { |
|
266 // 'prodid' and 'version' are both REQUIRED, |
|
267 // but MUST NOT occur more than once |
|
268 PropertyValidator.getInstance().assertOne(Property.PRODID, properties); |
|
269 PropertyValidator.getInstance().assertOne(Property.VERSION, properties); |
|
270 |
|
271 if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { |
|
272 // require VERSION:2.0 for RFC2445.. |
|
273 if (!Version.VERSION_2_0.equals(getProperty(Property.VERSION))) { |
|
274 throw new ValidationException("Unsupported Version: " + getProperty(Property.VERSION).getValue()); |
|
275 } |
|
276 } |
|
277 |
|
278 // 'calscale' and 'method' are optional, |
|
279 // but MUST NOT occur more than once |
|
280 PropertyValidator.getInstance().assertOneOrLess(Property.CALSCALE, |
|
281 properties); |
|
282 PropertyValidator.getInstance().assertOneOrLess(Property.METHOD, |
|
283 properties); |
|
284 |
|
285 // must contain at least one component |
|
286 if (getComponents().isEmpty()) { |
|
287 throw new ValidationException( |
|
288 "Calendar must contain at least one component"); |
|
289 } |
|
290 |
|
291 // validate properties.. |
|
292 for (final Iterator i = getProperties().iterator(); i.hasNext();) { |
|
293 final Property property = (Property) i.next(); |
|
294 |
|
295 if (!(property instanceof XProperty) |
|
296 && !property.isCalendarProperty()) { |
|
297 throw new ValidationException("Invalid property: " |
|
298 + property.getName()); |
|
299 } |
|
300 } |
|
301 |
|
302 // validate components.. |
|
303 for (final Iterator i = getComponents().iterator(); i.hasNext();) { |
|
304 final Component component = (Component) i.next(); |
|
305 if (!(component instanceof CalendarComponent)) { |
|
306 throw new ValidationException("Not a valid calendar component: " + component.getName()); |
|
307 } |
|
308 } |
|
309 |
|
310 // if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { |
|
311 // validate method.. |
|
312 final Method method = (Method) getProperty(Property.METHOD); |
|
313 if (Method.PUBLISH.equals(method)) { |
|
314 if (getComponent(Component.VEVENT) != null) { |
|
315 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
316 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
317 |
|
318 if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { |
|
319 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
320 } |
|
321 } |
|
322 else if (getComponent(Component.VFREEBUSY) != null) { |
|
323 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
324 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
325 ComponentValidator.assertNone(Component.VTIMEZONE, getComponents()); |
|
326 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
327 } |
|
328 else if (getComponent(Component.VTODO) != null) { |
|
329 // ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
330 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
331 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
332 } |
|
333 else if (getComponent(Component.VJOURNAL) != null) { |
|
334 // ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
335 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
336 // ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
337 } |
|
338 } |
|
339 else if (Method.REQUEST.equals(getProperty(Property.METHOD))) { |
|
340 if (getComponent(Component.VEVENT) != null) { |
|
341 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
342 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
343 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
344 } |
|
345 else if (getComponent(Component.VFREEBUSY) != null) { |
|
346 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
347 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
348 ComponentValidator.assertNone(Component.VTIMEZONE, getComponents()); |
|
349 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
350 } |
|
351 else if (getComponent(Component.VTODO) != null) { |
|
352 // ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
353 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
354 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
355 } |
|
356 } |
|
357 else if (Method.REPLY.equals(getProperty(Property.METHOD))) { |
|
358 if (getComponent(Component.VEVENT) != null) { |
|
359 ComponentValidator.assertOneOrLess(Component.VTIMEZONE, getComponents()); |
|
360 |
|
361 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
362 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
363 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
364 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
365 } |
|
366 else if (getComponent(Component.VFREEBUSY) != null) { |
|
367 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
368 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
369 ComponentValidator.assertNone(Component.VTIMEZONE, getComponents()); |
|
370 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
371 } |
|
372 else if (getComponent(Component.VTODO) != null) { |
|
373 ComponentValidator.assertOneOrLess(Component.VTIMEZONE, getComponents()); |
|
374 |
|
375 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
376 // ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
377 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
378 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
379 } |
|
380 } |
|
381 else if (Method.ADD.equals(getProperty(Property.METHOD))) { |
|
382 if (getComponent(Component.VEVENT) != null) { |
|
383 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
384 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
385 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
386 } |
|
387 else if (getComponent(Component.VTODO) != null) { |
|
388 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
389 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
390 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
391 } |
|
392 else if (getComponent(Component.VJOURNAL) != null) { |
|
393 ComponentValidator.assertOneOrLess(Component.VTIMEZONE, getComponents()); |
|
394 |
|
395 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
396 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
397 // ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
398 } |
|
399 } |
|
400 else if (Method.CANCEL.equals(getProperty(Property.METHOD))) { |
|
401 if (getComponent(Component.VEVENT) != null) { |
|
402 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
403 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
404 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
405 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
406 } |
|
407 else if (getComponent(Component.VTODO) != null) { |
|
408 ComponentValidator.assertOneOrLess(Component.VTIMEZONE, getComponents()); |
|
409 |
|
410 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
411 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
412 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
413 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
414 } |
|
415 else if (getComponent(Component.VJOURNAL) != null) { |
|
416 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
417 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
418 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
419 // ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
420 } |
|
421 } |
|
422 else if (Method.REFRESH.equals(getProperty(Property.METHOD))) { |
|
423 if (getComponent(Component.VEVENT) != null) { |
|
424 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
425 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
426 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
427 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
428 } |
|
429 else if (getComponent(Component.VTODO) != null) { |
|
430 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
431 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
432 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
433 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
434 ComponentValidator.assertNone(Component.VTIMEZONE, getComponents()); |
|
435 } |
|
436 } |
|
437 else if (Method.COUNTER.equals(getProperty(Property.METHOD))) { |
|
438 if (getComponent(Component.VEVENT) != null) { |
|
439 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
440 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
441 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
442 } |
|
443 else if (getComponent(Component.VTODO) != null) { |
|
444 ComponentValidator.assertOneOrLess(Component.VTIMEZONE, getComponents()); |
|
445 |
|
446 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
447 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
448 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
449 } |
|
450 } |
|
451 else if (Method.DECLINE_COUNTER.equals(getProperty(Property.METHOD))) { |
|
452 if (getComponent(Component.VEVENT) != null) { |
|
453 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
454 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
455 ComponentValidator.assertNone(Component.VTODO, getComponents()); |
|
456 ComponentValidator.assertNone(Component.VTIMEZONE, getComponents()); |
|
457 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
458 } |
|
459 else if (getComponent(Component.VTODO) != null) { |
|
460 ComponentValidator.assertNone(Component.VALARM, getComponents()); |
|
461 ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); |
|
462 // ComponentValidator.assertNone(Component.VEVENT, getComponents()); |
|
463 ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); |
|
464 } |
|
465 } |
|
466 // } |
|
467 |
|
468 // perform ITIP validation on components.. |
|
469 if (method != null) { |
|
470 for (final Iterator i = getComponents().iterator(); i.hasNext();) { |
|
471 final CalendarComponent component = (CalendarComponent) i.next(); |
|
472 component.validate(method); |
|
473 } |
|
474 } |
|
475 |
|
476 if (recurse) { |
|
477 validateProperties(); |
|
478 validateComponents(); |
|
479 } |
|
480 } |
|
481 |
|
482 /** |
|
483 * Invoke validation on the calendar properties in its current state. |
|
484 * @throws ValidationException where any of the calendar properties is not in a valid state |
|
485 */ |
|
486 private void validateProperties() throws ValidationException { |
|
487 for (final Iterator i = getProperties().iterator(); i.hasNext();) { |
|
488 final Property property = (Property) i.next(); |
|
489 property.validate(); |
|
490 } |
|
491 } |
|
492 |
|
493 /** |
|
494 * Invoke validation on the calendar components in its current state. |
|
495 * @throws ValidationException where any of the calendar components is not in a valid state |
|
496 */ |
|
497 private void validateComponents() throws ValidationException { |
|
498 for (final Iterator i = getComponents().iterator(); i.hasNext();) { |
|
499 final Component component = (Component) i.next(); |
|
500 component.validate(); |
|
501 } |
|
502 } |
|
503 |
|
504 /** |
|
505 * Returns the mandatory prodid property. |
|
506 * @return the PRODID property, or null if property doesn't exist |
|
507 */ |
|
508 public final ProdId getProductId() { |
|
509 return (ProdId) getProperty(Property.PRODID); |
|
510 } |
|
511 |
|
512 /** |
|
513 * Returns the mandatory version property. |
|
514 * @return the VERSION property, or null if property doesn't exist |
|
515 */ |
|
516 public final Version getVersion() { |
|
517 return (Version) getProperty(Property.VERSION); |
|
518 } |
|
519 |
|
520 /** |
|
521 * Returns the optional calscale property. |
|
522 * @return the CALSCALE property, or null if property doesn't exist |
|
523 */ |
|
524 public final CalScale getCalendarScale() { |
|
525 return (CalScale) getProperty(Property.CALSCALE); |
|
526 } |
|
527 |
|
528 /** |
|
529 * Returns the optional method property. |
|
530 * @return the METHOD property, or null if property doesn't exist |
|
531 */ |
|
532 public final Method getMethod() { |
|
533 return (Method) getProperty(Property.METHOD); |
|
534 } |
|
535 |
|
536 /** |
|
537 * {@inheritDoc} |
|
538 */ |
|
539 public final boolean equals(final Object arg0) { |
|
540 if (arg0 instanceof Calendar) { |
|
541 final Calendar calendar = (Calendar) arg0; |
|
542 return new EqualsBuilder().append(getProperties(), calendar.getProperties()) |
|
543 .append(getComponents(), calendar.getComponents()).isEquals(); |
|
544 } |
|
545 return super.equals(arg0); |
|
546 } |
|
547 |
|
548 /** |
|
549 * {@inheritDoc} |
|
550 */ |
|
551 public final int hashCode() { |
|
552 return new HashCodeBuilder().append(getProperties()).append( |
|
553 getComponents()).toHashCode(); |
|
554 } |
|
555 } |