Example #1
0
  /**
   * Compile a buildKeys() method into the output class. Note that keys for the input document are
   * created in topLevel(), not in this method. However, we still need this method to create keys
   * for documents loaded via the XPath document() function.
   */
  private String compileBuildKeys(ClassGenerator classGen) {
    final ConstantPoolGen cpg = classGen.getConstantPool();

    final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = {
      Util.getJCRefType(DOM_INTF_SIG),
      Util.getJCRefType(NODE_ITERATOR_SIG),
      Util.getJCRefType(TRANSLET_OUTPUT_SIG),
      com.sun.org.apache.bcel.internal.generic.Type.INT
    };

    final String[] argNames = {DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME, "current"};

    final InstructionList il = new InstructionList();

    final MethodGenerator buildKeys =
        new MethodGenerator(
            ACC_PUBLIC,
            com.sun.org.apache.bcel.internal.generic.Type.VOID,
            argTypes,
            argNames,
            "buildKeys",
            _className,
            il,
            classGen.getConstantPool());

    buildKeys.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");

    final Enumeration elements = elements();
    while (elements.hasMoreElements()) {
      // xsl:key
      final Object element = elements.nextElement();
      if (element instanceof Key) {
        final Key key = (Key) element;
        key.translate(classGen, buildKeys);
        _keys.put(key.getName(), key);
      }
    }

    il.append(RETURN);

    // Compute max locals + stack and add method to class
    buildKeys.stripAttributes(true);
    buildKeys.setMaxLocals();
    buildKeys.setMaxStack();
    buildKeys.removeNOPs();

    classGen.addMethod(buildKeys.getMethod());

    return ("(" + DOM_INTF_SIG + NODE_ITERATOR_SIG + TRANSLET_OUTPUT_SIG + "I)V");
  }
Example #2
0
  /**
   * Compile a topLevel() method into the output class. This method is called from transform() to
   * handle all non-template top-level elements. Returns the signature of the topLevel() method.
   *
   * <p>Global variables/params and keys are first sorted to resolve dependencies between them. The
   * XSLT 1.0 spec does not allow a key to depend on a variable. However, for compatibility with
   * Xalan interpretive, that type of dependency is allowed. Note also that the buildKeys() method
   * is still generated as it is used by the LoadDocument class, but it no longer called from
   * transform().
   */
  private String compileTopLevel(ClassGenerator classGen) {

    final ConstantPoolGen cpg = classGen.getConstantPool();

    final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = {
      Util.getJCRefType(DOM_INTF_SIG),
      Util.getJCRefType(NODE_ITERATOR_SIG),
      Util.getJCRefType(TRANSLET_OUTPUT_SIG)
    };

    final String[] argNames = {DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME};

    final InstructionList il = new InstructionList();

    final MethodGenerator toplevel =
        new MethodGenerator(
            ACC_PUBLIC,
            com.sun.org.apache.bcel.internal.generic.Type.VOID,
            argTypes,
            argNames,
            "topLevel",
            _className,
            il,
            classGen.getConstantPool());

    toplevel.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");

    // Define and initialize 'current' variable with the root node
    final LocalVariableGen current =
        toplevel.addLocalVariable(
            "current", com.sun.org.apache.bcel.internal.generic.Type.INT, null, null);

    final int setFilter =
        cpg.addInterfaceMethodref(
            DOM_INTF, "setFilter", "(Lcom/sun/org/apache/xalan/internal/xsltc/StripFilter;)V");

    final int gitr = cpg.addInterfaceMethodref(DOM_INTF, "getIterator", "()" + NODE_ITERATOR_SIG);
    il.append(toplevel.loadDOM());
    il.append(new INVOKEINTERFACE(gitr, 1));
    il.append(toplevel.nextNode());
    current.setStart(il.append(new ISTORE(current.getIndex())));

    // Create a new list containing variables/params + keys
    Vector varDepElements = new Vector(_globals);
    Enumeration elements = elements();
    while (elements.hasMoreElements()) {
      final Object element = elements.nextElement();
      if (element instanceof Key) {
        varDepElements.add(element);
      }
    }

    // Determine a partial order for the variables/params and keys
    varDepElements = resolveDependencies(varDepElements);

    // Translate vars/params and keys in the right order
    final int count = varDepElements.size();
    for (int i = 0; i < count; i++) {
      final TopLevelElement tle = (TopLevelElement) varDepElements.elementAt(i);
      tle.translate(classGen, toplevel);
      if (tle instanceof Key) {
        final Key key = (Key) tle;
        _keys.put(key.getName(), key);
      }
    }

    // Compile code for other top-level elements
    Vector whitespaceRules = new Vector();
    elements = elements();
    while (elements.hasMoreElements()) {
      final Object element = elements.nextElement();
      // xsl:decimal-format
      if (element instanceof DecimalFormatting) {
        ((DecimalFormatting) element).translate(classGen, toplevel);
      }
      // xsl:strip/preserve-space
      else if (element instanceof Whitespace) {
        whitespaceRules.addAll(((Whitespace) element).getRules());
      }
    }

    // Translate all whitespace strip/preserve rules
    if (whitespaceRules.size() > 0) {
      Whitespace.translateRules(whitespaceRules, classGen);
    }

    if (classGen.containsMethod(STRIP_SPACE, STRIP_SPACE_PARAMS) != null) {
      il.append(toplevel.loadDOM());
      il.append(classGen.loadTranslet());
      il.append(new INVOKEINTERFACE(setFilter, 2));
    }

    il.append(RETURN);

    // Compute max locals + stack and add method to class
    classGen.addMethod(toplevel);

    return ("(" + DOM_INTF_SIG + NODE_ITERATOR_SIG + TRANSLET_OUTPUT_SIG + ")V");
  }
Example #3
0
  /** Compile the translet's constructor */
  private void compileConstructor(ClassGenerator classGen, Output output) {

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

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

    // Call the constructor in the AbstractTranslet superclass
    il.append(classGen.loadTranslet());
    il.append(new INVOKESPECIAL(cpg.addMethodref(TRANSLET_CLASS, "<init>", "()V")));

    constructor.markChunkStart();
    il.append(classGen.loadTranslet());
    il.append(
        new GETSTATIC(cpg.addFieldref(_className, STATIC_NAMES_ARRAY_FIELD, NAMES_INDEX_SIG)));
    il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS, NAMES_INDEX, NAMES_INDEX_SIG)));

    il.append(classGen.loadTranslet());
    il.append(new GETSTATIC(cpg.addFieldref(_className, STATIC_URIS_ARRAY_FIELD, URIS_INDEX_SIG)));
    il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS, URIS_INDEX, URIS_INDEX_SIG)));
    constructor.markChunkEnd();

    constructor.markChunkStart();
    il.append(classGen.loadTranslet());
    il.append(
        new GETSTATIC(cpg.addFieldref(_className, STATIC_TYPES_ARRAY_FIELD, TYPES_INDEX_SIG)));
    il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS, TYPES_INDEX, TYPES_INDEX_SIG)));
    constructor.markChunkEnd();

    constructor.markChunkStart();
    il.append(classGen.loadTranslet());
    il.append(
        new GETSTATIC(
            cpg.addFieldref(_className, STATIC_NAMESPACE_ARRAY_FIELD, NAMESPACE_INDEX_SIG)));
    il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS, NAMESPACE_INDEX, NAMESPACE_INDEX_SIG)));
    constructor.markChunkEnd();

    constructor.markChunkStart();
    il.append(classGen.loadTranslet());
    il.append(new PUSH(cpg, AbstractTranslet.CURRENT_TRANSLET_VERSION));
    il.append(
        new PUTFIELD(
            cpg.addFieldref(TRANSLET_CLASS, TRANSLET_VERSION_INDEX, TRANSLET_VERSION_INDEX_SIG)));
    constructor.markChunkEnd();

    if (_hasIdCall) {
      constructor.markChunkStart();
      il.append(classGen.loadTranslet());
      il.append(new PUSH(cpg, Boolean.TRUE));
      il.append(
          new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS, HASIDCALL_INDEX, HASIDCALL_INDEX_SIG)));
      constructor.markChunkEnd();
    }

    // Compile in code to set the output configuration from <xsl:output>
    if (output != null) {
      // Set all the output settings files in the translet
      constructor.markChunkStart();
      output.translate(classGen, constructor);
      constructor.markChunkEnd();
    }

    // Compile default decimal formatting symbols.
    // This is an implicit, nameless xsl:decimal-format top-level element.
    if (_numberFormattingUsed) {
      constructor.markChunkStart();
      DecimalFormatting.translateDefaultDFS(classGen, constructor);
      constructor.markChunkEnd();
    }

    il.append(RETURN);

    classGen.addMethod(constructor);
  }
Example #4
0
  /**
   * Compile the namesArray, urisArray and typesArray into the static initializer. They are
   * read-only from the translet. All translet instances can share a single copy of this informtion.
   */
  private void compileStaticInitializer(ClassGenerator classGen) {
    final ConstantPoolGen cpg = classGen.getConstantPool();
    final InstructionList il = new InstructionList();

    final MethodGenerator staticConst =
        new MethodGenerator(
            ACC_PUBLIC | ACC_STATIC,
            com.sun.org.apache.bcel.internal.generic.Type.VOID,
            null,
            null,
            "<clinit>",
            _className,
            il,
            cpg);

    addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMES_ARRAY_FIELD);
    addStaticField(classGen, "[" + STRING_SIG, STATIC_URIS_ARRAY_FIELD);
    addStaticField(classGen, "[I", STATIC_TYPES_ARRAY_FIELD);
    addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMESPACE_ARRAY_FIELD);
    // Create fields of type char[] that will contain literal text from
    // the stylesheet.
    final int charDataFieldCount = getXSLTC().getCharacterDataCount();
    for (int i = 0; i < charDataFieldCount; i++) {
      addStaticField(classGen, STATIC_CHAR_DATA_FIELD_SIG, STATIC_CHAR_DATA_FIELD + i);
    }

    // Put the names array into the translet - used for dom/translet mapping
    final Vector namesIndex = getXSLTC().getNamesIndex();
    int size = namesIndex.size();
    String[] namesArray = new String[size];
    String[] urisArray = new String[size];
    int[] typesArray = new int[size];

    int index;
    for (int i = 0; i < size; i++) {
      String encodedName = (String) namesIndex.elementAt(i);
      if ((index = encodedName.lastIndexOf(':')) > -1) {
        urisArray[i] = encodedName.substring(0, index);
      }

      index = index + 1;
      if (encodedName.charAt(index) == '@') {
        typesArray[i] = DTM.ATTRIBUTE_NODE;
        index++;
      } else if (encodedName.charAt(index) == '?') {
        typesArray[i] = DTM.NAMESPACE_NODE;
        index++;
      } else {
        typesArray[i] = DTM.ELEMENT_NODE;
      }

      if (index == 0) {
        namesArray[i] = encodedName;
      } else {
        namesArray[i] = encodedName.substring(index);
      }
    }

    staticConst.markChunkStart();
    il.append(new PUSH(cpg, size));
    il.append(new ANEWARRAY(cpg.addClass(STRING)));
    int namesArrayRef = cpg.addFieldref(_className, STATIC_NAMES_ARRAY_FIELD, NAMES_INDEX_SIG);
    il.append(new PUTSTATIC(namesArrayRef));
    staticConst.markChunkEnd();

    for (int i = 0; i < size; i++) {
      final String name = namesArray[i];
      staticConst.markChunkStart();
      il.append(new GETSTATIC(namesArrayRef));
      il.append(new PUSH(cpg, i));
      il.append(new PUSH(cpg, name));
      il.append(AASTORE);
      staticConst.markChunkEnd();
    }

    staticConst.markChunkStart();
    il.append(new PUSH(cpg, size));
    il.append(new ANEWARRAY(cpg.addClass(STRING)));
    int urisArrayRef = cpg.addFieldref(_className, STATIC_URIS_ARRAY_FIELD, URIS_INDEX_SIG);
    il.append(new PUTSTATIC(urisArrayRef));
    staticConst.markChunkEnd();

    for (int i = 0; i < size; i++) {
      final String uri = urisArray[i];
      staticConst.markChunkStart();
      il.append(new GETSTATIC(urisArrayRef));
      il.append(new PUSH(cpg, i));
      il.append(new PUSH(cpg, uri));
      il.append(AASTORE);
      staticConst.markChunkEnd();
    }

    staticConst.markChunkStart();
    il.append(new PUSH(cpg, size));
    il.append(new NEWARRAY(BasicType.INT));
    int typesArrayRef = cpg.addFieldref(_className, STATIC_TYPES_ARRAY_FIELD, TYPES_INDEX_SIG);
    il.append(new PUTSTATIC(typesArrayRef));
    staticConst.markChunkEnd();

    for (int i = 0; i < size; i++) {
      final int nodeType = typesArray[i];
      staticConst.markChunkStart();
      il.append(new GETSTATIC(typesArrayRef));
      il.append(new PUSH(cpg, i));
      il.append(new PUSH(cpg, nodeType));
      il.append(IASTORE);
    }

    // Put the namespace names array into the translet
    final Vector namespaces = getXSLTC().getNamespaceIndex();
    staticConst.markChunkStart();
    il.append(new PUSH(cpg, namespaces.size()));
    il.append(new ANEWARRAY(cpg.addClass(STRING)));
    int namespaceArrayRef =
        cpg.addFieldref(_className, STATIC_NAMESPACE_ARRAY_FIELD, NAMESPACE_INDEX_SIG);
    il.append(new PUTSTATIC(namespaceArrayRef));
    staticConst.markChunkEnd();

    for (int i = 0; i < namespaces.size(); i++) {
      final String ns = (String) namespaces.elementAt(i);
      staticConst.markChunkStart();
      il.append(new GETSTATIC(namespaceArrayRef));
      il.append(new PUSH(cpg, i));
      il.append(new PUSH(cpg, ns));
      il.append(AASTORE);
      staticConst.markChunkEnd();
    }

    // Grab all the literal text in the stylesheet and put it in a char[]
    final int charDataCount = getXSLTC().getCharacterDataCount();
    final int toCharArray = cpg.addMethodref(STRING, "toCharArray", "()[C");
    for (int i = 0; i < charDataCount; i++) {
      staticConst.markChunkStart();
      il.append(new PUSH(cpg, getXSLTC().getCharacterData(i)));
      il.append(new INVOKEVIRTUAL(toCharArray));
      il.append(
          new PUTSTATIC(
              cpg.addFieldref(_className, STATIC_CHAR_DATA_FIELD + i, STATIC_CHAR_DATA_FIELD_SIG)));
      staticConst.markChunkEnd();
    }

    il.append(RETURN);

    classGen.addMethod(staticConst);
  }
Example #5
0
  /**
   * Compile transform() into the output class. This method is used to initialize global variables
   * and global parameters. The current node is set to be the document's root node.
   */
  private void compileTransform(ClassGenerator classGen) {
    final ConstantPoolGen cpg = classGen.getConstantPool();

    /*
     * Define the the method transform with the following signature:
     * void transform(DOM, NodeIterator, HandlerBase)
     */
    final com.sun.org.apache.bcel.internal.generic.Type[] argTypes =
        new com.sun.org.apache.bcel.internal.generic.Type[3];
    argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
    argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
    argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);

    final String[] argNames = new String[3];
    argNames[0] = DOCUMENT_PNAME;
    argNames[1] = ITERATOR_PNAME;
    argNames[2] = TRANSLET_OUTPUT_PNAME;

    final InstructionList il = new InstructionList();
    final MethodGenerator transf =
        new MethodGenerator(
            ACC_PUBLIC,
            com.sun.org.apache.bcel.internal.generic.Type.VOID,
            argTypes,
            argNames,
            "transform",
            _className,
            il,
            classGen.getConstantPool());
    transf.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");

    // Define and initialize current with the root node
    final LocalVariableGen current =
        transf.addLocalVariable(
            "current", com.sun.org.apache.bcel.internal.generic.Type.INT, null, null);
    final String applyTemplatesSig = classGen.getApplyTemplatesSig();
    final int applyTemplates =
        cpg.addMethodref(getClassName(), "applyTemplates", applyTemplatesSig);
    final int domField = cpg.addFieldref(getClassName(), DOM_FIELD, DOM_INTF_SIG);

    // push translet for PUTFIELD
    il.append(classGen.loadTranslet());
    // prepare appropriate DOM implementation

    if (isMultiDocument()) {
      il.append(new NEW(cpg.addClass(MULTI_DOM_CLASS)));
      il.append(DUP);
    }

    il.append(classGen.loadTranslet());
    il.append(transf.loadDOM());
    il.append(
        new INVOKEVIRTUAL(
            cpg.addMethodref(
                TRANSLET_CLASS, "makeDOMAdapter", "(" + DOM_INTF_SIG + ")" + DOM_ADAPTER_SIG)));
    // DOMAdapter is on the stack

    if (isMultiDocument()) {
      final int init = cpg.addMethodref(MULTI_DOM_CLASS, "<init>", "(" + DOM_INTF_SIG + ")V");
      il.append(new INVOKESPECIAL(init));
      // MultiDOM is on the stack
    }

    // store to _dom variable
    il.append(new PUTFIELD(domField));

    // continue with globals initialization
    final int gitr = cpg.addInterfaceMethodref(DOM_INTF, "getIterator", "()" + NODE_ITERATOR_SIG);
    il.append(transf.loadDOM());
    il.append(new INVOKEINTERFACE(gitr, 1));
    il.append(transf.nextNode());
    current.setStart(il.append(new ISTORE(current.getIndex())));

    // Transfer the output settings to the output post-processor
    il.append(classGen.loadTranslet());
    il.append(transf.loadHandler());
    final int index =
        cpg.addMethodref(TRANSLET_CLASS, "transferOutputSettings", "(" + OUTPUT_HANDLER_SIG + ")V");
    il.append(new INVOKEVIRTUAL(index));

    /*
     * Compile buildKeys() method. Note that this method is not
     * invoked here as keys for the input document are now created
     * in topLevel(). However, this method is still needed by the
     * LoadDocument class.
     */
    final String keySig = compileBuildKeys(classGen);
    final int keyIdx = cpg.addMethodref(getClassName(), "buildKeys", keySig);

    // Look for top-level elements that need handling
    final Enumeration toplevel = elements();
    if (_globals.size() > 0 || toplevel.hasMoreElements()) {
      // Compile method for handling top-level elements
      final String topLevelSig = compileTopLevel(classGen);
      // Get a reference to that method
      final int topLevelIdx = cpg.addMethodref(getClassName(), "topLevel", topLevelSig);
      // Push all parameters on the stack and call topLevel()
      il.append(classGen.loadTranslet()); // The 'this' pointer
      il.append(classGen.loadTranslet());
      il.append(new GETFIELD(domField)); // The DOM reference
      il.append(transf.loadIterator());
      il.append(transf.loadHandler()); // The output handler
      il.append(new INVOKEVIRTUAL(topLevelIdx));
    }

    // start document
    il.append(transf.loadHandler());
    il.append(transf.startDocument());

    // push first arg for applyTemplates
    il.append(classGen.loadTranslet());
    // push translet for GETFIELD to get DOM arg
    il.append(classGen.loadTranslet());
    il.append(new GETFIELD(domField));
    // push remaining 2 args
    il.append(transf.loadIterator());
    il.append(transf.loadHandler());
    il.append(new INVOKEVIRTUAL(applyTemplates));
    // endDocument
    il.append(transf.loadHandler());
    il.append(transf.endDocument());

    il.append(RETURN);

    // Compute max locals + stack and add method to class
    classGen.addMethod(transf);
  }