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    }