1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package java.text;
19 
20 import java.io.Serializable;
21 
22 /**
23  * The base class for all formats.
24  * <p>
25  * This is an abstract base class which specifies the protocol for classes which
26  * convert other objects or values, such as numeric values and dates, and their
27  * string representations. In some cases these representations may be localized
28  * or contain localized characters or strings. For example, a numeric formatter
29  * such as {@code DecimalFormat} may convert a numeric value such as 12345 to
30  * the string "$12,345". It may also parse the string back into a numeric value.
31  * A date and time formatter like {@code SimpleDateFormat} may represent a
32  * specific date, encoded numerically, as a string such as "Wednesday, February
33  * 26, 1997 AD".
34  * <p>
35  * Many of the concrete subclasses of {@code Format} employ the notion of a
36  * pattern. A pattern is a string representation of the rules which govern the
37  * conversion between values and strings. For example, a {@code DecimalFormat}
38  * object may be associated with the pattern "$#,##0.00;($#,##0.00)", which is a
39  * common US English format for currency values, yielding strings such as
40  * "$1,234.45" for 1234.45, and "($987.65)" for -987.6543. The specific syntax
41  * of a pattern is defined by each subclass. Even though many subclasses use
42  * patterns, the notion of a pattern is not inherent to {@code Format} classes
43  * in general, and is not part of the explicit base class protocol.
44  * <p>
45  * Two complex formatting classes are worth mentioning: {@code MessageFormat}
46  * and {@code ChoiceFormat}. {@code ChoiceFormat} is a subclass of
47  * {@code NumberFormat} which allows the user to format different number ranges
48  * as strings. For instance, 0 may be represented as "no files", 1 as "one
49  * file", and any number greater than 1 as "many files". {@code MessageFormat}
50  * is a formatter which utilizes other {@code Format} objects to format a string
51  * containing multiple values. For instance, a {@code MessageFormat} object
52  * might produce the string "There are no files on the disk MyDisk on February
53  * 27, 1997." given the arguments 0, "MyDisk", and the date value of 2/27/97.
54  * See the {@link ChoiceFormat} and {@link MessageFormat} descriptions for
55  * further information.
56  */
57 public abstract class Format implements Serializable, Cloneable {
58 
59     private static final long serialVersionUID = -299282585814624189L;
60 
61     /**
62      * Used by subclasses. This was public in Java 5.
63      */
Format()64     protected Format() {
65     }
66 
67     /**
68      * Returns a copy of this {@code Format} instance.
69      *
70      * @return a shallow copy of this format.
71      *
72      * @see java.lang.Cloneable
73      */
74     @Override
clone()75     public Object clone() {
76         try {
77             return super.clone();
78         } catch (CloneNotSupportedException e) {
79             throw new AssertionError(e);
80         }
81     }
82 
83     /**
84      * Formats the specified object using the rules of this format.
85      *
86      * @param object
87      *            the object to format.
88      * @return the formatted string.
89      * @throws IllegalArgumentException
90      *         if the object cannot be formatted by this format.
91      */
format(Object object)92     public final String format(Object object) {
93         return format(object, new StringBuffer(), new FieldPosition(0))
94                 .toString();
95     }
96 
97     /**
98      * Appends the specified object to the specified string buffer using the
99      * rules of this format.
100      * <p>
101      * {@code field} is an input/output parameter. If its {@code field}
102      * member contains an enum value specifying a field on input, then its
103      * {@code beginIndex} and {@code endIndex} members will be updated with the
104      * text offset of the first occurrence of this field in the formatted text.
105      *
106      * @param object
107      *            the object to format.
108      * @param buffer
109      *            the string buffer where the formatted string is appended to.
110      * @param field
111      *            on input: an optional alignment field; on output: the offsets
112      *            of the alignment field in the formatted text.
113      * @return the string buffer.
114      * @throws IllegalArgumentException
115      *            if the object cannot be formatted by this format.
116      */
format(Object object, StringBuffer buffer, FieldPosition field)117     public abstract StringBuffer format(Object object, StringBuffer buffer,
118             FieldPosition field);
119 
120     /**
121      * Formats the specified object using the rules of this format and returns
122      * an {@code AttributedCharacterIterator} with the formatted string and no
123      * attributes.
124      * <p>
125      * Subclasses should return an {@code AttributedCharacterIterator} with the
126      * appropriate attributes.
127      *
128      * @param object
129      *            the object to format.
130      * @return an {@code AttributedCharacterIterator} with the formatted object
131      *         and attributes.
132      * @throws IllegalArgumentException
133      *            if the object cannot be formatted by this format.
134      */
formatToCharacterIterator(Object object)135     public AttributedCharacterIterator formatToCharacterIterator(Object object) {
136         return new AttributedString(format(object)).getIterator();
137     }
138 
139     /**
140      * Parses the specified string using the rules of this format.
141      *
142      * @param string
143      *            the string to parse.
144      * @return the object resulting from the parse.
145      * @throws ParseException
146      *            if an error occurs during parsing.
147      */
parseObject(String string)148     public Object parseObject(String string) throws ParseException {
149         ParsePosition position = new ParsePosition(0);
150         Object result = parseObject(string, position);
151         if (position.getIndex() == 0) {
152             throw new ParseException("Parse failure", position.getErrorIndex());
153         }
154         return result;
155     }
156 
157     /**
158      * Parses the specified string starting at the index specified by
159      * {@code position}. If the string is successfully parsed then the index of
160      * the {@code ParsePosition} is updated to the index following the parsed
161      * text. On error, the index is unchanged and the error index of
162      * {@code ParsePosition} is set to the index where the error occurred.
163      *
164      * @param string
165      *            the string to parse.
166      * @param position
167      *            input/output parameter, specifies the start index in
168      *            {@code string} from where to start parsing. If parsing is
169      *            successful, it is updated with the index following the parsed
170      *            text; on error, the index is unchanged and the error index is
171      *            set to the index where the error occurred.
172      * @return the object resulting from the parse or {@code null} if there is
173      *         an error.
174      */
parseObject(String string, ParsePosition position)175     public abstract Object parseObject(String string, ParsePosition position);
176 
upTo(String string, ParsePosition position, StringBuffer buffer, char stop)177     static boolean upTo(String string, ParsePosition position,
178             StringBuffer buffer, char stop) {
179         int index = position.getIndex(), length = string.length();
180         boolean lastQuote = false, quote = false;
181         while (index < length) {
182             char ch = string.charAt(index++);
183             if (ch == '\'') {
184                 if (lastQuote) {
185                     buffer.append('\'');
186                 }
187                 quote = !quote;
188                 lastQuote = true;
189             } else if (ch == stop && !quote) {
190                 position.setIndex(index);
191                 return true;
192             } else {
193                 lastQuote = false;
194                 buffer.append(ch);
195             }
196         }
197         position.setIndex(index);
198         return false;
199     }
200 
upToWithQuotes(String string, ParsePosition position, StringBuffer buffer, char stop, char start)201     static boolean upToWithQuotes(String string, ParsePosition position,
202             StringBuffer buffer, char stop, char start) {
203         int index = position.getIndex(), length = string.length(), count = 1;
204         boolean quote = false;
205         while (index < length) {
206             char ch = string.charAt(index++);
207             if (ch == '\'') {
208                 quote = !quote;
209             }
210             if (!quote) {
211                 if (ch == stop) {
212                     count--;
213                 }
214                 if (count == 0) {
215                     position.setIndex(index);
216                     return true;
217                 }
218                 if (ch == start) {
219                     count++;
220                 }
221             }
222             buffer.append(ch);
223         }
224         throw new IllegalArgumentException("Unmatched braces in the pattern");
225     }
226 
227     /**
228      * Inner class used to represent {@code Format} attributes in the
229      * {@code AttributedCharacterIterator} that the
230      * {@code formatToCharacterIterator()} method returns in {@code Format}
231      * subclasses.
232      */
233     public static class Field extends AttributedCharacterIterator.Attribute {
234 
235         private static final long serialVersionUID = 276966692217360283L;
236 
237         /**
238          * Constructs a new instance of {@code Field} with the given field name.
239          *
240          * @param fieldName
241          *            the field name.
242          */
Field(String fieldName)243         protected Field(String fieldName) {
244             super(fieldName);
245         }
246     }
247 }
248