1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: Sort.java,v 1.23 2004/02/24 02:58:42 zongaro Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler;
  20. import java.text.Collator;
  21. import java.util.ArrayList;
  22. import java.util.NoSuchElementException;
  23. import java.util.StringTokenizer;
  24. import java.util.Vector;
  25. import com.sun.org.apache.bcel.internal.classfile.Field;
  26. import com.sun.org.apache.bcel.internal.classfile.Method;
  27. import com.sun.org.apache.bcel.internal.generic.ALOAD;
  28. import com.sun.org.apache.bcel.internal.generic.ANEWARRAY;
  29. import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
  30. import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  31. import com.sun.org.apache.bcel.internal.generic.GETFIELD;
  32. import com.sun.org.apache.bcel.internal.generic.ICONST;
  33. import com.sun.org.apache.bcel.internal.generic.ILOAD;
  34. import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  35. import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  36. import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  37. import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  38. import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  39. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  40. import com.sun.org.apache.bcel.internal.generic.NEW;
  41. import com.sun.org.apache.bcel.internal.generic.NOP;
  42. import com.sun.org.apache.bcel.internal.generic.PUSH;
  43. import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
  44. import com.sun.org.apache.bcel.internal.generic.TABLESWITCH;
  45. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  46. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.CompareGenerator;
  47. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  48. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
  49. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  50. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSortRecordFactGenerator;
  51. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSortRecordGenerator;
  52. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.StringType;
  53. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  54. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  55. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  56. import com.sun.org.apache.xalan.internal.xsltc.dom.Axis;
  57. /**
  58. * @author Jacek Ambroziak
  59. * @author Santiago Pericas-Geertsen
  60. * @author Morten Jorgensen
  61. */
  62. final class Sort extends Instruction implements Closure {
  63. private Expression _select;
  64. private AttributeValue _order;
  65. private AttributeValue _caseOrder;
  66. private AttributeValue _dataType;
  67. private String _lang; // bug! see 26869
  68. private String _data = null;
  69. private String _className = null;
  70. private ArrayList _closureVars = null;
  71. private boolean _needsSortRecordFactory = false;
  72. // -- Begin Closure interface --------------------
  73. /**
  74. * Returns true if this closure is compiled in an inner class (i.e.
  75. * if this is a real closure).
  76. */
  77. public boolean inInnerClass() {
  78. return (_className != null);
  79. }
  80. /**
  81. * Returns a reference to its parent closure or null if outermost.
  82. */
  83. public Closure getParentClosure() {
  84. return null;
  85. }
  86. /**
  87. * Returns the name of the auxiliary class or null if this predicate
  88. * is compiled inside the Translet.
  89. */
  90. public String getInnerClassName() {
  91. return _className;
  92. }
  93. /**
  94. * Add new variable to the closure.
  95. */
  96. public void addVariable(VariableRefBase variableRef) {
  97. if (_closureVars == null) {
  98. _closureVars = new ArrayList();
  99. }
  100. // Only one reference per variable
  101. if (!_closureVars.contains(variableRef)) {
  102. _closureVars.add(variableRef);
  103. _needsSortRecordFactory = true;
  104. }
  105. }
  106. // -- End Closure interface ----------------------
  107. private void setInnerClassName(String className) {
  108. _className = className;
  109. }
  110. /**
  111. * Parse the attributes of the xsl:sort element
  112. */
  113. public void parseContents(Parser parser) {
  114. final SyntaxTreeNode parent = getParent();
  115. if (!(parent instanceof ApplyTemplates) &&
  116. !(parent instanceof ForEach)) {
  117. reportError(this, parser, ErrorMsg.STRAY_SORT_ERR, null);
  118. return;
  119. }
  120. // Parse the select expression (node string value if no expression)
  121. _select = parser.parseExpression(this, "select", "string(.)");
  122. // Get the sort order; default is 'ascending'
  123. String val = getAttribute("order");
  124. if (val.length() == 0) val = "ascending";
  125. _order = AttributeValue.create(this, val, parser);
  126. // Get the sort data type; default is text
  127. val = getAttribute("data-type");
  128. if (val.length() == 0) {
  129. try {
  130. final Type type = _select.typeCheck(parser.getSymbolTable());
  131. if (type instanceof IntType)
  132. val = "number";
  133. else
  134. val = "text";
  135. }
  136. catch (TypeCheckError e) {
  137. val = "text";
  138. }
  139. }
  140. _dataType = AttributeValue.create(this, val, parser);
  141. _lang = getAttribute("lang"); // bug! see 26869
  142. // val = getAttribute("lang");
  143. // _lang = AttributeValue.create(this, val, parser);
  144. // Get the case order; default is language dependant
  145. val = getAttribute("case-order");
  146. _caseOrder = AttributeValue.create(this, val, parser);
  147. }
  148. /**
  149. * Run type checks on the attributes; expression must return a string
  150. * which we will use as a sort key
  151. */
  152. public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  153. final Type tselect = _select.typeCheck(stable);
  154. // If the sort data-type is not set we use the natural data-type
  155. // of the data we will sort
  156. if (!(tselect instanceof StringType)) {
  157. _select = new CastExpr(_select, Type.String);
  158. }
  159. _order.typeCheck(stable);
  160. _caseOrder.typeCheck(stable);
  161. _dataType.typeCheck(stable);
  162. return Type.Void;
  163. }
  164. /**
  165. * These two methods are needed in the static methods that compile the
  166. * overloaded NodeSortRecord.compareType() and NodeSortRecord.sortOrder()
  167. */
  168. public void translateSortType(ClassGenerator classGen,
  169. MethodGenerator methodGen) {
  170. _dataType.translate(classGen, methodGen);
  171. }
  172. public void translateSortOrder(ClassGenerator classGen,
  173. MethodGenerator methodGen) {
  174. _order.translate(classGen, methodGen);
  175. }
  176. public void translateCaseOrder(ClassGenerator classGen,
  177. MethodGenerator methodGen) {
  178. _caseOrder.translate(classGen, methodGen);
  179. }
  180. public void translateLang(ClassGenerator classGen,
  181. MethodGenerator methodGen) {
  182. final ConstantPoolGen cpg = classGen.getConstantPool();
  183. final InstructionList il = methodGen.getInstructionList();
  184. il.append(new PUSH(cpg, _lang)); // bug! see 26869
  185. }
  186. /**
  187. * This method compiles code for the select expression for this
  188. * xsl:sort element. The method is called from the static code-generating
  189. * methods in this class.
  190. */
  191. public void translateSelect(ClassGenerator classGen,
  192. MethodGenerator methodGen) {
  193. _select.translate(classGen,methodGen);
  194. }
  195. /**
  196. * This method should not produce any code
  197. */
  198. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  199. // empty
  200. }
  201. /**
  202. * Compiles code that instantiates a SortingIterator object.
  203. * This object's constructor needs referencdes to the current iterator
  204. * and a node sort record producing objects as its parameters.
  205. */
  206. public static void translateSortIterator(ClassGenerator classGen,
  207. MethodGenerator methodGen,
  208. Expression nodeSet,
  209. Vector sortObjects)
  210. {
  211. final ConstantPoolGen cpg = classGen.getConstantPool();
  212. final InstructionList il = methodGen.getInstructionList();
  213. // SortingIterator.SortingIterator(NodeIterator,NodeSortRecordFactory);
  214. final int init = cpg.addMethodref(SORT_ITERATOR, "<init>",
  215. "("
  216. + NODE_ITERATOR_SIG
  217. + NODE_SORT_FACTORY_SIG
  218. + ")V");
  219. il.append(new NEW(cpg.addClass(SORT_ITERATOR)));
  220. il.append(DUP);
  221. // Get the current node iterator
  222. if (nodeSet == null) { // apply-templates default
  223. final int children = cpg.addInterfaceMethodref(DOM_INTF,
  224. "getAxisIterator",
  225. "(I)"+
  226. NODE_ITERATOR_SIG);
  227. il.append(methodGen.loadDOM());
  228. il.append(new PUSH(cpg, Axis.CHILD));
  229. il.append(new INVOKEINTERFACE(children, 2));
  230. }
  231. else {
  232. nodeSet.translate(classGen, methodGen);
  233. }
  234. // Compile the code for the NodeSortRecord producing class and pass
  235. // that as the last argument to the SortingIterator constructor.
  236. compileSortRecordFactory(sortObjects, classGen, methodGen);
  237. il.append(new INVOKESPECIAL(init));
  238. }
  239. /**
  240. * Compiles code that instantiates a NodeSortRecordFactory object which
  241. * will produce NodeSortRecord objects of a specific type.
  242. */
  243. public static void compileSortRecordFactory(Vector sortObjects,
  244. ClassGenerator classGen, MethodGenerator methodGen)
  245. {
  246. String sortRecordClass =
  247. compileSortRecord(sortObjects, classGen, methodGen);
  248. boolean needsSortRecordFactory = false;
  249. final int nsorts = sortObjects.size();
  250. for (int i = 0; i < nsorts; i++) {
  251. final Sort sort = (Sort) sortObjects.elementAt(i);
  252. needsSortRecordFactory |= sort._needsSortRecordFactory;
  253. }
  254. String sortRecordFactoryClass = NODE_SORT_FACTORY;
  255. if (needsSortRecordFactory) {
  256. sortRecordFactoryClass =
  257. compileSortRecordFactory(sortObjects, classGen, methodGen,
  258. sortRecordClass);
  259. }
  260. final ConstantPoolGen cpg = classGen.getConstantPool();
  261. final InstructionList il = methodGen.getInstructionList();
  262. il.append(new NEW(cpg.addClass(sortRecordFactoryClass)));
  263. il.append(DUP);
  264. il.append(methodGen.loadDOM());
  265. il.append(new PUSH(cpg, sortRecordClass));
  266. il.append(classGen.loadTranslet());
  267. // Compile code that initializes the static _sortOrder
  268. il.append(new PUSH(cpg, nsorts));
  269. il.append(new ANEWARRAY(cpg.addClass(STRING)));
  270. for (int level = 0; level < nsorts; level++) {
  271. final Sort sort = (Sort)sortObjects.elementAt(level);
  272. il.append(DUP);
  273. il.append(new PUSH(cpg, level));
  274. sort.translateSortOrder(classGen, methodGen);
  275. il.append(AASTORE);
  276. }
  277. il.append(new PUSH(cpg, nsorts));
  278. il.append(new ANEWARRAY(cpg.addClass(STRING)));
  279. for (int level = 0; level < nsorts; level++) {
  280. final Sort sort = (Sort)sortObjects.elementAt(level);
  281. il.append(DUP);
  282. il.append(new PUSH(cpg, level));
  283. sort.translateSortType(classGen, methodGen);
  284. il.append(AASTORE);
  285. }
  286. il.append(new PUSH(cpg, nsorts));
  287. il.append(new ANEWARRAY(cpg.addClass(STRING)));
  288. for (int level = 0; level < nsorts; level++) {
  289. final Sort sort = (Sort)sortObjects.elementAt(level);
  290. il.append(DUP);
  291. il.append(new PUSH(cpg, level));
  292. sort.translateLang(classGen, methodGen);
  293. il.append(AASTORE);
  294. }
  295. il.append(new PUSH(cpg, nsorts));
  296. il.append(new ANEWARRAY(cpg.addClass(STRING)));
  297. for (int level = 0; level < nsorts; level++) {
  298. final Sort sort = (Sort)sortObjects.elementAt(level);
  299. il.append(DUP);
  300. il.append(new PUSH(cpg, level));
  301. sort.translateCaseOrder(classGen, methodGen);
  302. il.append(AASTORE);
  303. }
  304. il.append(new INVOKESPECIAL(
  305. cpg.addMethodref(sortRecordFactoryClass, "<init>",
  306. "(" + DOM_INTF_SIG
  307. + STRING_SIG
  308. + TRANSLET_INTF_SIG
  309. + "[" + STRING_SIG
  310. + "[" + STRING_SIG
  311. + "[" + STRING_SIG
  312. + "[" + STRING_SIG + ")V")));
  313. // Initialize closure variables in sortRecordFactory
  314. final ArrayList dups = new ArrayList();
  315. for (int j = 0; j < nsorts; j++) {
  316. final Sort sort = (Sort) sortObjects.get(j);
  317. final int length = (sort._closureVars == null) ? 0 :
  318. sort._closureVars.size();
  319. for (int i = 0; i < length; i++) {
  320. VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i);
  321. // Discard duplicate variable references
  322. if (dups.contains(varRef)) continue;
  323. final VariableBase var = varRef.getVariable();
  324. // Store variable in new closure
  325. il.append(DUP);
  326. il.append(var.loadInstruction());
  327. il.append(new PUTFIELD(
  328. cpg.addFieldref(sortRecordFactoryClass, var.getEscapedName(),
  329. var.getType().toSignature())));
  330. dups.add(varRef);
  331. }
  332. }
  333. }
  334. public static String compileSortRecordFactory(Vector sortObjects,
  335. ClassGenerator classGen, MethodGenerator methodGen,
  336. String sortRecordClass)
  337. {
  338. final XSLTC xsltc = ((Sort)sortObjects.firstElement()).getXSLTC();
  339. final String className = xsltc.getHelperClassName();
  340. final NodeSortRecordFactGenerator sortRecordFactory =
  341. new NodeSortRecordFactGenerator(className,
  342. NODE_SORT_FACTORY,
  343. className + ".java",
  344. ACC_PUBLIC | ACC_SUPER | ACC_FINAL,
  345. new String[] {},
  346. classGen.getStylesheet());
  347. ConstantPoolGen cpg = sortRecordFactory.getConstantPool();
  348. // Add a new instance variable for each var in closure
  349. final int nsorts = sortObjects.size();
  350. final ArrayList dups = new ArrayList();
  351. for (int j = 0; j < nsorts; j++) {
  352. final Sort sort = (Sort) sortObjects.get(j);
  353. final int length = (sort._closureVars == null) ? 0 :
  354. sort._closureVars.size();
  355. for (int i = 0; i < length; i++) {
  356. final VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i);
  357. // Discard duplicate variable references
  358. if (dups.contains(varRef)) continue;
  359. final VariableBase var = varRef.getVariable();
  360. sortRecordFactory.addField(new Field(ACC_PUBLIC,
  361. cpg.addUtf8(var.getEscapedName()),
  362. cpg.addUtf8(var.getType().toSignature()),
  363. null, cpg.getConstantPool()));
  364. dups.add(varRef);
  365. }
  366. }
  367. // Define a constructor for this class
  368. final com.sun.org.apache.bcel.internal.generic.Type[] argTypes =
  369. new com.sun.org.apache.bcel.internal.generic.Type[7];
  370. argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
  371. argTypes[1] = Util.getJCRefType(STRING_SIG);
  372. argTypes[2] = Util.getJCRefType(TRANSLET_INTF_SIG);
  373. argTypes[3] = Util.getJCRefType("[" + STRING_SIG);
  374. argTypes[4] = Util.getJCRefType("[" + STRING_SIG);
  375. argTypes[5] = Util.getJCRefType("[" + STRING_SIG);
  376. argTypes[6] = Util.getJCRefType("[" + STRING_SIG);
  377. final String[] argNames = new String[7];
  378. argNames[0] = DOCUMENT_PNAME;
  379. argNames[1] = "className";
  380. argNames[2] = TRANSLET_PNAME;
  381. argNames[3] = "order";
  382. argNames[4] = "type";
  383. argNames[5] = "lang";
  384. argNames[6] = "case_order";
  385. InstructionList il = new InstructionList();
  386. final MethodGenerator constructor =
  387. new MethodGenerator(ACC_PUBLIC,
  388. com.sun.org.apache.bcel.internal.generic.Type.VOID,
  389. argTypes, argNames, "<init>",
  390. className, il, cpg);
  391. // Push all parameters onto the stack and called super.<init>()
  392. il.append(ALOAD_0);
  393. il.append(ALOAD_1);
  394. il.append(ALOAD_2);
  395. il.append(new ALOAD(3));
  396. il.append(new ALOAD(4));
  397. il.append(new ALOAD(5));
  398. il.append(new ALOAD(6));
  399. il.append(new ALOAD(7));
  400. il.append(new INVOKESPECIAL(cpg.addMethodref(NODE_SORT_FACTORY,
  401. "<init>",
  402. "(" + DOM_INTF_SIG
  403. + STRING_SIG
  404. + TRANSLET_INTF_SIG
  405. + "[" + STRING_SIG
  406. + "[" + STRING_SIG
  407. + "[" + STRING_SIG
  408. + "[" + STRING_SIG + ")V")));
  409. il.append(RETURN);
  410. // Override the definition of makeNodeSortRecord()
  411. il = new InstructionList();
  412. final MethodGenerator makeNodeSortRecord =
  413. new MethodGenerator(ACC_PUBLIC,
  414. Util.getJCRefType(NODE_SORT_RECORD_SIG),
  415. new com.sun.org.apache.bcel.internal.generic.Type[] {
  416. com.sun.org.apache.bcel.internal.generic.Type.INT,
  417. com.sun.org.apache.bcel.internal.generic.Type.INT },
  418. new String[] { "node", "last" }, "makeNodeSortRecord",
  419. className, il, cpg);
  420. il.append(ALOAD_0);
  421. il.append(ILOAD_1);
  422. il.append(ILOAD_2);
  423. il.append(new INVOKESPECIAL(cpg.addMethodref(NODE_SORT_FACTORY,
  424. "makeNodeSortRecord", "(II)" + NODE_SORT_RECORD_SIG)));
  425. il.append(DUP);
  426. il.append(new CHECKCAST(cpg.addClass(sortRecordClass)));
  427. // Initialize closure in record class
  428. final int ndups = dups.size();
  429. for (int i = 0; i < ndups; i++) {
  430. final VariableRefBase varRef = (VariableRefBase) dups.get(i);
  431. final VariableBase var = varRef.getVariable();
  432. final Type varType = var.getType();
  433. il.append(DUP);
  434. // Get field from factory class
  435. il.append(ALOAD_0);
  436. il.append(new GETFIELD(
  437. cpg.addFieldref(className,
  438. var.getEscapedName(), varType.toSignature())));
  439. // Put field in record class
  440. il.append(new PUTFIELD(
  441. cpg.addFieldref(sortRecordClass,
  442. var.getEscapedName(), varType.toSignature())));
  443. }
  444. il.append(POP);
  445. il.append(ARETURN);
  446. constructor.setMaxLocals();
  447. constructor.setMaxStack();
  448. sortRecordFactory.addMethod(constructor.getMethod());
  449. makeNodeSortRecord.setMaxLocals();
  450. makeNodeSortRecord.setMaxStack();
  451. sortRecordFactory.addMethod(makeNodeSortRecord.getMethod());
  452. xsltc.dumpClass(sortRecordFactory.getJavaClass());
  453. return className;
  454. }
  455. /**
  456. * Create a new auxillary class extending NodeSortRecord.
  457. */
  458. private static String compileSortRecord(Vector sortObjects,
  459. ClassGenerator classGen,
  460. MethodGenerator methodGen) {
  461. final XSLTC xsltc = ((Sort)sortObjects.firstElement()).getXSLTC();
  462. final String className = xsltc.getHelperClassName();
  463. // This generates a new class for handling this specific sort
  464. final NodeSortRecordGenerator sortRecord =
  465. new NodeSortRecordGenerator(className,
  466. NODE_SORT_RECORD,
  467. "sort$0.java",
  468. ACC_PUBLIC | ACC_SUPER | ACC_FINAL,
  469. new String[] {},
  470. classGen.getStylesheet());
  471. final ConstantPoolGen cpg = sortRecord.getConstantPool();
  472. // Add a new instance variable for each var in closure
  473. final int nsorts = sortObjects.size();
  474. final ArrayList dups = new ArrayList();
  475. for (int j = 0; j < nsorts; j++) {
  476. final Sort sort = (Sort) sortObjects.get(j);
  477. // Set the name of the inner class in this sort object
  478. sort.setInnerClassName(className);
  479. final int length = (sort._closureVars == null) ? 0 :
  480. sort._closureVars.size();
  481. for (int i = 0; i < length; i++) {
  482. final VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i);
  483. // Discard duplicate variable references
  484. if (dups.contains(varRef)) continue;
  485. final VariableBase var = varRef.getVariable();
  486. sortRecord.addField(new Field(ACC_PUBLIC,
  487. cpg.addUtf8(var.getEscapedName()),
  488. cpg.addUtf8(var.getType().toSignature()),
  489. null, cpg.getConstantPool()));
  490. dups.add(varRef);
  491. }
  492. }
  493. Method init = compileInit(sortObjects, sortRecord,
  494. cpg, className);
  495. Method extract = compileExtract(sortObjects, sortRecord,
  496. cpg, className);
  497. sortRecord.addMethod(init);
  498. sortRecord.addMethod(extract);
  499. xsltc.dumpClass(sortRecord.getJavaClass());
  500. return className;
  501. }
  502. /**
  503. * Create a constructor for the new class. Updates the reference to the
  504. * collator in the super calls only when the stylesheet specifies a new
  505. * language in xsl:sort.
  506. */
  507. private static Method compileInit(Vector sortObjects,
  508. NodeSortRecordGenerator sortRecord,
  509. ConstantPoolGen cpg,
  510. String className)
  511. {
  512. final InstructionList il = new InstructionList();
  513. final MethodGenerator init =
  514. new MethodGenerator(ACC_PUBLIC,
  515. com.sun.org.apache.bcel.internal.generic.Type.VOID,
  516. null, null, "<init>", className,
  517. il, cpg);
  518. // Call the constructor in the NodeSortRecord superclass
  519. il.append(ALOAD_0);
  520. il.append(new INVOKESPECIAL(cpg.addMethodref(NODE_SORT_RECORD,
  521. "<init>", "()V")));
  522. il.append(RETURN);
  523. init.stripAttributes(true);
  524. init.setMaxLocals();
  525. init.setMaxStack();
  526. return init.getMethod();
  527. }
  528. /**
  529. * Compiles a method that overloads NodeSortRecord.extractValueFromDOM()
  530. */
  531. private static Method compileExtract(Vector sortObjects,
  532. NodeSortRecordGenerator sortRecord,
  533. ConstantPoolGen cpg,
  534. String className) {
  535. final InstructionList il = new InstructionList();
  536. // String NodeSortRecord.extractValueFromDOM(dom,node,level);
  537. final CompareGenerator extractMethod =
  538. new CompareGenerator(ACC_PUBLIC | ACC_FINAL,
  539. com.sun.org.apache.bcel.internal.generic.Type.STRING,
  540. new com.sun.org.apache.bcel.internal.generic.Type[] {
  541. Util.getJCRefType(DOM_INTF_SIG),
  542. com.sun.org.apache.bcel.internal.generic.Type.INT,
  543. com.sun.org.apache.bcel.internal.generic.Type.INT,
  544. Util.getJCRefType(TRANSLET_SIG),
  545. com.sun.org.apache.bcel.internal.generic.Type.INT
  546. },
  547. new String[] { "dom",
  548. "current",
  549. "level",
  550. "translet",
  551. "last"
  552. },
  553. "extractValueFromDOM", className, il, cpg);
  554. // Values needed for the switch statement
  555. final int levels = sortObjects.size();
  556. final int match[] = new int[levels];
  557. final InstructionHandle target[] = new InstructionHandle[levels];
  558. InstructionHandle tblswitch = null;
  559. // Compile switch statement only if the key has multiple levels
  560. if (levels > 1) {
  561. // Put the parameter to the swtich statement on the stack
  562. il.append(new ILOAD(extractMethod.getLocalIndex("level")));
  563. // Append the switch statement here later on
  564. tblswitch = il.append(new NOP());
  565. }
  566. // Append all the cases for the switch statment
  567. for (int level = 0; level < levels; level++) {
  568. match[level] = level;
  569. final Sort sort = (Sort)sortObjects.elementAt(level);
  570. target[level] = il.append(NOP);
  571. sort.translateSelect(sortRecord, extractMethod);
  572. il.append(ARETURN);
  573. }
  574. // Compile def. target for switch statement if key has multiple levels
  575. if (levels > 1) {
  576. // Append the default target - it will _NEVER_ be reached
  577. InstructionHandle defaultTarget =
  578. il.append(new PUSH(cpg, EMPTYSTRING));
  579. il.insert(tblswitch,new TABLESWITCH(match, target, defaultTarget));
  580. il.append(ARETURN);
  581. }
  582. extractMethod.stripAttributes(true);
  583. extractMethod.setMaxLocals();
  584. extractMethod.setMaxStack();
  585. extractMethod.removeNOPs();
  586. return extractMethod.getMethod();
  587. }
  588. }