src/net/fortuna/ical4j/model/Calendar.java

Tue, 10 Feb 2015 19:58:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 19:58:00 +0100
changeset 4
45d57ecba757
parent 0
fb9019fb1bf7
permissions
-rw-r--r--

Upgrade the upgraded ical4j component to use org.apache.commons.lang3.

     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;
    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;
    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;
    51 import org.apache.commons.lang3.builder.EqualsBuilder;
    52 import org.apache.commons.lang3.builder.HashCodeBuilder;
    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  = &quot;BEGIN&quot; &quot;:&quot; iana-token CRLF
    96  *    
    97  *                      1*contentline
    98  *    
    99  *                      &quot;END&quot; &quot;:&quot; iana-token CRLF
   100  *    
   101  *         x-comp     = &quot;BEGIN&quot; &quot;:&quot; x-name CRLF
   102  *    
   103  *                      1*contentline
   104  *    
   105  *                      &quot;END&quot; &quot;:&quot; 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(&quot;-//Ben Fortuna//iCal4j 1.0//EN&quot;));
   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 {
   123     private static final long serialVersionUID = -1654118204678581940L;
   125     /**
   126      * Begin token.
   127      */
   128     public static final String BEGIN = "BEGIN";
   130     /**
   131      * Calendar token.
   132      */
   133     public static final String VCALENDAR = "VCALENDAR";
   135     /**
   136      * End token.
   137      */
   138     public static final String END = "END";
   140     private PropertyList properties;
   142     private ComponentList components;
   144     /**
   145      * Default constructor.
   146      */
   147     public Calendar() {
   148         this(new PropertyList(), new ComponentList());
   149     }
   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     }
   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     }
   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 {
   179         this(new PropertyList(c.getProperties()), new ComponentList(c
   180                 .getComponents()));
   181     }
   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);
   199         return buffer.toString();
   200     }
   202     /**
   203      * @return Returns the components.
   204      */
   205     public final ComponentList getComponents() {
   206         return components;
   207     }
   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     }
   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     }
   227     /**
   228      * @return Returns the properties.
   229      */
   230     public final PropertyList getProperties() {
   231         return properties;
   232     }
   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     }
   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     }
   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     }
   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);
   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         }
   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);
   285         // must contain at least one component
   286         if (getComponents().isEmpty()) {
   287             throw new ValidationException(
   288                     "Calendar must contain at least one component");
   289         }
   291         // validate properties..
   292         for (final Iterator i = getProperties().iterator(); i.hasNext();) {
   293             final Property property = (Property) i.next();
   295             if (!(property instanceof XProperty)
   296                     && !property.isCalendarProperty()) {
   297                 throw new ValidationException("Invalid property: "
   298                         + property.getName());
   299             }
   300         }
   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         }
   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());
   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());
   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());
   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());
   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());
   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());
   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 //        }
   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             }
   476         if (recurse) {
   477             validateProperties();
   478             validateComponents();
   479         }
   480     }
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   548     /**
   549      * {@inheritDoc}
   550      */
   551     public final int hashCode() {
   552         return new HashCodeBuilder().append(getProperties()).append(
   553                 getComponents()).toHashCode();
   554     }
   555 }

mercurial