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&lt;ICalendar&gt; icals = new ArrayList&lt;ICalendar&gt;();
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    }