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 }