0001: /*
0002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
0003: * Copyright (C) 2006 - Javolution (http://javolution.org/)
0004: * All rights reserved.
0005: *
0006: * Permission to use, copy, modify, and distribute this software is
0007: * freely granted, provided that this notice is preserved.
0008: */
0009: package javolution.xml;
0010:
0011: import java.io.IOException;
0012: import javolution.Javolution;
0013: import javolution.JavolutionError;
0014: import javolution.context.PersistentContext;
0015: import javolution.lang.ClassInitializer;
0016: import javolution.lang.Reflection;
0017: import javolution.lang.Reusable;
0018: import javolution.text.Appendable;
0019: import javolution.text.CharArray;
0020: import javolution.text.Text;
0021: import javolution.util.FastCollection;
0022: import javolution.util.FastComparator;
0023: import javolution.util.FastMap;
0024: import javolution.util.Index;
0025: import javolution.util.FastCollection.Record;
0026: import javolution.util.FastMap.Entry;
0027: import javolution.xml.stream.XMLStreamException;
0028: import javolution.xml.stream.XMLStreamReaderImpl;
0029: import javolution.xml.stream.XMLStreamWriterImpl;
0030: import j2me.lang.CharSequence;
0031: import j2me.util.Collection;
0032: import j2me.util.Iterator;
0033: import j2me.util.Map;
0034:
0035: /**
0036: * <p> This class represents the binding between Java classes and
0037: * their XML representation ({@link XMLFormat}); the binding may be shared
0038: * among multiple {@link XMLObjectReader}/ {@link XMLObjectWriter}
0039: * instances (thread-safe).</p>
0040: *
0041: * <p> Custom XML bindings can also be used to alias class names and
0042: * ensure that the XML representation is:<ul>
0043: * <li> Impervious to obfuscation.</li>
0044: * <li> Unnaffected by any class refactoring.</li>
0045: * <li> Can be mapped to multiple implementations. For example:[code]
0046: *
0047: * // Creates a binding to serialize Swing components into high-level XML
0048: * // and deserialize the same XML into SWT components.
0049: * XMLBinding swingBinding = new XMLBinding();
0050: * swingBinding.setAlias(javax.swing.JButton.class, "Button");
0051: * swingBinding.setAlias(javax.swing.JTable.class, "Table");
0052: * ...
0053: * XMLBinding swtBinding = new XMLBinding();
0054: * swtBinding.setAlias(org.eclipse.swt.widgets.Button.class, "Button");
0055: * swtBinding.setAlias(org.eclipse.swt.widgets.Table.class, "Table");
0056: * ...
0057: *
0058: * // Writes Swing Desktop to XML.
0059: * XMLObjectWriter writer = new XMLObjectWriter().setBinding(swingBinding);
0060: * writer.setOutput(new FileOutputStream("C:/desktop.xml"));
0061: * writer.write(swingDesktop, "Desktop", SwingDesktop.class);
0062: * writer.close();
0063: *
0064: * // Reads back high-level XML to a SWT implementation!
0065: * XMLObjectReader reader = new XMLObjectReader().setXMLBinding(swtBinding);
0066: * reader.setInput(new FileInputStream("C:/desktop.xml"));
0067: * SWTDesktop swtDesktop = reader.read("Desktop", SWTDesktop.class);
0068: * reader.close();
0069: * [/code]</li>
0070: * </ul></p>
0071: *
0072: * <p> More advanced bindings can also be created through sub-classing.[code]
0073: *
0074: * // XML binding using reflection.
0075: * public ReflectionBinding extends XMLBinding {
0076: * public <T> XMLFormat<T> getFormat(Class<T> cls) {
0077: * Field[] fields = clt.getDeclaredFields();
0078: * return new XMLReflectionFormat<T>(fields);
0079: * }
0080: * }
0081: *
0082: * // XML binding read from DTD input source.
0083: * public DTDBinding extends XMLBinding {
0084: * public DTDBinding(InputStream dtd) {
0085: * ...
0086: * }
0087: * }
0088: *
0089: * // XML binding overriding statically bounded formats.
0090: * public MyBinding extends XMLBinding {
0091: * // Non-static formats use unmapped XMLFormat instances.
0092: * XMLFormat<String> _myStringFormat = new XMLFormat<String>(null) {...}
0093: * XMLFormat<Collection> _myCollectionFormat = new XMLFormat<Collection>(null) {...}
0094: * public <T> XMLFormat<T> getFormat(Class<T> cls) {
0095: * if (String.class.equals(cls))
0096: * return _myStringFormat;
0097: * if (Collection.class.isAssignableFrom(cls))
0098: * return _myCollectionFormat;
0099: * return super.getFormat(cls);
0100: * }
0101: * }
0102: * [/code]
0103: *
0104: * <p> The default XML binding supports all static XML formats
0105: * (static members of the classes being mapped) as well as the
0106: * following types:<ul>
0107: * <li><code>java.lang.Object</code> (empty element)</li>
0108: * <li><code>java.lang.Class</code></li>
0109: * <li><code>java.lang.String</code></li>
0110: * <li><code>java.lang.Appendable</code></li>
0111: * <li><code>java.util.Collection</code></li>
0112: * <li><code>java.util.Map</code></li>
0113: * <li><code>java.lang.Object[]</code></li>
0114: * <li> all primitive types wrappers (e.g.
0115: * <code>Boolean, Integer ...</code>)</li>
0116: * </ul></p>
0117: *
0118: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
0119: * @version 4.0, April 9, 2007
0120: */
0121: public class XMLBinding implements Reusable, XMLSerializable {
0122:
0123: /**
0124: * Holds the static mapping format.
0125: */
0126: private static FastMap STATIC_MAPPING = new FastMap()
0127: .setShared(true);
0128:
0129: /**
0130: * Holds the default instance used by readers/writers.
0131: */
0132: static final XMLBinding DEFAULT = new XMLBinding();
0133:
0134: /**
0135: * Holds the XML representation of this binding (class/alias mapping
0136: * and class attribute values).
0137: */
0138: static final XMLFormat XML = new XMLFormat(Javolution
0139: .j2meGetClass("javolution.xml.XMLBinding")) {
0140:
0141: public void read(InputElement xml, Object obj)
0142: throws XMLStreamException {
0143: XMLBinding binding = (XMLBinding) obj;
0144: binding._classAttributeName = xml.getAttribute(
0145: "classAttributeName", (String) null);
0146: binding._classAttributeURI = xml.getAttribute(
0147: "classAttributeURI", (String) null);
0148: FastMap fm = binding._aliasToClass = (FastMap) xml.get(
0149: "AliasToClass", FastMap.class);
0150: // Builds reverse mapping automatically.
0151: for (Entry e = fm.head(), t = fm.tail(); (e = (Entry) e
0152: .getNext()) != t;) {
0153: binding._classToAlias.put(e.getValue(), e.getKey());
0154: }
0155: }
0156:
0157: public void write(Object obj, OutputElement xml)
0158: throws XMLStreamException {
0159: XMLBinding binding = (XMLBinding) obj;
0160: xml.setAttribute("classAttributeName",
0161: binding._classAttributeName);
0162: xml.setAttribute("classAttributeURI",
0163: binding._classAttributeURI);
0164: xml.add(binding._aliasToClass, "AliasToClass",
0165: FastMap.class);
0166: }
0167: };
0168:
0169: /**
0170: * Holds the local name of the class attribute.
0171: */
0172: private String _classAttributeName = "class";
0173:
0174: /**
0175: * Holds the URI of the class attribute if any.
0176: */
0177: private String _classAttributeURI = null;
0178:
0179: /**
0180: * Holds the class to name mapping.
0181: */
0182: private FastMap _classToAlias = new FastMap();
0183:
0184: /**
0185: * Holds the name to class mapping.
0186: */
0187: private FastMap _aliasToClass = new FastMap();
0188:
0189: /**
0190: * Default constructor.
0191: */
0192: public XMLBinding() {
0193: }
0194:
0195: /**
0196: * Sets the alias of the specified class. Classes may have multiple
0197: * aliases but any given alias maps to a single class.
0198: *
0199: * @param cls the class being aliased.
0200: * @param alias the alias for the specified class.
0201: */
0202: public void setAlias(Class cls, String alias) {
0203: Class prevForAlias = (Class) _aliasToClass.put(alias, cls);
0204: // Removes any previous class to given alias mapping.
0205: if (prevForAlias != null) {
0206: _classToAlias.put(prevForAlias, null);
0207: }
0208: _classToAlias.put(cls, alias);
0209: }
0210:
0211: /**
0212: * Sets the name of the attribute holding the classname/alias
0213: * (by default<code>"class"</code>).
0214: * If the local name is <code>null</code> then the class attribute
0215: * is never read/written (which may prevent unmarshalling).
0216: *
0217: * @param name the local name of the attribute or <code>null</code>.
0218: */
0219: public void setClassAttribute(String name) {
0220: _classAttributeName = name;
0221: _classAttributeURI = null;
0222: }
0223:
0224: /**
0225: * Sets the local name and namespace URI of the attribute holding the
0226: * classname/alias (by default<code>"class"</code> and no namespace URI).
0227: * If the local name is <code>null</code> then the class attribute
0228: * is never read/written (which may prevent unmarshalling).
0229: *
0230: * @param localName the local name of the attribute or <code>null</code>.
0231: * @param uri the URI of the attribute or <code>null</code> if the
0232: * class attribute has no namespace URI.
0233: */
0234: public void setClassAttribute(String localName, String uri) {
0235: _classAttributeName = localName;
0236: _classAttributeURI = uri;
0237: }
0238:
0239: /**
0240: * Returns the XML format for the specified class/interface.
0241: * The default implementation returns the most
0242: * specialized static format compatible with the specified class.
0243: *
0244: * @param cls the class for which the XML format is returned.
0245: * @return the XML format for the specified class.
0246: */
0247: public/*<T>*/XMLFormat/*<T>*/getFormat(Class/*<T>*/cls) {
0248: Object xmlFormat = STATIC_MAPPING.get(cls);
0249: return (xmlFormat != null) ? (XMLFormat) xmlFormat
0250: : searchFormat(cls);
0251: }
0252:
0253: private XMLFormat searchFormat(Class cls) {
0254: // First initialize class to ensure static format creation.
0255: ClassInitializer.initialize(cls);
0256:
0257: // Then search best match.
0258: XMLFormat bestMatchFormat = null;
0259: for (int i = 0, j = XMLFormat._ClassInstancesLength; i < j; i++) {
0260: XMLFormat xmlFormat = XMLFormat._ClassInstances[i];
0261: if (xmlFormat._class.isAssignableFrom(cls)) { // Compatible.
0262: if ((bestMatchFormat == null)
0263: || (bestMatchFormat._class
0264: .isAssignableFrom(xmlFormat._class))) {
0265: bestMatchFormat = xmlFormat;
0266: }
0267: }
0268: }
0269: if (bestMatchFormat == null)
0270: throw new JavolutionError("Cannot find format for " + cls);
0271:
0272: STATIC_MAPPING.put(cls, bestMatchFormat);
0273: return bestMatchFormat;
0274: }
0275:
0276: /**
0277: * Returns the name identifying the specified class (value of
0278: * {@link #setClassAttribute class attribute} during marshalling).
0279: * The default implementation returns the class alias (if any) or
0280: * <code>cls.getName()</code>.
0281: *
0282: * @param cls the class for which a name identifier is returned.
0283: * @return the alias or name for the class.
0284: */
0285: protected String getName(Class cls) {
0286: String alias = (String) _classToAlias.get(cls);
0287: return (alias != null) ? alias : cls.getName();
0288: }
0289:
0290: /**
0291: * Returns the class identified by the specified name (value of
0292: * {@link #setClassAttribute class attribute} during unmarshalling).
0293: * The default implementation returns an aliased class or
0294: * <code>Class.forName(name.toString())</code>.
0295: *
0296: * @param name the class name identifier.
0297: * @return the class for the specified name.
0298: * @throws ClassNotFoundException
0299: */
0300: protected Class getClass(CharArray name)
0301: throws ClassNotFoundException {
0302: Class cls = (Class) _aliasToClass.get(name);
0303: return (cls != null) ? cls : Reflection.getClass(name);
0304: }
0305:
0306: /**
0307: * Returns the local name identifying the specified class (the element local
0308: * name during marshalling). The default implementation returns
0309: * <code>this.getName(cls)</code>.
0310: *
0311: * @param cls the class for which the local name is returned.
0312: * @return the local name of the specified class.
0313: */
0314: protected String getLocalName(Class cls) {
0315: return this .getName(cls);
0316: }
0317:
0318: /**
0319: * Returns the URI identifying the specified class (the element namespace
0320: * URI during marshalling). The default implementation returns
0321: * <code>null</code> (no namespace URI).
0322: *
0323: * @param cls the class for which the namespace URI is returned.
0324: * @return the URI for the specified class or <code>null</code> if none.
0325: */
0326: protected String getURI(Class cls) {
0327: return null;
0328: }
0329:
0330: /**
0331: * Returns the class identified by the specified local name and URI
0332: * (the element local name and URI during unmarshalling). The default
0333: * implementation returns <code>getClass(localName)</code>.
0334: *
0335: * @param localName the class local name identifier.
0336: * @param uri the class URI identifier (can be <code>null</code>).
0337: * @return the corresponding class.
0338: * @throws ClassNotFoundException
0339: */
0340: protected Class getClass(CharArray localName, CharArray uri)
0341: throws ClassNotFoundException {
0342: return getClass(localName);
0343: }
0344:
0345: // Implements Reusable.
0346: public void reset() {
0347: _aliasToClass.reset();
0348: _classToAlias.reset();
0349: }
0350:
0351: /**
0352: * Reads the class from the class attribute of current XML element.
0353: *
0354: * @param reader the reader to be used.
0355: * @return the corresponding class.
0356: * @throws XMLStreamException
0357: */
0358: final Class readClassAttribute(XMLStreamReaderImpl reader)
0359: throws XMLStreamException {
0360: if (_classAttributeName == null)
0361: throw new XMLStreamException(
0362: "Binding has no class attribute defined, cannot retrieve class");
0363: CharArray className = reader.getAttributeValue(
0364: toCsq(_classAttributeURI), toCsq(_classAttributeName));
0365: if (className == null)
0366: throw new XMLStreamException(
0367: "Cannot retrieve class (class attribute not found)");
0368: try {
0369: return getClass(className);
0370: } catch (ClassNotFoundException e) {
0371: throw new XMLStreamException(e);
0372: }
0373: }
0374:
0375: /**
0376: * Writes the class to the class attribute of the current XML element.
0377: *
0378: * @param writer the writer to be used.
0379: * @param cls the class being written.
0380: * @throws XMLStreamException
0381: */
0382: final void writeClassAttribute(XMLStreamWriterImpl writer, Class cls)
0383: throws XMLStreamException {
0384:
0385: if (_classAttributeName != null) {
0386: String value = getName(cls);
0387: if (_classAttributeURI == null) {
0388: writer.writeAttribute(toCsq(_classAttributeName),
0389: toCsq(value));
0390: } else {
0391: writer.writeAttribute(toCsq(_classAttributeURI),
0392: toCsq(_classAttributeName), toCsq(value));
0393: }
0394: }
0395: }
0396:
0397: /**
0398: * Holds the static XML format for <code>Object.class</code> instances
0399: * (default format when a more specialized format does not exist).
0400: * The XML representation consists of an empty element with no attribute.
0401: */
0402: static final XMLFormat/*<Object>*/OBJECT_XML = new XMLFormat(
0403: new Object().getClass()) {
0404:
0405: public void read(javolution.xml.XMLFormat.InputElement xml,
0406: Object obj) {
0407: // Do nothing.
0408: }
0409:
0410: public void write(Object obj,
0411: javolution.xml.XMLFormat.OutputElement xml) {
0412: // Do nothing
0413: }
0414: };
0415:
0416: /**
0417: * Holds the default XML representation for <code>java.lang.Class</code>
0418: * instances. This representation consists of a <code>"name"</code>
0419: * attribute holding the class name.
0420: */
0421: static final XMLFormat/*<Class>*/CLASS_XML = new XMLFormat(""
0422: .getClass().getClass()) {
0423:
0424: public boolean isReferenceable() {
0425: return false; // Always by value (immutable).
0426: }
0427:
0428: public Object newInstance(Class cls,
0429: javolution.xml.XMLFormat.InputElement xml)
0430: throws XMLStreamException {
0431: CharArray name = xml.getAttribute("name");
0432: if (name == null)
0433: throw new XMLStreamException("Attribute 'name' missing");
0434: Class clazz;
0435: try {
0436: clazz = Reflection.getClass(name);
0437: } catch (ClassNotFoundException e) {
0438: throw new XMLStreamException(e);
0439: }
0440: return clazz;
0441: }
0442:
0443: public void read(javolution.xml.XMLFormat.InputElement xml,
0444: Object obj) throws XMLStreamException {
0445: // Do nothing.
0446: }
0447:
0448: public void write(Object obj,
0449: javolution.xml.XMLFormat.OutputElement xml)
0450: throws XMLStreamException {
0451: xml.setAttribute("name", ((Class) obj).getName());
0452: }
0453: };
0454:
0455: /**
0456: * Holds the default XML representation for <code>java.lang.String</code>
0457: * instances. This representation consists of a <code>"value"</code>
0458: * attribute holding the string.
0459: */
0460: static final XMLFormat/*<String>*/STRING_XML = new XMLFormat(""
0461: .getClass()) {
0462:
0463: public Object newInstance(Class cls,
0464: javolution.xml.XMLFormat.InputElement xml)
0465: throws XMLStreamException {
0466: return xml.getAttribute("value", "");
0467: }
0468:
0469: public void read(InputElement xml, Object obj)
0470: throws XMLStreamException {
0471: // Do nothing.
0472: }
0473:
0474: public void write(Object obj, OutputElement xml)
0475: throws XMLStreamException {
0476: xml.setAttribute("value", (String) obj);
0477: }
0478: };
0479:
0480: /**
0481: * Holds the default XML representation for <code>java.lang.Appendable</code>
0482: * instances. This representation consists of a <code>"value"</code> attribute
0483: * holding the characters.
0484: */
0485: static final XMLFormat/*<Appendable>*/APPENDABLE_XML = new XMLFormat(
0486: Javolution.j2meGetClass("javolution.text.Appendable")) {
0487:
0488: public void read(InputElement xml, Object obj)
0489: throws XMLStreamException {
0490: CharSequence csq = xml.getAttribute("value");
0491: if (csq != null) {
0492: try {
0493: ((Appendable) obj).append(csq);
0494: } catch (IOException e) {
0495: throw new XMLStreamException(e);
0496: }
0497: }
0498: }
0499:
0500: public void write(Object obj, OutputElement xml)
0501: throws XMLStreamException {
0502: if (obj instanceof CharSequence) {
0503: xml.setAttribute("value", (CharSequence) obj);
0504: } else {
0505: xml.setAttribute("value", obj.toString());
0506: }
0507: }
0508: };
0509:
0510: /**
0511: * Holds the default XML representation for <code>java.util.Collection</code>
0512: * instances. This representation consists of nested XML elements one for
0513: * each element of the collection. The elements' order is defined by
0514: * the collection iterator order. Collections are deserialized using their
0515: * default constructor.
0516: */
0517: static final XMLFormat/*<Collection>*/COLLECTION_XML = new XMLFormat(
0518: Javolution.j2meGetClass("j2me.util.Collection")) {
0519:
0520: public void read(InputElement xml, Object obj)
0521: throws XMLStreamException {
0522: Collection collection = (Collection) obj;
0523: while (xml.hasNext()) {
0524: collection.add(xml.getNext());
0525: }
0526: }
0527:
0528: public void write(Object obj, OutputElement xml)
0529: throws XMLStreamException {
0530: Collection collection = (Collection) obj;
0531: for (Iterator i = collection.iterator(); i.hasNext();) {
0532: xml.add(i.next());
0533: }
0534: }
0535: };
0536:
0537: /**
0538: * Holds the default XML representation for <code>java.util.Map</code>
0539: * instances. This representation consists of key/value pair as nested
0540: * XML elements. For example:[code]
0541: * <javolution.util.FastMap>
0542: * <Key class="java.lang.String" value="ONE"/>
0543: * <Value class="java.lang.Integer" value="1"/>
0544: * <Key class="java.lang.String" value="TWO"/>
0545: * <Value class="java.lang.Integer" value="2"/>
0546: * <Key class="java.lang.String" value="THREE"/>
0547: * <Value class="java.lang.Integer" value="3"/>
0548: * </javolution.util.FastMap>[/code]
0549: *
0550: * The elements' order is defined by the map's entries iterator order.
0551: * Maps are deserialized using their default constructor.
0552: */
0553: static final XMLFormat/*<Map>*/MAP_XML = new XMLFormat(Javolution
0554: .j2meGetClass("j2me.util.Map")) {
0555:
0556: public void read(InputElement xml, Object obj)
0557: throws XMLStreamException {
0558: final Map map = (Map) obj;
0559: while (xml.hasNext()) {
0560: Object key = xml.get("Key");
0561: Object value = xml.get("Value");
0562: map.put(key, value);
0563: }
0564: }
0565:
0566: public void write(Object obj, OutputElement xml)
0567: throws XMLStreamException {
0568: final Map map = (Map) obj;
0569: for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
0570: Map.Entry entry = (Map.Entry) it.next();
0571: xml.add(entry.getKey(), "Key");
0572: xml.add(entry.getValue(), "Value");
0573: }
0574: }
0575: };
0576:
0577: /**
0578: * Holds the default XML representation for <code>java.lang.Object[]</code>
0579: * instances. This representation consists of nested XML elements one for
0580: * each element of the array.
0581: /*@JVM-1.4+@
0582: static final XMLFormat
0583: /**/
0584: /*<Object[]>*//*@JVM-1.4+@
0585: OBJECT_ARRAY_XML = new XMLFormat(
0586: new Object[0].getClass()) {
0587: public Object newInstance(Class cls, javolution.xml.XMLFormat.InputElement xml) throws XMLStreamException {
0588: Class componentType = cls.getComponentType();
0589: int length = xml.getAttribute("length", 0);
0590: return java.lang.reflect.Array.newInstance(componentType, length);
0591: }
0592:
0593: public void read(InputElement xml, Object obj) throws XMLStreamException {
0594: Object[] array = (Object[]) obj;
0595: for (int i=0; i < array.length; i++) {
0596: array[i] = xml.getNext();
0597: }
0598: }
0599:
0600: public void write(Object obj, OutputElement xml) throws XMLStreamException {
0601: Object[] array = (Object[]) obj;
0602: xml.setAttribute("length", array.length);
0603: for (int i=0; i < array.length; i++) {
0604: xml.add(array[i]);
0605: }
0606: }
0607: };
0608: /**/
0609:
0610: /**
0611: * Holds the default XML representation for <code>java.lang.Boolean</code>.
0612: */
0613: static final XMLFormat/*<Boolean>*/BOOLEAN_XML = new XMLFormat(
0614: new Boolean(true).getClass()) {
0615:
0616: public boolean isReferenceable() {
0617: return false; // Always by value (immutable).
0618: }
0619:
0620: public Object newInstance(Class cls,
0621: javolution.xml.XMLFormat.InputElement xml)
0622: throws XMLStreamException {
0623: return new Boolean(xml.getAttribute("value", false));
0624: }
0625:
0626: public void read(InputElement xml, Object obj)
0627: throws XMLStreamException {
0628: // Do nothing.
0629: }
0630:
0631: public void write(Object obj, OutputElement xml)
0632: throws XMLStreamException {
0633: xml.setAttribute("value", ((Boolean) obj).booleanValue());
0634: }
0635: };
0636:
0637: /**
0638: * Holds the default XML representation for <code>java.lang.Byte</code>.
0639: */
0640: static final XMLFormat/*<Byte>*/BYTE_XML = new XMLFormat(new Byte(
0641: (byte) 0).getClass()) {
0642:
0643: public boolean isReferenceable() {
0644: return false; // Always by value (immutable).
0645: }
0646:
0647: public Object newInstance(Class cls,
0648: javolution.xml.XMLFormat.InputElement xml)
0649: throws XMLStreamException {
0650: return new Byte((byte) xml.getAttribute("value", 0));
0651: }
0652:
0653: public void read(InputElement xml, Object obj)
0654: throws XMLStreamException {
0655: // Do nothing.
0656: }
0657:
0658: public void write(Object obj, OutputElement xml)
0659: throws XMLStreamException {
0660: xml.setAttribute("value", ((Byte) obj).byteValue());
0661: }
0662: };
0663:
0664: /**
0665: * Holds the default XML representation for <code>java.lang.Character</code>.
0666: */
0667: static final XMLFormat/*<Character>*/CHARACTER_XML = new XMLFormat(
0668: new Character(' ').getClass()) {
0669:
0670: public boolean isReferenceable() {
0671: return false; // Always by value (immutable).
0672: }
0673:
0674: public Object newInstance(Class cls,
0675: javolution.xml.XMLFormat.InputElement xml)
0676: throws XMLStreamException {
0677: CharSequence csq = xml.getAttribute("value");
0678: if ((csq == null) || (csq.length() != 1))
0679: throw new XMLStreamException(
0680: "Missing or invalid value attribute");
0681: return new Character(csq.charAt(0));
0682: }
0683:
0684: public void read(InputElement xml, Object obj)
0685: throws XMLStreamException {
0686: // Do nothing.
0687: }
0688:
0689: public void write(Object obj, OutputElement xml)
0690: throws XMLStreamException {
0691: xml.setAttribute("value", Text.valueOf(((Character) obj)
0692: .charValue()));
0693: }
0694: };
0695:
0696: /**
0697: * Holds the default XML representation for <code>java.lang.Short</code>.
0698: */
0699: static final XMLFormat/*<Short>*/SHORT_XML = new XMLFormat(
0700: new Short((short) 0).getClass()) {
0701:
0702: public boolean isReferenceable() {
0703: return false; // Always by value (immutable).
0704: }
0705:
0706: public Object newInstance(Class cls,
0707: javolution.xml.XMLFormat.InputElement xml)
0708: throws XMLStreamException {
0709: return new Short((short) xml.getAttribute("value", 0));
0710: }
0711:
0712: public void read(InputElement xml, Object obj)
0713: throws XMLStreamException {
0714: // Do nothing.
0715: }
0716:
0717: public void write(Object obj, OutputElement xml)
0718: throws XMLStreamException {
0719: xml.setAttribute("value", ((Short) obj).shortValue());
0720: }
0721: };
0722:
0723: /**
0724: * Holds the default XML representation for <code>java.lang.Integer</code>.
0725: */
0726: static final XMLFormat/*<Integer>*/INTEGER_XML = new XMLFormat(
0727: new Integer(0).getClass()) {
0728:
0729: public boolean isReferenceable() {
0730: return false; // Always by value (immutable).
0731: }
0732:
0733: public Object newInstance(Class cls,
0734: javolution.xml.XMLFormat.InputElement xml)
0735: throws XMLStreamException {
0736: return new Integer(xml.getAttribute("value", 0));
0737: }
0738:
0739: public void read(InputElement xml, Object obj)
0740: throws XMLStreamException {
0741: // Do nothing.
0742: }
0743:
0744: public void write(Object obj, OutputElement xml)
0745: throws XMLStreamException {
0746: xml.setAttribute("value", ((Integer) obj).intValue());
0747: }
0748: };
0749:
0750: /**
0751: * Holds the default XML representation for <code>java.lang.Long</code>.
0752: */
0753: static final XMLFormat/*<Long>*/LONG_XML = new XMLFormat(new Long(
0754: 0).getClass()) {
0755:
0756: public boolean isReferenceable() {
0757: return false; // Always by value (immutable).
0758: }
0759:
0760: public Object newInstance(Class cls,
0761: javolution.xml.XMLFormat.InputElement xml)
0762: throws XMLStreamException {
0763: return new Long(xml.getAttribute("value", 0L));
0764: }
0765:
0766: public void read(InputElement xml, Object obj)
0767: throws XMLStreamException {
0768: // Do nothing.
0769: }
0770:
0771: public void write(Object obj, OutputElement xml)
0772: throws XMLStreamException {
0773: xml.setAttribute("value", ((Long) obj).longValue());
0774: }
0775: };
0776:
0777: /**
0778: * Holds the default XML representation for <code>java.lang.Float</code>.
0779: /*@JVM-1.1+@
0780: static final XMLFormat
0781: /**/
0782: /*<Float>*//*@JVM-1.1+@
0783: FLOAT_XML = new XMLFormat(new Float(0f).getClass()) {
0784:
0785: public boolean isReferenceable() {
0786: return false; // Always by value (immutable).
0787: }
0788:
0789: public Object newInstance(Class cls, javolution.xml.XMLFormat.InputElement xml) throws XMLStreamException {
0790: return new Float(xml.getAttribute("value", 0f));
0791: }
0792:
0793: public void read(InputElement xml, Object obj) throws XMLStreamException {
0794: // Do nothing.
0795: }
0796:
0797: public void write(Object obj, OutputElement xml) throws XMLStreamException {
0798: xml.setAttribute("value", ((Float) obj).floatValue());
0799: }
0800: };
0801: /**/
0802:
0803: /**
0804: * Holds the default XML representation for <code>java.lang.Double</code>.
0805: /*@JVM-1.1+@
0806: static final XMLFormat
0807: /**/
0808: /*<Double>*//*@JVM-1.1+@
0809: DOUBLE_XML = new XMLFormat(new Double(0.0).getClass()) {
0810: public boolean isReferenceable() {
0811: return false; // Always by value (immutable).
0812: }
0813:
0814: public Object newInstance(Class cls, javolution.xml.XMLFormat.InputElement xml) throws XMLStreamException {
0815: return new Double(xml.getAttribute("value", 0.0));
0816: }
0817:
0818: public void read(InputElement xml, Object obj) throws XMLStreamException {
0819: // Do nothing.
0820: }
0821:
0822: public void write(Object obj, OutputElement xml) throws XMLStreamException {
0823: xml.setAttribute("value", ((Double) obj).doubleValue());
0824: }
0825: };
0826: /**/
0827:
0828: ////////////////////////////////////////////////////////////////////////////
0829: // JAVOLUTION XML FORMAT (HERE TO AVOID LOADING XML FRAMEWORK IF NOT USED)//
0830: ////////////////////////////////////////////////////////////////////////////
0831: /**
0832: * Holds the default XML representation for Text instances.
0833: * This representation consists of a <code>"value"</code> attribute
0834: * holding the characters.
0835: */
0836: static final XMLFormat/*<Text>*/TEXT_XML = new XMLFormat(
0837: Javolution.j2meGetClass("javolution.text.Text")) {
0838:
0839: public Object newInstance(Class cls,
0840: javolution.xml.XMLFormat.InputElement xml)
0841: throws XMLStreamException {
0842: CharSequence csq = xml.getAttribute("value");
0843: return csq != null ? Text.valueOf(csq) : Text.EMPTY;
0844: }
0845:
0846: public void read(InputElement xml, Object obj)
0847: throws XMLStreamException {
0848: // Do nothing.
0849: }
0850:
0851: public void write(Object obj, OutputElement xml)
0852: throws XMLStreamException {
0853: xml.setAttribute("value", (Text) obj);
0854: }
0855: };
0856:
0857: /**
0858: * Holds the default XML representation for FastMap instances.
0859: * This representation is identical to {@link XMLBinding#MAP_XML}
0860: * except that it may include the key/value comparators for the map
0861: * (if different from {@link FastComparator#DEFAULT}) and the
0862: * {@link #isShared() "shared"} attribute.
0863: */
0864: static final XMLFormat/*<FastMap>*/FASTMAP_XML = new XMLFormat(
0865: new FastMap().getClass()) {
0866:
0867: public void read(InputElement xml, Object obj)
0868: throws XMLStreamException {
0869: final FastMap fm = (FastMap) obj;
0870: fm.setShared(xml.getAttribute("shared", false));
0871: FastComparator keyComparator = (FastComparator) xml
0872: .get("KeyComparator");
0873: if (keyComparator != null) {
0874: fm.setKeyComparator(keyComparator);
0875: }
0876: FastComparator valueComparator = (FastComparator) xml
0877: .get("ValueComparator");
0878: if (valueComparator != null) {
0879: fm.setValueComparator(valueComparator);
0880: }
0881: while (xml.hasNext()) {
0882: Object key = xml.get("Key");
0883: Object value = xml.get("Value");
0884: fm.put(key, value);
0885: }
0886: }
0887:
0888: public void write(Object obj, OutputElement xml)
0889: throws XMLStreamException {
0890: final FastMap fm = (FastMap) obj;
0891: if (fm.isShared()) {
0892: xml.setAttribute("shared", true);
0893: }
0894: if (fm.getKeyComparator() != FastComparator.DEFAULT) {
0895: xml.add(fm.getKeyComparator(), "KeyComparator");
0896: }
0897: if (fm.getValueComparator() != FastComparator.DEFAULT) {
0898: xml.add(fm.getValueComparator(), "ValueComparator");
0899: }
0900: for (Entry e = fm.head(), end = fm.tail(); (e = (Entry) e
0901: .getNext()) != end;) {
0902: xml.add(e.getKey(), "Key");
0903: xml.add(e.getValue(), "Value");
0904: }
0905: }
0906: };
0907:
0908: /**
0909: * Holds the default XML representation for FastCollection instances.
0910: * This representation is identical to {@link XMLBinding#COLLECTION_XML}.
0911: */
0912: static final XMLFormat/*<FastCollection>*/FASTCOLLECTION_XML = new XMLFormat(
0913: Javolution.j2meGetClass("javolution.util.FastCollection")) {
0914:
0915: public void read(InputElement xml, Object obj)
0916: throws XMLStreamException {
0917: FastCollection fc = (FastCollection) obj;
0918: while (xml.hasNext()) {
0919: fc.add(xml.getNext());
0920: }
0921: }
0922:
0923: public void write(Object obj, OutputElement xml)
0924: throws XMLStreamException {
0925: FastCollection fc = (FastCollection) obj;
0926: for (Record r = fc.head(), end = fc.tail(); (r = r
0927: .getNext()) != end;) {
0928: xml.add(fc.valueOf(r));
0929: }
0930: }
0931: };
0932:
0933: /**
0934: * Holds the default XML representation for FastComparator instances
0935: * (format ensures unicity of predefined comparator).
0936: */
0937: static final XMLFormat/*<FastComparator>*/FASTCOMPARATOR_XML = new XMLFormat(
0938: Javolution.j2meGetClass("javolution.util.FastComparator")) {
0939:
0940: public Object newInstance(Class cls,
0941: javolution.xml.XMLFormat.InputElement xml)
0942: throws XMLStreamException {
0943: if (cls == FastComparator.DEFAULT.getClass())
0944: return FastComparator.DEFAULT;
0945: if (cls == FastComparator.DIRECT.getClass())
0946: return FastComparator.DIRECT;
0947: if (cls == FastComparator.IDENTITY.getClass())
0948: return FastComparator.IDENTITY;
0949: if (cls == FastComparator.LEXICAL.getClass())
0950: return FastComparator.LEXICAL;
0951: if (cls == FastComparator.REHASH.getClass())
0952: return FastComparator.REHASH;
0953: if (cls == FastComparator.STRING.getClass())
0954: return FastComparator.STRING;
0955: return super .newInstance(cls, xml);
0956: }
0957:
0958: public void read(InputElement xml, Object obj)
0959: throws XMLStreamException {
0960: // Do nothing.
0961: }
0962:
0963: public void write(Object obj, OutputElement xml)
0964: throws XMLStreamException {
0965: // Do nothing.
0966: }
0967: };
0968:
0969: /**
0970: * Holds the default XML representation for indexes.
0971: * This presentation consists of a <code>"value"</code> attribute
0972: * holding the index <code>int</code> value.
0973: */
0974: static final XMLFormat/*<Index>*/INDEX_XML = new XMLFormat(
0975: Index.ZERO.getClass()) {
0976:
0977: public boolean isReferenceable() {
0978: return false; // Always by value (immutable).
0979: }
0980:
0981: public Object newInstance(Class cls, InputElement xml)
0982: throws XMLStreamException {
0983: return Index.valueOf(xml.getAttribute("value", 0));
0984: }
0985:
0986: public void read(InputElement xml, Object obj)
0987: throws XMLStreamException {
0988: // Do nothing.
0989: }
0990:
0991: public void write(Object obj, OutputElement xml)
0992: throws XMLStreamException {
0993: xml.setAttribute("value", ((Index) obj).intValue());
0994: }
0995: };
0996:
0997: /**
0998: * Holds the XML representation for persistent contexts
0999: * (holds persistent reference mapping).
1000: */
1001: static final XMLFormat/*<PersistentContext>*/PERSISTENT_CONTEXT_XML = new XMLFormat(
1002: new PersistentContext().getClass()) {
1003: public void read(InputElement xml, Object obj)
1004: throws XMLStreamException {
1005: final PersistentContext ctx = (PersistentContext) obj;
1006: ctx.getIdToValue().putAll((FastMap) xml.get("References"));
1007: }
1008:
1009: public void write(Object obj, OutputElement xml)
1010: throws XMLStreamException {
1011: final PersistentContext ctx = (PersistentContext) obj;
1012: xml.add(ctx.getIdToValue(), "References");
1013: }
1014: };
1015:
1016: private static CharSequence toCsq/**/(Object str) {
1017: return Javolution.j2meToCharSeq(str);
1018: }
1019:
1020: }
|