1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/net/fortuna/ical4j/model/Calendar.java Tue Feb 10 18:12:00 2015 +0100 1.3 @@ -0,0 +1,555 @@ 1.4 +/** 1.5 + * Copyright (c) 2012, Ben Fortuna 1.6 + * All rights reserved. 1.7 + * 1.8 + * Redistribution and use in source and binary forms, with or without 1.9 + * modification, are permitted provided that the following conditions 1.10 + * are met: 1.11 + * 1.12 + * o Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 1.15 + * o Redistributions in binary form must reproduce the above copyright 1.16 + * notice, this list of conditions and the following disclaimer in the 1.17 + * documentation and/or other materials provided with the distribution. 1.18 + * 1.19 + * o Neither the name of Ben Fortuna nor the names of any other contributors 1.20 + * may be used to endorse or promote products derived from this software 1.21 + * without specific prior written permission. 1.22 + * 1.23 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.24 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.25 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.26 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 1.27 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 1.28 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1.29 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 1.30 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 1.31 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 1.32 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 1.33 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.34 + */ 1.35 +package net.fortuna.ical4j.model; 1.36 + 1.37 +import java.io.IOException; 1.38 +import java.io.Serializable; 1.39 +import java.net.URISyntaxException; 1.40 +import java.text.ParseException; 1.41 +import java.util.Iterator; 1.42 + 1.43 +import net.fortuna.ical4j.model.component.CalendarComponent; 1.44 +import net.fortuna.ical4j.model.property.CalScale; 1.45 +import net.fortuna.ical4j.model.property.Method; 1.46 +import net.fortuna.ical4j.model.property.ProdId; 1.47 +import net.fortuna.ical4j.model.property.Version; 1.48 +import net.fortuna.ical4j.model.property.XProperty; 1.49 +import net.fortuna.ical4j.util.CompatibilityHints; 1.50 +import net.fortuna.ical4j.util.ComponentValidator; 1.51 +import net.fortuna.ical4j.util.PropertyValidator; 1.52 +import net.fortuna.ical4j.util.Strings; 1.53 + 1.54 +import org.apache.commons.lang.builder.EqualsBuilder; 1.55 +import org.apache.commons.lang.builder.HashCodeBuilder; 1.56 + 1.57 +/** 1.58 + * $Id$ [Apr 5, 2004] 1.59 + * 1.60 + * Defines an iCalendar calendar. 1.61 + * 1.62 + * <pre> 1.63 + * 4.6 Calendar Components 1.64 + * 1.65 + * The body of the iCalendar object consists of a sequence of calendar 1.66 + * properties and one or more calendar components. The calendar 1.67 + * properties are attributes that apply to the calendar as a whole. The 1.68 + * calendar components are collections of properties that express a 1.69 + * particular calendar semantic. For example, the calendar component can 1.70 + * specify an event, a to-do, a journal entry, time zone information, or 1.71 + * free/busy time information, or an alarm. 1.72 + * 1.73 + * The body of the iCalendar object is defined by the following 1.74 + * notation: 1.75 + * 1.76 + * icalbody = calprops component 1.77 + * 1.78 + * calprops = 2*( 1.79 + * 1.80 + * ; 'prodid' and 'version' are both REQUIRED, 1.81 + * ; but MUST NOT occur more than once 1.82 + * 1.83 + * prodid /version / 1.84 + * 1.85 + * ; 'calscale' and 'method' are optional, 1.86 + * ; but MUST NOT occur more than once 1.87 + * 1.88 + * calscale / 1.89 + * method / 1.90 + * 1.91 + * x-prop 1.92 + * 1.93 + * ) 1.94 + * 1.95 + * component = 1*(eventc / todoc / journalc / freebusyc / 1.96 + * / timezonec / iana-comp / x-comp) 1.97 + * 1.98 + * iana-comp = "BEGIN" ":" iana-token CRLF 1.99 + * 1.100 + * 1*contentline 1.101 + * 1.102 + * "END" ":" iana-token CRLF 1.103 + * 1.104 + * x-comp = "BEGIN" ":" x-name CRLF 1.105 + * 1.106 + * 1*contentline 1.107 + * 1.108 + * "END" ":" x-name CRLF 1.109 + * </pre> 1.110 + * 1.111 + * Example 1 - Creating a new calendar: 1.112 + * 1.113 + * <pre><code> 1.114 + * Calendar calendar = new Calendar(); 1.115 + * calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN")); 1.116 + * calendar.getProperties().add(Version.VERSION_2_0); 1.117 + * calendar.getProperties().add(CalScale.GREGORIAN); 1.118 + * 1.119 + * // Add events, etc.. 1.120 + * </code></pre> 1.121 + * 1.122 + * @author Ben Fortuna 1.123 + */ 1.124 +public class Calendar implements Serializable { 1.125 + 1.126 + private static final long serialVersionUID = -1654118204678581940L; 1.127 + 1.128 + /** 1.129 + * Begin token. 1.130 + */ 1.131 + public static final String BEGIN = "BEGIN"; 1.132 + 1.133 + /** 1.134 + * Calendar token. 1.135 + */ 1.136 + public static final String VCALENDAR = "VCALENDAR"; 1.137 + 1.138 + /** 1.139 + * End token. 1.140 + */ 1.141 + public static final String END = "END"; 1.142 + 1.143 + private PropertyList properties; 1.144 + 1.145 + private ComponentList components; 1.146 + 1.147 + /** 1.148 + * Default constructor. 1.149 + */ 1.150 + public Calendar() { 1.151 + this(new PropertyList(), new ComponentList()); 1.152 + } 1.153 + 1.154 + /** 1.155 + * Constructs a new calendar with no properties and the specified components. 1.156 + * @param components a list of components to add to the calendar 1.157 + */ 1.158 + public Calendar(final ComponentList components) { 1.159 + this(new PropertyList(), components); 1.160 + } 1.161 + 1.162 + /** 1.163 + * Constructor. 1.164 + * @param p a list of properties 1.165 + * @param c a list of components 1.166 + */ 1.167 + public Calendar(final PropertyList p, final ComponentList c) { 1.168 + this.properties = p; 1.169 + this.components = c; 1.170 + } 1.171 + 1.172 + /** 1.173 + * Creates a deep copy of the specified calendar. 1.174 + * @param c the calendar to copy 1.175 + * @throws IOException where an error occurs reading calendar data 1.176 + * @throws ParseException where calendar parsing fails 1.177 + * @throws URISyntaxException where an invalid URI string is encountered 1.178 + */ 1.179 + public Calendar(Calendar c) throws ParseException, IOException, 1.180 + URISyntaxException { 1.181 + 1.182 + this(new PropertyList(c.getProperties()), new ComponentList(c 1.183 + .getComponents())); 1.184 + } 1.185 + 1.186 + /** 1.187 + * {@inheritDoc} 1.188 + */ 1.189 + public final String toString() { 1.190 + final StringBuffer buffer = new StringBuffer(); 1.191 + buffer.append(BEGIN); 1.192 + buffer.append(':'); 1.193 + buffer.append(VCALENDAR); 1.194 + buffer.append(Strings.LINE_SEPARATOR); 1.195 + buffer.append(getProperties()); 1.196 + buffer.append(getComponents()); 1.197 + buffer.append(END); 1.198 + buffer.append(':'); 1.199 + buffer.append(VCALENDAR); 1.200 + buffer.append(Strings.LINE_SEPARATOR); 1.201 + 1.202 + return buffer.toString(); 1.203 + } 1.204 + 1.205 + /** 1.206 + * @return Returns the components. 1.207 + */ 1.208 + public final ComponentList getComponents() { 1.209 + return components; 1.210 + } 1.211 + 1.212 + /** 1.213 + * Convenience method for retrieving a list of named components. 1.214 + * @param name name of components to retrieve 1.215 + * @return a component list containing only components with the specified name 1.216 + */ 1.217 + public final ComponentList getComponents(final String name) { 1.218 + return getComponents().getComponents(name); 1.219 + } 1.220 + 1.221 + /** 1.222 + * Convenience method for retrieving a named component. 1.223 + * @param name name of the component to retrieve 1.224 + * @return the first matching component in the component list with the specified name 1.225 + */ 1.226 + public final Component getComponent(final String name) { 1.227 + return getComponents().getComponent(name); 1.228 + } 1.229 + 1.230 + /** 1.231 + * @return Returns the properties. 1.232 + */ 1.233 + public final PropertyList getProperties() { 1.234 + return properties; 1.235 + } 1.236 + 1.237 + /** 1.238 + * Convenience method for retrieving a list of named properties. 1.239 + * @param name name of properties to retrieve 1.240 + * @return a property list containing only properties with the specified name 1.241 + */ 1.242 + public final PropertyList getProperties(final String name) { 1.243 + return getProperties().getProperties(name); 1.244 + } 1.245 + 1.246 + /** 1.247 + * Convenience method for retrieving a named property. 1.248 + * @param name name of the property to retrieve 1.249 + * @return the first matching property in the property list with the specified name 1.250 + */ 1.251 + public final Property getProperty(final String name) { 1.252 + return getProperties().getProperty(name); 1.253 + } 1.254 + 1.255 + /** 1.256 + * Perform validation on the calendar, its properties and its components in its current state. 1.257 + * @throws ValidationException where the calendar is not in a valid state 1.258 + */ 1.259 + public final void validate() throws ValidationException { 1.260 + validate(true); 1.261 + } 1.262 + 1.263 + /** 1.264 + * Perform validation on the calendar in its current state. 1.265 + * @param recurse indicates whether to validate the calendar's properties and components 1.266 + * @throws ValidationException where the calendar is not in a valid state 1.267 + */ 1.268 + public void validate(final boolean recurse) throws ValidationException { 1.269 + // 'prodid' and 'version' are both REQUIRED, 1.270 + // but MUST NOT occur more than once 1.271 + PropertyValidator.getInstance().assertOne(Property.PRODID, properties); 1.272 + PropertyValidator.getInstance().assertOne(Property.VERSION, properties); 1.273 + 1.274 + if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { 1.275 + // require VERSION:2.0 for RFC2445.. 1.276 + if (!Version.VERSION_2_0.equals(getProperty(Property.VERSION))) { 1.277 + throw new ValidationException("Unsupported Version: " + getProperty(Property.VERSION).getValue()); 1.278 + } 1.279 + } 1.280 + 1.281 + // 'calscale' and 'method' are optional, 1.282 + // but MUST NOT occur more than once 1.283 + PropertyValidator.getInstance().assertOneOrLess(Property.CALSCALE, 1.284 + properties); 1.285 + PropertyValidator.getInstance().assertOneOrLess(Property.METHOD, 1.286 + properties); 1.287 + 1.288 + // must contain at least one component 1.289 + if (getComponents().isEmpty()) { 1.290 + throw new ValidationException( 1.291 + "Calendar must contain at least one component"); 1.292 + } 1.293 + 1.294 + // validate properties.. 1.295 + for (final Iterator i = getProperties().iterator(); i.hasNext();) { 1.296 + final Property property = (Property) i.next(); 1.297 + 1.298 + if (!(property instanceof XProperty) 1.299 + && !property.isCalendarProperty()) { 1.300 + throw new ValidationException("Invalid property: " 1.301 + + property.getName()); 1.302 + } 1.303 + } 1.304 + 1.305 + // validate components.. 1.306 + for (final Iterator i = getComponents().iterator(); i.hasNext();) { 1.307 + final Component component = (Component) i.next(); 1.308 + if (!(component instanceof CalendarComponent)) { 1.309 + throw new ValidationException("Not a valid calendar component: " + component.getName()); 1.310 + } 1.311 + } 1.312 + 1.313 +// if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { 1.314 + // validate method.. 1.315 + final Method method = (Method) getProperty(Property.METHOD); 1.316 + if (Method.PUBLISH.equals(method)) { 1.317 + if (getComponent(Component.VEVENT) != null) { 1.318 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.319 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.320 + 1.321 + if (!CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_VALIDATION)) { 1.322 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.323 + } 1.324 + } 1.325 + else if (getComponent(Component.VFREEBUSY) != null) { 1.326 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.327 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.328 + ComponentValidator.assertNone(Component.VTIMEZONE, getComponents()); 1.329 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.330 + } 1.331 + else if (getComponent(Component.VTODO) != null) { 1.332 +// ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.333 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.334 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.335 + } 1.336 + else if (getComponent(Component.VJOURNAL) != null) { 1.337 +// ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.338 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.339 +// ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.340 + } 1.341 + } 1.342 + else if (Method.REQUEST.equals(getProperty(Property.METHOD))) { 1.343 + if (getComponent(Component.VEVENT) != null) { 1.344 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.345 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.346 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.347 + } 1.348 + else if (getComponent(Component.VFREEBUSY) != null) { 1.349 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.350 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.351 + ComponentValidator.assertNone(Component.VTIMEZONE, getComponents()); 1.352 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.353 + } 1.354 + else if (getComponent(Component.VTODO) != null) { 1.355 +// ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.356 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.357 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.358 + } 1.359 + } 1.360 + else if (Method.REPLY.equals(getProperty(Property.METHOD))) { 1.361 + if (getComponent(Component.VEVENT) != null) { 1.362 + ComponentValidator.assertOneOrLess(Component.VTIMEZONE, getComponents()); 1.363 + 1.364 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.365 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.366 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.367 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.368 + } 1.369 + else if (getComponent(Component.VFREEBUSY) != null) { 1.370 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.371 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.372 + ComponentValidator.assertNone(Component.VTIMEZONE, getComponents()); 1.373 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.374 + } 1.375 + else if (getComponent(Component.VTODO) != null) { 1.376 + ComponentValidator.assertOneOrLess(Component.VTIMEZONE, getComponents()); 1.377 + 1.378 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.379 +// ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.380 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.381 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.382 + } 1.383 + } 1.384 + else if (Method.ADD.equals(getProperty(Property.METHOD))) { 1.385 + if (getComponent(Component.VEVENT) != null) { 1.386 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.387 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.388 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.389 + } 1.390 + else if (getComponent(Component.VTODO) != null) { 1.391 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.392 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.393 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.394 + } 1.395 + else if (getComponent(Component.VJOURNAL) != null) { 1.396 + ComponentValidator.assertOneOrLess(Component.VTIMEZONE, getComponents()); 1.397 + 1.398 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.399 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.400 +// ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.401 + } 1.402 + } 1.403 + else if (Method.CANCEL.equals(getProperty(Property.METHOD))) { 1.404 + if (getComponent(Component.VEVENT) != null) { 1.405 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.406 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.407 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.408 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.409 + } 1.410 + else if (getComponent(Component.VTODO) != null) { 1.411 + ComponentValidator.assertOneOrLess(Component.VTIMEZONE, getComponents()); 1.412 + 1.413 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.414 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.415 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.416 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.417 + } 1.418 + else if (getComponent(Component.VJOURNAL) != null) { 1.419 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.420 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.421 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.422 +// ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.423 + } 1.424 + } 1.425 + else if (Method.REFRESH.equals(getProperty(Property.METHOD))) { 1.426 + if (getComponent(Component.VEVENT) != null) { 1.427 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.428 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.429 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.430 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.431 + } 1.432 + else if (getComponent(Component.VTODO) != null) { 1.433 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.434 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.435 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.436 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.437 + ComponentValidator.assertNone(Component.VTIMEZONE, getComponents()); 1.438 + } 1.439 + } 1.440 + else if (Method.COUNTER.equals(getProperty(Property.METHOD))) { 1.441 + if (getComponent(Component.VEVENT) != null) { 1.442 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.443 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.444 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.445 + } 1.446 + else if (getComponent(Component.VTODO) != null) { 1.447 + ComponentValidator.assertOneOrLess(Component.VTIMEZONE, getComponents()); 1.448 + 1.449 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.450 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.451 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.452 + } 1.453 + } 1.454 + else if (Method.DECLINE_COUNTER.equals(getProperty(Property.METHOD))) { 1.455 + if (getComponent(Component.VEVENT) != null) { 1.456 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.457 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.458 + ComponentValidator.assertNone(Component.VTODO, getComponents()); 1.459 + ComponentValidator.assertNone(Component.VTIMEZONE, getComponents()); 1.460 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.461 + } 1.462 + else if (getComponent(Component.VTODO) != null) { 1.463 + ComponentValidator.assertNone(Component.VALARM, getComponents()); 1.464 + ComponentValidator.assertNone(Component.VFREEBUSY, getComponents()); 1.465 +// ComponentValidator.assertNone(Component.VEVENT, getComponents()); 1.466 + ComponentValidator.assertNone(Component.VJOURNAL, getComponents()); 1.467 + } 1.468 + } 1.469 +// } 1.470 + 1.471 + // perform ITIP validation on components.. 1.472 + if (method != null) { 1.473 + for (final Iterator i = getComponents().iterator(); i.hasNext();) { 1.474 + final CalendarComponent component = (CalendarComponent) i.next(); 1.475 + component.validate(method); 1.476 + } 1.477 + } 1.478 + 1.479 + if (recurse) { 1.480 + validateProperties(); 1.481 + validateComponents(); 1.482 + } 1.483 + } 1.484 + 1.485 + /** 1.486 + * Invoke validation on the calendar properties in its current state. 1.487 + * @throws ValidationException where any of the calendar properties is not in a valid state 1.488 + */ 1.489 + private void validateProperties() throws ValidationException { 1.490 + for (final Iterator i = getProperties().iterator(); i.hasNext();) { 1.491 + final Property property = (Property) i.next(); 1.492 + property.validate(); 1.493 + } 1.494 + } 1.495 + 1.496 + /** 1.497 + * Invoke validation on the calendar components in its current state. 1.498 + * @throws ValidationException where any of the calendar components is not in a valid state 1.499 + */ 1.500 + private void validateComponents() throws ValidationException { 1.501 + for (final Iterator i = getComponents().iterator(); i.hasNext();) { 1.502 + final Component component = (Component) i.next(); 1.503 + component.validate(); 1.504 + } 1.505 + } 1.506 + 1.507 + /** 1.508 + * Returns the mandatory prodid property. 1.509 + * @return the PRODID property, or null if property doesn't exist 1.510 + */ 1.511 + public final ProdId getProductId() { 1.512 + return (ProdId) getProperty(Property.PRODID); 1.513 + } 1.514 + 1.515 + /** 1.516 + * Returns the mandatory version property. 1.517 + * @return the VERSION property, or null if property doesn't exist 1.518 + */ 1.519 + public final Version getVersion() { 1.520 + return (Version) getProperty(Property.VERSION); 1.521 + } 1.522 + 1.523 + /** 1.524 + * Returns the optional calscale property. 1.525 + * @return the CALSCALE property, or null if property doesn't exist 1.526 + */ 1.527 + public final CalScale getCalendarScale() { 1.528 + return (CalScale) getProperty(Property.CALSCALE); 1.529 + } 1.530 + 1.531 + /** 1.532 + * Returns the optional method property. 1.533 + * @return the METHOD property, or null if property doesn't exist 1.534 + */ 1.535 + public final Method getMethod() { 1.536 + return (Method) getProperty(Property.METHOD); 1.537 + } 1.538 + 1.539 + /** 1.540 + * {@inheritDoc} 1.541 + */ 1.542 + public final boolean equals(final Object arg0) { 1.543 + if (arg0 instanceof Calendar) { 1.544 + final Calendar calendar = (Calendar) arg0; 1.545 + return new EqualsBuilder().append(getProperties(), calendar.getProperties()) 1.546 + .append(getComponents(), calendar.getComponents()).isEquals(); 1.547 + } 1.548 + return super.equals(arg0); 1.549 + } 1.550 + 1.551 + /** 1.552 + * {@inheritDoc} 1.553 + */ 1.554 + public final int hashCode() { 1.555 + return new HashCodeBuilder().append(getProperties()).append( 1.556 + getComponents()).toHashCode(); 1.557 + } 1.558 +}