001: package uk.org.ponder.conversion;
002:
003: import java.util.Date;
004: import java.util.HashMap;
005: import java.util.Map;
006:
007: import uk.org.ponder.arrayutil.ArrayUtil;
008: import uk.org.ponder.matrix.Matrix;
009: import uk.org.ponder.matrix.MatrixParser;
010: import uk.org.ponder.util.AssertionException;
011:
012: class BooleanParser implements LeafObjectParser {
013: public Object parse(String string) {
014: return (string.equals("yes") || string.equals("y") || string
015: .equals("true")) ? Boolean.TRUE : Boolean.FALSE;
016: }
017:
018: public String render(Object torender) {
019: return torender.toString();
020: }
021:
022: public Object copy(Object tocopy) {
023: return tocopy;
024: }
025: }
026:
027: class DoubleParser implements LeafObjectParser {
028: public Object parse(String string) {
029: return Double.valueOf(string);
030: }
031:
032: public String render(Object torender) {
033: return torender.toString();
034: }
035:
036: public Object copy(Object tocopy) {
037: return tocopy;
038: }
039: }
040:
041: class IntegerParser implements LeafObjectParser {
042: public Object parse(String string) {
043: return Integer.valueOf(string);
044: }
045:
046: public String render(Object torender) {
047: return torender.toString();
048: }
049:
050: public Object copy(Object tocopy) {
051: return tocopy;
052: }
053: }
054:
055: class LongParser implements LeafObjectParser {
056: public Object parse(String string) {
057: return Long.valueOf(string);
058: }
059:
060: public String render(Object torender) {
061: return torender.toString();
062: }
063:
064: public Object copy(Object tocopy) {
065: return tocopy;
066: }
067: }
068:
069: /**
070: * A SAXLeafParser holds a registry of classes capable of parsing Strings into
071: * Java objects for the purposes of representing leaf nodes of the XML tag tree.
072: */
073:
074: public class StaticLeafParser {
075:
076: private static final Map primitiveWrapperTypeMap = new HashMap(16);
077:
078: static {
079: primitiveWrapperTypeMap.put(Boolean.TYPE, Boolean.class);
080: primitiveWrapperTypeMap.put(Byte.TYPE, Byte.class);
081: primitiveWrapperTypeMap.put(Character.TYPE, Character.class);
082: primitiveWrapperTypeMap.put(Double.TYPE, Double.class);
083: primitiveWrapperTypeMap.put(Float.TYPE, Float.class);
084: primitiveWrapperTypeMap.put(Integer.TYPE, Integer.class);
085: primitiveWrapperTypeMap.put(Long.TYPE, Long.class);
086: primitiveWrapperTypeMap.put(Short.TYPE, Short.class);
087: }
088:
089: public static Class wrapClass(Class towrap) {
090: Class wrapper = (Class) primitiveWrapperTypeMap.get(towrap);
091: return wrapper == null ? towrap : wrapper;
092: }
093:
094: // This is a hashtable of classes to SAXLeafTypeParsers
095: HashMap parseabletypes = new HashMap();
096:
097: private static StaticLeafParser instance = new StaticLeafParser();
098:
099: // cross-hatched square character in Unicode, should be entirely unused
100: // in UTF-16, would appear as percent-sign copyright-symbol. 0010010111001001
101: // in UTF-8, would appear as a-hat (unassigned) (unassigned) e29789. 11100010
102: // 10010111 10001001
103: // public static final char solidus = '\u25a9';
104: // public static String NULL_STRING = "\u25a9null\u25a9";
105:
106: private void registerDefaultParsers() {
107: registerParser(Boolean.class, new BooleanParser());
108: registerParser(String.class, new StringParser());
109: registerParser(Integer.class, new IntegerParser());
110: registerParser(Double.class, new DoubleParser());
111: registerParser(Long.class, new LongParser());
112: registerParser(Date.class, new DateParser());
113: registerParser(java.sql.Date.class, new DateParser());
114: registerParser(DateParser.class, new DateParserParser());
115: registerParser(Class.class, new ClassParser());
116: // TODO: These are not suitable for some environments, for example
117: // Javascript
118: registerParser(ArrayUtil.intArrayClass, new intArrayParser());
119: registerParser(ArrayUtil.doubleArrayClass,
120: new doubleArrayParser());
121: registerParser(ArrayUtil.stringArrayClass,
122: StringArrayParser.instance);
123: registerParser(Matrix.class, new MatrixParser());
124: }
125:
126: public StaticLeafParser() {
127: registerDefaultParsers();
128: }
129:
130: /**
131: * Returns the global (singleton) instance of the SAXLeafParser.
132: *
133: * @return The required SAXLeafParser.
134: */
135: public static StaticLeafParser instance() {
136: return instance;
137: }
138:
139: /**
140: * Registers a SAXLeafTypeParser as the parser to be used wherever a
141: * particular class occurs as a leaf type during SAXalization or
142: * DeSAXalization.
143: *
144: * @param toparse The class type parsed by the supplied parser object.
145: * @param parser A SAXLeafTypeParser parsing objects of the supplied class.
146: */
147:
148: public void registerParser(Class toparse, LeafObjectParser parser) {
149: parseabletypes.put(toparse, parser);
150: }
151:
152: /**
153: * This method determines whether the supplied Class object is registered with
154: * the leaf parser.
155: *
156: * @param totest The class type to look up.
157: * @return <code>true</code> if the class type is registered.
158: */
159: public boolean isLeafType(Class totest) {
160: return fetchParser(totest) != null;
161: }
162:
163: private LeafObjectParser fetchParser(Class totest) {
164: if (totest.isPrimitive()) {
165: totest = wrapClass(totest);
166: }
167: LeafObjectParser stored = (LeafObjectParser) parseabletypes
168: .get(totest);
169: if (stored == null) {
170: stored = loadDefaultParser(totest);
171: }
172: return stored;
173: }
174:
175: private LeafObjectParser loadDefaultParser(Class clazz) {
176: StringableLeafTypeParser leafparser = StringableLeafTypeParser
177: .checkClass(clazz);
178: if (leafparser != null) {
179: registerParser(clazz, leafparser);
180: }
181: return leafparser;
182: }
183:
184: /**
185: * This method parses a <code>String</code> into any required object type,
186: * by locating the required parsing class and calling any method discovered in
187: * it called <code>parse</code> that takes an argument of type
188: * <code>String</code>,
189: *
190: * @param returntype The type of the required object.
191: * @param bulk The data to be parsed.
192: * @return the data parsed into an object of the required type.
193: */
194:
195: public Object parse(Class returntype, String bulk) {
196: LeafObjectParser parser = fetchParser(returntype);
197: return parser.parse(bulk);
198: }
199:
200: /**
201: * This method renders the supplied object into text by locating the required
202: * rendering SAXLeafTypeParser class and calling its <code>render</code>
203: * method.
204: *
205: * @param torender The object to be rendered.
206: * @param renderinto A vacant CharWrap object that the renderer may choose to
207: * use for its rendering.
208: * @return a CharWrap object containing the rendered text.
209: */
210: public String render(Object torender) {
211: LeafObjectParser parser = fetchParser(torender.getClass());
212: if (parser == null) {
213: throw new AssertionException(
214: "LeafParser asked to render object of "
215: + torender.getClass()
216: + " which has no registered parser");
217: }
218: return parser.render(torender);
219: }
220:
221: public Object copy(Object tocopy) {
222: Class objtype = tocopy.getClass();
223: LeafObjectParser parser = fetchParser(objtype);
224: if (parser == null) {
225: throw new AssertionException(
226: "LeafParser asked to copy object of type "
227: + objtype.getName()
228: + " which has no registered parser");
229: }
230: return parser.copy(tocopy);
231: }
232: }
233:
234: class StringParser implements LeafObjectParser {
235: public Object parse(String string) {
236: return string;
237: }
238:
239: public String render(Object torender) {
240: return (String) torender;
241: }
242:
243: public Object copy(Object tocopy) {
244: return tocopy;
245: }
246: }
|