KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > text > TextFormat


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2006 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.text;
10
11 import j2me.lang.CharSequence;
12 import j2me.text.ParsePosition;
13 import javolution.context.ObjectFactory;
14
15 import java.io.IOException JavaDoc;
16
17 /**
18  * <p> This class represents the base format for text parsing and formatting;
19  * it supports {@link CharSequence} and {@link javolution.text.Appendable}
20  * interfaces for greater flexibility.</p>
21  *
22  * <p> The default format (used by <code>valueOf(CharSequence)</code>,
23  * <code>toString()</code> or <code>toText()</code>)
24  * can be {@link javolution.context.LocalContext locally scoped}.
25  * For example:[code]
26  * public class Complex extends RealtimeObject {
27  * public static final LocalContext.Reference<TextFormat<Complex>> FORMAT
28  * = new LocalContext.Reference<TextFormat<Complex>>(new TextFormat<Complex>() {
29  * ... // Default format (cartesien form).
30  * });
31  * public Complex valueOf(CharSequence csq) {
32  * return FORMAT.get().parse(csq);
33  * }
34  * public Text toText() {
35  * return FORMAT.get().format(this);
36  * }
37  * }
38  * ...
39  * Matrix<Complex> M = ...;
40  * LocalContext.enter();
41  * try {
42  * Complex.FORMAT.set(POLAR); // Current thread displays complex numbers
43  * System.out.prinln(M); // using the polar form.
44  * } finally {
45  * LocalContext.exit(); // Current thread reverts to previous format.
46  * }[/code]</p>
47  *
48  * <p> For parsing/formatting of primitive types, the {@link TypeFormat}
49  * utility class is recommended.</p>
50  *
51  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle </a>
52  * @version 3.7, January 14, 2006
53  */

54 public abstract class TextFormat/*<T>*/{
55
56     /*
57      * Default constructor.
58      */

59     protected TextFormat() {
60     }
61
62     /**
63      * Formats the specified object into an <code>Appendable</code>
64      *
65      * @param obj the object to format.
66      * @param dest the appendable destination.
67      * @return the specified <code>Appendable</code>.
68      * @throws IOException if an I/O exception occurs.
69      */

70     public abstract Appendable JavaDoc format(Object JavaDoc/*{T}*/obj, Appendable JavaDoc dest)
71             throws IOException JavaDoc;
72
73     /**
74      * Parses a portion of the specified <code>CharSequence</code> from the
75      * specified position to produce an object. If parsing succeeds, then the
76      * index of the <code>cursor</code> argument is updated to the index after
77      * the last character used.
78      *
79      * @param csq the <code>CharSequence</code> to parse.
80      * @param cursor the cursor holding the current parsing index.
81      * @return the object parsed from the specified character sub-sequence.
82      * @throws RuntimeException if any problem occurs while parsing the
83      * specified character sequence (e.g. illegal syntax).
84      */

85     public abstract Object JavaDoc/*{T}*/parse(CharSequence JavaDoc csq, Cursor cursor);
86
87     /**
88      * Formats the specified object to a {@link Text} instance
89      * (convenience method).
90      *
91      * @param obj the object being formated.
92      * @return the text representing the specified object.
93      */

94     public final Text format(Object JavaDoc/*{T}*/obj) {
95         try {
96             TextBuilder tb = TextBuilder.newInstance();
97             format(obj, tb);
98             return tb.toText();
99         } catch (IOException JavaDoc e) {
100             throw new Error JavaDoc(); // Should never happen.
101
}
102     }
103
104     /**
105      * Parses a whole character sequence from the beginning to produce an object
106      * (convenience method).
107      *
108      * @param csq the whole character sequence to parse.
109      * @return the corresponding object.
110      * @throws IllegalArgumentException if the specified character sequence
111      * cannot be fully parsed.
112      */

113     public final Object JavaDoc/*{T}*/parse(CharSequence JavaDoc csq) {
114         Cursor cursor = Cursor.newInstance(0, csq.length());
115         Object JavaDoc/*{T}*/obj = parse(csq, cursor);
116         if (cursor.hasNext())
117             throw new IllegalArgumentException JavaDoc("Incomplete Parsing");
118         Cursor.recycle(cursor);
119         return obj;
120     }
121
122     /**
123      * This class represents a parsing cursor over a character sequence
124      * (or subsequence). A cursor location may start and end at any predefined
125      * location within the character sequence iterated over (equivalent to
126      * parsing a subsequence of the character sequence input).
127      */

128     public static class Cursor extends ParsePosition {
129
130         /**
131          * Holds the cursor factory.
132          */

133         private static final ObjectFactory FACTORY = new ObjectFactory() {
134             public Object JavaDoc create() {
135                 return new Cursor();
136             }
137         };
138
139         /**
140          * Holds the cursor index.
141          */

142         private int _index;
143
144         /**
145          * Holds the start index.
146          */

147         private int _start;
148
149         /**
150          * Holds the end index.
151          */

152         private int _end;
153
154         /**
155          * Default constructor.
156          */

157         private Cursor() {
158             super(0);
159         }
160
161         /**
162          * Returns a new, preallocated or {@link #recycle recycled} cursor
163          * instance (on the stack when executing in a {@link
164          * javolution.context.PoolContext PoolContext}).
165          *
166          * @param start the start index.
167          * @param end the end index (index after the last character to be read).
168          * @return a new or recycled cursor instance.
169          */

170         public static Cursor newInstance(int start, int end) {
171             Cursor cursor = (Cursor) FACTORY.object();
172             cursor._start = cursor._index = start;
173             cursor._end = end;
174             cursor.setErrorIndex(-1);
175             return cursor;
176         }
177
178         /**
179          * Recycles a cursor {@link #newInstance instance} immediately
180          * (on the stack when executing in a {@link
181          * javolution.context.PoolContext PoolContext}).
182          *
183          * @param instance the cursor instance being recycled.
184          */

185         public static void recycle(Cursor instance) {
186             FACTORY.recycle(instance);
187         }
188
189         /**
190          * Returns this cursor index.
191          *
192          * @return the index of the next character to parse.
193          */

194         public final int getIndex() {
195             return _index;
196         }
197
198         /**
199          * Returns this cursor start index.
200          *
201          * @return the start index.
202          */

203         public final int getStartIndex() {
204             return _start;
205         }
206
207         /**
208          * Returns this cursor end index.
209          *
210          * @return the end index.
211          */

212         public final int getEndIndex() {
213             return _end;
214         }
215
216         /**
217          * Returns the error index of this cursor if
218          * {@link #setErrorIndex set}; otherwise returns the current
219          * {@link #getIndex index}.
220          *
221          * @return the error index.
222          */

223         public final int getErrorIndex() {
224             int errorIndex = this.getErrorIndex();
225             return errorIndex >= 0 ? errorIndex : _index;
226         }
227
228         /**
229          * Sets the cursor current index.
230          *
231          * @param i the index of the next character to parse.
232          * @throws IllegalArgumentException
233          * if <code>((i < getStartIndex()) || (i > getEndIndex()))</code>
234          */

235         public final void setIndex(int i) {
236             if ((i < _start) || (i > _end))
237                 throw new IllegalArgumentException JavaDoc();
238             _index = i;
239         }
240
241         /**
242          * Sets this cursor start index.
243          *
244          * @param start the start index.
245          */

246         public final void setStartIndex(int start) {
247             _start = start;
248         }
249
250         /**
251          * Sets this cursor end index.
252          *
253          * @param end the end index.
254          */

255         public final void setEndIndex(int end) {
256             _end = end;
257         }
258
259         /**
260          * Sets this cursor error index.
261          *
262          * @param errorIndex the error index.
263          */

264         public final void setErrorIndex(int errorIndex) {
265             super.setErrorIndex(errorIndex);
266         }
267
268         /**
269          * Indicates if this cursor has not reached the end index.
270          *
271          * @return <code>this.getIndex() &lt; this.getEndIndex()</code>
272          */

273         public final boolean hasNext() {
274             return _index < _end;
275         }
276
277         /**
278          * Returns the next character at the cursor position in the specified
279          * character sequence and increments the cursor position by one.
280          * For example:[code]
281          * for (char c=cursor.next(csq); c != 0; c = cursor.next(csq)) {
282          * ...
283          * }
284          * }[/code]
285          *
286          * @param csq the character sequence iterated by this cursor.
287          * @return the character at the current cursor position in the
288          * specified character sequence or <code>'&#92;u0000'</code>
289          * if the end index has already been reached.
290          */

291         public final char next(CharSequence JavaDoc csq) {
292             return (_index < _end) ? csq.charAt(_index++) : 0;
293         }
294
295         /**
296          * Indicates if this cursor points to the specified character
297          * in the specified character sequence.
298          *
299          * @param c the character.
300          * @param csq the character sequence iterated by this cursor.
301          * @return <code>true</code> if the cursor next character is the
302          * one specified; <code>false</code> otherwise.
303          */

304         public final boolean at(char c, CharSequence JavaDoc csq) {
305             return (_index < _end) && (csq.charAt(_index) == c);
306         }
307
308         /**
309          * Indicates if this cursor points to one of the specified character.
310          *
311          * @param charSet the character set
312          * @param csq the character sequence iterated by this cursor.
313          * @return <code>true</code> if the cursor next character is one
314          * of the character contained by the character set;
315          * <code>false</code> otherwise.
316          */

317         public final boolean at(CharSet charSet, CharSequence JavaDoc csq) {
318             return (_index < _end) && (charSet.contains(csq.charAt(_index)));
319         }
320
321         /**
322          * Indicates if this cursor points to the specified characters
323          * in the specified character sequence.
324          *
325          * @param pattern the characters searched for.
326          * @param csq the character sequence iterated by this cursor.
327          * @return <code>true</code> if the cursor next character are the
328          * one specified in the pattern; <code>false</code> otherwise.
329          */

330         public final boolean at(String JavaDoc pattern, CharSequence JavaDoc csq) {
331             return (_index < _end) && (csq.charAt(_index) == pattern.charAt(0)) ? match(
332                     pattern, csq)
333                     : false;
334         }
335
336         private final boolean match(String JavaDoc pattern, CharSequence JavaDoc csq) {
337             for (int i = 1, j = _index + 1, n = pattern.length(), m = _end; i < n;) {
338                 if ((j >= m) || (csq.charAt(j++) != pattern.charAt(i++)))
339                     return false;
340             }
341             return true;
342         }
343
344         /**
345          * Moves this cursor forward until it points to a character
346          * different from the character specified.
347          *
348          * @param c the character to skip.
349          * @param csq the character sequence iterated by this cursor.
350          * @return <code>true</code> if this cursor points to a character
351          * different from the ones specified; <code>false</code>
352          * otherwise (e.g. end of sequence reached).
353          */

354         public final boolean skip(char c, CharSequence JavaDoc csq) {
355             while ((_index < _end) && (csq.charAt(_index) == c)) {
356                 _index++;
357             }
358             return _index < _end;
359         }
360
361         /**
362          * Moves this cursor forward until it points to a character
363          * different from any of the character in the specified set.
364          * For example: [code]
365          * // Reads numbers separated by tabulations or spaces.
366          * FastTable<Integer> numbers = new FastTable<Integer>();
367          * while (cursor.skip(CharSet.SPACE_OR_TAB, csq)) {
368          * numbers.add(TypeFormat.parseInt(csq, cursor));
369          * }[/code]
370          *
371          * @param charSet the character to skip.
372          * @param csq the character sequence iterated by this cursor.
373          * @return <code>true</code> if this cursor points to a character
374          * different from the ones specified; <code>false</code>
375          * otherwise (e.g. end of sequence reached).
376          */

377         public final boolean skip(CharSet charSet, CharSequence JavaDoc csq) {
378             while ((_index < _end) && (charSet.contains(csq.charAt(_index)))) {
379                 _index++;
380             }
381             return _index < _end;
382         }
383
384         /**
385          * Increments the cursor index by one.
386          *
387          * @return <code>this</code>
388          */

389         public final Cursor increment() {
390             _index++;
391             return this;
392         }
393
394         /**
395          * Increments the cursor index by the specified value.
396          *
397          * @param i the increment value.
398          * @return <code>this</code>
399          */

400         public final Cursor increment(int i) {
401             _index += i;
402             return this;
403         }
404
405         /**
406          * Returns the string representation of this cursor.
407          *
408          * @return the index value as a string.
409          */

410         public String JavaDoc toString() {
411             return String.valueOf(_index);
412         }
413         
414         /**
415          * Indicates if this cursor is equals to the specified object.
416          *
417          * @return <code>true</code> if the specified object is a cursor
418          * at the same index; <code>false</code> otherwise.
419          */

420         public boolean equals(Object JavaDoc obj) {
421             if (obj == null) return false;
422             if (!(obj instanceof Cursor))
423                 return false;
424             return _index == ((Cursor)obj)._index;
425         }
426
427         /**
428          * Returns the hash code for this cursor.
429          *
430          * @return the hash code value for this object
431          */

432         public int hashCode() {
433             return _index;
434         }
435         
436     }
437 }
Popular Tags