java/src/org/apache/qetest/xalanj2/LoggingTransformState.java (258 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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$ */ /* * * LoggingTransformState.java * */ package org.apache.qetest.xalanj2; import java.lang.reflect.Method; import org.apache.qetest.Logger; import org.apache.qetest.LoggingHandler; import org.apache.xalan.templates.ElemLiteralResult; import org.apache.xalan.templates.ElemTemplateElement; import org.apache.xalan.transformer.TransformState; import org.apache.xalan.transformer.TransformerClient; import org.apache.xpath.XPath; import org.w3c.dom.Node; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; /** * Cheap-o ContentHandler that logs info about TransformState interface. * <p>Implements ContentHandler and dumps simplistic info * everything to a Logger; a way to debug TransformState.</p> * <p>This class could use improvement, but currently serves both * as a 'layer' for a ContentHandler (i.e. you can stick * setDefaultHandler in which we'll call for you, thus actually * getting output from your transform) as well as a logging * service for the TransformState interface. We dump to our * Logger various interesting info from the TransformState * object during each of our startElement(), endElement(), and * characters() calls about both the source node being processed * and about the xsl: element doing the processing. * @author shane_curcuru@lotus.com * @version $Id$ */ public class LoggingTransformState extends LoggingHandler implements ContentHandler, TransformerClient { /** No-op sets logger to default. */ public LoggingTransformState() { setLogger(getDefaultLogger()); } /** * Ctor that calls setLogger automatically. * * @param r Logger we should log to */ public LoggingTransformState(Logger l) { setLogger(l); } /** * A TransformState object that we use to log state data. * This is the equivalent of the defaultHandler, even though * that's not really the right metaphor. This class could be * upgraded to have both a default ContentHandler and a * defaultTransformerClient in the future. */ protected TransformState transformState = null; /** * Implement TransformerClient.setTransformState interface. * Pass in a reference to a TransformState object, which * can be used during SAX ContentHandler events to obtain * information about he state of the transformation. This * method will be called before each startDocument event. * * @param ts A reference to a TransformState object */ public void setTransformState(TransformState ts) { transformState = ts; } /** * Accessor method for our TransformState object. * * @param TransformState object we are using */ public TransformState getTransformState() { return transformState; } /** * Our default handler that we pass all events through to. */ protected ContentHandler defaultHandler = null; /** * Set a default handler for us to wrapper. * Set a ContentHandler for us to use. * * @param default Object of the correct type to pass-through to; * throws IllegalArgumentException if null or incorrect type */ public void setDefaultHandler(Object defaultC) { try { defaultHandler = (ContentHandler)defaultC; } catch (Throwable t) { throw new java.lang.IllegalArgumentException("setDefaultHandler illegal type: " + t.toString()); } } /** * Accessor method for our default handler. * * @return default (Object) our default handler; null if unset */ public Object getDefaultHandler() { return (Object)defaultHandler; } /** Prefixed to all logger msg output for ContentHandler. */ public final String prefix = "LTS:"; /** Prefixed to all logger msg output for TransformState. */ public final String prefix2 = "LTS2:"; /** Cheap-o string representation of last event we got. */ protected String lastItem = NOTHING_HANDLED; /** * Cheap-o Verbosity flag: should we log all ContentHandler * messages or not. * //@todo should have accessors and be integrated better */ public boolean verbose = false; /** * Accessor for string representation of last event we got. * @param s string to set */ protected void setLastItem(String s) { lastItem = s; } /** * Accessor for string representation of last event we got. * @return last event string we had */ public String getLast() { return lastItem; } /** setExpected, etc. not yet implemented. */ /** How many characters to report from characters event. */ private int charLimit = 30; /** * How many characters to report from characters event. * @param l charLimit for us to use */ public void setCharLimit(int l) { charLimit = l; } /** * How many characters to report from characters event. * @return charLimit we use */ public int getCharLimit() { return charLimit; } ////////////////// Utility methods for TransformState ////////////////// /** * Utility method to gather data about current node. * @return String describing node */ protected String getCurrentNodeInfo(TransformState ts, String x) { StringBuffer buf = new StringBuffer(); Node n = ts.getCurrentNode(); if(null != n) { buf.append(n.getNodeName()); if(Node.TEXT_NODE == n.getNodeType()) { buf.append("["); buf.append(n.getNodeValue()); buf.append("]"); } } else buf.append("[NULL-NODE]"); if (null != x) buf.append("[" + x + "]"); return buf.toString(); } /** * Utility method to gather data about current element in xsl. * @return String describing element */ protected String getCurrentElementInfo(TransformState ts) { StringBuffer buf = new StringBuffer(); ElemTemplateElement templ = ts.getCurrentElement(); if(null != templ) { // Note for user if it's an LRE or an xsl element if(templ instanceof ElemLiteralResult) buf.append("LRE:"); else buf.append("xsl:"); buf.append(templ.getNodeName()); buf.append(", line# "+templ.getLineNumber()); buf.append(", col# "+templ.getColumnNumber()); try { Class cl = ((Object)templ).getClass(); Method getSelect = cl.getMethod("getSelect", null); if(null != getSelect) { buf.append(", select='"); XPath xpath = (XPath)getSelect.invoke(templ, null); buf.append(xpath.getPatternString()+"'"); } } catch(java.lang.reflect.InvocationTargetException ite) { // no-op: just don't put in the select info for these items // buf.append("(threw: InvocationTargetException)"); } catch(IllegalAccessException iae) { // no-op } catch(NoSuchMethodException nsme) { // no-op } } else buf.append("[NULL-ELEMENT]"); return buf.toString(); } ////////////////// Implement ContentHandler ////////////////// protected Locator ourLocator = null; /** Implement ContentHandler.setDocumentLocator. */ public void setDocumentLocator (Locator locator) { // Note: this implies this class is !not! threadsafe setLastItem("setDocumentLocator"); ourLocator = locator; // future use logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.setDocumentLocator(locator); } /** Implement ContentHandler.startDocument. */ public void startDocument () throws SAXException { setLastItem("startDocument"); logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.startDocument(); } /** Implement ContentHandler.endDocument. */ public void endDocument() throws SAXException { setLastItem("endDocument"); logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.endDocument(); } /** Implement ContentHandler.startPrefixMapping. */ public void startPrefixMapping (String prefix, String uri) throws SAXException { setLastItem("startPrefixMapping: " + prefix + ", " + uri); logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.startPrefixMapping(prefix, uri); } /** Implement ContentHandler.endPrefixMapping. */ public void endPrefixMapping (String prefix) throws SAXException { setLastItem("endPrefixMapping: " + prefix); logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.endPrefixMapping(prefix); } /** Implement ContentHandler.startElement. */ public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { final String START_ELEMENT = "startElement: "; StringBuffer buf = new StringBuffer(); buf.append(namespaceURI + ", " + namespaceURI + ", " + qName); int n = atts.getLength(); for(int i = 0; i < n; i++) { buf.append(", " + atts.getQName(i)); } setLastItem(START_ELEMENT + buf.toString()); if (verbose) logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.startElement(namespaceURI, localName, qName, atts); // Also handle TransformerState if(null != transformState) { logger.logMsg(level, prefix2 + START_ELEMENT + getCurrentElementInfo(transformState) + " is processing: " + getCurrentNodeInfo(transformState, buf.toString())); } } /** Implement ContentHandler.endElement. */ public void endElement (String namespaceURI, String localName, String qName) throws SAXException { final String END_ELEMENT = "endElement: "; setLastItem(END_ELEMENT + namespaceURI + ", " + namespaceURI + ", " + qName); if (verbose) logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.endElement(namespaceURI, localName, qName); // Also handle TransformerState if(null != transformState) { logger.logMsg(level, prefix2 + END_ELEMENT + getCurrentElementInfo(transformState) + " is processing: " + getCurrentNodeInfo(transformState, null)); } } /** Implement ContentHandler.characters. */ public void characters (char ch[], int start, int length) throws SAXException { final String CHARACTERS = "characters: "; String s = new String(ch, start, (length > charLimit) ? charLimit : length); String tmp = null; if(length > charLimit) tmp = "\"" + s + "\"..."; else tmp = "\"" + s + "\""; setLastItem(CHARACTERS + tmp); if (verbose) logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.characters(ch, start, length); // Also handle TransformerState if(null != transformState) { logger.logMsg(level, prefix2 + CHARACTERS + getCurrentElementInfo(transformState) + " is processing: " + getCurrentNodeInfo(transformState, tmp)); } } /** Implement ContentHandler.ignorableWhitespace. */ public void ignorableWhitespace (char ch[], int start, int length) throws SAXException { setLastItem("ignorableWhitespace: len " + length); logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.ignorableWhitespace(ch, start, length); } /** Implement ContentHandler.processingInstruction. */ public void processingInstruction (String target, String data) throws SAXException { setLastItem("processingInstruction: " + target + ", " + data); logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.processingInstruction(target, data); } /** Implement ContentHandler.skippedEntity. */ public void skippedEntity (String name) throws SAXException { setLastItem("skippedEntity: " + name); logger.logMsg(level, prefix + getLast()); if (null != defaultHandler) defaultHandler.skippedEntity(name); } }