/* * Copyright 2001-2005 Stephen Colebourne * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.joda.time.convert; import org.joda.time.JodaTimePermission; /** * ConverterManager controls the date and time converters. * <p> * This class enables additional conversion classes to be added via * {@link #addInstantConverter(InstantConverter)}, which may replace an * existing converter. Similar methods exist for duration, time period and * interval converters. * <p> * This class is threadsafe, so adding/removing converters can be done at any * time. Updating the set of convertors is relatively expensive, and so should * not be performed often. * <p> * The default instant converters are: * <ul> * <li>ReadableInstant * <li>String * <li>Calendar * <li>Date (includes sql package subclasses) * <li>Long (milliseconds) * <li>null (now) * </ul> * * The default partial converters are: * <ul> * <li>ReadablePartial * <li>ReadableInstant * <li>String * <li>Calendar * <li>Date (includes sql package subclasses) * <li>Long (milliseconds) * <li>null (now) * </ul> * * The default duration converters are: * <ul> * <li>ReadableDuration * <li>ReadableInterval * <li>String * <li>Long (milliseconds) * <li>null (zero ms) * </ul> * * The default time period converters are: * <ul> * <li>ReadablePeriod * <li>ReadableInterval * <li>String * <li>null (zero) * </ul> * * The default interval converters are: * <ul> * <li>ReadableInterval * <li>String * <li>null (zero-length from now to now) * </ul> * * @author Stephen Colebourne * @author Brian S O'Neill * @since 1.0 */ public final class ConverterManager { /** * Singleton instance, lazily loaded to avoid class loading. */ private static ConverterManager INSTANCE; public static ConverterManager getInstance() { if (INSTANCE == null) { INSTANCE = new ConverterManager(); } return INSTANCE; } private ConverterSet iInstantConverters; private ConverterSet iPartialConverters; private ConverterSet iDurationConverters; private ConverterSet iPeriodConverters; private ConverterSet iIntervalConverters; /** * Restricted constructor. */ protected ConverterManager() { super(); iInstantConverters = new ConverterSet(new Converter[] { ReadableInstantConverter.INSTANCE, StringConverter.INSTANCE, CalendarConverter.INSTANCE, DateConverter.INSTANCE, LongConverter.INSTANCE, NullConverter.INSTANCE, }); iPartialConverters = new ConverterSet(new Converter[] { ReadablePartialConverter.INSTANCE, ReadableInstantConverter.INSTANCE, StringConverter.INSTANCE, CalendarConverter.INSTANCE, DateConverter.INSTANCE, LongConverter.INSTANCE, NullConverter.INSTANCE, }); iDurationConverters = new ConverterSet(new Converter[] { ReadableDurationConverter.INSTANCE, ReadableIntervalConverter.INSTANCE, StringConverter.INSTANCE, LongConverter.INSTANCE, NullConverter.INSTANCE, }); iPeriodConverters = new ConverterSet(new Converter[] { ReadableDurationConverter.INSTANCE, ReadablePeriodConverter.INSTANCE, ReadableIntervalConverter.INSTANCE, StringConverter.INSTANCE, NullConverter.INSTANCE, }); iIntervalConverters = new ConverterSet(new Converter[] { ReadableIntervalConverter.INSTANCE, StringConverter.INSTANCE, NullConverter.INSTANCE, }); } //----------------------------------------------------------------------- /** * Gets the best converter for the object specified. * * @param object the object to convert * @return the converter to use * @throws IllegalArgumentException if no suitable converter * @throws IllegalStateException if multiple converters match the type * equally well */ public InstantConverter getInstantConverter(Object object) { InstantConverter converter = (InstantConverter)iInstantConverters.select(object == null ? null : object.getClass()); if (converter != null) { return converter; } throw new IllegalArgumentException("No instant converter found for type: " + (object == null ? "null" : object.getClass().getName())); } //----------------------------------------------------------------------- /** * Gets a copy of the set of converters. * * @return the converters, a copy of the real data, never null */ public InstantConverter[] getInstantConverters() { ConverterSet set = iInstantConverters; InstantConverter[] converters = new InstantConverter[set.size()]; set.copyInto(converters); return converters; } /** * Adds a converter to the set of converters. If a matching converter is * already in the set, the given converter replaces it. If the converter is * exactly the same as one already in the set, no changes are made. * <p> * The order in which converters are added is not relevent. The best * converter is selected by examining the object hierarchy. * * @param converter the converter to add, null ignored * @return replaced converter, or null */ public InstantConverter addInstantConverter(InstantConverter converter) throws SecurityException { checkAlterInstantConverters(); if (converter == null) { return null; } InstantConverter[] removed = new InstantConverter[1]; iInstantConverters = iInstantConverters.add(converter, removed); return removed[0]; } /** * Removes a converter from the set of converters. If the converter was * not in the set, no changes are made. * * @param converter the converter to remove, null ignored * @return replaced converter, or null */ public InstantConverter removeInstantConverter(InstantConverter converter) throws SecurityException { checkAlterInstantConverters(); if (converter == null) { return null; } InstantConverter[] removed = new InstantConverter[1]; iInstantConverters = iInstantConverters.remove(converter, removed); return removed[0]; } /** * Checks whether the user has permission 'ConverterManager.alterInstantConverters'. * * @throws SecurityException if the user does not have the permission */ private void checkAlterInstantConverters() throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new JodaTimePermission("ConverterManager.alterInstantConverters")); } } //----------------------------------------------------------------------- /** * Gets the best converter for the object specified. * * @param object the object to convert * @return the converter to use * @throws IllegalArgumentException if no suitable converter * @throws IllegalStateException if multiple converters match the type * equally well */ public PartialConverter getPartialConverter(Object object) { PartialConverter converter = (PartialConverter)iPartialConverters.select(object == null ? null : object.getClass()); if (converter != null) { return converter; } throw new IllegalArgumentException("No partial converter found for type: " + (object == null ? "null" : object.getClass().getName())); } //----------------------------------------------------------------------- /** * Gets a copy of the set of converters. * * @return the converters, a copy of the real data, never null */ public PartialConverter[] getPartialConverters() { ConverterSet set = iPartialConverters; PartialConverter[] converters = new PartialConverter[set.size()]; set.copyInto(converters); return converters; } /** * Adds a converter to the set of converters. If a matching converter is * already in the set, the given converter replaces it. If the converter is * exactly the same as one already in the set, no changes are made. * <p> * The order in which converters are added is not relevent. The best * converter is selected by examining the object hierarchy. * * @param converter the converter to add, null ignored * @return replaced converter, or null */ public PartialConverter addPartialConverter(PartialConverter converter) throws SecurityException { checkAlterPartialConverters(); if (converter == null) { return null; } PartialConverter[] removed = new PartialConverter[1]; iPartialConverters = iPartialConverters.add(converter, removed); return removed[0]; } /** * Removes a converter from the set of converters. If the converter was * not in the set, no changes are made. * * @param converter the converter to remove, null ignored * @return replaced converter, or null */ public PartialConverter removePartialConverter(PartialConverter converter) throws SecurityException { checkAlterPartialConverters(); if (converter == null) { return null; } PartialConverter[] removed = new PartialConverter[1]; iPartialConverters = iPartialConverters.remove(converter, removed); return removed[0]; } /** * Checks whether the user has permission 'ConverterManager.alterPartialConverters'. * * @throws SecurityException if the user does not have the permission */ private void checkAlterPartialConverters() throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new JodaTimePermission("ConverterManager.alterPartialConverters")); } } //----------------------------------------------------------------------- /** * Gets the best converter for the object specified. * * @param object the object to convert * @return the converter to use * @throws IllegalArgumentException if no suitable converter * @throws IllegalStateException if multiple converters match the type * equally well */ public DurationConverter getDurationConverter(Object object) { DurationConverter converter = (DurationConverter)iDurationConverters.select(object == null ? null : object.getClass()); if (converter != null) { return converter; } throw new IllegalArgumentException("No duration converter found for type: " + (object == null ? "null" : object.getClass().getName())); } //----------------------------------------------------------------------- /** * Gets a copy of the list of converters. * * @return the converters, a copy of the real data, never null */ public DurationConverter[] getDurationConverters() { ConverterSet set = iDurationConverters; DurationConverter[] converters = new DurationConverter[set.size()]; set.copyInto(converters); return converters; } /** * Adds a converter to the set of converters. If a matching converter is * already in the set, the given converter replaces it. If the converter is * exactly the same as one already in the set, no changes are made. * <p> * The order in which converters are added is not relevent. The best * converter is selected by examining the object hierarchy. * * @param converter the converter to add, null ignored * @return replaced converter, or null */ public DurationConverter addDurationConverter(DurationConverter converter) throws SecurityException { checkAlterDurationConverters(); if (converter == null) { return null; } DurationConverter[] removed = new DurationConverter[1]; iDurationConverters = iDurationConverters.add(converter, removed); return removed[0]; } /** * Removes a converter from the set of converters. If the converter was * not in the set, no changes are made. * * @param converter the converter to remove, null ignored * @return replaced converter, or null */ public DurationConverter removeDurationConverter(DurationConverter converter) throws SecurityException { checkAlterDurationConverters(); if (converter == null) { return null; } DurationConverter[] removed = new DurationConverter[1]; iDurationConverters = iDurationConverters.remove(converter, removed); return removed[0]; } /** * Checks whether the user has permission 'ConverterManager.alterDurationConverters'. * * @throws SecurityException if the user does not have the permission */ private void checkAlterDurationConverters() throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new JodaTimePermission("ConverterManager.alterDurationConverters")); } } //----------------------------------------------------------------------- /** * Gets the best converter for the object specified. * * @param object the object to convert * @return the converter to use * @throws IllegalArgumentException if no suitable converter * @throws IllegalStateException if multiple converters match the type * equally well */ public PeriodConverter getPeriodConverter(Object object) { PeriodConverter converter = (PeriodConverter)iPeriodConverters.select(object == null ? null : object.getClass()); if (converter != null) { return converter; } throw new IllegalArgumentException("No period converter found for type: " + (object == null ? "null" : object.getClass().getName())); } //----------------------------------------------------------------------- /** * Gets a copy of the list of converters. * * @return the converters, a copy of the real data, never null */ public PeriodConverter[] getPeriodConverters() { ConverterSet set = iPeriodConverters; PeriodConverter[] converters = new PeriodConverter[set.size()]; set.copyInto(converters); return converters; } /** * Adds a converter to the set of converters. If a matching converter is * already in the set, the given converter replaces it. If the converter is * exactly the same as one already in the set, no changes are made. * <p> * The order in which converters are added is not relevent. The best * converter is selected by examining the object hierarchy. * * @param converter the converter to add, null ignored * @return replaced converter, or null */ public PeriodConverter addPeriodConverter(PeriodConverter converter) throws SecurityException { checkAlterPeriodConverters(); if (converter == null) { return null; } PeriodConverter[] removed = new PeriodConverter[1]; iPeriodConverters = iPeriodConverters.add(converter, removed); return removed[0]; } /** * Removes a converter from the set of converters. If the converter was * not in the set, no changes are made. * * @param converter the converter to remove, null ignored * @return replaced converter, or null */ public PeriodConverter removePeriodConverter(PeriodConverter converter) throws SecurityException { checkAlterPeriodConverters(); if (converter == null) { return null; } PeriodConverter[] removed = new PeriodConverter[1]; iPeriodConverters = iPeriodConverters.remove(converter, removed); return removed[0]; } /** * Checks whether the user has permission 'ConverterManager.alterPeriodConverters'. * * @throws SecurityException if the user does not have the permission */ private void checkAlterPeriodConverters() throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new JodaTimePermission("ConverterManager.alterPeriodConverters")); } } //----------------------------------------------------------------------- /** * Gets the best converter for the object specified. * * @param object the object to convert * @return the converter to use * @throws IllegalArgumentException if no suitable converter * @throws IllegalStateException if multiple converters match the type * equally well */ public IntervalConverter getIntervalConverter(Object object) { IntervalConverter converter = (IntervalConverter)iIntervalConverters.select(object == null ? null : object.getClass()); if (converter != null) { return converter; } throw new IllegalArgumentException("No interval converter found for type: " + (object == null ? "null" : object.getClass().getName())); } //----------------------------------------------------------------------- /** * Gets a copy of the list of converters. * * @return the converters, a copy of the real data, never null */ public IntervalConverter[] getIntervalConverters() { ConverterSet set = iIntervalConverters; IntervalConverter[] converters = new IntervalConverter[set.size()]; set.copyInto(converters); return converters; } /** * Adds a converter to the set of converters. If a matching converter is * already in the set, the given converter replaces it. If the converter is * exactly the same as one already in the set, no changes are made. * <p> * The order in which converters are added is not relevent. The best * converter is selected by examining the object hierarchy. * * @param converter the converter to add, null ignored * @return replaced converter, or null */ public IntervalConverter addIntervalConverter(IntervalConverter converter) throws SecurityException { checkAlterIntervalConverters(); if (converter == null) { return null; } IntervalConverter[] removed = new IntervalConverter[1]; iIntervalConverters = iIntervalConverters.add(converter, removed); return removed[0]; } /** * Removes a converter from the set of converters. If the converter was * not in the set, no changes are made. * * @param converter the converter to remove, null ignored * @return replaced converter, or null */ public IntervalConverter removeIntervalConverter(IntervalConverter converter) throws SecurityException { checkAlterIntervalConverters(); if (converter == null) { return null; } IntervalConverter[] removed = new IntervalConverter[1]; iIntervalConverters = iIntervalConverters.remove(converter, removed); return removed[0]; } /** * Checks whether the user has permission 'ConverterManager.alterIntervalConverters'. * * @throws SecurityException if the user does not have the permission */ private void checkAlterIntervalConverters() throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new JodaTimePermission("ConverterManager.alterIntervalConverters")); } } //----------------------------------------------------------------------- /** * Gets a debug representation of the object. */ public String toString() { return "ConverterManager[" + iInstantConverters.size() + " instant," + iPartialConverters.size() + " partial," + iDurationConverters.size() + " duration," + iPeriodConverters.size() + " period," + iIntervalConverters.size() + " interval]"; } }