FileDocCategorySizeDatePackage
Sort.javaAPI DocJava SE 5 API22630Fri Aug 26 14:55:36 BST 2005com.sun.org.apache.xalan.internal.xsltc.compiler

Sort

public final class Sort extends Instruction implements Closure
author
Jacek Ambroziak
author
Santiago Pericas-Geertsen
author
Morten Jorgensen

Fields Summary
private Expression
_select
private AttributeValue
_order
private AttributeValue
_caseOrder
private AttributeValue
_dataType
private String
_lang
private String
_data
private String
_className
private ArrayList
_closureVars
private boolean
_needsSortRecordFactory
Constructors Summary
Methods Summary
public voidaddVariable(com.sun.org.apache.xalan.internal.xsltc.compiler.VariableRefBase variableRef)
Add new variable to the closure.

	if (_closureVars == null) {
	    _closureVars = new ArrayList();
	}

	// Only one reference per variable
	if (!_closureVars.contains(variableRef)) {
	    _closureVars.add(variableRef);
	    _needsSortRecordFactory = true;
	}
    
private static com.sun.org.apache.bcel.internal.classfile.MethodcompileExtract(java.util.Vector sortObjects, com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSortRecordGenerator sortRecord, com.sun.org.apache.bcel.internal.generic.ConstantPoolGen cpg, java.lang.String className)
Compiles a method that overloads NodeSortRecord.extractValueFromDOM()

	final InstructionList il = new InstructionList();
	
	// String NodeSortRecord.extractValueFromDOM(dom,node,level);
	final CompareGenerator extractMethod =
	    new CompareGenerator(ACC_PUBLIC | ACC_FINAL,
				 com.sun.org.apache.bcel.internal.generic.Type.STRING, 
				 new com.sun.org.apache.bcel.internal.generic.Type[] {
		                     Util.getJCRefType(DOM_INTF_SIG),
				     com.sun.org.apache.bcel.internal.generic.Type.INT,
				     com.sun.org.apache.bcel.internal.generic.Type.INT,
				     Util.getJCRefType(TRANSLET_SIG),
				     com.sun.org.apache.bcel.internal.generic.Type.INT
				 },
				 new String[] { "dom",
						"current",
						"level",
						"translet",
						"last"
				 },
				 "extractValueFromDOM", className, il, cpg);

	// Values needed for the switch statement
	final int levels = sortObjects.size();
	final int match[] = new int[levels];
	final InstructionHandle target[] = new InstructionHandle[levels];
	InstructionHandle tblswitch = null;

	// Compile switch statement only if the key has multiple levels
	if (levels > 1) {
	    // Put the parameter to the swtich statement on the stack
	    il.append(new ILOAD(extractMethod.getLocalIndex("level")));
	    // Append the switch statement here later on
	    tblswitch = il.append(new NOP());
	}

	// Append all the cases for the switch statment
	for (int level = 0; level < levels; level++) {
	    match[level] = level;
	    final Sort sort = (Sort)sortObjects.elementAt(level);
	    target[level] = il.append(NOP);
	    sort.translateSelect(sortRecord, extractMethod);
	    il.append(ARETURN);
	}
	
	// Compile def. target for switch statement if key has multiple levels
	if (levels > 1) {
	    // Append the default target - it will _NEVER_ be reached
	    InstructionHandle defaultTarget =
		il.append(new PUSH(cpg, EMPTYSTRING));
	    il.insert(tblswitch,new TABLESWITCH(match, target, defaultTarget));
	    il.append(ARETURN);
	}

	extractMethod.stripAttributes(true);
	extractMethod.setMaxLocals();
	extractMethod.setMaxStack();
	extractMethod.removeNOPs();

	return extractMethod.getMethod();
    
private static com.sun.org.apache.bcel.internal.classfile.MethodcompileInit(java.util.Vector sortObjects, com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSortRecordGenerator sortRecord, com.sun.org.apache.bcel.internal.generic.ConstantPoolGen cpg, java.lang.String className)
Create a constructor for the new class. Updates the reference to the collator in the super calls only when the stylesheet specifies a new language in xsl:sort.

	final InstructionList il = new InstructionList();
	final MethodGenerator init = 
	    new MethodGenerator(ACC_PUBLIC, 
				com.sun.org.apache.bcel.internal.generic.Type.VOID, 
				null, null, "<init>", className, 
				il, cpg);

	// Call the constructor in the NodeSortRecord superclass
	il.append(ALOAD_0);
	il.append(new INVOKESPECIAL(cpg.addMethodref(NODE_SORT_RECORD,
						     "<init>", "()V")));

	

	il.append(RETURN);

	init.stripAttributes(true);
	init.setMaxLocals();
	init.setMaxStack();

	return init.getMethod();
    
private static java.lang.StringcompileSortRecord(java.util.Vector sortObjects, com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)
Create a new auxillary class extending NodeSortRecord.

	final XSLTC  xsltc = ((Sort)sortObjects.firstElement()).getXSLTC();
	final String className = xsltc.getHelperClassName();

	// This generates a new class for handling this specific sort
	final NodeSortRecordGenerator sortRecord =
	    new NodeSortRecordGenerator(className,
					NODE_SORT_RECORD,
					"sort$0.java",
					ACC_PUBLIC | ACC_SUPER | ACC_FINAL,
					new String[] {},
					classGen.getStylesheet());
	
	final ConstantPoolGen cpg = sortRecord.getConstantPool();	

	// Add a new instance variable for each var in closure
	final int nsorts = sortObjects.size();
	final ArrayList dups = new ArrayList();

	for (int j = 0; j < nsorts; j++) {
	    final Sort sort = (Sort) sortObjects.get(j);

	    // Set the name of the inner class in this sort object
	    sort.setInnerClassName(className);	

	    final int length = (sort._closureVars == null) ? 0 : 
		sort._closureVars.size();
	    for (int i = 0; i < length; i++) {
		final VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i);

		// Discard duplicate variable references
		if (dups.contains(varRef)) continue;

		final VariableBase var = varRef.getVariable();
		sortRecord.addField(new Field(ACC_PUBLIC, 
				    cpg.addUtf8(var.getEscapedName()),
				    cpg.addUtf8(var.getType().toSignature()),
				    null, cpg.getConstantPool()));
		dups.add(varRef);
	    }
	}

	Method init = compileInit(sortObjects, sortRecord,
					 cpg, className);
	Method extract = compileExtract(sortObjects, sortRecord,
					cpg, className);
	sortRecord.addMethod(init);
	sortRecord.addMethod(extract);

	xsltc.dumpClass(sortRecord.getJavaClass());
	return className;
    
public static voidcompileSortRecordFactory(java.util.Vector sortObjects, com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)
Compiles code that instantiates a NodeSortRecordFactory object which will produce NodeSortRecord objects of a specific type.

	String sortRecordClass = 
	    compileSortRecord(sortObjects, classGen, methodGen);

	boolean needsSortRecordFactory = false;
	final int nsorts = sortObjects.size();
	for (int i = 0; i < nsorts; i++) {
	    final Sort sort = (Sort) sortObjects.elementAt(i);
	    needsSortRecordFactory |= sort._needsSortRecordFactory;
	}

	String sortRecordFactoryClass = NODE_SORT_FACTORY;
	if (needsSortRecordFactory) {
	    sortRecordFactoryClass = 
		compileSortRecordFactory(sortObjects, classGen, methodGen, 
		    sortRecordClass);
	}

	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();
	
	il.append(new NEW(cpg.addClass(sortRecordFactoryClass)));
	il.append(DUP);
	il.append(methodGen.loadDOM());
	il.append(new PUSH(cpg, sortRecordClass));
	il.append(classGen.loadTranslet());

	// Compile code that initializes the static _sortOrder
	il.append(new PUSH(cpg, nsorts));
	il.append(new ANEWARRAY(cpg.addClass(STRING)));
	for (int level = 0; level < nsorts; level++) {
	    final Sort sort = (Sort)sortObjects.elementAt(level);
	    il.append(DUP);
	    il.append(new PUSH(cpg, level));
	    sort.translateSortOrder(classGen, methodGen);
	    il.append(AASTORE);
	}

	il.append(new PUSH(cpg, nsorts));
	il.append(new ANEWARRAY(cpg.addClass(STRING)));
	for (int level = 0; level < nsorts; level++) {
	    final Sort sort = (Sort)sortObjects.elementAt(level);
	    il.append(DUP);
	    il.append(new PUSH(cpg, level));
	    sort.translateSortType(classGen, methodGen);
	    il.append(AASTORE);
	}
  
  il.append(new PUSH(cpg, nsorts));
  il.append(new ANEWARRAY(cpg.addClass(STRING)));
  for (int level = 0; level < nsorts; level++) {
        final Sort sort = (Sort)sortObjects.elementAt(level);
        il.append(DUP);
        il.append(new PUSH(cpg, level));
        sort.translateLang(classGen, methodGen);
        il.append(AASTORE);
   }
 
   il.append(new PUSH(cpg, nsorts));
   il.append(new ANEWARRAY(cpg.addClass(STRING)));
   for (int level = 0; level < nsorts; level++) {
        final Sort sort = (Sort)sortObjects.elementAt(level);
        il.append(DUP);
        il.append(new PUSH(cpg, level));
        sort.translateCaseOrder(classGen, methodGen);
        il.append(AASTORE);
  }

	il.append(new INVOKESPECIAL(
	    cpg.addMethodref(sortRecordFactoryClass, "<init>", 
		"(" + DOM_INTF_SIG 
		    + STRING_SIG
		    + TRANSLET_INTF_SIG
		    + "[" + STRING_SIG
        + "[" + STRING_SIG
        + "[" + STRING_SIG
		    + "[" + STRING_SIG + ")V")));

	// Initialize closure variables in sortRecordFactory
	final ArrayList dups = new ArrayList();

	for (int j = 0; j < nsorts; j++) {
	    final Sort sort = (Sort) sortObjects.get(j);
	    final int length = (sort._closureVars == null) ? 0 : 
		sort._closureVars.size();

	    for (int i = 0; i < length; i++) {
		VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i);

		// Discard duplicate variable references
		if (dups.contains(varRef)) continue;

		final VariableBase var = varRef.getVariable();

		// Store variable in new closure
		il.append(DUP);
		il.append(var.loadInstruction());
		il.append(new PUTFIELD(
			cpg.addFieldref(sortRecordFactoryClass, var.getEscapedName(), 
			    var.getType().toSignature())));
		dups.add(varRef);
	    }
	}
    
public static java.lang.StringcompileSortRecordFactory(java.util.Vector sortObjects, com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen, java.lang.String sortRecordClass)

	final XSLTC  xsltc = ((Sort)sortObjects.firstElement()).getXSLTC();
	final String className = xsltc.getHelperClassName();

	final NodeSortRecordFactGenerator sortRecordFactory =
	    new NodeSortRecordFactGenerator(className,
					NODE_SORT_FACTORY,
					className + ".java",
					ACC_PUBLIC | ACC_SUPER | ACC_FINAL,
					new String[] {},
					classGen.getStylesheet());

	ConstantPoolGen cpg = sortRecordFactory.getConstantPool();

	// Add a new instance variable for each var in closure
	final int nsorts = sortObjects.size();
	final ArrayList dups = new ArrayList();

	for (int j = 0; j < nsorts; j++) {
	    final Sort sort = (Sort) sortObjects.get(j);
	    final int length = (sort._closureVars == null) ? 0 : 
		sort._closureVars.size();

	    for (int i = 0; i < length; i++) {
		final VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i);

		// Discard duplicate variable references
		if (dups.contains(varRef)) continue;

		final VariableBase var = varRef.getVariable();
		sortRecordFactory.addField(new Field(ACC_PUBLIC, 
					   cpg.addUtf8(var.getEscapedName()),
					   cpg.addUtf8(var.getType().toSignature()),
					   null, cpg.getConstantPool()));
		dups.add(varRef);
	    }
	}

	// Define a constructor for this class
	final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = 
	    new com.sun.org.apache.bcel.internal.generic.Type[7];
	argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
	argTypes[1] = Util.getJCRefType(STRING_SIG);
	argTypes[2] = Util.getJCRefType(TRANSLET_INTF_SIG);
	argTypes[3] = Util.getJCRefType("[" + STRING_SIG);
	argTypes[4] = Util.getJCRefType("[" + STRING_SIG);
  argTypes[5] = Util.getJCRefType("[" + STRING_SIG);
  argTypes[6] = Util.getJCRefType("[" + STRING_SIG);

	final String[] argNames = new String[7];
	argNames[0] = DOCUMENT_PNAME;
	argNames[1] = "className";
	argNames[2] = TRANSLET_PNAME;
	argNames[3] = "order";
	argNames[4] = "type";
  argNames[5] = "lang";
  argNames[6] = "case_order";
  

	InstructionList il = new InstructionList();
	final MethodGenerator constructor =
	    new MethodGenerator(ACC_PUBLIC,
				com.sun.org.apache.bcel.internal.generic.Type.VOID, 
				argTypes, argNames, "<init>", 
				className, il, cpg);

	// Push all parameters onto the stack and called super.<init>()
	il.append(ALOAD_0);
	il.append(ALOAD_1);
	il.append(ALOAD_2);
	il.append(new ALOAD(3));
	il.append(new ALOAD(4));
	il.append(new ALOAD(5));
  il.append(new ALOAD(6));
  il.append(new ALOAD(7));
	il.append(new INVOKESPECIAL(cpg.addMethodref(NODE_SORT_FACTORY,
	    "<init>", 
	    "(" + DOM_INTF_SIG 
		+ STRING_SIG 
		+ TRANSLET_INTF_SIG 
		+ "[" + STRING_SIG
    + "[" + STRING_SIG
    + "[" + STRING_SIG
		+ "[" + STRING_SIG + ")V")));
	il.append(RETURN);

	// Override the definition of makeNodeSortRecord()
	il = new InstructionList(); 
	final MethodGenerator makeNodeSortRecord =
	    new MethodGenerator(ACC_PUBLIC,
		Util.getJCRefType(NODE_SORT_RECORD_SIG), 
		new com.sun.org.apache.bcel.internal.generic.Type[] { 
		    com.sun.org.apache.bcel.internal.generic.Type.INT,
		    com.sun.org.apache.bcel.internal.generic.Type.INT },
		new String[] { "node", "last" }, "makeNodeSortRecord",
		className, il, cpg);

	il.append(ALOAD_0);
	il.append(ILOAD_1);
	il.append(ILOAD_2);
	il.append(new INVOKESPECIAL(cpg.addMethodref(NODE_SORT_FACTORY,
	    "makeNodeSortRecord", "(II)" + NODE_SORT_RECORD_SIG)));
	il.append(DUP);
	il.append(new CHECKCAST(cpg.addClass(sortRecordClass)));

	// Initialize closure in record class
	final int ndups = dups.size();
	for (int i = 0; i < ndups; i++) {
	    final VariableRefBase varRef = (VariableRefBase) dups.get(i);
	    final VariableBase var = varRef.getVariable();
	    final Type varType = var.getType();
	    
	    il.append(DUP);

	    // Get field from factory class
	    il.append(ALOAD_0);
	    il.append(new GETFIELD(
		cpg.addFieldref(className,
		    var.getEscapedName(), varType.toSignature())));

	    // Put field in record class
	    il.append(new PUTFIELD(
		cpg.addFieldref(sortRecordClass,
		    var.getEscapedName(), varType.toSignature())));
	}
	il.append(POP);
	il.append(ARETURN);

	constructor.setMaxLocals();
	constructor.setMaxStack();
	sortRecordFactory.addMethod(constructor.getMethod());
	makeNodeSortRecord.setMaxLocals();
	makeNodeSortRecord.setMaxStack();
	sortRecordFactory.addMethod(makeNodeSortRecord.getMethod());
	xsltc.dumpClass(sortRecordFactory.getJavaClass());

	return className;
    
public java.lang.StringgetInnerClassName()
Returns the name of the auxiliary class or null if this predicate is compiled inside the Translet.

	return _className;
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.ClosuregetParentClosure()
Returns a reference to its parent closure or null if outermost.

	return null;
    
public booleaninInnerClass()
Returns true if this closure is compiled in an inner class (i.e. if this is a real closure).


    // -- Begin Closure interface --------------------

                           
       
	return (_className != null);
    
public voidparseContents(com.sun.org.apache.xalan.internal.xsltc.compiler.Parser parser)
Parse the attributes of the xsl:sort element


	final SyntaxTreeNode parent = getParent();
	if (!(parent instanceof ApplyTemplates) &&
	    !(parent instanceof ForEach)) {
	    reportError(this, parser, ErrorMsg.STRAY_SORT_ERR, null);
	    return;
	}

	// Parse the select expression (node string value if no expression)
	_select = parser.parseExpression(this, "select", "string(.)");

	// Get the sort order; default is 'ascending'
	String val = getAttribute("order");
	if (val.length() == 0) val = "ascending";
	_order = AttributeValue.create(this, val, parser);

	// Get the sort data type; default is text
	val = getAttribute("data-type");
	if (val.length() == 0) {
	    try {
		final Type type = _select.typeCheck(parser.getSymbolTable());
		if (type instanceof IntType)
		    val = "number";
		else
		    val = "text";
	    }
	    catch (TypeCheckError e) {
		val = "text";
	    }
	}
	_dataType = AttributeValue.create(this, val, parser);

	 _lang =  getAttribute("lang"); // bug! see 26869
  // val =  getAttribute("lang"); 
  // _lang = AttributeValue.create(this, val, parser);
        // Get the case order; default is language dependant
    val = getAttribute("case-order");
    _caseOrder = AttributeValue.create(this, val, parser);
	
    
private voidsetInnerClassName(java.lang.String className)

	_className = className;
    
public voidtranslate(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)
This method should not produce any code

	// empty
    
public voidtranslateCaseOrder(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)

    _caseOrder.translate(classGen, methodGen);
    
public voidtranslateLang(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)

    final ConstantPoolGen cpg = classGen.getConstantPool();
    final InstructionList il = methodGen.getInstructionList();
    il.append(new PUSH(cpg, _lang)); // bug! see 26869
    
public voidtranslateSelect(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)
This method compiles code for the select expression for this xsl:sort element. The method is called from the static code-generating methods in this class.

	_select.translate(classGen,methodGen);
    
public static voidtranslateSortIterator(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen, com.sun.org.apache.xalan.internal.xsltc.compiler.Expression nodeSet, java.util.Vector sortObjects)
Compiles code that instantiates a SortingIterator object. This object's constructor needs referencdes to the current iterator and a node sort record producing objects as its parameters.

	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();

	// SortingIterator.SortingIterator(NodeIterator,NodeSortRecordFactory);
	final int init = cpg.addMethodref(SORT_ITERATOR, "<init>",
					  "("
					  + NODE_ITERATOR_SIG
					  + NODE_SORT_FACTORY_SIG
					  + ")V");	

	il.append(new NEW(cpg.addClass(SORT_ITERATOR)));
	il.append(DUP);

	// Get the current node iterator
	if (nodeSet == null) {	// apply-templates default
	    final int children = cpg.addInterfaceMethodref(DOM_INTF,
							   "getAxisIterator",
							   "(I)"+
							   NODE_ITERATOR_SIG);
	    il.append(methodGen.loadDOM());
	    il.append(new PUSH(cpg, Axis.CHILD));
	    il.append(new INVOKEINTERFACE(children, 2));
	}
	else {
	    nodeSet.translate(classGen, methodGen);
	}
	
	// Compile the code for the NodeSortRecord producing class and pass
	// that as the last argument to the SortingIterator constructor.
	compileSortRecordFactory(sortObjects, classGen, methodGen);
	il.append(new INVOKESPECIAL(init));
    
public voidtranslateSortOrder(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)

	_order.translate(classGen, methodGen);
    
public voidtranslateSortType(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)
These two methods are needed in the static methods that compile the overloaded NodeSortRecord.compareType() and NodeSortRecord.sortOrder()

	_dataType.translate(classGen, methodGen);
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypetypeCheck(com.sun.org.apache.xalan.internal.xsltc.compiler.SymbolTable stable)
Run type checks on the attributes; expression must return a string which we will use as a sort key

	final Type tselect = _select.typeCheck(stable);

	// If the sort data-type is not set we use the natural data-type
	// of the data we will sort
	if (!(tselect instanceof StringType)) {
	    _select = new CastExpr(_select, Type.String);
	}

	_order.typeCheck(stable);
	_caseOrder.typeCheck(stable);
	_dataType.typeCheck(stable);
	return Type.Void;