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