001 package biweekly.io;
002
003 import java.util.HashMap;
004 import java.util.Map;
005
006 import javax.xml.namespace.QName;
007
008 import biweekly.ICalendar;
009 import biweekly.component.ICalComponent;
010 import biweekly.component.RawComponent;
011 import biweekly.component.marshaller.DaylightSavingsTimeMarshaller;
012 import biweekly.component.marshaller.ICalComponentMarshaller;
013 import biweekly.component.marshaller.ICalendarMarshaller;
014 import biweekly.component.marshaller.RawComponentMarshaller;
015 import biweekly.component.marshaller.StandardTimeMarshaller;
016 import biweekly.component.marshaller.VAlarmMarshaller;
017 import biweekly.component.marshaller.VEventMarshaller;
018 import biweekly.component.marshaller.VFreeBusyMarshaller;
019 import biweekly.component.marshaller.VJournalMarshaller;
020 import biweekly.component.marshaller.VTimezoneMarshaller;
021 import biweekly.component.marshaller.VTodoMarshaller;
022 import biweekly.io.xml.XCalNamespaceContext;
023 import biweekly.property.ICalProperty;
024 import biweekly.property.RawProperty;
025 import biweekly.property.Xml;
026 import biweekly.property.marshaller.ActionMarshaller;
027 import biweekly.property.marshaller.AttachmentMarshaller;
028 import biweekly.property.marshaller.AttendeeMarshaller;
029 import biweekly.property.marshaller.CalendarScaleMarshaller;
030 import biweekly.property.marshaller.CategoriesMarshaller;
031 import biweekly.property.marshaller.ClassificationMarshaller;
032 import biweekly.property.marshaller.CommentMarshaller;
033 import biweekly.property.marshaller.CompletedMarshaller;
034 import biweekly.property.marshaller.ContactMarshaller;
035 import biweekly.property.marshaller.CreatedMarshaller;
036 import biweekly.property.marshaller.DateDueMarshaller;
037 import biweekly.property.marshaller.DateEndMarshaller;
038 import biweekly.property.marshaller.DateStartMarshaller;
039 import biweekly.property.marshaller.DateTimeStampMarshaller;
040 import biweekly.property.marshaller.DescriptionMarshaller;
041 import biweekly.property.marshaller.DurationPropertyMarshaller;
042 import biweekly.property.marshaller.ExceptionDatesMarshaller;
043 import biweekly.property.marshaller.ExceptionRuleMarshaller;
044 import biweekly.property.marshaller.FreeBusyMarshaller;
045 import biweekly.property.marshaller.GeoMarshaller;
046 import biweekly.property.marshaller.ICalPropertyMarshaller;
047 import biweekly.property.marshaller.LastModifiedMarshaller;
048 import biweekly.property.marshaller.LocationMarshaller;
049 import biweekly.property.marshaller.MethodMarshaller;
050 import biweekly.property.marshaller.OrganizerMarshaller;
051 import biweekly.property.marshaller.PercentCompleteMarshaller;
052 import biweekly.property.marshaller.PriorityMarshaller;
053 import biweekly.property.marshaller.ProductIdMarshaller;
054 import biweekly.property.marshaller.RawPropertyMarshaller;
055 import biweekly.property.marshaller.RecurrenceDatesMarshaller;
056 import biweekly.property.marshaller.RecurrenceIdMarshaller;
057 import biweekly.property.marshaller.RecurrenceRuleMarshaller;
058 import biweekly.property.marshaller.RelatedToMarshaller;
059 import biweekly.property.marshaller.RepeatMarshaller;
060 import biweekly.property.marshaller.RequestStatusMarshaller;
061 import biweekly.property.marshaller.ResourcesMarshaller;
062 import biweekly.property.marshaller.SequenceMarshaller;
063 import biweekly.property.marshaller.StatusMarshaller;
064 import biweekly.property.marshaller.SummaryMarshaller;
065 import biweekly.property.marshaller.TimezoneIdMarshaller;
066 import biweekly.property.marshaller.TimezoneNameMarshaller;
067 import biweekly.property.marshaller.TimezoneOffsetFromMarshaller;
068 import biweekly.property.marshaller.TimezoneOffsetToMarshaller;
069 import biweekly.property.marshaller.TimezoneUrlMarshaller;
070 import biweekly.property.marshaller.TransparencyMarshaller;
071 import biweekly.property.marshaller.TriggerMarshaller;
072 import biweekly.property.marshaller.UidMarshaller;
073 import biweekly.property.marshaller.UrlMarshaller;
074 import biweekly.property.marshaller.VersionMarshaller;
075 import biweekly.property.marshaller.XmlMarshaller;
076
077 /*
078 Copyright (c) 2013, Michael Angstadt
079 All rights reserved.
080
081 Redistribution and use in source and binary forms, with or without
082 modification, are permitted provided that the following conditions are met:
083
084 1. Redistributions of source code must retain the above copyright notice, this
085 list of conditions and the following disclaimer.
086 2. Redistributions in binary form must reproduce the above copyright notice,
087 this list of conditions and the following disclaimer in the documentation
088 and/or other materials provided with the distribution.
089
090 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
091 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
092 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
093 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
094 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
095 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
096 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
097 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
098 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
099 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
100 */
101
102 /**
103 * <p>
104 * Manages a listing of component and property marshallers. This is useful for
105 * injecting the marshallers of any experimental components or properties you
106 * have defined into a reader or writer object. The same object instance can be
107 * reused and injected into multiple reader/writer classes.
108 * </p>
109 * <p>
110 * <b>Example:</b>
111 *
112 * <pre class="brush:java">
113 * //init the registrar
114 * ICalMarshallerRegistrar registrar = new ICalMarshallerRegistrar();
115 * registrar.register(new CustomPropertyMarshaller());
116 * registrar.register(new AnotherCustomPropertyMarshaller());
117 * registrar.register(new CustomComponentMarshaller());
118 *
119 * //inject into a reader class
120 * ICalReader textReader = new ICalReader(...);
121 * textReader.setRegistrar(registrar);
122 * List<ICalendar> icals = new ArrayList<ICalendar>();
123 * ICalendar ical;
124 * while ((ical = textReader.readNext()) != null){
125 * icals.add(ical);
126 * }
127 *
128 * //inject the same instance in another reader/writer class
129 * JCalWriter writer = new JCalWriter(...);
130 * writer.setRegistrar(registrar);
131 * for (ICalendar ical : icals){
132 * writer.write(ical);
133 * }
134 * </pre>
135 *
136 * </p>
137 * @author Michael Angstadt
138 */
139 public class ICalMarshallerRegistrar {
140 //define standard component marshallers
141 private static final Map<String, ICalComponentMarshaller<? extends ICalComponent>> standardCompByName = new HashMap<String, ICalComponentMarshaller<? extends ICalComponent>>();
142 private static final Map<Class<? extends ICalComponent>, ICalComponentMarshaller<? extends ICalComponent>> standardCompByClass = new HashMap<Class<? extends ICalComponent>, ICalComponentMarshaller<? extends ICalComponent>>();
143 static {
144 registerStandard(new ICalendarMarshaller());
145 registerStandard(new VAlarmMarshaller());
146 registerStandard(new VEventMarshaller());
147 registerStandard(new VFreeBusyMarshaller());
148 registerStandard(new VJournalMarshaller());
149 registerStandard(new VTodoMarshaller());
150 registerStandard(new VTimezoneMarshaller());
151 registerStandard(new StandardTimeMarshaller());
152 registerStandard(new DaylightSavingsTimeMarshaller());
153 }
154
155 //define standard property marshallers
156 private static final Map<String, ICalPropertyMarshaller<? extends ICalProperty>> standardPropByName = new HashMap<String, ICalPropertyMarshaller<? extends ICalProperty>>();
157 private static final Map<Class<? extends ICalProperty>, ICalPropertyMarshaller<? extends ICalProperty>> standardPropByClass = new HashMap<Class<? extends ICalProperty>, ICalPropertyMarshaller<? extends ICalProperty>>();
158 private static final Map<QName, ICalPropertyMarshaller<? extends ICalProperty>> standardPropByQName = new HashMap<QName, ICalPropertyMarshaller<? extends ICalProperty>>();
159 static {
160 //RFC 5545
161 registerStandard(new ActionMarshaller());
162 registerStandard(new AttachmentMarshaller());
163 registerStandard(new AttendeeMarshaller());
164 registerStandard(new CalendarScaleMarshaller());
165 registerStandard(new CategoriesMarshaller());
166 registerStandard(new ClassificationMarshaller());
167 registerStandard(new CommentMarshaller());
168 registerStandard(new CompletedMarshaller());
169 registerStandard(new ContactMarshaller());
170 registerStandard(new CreatedMarshaller());
171 registerStandard(new DateDueMarshaller());
172 registerStandard(new DateEndMarshaller());
173 registerStandard(new DateStartMarshaller());
174 registerStandard(new DateTimeStampMarshaller());
175 registerStandard(new DescriptionMarshaller());
176 registerStandard(new DurationPropertyMarshaller());
177 registerStandard(new ExceptionDatesMarshaller());
178 registerStandard(new FreeBusyMarshaller());
179 registerStandard(new GeoMarshaller());
180 registerStandard(new LastModifiedMarshaller());
181 registerStandard(new LocationMarshaller());
182 registerStandard(new MethodMarshaller());
183 registerStandard(new OrganizerMarshaller());
184 registerStandard(new PercentCompleteMarshaller());
185 registerStandard(new PriorityMarshaller());
186 registerStandard(new ProductIdMarshaller());
187 registerStandard(new RecurrenceDatesMarshaller());
188 registerStandard(new RecurrenceIdMarshaller());
189 registerStandard(new RecurrenceRuleMarshaller());
190 registerStandard(new RelatedToMarshaller());
191 registerStandard(new RepeatMarshaller());
192 registerStandard(new RequestStatusMarshaller());
193 registerStandard(new ResourcesMarshaller());
194 registerStandard(new SequenceMarshaller());
195 registerStandard(new StatusMarshaller());
196 registerStandard(new SummaryMarshaller());
197 registerStandard(new TimezoneIdMarshaller());
198 registerStandard(new TimezoneNameMarshaller());
199 registerStandard(new TimezoneOffsetFromMarshaller());
200 registerStandard(new TimezoneOffsetToMarshaller());
201 registerStandard(new TimezoneUrlMarshaller());
202 registerStandard(new TransparencyMarshaller());
203 registerStandard(new TriggerMarshaller());
204 registerStandard(new UidMarshaller());
205 registerStandard(new UrlMarshaller());
206 registerStandard(new VersionMarshaller());
207
208 //RFC 6321
209 registerStandard(new XmlMarshaller());
210
211 //RFC 2445
212 registerStandard(new ExceptionRuleMarshaller());
213 }
214
215 private final Map<String, ICalComponentMarshaller<? extends ICalComponent>> experimentalCompByName = new HashMap<String, ICalComponentMarshaller<? extends ICalComponent>>(0);
216 private final Map<Class<? extends ICalComponent>, ICalComponentMarshaller<? extends ICalComponent>> experimentalCompByClass = new HashMap<Class<? extends ICalComponent>, ICalComponentMarshaller<? extends ICalComponent>>(0);
217
218 private final Map<String, ICalPropertyMarshaller<? extends ICalProperty>> experimentalPropByName = new HashMap<String, ICalPropertyMarshaller<? extends ICalProperty>>(0);
219 private final Map<Class<? extends ICalProperty>, ICalPropertyMarshaller<? extends ICalProperty>> experimentalPropByClass = new HashMap<Class<? extends ICalProperty>, ICalPropertyMarshaller<? extends ICalProperty>>(0);
220 private final Map<QName, ICalPropertyMarshaller<? extends ICalProperty>> experimentalPropByQName = new HashMap<QName, ICalPropertyMarshaller<? extends ICalProperty>>(0);
221
222 /**
223 * Gets a component marshaller by name.
224 * @param componentName the component name (e.g. "VEVENT")
225 * @return the component marshaller or a {@link RawComponentMarshaller} if
226 * not found
227 */
228 public ICalComponentMarshaller<? extends ICalComponent> getComponentMarshaller(String componentName) {
229 componentName = componentName.toUpperCase();
230
231 ICalComponentMarshaller<? extends ICalComponent> marshaller = experimentalCompByName.get(componentName);
232 if (marshaller != null) {
233 return marshaller;
234 }
235
236 marshaller = standardCompByName.get(componentName);
237 if (marshaller != null) {
238 return marshaller;
239 }
240
241 return new RawComponentMarshaller(componentName);
242 }
243
244 /**
245 * Gets a property marshaller by name.
246 * @param propertyName the property name (e.g. "VERSION")
247 * @return the property marshaller or a {@link RawPropertyMarshaller} if not
248 * found
249 */
250 public ICalPropertyMarshaller<? extends ICalProperty> getPropertyMarshaller(String propertyName) {
251 propertyName = propertyName.toUpperCase();
252
253 ICalPropertyMarshaller<? extends ICalProperty> marshaller = experimentalPropByName.get(propertyName);
254 if (marshaller != null) {
255 return marshaller;
256 }
257
258 marshaller = standardPropByName.get(propertyName);
259 if (marshaller != null) {
260 return marshaller;
261 }
262
263 return new RawPropertyMarshaller(propertyName);
264 }
265
266 /**
267 * Gets a component marshaller by class.
268 * @param clazz the component class
269 * @return the component marshaller or null if not found
270 */
271 public ICalComponentMarshaller<? extends ICalComponent> getComponentMarshaller(Class<? extends ICalComponent> clazz) {
272 ICalComponentMarshaller<? extends ICalComponent> marshaller = experimentalCompByClass.get(clazz);
273 if (marshaller != null) {
274 return marshaller;
275 }
276
277 return standardCompByClass.get(clazz);
278 }
279
280 /**
281 * Gets a property marshaller by class.
282 * @param clazz the property class
283 * @return the property marshaller or null if not found
284 */
285 public ICalPropertyMarshaller<? extends ICalProperty> getPropertyMarshaller(Class<? extends ICalProperty> clazz) {
286 ICalPropertyMarshaller<? extends ICalProperty> marshaller = experimentalPropByClass.get(clazz);
287 if (marshaller != null) {
288 return marshaller;
289 }
290
291 return standardPropByClass.get(clazz);
292 }
293
294 /**
295 * Gets the appropriate component marshaller for a given component instance.
296 * @param component the component instance
297 * @return the component marshaller or null if not found
298 */
299 public ICalComponentMarshaller<? extends ICalComponent> getComponentMarshaller(ICalComponent component) {
300 if (component instanceof RawComponent) {
301 RawComponent raw = (RawComponent) component;
302 return new RawComponentMarshaller(raw.getName());
303 }
304
305 return getComponentMarshaller(component.getClass());
306 }
307
308 /**
309 * Gets the appropriate property marshaller for a given property instance.
310 * @param property the property instance
311 * @return the property marshaller or null if not found
312 */
313 public ICalPropertyMarshaller<? extends ICalProperty> getPropertyMarshaller(ICalProperty property) {
314 if (property instanceof RawProperty) {
315 RawProperty raw = (RawProperty) property;
316 return new RawPropertyMarshaller(raw.getName());
317 }
318
319 return getPropertyMarshaller(property.getClass());
320 }
321
322 /**
323 * Gets a property marshaller by XML local name and namespace.
324 * @param qname the XML local name and namespace
325 * @return the property marshaller or a {@link XmlMarshaller} if not found
326 */
327 public ICalPropertyMarshaller<? extends ICalProperty> getPropertyMarshaller(QName qname) {
328 ICalPropertyMarshaller<? extends ICalProperty> marshaller = experimentalPropByQName.get(qname);
329 if (marshaller != null) {
330 return marshaller;
331 }
332
333 marshaller = standardPropByQName.get(qname);
334 if (marshaller != null) {
335 return marshaller;
336 }
337
338 if (XCalNamespaceContext.XCAL_NS.equals(qname.getNamespaceURI())) {
339 return new RawPropertyMarshaller(qname.getLocalPart().toUpperCase());
340 }
341
342 return getPropertyMarshaller(Xml.class);
343 }
344
345 /**
346 * Registers a component marshaller.
347 * @param marshaller the marshaller to register
348 */
349 public void register(ICalComponentMarshaller<? extends ICalComponent> marshaller) {
350 experimentalCompByName.put(marshaller.getComponentName().toUpperCase(), marshaller);
351 experimentalCompByClass.put(marshaller.getComponentClass(), marshaller);
352 }
353
354 /**
355 * Registers a property marshaller.
356 * @param marshaller the marshaller to register
357 */
358 public void register(ICalPropertyMarshaller<? extends ICalProperty> marshaller) {
359 experimentalPropByName.put(marshaller.getPropertyName().toUpperCase(), marshaller);
360 experimentalPropByClass.put(marshaller.getPropertyClass(), marshaller);
361 experimentalPropByQName.put(marshaller.getQName(), marshaller);
362 }
363
364 /**
365 * Unregisters a component marshaller.
366 * @param marshaller the marshaller to unregister
367 */
368 public void unregister(ICalComponentMarshaller<? extends ICalComponent> marshaller) {
369 experimentalCompByName.remove(marshaller.getComponentName().toUpperCase());
370 experimentalCompByClass.remove(marshaller.getComponentClass());
371 }
372
373 /**
374 * Unregisters a property marshaller
375 * @param marshaller the marshaller to unregister
376 */
377 public void unregister(ICalPropertyMarshaller<? extends ICalProperty> marshaller) {
378 experimentalPropByName.remove(marshaller.getPropertyName().toUpperCase());
379 experimentalPropByClass.remove(marshaller.getPropertyClass());
380 experimentalPropByQName.remove(marshaller.getQName());
381 }
382
383 /**
384 * Convenience method for getting the marshaller of the root iCalendar
385 * component ("VCALENDAR").
386 * @return the marshaller
387 */
388 public static ICalendarMarshaller getICalendarMarshaller() {
389 return (ICalendarMarshaller) standardCompByClass.get(ICalendar.class);
390 }
391
392 private static void registerStandard(ICalComponentMarshaller<? extends ICalComponent> marshaller) {
393 standardCompByName.put(marshaller.getComponentName().toUpperCase(), marshaller);
394 standardCompByClass.put(marshaller.getComponentClass(), marshaller);
395 }
396
397 private static void registerStandard(ICalPropertyMarshaller<? extends ICalProperty> marshaller) {
398 standardPropByName.put(marshaller.getPropertyName().toUpperCase(), marshaller);
399 standardPropByClass.put(marshaller.getPropertyClass(), marshaller);
400 standardPropByQName.put(marshaller.getQName(), marshaller);
401 }
402 }