1 23 24 package org.enhydra.xml.xmlc.dom.generic; 25 26 import java.util.ArrayList ; 27 import java.util.Collections ; 28 import java.util.Comparator ; 29 import java.util.HashMap ; 30 31 import org.enhydra.xml.xmlc.XMLCError; 32 import org.enhydra.xml.xmlc.codegen.JavaLang; 33 import org.w3c.dom.Document ; 34 import org.w3c.dom.Element ; 35 import org.w3c.dom.Node ; 36 37 58 final class BuildMethodMappings { 59 62 public static final int BUILD_METHOD_CALL_CREATE_COST = 1; 63 64 68 public static final int CREATE_ELEMENT_CREATE_COST = 2; 69 70 73 public static final int CREATE_NODE_CREATE_COST = 1; 74 75 78 private Document fDocument; 79 80 83 private int fMaxCreateCostPerBuildMethod; 84 85 88 private HashMap fNodeRecordTable = new HashMap (); 89 90 93 private class Record { 94 95 private Node fNode; 96 97 102 private int fCreateCost; 103 104 110 private int fParentCreateCost; 111 112 113 private boolean fMethodRoot; 114 115 116 private boolean fChainedChildrenMethods; 117 118 121 public Record(Node node) { 122 fNode = node; 123 fCreateCost = getNodeTypeCost(node); 124 fParentCreateCost = fCreateCost; 125 126 fNodeRecordTable.put(node, this); 128 } 129 130 131 public void makeMethodRoot() { 132 fParentCreateCost = BUILD_METHOD_CALL_CREATE_COST; 133 fMethodRoot = true; 134 } 135 136 137 public void makeChainedChildrenMethods () { 138 fChainedChildrenMethods = true; 139 } 140 141 142 public boolean canBeMethodRoot() { 143 return BuildMethodMappings.this.canBeMethodRoot(fNode); 144 } 145 146 151 public void adjustCreateCost(int amount) { 152 fCreateCost += amount; 153 if (!fMethodRoot) { 154 fParentCreateCost += amount; 155 } 156 } 157 158 159 public Node getNode() { 160 return fNode; 161 } 162 163 164 public int getCreateCost() { 165 return fCreateCost; 166 } 167 168 169 public int getParentCreateCost() { 170 return fParentCreateCost; 171 } 172 173 174 public boolean isMethodRoot() { 175 return fMethodRoot; 176 } 177 178 179 public boolean useChainedChildrenMethods() { 180 return fChainedChildrenMethods; 181 } 182 183 184 public String toString() { 185 return JavaLang.simpleClassName(fNode) 186 + " method=" + fMethodRoot 187 + " chained=" + fChainedChildrenMethods 188 + " cost=" + fCreateCost 189 + " parentCost=" + fParentCreateCost; 190 } 191 } 192 193 196 public BuildMethodMappings(int maxCreateCostPerBuildMethod, 197 Document document) { 198 fDocument = document; 199 fMaxCreateCostPerBuildMethod = maxCreateCostPerBuildMethod; 200 calculateTreeCosts(document); 201 } 202 203 207 boolean canBeMethodRoot(Node node) { 208 switch (node.getNodeType()) { 210 case Node.DOCUMENT_NODE: 211 case Node.DOCUMENT_TYPE_NODE: 212 case Node.ELEMENT_NODE: 213 return true; 214 default: 215 return false; 216 } 217 } 218 219 223 public int getNodeTypeCost(Node node) { 224 if (node instanceof Element ) { 226 return CREATE_ELEMENT_CREATE_COST; 227 } else { 228 return CREATE_NODE_CREATE_COST; 229 } 230 } 231 232 235 private Record getRecord(Node node) { 236 Record rec = (Record)fNodeRecordTable.get(node); 237 if (rec == null) { 238 throw new XMLCError("BUG: record not found: " + node); 239 } 240 return rec; 241 } 242 243 249 private Record calculateTreeCosts(Node node) { 250 Record rec = new Record(node); 251 if (node instanceof Document ) { 252 rec.makeMethodRoot(); 253 } 254 255 ContainedNodeEnum nodes = new ContainedNodeEnum(rec.fNode); 257 while (nodes.hasMoreElements()) { 258 Record child = calculateTreeCosts(nodes.nextNode()); 259 rec.adjustCreateCost(child.getParentCreateCost()); 260 } 261 adjustRecord(rec); 262 return rec; 263 } 264 265 269 private void moveChildIntoMethod(Record parent, 270 Record child) { 271 parent.adjustCreateCost(-child.getParentCreateCost()); 272 child.makeMethodRoot(); 273 parent.adjustCreateCost(child.getParentCreateCost()); 274 } 275 276 280 private void minimizeChildCreateCost(Record parent, 281 Record child) { 282 if (!child.isMethodRoot() && child.canBeMethodRoot() 283 && (child.getParentCreateCost() > BUILD_METHOD_CALL_CREATE_COST)) { 284 moveChildIntoMethod(parent, child); 285 } 286 } 287 288 292 private ArrayList buildSortedBuildMethodCandidates(Record rec) { 293 ArrayList list = new ArrayList (); 294 295 ContainedNodeEnum children = new ContainedNodeEnum(rec.fNode); 296 while (children.hasMoreElements()) { 297 Record child = getRecord(children.nextNode()); 298 if (child.canBeMethodRoot()) { 299 list.add(child); 300 } 301 } 302 303 Comparator cmp 304 = new Comparator () { 305 public int compare(Object o1, 306 Object o2) { 307 int cost1 = ((Record)o1).getParentCreateCost(); 308 int cost2 = ((Record)o2).getParentCreateCost(); 309 return ((cost1 > cost2) ? -1 : ((cost1 < cost2) ? 1 : 0)); 310 } 311 }; 312 313 Collections.sort(list, cmp); 314 return list; 315 } 316 317 322 private void adjustBuildMethod(Record rec) { 323 ArrayList list = buildSortedBuildMethodCandidates(rec); 324 325 int numChildren = list.size(); 328 for (int idx = 0; 329 (idx < numChildren) 330 && (rec.getCreateCost() >= fMaxCreateCostPerBuildMethod); 331 idx++) { 332 minimizeChildCreateCost(rec, (Record)list.get(idx)); 333 } 334 } 335 336 341 private void adjustRecord(Record rec) { 342 if (rec.getCreateCost() >= fMaxCreateCostPerBuildMethod) { 343 adjustBuildMethod(rec); 345 } 346 if (rec.getCreateCost() > fMaxCreateCostPerBuildMethod) { 347 rec.makeChainedChildrenMethods(); 349 } 350 } 351 352 355 public boolean isMethodRoot(Node node) { 356 return getRecord(node).isMethodRoot(); 357 } 358 359 362 public boolean useChainedChildrenMethods(Node node) { 363 return getRecord(node).useChainedChildrenMethods(); 364 } 365 366 369 public int getCreateCost(Node node) { 370 return getRecord(node).getCreateCost(); 371 } 372 373 376 public String toString(Node node) { 377 return getRecord(node).toString(); 378 } 379 } 380 | Popular Tags |