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 }