1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/net/fortuna/ical4j/model/Property.java Tue Feb 10 18:12:00 2015 +0100 1.3 @@ -0,0 +1,537 @@ 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.net.URISyntaxException; 1.39 +import java.text.ParseException; 1.40 +import net.fortuna.ical4j.model.parameter.Value; 1.41 +import net.fortuna.ical4j.model.property.XProperty; 1.42 + 1.43 +import net.fortuna.ical4j.util.Strings; 1.44 + 1.45 +import org.apache.commons.lang.builder.EqualsBuilder; 1.46 +import org.apache.commons.lang.builder.HashCodeBuilder; 1.47 + 1.48 +/** 1.49 + * Defines an iCalendar property. Subclasses of this class provide additional validation and typed values for specific 1.50 + * iCalendar properties. 1.51 + * 1.52 + * Note that subclasses must provide a reference to the factory used to create the 1.53 + * property to support property cloning (copy). If no factory is specified an 1.54 + * {@link UnsupportedOperationException} will be thrown by the {@link #copy()} method. 1.55 + * 1.56 + * @author Ben Fortuna 1.57 + * 1.58 + * $Id$ [Apr 5, 2004] 1.59 + */ 1.60 +public abstract class Property extends Content { 1.61 + 1.62 + private static final long serialVersionUID = 7048785558435608687L; 1.63 + 1.64 + // iCalendar properties.. 1.65 + 1.66 + /** 1.67 + * Product identifier property name. 1.68 + */ 1.69 + public static final String PRODID = "PRODID"; 1.70 + 1.71 + /** 1.72 + * iCalendar version property name. 1.73 + */ 1.74 + public static final String VERSION = "VERSION"; 1.75 + 1.76 + /** 1.77 + * Calendar scale property name. 1.78 + */ 1.79 + public static final String CALSCALE = "CALSCALE"; 1.80 + 1.81 + /** 1.82 + * iTIP method property name. 1.83 + */ 1.84 + public static final String METHOD = "METHOD"; 1.85 + 1.86 + // Component properties.. 1.87 + 1.88 + /** 1.89 + * Busy type property name. 1.90 + */ 1.91 + public static final String BUSYTYPE = "BUSYTYPE"; 1.92 + 1.93 + /** 1.94 + * Classifier property name. 1.95 + */ 1.96 + public static final String CLASS = "CLASS"; 1.97 + 1.98 + /** 1.99 + * Creation date property name. 1.100 + */ 1.101 + public static final String CREATED = "CREATED"; 1.102 + 1.103 + /** 1.104 + * Description property name. 1.105 + */ 1.106 + public static final String DESCRIPTION = "DESCRIPTION"; 1.107 + 1.108 + /** 1.109 + * Start date property name. 1.110 + */ 1.111 + public static final String DTSTART = "DTSTART"; 1.112 + 1.113 + /** 1.114 + * Geographic location property name. 1.115 + */ 1.116 + public static final String GEO = "GEO"; 1.117 + 1.118 + /** 1.119 + * Last modified date property name. 1.120 + */ 1.121 + public static final String LAST_MODIFIED = "LAST-MODIFIED"; 1.122 + 1.123 + /** 1.124 + * Location property name. 1.125 + */ 1.126 + public static final String LOCATION = "LOCATION"; 1.127 + 1.128 + /** 1.129 + * Organiser property name. 1.130 + */ 1.131 + public static final String ORGANIZER = "ORGANIZER"; 1.132 + 1.133 + /** 1.134 + * Percentage complete property name. 1.135 + */ 1.136 + public static final String PERCENT_COMPLETE = "PERCENT-COMPLETE"; 1.137 + 1.138 + /** 1.139 + * Prority property name. 1.140 + */ 1.141 + public static final String PRIORITY = "PRIORITY"; 1.142 + 1.143 + /** 1.144 + * Date-stamp property name. 1.145 + */ 1.146 + public static final String DTSTAMP = "DTSTAMP"; 1.147 + 1.148 + /** 1.149 + * Sequence property name. 1.150 + */ 1.151 + public static final String SEQUENCE = "SEQUENCE"; 1.152 + 1.153 + /** 1.154 + * Status property name. 1.155 + */ 1.156 + public static final String STATUS = "STATUS"; 1.157 + 1.158 + /** 1.159 + * Summary property name. 1.160 + */ 1.161 + public static final String SUMMARY = "SUMMARY"; 1.162 + 1.163 + /** 1.164 + * Transparency property name. 1.165 + */ 1.166 + public static final String TRANSP = "TRANSP"; 1.167 + 1.168 + /** 1.169 + * Unique identifier property name. 1.170 + */ 1.171 + public static final String UID = "UID"; 1.172 + 1.173 + /** 1.174 + * Uniform resource locator property name. 1.175 + */ 1.176 + public static final String URL = "URL"; 1.177 + 1.178 + /** 1.179 + * Recurrence identifier property name. 1.180 + */ 1.181 + public static final String RECURRENCE_ID = "RECURRENCE-ID"; 1.182 + 1.183 + /** 1.184 + * Completed date property name. 1.185 + */ 1.186 + public static final String COMPLETED = "COMPLETED"; 1.187 + 1.188 + /** 1.189 + * Due date property name. 1.190 + */ 1.191 + public static final String DUE = "DUE"; 1.192 + 1.193 + /** 1.194 + * Free/busy property name. 1.195 + */ 1.196 + public static final String FREEBUSY = "FREEBUSY"; 1.197 + 1.198 + /** 1.199 + * Timezone identifier property name. 1.200 + */ 1.201 + public static final String TZID = "TZID"; 1.202 + 1.203 + /** 1.204 + * Timezone name property name. 1.205 + */ 1.206 + public static final String TZNAME = "TZNAME"; 1.207 + 1.208 + /** 1.209 + * Prior timezone offset property name. 1.210 + */ 1.211 + public static final String TZOFFSETFROM = "TZOFFSETFROM"; 1.212 + 1.213 + /** 1.214 + * New timezone offset property name. 1.215 + */ 1.216 + public static final String TZOFFSETTO = "TZOFFSETTO"; 1.217 + 1.218 + /** 1.219 + * URL for timezone definition property name. 1.220 + */ 1.221 + public static final String TZURL = "TZURL"; 1.222 + 1.223 + /** 1.224 + * Alarm action property name. 1.225 + */ 1.226 + public static final String ACTION = "ACTION"; 1.227 + 1.228 + /** 1.229 + * Repeat rule property name. 1.230 + */ 1.231 + public static final String REPEAT = "REPEAT"; 1.232 + 1.233 + /** 1.234 + * Alarm trigger property name. 1.235 + */ 1.236 + public static final String TRIGGER = "TRIGGER"; 1.237 + 1.238 + /** 1.239 + * Request status property name. 1.240 + */ 1.241 + public static final String REQUEST_STATUS = "REQUEST-STATUS"; 1.242 + 1.243 + /** 1.244 + * End date property name. 1.245 + */ 1.246 + public static final String DTEND = "DTEND"; 1.247 + 1.248 + /** 1.249 + * Duration property name. 1.250 + */ 1.251 + public static final String DURATION = "DURATION"; 1.252 + 1.253 + /** 1.254 + * Attachment property name. 1.255 + */ 1.256 + public static final String ATTACH = "ATTACH"; 1.257 + 1.258 + /** 1.259 + * Attendee property name. 1.260 + */ 1.261 + public static final String ATTENDEE = "ATTENDEE"; 1.262 + 1.263 + /** 1.264 + * Categories property name. 1.265 + */ 1.266 + public static final String CATEGORIES = "CATEGORIES"; 1.267 + 1.268 + /** 1.269 + * Comment property name. 1.270 + */ 1.271 + public static final String COMMENT = "COMMENT"; 1.272 + 1.273 + /** 1.274 + * Contact property name. 1.275 + */ 1.276 + public static final String CONTACT = "CONTACT"; 1.277 + 1.278 + /** 1.279 + * Exclusion date property name. 1.280 + */ 1.281 + public static final String EXDATE = "EXDATE"; 1.282 + 1.283 + /** 1.284 + * Exclusion rule property name. 1.285 + */ 1.286 + public static final String EXRULE = "EXRULE"; 1.287 + 1.288 + /** 1.289 + * Relationship property name. 1.290 + */ 1.291 + public static final String RELATED_TO = "RELATED-TO"; 1.292 + 1.293 + /** 1.294 + * Resources property name. 1.295 + */ 1.296 + public static final String RESOURCES = "RESOURCES"; 1.297 + 1.298 + /** 1.299 + * Recurrence date property name. 1.300 + */ 1.301 + public static final String RDATE = "RDATE"; 1.302 + 1.303 + /** 1.304 + * Recurrence rule property name. 1.305 + */ 1.306 + public static final String RRULE = "RRULE"; 1.307 + 1.308 + /** 1.309 + * Prefix for non-standard properties. 1.310 + */ 1.311 + public static final String EXPERIMENTAL_PREFIX = "X-"; 1.312 + 1.313 + /** 1.314 + * VVENUE country property name. 1.315 + */ 1.316 + public static final String COUNTRY = "COUNTRY"; 1.317 + 1.318 + /** 1.319 + * VVENUE extended address property name. 1.320 + */ 1.321 + public static final String EXTENDED_ADDRESS = "EXTENDED-ADDRESS"; 1.322 + 1.323 + /** 1.324 + * VVENUE locality property name. 1.325 + */ 1.326 + public static final String LOCALITY = "LOCALITY"; 1.327 + 1.328 + /** 1.329 + * VVENUE location type property name. 1.330 + */ 1.331 + public static final String LOCATION_TYPE = "LOCATION-TYPE"; 1.332 + 1.333 + /** 1.334 + * VVENUE name property name. 1.335 + */ 1.336 + public static final String NAME = "NAME"; 1.337 + 1.338 + /** 1.339 + * VVENUE postal code property name. 1.340 + */ 1.341 + public static final String POSTALCODE = "POSTAL-CODE"; 1.342 + 1.343 + /** 1.344 + * VVENUE region property name. 1.345 + */ 1.346 + public static final String REGION = "REGION"; 1.347 + 1.348 + /** 1.349 + * VVENUE street address property name. 1.350 + */ 1.351 + public static final String STREET_ADDRESS = "STREET-ADDRESS"; 1.352 + 1.353 + /** 1.354 + * VVENUE telephone property name. 1.355 + */ 1.356 + public static final String TEL = "TEL"; 1.357 + 1.358 + private String name; 1.359 + 1.360 + private ParameterList parameters; 1.361 + 1.362 + private final PropertyFactory factory; 1.363 + 1.364 + /** 1.365 + * Constructor. 1.366 + * @param aName property name 1.367 + * @param factory the factory used to create the property instance 1.368 + */ 1.369 + protected Property(final String aName, PropertyFactory factory) { 1.370 + this(aName, new ParameterList(), factory); 1.371 + } 1.372 + 1.373 + /** 1.374 + * Constructor made protected to enforce the use of <code>PropertyFactory</code> for property instantiation. 1.375 + * @param aName property name 1.376 + * @param aList a list of parameters 1.377 + */ 1.378 +// protected Property(final String aName, final ParameterList aList) { 1.379 +// this(aName, aList, PropertyFactoryImpl.getInstance()); 1.380 +// } 1.381 + 1.382 + /** 1.383 + * @param aName a property identifier 1.384 + * @param aList a list of initial parameters 1.385 + * @param factory the factory used to create the property instance 1.386 + */ 1.387 + protected Property(final String aName, final ParameterList aList, PropertyFactory factory) { 1.388 + this.name = aName; 1.389 + this.parameters = aList; 1.390 + this.factory = factory; 1.391 + } 1.392 + 1.393 + /** 1.394 + * Creates a deep copy of the specified property. That is, the name, parameter list, and value are duplicated from 1.395 + * the specified property. This constructor should only be called from sub-classes to ensure type integrity is 1.396 + * maintained. 1.397 + * @param property a property to copy 1.398 + * @throws URISyntaxException where the specified property contains an invalid URI value 1.399 + * @throws ParseException where the specified property has invalid data 1.400 + * @throws IOException where an error occurs reading data from the specified property 1.401 + * @deprecated Use {@link #copy()} instead 1.402 + */ 1.403 + protected Property(final Property property) throws IOException, 1.404 + URISyntaxException, ParseException { 1.405 + this(property.getName(), new ParameterList(property.getParameters(), false), 1.406 + property.factory); 1.407 + setValue(property.getValue()); 1.408 + } 1.409 + 1.410 + /** 1.411 + * {@inheritDoc} 1.412 + */ 1.413 + public final String toString() { 1.414 + final StringBuffer buffer = new StringBuffer(); 1.415 + buffer.append(getName()); 1.416 + if (getParameters() != null) { 1.417 + buffer.append(getParameters()); 1.418 + } 1.419 + buffer.append(':'); 1.420 + boolean needsEscape = false; 1.421 + if (this instanceof XProperty) { 1.422 + Value valParam = (Value)getParameter(Parameter.VALUE); 1.423 + if (valParam == null || valParam.equals(Value.TEXT)) { 1.424 + needsEscape = true; 1.425 + } 1.426 + } else if (this instanceof Escapable) { 1.427 + needsEscape = true; 1.428 + } 1.429 + if (needsEscape) { 1.430 + buffer.append(Strings.escape(Strings.valueOf(getValue()))); 1.431 + } 1.432 + else { 1.433 + buffer.append(Strings.valueOf(getValue())); 1.434 + } 1.435 + buffer.append(Strings.LINE_SEPARATOR); 1.436 + 1.437 + return buffer.toString(); 1.438 + } 1.439 + 1.440 + /** 1.441 + * Indicates whether this property is a calendar property. 1.442 + * @return boolean 1.443 + */ 1.444 + public boolean isCalendarProperty() { 1.445 + 1.446 + return PRODID.equalsIgnoreCase(getName()) 1.447 + || VERSION.equalsIgnoreCase(getName()) 1.448 + || CALSCALE.equalsIgnoreCase(getName()) 1.449 + || METHOD.equalsIgnoreCase(getName()); 1.450 + } 1.451 + 1.452 + /** 1.453 + * @return Returns the name. 1.454 + */ 1.455 + public final String getName() { 1.456 + return name; 1.457 + } 1.458 + 1.459 + /** 1.460 + * @return Returns the parameters. 1.461 + */ 1.462 + public final ParameterList getParameters() { 1.463 + return parameters; 1.464 + } 1.465 + 1.466 + /** 1.467 + * Convenience method for retrieving a list of named parameters. 1.468 + * @param name name of parameters to retrieve 1.469 + * @return a parameter list containing only parameters with the specified name 1.470 + */ 1.471 + public final ParameterList getParameters(final String name) { 1.472 + return getParameters().getParameters(name); 1.473 + } 1.474 + 1.475 + /** 1.476 + * Convenience method for retrieving a single parameter. 1.477 + * @param name name of the parameter to retrieve 1.478 + * @return the first parameter from the parameter list with the specified name 1.479 + */ 1.480 + public final Parameter getParameter(final String name) { 1.481 + return getParameters().getParameter(name); 1.482 + } 1.483 + 1.484 + /** 1.485 + * Sets the current value of the property. 1.486 + * @param aValue a string representation of the property value 1.487 + * @throws IOException possibly thrown by setting the value of certain properties 1.488 + * @throws URISyntaxException possibly thrown by setting the value of certain properties 1.489 + * @throws ParseException possibly thrown by setting the value of certain properties 1.490 + */ 1.491 + public abstract void setValue(String aValue) throws IOException, 1.492 + URISyntaxException, ParseException; 1.493 + 1.494 + /** 1.495 + * Perform validation on a property. 1.496 + * @throws ValidationException where the property is not in a valid state 1.497 + */ 1.498 + public abstract void validate() throws ValidationException; 1.499 + 1.500 + /** 1.501 + * {@inheritDoc} 1.502 + */ 1.503 + public final boolean equals(final Object arg0) { 1.504 + if (arg0 instanceof Property) { 1.505 + final Property p = (Property) arg0; 1.506 + if (getName().equals(p.getName())) { 1.507 + return new EqualsBuilder().append(getValue(), p.getValue()) 1.508 + .append(getParameters(), p.getParameters()).isEquals(); 1.509 + } else { 1.510 + return false; 1.511 + } 1.512 + } 1.513 + return super.equals(arg0); 1.514 + } 1.515 + 1.516 + /** 1.517 + * {@inheritDoc} 1.518 + */ 1.519 + public int hashCode() { 1.520 + // as property name is case-insensitive generate hash for uppercase.. 1.521 + return new HashCodeBuilder().append(getName().toUpperCase()).append( 1.522 + getValue()).append(getParameters()).toHashCode(); 1.523 + } 1.524 + 1.525 + /** 1.526 + * Create a (deep) copy of this property. 1.527 + * @return the copy of the property 1.528 + * @throws IOException where an error occurs reading property data 1.529 + * @throws URISyntaxException where the property contains an invalid URI value 1.530 + * @throws ParseException where the property contains an invalid date value 1.531 + */ 1.532 + public Property copy() throws IOException, URISyntaxException, ParseException { 1.533 + if (factory == null) { 1.534 + throw new UnsupportedOperationException("No factory specified"); 1.535 + } 1.536 + // Deep copy parameter list.. 1.537 + final ParameterList params = new ParameterList(getParameters(), false); 1.538 + return factory.createProperty(getName(), params, getValue()); 1.539 + } 1.540 +}