001: /*
002: * Copyright 2001-2005 Stephen Colebourne
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.joda.time.convert;
017:
018: import org.joda.time.JodaTimePermission;
019:
020: /**
021: * ConverterManager controls the date and time converters.
022: * <p>
023: * This class enables additional conversion classes to be added via
024: * {@link #addInstantConverter(InstantConverter)}, which may replace an
025: * existing converter. Similar methods exist for duration, time period and
026: * interval converters.
027: * <p>
028: * This class is threadsafe, so adding/removing converters can be done at any
029: * time. Updating the set of convertors is relatively expensive, and so should
030: * not be performed often.
031: * <p>
032: * The default instant converters are:
033: * <ul>
034: * <li>ReadableInstant
035: * <li>String
036: * <li>Calendar
037: * <li>Date (includes sql package subclasses)
038: * <li>Long (milliseconds)
039: * <li>null (now)
040: * </ul>
041: *
042: * The default partial converters are:
043: * <ul>
044: * <li>ReadablePartial
045: * <li>ReadableInstant
046: * <li>String
047: * <li>Calendar
048: * <li>Date (includes sql package subclasses)
049: * <li>Long (milliseconds)
050: * <li>null (now)
051: * </ul>
052: *
053: * The default duration converters are:
054: * <ul>
055: * <li>ReadableDuration
056: * <li>ReadableInterval
057: * <li>String
058: * <li>Long (milliseconds)
059: * <li>null (zero ms)
060: * </ul>
061: *
062: * The default time period converters are:
063: * <ul>
064: * <li>ReadablePeriod
065: * <li>ReadableInterval
066: * <li>String
067: * <li>null (zero)
068: * </ul>
069: *
070: * The default interval converters are:
071: * <ul>
072: * <li>ReadableInterval
073: * <li>String
074: * <li>null (zero-length from now to now)
075: * </ul>
076: *
077: * @author Stephen Colebourne
078: * @author Brian S O'Neill
079: * @since 1.0
080: */
081: public final class ConverterManager {
082:
083: /**
084: * Singleton instance, lazily loaded to avoid class loading.
085: */
086: private static ConverterManager INSTANCE;
087:
088: public static ConverterManager getInstance() {
089: if (INSTANCE == null) {
090: INSTANCE = new ConverterManager();
091: }
092: return INSTANCE;
093: }
094:
095: private ConverterSet iInstantConverters;
096: private ConverterSet iPartialConverters;
097: private ConverterSet iDurationConverters;
098: private ConverterSet iPeriodConverters;
099: 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, CalendarConverter.INSTANCE,
110: DateConverter.INSTANCE, LongConverter.INSTANCE,
111: NullConverter.INSTANCE, });
112:
113: iPartialConverters = new ConverterSet(new Converter[] {
114: ReadablePartialConverter.INSTANCE,
115: ReadableInstantConverter.INSTANCE,
116: StringConverter.INSTANCE, CalendarConverter.INSTANCE,
117: DateConverter.INSTANCE, LongConverter.INSTANCE,
118: NullConverter.INSTANCE, });
119:
120: iDurationConverters = new ConverterSet(new Converter[] {
121: ReadableDurationConverter.INSTANCE,
122: ReadableIntervalConverter.INSTANCE,
123: StringConverter.INSTANCE, LongConverter.INSTANCE,
124: NullConverter.INSTANCE, });
125:
126: iPeriodConverters = new ConverterSet(new Converter[] {
127: ReadableDurationConverter.INSTANCE,
128: ReadablePeriodConverter.INSTANCE,
129: ReadableIntervalConverter.INSTANCE,
130: StringConverter.INSTANCE, NullConverter.INSTANCE, });
131:
132: iIntervalConverters = new ConverterSet(new Converter[] {
133: ReadableIntervalConverter.INSTANCE,
134: StringConverter.INSTANCE, NullConverter.INSTANCE, });
135: }
136:
137: //-----------------------------------------------------------------------
138: /**
139: * Gets the best converter for the object specified.
140: *
141: * @param object the object to convert
142: * @return the converter to use
143: * @throws IllegalArgumentException if no suitable converter
144: * @throws IllegalStateException if multiple converters match the type
145: * equally well
146: */
147: public InstantConverter getInstantConverter(Object object) {
148: InstantConverter converter = (InstantConverter) iInstantConverters
149: .select(object == null ? null : object.getClass());
150: if (converter != null) {
151: return converter;
152: }
153: throw new IllegalArgumentException(
154: "No instant converter found for type: "
155: + (object == null ? "null" : object.getClass()
156: .getName()));
157: }
158:
159: //-----------------------------------------------------------------------
160: /**
161: * Gets a copy of the set of converters.
162: *
163: * @return the converters, a copy of the real data, never null
164: */
165: public InstantConverter[] getInstantConverters() {
166: ConverterSet set = iInstantConverters;
167: InstantConverter[] converters = new InstantConverter[set.size()];
168: set.copyInto(converters);
169: return converters;
170: }
171:
172: /**
173: * Adds a converter to the set of converters. If a matching converter is
174: * already in the set, the given converter replaces it. If the converter is
175: * exactly the same as one already in the set, no changes are made.
176: * <p>
177: * The order in which converters are added is not relevent. The best
178: * converter is selected by examining the object hierarchy.
179: *
180: * @param converter the converter to add, null ignored
181: * @return replaced converter, or null
182: */
183: public InstantConverter addInstantConverter(
184: InstantConverter converter) throws SecurityException {
185:
186: checkAlterInstantConverters();
187: if (converter == null) {
188: return null;
189: }
190: InstantConverter[] removed = new InstantConverter[1];
191: iInstantConverters = iInstantConverters.add(converter, removed);
192: return removed[0];
193: }
194:
195: /**
196: * Removes a converter from the set of converters. If the converter was
197: * not in the set, no changes are made.
198: *
199: * @param converter the converter to remove, null ignored
200: * @return replaced converter, or null
201: */
202: public InstantConverter removeInstantConverter(
203: InstantConverter converter) throws SecurityException {
204:
205: checkAlterInstantConverters();
206: if (converter == null) {
207: return null;
208: }
209: InstantConverter[] removed = new InstantConverter[1];
210: iInstantConverters = iInstantConverters.remove(converter,
211: removed);
212: return removed[0];
213: }
214:
215: /**
216: * Checks whether the user has permission 'ConverterManager.alterInstantConverters'.
217: *
218: * @throws SecurityException if the user does not have the permission
219: */
220: private void checkAlterInstantConverters() throws SecurityException {
221: SecurityManager sm = System.getSecurityManager();
222: if (sm != null) {
223: sm.checkPermission(new JodaTimePermission(
224: "ConverterManager.alterInstantConverters"));
225: }
226: }
227:
228: //-----------------------------------------------------------------------
229: /**
230: * Gets the best converter for the object specified.
231: *
232: * @param object the object to convert
233: * @return the converter to use
234: * @throws IllegalArgumentException if no suitable converter
235: * @throws IllegalStateException if multiple converters match the type
236: * equally well
237: */
238: public PartialConverter getPartialConverter(Object object) {
239: PartialConverter converter = (PartialConverter) iPartialConverters
240: .select(object == null ? null : object.getClass());
241: if (converter != null) {
242: return converter;
243: }
244: throw new IllegalArgumentException(
245: "No partial converter found for type: "
246: + (object == null ? "null" : object.getClass()
247: .getName()));
248: }
249:
250: //-----------------------------------------------------------------------
251: /**
252: * Gets a copy of the set of converters.
253: *
254: * @return the converters, a copy of the real data, never null
255: */
256: public PartialConverter[] getPartialConverters() {
257: ConverterSet set = iPartialConverters;
258: PartialConverter[] converters = new PartialConverter[set.size()];
259: set.copyInto(converters);
260: return converters;
261: }
262:
263: /**
264: * Adds a converter to the set of converters. If a matching converter is
265: * already in the set, the given converter replaces it. If the converter is
266: * exactly the same as one already in the set, no changes are made.
267: * <p>
268: * The order in which converters are added is not relevent. The best
269: * converter is selected by examining the object hierarchy.
270: *
271: * @param converter the converter to add, null ignored
272: * @return replaced converter, or null
273: */
274: public PartialConverter addPartialConverter(
275: PartialConverter converter) throws SecurityException {
276:
277: checkAlterPartialConverters();
278: if (converter == null) {
279: return null;
280: }
281: PartialConverter[] removed = new PartialConverter[1];
282: iPartialConverters = iPartialConverters.add(converter, removed);
283: return removed[0];
284: }
285:
286: /**
287: * Removes a converter from the set of converters. If the converter was
288: * not in the set, no changes are made.
289: *
290: * @param converter the converter to remove, null ignored
291: * @return replaced converter, or null
292: */
293: public PartialConverter removePartialConverter(
294: PartialConverter converter) throws SecurityException {
295:
296: checkAlterPartialConverters();
297: if (converter == null) {
298: return null;
299: }
300: PartialConverter[] removed = new PartialConverter[1];
301: iPartialConverters = iPartialConverters.remove(converter,
302: removed);
303: return removed[0];
304: }
305:
306: /**
307: * Checks whether the user has permission 'ConverterManager.alterPartialConverters'.
308: *
309: * @throws SecurityException if the user does not have the permission
310: */
311: private void checkAlterPartialConverters() throws SecurityException {
312: SecurityManager sm = System.getSecurityManager();
313: if (sm != null) {
314: sm.checkPermission(new JodaTimePermission(
315: "ConverterManager.alterPartialConverters"));
316: }
317: }
318:
319: //-----------------------------------------------------------------------
320: /**
321: * Gets the best converter for the object specified.
322: *
323: * @param object the object to convert
324: * @return the converter to use
325: * @throws IllegalArgumentException if no suitable converter
326: * @throws IllegalStateException if multiple converters match the type
327: * equally well
328: */
329: public DurationConverter getDurationConverter(Object object) {
330: DurationConverter converter = (DurationConverter) iDurationConverters
331: .select(object == null ? null : object.getClass());
332: if (converter != null) {
333: return converter;
334: }
335: throw new IllegalArgumentException(
336: "No duration converter found for type: "
337: + (object == null ? "null" : object.getClass()
338: .getName()));
339: }
340:
341: //-----------------------------------------------------------------------
342: /**
343: * Gets a copy of the list of converters.
344: *
345: * @return the converters, a copy of the real data, never null
346: */
347: public DurationConverter[] getDurationConverters() {
348: ConverterSet set = iDurationConverters;
349: DurationConverter[] converters = new DurationConverter[set
350: .size()];
351: set.copyInto(converters);
352: return converters;
353: }
354:
355: /**
356: * Adds a converter to the set of converters. If a matching converter is
357: * already in the set, the given converter replaces it. If the converter is
358: * exactly the same as one already in the set, no changes are made.
359: * <p>
360: * The order in which converters are added is not relevent. The best
361: * converter is selected by examining the object hierarchy.
362: *
363: * @param converter the converter to add, null ignored
364: * @return replaced converter, or null
365: */
366: public DurationConverter addDurationConverter(
367: DurationConverter converter) throws SecurityException {
368:
369: checkAlterDurationConverters();
370: if (converter == null) {
371: return null;
372: }
373: DurationConverter[] removed = new DurationConverter[1];
374: iDurationConverters = iDurationConverters.add(converter,
375: 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(
387: DurationConverter converter) throws SecurityException {
388:
389: checkAlterDurationConverters();
390: if (converter == null) {
391: return null;
392: }
393: DurationConverter[] removed = new DurationConverter[1];
394: iDurationConverters = iDurationConverters.remove(converter,
395: removed);
396: return removed[0];
397: }
398:
399: /**
400: * Checks whether the user has permission 'ConverterManager.alterDurationConverters'.
401: *
402: * @throws SecurityException if the user does not have the permission
403: */
404: private void checkAlterDurationConverters()
405: throws SecurityException {
406: SecurityManager sm = System.getSecurityManager();
407: if (sm != null) {
408: sm.checkPermission(new JodaTimePermission(
409: "ConverterManager.alterDurationConverters"));
410: }
411: }
412:
413: //-----------------------------------------------------------------------
414: /**
415: * Gets the best converter for the object specified.
416: *
417: * @param object the object to convert
418: * @return the converter to use
419: * @throws IllegalArgumentException if no suitable converter
420: * @throws IllegalStateException if multiple converters match the type
421: * equally well
422: */
423: public PeriodConverter getPeriodConverter(Object object) {
424: PeriodConverter converter = (PeriodConverter) iPeriodConverters
425: .select(object == null ? null : object.getClass());
426: if (converter != null) {
427: return converter;
428: }
429: throw new IllegalArgumentException(
430: "No period converter found for type: "
431: + (object == null ? "null" : object.getClass()
432: .getName()));
433: }
434:
435: //-----------------------------------------------------------------------
436: /**
437: * Gets a copy of the list of converters.
438: *
439: * @return the converters, a copy of the real data, never null
440: */
441: public PeriodConverter[] getPeriodConverters() {
442: ConverterSet set = iPeriodConverters;
443: PeriodConverter[] converters = new PeriodConverter[set.size()];
444: set.copyInto(converters);
445: return converters;
446: }
447:
448: /**
449: * Adds a converter to the set of converters. If a matching converter is
450: * already in the set, the given converter replaces it. If the converter is
451: * exactly the same as one already in the set, no changes are made.
452: * <p>
453: * The order in which converters are added is not relevent. The best
454: * converter is selected by examining the object hierarchy.
455: *
456: * @param converter the converter to add, null ignored
457: * @return replaced converter, or null
458: */
459: public PeriodConverter addPeriodConverter(PeriodConverter converter)
460: throws SecurityException {
461:
462: checkAlterPeriodConverters();
463: if (converter == null) {
464: return null;
465: }
466: PeriodConverter[] removed = new PeriodConverter[1];
467: iPeriodConverters = iPeriodConverters.add(converter, removed);
468: return removed[0];
469: }
470:
471: /**
472: * Removes a converter from the set of converters. If the converter was
473: * not in the set, no changes are made.
474: *
475: * @param converter the converter to remove, null ignored
476: * @return replaced converter, or null
477: */
478: public PeriodConverter removePeriodConverter(
479: PeriodConverter converter) throws SecurityException {
480:
481: checkAlterPeriodConverters();
482: if (converter == null) {
483: return null;
484: }
485: PeriodConverter[] removed = new PeriodConverter[1];
486: iPeriodConverters = iPeriodConverters
487: .remove(converter, removed);
488: return removed[0];
489: }
490:
491: /**
492: * Checks whether the user has permission 'ConverterManager.alterPeriodConverters'.
493: *
494: * @throws SecurityException if the user does not have the permission
495: */
496: private void checkAlterPeriodConverters() throws SecurityException {
497: SecurityManager sm = System.getSecurityManager();
498: if (sm != null) {
499: sm.checkPermission(new JodaTimePermission(
500: "ConverterManager.alterPeriodConverters"));
501: }
502: }
503:
504: //-----------------------------------------------------------------------
505: /**
506: * Gets the best converter for the object specified.
507: *
508: * @param object the object to convert
509: * @return the converter to use
510: * @throws IllegalArgumentException if no suitable converter
511: * @throws IllegalStateException if multiple converters match the type
512: * equally well
513: */
514: public IntervalConverter getIntervalConverter(Object object) {
515: IntervalConverter converter = (IntervalConverter) iIntervalConverters
516: .select(object == null ? null : object.getClass());
517: if (converter != null) {
518: return converter;
519: }
520: throw new IllegalArgumentException(
521: "No interval converter found for type: "
522: + (object == null ? "null" : object.getClass()
523: .getName()));
524: }
525:
526: //-----------------------------------------------------------------------
527: /**
528: * Gets a copy of the list of converters.
529: *
530: * @return the converters, a copy of the real data, never null
531: */
532: public IntervalConverter[] getIntervalConverters() {
533: ConverterSet set = iIntervalConverters;
534: IntervalConverter[] converters = new IntervalConverter[set
535: .size()];
536: set.copyInto(converters);
537: return converters;
538: }
539:
540: /**
541: * Adds a converter to the set of converters. If a matching converter is
542: * already in the set, the given converter replaces it. If the converter is
543: * exactly the same as one already in the set, no changes are made.
544: * <p>
545: * The order in which converters are added is not relevent. The best
546: * converter is selected by examining the object hierarchy.
547: *
548: * @param converter the converter to add, null ignored
549: * @return replaced converter, or null
550: */
551: public IntervalConverter addIntervalConverter(
552: IntervalConverter converter) throws SecurityException {
553:
554: checkAlterIntervalConverters();
555: if (converter == null) {
556: return null;
557: }
558: IntervalConverter[] removed = new IntervalConverter[1];
559: iIntervalConverters = iIntervalConverters.add(converter,
560: removed);
561: return removed[0];
562: }
563:
564: /**
565: * Removes a converter from the set of converters. If the converter was
566: * not in the set, no changes are made.
567: *
568: * @param converter the converter to remove, null ignored
569: * @return replaced converter, or null
570: */
571: public IntervalConverter removeIntervalConverter(
572: IntervalConverter converter) throws SecurityException {
573:
574: checkAlterIntervalConverters();
575: if (converter == null) {
576: return null;
577: }
578: IntervalConverter[] removed = new IntervalConverter[1];
579: iIntervalConverters = iIntervalConverters.remove(converter,
580: removed);
581: return removed[0];
582: }
583:
584: /**
585: * Checks whether the user has permission 'ConverterManager.alterIntervalConverters'.
586: *
587: * @throws SecurityException if the user does not have the permission
588: */
589: private void checkAlterIntervalConverters()
590: throws SecurityException {
591: SecurityManager sm = System.getSecurityManager();
592: if (sm != null) {
593: sm.checkPermission(new JodaTimePermission(
594: "ConverterManager.alterIntervalConverters"));
595: }
596: }
597:
598: //-----------------------------------------------------------------------
599: /**
600: * Gets a debug representation of the object.
601: */
602: public String toString() {
603: return "ConverterManager[" + iInstantConverters.size()
604: + " instant," + iPartialConverters.size() + " partial,"
605: + iDurationConverters.size() + " duration,"
606: + iPeriodConverters.size() + " period,"
607: + iIntervalConverters.size() + " interval]";
608: }
609:
610: }
|