package client.net.sf.saxon.ce.functions;
import java.util.logging.Logger;
import com.google.gwt.logging.client.LogConfiguration;
import client.net.sf.saxon.ce.Controller;
import client.net.sf.saxon.ce.LogController;
import client.net.sf.saxon.ce.expr.Expression;
import client.net.sf.saxon.ce.expr.ExpressionTool;
import client.net.sf.saxon.ce.expr.ExpressionVisitor;
import client.net.sf.saxon.ce.expr.TraceExpression;
import client.net.sf.saxon.ce.expr.XPathContext;
import client.net.sf.saxon.ce.lib.TraceListener;
import client.net.sf.saxon.ce.om.Item;
import client.net.sf.saxon.ce.om.NodeInfo;
import client.net.sf.saxon.ce.om.SequenceIterator;
import client.net.sf.saxon.ce.trace.Location;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.tree.util.Navigator;
import client.net.sf.saxon.ce.type.Type;
import client.net.sf.saxon.ce.value.SequenceExtent;
import client.net.sf.saxon.ce.value.Value;
/**
* This class supports the XPath 2.0 function trace().
* The value is traced to the Logger output if logLevel is FINE, if logLevel is FINEST then
* TraceListener is in use, in which case the information is sent to the TraceListener
*/
public class Trace extends SystemFunction {
private static Logger logger = Logger.getLogger("Trace");
/**
* preEvaluate: this method suppresses compile-time evaluation by doing nothing
* @param visitor an expression visitor
*/
public Expression preEvaluate(ExpressionVisitor visitor) {
return this;
}
/**
* Get the static properties of this expression (other than its type). The result is
* bit-significant. These properties are used for optimizations. In general, if
* property bit is set, it is true, but if it is unset, the value is unknown.
*/
public int computeSpecialProperties() {
return argument[0].getSpecialProperties();
}
/**
* Get the static cardinality
*/
public int computeCardinality() {
return argument[0].getCardinality();
}
/**
* Evaluate the function
*/
public Item evaluateItem(XPathContext context) throws XPathException {
Item val = argument[0].evaluateItem(context);
if (LogConfiguration.loggingIsEnabled()) {
String label = argument[1].evaluateAsString(context).toString();
if (LogController.traceIsEnabled()) {
notifyListener(label, Value.asValue(val), context);
} else {
traceItem(val, label);
}
}
return val;
}
private void notifyListener(String label, Value val, XPathContext context) {
TraceExpression info = new TraceExpression(this);
info.setConstructType(Location.TRACE_CALL);
info.setSourceLocator(this.getSourceLocator());
info.setProperty("label", label);
info.setProperty("value", val);
TraceListener listener = LogController.getTraceListener();
listener.enter(info, context);
listener.leave(info);
}
public static void traceItem(/*@Nullable*/ Item val, String label) {
if (val==null) {
logger.info(label + ": empty sequence");
} else {
if (val instanceof NodeInfo) {
logger.info(label + ": " + Type.displayTypeName(val) + ": "
+ Navigator.getPath((NodeInfo)val));
} else {
logger.info(label + ": " + Type.displayTypeName(val) + ": "
+ val.getStringValue());
}
}
}
/**
* Iterate over the results of the function
*/
/*@NotNull*/
public SequenceIterator iterate(XPathContext context) throws XPathException {
if (LogConfiguration.loggingIsEnabled() && LogController.traceIsEnabled()) {
String label = argument[1].evaluateAsString(context).toString();
int evalMode = ExpressionTool.eagerEvaluationMode(argument[0]); // eagerEvaluate not implemented in CE
Value value = Value.asValue(ExpressionTool.evaluate(argument[0], evalMode, context, 10));
notifyListener(label, value, context);
return value.iterate();
} else {
if (!LogConfiguration.loggingIsEnabled()) {
return argument[0].iterate(context);
} else {
return new TracingIterator(argument[0].iterate(context),
argument[1].evaluateAsString(context).toString());
}
}
}
/**
* Evaluate the expression
*
* @param arguments the values of the arguments, supplied as SequenceIterators
* @param context the dynamic evaluation context
* @return the result of the evaluation, in the form of a SequenceIterator
* @throws net.sf.saxon.trans.XPathException
* if a dynamic error occurs during the evaluation of the expression
*/
public SequenceIterator call(SequenceIterator[] arguments, XPathContext context) throws XPathException {
if (LogConfiguration.loggingIsEnabled() && LogController.traceIsEnabled()) {
String label = arguments[1].next().getStringValue();
Value value = Value.asValue(SequenceExtent.makeSequenceExtent(arguments[0]));
notifyListener(label, value, context);
return value.iterate();
} else {
if (!LogConfiguration.loggingIsEnabled()) {
return argument[0].iterate(context);
} else {
return new TracingIterator(argument[0].iterate(context),
argument[1].evaluateAsString(context).toString());
}
}
}
/**
* Tracing Iterator class
*/
private class TracingIterator implements SequenceIterator {
SequenceIterator base;
String label;
boolean empty = true;
public TracingIterator(SequenceIterator base, String label) {
this.base = base;
this.label = label;
}
public Item next() throws XPathException {
Item n = base.next();
if (n==null) {
if (empty) {
traceItem(null, label);
}
} else {
traceItem(n, label + " [" + position() + ']');
empty = false;
}
return n;
}
public Item current() {
return base.current();
}
public int position() {
return base.position();
}
/*@NotNull*/
public SequenceIterator getAnother() throws XPathException {
return new TracingIterator(base.getAnother(), label);
}
/**
* Get properties of this iterator, as a bit-significant integer.
*
* @return the properties of this iterator. This will be some combination of
* properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER},
* and {@link #LOOKAHEAD}. It is always
* acceptable to return the value zero, indicating that there are no known special properties.
* It is acceptable for the properties of the iterator to change depending on its state.
*/
public int getProperties() {
return 0;
}
}
@Override
public SystemFunction newInstance() {
return new Trace();
}
}
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.