001package biweekly; 002 003import java.io.File; 004import java.io.IOException; 005import java.io.OutputStream; 006import java.io.Writer; 007import java.util.ArrayList; 008import java.util.List; 009 010import javax.xml.transform.TransformerException; 011 012import biweekly.ValidationWarnings.WarningsGroup; 013import biweekly.component.ICalComponent; 014import biweekly.component.VEvent; 015import biweekly.component.VFreeBusy; 016import biweekly.component.VJournal; 017import biweekly.component.VTodo; 018import biweekly.property.CalendarScale; 019import biweekly.property.Geo; 020import biweekly.property.Method; 021import biweekly.property.ProductId; 022 023/* 024 Copyright (c) 2013-2015, Michael Angstadt 025 All rights reserved. 026 027 Redistribution and use in source and binary forms, with or without 028 modification, are permitted provided that the following conditions are met: 029 030 1. Redistributions of source code must retain the above copyright notice, this 031 list of conditions and the following disclaimer. 032 2. Redistributions in binary form must reproduce the above copyright notice, 033 this list of conditions and the following disclaimer in the documentation 034 and/or other materials provided with the distribution. 035 036 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 037 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 038 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 039 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 040 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 041 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 042 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 043 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 044 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 045 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 046 */ 047 048/** 049 * <p> 050 * Represents an iCalendar object. 051 * </p> 052 * 053 * <p> 054 * <b>Examples:</b> 055 * 056 * <pre class="brush:java"> 057 * ICalendar ical = new ICalendar(); 058 * 059 * VEvent event = new VEvent(); 060 * event.setSummary("Team Meeting"); 061 * Date start = ...; 062 * event.setDateStart(start); 063 * Date end = ...; 064 * event.setDateEnd(end); 065 * ical.addEvent(event); 066 * </pre> 067 * 068 * </p> 069 * @author Michael Angstadt 070 * @see <a href="http://tools.ietf.org/html/rfc5545">RFC 5545</a> 071 */ 072public class ICalendar extends ICalComponent { 073 private ICalVersion version; 074 075 /** 076 * <p> 077 * Creates a new iCalendar object. 078 * </p> 079 * <p> 080 * The following properties are auto-generated on object creation. These 081 * properties <b>must</b> be present in order for the iCalendar object to be 082 * valid: 083 * <ul> 084 * <li>{@link ProductId} - Set to a value that represents this library.</li> 085 * </ul> 086 * </p> 087 */ 088 public ICalendar() { 089 setProductId(ProductId.biweekly()); 090 } 091 092 /** 093 * Gets the version of this iCalendar object. 094 * @return the version 095 */ 096 public ICalVersion getVersion() { 097 return version; 098 } 099 100 /** 101 * Sets the version of this iCalendar object. 102 * @param version the version 103 */ 104 public void setVersion(ICalVersion version) { 105 this.version = version; 106 } 107 108 /** 109 * Gets the name of the application that created the iCalendar object. All 110 * {@link ICalendar} objects are initialized with a product ID representing 111 * this library. It is a <b>required</b> property. 112 * @return the property instance or null if not set 113 * @see <a href="http://tools.ietf.org/html/rfc5545#page-78">RFC 5545 114 * p.78-9</a> 115 * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.24</a> 116 */ 117 public ProductId getProductId() { 118 return getProperty(ProductId.class); 119 } 120 121 /** 122 * Sets the name of the application that created the iCalendar object. All 123 * {@link ICalendar} objects are initialized with a product ID representing 124 * this library. It is a <b>required</b> property. 125 * @param prodId the property instance or null to remove 126 * @see <a href="http://tools.ietf.org/html/rfc5545#page-78">RFC 5545 127 * p.78-9</a> 128 * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.24</a> 129 */ 130 public void setProductId(ProductId prodId) { 131 setProperty(ProductId.class, prodId); 132 } 133 134 /** 135 * Sets the application that created the iCalendar object. All 136 * {@link ICalendar} objects are initialized with a product ID representing 137 * this library. 138 * @param prodId a unique string representing the application (e.g. 139 * "-//Company//Application//EN") or null to remove 140 * @return the property that was created 141 * @see <a href="http://tools.ietf.org/html/rfc5545#page-78">RFC 5545 142 * p.78-9</a> 143 * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.24</a> 144 */ 145 public ProductId setProductId(String prodId) { 146 ProductId prop = (prodId == null) ? null : new ProductId(prodId); 147 setProductId(prop); 148 return prop; 149 } 150 151 /** 152 * Gets the calendar system that this iCalendar object uses. If none is 153 * specified, then the calendar is assumed to be in Gregorian format. 154 * @return the calendar system or null if not set 155 * @see <a href="http://tools.ietf.org/html/rfc5545#page-76">RFC 5545 156 * p.76-7</a> 157 */ 158 public CalendarScale getCalendarScale() { 159 return getProperty(CalendarScale.class); 160 } 161 162 /** 163 * Sets the calendar system that this iCalendar object uses. If none is 164 * specified, then the calendar is assumed to be in Gregorian format. 165 * @param calendarScale the calendar system or null to remove 166 * @see <a href="http://tools.ietf.org/html/rfc5545#page-76">RFC 5545 167 * p.76-7</a> 168 */ 169 public void setCalendarScale(CalendarScale calendarScale) { 170 setProperty(CalendarScale.class, calendarScale); 171 } 172 173 /** 174 * Gets the value of the Content-Type "method" parameter if the iCalendar 175 * object is defined as a MIME message entity. 176 * @return the property or null if not set 177 * @see <a href="http://tools.ietf.org/html/rfc5545#page-77">RFC 5545 178 * p.77-8</a> 179 */ 180 public Method getMethod() { 181 return getProperty(Method.class); 182 } 183 184 /** 185 * Sets the value of the Content-Type "method" parameter if the iCalendar 186 * object is defined as a MIME message entity. 187 * @param method the property or null to remove 188 * @see <a href="http://tools.ietf.org/html/rfc5545#page-77">RFC 5545 189 * p.77-8</a> 190 */ 191 public void setMethod(Method method) { 192 setProperty(Method.class, method); 193 } 194 195 /** 196 * Sets the value of the Content-Type "method" parameter if the iCalendar 197 * object is defined as a MIME message entity. 198 * @param method the method or null to remove 199 * @return the property that was created 200 * @see <a href="http://tools.ietf.org/html/rfc5545#page-77">RFC 5545 201 * p.77-8</a> 202 */ 203 public Method setMethod(String method) { 204 Method prop = (method == null) ? null : new Method(method); 205 setMethod(prop); 206 return prop; 207 } 208 209 /** 210 * Gets the events. 211 * @return the events 212 * @see <a href="http://tools.ietf.org/html/rfc5545#page-52">RFC 5545 213 * p.52-5</a> 214 * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.13</a> 215 */ 216 public List<VEvent> getEvents() { 217 return getComponents(VEvent.class); 218 } 219 220 /** 221 * Adds an event. 222 * @param event the event 223 * @see <a href="http://tools.ietf.org/html/rfc5545#page-52">RFC 5545 224 * p.52-5</a> 225 * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.13</a> 226 */ 227 public void addEvent(VEvent event) { 228 addComponent(event); 229 } 230 231 /** 232 * Gets the to-dos. 233 * @return the to-dos 234 * @see <a href="http://tools.ietf.org/html/rfc5545#page-55">RFC 5545 235 * p.55-7</a> 236 * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.14</a> 237 */ 238 public List<VTodo> getTodos() { 239 return getComponents(VTodo.class); 240 } 241 242 /** 243 * Adds a to-do. 244 * @param todo the to-do 245 * @see <a href="http://tools.ietf.org/html/rfc5545#page-55">RFC 5545 246 * p.55-7</a> 247 * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.14</a> 248 */ 249 public void addTodo(VTodo todo) { 250 addComponent(todo); 251 } 252 253 /** 254 * Gets the journal entries. 255 * @return the journal entries 256 * @see <a href="http://tools.ietf.org/html/rfc5545#page-55">RFC 5545 257 * p.57-9</a> 258 */ 259 public List<VJournal> getJournals() { 260 return getComponents(VJournal.class); 261 } 262 263 /** 264 * Adds a journal entry. 265 * @param journal the journal entry 266 * @see <a href="http://tools.ietf.org/html/rfc5545#page-55">RFC 5545 267 * p.57-9</a> 268 */ 269 public void addJournal(VJournal journal) { 270 addComponent(journal); 271 } 272 273 /** 274 * Gets the free/busy entries. 275 * @return the free/busy entries 276 * @see <a href="http://tools.ietf.org/html/rfc5545#page-59">RFC 5545 277 * p.59-62</a> 278 */ 279 public List<VFreeBusy> getFreeBusies() { 280 return getComponents(VFreeBusy.class); 281 } 282 283 /** 284 * Adds a free/busy entry. 285 * @param freeBusy the free/busy entry 286 * @see <a href="http://tools.ietf.org/html/rfc5545#page-59">RFC 5545 287 * p.59-62</a> 288 */ 289 public void addFreeBusy(VFreeBusy freeBusy) { 290 addComponent(freeBusy); 291 } 292 293 /** 294 * Checks this iCalendar object for data consistency problems or deviations 295 * from the spec. These problems will not prevent the iCalendar object from 296 * being written to a data stream, but may prevent it from being parsed 297 * correctly by the consuming application. These problems can largely be 298 * avoided by reading the Javadocs of the component and property classes, or 299 * by being familiar with the iCalendar standard. 300 * @param version the version to validate against 301 * @return the validation warnings 302 */ 303 public ValidationWarnings validate(ICalVersion version) { 304 List<WarningsGroup> warnings = validate(new ArrayList<ICalComponent>(0), version); 305 return new ValidationWarnings(warnings); 306 } 307 308 @SuppressWarnings("unchecked") 309 @Override 310 protected void validate(List<ICalComponent> components, ICalVersion version, List<Warning> warnings) { 311 if (version != ICalVersion.V1_0) { 312 checkRequiredCardinality(warnings, ProductId.class); 313 314 if (this.components.isEmpty()) { 315 warnings.add(Warning.validate(4)); 316 } 317 318 if (getProperty(Geo.class) != null) { 319 warnings.add(Warning.validate(44)); 320 } 321 } 322 } 323 324 /** 325 * Marshals this iCalendar object to its plain text representation. 326 * @return the plain text representation 327 */ 328 public String write() { 329 ICalVersion version = (this.version == null) ? ICalVersion.V2_0 : this.version; 330 return Biweekly.write(this).version(version).go(); 331 } 332 333 /** 334 * Marshals this iCalendar object to its plain text representation. 335 * @param file the file to write to 336 * @throws IOException if there's an I/O problem 337 */ 338 public void write(File file) throws IOException { 339 ICalVersion version = (this.version == null) ? ICalVersion.V2_0 : this.version; 340 Biweekly.write(this).version(version).go(file); 341 } 342 343 /** 344 * Marshals this iCalendar object to its plain text representation. 345 * @param out the data stream to write to 346 * @throws IOException if there's an I/O problem 347 */ 348 public void write(OutputStream out) throws IOException { 349 ICalVersion version = (this.version == null) ? ICalVersion.V2_0 : this.version; 350 Biweekly.write(this).version(version).go(out); 351 } 352 353 /** 354 * Marshals this iCalendar object to its plain text representation. 355 * @param writer the data stream to write to 356 * @throws IOException if there's an I/O problem 357 */ 358 public void write(Writer writer) throws IOException { 359 ICalVersion version = (this.version == null) ? ICalVersion.V2_0 : this.version; 360 Biweekly.write(this).version(version).go(writer); 361 } 362 363 /** 364 * Marshals this iCalendar object to its XML representation (xCal). If the 365 * iCalendar object contains user-defined property or component objects, use 366 * the {@link Biweekly} class instead, in order to register the scribe 367 * classes. 368 * @return the XML document 369 * @throws IllegalArgumentException if the iCalendar object contains 370 * user-defined property or component objects 371 */ 372 public String writeXml() { 373 return Biweekly.writeXml(this).indent(2).go(); 374 } 375 376 /** 377 * Marshals this iCalendar object to its XML representation (xCal). If the 378 * iCalendar object contains user-defined property or component objects, use 379 * the {@link Biweekly} class instead, in order to register the scribe 380 * classes. 381 * @param file the file to write to 382 * @throws IllegalArgumentException if the iCalendar object contains 383 * user-defined property or component objects 384 * @throws TransformerException if there's an I/O problem 385 * @throws IOException if the file cannot be written to 386 */ 387 public void writeXml(File file) throws TransformerException, IOException { 388 Biweekly.writeXml(this).indent(2).go(file); 389 } 390 391 /** 392 * Marshals this iCalendar object to its XML representation (xCal). If the 393 * iCalendar object contains user-defined property or component objects, use 394 * the {@link Biweekly} class instead, in order to register the scribe 395 * classes. 396 * @param out the data stream to write to 397 * @throws IllegalArgumentException if the iCalendar object contains 398 * user-defined property or component objects 399 * @throws TransformerException if there's an I/O problem 400 */ 401 public void writeXml(OutputStream out) throws TransformerException { 402 Biweekly.writeXml(this).indent(2).go(out); 403 } 404 405 /** 406 * Marshals this iCalendar object to its XML representation (xCal). If the 407 * iCalendar object contains user-defined property or component objects, use 408 * the {@link Biweekly} class instead, in order to register the scribe 409 * classes. 410 * @param writer the data stream to write to 411 * @throws IllegalArgumentException if the iCalendar object contains 412 * user-defined property or component objects 413 * @throws TransformerException if there's an I/O problem 414 */ 415 public void writeXml(Writer writer) throws TransformerException { 416 Biweekly.writeXml(this).indent(2).go(writer); 417 } 418 419 /** 420 * Marshals this iCalendar object to its JSON representation (jCal). If the 421 * iCalendar object contains user-defined property or component objects, use 422 * the {@link Biweekly} class instead, in order to register the scribe 423 * classes. 424 * @return the JSON string 425 * @throws IllegalArgumentException if the iCalendar object contains 426 * user-defined property or component objects 427 */ 428 public String writeJson() { 429 return Biweekly.writeJson(this).go(); 430 } 431 432 /** 433 * Marshals this iCalendar object to its JSON representation (jCal). If the 434 * iCalendar object contains user-defined property or component objects, use 435 * the {@link Biweekly} class instead, in order to register the scribe 436 * classes. 437 * @param file the file to write to 438 * @throws IllegalArgumentException if the iCalendar object contains 439 * user-defined property or component objects 440 * @throws IOException if there's a problem writing to the file 441 */ 442 public void writeJson(File file) throws IOException { 443 Biweekly.writeJson(this).go(file); 444 } 445 446 /** 447 * Marshals this iCalendar object to its JSON representation (jCal). If the 448 * iCalendar object contains user-defined property or component objects, use 449 * the {@link Biweekly} class instead, in order to register the scribe 450 * classes. 451 * @param out the data stream to write to 452 * @throws IllegalArgumentException if the iCalendar object contains 453 * user-defined property or component objects 454 * @throws IOException if there's a problem writing to the output stream 455 */ 456 public void writeJson(OutputStream out) throws IOException { 457 Biweekly.writeJson(this).go(out); 458 } 459 460 /** 461 * Marshals this iCalendar object to its JSON representation (jCal). If the 462 * iCalendar object contains user-defined property or component objects, use 463 * the {@link Biweekly} class instead, in order to register the scribe 464 * classes. 465 * @param writer the data stream to write to 466 * @throws IllegalArgumentException if the iCalendar object contains 467 * user-defined property or component objects 468 * @throws IOException if there's a problem writing to the writer 469 */ 470 public void writeJson(Writer writer) throws IOException { 471 Biweekly.writeJson(this).go(writer); 472 } 473}