001    /*
002     *  Copyright 2001-2006 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;
017    
018    /**
019     * Exception thrown when attempting to set a field outside its supported range.
020     *
021     * @author Brian S O'Neill
022     * @since 1.1
023     */
024    public class IllegalFieldValueException extends IllegalArgumentException {
025        
026        /** Serialization lock. */
027        private static final long serialVersionUID = 6305711765985447737L;
028    
029        /**
030         * Creates a message for the exception.
031         *
032         * @param fieldName  the field name
033         * @param value  the value rejected
034         * @param lowerBound  the lower bound allowed
035         * @param upperBound  the uppe bound allowed
036         * @param explain  an explanation
037         * @return the message
038         */
039        private static String createMessage(String fieldName, Number value,
040                                            Number lowerBound, Number upperBound, String explain) {
041            StringBuilder buf = new StringBuilder()
042                .append("Value ").append(value).append(" for ").append(fieldName).append(' ');
043    
044            if (lowerBound == null) {
045                if (upperBound == null) {
046                    buf.append("is not supported");
047                } else {
048                    buf.append("must not be larger than ").append(upperBound);
049                }
050            } else if (upperBound == null) {
051                buf.append("must not be smaller than ").append(lowerBound);
052            } else {
053                buf.append("must be in the range [")
054                    .append(lowerBound)
055                    .append(',')
056                    .append(upperBound)
057                    .append(']');
058            }
059            if (explain != null) {
060                buf.append(": ").append(explain);
061            }
062    
063            return buf.toString();
064        }
065    
066        /**
067         * Creates a message for the exception.
068         *
069         * @param fieldName  the field name
070         * @param value  the value rejected
071         * @return the message
072         */
073        private static String createMessage(String fieldName, String value) {
074            StringBuffer buf = new StringBuffer().append("Value ");
075    
076            if (value == null) {
077                buf.append("null");
078            } else {
079                buf.append('"');
080                buf.append(value);
081                buf.append('"');
082            }
083    
084            buf.append(" for ").append(fieldName).append(' ').append("is not supported");
085            
086            return buf.toString();
087        }
088    
089        private final DateTimeFieldType iDateTimeFieldType;
090        private final DurationFieldType iDurationFieldType;
091        private final String iFieldName;
092        private final Number iNumberValue;
093        private final String iStringValue;
094        private final Number iLowerBound;
095        private final Number iUpperBound;
096        private String iMessage;
097    
098        /**
099         * Constructor.
100         * 
101         * @param fieldType  type of field being set
102         * @param value  illegal value being set
103         * @param lowerBound  lower legal field value, or null if not applicable
104         * @param upperBound  upper legal field value, or null if not applicable
105         */
106        public IllegalFieldValueException(DateTimeFieldType fieldType,
107                                          Number value, Number lowerBound, Number upperBound) {
108            super(createMessage(fieldType.getName(), value, lowerBound, upperBound, null));
109            iDateTimeFieldType = fieldType;
110            iDurationFieldType = null;
111            iFieldName = fieldType.getName();
112            iNumberValue = value;
113            iStringValue = null;
114            iLowerBound = lowerBound;
115            iUpperBound = upperBound;
116            iMessage = super.getMessage();
117        }
118    
119        /**
120         * Constructor.
121         * 
122         * @param fieldType  type of field being set
123         * @param value  illegal value being set
124         * @param explain  an explanation
125         * @since 1.5
126         */
127        public IllegalFieldValueException(DateTimeFieldType fieldType,
128                                          Number value, String explain) {
129            super(createMessage(fieldType.getName(), value, null, null, explain));
130            iDateTimeFieldType = fieldType;
131            iDurationFieldType = null;
132            iFieldName = fieldType.getName();
133            iNumberValue = value;
134            iStringValue = null;
135            iLowerBound = null;
136            iUpperBound = null;
137            iMessage = super.getMessage();
138        }
139    
140        /**
141         * Constructor.
142         * 
143         * @param fieldType  type of field being set
144         * @param value  illegal value being set
145         * @param lowerBound  lower legal field value, or null if not applicable
146         * @param upperBound  upper legal field value, or null if not applicable
147         */
148        public IllegalFieldValueException(DurationFieldType fieldType,
149                                          Number value, Number lowerBound, Number upperBound) {
150            super(createMessage(fieldType.getName(), value, lowerBound, upperBound, null));
151            iDateTimeFieldType = null;
152            iDurationFieldType = fieldType;
153            iFieldName = fieldType.getName();
154            iNumberValue = value;
155            iStringValue = null;
156            iLowerBound = lowerBound;
157            iUpperBound = upperBound;
158            iMessage = super.getMessage();
159        }
160    
161        /**
162         * Constructor.
163         * 
164         * @param fieldName  name of field being set
165         * @param value  illegal value being set
166         * @param lowerBound  lower legal field value, or null if not applicable
167         * @param upperBound  upper legal field value, or null if not applicable
168         */
169        public IllegalFieldValueException(String fieldName,
170                                          Number value, Number lowerBound, Number upperBound) {
171            super(createMessage(fieldName, value, lowerBound, upperBound, null));
172            iDateTimeFieldType = null;
173            iDurationFieldType = null;
174            iFieldName = fieldName;
175            iNumberValue = value;
176            iStringValue = null;
177            iLowerBound = lowerBound;
178            iUpperBound = upperBound;
179            iMessage = super.getMessage();
180        }
181    
182        /**
183         * Constructor.
184         * 
185         * @param fieldType  type of field being set
186         * @param value  illegal value being set
187         */
188        public IllegalFieldValueException(DateTimeFieldType fieldType, String value) {
189            super(createMessage(fieldType.getName(), value));
190            iDateTimeFieldType = fieldType;
191            iDurationFieldType = null;
192            iFieldName = fieldType.getName();
193            iStringValue = value;
194            iNumberValue = null;
195            iLowerBound = null;
196            iUpperBound = null;
197            iMessage = super.getMessage();
198        }
199    
200        /**
201         * Constructor.
202         * 
203         * @param fieldType  type of field being set
204         * @param value  illegal value being set
205         */
206        public IllegalFieldValueException(DurationFieldType fieldType, String value) {
207            super(createMessage(fieldType.getName(), value));
208            iDateTimeFieldType = null;
209            iDurationFieldType = fieldType;
210            iFieldName = fieldType.getName();
211            iStringValue = value;
212            iNumberValue = null;
213            iLowerBound = null;
214            iUpperBound = null;
215            iMessage = super.getMessage();
216        }
217    
218        /**
219         * Constructor.
220         * 
221         * @param fieldName  name of field being set
222         * @param value  illegal value being set
223         */
224        public IllegalFieldValueException(String fieldName, String value) {
225            super(createMessage(fieldName, value));
226            iDateTimeFieldType = null;
227            iDurationFieldType = null;
228            iFieldName = fieldName;
229            iStringValue = value;
230            iNumberValue = null;
231            iLowerBound = null;
232            iUpperBound = null;
233            iMessage = super.getMessage();
234        }
235    
236        //-----------------------------------------------------------------------
237        /**
238         * Returns the DateTimeFieldType whose value was invalid, or null if not applicable.
239         * 
240         * @return the datetime field type
241         */
242        public DateTimeFieldType getDateTimeFieldType() {
243            return iDateTimeFieldType;
244        }
245    
246        /**
247         * Returns the DurationFieldType whose value was invalid, or null if not applicable.
248         * 
249         * @return the duration field type
250         */
251        public DurationFieldType getDurationFieldType() {
252            return iDurationFieldType;
253        }
254    
255        /**
256         * Returns the name of the field whose value was invalid.
257         * 
258         * @return the field name
259         */
260        public String getFieldName() {
261            return iFieldName;
262        }
263    
264        /**
265         * Returns the illegal integer value assigned to the field, or null if not applicable.
266         * 
267         * @return the value
268         */
269        public Number getIllegalNumberValue() {
270            return iNumberValue;
271        }
272    
273        /**
274         * Returns the illegal string value assigned to the field, or null if not applicable.
275         * 
276         * @return the value
277         */
278        public String getIllegalStringValue() {
279            return iStringValue;
280        }
281    
282        /**
283         * Returns the illegal value assigned to the field as a non-null string.
284         * 
285         * @return the value
286         */
287        public String getIllegalValueAsString() {
288            String value = iStringValue;
289            if (value == null) {
290                value = String.valueOf(iNumberValue);
291            }
292            return value;
293        }
294    
295        /**
296         * Returns the lower bound of the legal value range, or null if not applicable.
297         * 
298         * @return the lower bound
299         */
300        public Number getLowerBound() {
301            return iLowerBound;
302        }
303    
304        /**
305         * Returns the upper bound of the legal value range, or null if not applicable.
306         * 
307         * @return the upper bound
308         */
309        public Number getUpperBound() {
310            return iUpperBound;
311        }
312    
313        public String getMessage() {
314            return iMessage;
315        }
316    
317        /**
318         * Provide additional detail by prepending a message to the existing message.
319         * A colon is separator is automatically inserted between the messages.
320         * @since 1.3
321         */
322        public void prependMessage(String message) {
323            if (iMessage == null) {
324                iMessage = message;
325            } else if (message != null) {
326                iMessage = message + ": " + iMessage;
327            }
328        }
329    }