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