src/net/fortuna/ical4j/model/component/VTimeZone.java

Tue, 10 Feb 2015 18:12:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 18:12:00 +0100
changeset 0
fb9019fb1bf7
child 3
73bdfa70b04e
permissions
-rw-r--r--

Import initial revisions of existing project AndroidCaldavSyncAdapater,
forked from upstream repository at 27e8a0f8495c92e0780d450bdf0c7cec77a03a55.

     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.component;
    34 import java.io.IOException;
    35 import java.net.URISyntaxException;
    36 import java.text.ParseException;
    37 import java.util.Iterator;
    39 import net.fortuna.ical4j.model.Component;
    40 import net.fortuna.ical4j.model.ComponentList;
    41 import net.fortuna.ical4j.model.Date;
    42 import net.fortuna.ical4j.model.Property;
    43 import net.fortuna.ical4j.model.PropertyList;
    44 import net.fortuna.ical4j.model.ValidationException;
    45 import net.fortuna.ical4j.model.Validator;
    46 import net.fortuna.ical4j.model.property.LastModified;
    47 import net.fortuna.ical4j.model.property.Method;
    48 import net.fortuna.ical4j.model.property.TzId;
    49 import net.fortuna.ical4j.model.property.TzUrl;
    50 import net.fortuna.ical4j.util.PropertyValidator;
    51 import net.fortuna.ical4j.util.Strings;
    53 import org.apache.commons.lang.ObjectUtils;
    54 import org.apache.commons.lang.builder.HashCodeBuilder;
    56 /**
    57  * $Id$ [Apr 5, 2004]
    58  *
    59  * Defines an iCalendar VTIMEZONE component.
    60  * 
    61  * <pre>
    62  *       4.6.5 Time Zone Component
    63  *  
    64  *          Component Name: VTIMEZONE
    65  *  
    66  *          Purpose: Provide a grouping of component properties that defines a
    67  *          time zone.
    68  *  
    69  *          Formal Definition: A &quot;VTIMEZONE&quot; calendar component is defined by the
    70  *          following notation:
    71  *  
    72  *            timezonec  = &quot;BEGIN&quot; &quot;:&quot; &quot;VTIMEZONE&quot; CRLF
    73  *  
    74  *                         2*(
    75  *  
    76  *                         ; 'tzid' is required, but MUST NOT occur more
    77  *                         ; than once
    78  *  
    79  *                       tzid /
    80  *  
    81  *                         ; 'last-mod' and 'tzurl' are optional,
    82  *                       but MUST NOT occur more than once
    83  *  
    84  *                       last-mod / tzurl /
    85  *  
    86  *                         ; one of 'standardc' or 'daylightc' MUST occur
    87  *                       ..; and each MAY occur more than once.
    88  *  
    89  *                       standardc / daylightc /
    90  *  
    91  *                       ; the following is optional,
    92  *                       ; and MAY occur more than once
    93  *  
    94  *                         x-prop
    95  *  
    96  *                         )
    97  *  
    98  *                         &quot;END&quot; &quot;:&quot; &quot;VTIMEZONE&quot; CRLF
    99  *  
   100  *            standardc  = &quot;BEGIN&quot; &quot;:&quot; &quot;STANDARD&quot; CRLF
   101  *  
   102  *                         tzprop
   103  *  
   104  *                         &quot;END&quot; &quot;:&quot; &quot;STANDARD&quot; CRLF
   105  *  
   106  *            daylightc  = &quot;BEGIN&quot; &quot;:&quot; &quot;DAYLIGHT&quot; CRLF
   107  *  
   108  *                         tzprop
   109  *  
   110  *                         &quot;END&quot; &quot;:&quot; &quot;DAYLIGHT&quot; CRLF
   111  *  
   112  *            tzprop     = 3*(
   113  *  
   114  *                       ; the following are each REQUIRED,
   115  *                       ; but MUST NOT occur more than once
   116  *  
   117  *                       dtstart / tzoffsetto / tzoffsetfrom /
   118  *  
   119  *                       ; the following are optional,
   120  *                       ; and MAY occur more than once
   121  *  
   122  *                       comment / rdate / rrule / tzname / x-prop
   123  *  
   124  *                       )
   125  * </pre>
   126  * 
   127  * @author Ben Fortuna
   128  */
   129 public class VTimeZone extends CalendarComponent {
   131     private static final long serialVersionUID = 5629679741050917815L;
   133     private final Validator itipValidator = new ITIPValidator();
   135     private ComponentList observances;
   137     /**
   138      * Default constructor.
   139      */
   140     public VTimeZone() {
   141         super(VTIMEZONE);
   142         this.observances = new ComponentList();
   143     }
   145     /**
   146      * Constructs a new instance containing the specified properties.
   147      * @param properties a list of properties
   148      */
   149     public VTimeZone(final PropertyList properties) {
   150         super(VTIMEZONE, properties);
   151         this.observances = new ComponentList();
   152     }
   154     /**
   155      * Constructs a new vtimezone component with no properties and the specified list of type components.
   156      * @param observances a list of type components
   157      */
   158     public VTimeZone(final ComponentList observances) {
   159         super(VTIMEZONE);
   160         this.observances = observances;
   161     }
   163     /**
   164      * Constructor.
   165      * @param properties a list of properties
   166      * @param observances a list of timezone types
   167      */
   168     public VTimeZone(final PropertyList properties,
   169             final ComponentList observances) {
   170         super(VTIMEZONE, properties);
   171         this.observances = observances;
   172     }
   174     /**
   175      * {@inheritDoc}
   176      */
   177     public final String toString() {
   178         final StringBuffer b = new StringBuffer();
   179         b.append(BEGIN);
   180         b.append(':');
   181         b.append(getName());
   182         b.append(Strings.LINE_SEPARATOR);
   183         b.append(getProperties());
   184         b.append(observances);
   185         b.append(END);
   186         b.append(':');
   187         b.append(getName());
   188         b.append(Strings.LINE_SEPARATOR);
   189         return b.toString();
   190     }
   192     /**
   193      * {@inheritDoc}
   194      */
   195     public final void validate(final boolean recurse)
   196             throws ValidationException {
   198         /*
   199          * ; 'tzid' is required, but MUST NOT occur more ; than once tzid /
   200          */
   201         PropertyValidator.getInstance().assertOne(Property.TZID,
   202                 getProperties());
   204         /*
   205          * ; 'last-mod' and 'tzurl' are optional, but MUST NOT occur more than once last-mod / tzurl /
   206          */
   207         PropertyValidator.getInstance().assertOneOrLess(Property.LAST_MODIFIED,
   208                 getProperties());
   209         PropertyValidator.getInstance().assertOneOrLess(Property.TZURL,
   210                 getProperties());
   212         /*
   213          * ; one of 'standardc' or 'daylightc' MUST occur ..; and each MAY occur more than once. standardc / daylightc /
   214          */
   215         if (getObservances().getComponent(Observance.STANDARD) == null
   216                 && getObservances().getComponent(Observance.DAYLIGHT) == null) {
   217             throw new ValidationException("Sub-components ["
   218                     + Observance.STANDARD + "," + Observance.DAYLIGHT
   219                     + "] must be specified at least once");
   220         }
   222         for (final Iterator i = getObservances().iterator(); i.hasNext();) {
   223             ((Component) i.next()).validate(recurse);
   224         }
   226         /*
   227          * ; the following is optional, ; and MAY occur more than once x-prop
   228          */
   230         if (recurse) {
   231             validateProperties();
   232         }
   233     }
   235     /**
   236      * {@inheritDoc}
   237      */
   238     protected Validator getValidator(Method method) {
   239         return itipValidator;
   240     }
   242     /**
   243      * Common validation for all iTIP methods.
   244      * 
   245      * <pre>
   246      *    Component/Property  Presence
   247      *    ------------------- ----------------------------------------------
   248      *    VTIMEZONE           0+      MUST be present if any date/time refers
   249      *                                to timezone
   250      *        DAYLIGHT        0+      MUST be one or more of either STANDARD or
   251      *                                DAYLIGHT
   252      *           COMMENT      0 or 1
   253      *           DTSTART      1       MUST be local time format
   254      *           RDATE        0+      if present RRULE MUST NOT be present
   255      *           RRULE        0+      if present RDATE MUST NOT be present
   256      *           TZNAME       0 or 1
   257      *           TZOFFSET     1
   258      *           TZOFFSETFROM 1
   259      *           TZOFFSETTO   1
   260      *           X-PROPERTY   0+
   261      *        LAST-MODIFIED   0 or 1
   262      *        STANDARD        0+      MUST be one or more of either STANDARD or
   263      *                                DAYLIGHT
   264      *           COMMENT      0 or 1
   265      *           DTSTART      1       MUST be local time format
   266      *           RDATE        0+      if present RRULE MUST NOT be present
   267      *           RRULE        0+      if present RDATE MUST NOT be present
   268      *           TZNAME       0 or 1
   269      *           TZOFFSETFROM 1
   270      *           TZOFFSETTO   1
   271      *           X-PROPERTY   0+
   272      *        TZID            1
   273      *        TZURL           0 or 1
   274      *        X-PROPERTY      0+
   275      * </pre>
   276      */
   277     private class ITIPValidator implements Validator {
   279 		private static final long serialVersionUID = 1L;
   281         /**
   282          * {@inheritDoc}
   283          */
   284         public void validate() throws ValidationException {
   285             for (final Iterator i = getObservances().iterator(); i.hasNext();) {
   286                 final Observance observance = (Observance) i.next();
   287                 PropertyValidator.getInstance().assertOne(Property.DTSTART, observance.getProperties());
   288                 PropertyValidator.getInstance().assertOne(Property.TZOFFSETFROM, observance.getProperties());
   289                 PropertyValidator.getInstance().assertOne(Property.TZOFFSETTO, observance.getProperties());
   291                 PropertyValidator.getInstance().assertOneOrLess(Property.COMMENT, observance.getProperties());
   292                 PropertyValidator.getInstance().assertOneOrLess(Property.TZNAME, observance.getProperties());
   293             }
   294         }
   295     }
   297     /**
   298      * @return Returns the types.
   299      */
   300     public final ComponentList getObservances() {
   301         return observances;
   302     }
   304     /**
   305      * Returns the latest applicable timezone observance for the specified date.
   306      * @param date the latest possible date for a timezone observance onset
   307      * @return the latest applicable timezone observance for the specified date or null if there are no applicable
   308      * observances
   309      */
   310     public final Observance getApplicableObservance(final Date date) {
   311         Observance latestObservance = null;
   312         Date latestOnset = null;
   313         for (final Iterator i = getObservances().iterator(); i.hasNext();) {
   314             final Observance observance = (Observance) i.next();
   315             final Date onset = observance.getLatestOnset(date);
   316             if (latestOnset == null
   317                     || (onset != null && onset.after(latestOnset))) {
   318                 latestOnset = onset;
   319                 latestObservance = observance;
   320             }
   321         }
   322         return latestObservance;
   323     }
   325     /**
   326      * @return the mandatory timezone identifier property
   327      */
   328     public final TzId getTimeZoneId() {
   329         return (TzId) getProperty(Property.TZID);
   330     }
   332     /**
   333      * @return the optional last-modified property
   334      */
   335     public final LastModified getLastModified() {
   336         return (LastModified) getProperty(Property.LAST_MODIFIED);
   337     }
   339     /**
   340      * @return the optional timezone url property
   341      */
   342     public final TzUrl getTimeZoneUrl() {
   343         return (TzUrl) getProperty(Property.TZURL);
   344     }
   346     /**
   347      * {@inheritDoc}
   348      */
   349     public boolean equals(final Object arg0) {
   350         if (arg0 instanceof VTimeZone) {
   351             return super.equals(arg0)
   352                     && ObjectUtils.equals(observances, ((VTimeZone) arg0)
   353                             .getObservances());
   354         }
   355         return super.equals(arg0);
   356     }
   358     /**
   359      * {@inheritDoc}
   360      */
   361     public int hashCode() {
   362         return new HashCodeBuilder().append(getName()).append(getProperties())
   363                 .append(getObservances()).toHashCode();
   364     }
   366     /**
   367      * Overrides default copy method to add support for copying observance sub-components.
   368      * @return a copy of the instance
   369      * @throws ParseException where an error occurs parsing data
   370      * @throws IOException where an error occurs reading data
   371      * @throws URISyntaxException where an invalid URI is encountered
   372      * @see net.fortuna.ical4j.model.Component#copy()
   373      */
   374     public Component copy() throws ParseException, IOException, URISyntaxException {
   375         final VTimeZone copy = (VTimeZone) super.copy();
   376         copy.observances = new ComponentList(observances);
   377         return copy;
   378     }
   379 }

mercurial