1 6 package fr.jayasoft.ivy.util; 7 8 import java.lang.reflect.InvocationTargetException ; 9 import java.lang.reflect.Method ; 10 import java.util.ArrayList ; 11 import java.util.Arrays ; 12 import java.util.Collections ; 13 import java.util.HashMap ; 14 import java.util.Iterator ; 15 import java.util.LinkedHashMap ; 16 import java.util.List ; 17 import java.util.Map ; 18 import java.util.Stack ; 19 20 44 public class Configurator { 45 public static class Macro { 46 private MacroDef _macrodef; 47 private Map _attValues = new HashMap (); 48 private Map _macroRecords = new HashMap (); 49 50 public Macro(MacroDef def) { 51 _macrodef = def; 52 } 53 54 public void defineAttribute(String attributeName, String value) { 55 if (_macrodef.getAttribute(attributeName) == null) { 56 throw new IllegalArgumentException ("undeclared attribute "+attributeName+" on macro "+_macrodef.getName()); 57 } 58 _attValues.put(attributeName, value); 59 } 60 61 public MacroRecord recordCreateChild(String name) { 62 MacroRecord macroRecord = new MacroRecord(name); 63 List records = (List )_macroRecords.get(name); 64 if (records == null) { 65 records = new ArrayList (); 66 _macroRecords.put(name, records); 67 } 68 records.add(macroRecord); 69 return macroRecord; 70 } 71 72 public Object play(Configurator conf) { 73 return _macrodef.play(conf, _attValues, _macroRecords); 74 } 75 76 } 77 78 public static class Attribute { 79 private String _name; 80 private String _default; 81 82 public String getDefault() { 83 return _default; 84 } 85 public void setDefault(String default1) { 86 _default = default1; 87 } 88 public String getName() { 89 return _name; 90 } 91 public void setName(String name) { 92 _name = name; 93 } 94 } 95 96 public static class Element { 97 private String _name; 98 private boolean _optional = false; 99 public String getName() { 100 return _name; 101 } 102 public void setName(String name) { 103 _name = name; 104 } 105 public boolean isOptional() { 106 return _optional; 107 } 108 public void setOptional(boolean optional) { 109 _optional = optional; 110 } 111 } 112 113 public static class MacroRecord { 114 private String _name; 115 private Map _attributes = new LinkedHashMap (); 116 private List _children = new ArrayList (); 117 public MacroRecord(String name) { 118 _name = name; 119 } 120 public String getName() { 121 return _name; 122 } 123 public void recordAttribute(String name, String value) { 124 _attributes.put(name, value); 125 } 126 public MacroRecord recordChild(String name) { 127 MacroRecord child = new MacroRecord(name); 128 _children.add(child); 129 return child; 130 } 131 public Map getAttributes() { 132 return _attributes; 133 } 134 public List getChildren() { 135 return _children; 136 } 137 } 138 139 public static class MacroDef { 140 private String _name; 141 private Map _attributes = new HashMap (); 142 private Map _elements = new HashMap (); 143 private MacroRecord _macroRecord; 144 145 public MacroDef(String macroName) { 146 _name = macroName; 147 } 148 149 public Attribute getAttribute(String attributeName) { 150 return (Attribute)_attributes.get(attributeName); 151 } 152 153 public Object play(Configurator conf, Map attValues, Map macroRecords) { 154 for (Iterator iter = _attributes.values().iterator(); iter.hasNext();) { 155 Attribute att = (Attribute)iter.next(); 156 String val = (String )attValues.get(att.getName()); 157 if (val == null) { 158 if (att.getDefault() == null) { 159 throw new IllegalArgumentException ("attribute "+att.getName()+" is required in "+getName()); 160 } else { 161 attValues.put(att.getName(), att.getDefault()); 162 } 163 } 164 } 165 return play(conf, _macroRecord, attValues, macroRecords); 166 } 167 168 private Object play(Configurator conf, MacroRecord macroRecord, Map attValues, Map childrenRecords) { 169 conf.startCreateChild(macroRecord.getName()); 170 Map attributes = macroRecord.getAttributes(); 171 for (Iterator iter = attributes.keySet().iterator(); iter.hasNext();) { 172 String attName = (String )iter.next(); 173 String attValue = replaceParam((String )attributes.get(attName), attValues); 174 conf.setAttribute(attName, attValue); 175 } 176 for (Iterator iter = macroRecord.getChildren().iterator(); iter.hasNext();) { 177 MacroRecord child = (MacroRecord)iter.next(); 178 Element elt = (Element)_elements.get(child.getName()); 179 if (elt != null) { 180 List elements = (List )childrenRecords.get(child.getName()); 181 if (elements != null) { 182 for (Iterator iterator = elements.iterator(); iterator.hasNext();) { 183 MacroRecord element = (MacroRecord)iterator.next(); 184 for (Iterator it2 = element.getChildren().iterator(); it2.hasNext();) { 185 MacroRecord r = (MacroRecord)it2.next(); 186 play(conf, r, attValues, Collections.EMPTY_MAP); 187 } 188 } 189 } else if (!elt.isOptional()) { 190 throw new IllegalArgumentException ("non optional element is not specified: "+elt.getName()+" in macro "+getName()); 191 } 192 continue; 193 } 194 play(conf, child, attValues, childrenRecords); 195 } 196 return conf.endCreateChild(); 197 } 198 199 private String replaceParam(String string, Map attValues) { 200 return IvyPatternHelper.substituteParams(string, attValues); 201 } 202 203 public String getName() { 204 return _name; 205 } 206 207 public void addConfiguredAttribute(Attribute att) { 208 _attributes.put(att.getName(), att); 209 } 210 211 public void addConfiguredElement(Element elt) { 212 _elements.put(elt.getName(), elt); 213 } 214 215 public Macro createMacro() { 216 return new Macro(this); 217 } 218 219 public void addAttribute(String attName, String attDefaultValue) { 220 Attribute att = new Attribute(); 221 att.setName(attName); 222 att.setDefault(attDefaultValue); 223 addConfiguredAttribute(att); 224 } 225 226 public void addElement(String elementName, boolean optional) { 227 Element elt = new Element(); 228 elt.setName(elementName); 229 elt.setOptional(optional); 230 addConfiguredElement(elt); 231 } 232 233 public MacroRecord recordCreateChild(String name) { 234 _macroRecord = new MacroRecord(name); 235 return _macroRecord; 236 } 237 } 238 239 private static class ObjectDescriptor { 240 private Object _obj; 241 private String _objName; 242 private Map _createMethods = new HashMap (); 243 private Map _addMethods = new HashMap (); 244 private Map _addConfiguredMethods = new HashMap (); 245 private Map _setMethods = new HashMap (); 246 private Map _typeAddMethods = new HashMap (); 247 private Map _typeAddConfiguredMethods = new HashMap (); 248 249 public ObjectDescriptor(Object object, String objName) { 250 _obj = object; 251 _objName = objName; 252 Method [] methods = object.getClass().getMethods(); 253 for (int i = 0; i < methods.length; i++) { 254 Method m = methods[i]; 255 if (m.getName().startsWith("create") 256 && m.getParameterTypes().length == 0 257 && !Void.TYPE.equals(m.getReturnType())) { 258 String name = StringUtils.uncapitalize(m.getName().substring("create".length())); 259 if (name.length() == 0) { 260 continue; 261 } 262 addCreateMethod(name, m); 263 } else if (m.getName().startsWith("addConfigured") 264 && m.getParameterTypes().length == 1 265 && Void.TYPE.equals(m.getReturnType())) { 266 String name = StringUtils.uncapitalize(m.getName().substring("addConfigured".length())); 267 if (name.length() == 0) { 268 addAddConfiguredMethod(m); 269 } 270 addAddConfiguredMethod(name, m); 271 } else if (m.getName().startsWith("add") 272 && !m.getName().startsWith("addConfigured") 273 && m.getParameterTypes().length == 1 274 && Void.TYPE.equals(m.getReturnType())) { 275 String name = StringUtils.uncapitalize(m.getName().substring("add".length())); 276 if (name.length() == 0) { 277 addAddMethod(m); 278 } 279 addAddMethod(name, m); 280 } else if (m.getName().startsWith("set") 281 && m.getParameterTypes().length == 1 282 && Void.TYPE.equals(m.getReturnType())) { 283 String name = StringUtils.uncapitalize(m.getName().substring("set".length())); 284 if (name.length() == 0) { 285 continue; 286 } 287 addSetMethod(name, m); 288 } 289 } 290 } 291 public void addCreateMethod(String name, Method m) { 292 _createMethods.put(name, m); 293 } 294 public void addAddMethod(String name, Method m) { 295 _addMethods.put(name, m); 296 } 297 public void addAddConfiguredMethod(String name, Method m) { 298 _addConfiguredMethods.put(name, m); 299 } 300 private void addAddMethod(Method m) { 301 _typeAddMethods.put(m.getParameterTypes()[0], m); 302 } 303 private void addAddConfiguredMethod(Method m) { 304 _typeAddConfiguredMethods.put(m.getParameterTypes()[0], m); 305 } 306 public void addSetMethod(String name, Method m) { 307 _setMethods.put(name, m); 308 } 309 public Object getObject() { 310 return _obj; 311 } 312 public Method getCreateMethod(String name) { 313 return (Method )_createMethods.get(name); 314 } 315 public Method getAddMethod(String name) { 316 return (Method )_addMethods.get(name); 317 } 318 public Method getAddConfiguredMethod(String name) { 319 return (Method )_addConfiguredMethods.get(name); 320 } 321 public Method getAddMethod(Class type) { 322 return getTypeMatchingMethod(type, _typeAddMethods); 323 } 324 public Method getAddConfiguredMethod(Class type) { 325 return getTypeMatchingMethod(type, _typeAddConfiguredMethods); 326 } 327 private Method getTypeMatchingMethod(Class type, Map typeMethods) { 328 Method m = (Method )typeMethods.get(type); 329 if (m != null) { 330 return m; 331 } 332 for (Iterator iter = typeMethods.keySet().iterator(); iter.hasNext();) { 333 Class clss = (Class )iter.next(); 334 if (clss.isAssignableFrom(type)) { 335 return (Method )typeMethods.get(clss); 336 } 337 } 338 return null; 339 } 340 public Method getSetMethod(String name) { 341 return (Method )_setMethods.get(name); 342 } 343 public String getObjectName() { 344 return _objName; 345 } 346 } 347 348 private Map _typedefs = new HashMap (); 349 private Map _macrodefs = new HashMap (); 350 351 private Stack _objectStack = new Stack (); 353 354 355 private static final List TRUE_VALUES = Arrays.asList(new String [] {"true", "yes", "on"}); 356 357 public void typeDef(String name, String className) throws ClassNotFoundException { 358 typeDef(name, Class.forName(className)); 359 } 360 361 public void typeDef(String name, Class clazz) { 362 _typedefs.put(name, clazz); 363 } 364 365 public void setRoot(Object root) { 366 if (root == null) { 367 throw new NullPointerException (); 368 } 369 _objectStack.clear(); 370 setCurrent(root, null); 371 } 372 373 public void clear() { 374 _objectStack.clear(); 375 } 376 377 private void setCurrent(Object object, String name) { 378 _objectStack.push(new ObjectDescriptor(object, name)); 379 } 380 381 public Object startCreateChild(String name) { 382 if (_objectStack.isEmpty()) { 383 throw new IllegalStateException ("set root before creating child"); 384 } 385 ObjectDescriptor parentOD = (ObjectDescriptor)_objectStack.peek(); 386 Object parent = parentOD.getObject(); 387 if (parent instanceof MacroDef) { 388 if (!"attribute".equals(name) && !"element".equals(name)) { 389 MacroRecord record = ((MacroDef)parent).recordCreateChild(name); 390 setCurrent(record, name); 391 return record; 392 } 393 } 394 if (parent instanceof Macro) { 395 MacroRecord record = ((Macro)parent).recordCreateChild(name); 396 setCurrent(record, name); 397 return record; 398 } 399 if (parent instanceof MacroRecord) { 400 MacroRecord record = ((MacroRecord)parent).recordChild(name); 401 setCurrent(record, name); 402 return record; 403 } 404 Object child = null; 405 MacroDef macrodef = (MacroDef)_macrodefs.get(name); 406 if (macrodef != null) { 407 Macro macro = macrodef.createMacro(); 408 setCurrent(macro, name); 409 return macro; 410 } 411 Class childClass = (Class )_typedefs.get(name); 412 Method addChild = null; 413 try { 414 if (childClass != null) { 415 return addChild(parentOD, childClass, name, null); 416 } else { 417 addChild = parentOD.getCreateMethod(name); 418 if (addChild != null) { 419 child = addChild.invoke(parent, new Object [0]); 420 setCurrent(child, name); 421 return child; 422 } 423 addChild = parentOD.getAddMethod(name); 424 if (addChild != null) { 425 childClass = addChild.getParameterTypes()[0]; 426 child = childClass.newInstance(); 427 addChild.invoke(parent, new Object [] {child}); 428 setCurrent(child, name); 429 return child; 430 } 431 addChild = parentOD.getAddConfiguredMethod(name); 432 if (addChild != null) { 433 childClass = addChild.getParameterTypes()[0]; 434 child = childClass.newInstance(); 435 setCurrent(child, name); 436 return child; 437 } 438 } 439 } catch (InstantiationException ex) { 440 throw new IllegalArgumentException ("no default constructor on "+childClass+" for adding "+name+" on "+parent.getClass()); 441 } catch (Exception ex) { 442 IllegalArgumentException iae = new IllegalArgumentException ("bad method found for "+name+" on "+parent.getClass()); 443 iae.initCause(ex); 444 throw iae; 445 } 446 throw new IllegalArgumentException ("no appropriate method found for adding "+name+" on "+parent.getClass()); 447 } 448 449 public void addChild(String name, Object child) { 450 if (_objectStack.isEmpty()) { 451 throw new IllegalStateException ("set root before creating child"); 452 } 453 ObjectDescriptor parentOD = (ObjectDescriptor)_objectStack.peek(); 454 try { 455 addChild(parentOD, child.getClass(), name, child); 456 } catch (InstantiationException ex) { 457 throw new IllegalArgumentException ("no default constructor on "+child.getClass()+" for adding "+name+" on "+parentOD.getObject().getClass()); 458 } catch (Exception ex) { 459 IllegalArgumentException iae = new IllegalArgumentException ("bad method found for "+name+" on "+parentOD.getObject().getClass()); 460 iae.initCause(ex); 461 throw iae; 462 } 463 } 464 465 private Object addChild(ObjectDescriptor parentOD, Class childClass, String name, Object child) throws InstantiationException , IllegalAccessException , InvocationTargetException { 466 Object parent = parentOD.getObject(); 467 Method addChild; 468 addChild = parentOD.getAddMethod(childClass); 469 if (addChild != null) { 470 if (child == null) { 471 child = childClass.newInstance(); 472 } 473 addChild.invoke(parent, new Object [] {child}); 474 setCurrent(child, name); 475 return child; 476 } 477 addChild = parentOD.getAddConfiguredMethod(childClass); 478 if (addChild != null) { 479 if (child == null) { 480 child = childClass.newInstance(); 481 } 482 setCurrent(child, name); 483 return child; 484 } 485 throw new IllegalArgumentException ("no appropriate method found for adding "+name+" on "+parent.getClass()); 486 } 487 488 public boolean isTopLevelMacroRecord() { 489 if (_objectStack.isEmpty()) { 490 return false; 491 } 492 ObjectDescriptor od = (ObjectDescriptor)_objectStack.peek(); 493 return (od.getObject() instanceof MacroDef); 494 } 495 496 public void setAttribute(String attributeName, String value) { 497 if (_objectStack.isEmpty()) { 498 throw new IllegalStateException ("set root before setting attribute"); 499 } 500 ObjectDescriptor od = (ObjectDescriptor)_objectStack.peek(); 501 if (od.getObject() instanceof Macro) { 502 ((Macro)od.getObject()).defineAttribute(attributeName, value); 503 return; 504 } 505 if (od.getObject() instanceof MacroRecord) { 506 ((MacroRecord)od.getObject()).recordAttribute(attributeName, value); 507 return; 508 } 509 Method m = od.getSetMethod(attributeName); 510 if (m == null) { 511 throw new IllegalArgumentException ("no set method found for "+attributeName+" on "+od.getObject().getClass()); 512 } 513 Object convertedValue = null; 514 Class paramClass = m.getParameterTypes()[0]; 515 try { 516 if (paramClass.equals(String .class)) { 517 convertedValue = value; 518 } else if (paramClass.equals(Boolean .class) || paramClass.equals(boolean.class)) { 519 convertedValue = Boolean.valueOf(TRUE_VALUES.contains(value)); 520 } else if (paramClass.equals(Character .class) || paramClass.equals(char.class)) { 521 convertedValue = new Character (value.length() > 0 ? value.charAt(0) : ' '); 522 } else if (paramClass.equals(Short .class) || paramClass.equals(short.class)) { 523 convertedValue = Short.valueOf(value); 524 } else if (paramClass.equals(Integer .class) || paramClass.equals(int.class)) { 525 convertedValue = Integer.valueOf(value); 526 } else if (paramClass.equals(Long .class) || paramClass.equals(long.class)) { 527 convertedValue = Long.valueOf(value); 528 } else if (paramClass.equals(Class .class)) { 529 convertedValue = Class.forName(value); 530 } else { 531 convertedValue = paramClass.getConstructor(new Class [] {String .class}).newInstance(new Object [] {value}); 532 } 533 } catch (Exception ex) { 534 IllegalArgumentException iae = new IllegalArgumentException ("impossible to convert "+value+" to "+paramClass+" for setting "+attributeName+" on "+od.getObject().getClass()); 535 iae.initCause(ex); 536 throw iae; 537 } 538 try { 539 m.invoke(od.getObject(), new Object [] {convertedValue}); 540 } catch (Exception ex) { 541 IllegalArgumentException iae = new IllegalArgumentException ("impossible to set "+attributeName+" to "+convertedValue+" on "+od.getObject().getClass()); 542 iae.initCause(ex); 543 throw iae; 544 } 545 } 546 547 public void addText(String text) { 548 if (_objectStack.isEmpty()) { 549 throw new IllegalStateException ("set root before adding text"); 550 } 551 ObjectDescriptor od = (ObjectDescriptor)_objectStack.peek(); 552 try { 553 od.getObject().getClass().getMethod("addText", new Class [] {String .class}).invoke(od.getObject(), new Object [] {text}); 554 } catch (Exception ex) { 555 IllegalArgumentException iae = new IllegalArgumentException ("impossible to add text on "+od.getObject().getClass()); 556 iae.initCause(ex); 557 throw iae; 558 } 559 } 560 561 565 public Object endCreateChild() { 566 if (_objectStack.isEmpty()) { 567 throw new IllegalStateException ("set root before ending child"); 568 } 569 ObjectDescriptor od = (ObjectDescriptor)_objectStack.pop(); 570 if (_objectStack.isEmpty()) { 571 _objectStack.push(od); throw new IllegalStateException ("cannot end root"); 573 } 574 if (od.getObject() instanceof Macro) { 575 return ((Macro)od.getObject()).play(this); 576 } 577 ObjectDescriptor parentOD = (ObjectDescriptor)_objectStack.peek(); 578 String name = od.getObjectName(); 579 Class childClass = (Class )_typedefs.get(name); 580 Method m = null; 581 if (childClass != null) { 582 m = parentOD.getAddConfiguredMethod(childClass); 583 } else { 584 m = parentOD.getAddConfiguredMethod(name); 585 } 586 try { 587 if (m != null) { 588 m.invoke(parentOD.getObject(), new Object [] {od.getObject()}); 589 } 590 return od.getObject(); 591 } catch (Exception ex) { 592 IllegalArgumentException iae = new IllegalArgumentException ("impossible to add configured child for "+name+" on "+parentOD.getObject().getClass()); 593 iae.initCause(ex); 594 throw iae; 595 } 596 } 597 598 public Object getCurrent() { 599 return _objectStack.isEmpty()?null:((ObjectDescriptor)_objectStack.peek()).getObject(); 600 } 601 602 public int getDepth() { 603 return _objectStack.size(); 604 } 605 606 public MacroDef startMacroDef(String macroName) { 607 MacroDef macroDef = new MacroDef(macroName); 608 setCurrent(macroDef, macroName); 609 return macroDef; 610 } 611 612 public void addMacroAttribute(String attName, String attDefaultValue) { 613 ((MacroDef)getCurrent()).addAttribute(attName, attDefaultValue); 614 } 615 616 public void addMacroElement(String elementName, boolean optional) { 617 ((MacroDef)getCurrent()).addElement(elementName, optional); 618 } 619 620 public void endMacroDef() { 621 addConfiguredMacrodef(((MacroDef)getCurrent())); 622 _objectStack.pop(); 623 } 624 625 public void addConfiguredMacrodef(MacroDef macrodef) { 626 _macrodefs.put(macrodef.getName(), macrodef); 627 } 628 629 public Class getTypeDef(String name) { 630 return (Class )_typedefs.get(name); 631 } 632 } 633 | Popular Tags |