001/*
002 *  Copyright 2001-2009 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 */
016package org.joda.time.field;
017
018import java.io.Serializable;
019import java.util.HashMap;
020
021import org.joda.time.DurationField;
022import org.joda.time.DurationFieldType;
023
024/**
025 * A placeholder implementation to use when a duration field is not supported.
026 * <p>
027 * UnsupportedDurationField is thread-safe and immutable.
028 *
029 * @author Brian S O'Neill
030 * @since 1.0
031 */
032public final class UnsupportedDurationField extends DurationField implements Serializable {
033
034    /** Serialization lock. */
035    private static final long serialVersionUID = -6390301302770925357L;
036
037    /** The cache of unsupported duration field instances */
038    private static HashMap<DurationFieldType, UnsupportedDurationField> cCache;
039
040    /**
041     * Gets an instance of UnsupportedDurationField for a specific named field.
042     * The returned instance is cached.
043     * 
044     * @param type  the type to obtain
045     * @return the instance
046     */
047    public static synchronized UnsupportedDurationField getInstance(DurationFieldType type) {
048        UnsupportedDurationField field;
049        if (cCache == null) {
050            cCache = new HashMap<DurationFieldType, UnsupportedDurationField>(7);
051            field = null;
052        } else {
053            field = cCache.get(type);
054        }
055        if (field == null) {
056            field = new UnsupportedDurationField(type);
057            cCache.put(type, field);
058        }
059        return field;
060    }
061
062    /** The name of the field */
063    private final DurationFieldType iType;
064
065    /**
066     * Constructor.
067     * 
068     * @param type  the type to use
069     */
070    private UnsupportedDurationField(DurationFieldType type) {
071        iType = type;
072    }
073
074    //-----------------------------------------------------------------------
075    // Design note: Simple Accessors return a suitable value, but methods
076    // intended to perform calculations throw an UnsupportedOperationException.
077
078    public final DurationFieldType getType() {
079        return iType;
080    }
081
082    public String getName() {
083        return iType.getName();
084    }
085
086    /**
087     * This field is not supported.
088     *
089     * @return false always
090     */
091    public boolean isSupported() {
092        return false;
093    }
094
095    /**
096     * This field is precise.
097     * 
098     * @return true always
099     */
100    public boolean isPrecise() {
101        return true;
102    }
103
104    /**
105     * Always throws UnsupportedOperationException
106     *
107     * @throws UnsupportedOperationException
108     */
109    public int getValue(long duration) {
110        throw unsupported();
111    }
112
113    /**
114     * Always throws UnsupportedOperationException
115     *
116     * @throws UnsupportedOperationException
117     */
118    public long getValueAsLong(long duration) {
119        throw unsupported();
120    }
121
122    /**
123     * Always throws UnsupportedOperationException
124     *
125     * @throws UnsupportedOperationException
126     */
127    public int getValue(long duration, long instant) {
128        throw unsupported();
129    }
130
131    /**
132     * Always throws UnsupportedOperationException
133     *
134     * @throws UnsupportedOperationException
135     */
136    public long getValueAsLong(long duration, long instant) {
137        throw unsupported();
138    }
139
140    /**
141     * Always throws UnsupportedOperationException
142     *
143     * @throws UnsupportedOperationException
144     */
145    public long getMillis(int value) {
146        throw unsupported();
147    }
148
149    /**
150     * Always throws UnsupportedOperationException
151     *
152     * @throws UnsupportedOperationException
153     */
154    public long getMillis(long value) {
155        throw unsupported();
156    }
157
158    /**
159     * Always throws UnsupportedOperationException
160     *
161     * @throws UnsupportedOperationException
162     */
163    public long getMillis(int value, long instant) {
164        throw unsupported();
165    }
166
167    /**
168     * Always throws UnsupportedOperationException
169     *
170     * @throws UnsupportedOperationException
171     */
172    public long getMillis(long value, long instant) {
173        throw unsupported();
174    }
175
176    /**
177     * Always throws UnsupportedOperationException
178     *
179     * @throws UnsupportedOperationException
180     */
181    public long add(long instant, int value) {
182        throw unsupported();
183    }
184
185    /**
186     * Always throws UnsupportedOperationException
187     *
188     * @throws UnsupportedOperationException
189     */
190    public long add(long instant, long value) {
191        throw unsupported();
192    }
193
194    /**
195     * Always throws UnsupportedOperationException
196     *
197     * @throws UnsupportedOperationException
198     */
199    public int getDifference(long minuendInstant, long subtrahendInstant) {
200        throw unsupported();
201    }
202
203    /**
204     * Always throws UnsupportedOperationException
205     *
206     * @throws UnsupportedOperationException
207     */
208    public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
209        throw unsupported();
210    }
211
212    /**
213     * Always returns zero.
214     *
215     * @return zero always
216     */
217    public long getUnitMillis() {
218        return 0;
219    }
220
221    /**
222     * Always returns zero, indicating that sort order is not relevent.
223     *
224     * @return zero always
225     */
226    public int compareTo(DurationField durationField) {
227        return 0;
228    }
229
230    //------------------------------------------------------------------------
231    /**
232     * Compares this duration field to another.
233     * 
234     * @param obj  the object to compare to
235     * @return true if equal
236     */
237    public boolean equals(Object obj) {
238        if (this == obj) {
239            return true;
240        } else if (obj instanceof UnsupportedDurationField) {
241            UnsupportedDurationField other = (UnsupportedDurationField) obj;
242            if (other.getName() == null) {
243                return (getName() == null);
244            }
245            return (other.getName().equals(getName()));
246        }
247        return false;
248    }
249
250    /**
251     * Gets a suitable hashcode.
252     * 
253     * @return the hashcode
254     */
255    public int hashCode() {
256        return getName().hashCode();
257    }
258
259    /**
260     * Get a suitable debug string.
261     * 
262     * @return debug string
263     */
264    public String toString() {
265        return "UnsupportedDurationField[" + getName() + ']';
266    }
267
268    /**
269     * Ensure proper singleton serialization
270     */
271    private Object readResolve() {
272        return getInstance(iType);
273    }
274
275    private UnsupportedOperationException unsupported() {
276        return new UnsupportedOperationException(iType + " field is unsupported");
277    }
278
279}