blob: 3e0b940114e444f3ee824e3f4c6892332bfd07fd [file] [log] [blame]
/*
* 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);
}
}