1 18 19 package org.apache.tools.ant.taskdefs; 20 21 import java.io.File ; 22 import java.io.FileOutputStream ; 23 import java.io.FileWriter ; 24 import java.io.IOException ; 25 import java.io.OutputStreamWriter ; 26 import java.io.PrintWriter ; 27 import java.io.UnsupportedEncodingException ; 28 import java.util.Enumeration ; 29 import java.util.Hashtable ; 30 import java.util.Vector ; 31 import org.apache.tools.ant.BuildException; 32 import org.apache.tools.ant.IntrospectionHelper; 33 import org.apache.tools.ant.Project; 34 import org.apache.tools.ant.Task; 35 import org.apache.tools.ant.TaskContainer; 36 import org.apache.tools.ant.types.EnumeratedAttribute; 37 import org.apache.tools.ant.types.Reference; 38 39 47 public class AntStructure extends Task { 48 49 private static final String LINE_SEP 50 = System.getProperty("line.separator"); 51 52 private File output; 53 private StructurePrinter printer = new DTDPrinter(); 54 55 59 public void setOutput(File output) { 60 this.output = output; 61 } 62 63 68 public void add(StructurePrinter p) { 69 printer = p; 70 } 71 72 77 public void execute() throws BuildException { 78 79 if (output == null) { 80 throw new BuildException("output attribute is required", getLocation()); 81 } 82 83 PrintWriter out = null; 84 try { 85 try { 86 out = new PrintWriter (new OutputStreamWriter (new FileOutputStream (output), "UTF8")); 87 } catch (UnsupportedEncodingException ue) { 88 94 out = new PrintWriter (new FileWriter (output)); 95 } 96 97 printer.printHead(out, getProject(), 98 getProject().getTaskDefinitions(), 99 getProject().getDataTypeDefinitions()); 100 101 printer.printTargetDecl(out); 102 103 Enumeration dataTypes = getProject().getDataTypeDefinitions().keys(); 104 while (dataTypes.hasMoreElements()) { 105 String typeName = (String ) dataTypes.nextElement(); 106 printer.printElementDecl( 107 out, getProject(), typeName, 108 (Class ) getProject().getDataTypeDefinitions().get(typeName)); 109 } 110 111 Enumeration tasks = getProject().getTaskDefinitions().keys(); 112 while (tasks.hasMoreElements()) { 113 String tName = (String ) tasks.nextElement(); 114 printer.printElementDecl(out, getProject(), tName, 115 (Class ) getProject().getTaskDefinitions().get(tName)); 116 } 117 118 printer.printTail(out); 119 120 } catch (IOException ioe) { 121 throw new BuildException("Error writing " 122 + output.getAbsolutePath(), ioe, getLocation()); 123 } finally { 124 if (out != null) { 125 out.close(); 126 } 127 } 128 } 129 130 137 public static interface StructurePrinter { 138 147 void printHead(PrintWriter out, Project p, Hashtable tasks, 148 Hashtable types); 149 150 154 void printTargetDecl(PrintWriter out); 155 156 164 void printElementDecl(PrintWriter out, Project p, String name, 165 Class element); 166 167 171 void printTail(PrintWriter out); 172 } 173 174 private static class DTDPrinter implements StructurePrinter { 175 176 private static final String BOOLEAN = "%boolean;"; 177 private static final String TASKS = "%tasks;"; 178 private static final String TYPES = "%types;"; 179 180 private Hashtable visited = new Hashtable (); 181 182 public void printTail(PrintWriter out) { 183 visited.clear(); 184 } 185 186 public void printHead(PrintWriter out, Project p, Hashtable tasks, Hashtable types) { 187 printHead(out, tasks.keys(), types.keys()); 188 } 189 190 191 197 private void printHead(PrintWriter out, Enumeration tasks, 198 Enumeration types) { 199 out.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); 200 out.println("<!ENTITY % boolean \"(true|false|on|off|yes|no)\">"); 201 out.print("<!ENTITY % tasks \""); 202 boolean first = true; 203 while (tasks.hasMoreElements()) { 204 String tName = (String ) tasks.nextElement(); 205 if (!first) { 206 out.print(" | "); 207 } else { 208 first = false; 209 } 210 out.print(tName); 211 } 212 out.println("\">"); 213 out.print("<!ENTITY % types \""); 214 first = true; 215 while (types.hasMoreElements()) { 216 String typeName = (String ) types.nextElement(); 217 if (!first) { 218 out.print(" | "); 219 } else { 220 first = false; 221 } 222 out.print(typeName); 223 } 224 out.println("\">"); 225 226 out.println(""); 227 228 out.print("<!ELEMENT project (target | "); 229 out.print(TASKS); 230 out.print(" | "); 231 out.print(TYPES); 232 out.println(")*>"); 233 out.println("<!ATTLIST project"); 234 out.println(" name CDATA #IMPLIED"); 235 out.println(" default CDATA #IMPLIED"); 236 out.println(" basedir CDATA #IMPLIED>"); 237 out.println(""); 238 } 239 240 243 public void printTargetDecl(PrintWriter out) { 244 out.print("<!ELEMENT target ("); 245 out.print(TASKS); 246 out.print(" | "); 247 out.print(TYPES); 248 out.println(")*>"); 249 out.println(""); 250 251 out.println("<!ATTLIST target"); 252 out.println(" id ID #IMPLIED"); 253 out.println(" name CDATA #REQUIRED"); 254 out.println(" if CDATA #IMPLIED"); 255 out.println(" unless CDATA #IMPLIED"); 256 out.println(" depends CDATA #IMPLIED"); 257 out.println(" description CDATA #IMPLIED>"); 258 out.println(""); 259 } 260 261 264 public void printElementDecl(PrintWriter out, Project p, 265 String name, Class element) { 266 267 if (visited.containsKey(name)) { 268 return; 269 } 270 visited.put(name, ""); 271 272 IntrospectionHelper ih = null; 273 try { 274 ih = IntrospectionHelper.getHelper(p, element); 275 } catch (Throwable t) { 276 281 return; 282 } 283 284 StringBuffer sb = new StringBuffer ("<!ELEMENT "); 285 sb.append(name).append(" "); 286 287 if (org.apache.tools.ant.types.Reference.class.equals(element)) { 288 sb.append("EMPTY>").append(LINE_SEP); 289 sb.append("<!ATTLIST ").append(name); 290 sb.append(LINE_SEP).append(" id ID #IMPLIED"); 291 sb.append(LINE_SEP).append(" refid IDREF #IMPLIED"); 292 sb.append(">").append(LINE_SEP); 293 out.println(sb); 294 return; 295 } 296 297 Vector v = new Vector (); 298 if (ih.supportsCharacters()) { 299 v.addElement("#PCDATA"); 300 } 301 302 if (TaskContainer.class.isAssignableFrom(element)) { 303 v.addElement(TASKS); 304 } 305 306 Enumeration e = ih.getNestedElements(); 307 while (e.hasMoreElements()) { 308 v.addElement(e.nextElement()); 309 } 310 311 if (v.isEmpty()) { 312 sb.append("EMPTY"); 313 } else { 314 sb.append("("); 315 final int count = v.size(); 316 for (int i = 0; i < count; i++) { 317 if (i != 0) { 318 sb.append(" | "); 319 } 320 sb.append(v.elementAt(i)); 321 } 322 sb.append(")"); 323 if (count > 1 || !v.elementAt(0).equals("#PCDATA")) { 324 sb.append("*"); 325 } 326 } 327 sb.append(">"); 328 out.println(sb); 329 330 sb = new StringBuffer ("<!ATTLIST "); 331 sb.append(name); 332 sb.append(LINE_SEP).append(" id ID #IMPLIED"); 333 334 e = ih.getAttributes(); 335 while (e.hasMoreElements()) { 336 String attrName = (String ) e.nextElement(); 337 if ("id".equals(attrName)) { 338 continue; 339 } 340 341 sb.append(LINE_SEP).append(" ") 342 .append(attrName).append(" "); 343 Class type = ih.getAttributeType(attrName); 344 if (type.equals(java.lang.Boolean .class) 345 || type.equals(java.lang.Boolean.TYPE)) { 346 sb.append(BOOLEAN).append(" "); 347 } else if (Reference.class.isAssignableFrom(type)) { 348 sb.append("IDREF "); 349 } else if (EnumeratedAttribute.class.isAssignableFrom(type)) { 350 try { 351 EnumeratedAttribute ea = 352 (EnumeratedAttribute) type.newInstance(); 353 String [] values = ea.getValues(); 354 if (values == null 355 || values.length == 0 356 || !areNmtokens(values)) { 357 sb.append("CDATA "); 358 } else { 359 sb.append("("); 360 for (int i = 0; i < values.length; i++) { 361 if (i != 0) { 362 sb.append(" | "); 363 } 364 sb.append(values[i]); 365 } 366 sb.append(") "); 367 } 368 } catch (InstantiationException ie) { 369 sb.append("CDATA "); 370 } catch (IllegalAccessException ie) { 371 sb.append("CDATA "); 372 } 373 } else if (type.getSuperclass() != null 374 && type.getSuperclass().getName().equals("java.lang.Enum")) { 375 try { 376 Object [] values = (Object []) type.getMethod("values", (Class []) null) 377 .invoke(null, (Object []) null); 378 if (values.length == 0) { 379 sb.append("CDATA "); 380 } else { 381 sb.append('('); 382 for (int i = 0; i < values.length; i++) { 383 if (i != 0) { 384 sb.append(" | "); 385 } 386 sb.append(type.getMethod("name", (Class []) null) 387 .invoke(values[i], (Object []) null)); 388 } 389 sb.append(") "); 390 } 391 } catch (Exception x) { 392 sb.append("CDATA "); 393 } 394 } else { 395 sb.append("CDATA "); 396 } 397 sb.append("#IMPLIED"); 398 } 399 sb.append(">").append(LINE_SEP); 400 out.println(sb); 401 402 final int count = v.size(); 403 for (int i = 0; i < count; i++) { 404 String nestedName = (String ) v.elementAt(i); 405 if (!"#PCDATA".equals(nestedName) 406 && !TASKS.equals(nestedName) 407 && !TYPES.equals(nestedName)) { 408 printElementDecl(out, p, nestedName, ih.getElementType(nestedName)); 409 } 410 } 411 } 412 413 418 public static final boolean isNmtoken(String s) { 419 final int length = s.length(); 420 for (int i = 0; i < length; i++) { 421 char c = s.charAt(i); 422 if (!Character.isLetterOrDigit(c) 424 && c != '.' && c != '-' && c != '_' && c != ':') { 425 return false; 426 } 427 } 428 return true; 429 } 430 431 439 public static final boolean areNmtokens(String [] s) { 440 for (int i = 0; i < s.length; i++) { 441 if (!isNmtoken(s[i])) { 442 return false; 443 } 444 } 445 return true; 446 } 447 } 448 449 454 protected boolean isNmtoken(String s) { 455 return DTDPrinter.isNmtoken(s); 456 } 457 458 466 protected boolean areNmtokens(String [] s) { 467 return DTDPrinter.areNmtokens(s); 468 } 469 } 470 | Popular Tags |