View Javadoc

1   /*
2    *  Copyright 2001-2005 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.time.convert;
17  
18  import org.joda.time.JodaTimePermission;
19  
20  /**
21   * ConverterManager controls the date and time converters.
22   * <p>
23   * This class enables additional conversion classes to be added via
24   * {@link #addInstantConverter(InstantConverter)}, which may replace an
25   * existing converter. Similar methods exist for duration, time period and
26   * interval converters.
27   * <p>
28   * This class is threadsafe, so adding/removing converters can be done at any
29   * time. Updating the set of convertors is relatively expensive, and so should
30   * not be performed often.
31   * <p>
32   * The default instant converters are:
33   * <ul>
34   * <li>ReadableInstant
35   * <li>String
36   * <li>Calendar
37   * <li>Date (includes sql package subclasses)
38   * <li>Long (milliseconds)
39   * <li>null (now)
40   * </ul>
41   * 
42   * The default partial converters are:
43   * <ul>
44   * <li>ReadablePartial
45   * <li>ReadableInstant
46   * <li>String
47   * <li>Calendar
48   * <li>Date (includes sql package subclasses)
49   * <li>Long (milliseconds)
50   * <li>null (now)
51   * </ul>
52   * 
53   * The default duration converters are:
54   * <ul>
55   * <li>ReadableDuration
56   * <li>ReadableInterval
57   * <li>String
58   * <li>Long (milliseconds)
59   * <li>null (zero ms)
60   * </ul>
61   *
62   * The default time period converters are:
63   * <ul>
64   * <li>ReadablePeriod
65   * <li>ReadableInterval
66   * <li>String
67   * <li>null (zero)
68   * </ul>
69   * 
70   * The default interval converters are:
71   * <ul>
72   * <li>ReadableInterval
73   * <li>String
74   * <li>null (zero-length from now to now)
75   * </ul>
76   *
77   * @author Stephen Colebourne
78   * @author Brian S O'Neill
79   * @since 1.0
80   */
81  public final class ConverterManager {
82  
83      /**
84       * Singleton instance, lazily loaded to avoid class loading.
85       */
86      private static ConverterManager INSTANCE;
87  
88      public static ConverterManager getInstance() {
89          if (INSTANCE == null) {
90              INSTANCE = new ConverterManager();
91          }
92          return INSTANCE;
93      }
94      
95      private ConverterSet iInstantConverters;
96      private ConverterSet iPartialConverters;
97      private ConverterSet iDurationConverters;
98      private ConverterSet iPeriodConverters;
99      private ConverterSet iIntervalConverters;
100     
101     /**
102      * Restricted constructor.
103      */
104     protected ConverterManager() {
105         super();
106 
107         iInstantConverters = new ConverterSet(new Converter[] {
108             ReadableInstantConverter.INSTANCE,
109             StringConverter.INSTANCE,
110             CalendarConverter.INSTANCE,
111             DateConverter.INSTANCE,
112             LongConverter.INSTANCE,
113             NullConverter.INSTANCE,
114         });
115 
116         iPartialConverters = new ConverterSet(new Converter[] {
117             ReadablePartialConverter.INSTANCE,
118             ReadableInstantConverter.INSTANCE,
119             StringConverter.INSTANCE,
120             CalendarConverter.INSTANCE,
121             DateConverter.INSTANCE,
122             LongConverter.INSTANCE,
123             NullConverter.INSTANCE,
124         });
125 
126         iDurationConverters = new ConverterSet(new Converter[] {
127             ReadableDurationConverter.INSTANCE,
128             ReadableIntervalConverter.INSTANCE,
129             StringConverter.INSTANCE,
130             LongConverter.INSTANCE,
131             NullConverter.INSTANCE,
132         });
133 
134         iPeriodConverters = new ConverterSet(new Converter[] {
135             ReadableDurationConverter.INSTANCE,
136             ReadablePeriodConverter.INSTANCE,
137             ReadableIntervalConverter.INSTANCE,
138             StringConverter.INSTANCE,
139             NullConverter.INSTANCE,
140         });
141 
142         iIntervalConverters = new ConverterSet(new Converter[] {
143             ReadableIntervalConverter.INSTANCE,
144             StringConverter.INSTANCE,
145             NullConverter.INSTANCE,
146         });
147     }
148 
149     //-----------------------------------------------------------------------
150     /**
151      * Gets the best converter for the object specified.
152      * 
153      * @param object  the object to convert
154      * @return the converter to use
155      * @throws IllegalArgumentException if no suitable converter
156      * @throws IllegalStateException if multiple converters match the type
157      * equally well
158      */
159     public InstantConverter getInstantConverter(Object object) {
160         InstantConverter converter =
161             (InstantConverter)iInstantConverters.select(object == null ? null : object.getClass());
162         if (converter != null) {
163             return converter;
164         }
165         throw new IllegalArgumentException("No instant converter found for type: " +
166             (object == null ? "null" : object.getClass().getName()));
167     }
168     
169     //-----------------------------------------------------------------------
170     /**
171      * Gets a copy of the set of converters.
172      * 
173      * @return the converters, a copy of the real data, never null
174      */
175     public InstantConverter[] getInstantConverters() {
176         ConverterSet set = iInstantConverters;
177         InstantConverter[] converters = new InstantConverter[set.size()];
178         set.copyInto(converters);
179         return converters;
180     }
181     
182     /**
183      * Adds a converter to the set of converters. If a matching converter is
184      * already in the set, the given converter replaces it. If the converter is
185      * exactly the same as one already in the set, no changes are made.
186      * <p>
187      * The order in which converters are added is not relevent. The best
188      * converter is selected by examining the object hierarchy.
189      * 
190      * @param converter  the converter to add, null ignored
191      * @return replaced converter, or null
192      */
193     public InstantConverter addInstantConverter(InstantConverter converter)
194             throws SecurityException {
195         
196         checkAlterInstantConverters();
197         if (converter == null) {
198             return null;
199         }
200         InstantConverter[] removed = new InstantConverter[1];
201         iInstantConverters = iInstantConverters.add(converter, removed);
202         return removed[0];
203     }
204     
205     /**
206      * Removes a converter from the set of converters. If the converter was
207      * not in the set, no changes are made.
208      * 
209      * @param converter  the converter to remove, null ignored
210      * @return replaced converter, or null
211      */
212     public InstantConverter removeInstantConverter(InstantConverter converter)
213             throws SecurityException {
214         
215         checkAlterInstantConverters();
216         if (converter == null) {
217             return null;
218         }
219         InstantConverter[] removed = new InstantConverter[1];
220         iInstantConverters = iInstantConverters.remove(converter, removed);
221         return removed[0];
222     }
223     
224     /**
225      * Checks whether the user has permission 'ConverterManager.alterInstantConverters'.
226      * 
227      * @throws SecurityException if the user does not have the permission
228      */
229     private void checkAlterInstantConverters() throws SecurityException {
230         SecurityManager sm = System.getSecurityManager();
231         if (sm != null) {
232             sm.checkPermission(new JodaTimePermission("ConverterManager.alterInstantConverters"));
233         }
234     }
235 
236     //-----------------------------------------------------------------------
237     /**
238      * Gets the best converter for the object specified.
239      * 
240      * @param object  the object to convert
241      * @return the converter to use
242      * @throws IllegalArgumentException if no suitable converter
243      * @throws IllegalStateException if multiple converters match the type
244      * equally well
245      */
246     public PartialConverter getPartialConverter(Object object) {
247         PartialConverter converter =
248             (PartialConverter)iPartialConverters.select(object == null ? null : object.getClass());
249         if (converter != null) {
250             return converter;
251         }
252         throw new IllegalArgumentException("No partial converter found for type: " +
253             (object == null ? "null" : object.getClass().getName()));
254     }
255     
256     //-----------------------------------------------------------------------
257     /**
258      * Gets a copy of the set of converters.
259      * 
260      * @return the converters, a copy of the real data, never null
261      */
262     public PartialConverter[] getPartialConverters() {
263         ConverterSet set = iPartialConverters;
264         PartialConverter[] converters = new PartialConverter[set.size()];
265         set.copyInto(converters);
266         return converters;
267     }
268     
269     /**
270      * Adds a converter to the set of converters. If a matching converter is
271      * already in the set, the given converter replaces it. If the converter is
272      * exactly the same as one already in the set, no changes are made.
273      * <p>
274      * The order in which converters are added is not relevent. The best
275      * converter is selected by examining the object hierarchy.
276      * 
277      * @param converter  the converter to add, null ignored
278      * @return replaced converter, or null
279      */
280     public PartialConverter addPartialConverter(PartialConverter converter)
281             throws SecurityException {
282         
283         checkAlterPartialConverters();
284         if (converter == null) {
285             return null;
286         }
287         PartialConverter[] removed = new PartialConverter[1];
288         iPartialConverters = iPartialConverters.add(converter, removed);
289         return removed[0];
290     }
291     
292     /**
293      * Removes a converter from the set of converters. If the converter was
294      * not in the set, no changes are made.
295      * 
296      * @param converter  the converter to remove, null ignored
297      * @return replaced converter, or null
298      */
299     public PartialConverter removePartialConverter(PartialConverter converter)
300             throws SecurityException {
301         
302         checkAlterPartialConverters();
303         if (converter == null) {
304             return null;
305         }
306         PartialConverter[] removed = new PartialConverter[1];
307         iPartialConverters = iPartialConverters.remove(converter, removed);
308         return removed[0];
309     }
310     
311     /**
312      * Checks whether the user has permission 'ConverterManager.alterPartialConverters'.
313      * 
314      * @throws SecurityException if the user does not have the permission
315      */
316     private void checkAlterPartialConverters() throws SecurityException {
317         SecurityManager sm = System.getSecurityManager();
318         if (sm != null) {
319             sm.checkPermission(new JodaTimePermission("ConverterManager.alterPartialConverters"));
320         }
321     }
322 
323     //-----------------------------------------------------------------------
324     /**
325      * Gets the best converter for the object specified.
326      * 
327      * @param object  the object to convert
328      * @return the converter to use
329      * @throws IllegalArgumentException if no suitable converter
330      * @throws IllegalStateException if multiple converters match the type
331      * equally well
332      */
333     public DurationConverter getDurationConverter(Object object) {
334         DurationConverter converter =
335             (DurationConverter)iDurationConverters.select(object == null ? null : object.getClass());
336         if (converter != null) {
337             return converter;
338         }
339         throw new IllegalArgumentException("No duration converter found for type: " +
340             (object == null ? "null" : object.getClass().getName()));
341     }
342     
343     //-----------------------------------------------------------------------
344     /**
345      * Gets a copy of the list of converters.
346      * 
347      * @return the converters, a copy of the real data, never null
348      */
349     public DurationConverter[] getDurationConverters() {
350         ConverterSet set = iDurationConverters;
351         DurationConverter[] converters = new DurationConverter[set.size()];
352         set.copyInto(converters);
353         return converters;
354     }
355     
356     /**
357      * Adds a converter to the set of converters. If a matching converter is
358      * already in the set, the given converter replaces it. If the converter is
359      * exactly the same as one already in the set, no changes are made.
360      * <p>
361      * The order in which converters are added is not relevent. The best
362      * converter is selected by examining the object hierarchy.
363      * 
364      * @param converter  the converter to add, null ignored
365      * @return replaced converter, or null
366      */
367     public DurationConverter addDurationConverter(DurationConverter converter)
368             throws SecurityException {
369         
370         checkAlterDurationConverters();
371         if (converter == null) {
372             return null;
373         }
374         DurationConverter[] removed = new DurationConverter[1];
375         iDurationConverters = iDurationConverters.add(converter, removed);
376         return removed[0];
377     }
378     
379     /**
380      * Removes a converter from the set of converters. If the converter was
381      * not in the set, no changes are made.
382      * 
383      * @param converter  the converter to remove, null ignored
384      * @return replaced converter, or null
385      */
386     public DurationConverter removeDurationConverter(DurationConverter converter)
387             throws SecurityException {
388         
389         checkAlterDurationConverters();
390         if (converter == null) {
391             return null;
392         }
393         DurationConverter[] removed = new DurationConverter[1];
394         iDurationConverters = iDurationConverters.remove(converter, removed);
395         return removed[0];
396     }
397     
398     /**
399      * Checks whether the user has permission 'ConverterManager.alterDurationConverters'.
400      * 
401      * @throws SecurityException if the user does not have the permission
402      */
403     private void checkAlterDurationConverters() throws SecurityException {
404         SecurityManager sm = System.getSecurityManager();
405         if (sm != null) {
406             sm.checkPermission(new JodaTimePermission("ConverterManager.alterDurationConverters"));
407         }
408     }
409 
410     //-----------------------------------------------------------------------
411     /**
412      * Gets the best converter for the object specified.
413      * 
414      * @param object  the object to convert
415      * @return the converter to use
416      * @throws IllegalArgumentException if no suitable converter
417      * @throws IllegalStateException if multiple converters match the type
418      * equally well
419      */
420     public PeriodConverter getPeriodConverter(Object object) {
421         PeriodConverter converter =
422             (PeriodConverter)iPeriodConverters.select(object == null ? null : object.getClass());
423         if (converter != null) {
424             return converter;
425         }
426         throw new IllegalArgumentException("No period converter found for type: " +
427             (object == null ? "null" : object.getClass().getName()));
428     }
429     
430     //-----------------------------------------------------------------------
431     /**
432      * Gets a copy of the list of converters.
433      * 
434      * @return the converters, a copy of the real data, never null
435      */
436     public PeriodConverter[] getPeriodConverters() {
437         ConverterSet set = iPeriodConverters;
438         PeriodConverter[] converters = new PeriodConverter[set.size()];
439         set.copyInto(converters);
440         return converters;
441     }
442     
443     /**
444      * Adds a converter to the set of converters. If a matching converter is
445      * already in the set, the given converter replaces it. If the converter is
446      * exactly the same as one already in the set, no changes are made.
447      * <p>
448      * The order in which converters are added is not relevent. The best
449      * converter is selected by examining the object hierarchy.
450      * 
451      * @param converter  the converter to add, null ignored
452      * @return replaced converter, or null
453      */
454     public PeriodConverter addPeriodConverter(PeriodConverter converter)
455             throws SecurityException {
456         
457         checkAlterPeriodConverters();
458         if (converter == null) {
459             return null;
460         }
461         PeriodConverter[] removed = new PeriodConverter[1];
462         iPeriodConverters = iPeriodConverters.add(converter, removed);
463         return removed[0];
464     }
465     
466     /**
467      * Removes a converter from the set of converters. If the converter was
468      * not in the set, no changes are made.
469      * 
470      * @param converter  the converter to remove, null ignored
471      * @return replaced converter, or null
472      */
473     public PeriodConverter removePeriodConverter(PeriodConverter converter)
474             throws SecurityException {
475         
476         checkAlterPeriodConverters();
477         if (converter == null) {
478             return null;
479         }
480         PeriodConverter[] removed = new PeriodConverter[1];
481         iPeriodConverters = iPeriodConverters.remove(converter, removed);
482         return removed[0];
483     }
484     
485     /**
486      * Checks whether the user has permission 'ConverterManager.alterPeriodConverters'.
487      * 
488      * @throws SecurityException if the user does not have the permission
489      */
490     private void checkAlterPeriodConverters() throws SecurityException {
491         SecurityManager sm = System.getSecurityManager();
492         if (sm != null) {
493             sm.checkPermission(new JodaTimePermission("ConverterManager.alterPeriodConverters"));
494         }
495     }
496 
497     //-----------------------------------------------------------------------
498     /**
499      * Gets the best converter for the object specified.
500      * 
501      * @param object  the object to convert
502      * @return the converter to use
503      * @throws IllegalArgumentException if no suitable converter
504      * @throws IllegalStateException if multiple converters match the type
505      * equally well
506      */
507     public IntervalConverter getIntervalConverter(Object object) {
508         IntervalConverter converter =
509             (IntervalConverter)iIntervalConverters.select(object == null ? null : object.getClass());
510         if (converter != null) {
511             return converter;
512         }
513         throw new IllegalArgumentException("No interval converter found for type: " +
514             (object == null ? "null" : object.getClass().getName()));
515     }
516     
517     //-----------------------------------------------------------------------
518     /**
519      * Gets a copy of the list of converters.
520      * 
521      * @return the converters, a copy of the real data, never null
522      */
523     public IntervalConverter[] getIntervalConverters() {
524         ConverterSet set = iIntervalConverters;
525         IntervalConverter[] converters = new IntervalConverter[set.size()];
526         set.copyInto(converters);
527         return converters;
528     }
529     
530     /**
531      * Adds a converter to the set of converters. If a matching converter is
532      * already in the set, the given converter replaces it. If the converter is
533      * exactly the same as one already in the set, no changes are made.
534      * <p>
535      * The order in which converters are added is not relevent. The best
536      * converter is selected by examining the object hierarchy.
537      * 
538      * @param converter  the converter to add, null ignored
539      * @return replaced converter, or null
540      */
541     public IntervalConverter addIntervalConverter(IntervalConverter converter) 
542             throws SecurityException {
543         
544         checkAlterIntervalConverters();
545         if (converter == null) {
546             return null;
547         }
548         IntervalConverter[] removed = new IntervalConverter[1];
549         iIntervalConverters = iIntervalConverters.add(converter, removed);
550         return removed[0];
551     }
552     
553     /**
554      * Removes a converter from the set of converters. If the converter was
555      * not in the set, no changes are made.
556      * 
557      * @param converter  the converter to remove, null ignored
558      * @return replaced converter, or null
559      */
560     public IntervalConverter removeIntervalConverter(IntervalConverter converter)
561             throws SecurityException {
562         
563         checkAlterIntervalConverters();
564         if (converter == null) {
565             return null;
566         }
567         IntervalConverter[] removed = new IntervalConverter[1];
568         iIntervalConverters = iIntervalConverters.remove(converter, removed);
569         return removed[0];
570     }
571     
572     /**
573      * Checks whether the user has permission 'ConverterManager.alterIntervalConverters'.
574      * 
575      * @throws SecurityException if the user does not have the permission
576      */
577     private void checkAlterIntervalConverters() throws SecurityException {
578         SecurityManager sm = System.getSecurityManager();
579         if (sm != null) {
580             sm.checkPermission(new JodaTimePermission("ConverterManager.alterIntervalConverters"));
581         }
582     }
583 
584     //-----------------------------------------------------------------------
585     /**
586      * Gets a debug representation of the object.
587      */
588     public String toString() {
589         return "ConverterManager[" +
590             iInstantConverters.size() + " instant," +
591             iPartialConverters.size() + " partial," +
592             iDurationConverters.size() + " duration," +
593             iPeriodConverters.size() + " period," +
594             iIntervalConverters.size() + " interval]";
595     }
596 
597 }