1 9 package javolution.xml; 10 11 import java.io.IOException; 12 13 import j2me.lang.CharSequence; 14 import j2me.util.Collection; 15 import j2me.util.Iterator; 16 import j2me.util.Map; 17 18 import javolution.JavolutionError; 19 import javolution.lang.Appendable; 20 import javolution.lang.Reflection; 21 import javolution.lang.Text; 22 import javolution.lang.TypeFormat; 23 import javolution.util.FastList; 24 import javolution.util.FastMap; 25 26 114 public abstract class XmlFormat{ 115 116 119 private static final FastMap BASE_CLASS_TO_FORMAT = new FastMap(); 120 121 124 private static final FastMap CLASS_TO_FORMAT = new FastMap(); 125 126 130 private static final FastMap CLASS_TO_NAME = new FastMap(); 131 132 136 private static final FastMap NAME_TO_CLASS = new FastMap(); 137 138 141 private static final FastMap URI_LOCAL_NAME_TO_CLASS = new FastMap(); 142 143 149 protected static final Null NULL = new Null(); 150 151 157 protected static final XmlFormat OBJECT_XML = new XmlFormat() { 158 public void format(Object obj, XmlElement xml) { 159 } 161 162 public Object parse(XmlElement xml) { 163 return xml.object(); 164 } 165 }; 166 167 171 private static final XmlFormat NULL_XML = new XmlFormat(NULL.getClass()) { 172 public void format(Object obj, XmlElement xml) { 173 } 175 176 public Object parse(XmlElement xml) { 177 return null; 178 } 179 }; 180 static { 181 XmlFormat.setAlias(NULL.getClass(), "null"); 182 } 183 184 189 protected static final XmlFormat CLASS_XML = new XmlFormat( 190 "java.lang.Class") { 191 public void format(Object obj, XmlElement xml) { 192 xml.setAttribute("value", ((Class) obj).getName()); 193 } 194 195 public Object parse(XmlElement xml) { 196 try { 197 return Reflection.getClass(xml.getAttribute("name", "")); 198 } catch (ClassNotFoundException e) { 199 throw new XmlException(e); 200 } 201 } 202 }; 203 204 209 protected static final XmlFormat STRING_XML = new XmlFormat( 210 "java.lang.String") { 211 public void format(Object obj, XmlElement xml) { 212 xml.setAttribute("value", (String) obj); 213 } 214 215 public Object parse(XmlElement xml) { 216 return xml.getAttribute("value", ""); 217 } 218 }; 219 220 225 protected static final XmlFormat TEXT_XML = new XmlFormat( 226 "javolution.lang.Text") { 227 public void format(Object obj, XmlElement xml) { 228 xml.setAttribute("value", (Text) obj); 229 } 230 231 public Object parse(XmlElement xml) { 232 CharSequence csq = xml.getAttribute("value"); 233 return csq != null ? Text.valueOf(csq) : Text.EMPTY; 234 } 235 }; 236 237 242 protected static final XmlFormat APPENDABLE_XML = new XmlFormat( 243 "javolution.lang.Appendable") { 244 public void format(Object obj, XmlElement xml) { 245 xml.setAttribute("value", Text.valueOf(obj)); 246 } 247 248 public Object parse(XmlElement xml) { 249 Appendable appendable = (Appendable) xml.object(); 250 CharSequence csq = xml.getAttribute("value"); 251 try { 252 return csq != null ? appendable.append(csq) : appendable; 253 } catch (IOException e) { 254 throw new XmlException(e); 255 } 256 } 257 }; 258 259 267 protected static final XmlFormat COLLECTION_XML = new XmlFormat( 268 "j2me.util.Collection") { 269 public void format(Object obj, XmlElement xml) { 270 xml.getContent().addAll((Collection) obj); 271 } 272 273 public Object parse(XmlElement xml) { 274 Collection collection = (Collection) xml.object(); 275 collection.addAll(xml.getContent()); 276 return collection; 277 } 278 }; 279 280 287 protected static final XmlFormat MAP_XML = new XmlFormat("j2me.util.Map") { 288 289 public void format(Object obj, XmlElement xml) { 290 Map map = (Map) obj; 291 for (Iterator it = map.entrySet().iterator(); it.hasNext();) { 292 Map.Entry entry = (Map.Entry) it.next(); 293 xml.getContent().addLast(entry.getKey()); 294 xml.getContent().addLast(entry.getValue()); 295 } 296 } 297 298 public Object parse(XmlElement xml) { 299 Map map = (Map) xml.object(); 300 for (FastList.Node n = xml.getContent().headNode(), end = xml 301 .getContent().tailNode(); (n = n.getNextNode()) != end;) { 302 Object key = n.getValue(); 303 Object value = (n = n.getNextNode()).getValue(); 304 map.put(key, value); 305 } 306 return map; 307 } 308 }; 309 310 313 protected static final XmlFormat BOOLEAN_XML = new XmlFormat( 314 "java.lang.Boolean") { 315 public void format(Object obj, XmlElement xml) { 316 xml.setAttribute("value", ((Boolean) obj).booleanValue()); 317 } 318 319 public Object parse(XmlElement xml) { 320 CharSequence csq = xml.getAttribute("value"); 321 if (csq == null) 322 throw new XmlException("Missing value attribute"); 323 return new Boolean(TypeFormat.parseBoolean(csq)); 324 } 325 }; 326 327 330 protected static final XmlFormat BYTE_XML = new XmlFormat("java.lang.Byte") { 331 public void format(Object obj, XmlElement xml) { 332 xml.setAttribute("value", ((Byte) obj).byteValue()); 333 } 334 335 public Object parse(XmlElement xml) { 336 CharSequence csq = xml.getAttribute("value"); 337 if (csq == null) 338 throw new XmlException("Missing value attribute"); 339 return new Byte(TypeFormat.parseByte(csq)); 340 } 341 }; 342 343 346 protected static final XmlFormat CHARACTER_XML = new XmlFormat( 347 "java.lang.Character") { 348 public void format(Object obj, XmlElement xml) { 349 xml.setAttribute("value", Text.valueOf(((Character) obj) 350 .charValue())); 351 } 352 353 public Object parse(XmlElement xml) { 354 CharSequence csq = xml.getAttribute("value"); 355 if ((csq == null) || (csq.length() != 1)) 356 throw new XmlException("Missing or invalid value attribute"); 357 return new Character(csq.charAt(0)); 358 } 359 }; 360 361 364 protected static final XmlFormat INTEGER_XML = new XmlFormat( 365 "java.lang.Integer") { 366 public void format(Object obj, XmlElement xml) { 367 xml.setAttribute("value", ((Integer) obj).intValue()); 368 } 369 370 public Object parse(XmlElement xml) { 371 CharSequence csq = xml.getAttribute("value"); 372 if (csq == null) 373 throw new XmlException("Missing value attribute"); 374 return new Integer(TypeFormat.parseInt(csq)); 375 } 376 }; 377 378 381 protected static final XmlFormat LONG_XML = new XmlFormat("java.lang.Long") { 382 public void format(Object obj, XmlElement xml) { 383 xml.setAttribute("value", ((Long) obj).longValue()); 384 } 385 386 public Object parse(XmlElement xml) { 387 CharSequence csq = xml.getAttribute("value"); 388 if (csq == null) 389 throw new XmlException("Missing value attribute"); 390 return new Long(TypeFormat.parseLong(csq)); 391 } 392 }; 393 394 397 protected static final XmlFormat SHORT_XML = new XmlFormat("java.lang.Short") { 398 public void format(Object obj, XmlElement xml) { 399 xml.setAttribute("value", ((Short) obj).shortValue()); 400 } 401 402 public Object parse(XmlElement xml) { 403 CharSequence csq = xml.getAttribute("value"); 404 if (csq == null) 405 throw new XmlException("Missing value attribute"); 406 return new Short(TypeFormat.parseShort(csq)); 407 } 408 }; 409 410 426 427 443 444 447 private Class _mappedClass; 448 449 452 private XmlFormat _super; 453 454 457 final Text _idName; 458 459 462 final Text _idRef; 463 464 467 protected XmlFormat() { 468 _idName = null; 469 _idRef = null; 470 } 471 472 480 protected XmlFormat(Class clazz) { 481 mapTo(clazz); 482 _idName = _super._idName; 483 _idRef = _super._idRef; 484 } 485 486 496 protected XmlFormat(Class clazz, String idName, String idRef) { 497 mapTo(clazz); 498 _idName = (idName != null) ? Text.valueOf(idName) : null; 499 _idRef = (idRef != null) ? Text.valueOf(idRef) : null; 500 } 501 502 511 protected XmlFormat(String className) { 512 try { 513 mapTo(Reflection.getClass(className)); 514 } catch (ClassNotFoundException e) { 515 throw new JavolutionError(e); 516 } 517 _idName = _super._idName; 518 _idRef = _super._idRef; 519 } 520 521 private void mapTo(Class clazz) { 522 _mappedClass = clazz; 523 synchronized (BASE_CLASS_TO_FORMAT) { 524 if (BASE_CLASS_TO_FORMAT.containsKey(clazz)) { 525 throw new IllegalArgumentException( 526 "Mapping already exists for " + clazz); 527 } 528 _super = XmlFormat.getInstance(clazz); 529 BASE_CLASS_TO_FORMAT.put(clazz, this); 530 invalidateClassToFormatMapping(); 531 } 532 } 533 534 541 public static void setInstance(XmlFormat xmlFormat, Class forClass) { 542 xmlFormat._mappedClass = forClass; 543 synchronized (BASE_CLASS_TO_FORMAT) { 544 xmlFormat._super = XmlFormat.getInstance(forClass); 545 BASE_CLASS_TO_FORMAT.put(forClass, xmlFormat); 546 invalidateClassToFormatMapping(); 547 } 548 } 549 550 563 public static XmlFormat getInstance(Class mappedClass) { 564 565 Object obj = CLASS_TO_FORMAT.get(mappedClass); 567 if (obj != null) 568 return (XmlFormat) obj; 569 570 try { 572 Reflection.getClass(mappedClass.getName()); 573 } catch (ClassNotFoundException e) { 574 } 576 Class bestMatchClass = null; 577 XmlFormat bestMatchFormat = null; 578 for (FastMap.Entry e = BASE_CLASS_TO_FORMAT.headEntry(), end = BASE_CLASS_TO_FORMAT 580 .tailEntry(); (e = e.getNextEntry()) != end;) { 581 Class clazz = (Class) e.getKey(); 582 if (clazz.isAssignableFrom(mappedClass)) { if ((bestMatchClass == null) 584 || (bestMatchClass.isAssignableFrom(clazz))) { 585 XmlFormat xmlFormat = (XmlFormat) BASE_CLASS_TO_FORMAT 587 .get(clazz); 588 if (xmlFormat != null) { 589 bestMatchClass = clazz; 590 bestMatchFormat = xmlFormat; 591 } 592 } 593 } 594 } 595 596 if (bestMatchFormat == null) { 598 bestMatchFormat = OBJECT_XML; 599 } 600 synchronized (CLASS_TO_FORMAT) { 602 CLASS_TO_FORMAT.put(mappedClass, bestMatchFormat); 603 } 604 return (XmlFormat) bestMatchFormat; 605 606 } 607 608 621 public static void setAlias(Class forClass, String alias) { 622 synchronized (CLASS_TO_NAME) { 623 CLASS_TO_NAME.put(forClass, alias); 624 NAME_TO_CLASS.put(alias, forClass); 625 } 626 } 627 628 636 static String nameFor(Class clazz) { 637 String name = (String) CLASS_TO_NAME.get(clazz); 638 if (name == null) { 639 name = clazz.getName(); 640 synchronized (CLASS_TO_NAME) { 641 CLASS_TO_NAME.put(clazz, name); 642 NAME_TO_CLASS.put(name, clazz); 643 } 644 } 645 return name; 646 } 647 648 655 static Class classFor(Object uri, CharSequence localName) { 656 FastList list = (FastList) URI_LOCAL_NAME_TO_CLASS.get(localName); 658 if (list != null) { 659 for (int i=1; i < list.size(); i += 2) { 660 if (uri.equals(list.get(i))) { 661 return (Class) list.get(i-1); 662 } 663 } 664 } 665 String uriAsString = uri.toString(); 667 String localNameAsString = localName.toString(); 668 String className; 669 if ((uriAsString.length() == 0) || uriAsString.equals("http://javolution.org")) { 670 className = localNameAsString; } else { if (uriAsString.startsWith("java:")) { 673 className = (uriAsString.length() > 5) ? uriAsString.substring(5) + "." 674 + localNameAsString : localNameAsString; 675 } else { 676 throw new XmlException("Invalid URI (must use a java scheme)"); 677 } 678 } 679 680 Class clazz = (Class) NAME_TO_CLASS.get(className); 682 if (clazz == null) { 683 try { 684 clazz = Reflection.getClass(className); 685 } catch (ClassNotFoundException e) { 686 throw new XmlException(e); 687 } 688 synchronized (CLASS_TO_NAME) { 689 CLASS_TO_NAME.put(clazz, className); 690 NAME_TO_CLASS.put(className, clazz); 691 } 692 } 693 694 synchronized (URI_LOCAL_NAME_TO_CLASS) { 696 list = (FastList) URI_LOCAL_NAME_TO_CLASS.get(localNameAsString); 697 if (list == null) { 698 list = (FastList) FastList.newInstance().moveHeap(); 699 URI_LOCAL_NAME_TO_CLASS.put(localNameAsString, list); 700 } 701 list.addLast(clazz); 702 list.addLast(uriAsString); 703 } 704 return clazz; 705 } 706 707 712 private static void invalidateClassToFormatMapping() { 713 synchronized (CLASS_TO_FORMAT) { 714 for (FastMap.Entry e = CLASS_TO_FORMAT.headEntry(), end = CLASS_TO_FORMAT 715 .tailEntry(); (e = e.getNextEntry()) != end;) { 716 e.setValue(null); 717 } 718 } 719 } 720 721 726 public final XmlFormat getSuper() { 727 return (XmlFormat) _super; 728 } 729 730 739 public Objectpreallocate(XmlElement xml) { 740 return (_super != null) ? (Object)_super.preallocate(xml) : null; 741 } 742 743 744 772 public Class classFor(CharSequence elementName) { 773 return (_super != null) ? _super.classFor(elementName) : null; 774 } 775 776 782 public abstract void format(Objectobj, XmlElement xml); 783 784 793 public abstract Objectparse(XmlElement xml); 794 795 798 private static class Null { 799 }; 800 } | Popular Tags |