Package com.sun.org.apache.xalan.internal.xsltc.runtime

Source Code of com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet

/*
* 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: AbstractTranslet.java,v 1.6 2006/06/19 19:49:03 spericas Exp $
*/

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

import java.io.File;
import java.io.FileWriter;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;
import javax.xml.transform.Templates;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.DOMImplementation;
import javax.xml.parsers.ParserConfigurationException;

import com.sun.org.apache.xml.internal.dtm.DTM;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.DOMCache;
import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
import com.sun.org.apache.xalan.internal.xsltc.Translet;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter;
import com.sun.org.apache.xalan.internal.xsltc.dom.KeyIndex;
import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

/**
* @author Jacek Ambroziak
* @author Santiago Pericas-Geertsen
* @author Morten Jorgensen
* @author G. Todd Miller
* @author John Howard, JohnH@schemasoft.com
*/
public abstract class AbstractTranslet implements Translet {

    // These attributes are extracted from the xsl:output element. They also
    // appear as fields (with the same type, only public) in Output.java
    public String  _version = "1.0";
    public String  _method = null;
    public String  _encoding = "UTF-8";
    public boolean _omitHeader = false;
    public String  _standalone = null;
    public String  _doctypePublic = null;
    public String  _doctypeSystem = null;
    public boolean _indent = false;
    public String  _mediaType = null;
    public Vector _cdata = null;
    public int _indentamount = -1;

    public static final int FIRST_TRANSLET_VERSION = 100;
    public static final int VER_SPLIT_NAMES_ARRAY = 101;
    public static final int CURRENT_TRANSLET_VERSION = VER_SPLIT_NAMES_ARRAY;

    // Initialize Translet version field to base value.  A class that extends
    // AbstractTranslet may override this value to a more recent translet
    // version; if it doesn't override the value (because it was compiled
    // before the notion of a translet version was introduced, it will get
    // this default value).
    protected int transletVersion = FIRST_TRANSLET_VERSION;

    // DOM/translet handshaking - the arrays are set by the compiled translet
    protected String[] namesArray;
    protected String[] urisArray;
    protected int[]    typesArray;
    protected String[] namespaceArray;
   
    // The Templates object that is used to create this Translet instance
    protected Templates _templates = null;
   
    // Boolean flag to indicate whether this translet has id functions.
    protected boolean _hasIdCall = false;

    // TODO - these should only be instanciated when needed
    protected StringValueHandler stringValueHandler = new StringValueHandler();

    // Use one empty string instead of constantly instanciating String("");
    private final static String EMPTYSTRING = "";

    // This is the name of the index used for ID attributes
    private final static String ID_INDEX_NAME = "##id";

   
    /************************************************************************
     * Debugging
     ************************************************************************/
    public void printInternalState() {
  System.out.println("-------------------------------------");
  System.out.println("AbstractTranslet this = " + this);
  System.out.println("pbase = " + pbase);
  System.out.println("vframe = " + pframe);
  System.out.println("paramsStack.size() = " + paramsStack.size());
  System.out.println("namesArray.size = " + namesArray.length);
  System.out.println("namespaceArray.size = " + namespaceArray.length);
  System.out.println("");
  System.out.println("Total memory = " + Runtime.getRuntime().totalMemory());
    }

    /**
     * Wrap the initial input DOM in a dom adapter. This adapter is wrapped in
     * a DOM multiplexer if the document() function is used (handled by compiled
     * code in the translet - see compiler/Stylesheet.compileTransform()).
     */
    public final DOMAdapter makeDOMAdapter(DOM dom)
  throws TransletException {
        setRootForKeys(dom.getDocument());
  return new DOMAdapter(dom, namesArray, urisArray, typesArray, namespaceArray);
    }

    /************************************************************************
     * Parameter handling
     ************************************************************************/

    // Parameter's stack: <tt>pbase</tt> and <tt>pframe</tt> are used
    // to denote the current parameter frame.
    protected int pbase = 0, pframe = 0;
    protected ArrayList paramsStack = new ArrayList();

    /**
     * Push a new parameter frame.
     */
    public final void pushParamFrame() {
  paramsStack.add(pframe, new Integer(pbase));
  pbase = ++pframe;
    }

    /**
     * Pop the topmost parameter frame.
     */
    public final void popParamFrame() {
  if (pbase > 0) {
      final int oldpbase = ((Integer)paramsStack.get(--pbase)).intValue();
      for (int i = pframe - 1; i >= pbase; i--) {
    paramsStack.remove(i);
      }
      pframe = pbase; pbase = oldpbase;
  }
    }

    /**
     * Add a new global parameter if not already in the current frame.
     * To setParameters of the form {http://foo.bar}xyz
     * This needs to get mapped to an instance variable in the class
     * The mapping  created so that
     * the global variables in the generated class become
     * http$colon$$flash$$flash$foo$dot$bar$colon$xyz
     */
    public final Object addParameter(String name, Object value) {
        name = BasisLibrary.mapQNameToJavaName (name);
  return addParameter(name, value, false);
    }

    /**
     * Add a new global or local parameter if not already in the current frame.
     * The 'isDefault' parameter is set to true if the value passed is the
     * default value from the <xsl:parameter> element's select attribute or
     * element body.
     */
    public final Object addParameter(String name, Object value,
  boolean isDefault)
    {
  // Local parameters need to be re-evaluated for each iteration
  for (int i = pframe - 1; i >= pbase; i--) {
      final Parameter param = (Parameter) paramsStack.get(i);

      if (param._name.equals(name)) {
    // Only overwrite if current value is the default value and
    // the new value is _NOT_ the default value.
    if (param._isDefault || !isDefault) {
        param._value = value;
        param._isDefault = isDefault;
        return value;
    }
    return param._value;
      }
  }

  // Add new parameter to parameter stack
  paramsStack.add(pframe++, new Parameter(name, value, isDefault));
  return value;
    }

    /**
     * Clears the parameter stack.
     */
    public void clearParameters() { 
  pbase = pframe = 0;
  paramsStack.clear();
    }

    /**
     * Get the value of a parameter from the current frame or
     * <tt>null</tt> if undefined.
     */
    public final Object getParameter(String name) {

        name = BasisLibrary.mapQNameToJavaName (name);

  for (int i = pframe - 1; i >= pbase; i--) {
      final Parameter param = (Parameter)paramsStack.get(i);
      if (param._name.equals(name)) return param._value;
  }
  return null;
    }

    /************************************************************************
     * Message handling - implementation of <xsl:message>
     ************************************************************************/

    // Holds the translet's message handler - used for <xsl:message>.
    // The deault message handler dumps a string stdout, but anything can be
    // used, such as a dialog box for applets, etc.
    private MessageHandler _msgHandler = null;

    /**
     * Set the translet's message handler - must implement MessageHandler
     */
    public final void setMessageHandler(MessageHandler handler) {
  _msgHandler = handler;
    }

    /**
     * Pass a message to the message handler - used by Message class.
     */
    public final void displayMessage(String msg) {
  if (_msgHandler == null) {
            System.err.println(msg);
  }
  else {
      _msgHandler.displayMessage(msg);
  }
    }

    /************************************************************************
     * Decimal number format symbol handling
     ************************************************************************/

    // Contains decimal number formatting symbols used by FormatNumberCall
    public Hashtable _formatSymbols = null;

    /**
     * Adds a DecimalFormat object to the _formatSymbols hashtable.
     * The entry is created with the input DecimalFormatSymbols.
     */
    public void addDecimalFormat(String name, DecimalFormatSymbols symbols) {
  // Instanciate hashtable for formatting symbols if needed
  if (_formatSymbols == null) _formatSymbols = new Hashtable();

  // The name cannot be null - use empty string instead
  if (name == null) name = EMPTYSTRING;

  // Construct a DecimalFormat object containing the symbols we got
  final DecimalFormat df = new DecimalFormat();
  if (symbols != null) {
      df.setDecimalFormatSymbols(symbols);
  }
  _formatSymbols.put(name, df);
    }

    /**
     * Retrieves a named DecimalFormat object from _formatSymbols hashtable.
     */
    public final DecimalFormat getDecimalFormat(String name) {

  if (_formatSymbols != null) {
      // The name cannot be null - use empty string instead
      if (name == null) name = EMPTYSTRING;

      DecimalFormat df = (DecimalFormat)_formatSymbols.get(name);
      if (df == null) df = (DecimalFormat)_formatSymbols.get(EMPTYSTRING);
      return df;
  }
  return(null);
    }

    /**
     * Give the translet an opportunity to perform a prepass on the document
     * to extract any information that it can store in an optimized form.
     *
     * Currently, it only extracts information about attributes of type ID.
     */
    public final void prepassDocument(DOM document) {
        setIndexSize(document.getSize());
        buildIDIndex(document);
    }

    /**
     * Leverages the Key Class to implement the XSLT id() function.
     * buildIdIndex creates the index (##id) that Key Class uses.
     * The index contains the element node index (int) and Id value (String).
     */
    private final void buildIDIndex(DOM document) {
        setRootForKeys(document.getDocument());

        if (document instanceof DOMEnhancedForDTM) {
            DOMEnhancedForDTM enhancedDOM = (DOMEnhancedForDTM)document;
           
            // If the input source is DOMSource, the KeyIndex table is not
            // built at this time. It will be built later by the lookupId()
            // and containsId() methods of the KeyIndex class.
            if (enhancedDOM.hasDOMSource()) {
                buildKeyIndex(ID_INDEX_NAME, document);
                return;
            }
            else {
                final Hashtable elementsByID = enhancedDOM.getElementsWithIDs();

                if (elementsByID == null) {
                  return;
                }

                // Given a Hashtable of DTM nodes indexed by ID attribute values,
                // loop through the table copying information to a KeyIndex
                // for the mapping from ID attribute value to DTM node
                final Enumeration idValues = elementsByID.keys();
                boolean hasIDValues = false;

                while (idValues.hasMoreElements()) {
                  final Object idValue = idValues.nextElement();
                  final int element =
                            document.getNodeHandle(
                                        ((Integer)elementsByID.get(idValue))
                                                .intValue());

                  buildKeyIndex(ID_INDEX_NAME, element, idValue);
                  hasIDValues = true;
                }

                if (hasIDValues) {
                  setKeyIndexDom(ID_INDEX_NAME, document);
                }
            }
        }
    }

    /**
     * After constructing the translet object, this method must be called to
     * perform any version-specific post-initialization that's required.
     */
    public final void postInitialization() {
        // If the version of the translet had just one namesArray, split
        // it into multiple fields.
        if (transletVersion < VER_SPLIT_NAMES_ARRAY) {
            int arraySize = namesArray.length;
            String[] newURIsArray = new String[arraySize];
            String[] newNamesArray = new String[arraySize];
            int[] newTypesArray = new int[arraySize];

            for (int i = 0; i < arraySize; i++) {
                String name = namesArray[i];
                int colonIndex = name.lastIndexOf(':');
                int lNameStartIdx = colonIndex+1;

                if (colonIndex > -1) {
                    newURIsArray[i] = name.substring(0, colonIndex);
                }

               // Distinguish attribute and element names.  Attribute has
               // @ before local part of name.
               if (name.charAt(lNameStartIdx) == '@') {
                   lNameStartIdx++;
                   newTypesArray[i] = DTM.ATTRIBUTE_NODE;
               } else if (name.charAt(lNameStartIdx) == '?') {
                   lNameStartIdx++;
                   newTypesArray[i] = DTM.NAMESPACE_NODE;
               } else {
                   newTypesArray[i] = DTM.ELEMENT_NODE;
               }
               newNamesArray[i] =
                          (lNameStartIdx == 0) ? name
                                               : name.substring(lNameStartIdx);
            }

            namesArray = newNamesArray;
            urisArray  = newURIsArray;
            typesArray = newTypesArray;
        }

        // Was translet compiled using a more recent version of the XSLTC
        // compiler than is known by the AbstractTranslet class?  If, so
        // and we've made it this far (which is doubtful), we should give up.
        if (transletVersion > CURRENT_TRANSLET_VERSION) {
            BasisLibrary.runTimeError(BasisLibrary.UNKNOWN_TRANSLET_VERSION_ERR,
                                      this.getClass().getName());
        }
    }

    /************************************************************************
     * Index(es) for <xsl:key> / key() / id()
     ************************************************************************/

    // Container for all indexes for xsl:key elements
    private Hashtable _keyIndexes = null;
    private KeyIndex  _emptyKeyIndex = null;
    private int       _indexSize = 0;
    private int       _currentRootForKeys = 0;

    /**
     * This method is used to pass the largest DOM size to the translet.
     * Needed to make sure that the translet can index the whole DOM.
     */
    public void setIndexSize(int size) {
  if (size > _indexSize) _indexSize = size;
    }

    /**
     * Creates a KeyIndex object of the desired size - don't want to resize!!!
     */
    public KeyIndex createKeyIndex() {
  return(new KeyIndex(_indexSize));
    }

    /**
     * Adds a value to a key/id index
     *   @param name is the name of the index (the key or ##id)
     *   @param node is the node handle of the node to insert
     *   @param value is the value that will look up the node in the given index
     */
    public void buildKeyIndex(String name, int node, Object value) {
  if (_keyIndexes == null) _keyIndexes = new Hashtable();
 
  KeyIndex index = (KeyIndex)_keyIndexes.get(name);
  if (index == null) {
      _keyIndexes.put(name, index = new KeyIndex(_indexSize));
  }
  index.add(value, node, _currentRootForKeys);
    }

    /**
     * Create an empty KeyIndex in the DOM case
     *   @param name is the name of the index (the key or ##id)
     *   @param dom is the DOM
     */
    public void buildKeyIndex(String name, DOM dom) {
  if (_keyIndexes == null) _keyIndexes = new Hashtable();
 
  KeyIndex index = (KeyIndex)_keyIndexes.get(name);
  if (index == null) {
      _keyIndexes.put(name, index = new KeyIndex(_indexSize));
  }
  index.setDom(dom, dom.getDocument());
    }

    /**
     * Returns the index for a given key (or id).
     * The index implements our internal iterator interface
     */
    public KeyIndex getKeyIndex(String name) {
  // Return an empty key index iterator if none are defined
  if (_keyIndexes == null) {
      return (_emptyKeyIndex != null)
          ? _emptyKeyIndex
          : (_emptyKeyIndex = new KeyIndex(1));
  }

  // Look up the requested key index
  final KeyIndex index = (KeyIndex)_keyIndexes.get(name);

  // Return an empty key index iterator if the requested index not found
  if (index == null) {
      return (_emptyKeyIndex != null)
          ? _emptyKeyIndex
          : (_emptyKeyIndex = new KeyIndex(1));
  }

  return(index);
    }

    private void setRootForKeys(int root) {
        _currentRootForKeys = root;
    }

    /**
     * This method builds key indexes - it is overridden in the compiled
     * translet in cases where the <xsl:key> element is used
     */
    public void buildKeys(DOM document, DTMAxisIterator iterator,
        SerializationHandler handler,
        int root) throws TransletException {
         
    }
   
    /**
     * This method builds key indexes - it is overridden in the compiled
     * translet in cases where the <xsl:key> element is used
     */
    public void setKeyIndexDom(String name, DOM document) {
      getKeyIndex(name).setDom(document, document.getDocument());         
    }

    /************************************************************************
     * DOM cache handling
     ************************************************************************/

    // Hold the DOM cache (if any) used with this translet
    private DOMCache _domCache = null;

    /**
     * Sets the DOM cache used for additional documents loaded using the
     * document() function.
     */
    public void setDOMCache(DOMCache cache) {
  _domCache = cache;
    }

    /**
     * Returns the DOM cache used for this translet. Used by the LoadDocument
     * class (if present) when the document() function is used.
     */
    public DOMCache getDOMCache() {
  return(_domCache);
    }

    /************************************************************************
     * Multiple output document extension.
     * See compiler/TransletOutput for actual implementation.
     ************************************************************************/

    public SerializationHandler openOutputHandler(String filename, boolean append)
  throws TransletException
    {
  try {
      final TransletOutputHandlerFactory factory
    = TransletOutputHandlerFactory.newInstance();

            String dirStr = new File(filename).getParent();
            if ((null != dirStr) && (dirStr.length() > 0)) {
               File dir = new File(dirStr);
               dir.mkdirs();
            }

      factory.setEncoding(_encoding);
      factory.setOutputMethod(_method);
      factory.setWriter(new FileWriter(filename, append));
      factory.setOutputType(TransletOutputHandlerFactory.STREAM);

      final SerializationHandler handler
    = factory.getSerializationHandler();

      transferOutputSettings(handler);
      handler.startDocument();
      return handler;
  }
  catch (Exception e) {
      throw new TransletException(e);
  }
    }

    public SerializationHandler openOutputHandler(String filename)
       throws TransletException
    {
       return openOutputHandler(filename, false);
    }

    public void closeOutputHandler(SerializationHandler handler) {
  try {
      handler.endDocument();
      handler.close();
  }
  catch (Exception e) {
      // what can you do?
  }
    }

    /************************************************************************
     * Native API transformation methods - _NOT_ JAXP/TrAX
     ************************************************************************/

    /**
     * Main transform() method - this is overridden by the compiled translet
     */
    public abstract void transform(DOM document, DTMAxisIterator iterator,
           SerializationHandler handler)
  throws TransletException;

    /**
     * Calls transform() with a given output handler
     */
    public final void transform(DOM document, SerializationHandler handler)
  throws TransletException {
        try {
            transform(document, document.getIterator(), handler);
        } finally {
            _keyIndexes = null;
        }
    }
 
    /**
     * Used by some compiled code as a shortcut for passing strings to the
     * output handler
     */
    public final void characters(final String string,
         SerializationHandler handler)
  throws TransletException {
        if (string != null) {
           //final int length = string.length();
           try {
               handler.characters(string);
           } catch (Exception e) {
               throw new TransletException(e);
           }
        }  
    }

    /**
     * Add's a name of an element whose text contents should be output as CDATA
     */
    public void addCdataElement(String name) {
  if (_cdata == null) {
            _cdata = new Vector();
        }

        int lastColon = name.lastIndexOf(':');

        if (lastColon > 0) {
            String uri = name.substring(0, lastColon);
            String localName = name.substring(lastColon+1);
      _cdata.addElement(uri);
      _cdata.addElement(localName);
        } else {
      _cdata.addElement(null);
      _cdata.addElement(name);
        }
    }

    /**
     * Transfer the output settings to the output post-processor
     */
    protected void transferOutputSettings(SerializationHandler handler) {
  if (_method != null) {
      if (_method.equals("xml")) {
          if (_standalone != null) {
        handler.setStandalone(_standalone);
    }
    if (_omitHeader) {
        handler.setOmitXMLDeclaration(true);
    }
    handler.setCdataSectionElements(_cdata);
    if (_version != null) {
        handler.setVersion(_version);
    }
    handler.setIndent(_indent);
    handler.setIndentAmount(_indentamount);
    if (_doctypeSystem != null) {
        handler.setDoctype(_doctypeSystem, _doctypePublic);
    }
      }
      else if (_method.equals("html")) {
    handler.setIndent(_indent);
    handler.setDoctype(_doctypeSystem, _doctypePublic);
    if (_mediaType != null) {
        handler.setMediaType(_mediaType);
    }
      }
  }
  else {
      handler.setCdataSectionElements(_cdata);
      if (_version != null) {
    handler.setVersion(_version);
      }
      if (_standalone != null) {
    handler.setStandalone(_standalone);
      }
      if (_omitHeader) {
    handler.setOmitXMLDeclaration(true);
      }
      handler.setIndent(_indent);
      handler.setDoctype(_doctypeSystem, _doctypePublic);
  }
    }

    private Hashtable _auxClasses = null;

    public void addAuxiliaryClass(Class auxClass) {
  if (_auxClasses == null) _auxClasses = new Hashtable();
  _auxClasses.put(auxClass.getName(), auxClass);
    }

    public void setAuxiliaryClasses(Hashtable auxClasses) {
      _auxClasses = auxClasses;
    }
   
    public Class getAuxiliaryClass(String className) {
  if (_auxClasses == null) return null;
  return((Class)_auxClasses.get(className));
    }

    // GTM added (see pg 110)
    public String[] getNamesArray() {
  return namesArray;
    }
   
    public String[] getUrisArray() {
      return urisArray;
    }
   
    public int[] getTypesArray() {
      return typesArray;
    }
   
    public String[] getNamespaceArray() {
  return namespaceArray;
    }
   
    public boolean hasIdCall() {
      return _hasIdCall;
    }
   
    public Templates getTemplates() {
      return _templates;
    }
   
    public void setTemplates(Templates templates) {
      _templates = templates;
    }   
   
    /************************************************************************
     * DOMImplementation caching for basis library
     ************************************************************************/
    protected DOMImplementation _domImplementation = null;
   
    public Document newDocument(String uri, String qname)
        throws ParserConfigurationException
    {
        if (_domImplementation == null) {
            _domImplementation = DocumentBuilderFactory.newInstance()
                .newDocumentBuilder().getDOMImplementation();
        }
        return _domImplementation.createDocument(uri, qname, null);
    }
}
TOP

Related Classes of com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.