package iiuf.dom; import java.util.Map; import java.util.Iterator; import java.util.HashMap; import java.lang.reflect.Array; import iiuf.dom.DOMUtils; import iiuf.util.Util; import iiuf.util.Strings; import iiuf.util.NotImplementedException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; /** Manager for DOMable stuff.<p> (c) 2001, DIUF<p> @author $Author: ohitz $ @version $Name: $ $Revision: 1.1 $ */ public abstract class DOMManager { public static String ARRAY_PREFIX = "_"; public static String NULL = "null"; public static String SUPER = "super"; public static String CLASS = "class"; public static String LENGTH = "length"; public static String KEYS = "keys"; public static String VALUES = "values"; public static String VERSION = "vers."; public static Class CLS_OBJECT = Object.class; public static Class CLS_STRING = String.class; public static Class CLS_MAP = Map.class; private static Element[] ELEMENT_TMPL = new Element[0]; private static HashMap handlers = new HashMap(); public static Object fromDOM(DOMContext context, Element element, Object object) { if(element == null) throw new IllegalArgumentException("Element must not be null."); for(;;) { String clsName = element.getAttribute(CLASS); if(clsName == null || clsName.equals("")) break; Class cls = null; try {cls = Class.forName(clsName);} catch(ClassNotFoundException e) { System.out.println("Element:" + DOMUtils.toString(element)); System.out.println("Offending class: <" + clsName + ">"); Util.printStackTrace(e); return object; } if(CLS_STRING == cls) return DOMUtils.getTextValue(element); else if(CLS_MAP.isAssignableFrom(cls)) { try { Map result = (Map)cls.newInstance(); Object[] keys = (Object[])get(context, element, KEYS); Object[] values = (Object[])get(context, element, VALUES); for(int i = 0; i < keys.length; i++) result.put(keys[i], values[i]); return result; } catch(InstantiationException e) {Util.printStackTrace(e);} catch(IllegalAccessException e) {Util.printStackTrace(e);} } else if(cls.isArray()) { int len = getInt(element, LENGTH); Class cmpcls = cls.getComponentType(); Object result = Array.newInstance(cmpcls, len); if(cmpcls == Boolean.class) for(int i = 0; i < len; i++) Array.setBoolean(result, i, ((Boolean)get(context, element, ARRAY_PREFIX + i)).booleanValue()); else if(cmpcls == Byte.class) for(int i = 0; i < len; i++) Array.setByte(result, i, ((Byte)get(context, element, ARRAY_PREFIX + i)).byteValue()); else if(cmpcls == Character.class) for(int i = 0; i < len; i++) Array.setChar(result, i, ((Character)get(context, element, ARRAY_PREFIX + i)).charValue()); else if(cmpcls == Short.class) for(int i = 0; i < len; i++) Array.setShort(result, i, ((Short)get(context, element, ARRAY_PREFIX + i)).shortValue()); else if(cmpcls == Integer.class) for(int i = 0; i < len; i++) Array.setInt(result, i, ((Integer)get(context, element, ARRAY_PREFIX + i)).intValue()); else if(cmpcls == Long.class) for(int i = 0; i < len; i++) Array.setLong(result, i, ((Long)get(context, element, ARRAY_PREFIX + i)).longValue()); else if(cmpcls == Float.class) for(int i = 0; i < len; i++) Array.setFloat(result, i, ((Float)get(context, element, ARRAY_PREFIX + i)).floatValue()); else if(cmpcls == Double.class) for(int i = 0; i < len; i++) Array.setDouble(result, i, ((Double)get(context, element, ARRAY_PREFIX + i)).doubleValue()); else for(int i = 0; i < len; i++) Array.set(result, i, get(context, element, ARRAY_PREFIX + i)); return result; } else { DOMHandler handler = findHandler(cls).handler; if(handler == null) throw new IllegalArgumentException("No handler for:" + cls.getName() + ":" + object + ":" + element); object = handler.fromDOM(context, element, object); put(element, VERSION, handler.getVersion()); if(context.fBreak) { context.fBreak = false; break; } } element = DOMUtils.getFirstElement(element, SUPER); if(element == null) break; } return object; } public static int getVersion(Element element) { try {return getInt(element, VERSION);} catch(Exception e) {return -1;} } public static int getInt(Element e, String name) { try { return Integer.parseInt(e.getAttribute(name).substring(1)); } catch(NumberFormatException ex) { throw new IllegalArgumentException("Can't decode int:" + name + ":" + e.getAttribute(name)); } } public static boolean getBoolean(Element e, String name) { return (true + "").equals(e.getAttribute(name)); } public static double getDouble(Element e, String name) { try { return Double.parseDouble(e.getAttribute(name).substring(1)); } catch(NumberFormatException ex) { throw new IllegalArgumentException("Can't decode double:" + name + ":" + e.getAttribute(name)); } } public static Object get(DOMContext context, Element e, String name) { return get(context, e, name, null); } public static Object get(DOMContext context, Element e, String name, Object object) { String num = e.getAttribute(name); if(num != null && num.length() > 1) { try { switch(num.charAt(0)) { case 'B': return new Byte(num.substring(1)); case 'C': return new Character(num.charAt(1)); case 'D': return new Double(num.substring(1)); case 'F': return new Float(num.substring(1)); case 'I': return new Integer(num.substring(1)); case 'J': return new Long(num.substring(1)); case 'S': return new Short(num.substring(1)); case 'Z': return new Boolean(num.substring(1)); default: throw new IllegalArgumentException("Can't decode number:" + name + ":" + object); } } catch(NumberFormatException ex) { throw new IllegalArgumentException("Can't decode number:" + name + ":" + object); } } else { Element element = DOMUtils.getFirstElement(e, name); if(element != null) object = fromDOM(context, element, object); return object; } } public static Element[] find(Element e, Class cls) { return (Element[])DOMUtils.getElementsWithAttribute(e, CLASS, cls.getName()).toArray(ELEMENT_TMPL); } public static Element findSuper(Element e, Class cls) { Element result = DOMUtils.getFirstElement(e, SUPER); if(result == null) return null; else if(cls.getName().equals(result.getAttribute(CLASS))) return result; else return findSuper(result, cls); } public static Node toDOM(DOMContext context, String name, Object object) { Document document = context.getDocument(); if(object == null) return document.createElement(name); else { HandlerWrapper[] handlers = getHandlers(object.getClass()); if(handlers.length == 0) throw new IllegalArgumentException("Not DOMable (" + object.getClass().getName() + "):" + object); try { Element result = handlers[0].handler.toDOM(context, document.createElement(name), object); result.setAttribute(CLASS, handlers[0].cls.getName()); put(result, VERSION, handlers[0].handler.getVersion()); Element current = result; for(int i = 1; i < handlers.length; i++) { Element tmp = handlers[i].handler.toDOM(context, document.createElement(SUPER), object); tmp.setAttribute(CLASS, handlers[i].cls.getName()); put(tmp, VERSION, handlers[i].handler.getVersion()); current.appendChild(tmp); current = tmp; } return result; } catch(Exception e) { System.out.println(name + ":" + object.getClass().getName() + ":" + object); Util.printStackTrace(e); return null; } } } public static void put(Element element, String name, int value) { element.setAttribute(name, cPrefix(Integer.class) + value); } public static void put(Element element, String name, double value) { element.setAttribute(name, cPrefix(Double.class) + value); } public static void put(Element element, String name, boolean value) { element.setAttribute(name, value + ""); } private static String cPrefix(Class cls) { if(cls == Byte.class) return "B"; else if(cls == Character.class) return "C"; else if(cls == Double.class) return "D"; else if(cls == Float.class) return "F"; else if(cls == Integer.class) return "I"; else if(cls == Long.class) return "J"; else if(cls == Short.class) return "S"; else if(cls == Boolean.class) return "Z"; else return ""; } public static void put(DOMContext context, Element element, String name, Object value) { Document document = context.getDocument(); if(value instanceof Number) element.setAttribute(name, cPrefix(value.getClass()) + value.toString()); else if(value instanceof String) { Element val = document.createElement(name); val.appendChild(document.createTextNode(value.toString())); val.setAttribute(CLASS, value.getClass().getName()); element.appendChild(val); } else if(value instanceof Map) { Map map = (Map)value; Object[] keys = new Object[map.size()]; Object[] values = new Object[keys.length]; Element val = document.createElement(name); int j = 0; for(Iterator i = map.keySet().iterator(); i.hasNext();) { keys[j] = i.next(); values[j] = map.get(keys[j]); j++; } put(context, val, KEYS, keys); put(context, val, VALUES, values); val.setAttribute(CLASS, value.getClass().getName()); element.appendChild(val); } else if(value != null && value.getClass().isArray()) { Element val = document.createElement(name); val.setAttribute(CLASS, value.getClass().getName()); int len = Array.getLength(value); put(val, LENGTH, len); for(int i = 0; i < len; i++) put(context, val, ARRAY_PREFIX + i, Array.get(value, i)); element.appendChild(val); } else { Node val = DOMManager.toDOM(context, name, value); element.appendChild(val); } } public static int countHandlers(Class cls) { int result = 0; while(cls != CLS_OBJECT) { if(getHandler(cls) != null) result++; cls = cls.getSuperclass(); } return result; } private static HandlerWrapper[] getHandlers(Class cls) { HandlerWrapper[] result = new HandlerWrapper[countHandlers(cls)]; int i = 0; while(cls != CLS_OBJECT) { if(getHandler(cls) != null) { result[i] = new HandlerWrapper(getHandler(cls), cls); i++; } cls = cls.getSuperclass(); } return result; } private static HandlerWrapper findHandler(Class cls) { while(cls != CLS_OBJECT) { if(getHandler(cls) != null) return new HandlerWrapper(getHandler(cls), cls); cls = cls.getSuperclass(); } return null; } public static DOMHandler getHandler(Class cls) { return (DOMHandler)handlers.get(cls); } public static void register(Class cls, DOMHandler handler) { if(cls.isInterface()) throw new IllegalArgumentException(cls.getName() + " is an interface, only classes can be registred."); handlers.put(cls, handler); } static class HandlerWrapper { DOMHandler handler; Class cls; HandlerWrapper(DOMHandler handler_, Class cls_) { handler = handler_; cls = cls_; } public String toString() { return cls.getName(); } } } /* $Log: DOMManager.java,v $ Revision 1.1 2002/07/11 12:03:48 ohitz Initial checkin Revision 1.8 2001/04/11 19:02:07 schubige fixed connection bug and made JSliderSoundlet domable Revision 1.7 2001/03/30 17:33:28 schubige modified beat soundlet Revision 1.6 2001/03/28 21:31:18 schubige dom save and load works now (very early version) Revision 1.5 2001/03/28 18:44:33 schubige working on dom again Revision 1.4 2001/03/26 15:35:37 schubige fixed format bug Revision 1.3 2001/03/22 16:08:24 schubige more work on dom stuff Revision 1.2 2001/03/21 22:18:14 schubige working on dom stuff Revision 1.1 2001/03/21 19:37:45 schubige started with dom stuff */