1 23 24 package org.enhydra.xml.xmlc.dom.generic; 25 26 import org.enhydra.xml.xmlc.XMLCError; 27 import org.enhydra.xml.xmlc.XMLCException; 28 import org.enhydra.xml.xmlc.codegen.JavaClass; 29 import org.enhydra.xml.xmlc.codegen.JavaCode; 30 import org.enhydra.xml.xmlc.codegen.JavaMethod; 31 import org.enhydra.xml.xmlc.codegen.JavaModifiers; 32 import org.enhydra.xml.xmlc.codegen.JavaParameter; 33 import org.enhydra.xml.xmlc.codegen.VarNames; 34 import org.enhydra.xml.xmlc.compiler.ElementInfo; 35 import org.enhydra.xml.xmlc.compiler.ElementTable; 36 import org.enhydra.xml.xmlc.dom.AccessorGenerator; 37 import org.w3c.dom.Attr ; 38 import org.w3c.dom.Document ; 39 import org.w3c.dom.DocumentType ; 40 import org.w3c.dom.Element ; 41 import org.w3c.dom.Entity ; 42 import org.w3c.dom.NamedNodeMap ; 43 import org.w3c.dom.Node ; 44 import org.w3c.dom.Notation ; 45 46 48 58 public class DOMBuilderGenerator { 59 60 private static final boolean COST_DEBUG = false; 61 62 63 protected static final String PARENT_NODE_ARG = "parentNode"; 64 65 69 protected static final String DOCUMENT_ARG = "document"; 70 71 72 protected static final String DOCUMENT_TYPE_VAR = "docType"; 73 74 75 private int fMaxCreateCostPerBuildMethod; 76 77 81 private String fDocumentArgClassName; 82 83 84 private String fMethodName; 85 86 87 private Document fDocument; 88 89 90 private NodeCreateGenerator fNodeCreator; 91 92 93 private ElementTable fElementTable; 94 95 99 private BuildMethodMappings fBuildMethodMappings; 100 101 102 private JavaClass fDocClass; 103 104 108 private AccessorGenerator fAccessorGenerator; 109 110 113 private boolean fStaticMethods; 114 115 136 private class BuildMethodGenerator { 137 138 private VarNames fNodeVarNames = new VarNames("Node", "$node"); 139 140 141 private VarNames fElementVarNames = new VarNames("Element", "$elem"); 142 143 144 private VarNames fAttrVarNames = new VarNames("Attr", "$attr"); 145 146 147 private boolean fReferencedDocElement; 148 149 150 private JavaMethod fMethod; 151 152 153 private JavaCode fBody; 154 155 156 private int fNextSubMethodId; 157 158 159 private int fChainLevel; 160 161 162 private int fMethodCost; 163 164 171 public BuildMethodGenerator(String methodName, 172 Node root) throws XMLCException { 173 String type; 175 JavaParameter[] params; 176 if (root.getNodeType() == Node.DOCUMENT_NODE) { 177 type = root.getClass().getName(); 178 params = new JavaParameter[0]; 179 } else { 180 type = "void"; 181 JavaParameter docArg 182 = new JavaParameter(DOCUMENT_ARG, 183 fDocumentArgClassName, 184 (String )null); 185 JavaParameter parentArg 186 = new JavaParameter(PARENT_NODE_ARG, 187 Node .class.getName(), 188 (String )null); 189 params = new JavaParameter[]{docArg, parentArg}; 190 } 191 fMethod = new JavaMethod(methodName, type, 192 (JavaModifiers.PRIVATE | (fStaticMethods ? JavaModifiers.STATIC : 0)), 193 params, new String [] {"Create a subtree of the document."}); 194 fDocClass.addMethod(fMethod); 195 fBody = fMethod.getCode(); 196 } 197 198 202 public void createMethodCall(String docVar, 203 String parentVar, 204 JavaCode body) { 205 body.addln(fMethod.getName() + "(" + docVar + ", " 206 + parentVar + ");"); 207 } 208 209 215 public void createMethod(Document document) throws XMLCException { 216 if (COST_DEBUG) { 217 fBody.addln("// " +fBuildMethodMappings.toString(document)); 218 } 219 220 fNodeCreator.genDocumentCreate(document, DOCUMENT_ARG, 223 DOCUMENT_TYPE_VAR, fBody); 224 fMethodCost += fBuildMethodMappings.getNodeTypeCost(document); 225 226 processChildren(DOCUMENT_ARG, document, 1); 228 229 DocumentType docType = document.getDoctype(); 231 if (docType != null) { 232 processDocumentType(DOCUMENT_TYPE_VAR, docType, 1); 233 } 234 235 fBody.addln("return " + DOCUMENT_ARG + ";"); 236 createVariables(); 237 238 if (fMethodCost > fMaxCreateCostPerBuildMethod) { 239 throw new XMLCError("BUG: maximum number of nodes per method exceeded"); 240 } 241 } 242 243 249 public void createMethod(Node parent, 250 Node root) throws XMLCException { 251 processNode(PARENT_NODE_ARG, parent, root, 0); 252 createVariables(); 253 254 if (fMethodCost > fMaxCreateCostPerBuildMethod) { 255 throw new XMLCError("BUG: maximum number of nodes per method exceeded"); 256 } 257 } 258 259 265 private void createChainedChildrenMethod(int chainLevel, 266 String parentVar, 267 Node parent, 268 Node nextChild, 269 String docVar, 270 JavaCode body) throws XMLCException { 271 fChainLevel = chainLevel; 272 body.addln(fMethod.getName() + "(" + docVar + ", " + parentVar + ");"); 273 processChildrenChaining(PARENT_NODE_ARG, parent, nextChild, 0); 274 createVariables(); 275 } 276 277 282 private String getNodeVarName(Node node, 283 int level) { 284 if (node instanceof Element ) { 285 return fElementVarNames.getVarName(level); 286 } else { 287 return fNodeVarNames.getVarName(level); 288 } 289 } 290 291 294 private String getNextSubTreeMethodName() { 295 return fMethod.getName() + "_" + fNextSubMethodId++; 296 } 297 298 301 private int spaceLeft() { 302 int left = (fMaxCreateCostPerBuildMethod - fMethodCost); 303 return (left < 0) ? 0 : left; 304 } 305 306 309 private void createBuildMethod(String parentVar, 310 Node parent, 311 Node node) throws XMLCException { 312 BuildMethodGenerator buildMethod 313 = new BuildMethodGenerator(getNextSubTreeMethodName(), node); 314 buildMethod.createMethodCall(DOCUMENT_ARG, parentVar, fBody); 315 buildMethod.createMethod(parent, node); 316 fMethodCost += BuildMethodMappings.BUILD_METHOD_CALL_CREATE_COST; 317 } 318 319 322 private void processAttr(String elementVar, 323 Element element, 324 Attr attr, 325 int level) throws XMLCException { 326 String attrVar = fAttrVarNames.getVarName(level); 327 if (attr.getSpecified()) { 328 fNodeCreator.genNodeCreate(DOCUMENT_ARG, attrVar, attr, fBody); 330 fNodeCreator.genAddAttribute(elementVar, attrVar, fBody); 331 fMethodCost += fBuildMethodMappings.getNodeTypeCost(attr); 332 333 processChildren(attrVar, attr, level+1); 335 } 336 } 337 338 341 private void processAttrs(String elementVar, 342 Element element, 343 int level) throws XMLCException { 344 NamedNodeMap attrList = element.getAttributes(); 345 if (attrList != null) { 346 for (int idx = 0; idx < attrList.getLength(); idx++) { 347 processAttr(elementVar, element, 348 (Attr )attrList.item(idx), level); 349 } 350 } 351 } 352 353 357 private void processElement(String elementVar, 358 Element element, 359 int level) throws XMLCException { 360 processAttrs(elementVar, element, level); 361 ElementInfo elementInfo = fElementTable.getElementInfo(element); 362 if (elementInfo.getNumAccessMethods() > 0) { 363 fAccessorGenerator.createAccessMethodInit(elementInfo, elementVar, 364 fBody); 365 } 366 } 367 368 371 private void processEntity(String docTypeVar, 372 Entity entity, 373 int level) throws XMLCException { 374 String entityVar = getNodeVarName(entity, level); 375 fNodeCreator.genNodeCreate(DOCUMENT_ARG, entityVar, entity, fBody); 376 fNodeCreator.genAddEntity(docTypeVar, entityVar, entity, fBody); 377 fMethodCost += fBuildMethodMappings.getNodeTypeCost(entity); 378 processChildren(entityVar, entity, level+1); 379 } 380 381 384 private void processNotation(String docTypeVar, 385 Notation notation, 386 int level) throws XMLCException { 387 String notationVar = getNodeVarName(notation, level); 388 fNodeCreator.genNodeCreate(DOCUMENT_ARG, notationVar, notation, fBody); 389 fNodeCreator.genAddNotation(docTypeVar, notationVar, notation, fBody); 390 fMethodCost += fBuildMethodMappings.getNodeTypeCost(notation); 391 } 392 393 396 private void processDocumentType(String docTypeVar, 397 DocumentType docType, 398 int level) throws XMLCException { 399 NamedNodeMap entities = docType.getEntities(); 400 if (entities != null) { 401 for (int idx = 0; idx < entities.getLength(); idx++) { 402 processEntity(docTypeVar, (Entity )entities.item(idx), 403 level); 404 } 405 } 406 NamedNodeMap notations = docType.getNotations(); 407 if (notations != null) { 408 for (int idx = 0; idx < notations.getLength(); idx++) { 409 processNotation(docTypeVar, (Notation )notations.item(idx), 410 level); 411 } 412 } 413 } 414 415 420 private String createNode(String parentVar, 421 Node parent, 422 Node node, 423 int level) throws XMLCException { 424 String nodeVar = getNodeVarName(node, level); 425 fNodeCreator.genNodeCreate(DOCUMENT_ARG, nodeVar, node, fBody); 426 fNodeCreator.genAppendChild(parentVar, nodeVar, node, fBody); 427 fMethodCost += fBuildMethodMappings.getNodeTypeCost(node); 428 fBody.addln(); 429 return nodeVar; 430 } 431 432 435 private void processNode(String parentVar, 436 Node parent, 437 Node node, 438 int level) throws XMLCException { 439 if (node instanceof DocumentType ) { 440 return; } 442 if ((level != 0) && fBuildMethodMappings.isMethodRoot(node)) { 443 createBuildMethod(parentVar, parent, node); 445 } else { 446 if (COST_DEBUG) { 447 fBody.addln("// " + fBuildMethodMappings.toString(node)); 448 } 449 String nodeVar = createNode(parentVar, parent, node, level); 450 if (node instanceof Element ) { 451 processElement(nodeVar, (Element )node, level); 452 } 453 processChildren(nodeVar, node, level+1); 454 } 455 } 456 457 462 private void processChildrenChaining(String parentVar, 463 Node parent, 464 Node nextChild, 465 int level) throws XMLCException { 466 boolean isFirst = true; 470 while ((nextChild != null) 471 && ((fBuildMethodMappings.getCreateCost(nextChild) < spaceLeft()) 472 || isFirst)) { 473 processNode(parentVar, parent, nextChild, level); 474 nextChild = nextChild.getNextSibling(); 475 isFirst = false; 476 } 477 478 if (nextChild != null) { 480 BuildMethodGenerator nextBuildMethod 481 = new BuildMethodGenerator(fMethod.getName() + "c", 482 nextChild); 483 nextBuildMethod.createChainedChildrenMethod(fChainLevel+1, 484 parentVar, parent, 485 nextChild, 486 DOCUMENT_ARG, 487 fBody); 488 fMethodCost += BuildMethodMappings.BUILD_METHOD_CALL_CREATE_COST; 489 } 490 } 491 492 495 private void processChildren(String parentVar, 496 Node parent, 497 int level) throws XMLCException { 498 if (fBuildMethodMappings.useChainedChildrenMethods(parent)) { 499 processChildrenChaining(parentVar, parent, 500 parent.getFirstChild(), level); 501 } else { 502 for (Node child = parent.getFirstChild(); 503 child != null; child = child.getNextSibling()) { 504 processNode(parentVar, parent, child, level); 505 } 506 } 507 } 508 509 512 private void createVariables() { 513 fNodeVarNames.insertVarDefs(fBody); 514 fElementVarNames.insertVarDefs(fBody); 515 fAttrVarNames.insertVarDefs(fBody); 516 fBody.addVars(""); } 518 } 519 520 523 public DOMBuilderGenerator(String methodName, 524 Document document, 525 String documentArgClassName, 526 NodeCreateGenerator nodeCreator, 527 AccessorGenerator accessorGenerator, 528 ElementTable elementTable, 529 JavaClass docClass, 530 int maxCreateCostPerBuildMethod, 531 boolean staticMethods) throws XMLCException { 532 fMethodName = methodName; 533 fDocument = document; 534 fDocumentArgClassName = documentArgClassName; 535 fNodeCreator = nodeCreator; 536 fAccessorGenerator = accessorGenerator; 537 fElementTable = elementTable; 538 fDocClass = docClass; 539 fMaxCreateCostPerBuildMethod = maxCreateCostPerBuildMethod; 540 fStaticMethods = staticMethods; 541 542 fBuildMethodMappings = new BuildMethodMappings(fMaxCreateCostPerBuildMethod, 543 document); 544 545 BuildMethodGenerator buildMethod 546 = new BuildMethodGenerator(fMethodName, document); 547 buildMethod.createMethod(document); 548 } 549 550 553 public void createMethodCall(JavaCode body) { 554 body.addln(fMethodName + "();"); 555 } 556 } 557 | Popular Tags |