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    }