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.component.ICalComponent; 013 import biweekly.component.VEvent; 014 import biweekly.component.VFreeBusy; 015 import biweekly.component.VJournal; 016 import biweekly.component.VTimezone; 017 import biweekly.component.VTodo; 018 import biweekly.property.CalendarScale; 019 import biweekly.property.Method; 020 import biweekly.property.ProductId; 021 import biweekly.property.Version; 022 023 /* 024 Copyright (c) 2013, 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> 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 */ 072 public class ICalendar extends ICalComponent { 073 /** 074 * <p> 075 * Creates a new iCalendar object. 076 * </p> 077 * <p> 078 * The following properties are auto-generated on object creation. These 079 * properties <b>must</b> be present in order for the iCalendar object to be 080 * valid: 081 * <ul> 082 * <li>{@link Version} - Set to the default iCalendar version ("2.0").</li> 083 * <li>{@link ProductId} - Set to a value that represents this library.</li> 084 * </ul> 085 * </p> 086 */ 087 public ICalendar() { 088 setVersion(Version.v2_0()); 089 setProductId(ProductId.biweekly()); 090 } 091 092 /** 093 * Gets the min/max versions a consumer must support in order to 094 * successfully parse the iCalendar object. All {@link ICalendar} objects 095 * are initialized with a version of "2.0" (the default version). It is a 096 * <b>required</b> property. 097 * @return the version 098 * @see <a href="http://tools.ietf.org/html/rfc5545#page-79">RFC 5545 099 * p.79-80</a> 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 * @see <a href="http://tools.ietf.org/html/rfc5545#page-79">RFC 5545 112 * p.79-80</a> 113 */ 114 public void setVersion(Version version) { 115 setProperty(Version.class, version); 116 } 117 118 /** 119 * Gets the name of the application that created the iCalendar object. All 120 * {@link ICalendar} objects are initialized with a product ID representing 121 * this library. It is a <b>required</b> property. 122 * @return the property instance or null if not set 123 * @see <a href="http://tools.ietf.org/html/rfc5545#page-78">RFC 5545 124 * p.78-9</a> 125 */ 126 public ProductId getProductId() { 127 return getProperty(ProductId.class); 128 } 129 130 /** 131 * Sets the name of the application that created the iCalendar object. All 132 * {@link ICalendar} objects are initialized with a product ID representing 133 * this library. It is a <b>required</b> property. 134 * @param prodId the property instance or null to remove 135 * @see <a href="http://tools.ietf.org/html/rfc5545#page-78">RFC 5545 136 * p.78-9</a> 137 */ 138 public void setProductId(ProductId prodId) { 139 setProperty(ProductId.class, prodId); 140 } 141 142 /** 143 * Sets the application that created the iCalendar object. All 144 * {@link ICalendar} objects are initialized with a product ID representing 145 * this library. 146 * @param prodId a unique string representing the application (e.g. 147 * "-//Company//Application//EN") or null to remove 148 * @return the property that was created 149 * @see <a href="http://tools.ietf.org/html/rfc5545#page-78">RFC 5545 150 * p.78-9</a> 151 */ 152 public ProductId setProductId(String prodId) { 153 ProductId prop = (prodId == null) ? null : new ProductId(prodId); 154 setProductId(prop); 155 return prop; 156 } 157 158 /** 159 * Gets the calendar system that this iCalendar object uses. If none is 160 * specified, then the calendar is assumed to be in Gregorian format. 161 * @return the calendar system or null if not set 162 * @see <a href="http://tools.ietf.org/html/rfc5545#page-76">RFC 5545 163 * p.76-7</a> 164 */ 165 public CalendarScale getCalendarScale() { 166 return getProperty(CalendarScale.class); 167 } 168 169 /** 170 * Sets the calendar system that this iCalendar object uses. If none is 171 * specified, then the calendar is assumed to be in Gregorian format. 172 * @param calendarScale the calendar system or null to remove 173 * @see <a href="http://tools.ietf.org/html/rfc5545#page-76">RFC 5545 174 * p.76-7</a> 175 */ 176 public void setCalendarScale(CalendarScale calendarScale) { 177 setProperty(calendarScale); 178 } 179 180 /** 181 * Gets the value of the Content-Type "method" parameter if the iCalendar 182 * object is defined as a MIME message entity. 183 * @return the property or null if not set 184 * @see <a href="http://tools.ietf.org/html/rfc5545#page-77">RFC 5545 185 * p.77-8</a> 186 */ 187 public Method getMethod() { 188 return getProperty(Method.class); 189 } 190 191 /** 192 * Sets the value of the Content-Type "method" parameter if the iCalendar 193 * object is defined as a MIME message entity. 194 * @param method the property or null to remove 195 * @see <a href="http://tools.ietf.org/html/rfc5545#page-77">RFC 5545 196 * p.77-8</a> 197 */ 198 public void setMethod(Method method) { 199 setProperty(method); 200 } 201 202 /** 203 * Gets the events. 204 * @return the events 205 */ 206 public List<VEvent> getEvents() { 207 return getComponents(VEvent.class); 208 } 209 210 /** 211 * Adds an event. 212 * @param event the event 213 */ 214 public void addEvent(VEvent event) { 215 addComponent(event); 216 } 217 218 /** 219 * Gets the to-dos. 220 * @return the to-dos 221 */ 222 public List<VTodo> getTodos() { 223 return getComponents(VTodo.class); 224 } 225 226 /** 227 * Adds a to-do. 228 * @param todo the to-do 229 */ 230 public void addVTodo(VTodo todo) { 231 addComponent(todo); 232 } 233 234 /** 235 * Gets the journal entries. 236 * @return the journal entries 237 */ 238 public List<VJournal> getJournals() { 239 return getComponents(VJournal.class); 240 } 241 242 /** 243 * Adds a journal entry. 244 * @param journal the journal entry 245 */ 246 public void addJournal(VJournal journal) { 247 addComponent(journal); 248 } 249 250 /** 251 * Gets the free/busy entries. 252 * @return the free/busy entries 253 */ 254 public List<VFreeBusy> getFreeBusies() { 255 return getComponents(VFreeBusy.class); 256 } 257 258 /** 259 * Adds a free/busy entry. 260 * @param freeBusy the free/busy entry 261 */ 262 public void addFreeBusy(VFreeBusy freeBusy) { 263 addComponent(freeBusy); 264 } 265 266 /** 267 * Gets the timezones. 268 * @return the timezones 269 */ 270 public List<VTimezone> getTimezones() { 271 return getComponents(VTimezone.class); 272 } 273 274 /** 275 * Adds a timezone. 276 * @param timezone the timezone 277 */ 278 public void addTimezone(VTimezone timezone) { 279 addComponent(timezone); 280 } 281 282 /** 283 * Checks this iCalendar object for data consistency problems or deviations 284 * from the spec. These problems will not prevent the iCalendar object from 285 * being written to a data stream, but may prevent it from being parsed 286 * correctly by the consuming application. These problems can largely be 287 * avoided by reading the Javadocs of the component and property classes, or 288 * by being familiar with the iCalendar standard. 289 * @return a list of warnings or an empty list if no problems were found 290 */ 291 public List<String> validate() { 292 //TODO make concurrent 293 return validate(new ArrayList<ICalComponent>()); 294 } 295 296 @SuppressWarnings("unchecked") 297 @Override 298 protected void validate(List<ICalComponent> components, List<String> warnings) { 299 checkRequiredCardinality(warnings, ProductId.class, Version.class); 300 301 if (this.components.isEmpty()) { 302 warnings.add("An iCalendar object must have at least one component."); 303 } 304 } 305 306 /** 307 * Marshals this iCalendar object to its plain text representation. 308 * @return the plain text representation 309 */ 310 public String write() { 311 return Biweekly.write(this).go(); 312 } 313 314 /** 315 * Marshals this iCalendar object to its plain text representation. 316 * @param file the file to write to 317 * @throws IOException if there's an I/O problem 318 */ 319 public void write(File file) throws IOException { 320 Biweekly.write(this).go(file); 321 } 322 323 /** 324 * Marshals this iCalendar object to its plain text representation. 325 * @param out the data stream to write to 326 * @throws IOException if there's an I/O problem 327 */ 328 public void write(OutputStream out) throws IOException { 329 Biweekly.write(this).go(out); 330 } 331 332 /** 333 * Marshals this iCalendar object to its plain text representation. 334 * @param writer the data stream to write to 335 * @throws IOException if there's an I/O problem 336 */ 337 public void write(Writer writer) throws IOException { 338 Biweekly.write(this).go(writer); 339 } 340 341 /** 342 * Marshals this iCalendar object to its XML representation (xCal). 343 * @return the XML document 344 */ 345 public String writeXml() { 346 return Biweekly.writeXml(this).indent(2).go(); 347 } 348 349 /** 350 * Marshals this iCalendar object to its XML representation (xCal). 351 * @param file the file to write to 352 * @throws TransformerException if there's an I/O problem 353 * @throws IOException if the file cannot be written to 354 */ 355 public void writeXml(File file) throws TransformerException, IOException { 356 Biweekly.writeXml(this).indent(2).go(file); 357 } 358 359 /** 360 * Marshals this iCalendar object to its XML representation (xCal). 361 * @param out the data stream to write to 362 * @throws TransformerException if there's an I/O problem 363 */ 364 public void writeXml(OutputStream out) throws TransformerException { 365 Biweekly.writeXml(this).indent(2).go(out); 366 } 367 368 /** 369 * Marshals this iCalendar object to its XML representation (xCal). 370 * @param writer the data stream to write to 371 * @throws TransformerException if there's an I/O problem 372 */ 373 public void writeXml(Writer writer) throws TransformerException { 374 Biweekly.writeXml(this).indent(2).go(writer); 375 } 376 }