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,
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 }