alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Stylesheet.java)

This example Java source code file (Stylesheet.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

constantpoolgen, enumeration, hashtable, instructionlist, key, methodgenerator, mode, output, push, putstatic, string, stylesheet, template, util, vector

The Stylesheet.java Java example source code

/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
/*
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id: Stylesheet.java,v 1.5 2005/09/28 13:48:16 pvedula Exp $
 */

package com.sun.org.apache.xalan.internal.xsltc.compiler;

import java.util.Vector;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import java.util.StringTokenizer;

import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
import com.sun.org.apache.bcel.internal.generic.ANEWARRAY;
import com.sun.org.apache.bcel.internal.generic.BasicType;
import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
import com.sun.org.apache.bcel.internal.generic.FieldGen;
import com.sun.org.apache.bcel.internal.generic.GETFIELD;
import com.sun.org.apache.bcel.internal.generic.GETSTATIC;
import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
import com.sun.org.apache.bcel.internal.generic.ISTORE;
import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
import com.sun.org.apache.bcel.internal.generic.InstructionList;
import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.sun.org.apache.bcel.internal.generic.NEWARRAY;
import com.sun.org.apache.bcel.internal.generic.PUSH;
import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
import com.sun.org.apache.bcel.internal.generic.PUTSTATIC;
import com.sun.org.apache.bcel.internal.generic.TargetLostException;
import com.sun.org.apache.bcel.internal.util.InstructionFinder;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTM;

/**
 * @author Jacek Ambroziak
 * @author Santiago Pericas-Geertsen
 * @author Morten Jorgensen
 */
public final class Stylesheet extends SyntaxTreeNode {

    /**
     * XSLT version defined in the stylesheet.
     */
    private String _version;

    /**
     * Internal name of this stylesheet used as a key into the symbol table.
     */
    private QName _name;

    /**
     * A URI that represents the system ID for this stylesheet.
     */
    private String _systemId;

    /**
     * A reference to the parent stylesheet or null if topmost.
     */
    private Stylesheet _parentStylesheet;

    /**
     * Contains global variables and parameters defined in the stylesheet.
     */
    private Vector _globals = new Vector();

    /**
     * Used to cache the result returned by <code>hasLocalParams().
     */
    private Boolean _hasLocalParams = null;

    /**
     * The name of the class being generated.
     */
    private String _className;

    /**
      * Contains all templates defined in this stylesheet
      */
    private final Vector _templates = new Vector();

    /**
     * Used to cache result of <code>getAllValidTemplates(). Only
     * set in top-level stylesheets that include/import other stylesheets.
     */
    private Vector _allValidTemplates = null;

    /**
     * Counter to generate unique mode suffixes.
     */
    private int _nextModeSerial = 1;

    /**
     * Mapping between mode names and Mode instances.
     */
    private final Hashtable _modes = new Hashtable();

    /**
     * A reference to the default Mode object.
     */
    private Mode _defaultMode;

    /**
     * Mapping between extension URIs and their prefixes.
     */
    private final Hashtable _extensions = new Hashtable();

    /**
     * Reference to the stylesheet from which this stylesheet was
     * imported (if any).
     */
    public Stylesheet _importedFrom = null;

    /**
     * Reference to the stylesheet from which this stylesheet was
     * included (if any).
     */
    public Stylesheet _includedFrom = null;

    /**
     * Array of all the stylesheets imported or included from this one.
     */
    private Vector _includedStylesheets = null;

    /**
     * Import precendence for this stylesheet.
     */
    private int _importPrecedence = 1;

    /**
     * Minimum precendence of any descendant stylesheet by inclusion or
     * importation.
     */
    private int _minimumDescendantPrecedence = -1;

    /**
     * Mapping between key names and Key objects (needed by Key/IdPattern).
     */
    private Hashtable _keys = new Hashtable();

    /**
     * A reference to the SourceLoader set by the user (a URIResolver
     * if the JAXP API is being used).
     */
    private SourceLoader _loader = null;

    /**
     * Flag indicating if format-number() is called.
     */
    private boolean _numberFormattingUsed = false;

    /**
     * Flag indicating if this is a simplified stylesheets. A template
     * matching on "/" must be added in this case.
     */
    private boolean _simplified = false;

    /**
     * Flag indicating if multi-document support is needed.
     */
    private boolean _multiDocument = false;

    /**
     * Flag indicating if nodset() is called.
     */
    private boolean _callsNodeset = false;

    /**
     * Flag indicating if id() is called.
     */
    private boolean _hasIdCall = false;

    /**
     * Set to true to enable template inlining optimization.
     * @see XSLTC#_templateInlining
     */
    private boolean _templateInlining = false;

    /**
     * A reference to the last xsl:output object found in the styleshet.
     */
    private Output  _lastOutputElement = null;

    /**
     * Output properties for this stylesheet.
     */
    private Properties _outputProperties = null;

    /**
     * Output method for this stylesheet (must be set to one of
     * the constants defined below).
     */
    private int _outputMethod = UNKNOWN_OUTPUT;

    // Output method constants
    public static final int UNKNOWN_OUTPUT = 0;
    public static final int XML_OUTPUT     = 1;
    public static final int HTML_OUTPUT    = 2;
    public static final int TEXT_OUTPUT    = 3;

    /**
     * Return the output method
     */
    public int getOutputMethod() {
        return _outputMethod;
    }

    /**
     * Check and set the output method
     */
    private void checkOutputMethod() {
        if (_lastOutputElement != null) {
            String method = _lastOutputElement.getOutputMethod();
            if (method != null) {
                if (method.equals("xml"))
                    _outputMethod = XML_OUTPUT;
                else if (method.equals("html"))
                    _outputMethod = HTML_OUTPUT;
                else if (method.equals("text"))
                    _outputMethod = TEXT_OUTPUT;
            }
        }
    }

    public boolean getTemplateInlining() {
        return _templateInlining;
    }

    public void setTemplateInlining(boolean flag) {
        _templateInlining = flag;
    }

    public boolean isSimplified() {
        return(_simplified);
    }

    public void setSimplified() {
        _simplified = true;
    }

    public void setHasIdCall(boolean flag) {
        _hasIdCall = flag;
    }

    public void setOutputProperty(String key, String value) {
        if (_outputProperties == null) {
            _outputProperties = new Properties();
        }
        _outputProperties.setProperty(key, value);
    }

    public void setOutputProperties(Properties props) {
        _outputProperties = props;
    }

    public Properties getOutputProperties() {
        return _outputProperties;
    }

    public Output getLastOutputElement() {
        return _lastOutputElement;
    }

    public void setMultiDocument(boolean flag) {
        _multiDocument = flag;
    }

    public boolean isMultiDocument() {
        return _multiDocument;
    }

    public void setCallsNodeset(boolean flag) {
        if (flag) setMultiDocument(flag);
        _callsNodeset = flag;
    }

    public boolean callsNodeset() {
        return _callsNodeset;
    }

    public void numberFormattingUsed() {
        _numberFormattingUsed = true;
        /*
         * Fix for bug 23046, if the stylesheet is included, set the
         * numberFormattingUsed flag to the parent stylesheet too.
         * AbstractTranslet.addDecimalFormat() will be inlined once for the
         * outer most stylesheet.
         */
        Stylesheet parent = getParentStylesheet();
        if (null != parent) parent.numberFormattingUsed();
    }

    public void setImportPrecedence(final int precedence) {
        // Set import precedence for this stylesheet
        _importPrecedence = precedence;

        // Set import precedence for all included stylesheets
        final Enumeration elements = elements();
        while (elements.hasMoreElements()) {
            SyntaxTreeNode child = (SyntaxTreeNode)elements.nextElement();
            if (child instanceof Include) {
                Stylesheet included = ((Include)child).getIncludedStylesheet();
                if (included != null && included._includedFrom == this) {
                    included.setImportPrecedence(precedence);
                }
            }
        }

        // Set import precedence for the stylesheet that imported this one
        if (_importedFrom != null) {
            if (_importedFrom.getImportPrecedence() < precedence) {
                final Parser parser = getParser();
                final int nextPrecedence = parser.getNextImportPrecedence();
                _importedFrom.setImportPrecedence(nextPrecedence);
            }
        }
        // Set import precedence for the stylesheet that included this one
        else if (_includedFrom != null) {
            if (_includedFrom.getImportPrecedence() != precedence)
                _includedFrom.setImportPrecedence(precedence);
        }
    }

    public int getImportPrecedence() {
        return _importPrecedence;
    }

    /**
     * Get the minimum of the precedence of this stylesheet, any stylesheet
     * imported by this stylesheet and any include/import descendant of this
     * stylesheet.
     */
    public int getMinimumDescendantPrecedence() {
        if (_minimumDescendantPrecedence == -1) {
            // Start with precedence of current stylesheet as a basis.
            int min = getImportPrecedence();

            // Recursively examine all imported/included stylesheets.
            final int inclImpCount = (_includedStylesheets != null)
                                          ? _includedStylesheets.size()
                                          : 0;

            for (int i = 0; i < inclImpCount; i++) {
                int prec = ((Stylesheet)_includedStylesheets.elementAt(i))
                                              .getMinimumDescendantPrecedence();

                if (prec < min) {
                    min = prec;
                }
            }

            _minimumDescendantPrecedence = min;
        }
        return _minimumDescendantPrecedence;
    }

    public boolean checkForLoop(String systemId) {
        // Return true if this stylesheet includes/imports itself
        if (_systemId != null && _systemId.equals(systemId)) {
            return true;
        }
        // Then check with any stylesheets that included/imported this one
        if (_parentStylesheet != null)
            return _parentStylesheet.checkForLoop(systemId);
        // Otherwise OK
        return false;
    }

    public void setParser(Parser parser) {
        super.setParser(parser);
        _name = makeStylesheetName("__stylesheet_");
    }

    public void setParentStylesheet(Stylesheet parent) {
        _parentStylesheet = parent;
    }

    public Stylesheet getParentStylesheet() {
        return _parentStylesheet;
    }

    public void setImportingStylesheet(Stylesheet parent) {
        _importedFrom = parent;
        parent.addIncludedStylesheet(this);
    }

    public void setIncludingStylesheet(Stylesheet parent) {
        _includedFrom = parent;
        parent.addIncludedStylesheet(this);
    }

    public void addIncludedStylesheet(Stylesheet child) {
        if (_includedStylesheets == null) {
            _includedStylesheets = new Vector();
        }
        _includedStylesheets.addElement(child);
    }

    public void setSystemId(String systemId) {
        if (systemId != null) {
            _systemId = SystemIDResolver.getAbsoluteURI(systemId);
        }
    }

    public String getSystemId() {
        return _systemId;
    }

    public void setSourceLoader(SourceLoader loader) {
        _loader = loader;
    }

    public SourceLoader getSourceLoader() {
        return _loader;
    }

    private QName makeStylesheetName(String prefix) {
        return getParser().getQName(prefix+getXSLTC().nextStylesheetSerial());
    }

    /**
     * Returns true if this stylesheet has global vars or params.
     */
    public boolean hasGlobals() {
        return _globals.size() > 0;
    }

    /**
     * Returns true if at least one template in the stylesheet has params
     * defined. Uses the variable <code>_hasLocalParams to cache the
     * result.
     */
    public boolean hasLocalParams() {
        if (_hasLocalParams == null) {
            Vector templates = getAllValidTemplates();
            final int n = templates.size();
            for (int i = 0; i < n; i++) {
                final Template template = (Template)templates.elementAt(i);
                if (template.hasParams()) {
                    _hasLocalParams = Boolean.TRUE;
                    return true;
                }
            }
            _hasLocalParams = Boolean.FALSE;
            return false;
        }
        else {
            return _hasLocalParams.booleanValue();
        }
    }

    /**
     * Adds a single prefix mapping to this syntax tree node.
     * @param prefix Namespace prefix.
     * @param uri Namespace URI.
     */
    protected void addPrefixMapping(String prefix, String uri) {
        if (prefix.equals(EMPTYSTRING) && uri.equals(XHTML_URI)) return;
        super.addPrefixMapping(prefix, uri);
    }

    /**
     * Store extension URIs
     */
    private void extensionURI(String prefixes, SymbolTable stable) {
        if (prefixes != null) {
            StringTokenizer tokens = new StringTokenizer(prefixes);
            while (tokens.hasMoreTokens()) {
                final String prefix = tokens.nextToken();
                final String uri = lookupNamespace(prefix);
                if (uri != null) {
                    _extensions.put(uri, prefix);
                }
            }
        }
    }

    public boolean isExtension(String uri) {
        return (_extensions.get(uri) != null);
    }

    public void declareExtensionPrefixes(Parser parser) {
        final SymbolTable stable = parser.getSymbolTable();
        final String extensionPrefixes = getAttribute("extension-element-prefixes");
        extensionURI(extensionPrefixes, stable);
    }

    /**
     * Parse the version and uri fields of the stylesheet and add an
     * entry to the symbol table mapping the name <tt>__stylesheet_
     * to an instance of this class.
     */
    public void parseContents(Parser parser) {
        final SymbolTable stable = parser.getSymbolTable();

        /*
        // Make sure the XSL version set in this stylesheet
        if ((_version == null) || (_version.equals(EMPTYSTRING))) {
            reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR,"version");
        }
        // Verify that the version is 1.0 and nothing else
        else if (!_version.equals("1.0")) {
            reportError(this, parser, ErrorMsg.XSL_VERSION_ERR, _version);
        }
        */

        // Add the implicit mapping of 'xml' to the XML namespace URI
        addPrefixMapping("xml", "http://www.w3.org/XML/1998/namespace");

        // Report and error if more than one stylesheet defined
        final Stylesheet sheet = stable.addStylesheet(_name, this);
        if (sheet != null) {
            // Error: more that one stylesheet defined
            ErrorMsg err = new ErrorMsg(ErrorMsg.MULTIPLE_STYLESHEET_ERR,this);
            parser.reportError(Constants.ERROR, err);
        }

        // If this is a simplified stylesheet we must create a template that
        // grabs the root node of the input doc ( <xsl:template match="/"/> ).
        // This template needs the current element (the one passed to this
        // method) as its only child, so the Template class has a special
        // method that handles this (parseSimplified()).
        if (_simplified) {
            stable.excludeURI(XSLT_URI);
            Template template = new Template();
            template.parseSimplified(this, parser);
        }
        // Parse the children of this node
        else {
            parseOwnChildren(parser);
        }
    }

    /**
     * Parse all direct children of the <xsl:stylesheet/> element.
     */
    public final void parseOwnChildren(Parser parser) {
        final SymbolTable stable = parser.getSymbolTable();
        final String excludePrefixes = getAttribute("exclude-result-prefixes");
        final String extensionPrefixes = getAttribute("extension-element-prefixes");

        // Exclude XSLT uri
        stable.pushExcludedNamespacesContext();
        stable.excludeURI(Constants.XSLT_URI);
        stable.excludeNamespaces(excludePrefixes);
        stable.excludeNamespaces(extensionPrefixes);

        final Vector contents = getContents();
        final int count = contents.size();

        // We have to scan the stylesheet element's top-level elements for
        // variables and/or parameters before we parse the other elements
        for (int i = 0; i < count; i++) {
            SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
            if ((child instanceof VariableBase) ||
                (child instanceof NamespaceAlias)) {
                parser.getSymbolTable().setCurrentNode(child);
                child.parseContents(parser);
            }
        }

        // Now go through all the other top-level elements...
        for (int i = 0; i < count; i++) {
            SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
            if (!(child instanceof VariableBase) &&
                !(child instanceof NamespaceAlias)) {
                parser.getSymbolTable().setCurrentNode(child);
                child.parseContents(parser);
            }

            // All template code should be compiled as methods if the
            // <xsl:apply-imports/> element was ever used in this stylesheet
            if (!_templateInlining && (child instanceof Template)) {
                Template template = (Template)child;
                String name = "template$dot$" + template.getPosition();
                template.setName(parser.getQName(name));
            }
        }

        stable.popExcludedNamespacesContext();
    }

    public void processModes() {
        if (_defaultMode == null)
            _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
        _defaultMode.processPatterns(_keys);
        final Enumeration modes = _modes.elements();
        while (modes.hasMoreElements()) {
            final Mode mode = (Mode)modes.nextElement();
            mode.processPatterns(_keys);
        }
    }

    private void compileModes(ClassGenerator classGen) {
        _defaultMode.compileApplyTemplates(classGen);
        final Enumeration modes = _modes.elements();
        while (modes.hasMoreElements()) {
            final Mode mode = (Mode)modes.nextElement();
            mode.compileApplyTemplates(classGen);
        }
    }

    public Mode getMode(QName modeName) {
        if (modeName == null) {
            if (_defaultMode == null) {
                _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
            }
            return _defaultMode;
        }
        else {
            Mode mode = (Mode)_modes.get(modeName);
            if (mode == null) {
                final String suffix = Integer.toString(_nextModeSerial++);
                _modes.put(modeName, mode = new Mode(modeName, this, suffix));
            }
            return mode;
        }
    }

    /**
     * Type check all the children of this node.
     */
    public Type typeCheck(SymbolTable stable) throws TypeCheckError {
        final int count = _globals.size();
        for (int i = 0; i < count; i++) {
            final VariableBase var = (VariableBase)_globals.elementAt(i);
            var.typeCheck(stable);
        }
        return typeCheckContents(stable);
    }

    /**
     * Translate the stylesheet into JVM bytecodes.
     */
    public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
        translate();
    }

    private void addDOMField(ClassGenerator classGen) {
        final FieldGen fgen = new FieldGen(ACC_PUBLIC,
                                           Util.getJCRefType(DOM_INTF_SIG),
                                           DOM_FIELD,
                                           classGen.getConstantPool());
        classGen.addField(fgen.getField());
    }

    /**
     * Add a static field
     */
    private void addStaticField(ClassGenerator classGen, String type,
                                String name)
    {
        final FieldGen fgen = new FieldGen(ACC_PROTECTED|ACC_STATIC,
                                           Util.getJCRefType(type),
                                           name,
                                           classGen.getConstantPool());
        classGen.addField(fgen.getField());

    }

    /**
     * Translate the stylesheet into JVM bytecodes.
     */
    public void translate() {
        _className = getXSLTC().getClassName();

        // Define a new class by extending TRANSLET_CLASS
        final ClassGenerator classGen =
            new ClassGenerator(_className,
                               TRANSLET_CLASS,
                               Constants.EMPTYSTRING,
                               ACC_PUBLIC | ACC_SUPER,
                               null, this);

        addDOMField(classGen);

        // Compile transform() to initialize parameters, globals & output
        // and run the transformation
        compileTransform(classGen);

        // Translate all non-template elements and filter out all templates
        final Enumeration elements = elements();
        while (elements.hasMoreElements()) {
            Object element = elements.nextElement();
            // xsl:template
            if (element instanceof Template) {
                // Separate templates by modes
                final Template template = (Template)element;
                //_templates.addElement(template);
                getMode(template.getModeName()).addTemplate(template);
            }
            // xsl:attribute-set
            else if (element instanceof AttributeSet) {
                ((AttributeSet)element).translate(classGen, null);
            }
            else if (element instanceof Output) {
                // save the element for later to pass to compileConstructor
                Output output = (Output)element;
                if (output.enabled()) _lastOutputElement = output;
            }
            else {
                // Global variables and parameters are handled elsewhere.
                // Other top-level non-template elements are ignored. Literal
                // elements outside of templates will never be output.
            }
        }

        checkOutputMethod();
        processModes();
        compileModes(classGen);
        compileStaticInitializer(classGen);
        compileConstructor(classGen, _lastOutputElement);

        if (!getParser().errorsFound()) {
            getXSLTC().dumpClass(classGen.getJavaClass());
        }
    }

    /**
     * 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);

    }

    /**
     * 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);
    }

    /**
     * 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.
     *
     * 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");
    }

    /**
     * This method returns a vector with variables/params and keys in the
     * order in which they are to be compiled for initialization. The order
     * is determined by analyzing the 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 and, therefore, consider to determine the partial order.
     */
    private Vector resolveDependencies(Vector input) {
        /* DEBUG CODE - INGORE
        for (int i = 0; i < input.size(); i++) {
            final TopLevelElement e = (TopLevelElement) input.elementAt(i);
            System.out.println("e = " + e + " depends on:");
            Vector dep = e.getDependencies();
            for (int j = 0; j < (dep != null ? dep.size() : 0); j++) {
                System.out.println("\t" + dep.elementAt(j));
            }
        }
        System.out.println("=================================");
        */

        Vector result = new Vector();
        while (input.size() > 0) {
            boolean changed = false;
            for (int i = 0; i < input.size(); ) {
                final TopLevelElement vde = (TopLevelElement) input.elementAt(i);
                final Vector dep = vde.getDependencies();
                if (dep == null || result.containsAll(dep)) {
                    result.addElement(vde);
                    input.remove(i);
                    changed = true;
                }
                else {
                    i++;
                }
            }

            // If nothing was changed in this pass then we have a circular ref
            if (!changed) {
                ErrorMsg err = new ErrorMsg(ErrorMsg.CIRCULAR_VARIABLE_ERR,
                                            input.toString(), this);
                getParser().reportError(Constants.ERROR, err);
                return(result);
            }
        }

        /* DEBUG CODE - INGORE
        System.out.println("=================================");
        for (int i = 0; i < result.size(); i++) {
            final TopLevelElement e = (TopLevelElement) result.elementAt(i);
            System.out.println("e = " + e);
        }
        */

        return result;
    }

    /**
     * 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");
    }

    /**
     * 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);

    }

    /**
     * Peephole optimization: Remove sequences of [ALOAD, POP].
     */
    private void peepHoleOptimization(MethodGenerator methodGen) {
        final String pattern = "`aload'`pop'`instruction'";
        final InstructionList il = methodGen.getInstructionList();
        final InstructionFinder find = new InstructionFinder(il);
        for(Iterator iter=find.search(pattern); iter.hasNext(); ) {
            InstructionHandle[] match = (InstructionHandle[])iter.next();
            try {
                il.delete(match[0], match[1]);
            }
            catch (TargetLostException e) {
                // TODO: move target down into the list
            }
        }
    }

    public int addParam(Param param) {
        _globals.addElement(param);
        return _globals.size() - 1;
    }

    public int addVariable(Variable global) {
        _globals.addElement(global);
        return _globals.size() - 1;
    }

    public void display(int indent) {
        indent(indent);
        Util.println("Stylesheet");
        displayContents(indent + IndentIncrement);
    }

    // do we need this wrapper ?????
    public String getNamespace(String prefix) {
        return lookupNamespace(prefix);
    }

    public String getClassName() {
        return _className;
    }

    public Vector getTemplates() {
        return _templates;
    }

    public Vector getAllValidTemplates() {
        // Return templates if no imported/included stylesheets
        if (_includedStylesheets == null) {
            return _templates;
        }

        // Is returned value cached?
        if (_allValidTemplates == null) {
           Vector templates = new Vector();
           templates.addAll(_templates);
            int size = _includedStylesheets.size();
            for (int i = 0; i < size; i++) {
                Stylesheet included =(Stylesheet)_includedStylesheets.elementAt(i);
                templates.addAll(included.getAllValidTemplates());
            }
            //templates.addAll(_templates);

            // Cache results in top-level stylesheet only
            if (_parentStylesheet != null) {
                return templates;
            }
            _allValidTemplates = templates;
         }

        return _allValidTemplates;
    }

    protected void addTemplate(Template template) {
        _templates.addElement(template);
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java Stylesheet.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.