/* * 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$ */ /* * * LoggingURIResolver.java * */ package org.apache.qetest.trax; import java.util.Hashtable; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.URIResolver; import javax.xml.transform.stream.StreamSource; import org.apache.qetest.Logger; import org.apache.qetest.LoggingHandler; import org.apache.xml.utils.SystemIDResolver; import org.xml.sax.InputSource; //------------------------------------------------------------------------- /** * Implementation of URIResolver that logs all calls. * Currently just provides default service; returns null. * @author shane_curcuru@lotus.com * @version $Id$ */ public class LoggingURIResolver extends LoggingHandler implements URIResolver { /** No-op sets logger to default. */ public LoggingURIResolver() { setLogger(getDefaultLogger()); } /** * Ctor that calls setLogger automatically. * * @param l Logger we should log to */ public LoggingURIResolver(Logger l) { setLogger(l); } /** * Our default handler that we pass all events through to. */ protected URIResolver defaultHandler = null; /** * Set a default handler for us to wrapper. * Set a URIResolver for us to use. * // Note that we don't currently have a default URIResolver, * // so the LoggingURIResolver class will just attempt * // to use the SystemIDResolver class instead * * @param default Object of the correct type to pass-through to; * throws IllegalArgumentException if null or incorrect type */ public void setDefaultHandler(Object defaultU) { try { defaultHandler = (URIResolver)defaultU; } 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. */ public static final String prefix = "LUR:"; /** * Counter for how many URIs we've resolved. */ protected int[] counters = { 0 }; /** * Get a list of counters of all items we've logged. * Only a single array item is returned. * * @return array of int counter for each item we log */ public int[] getCounters() { return counters; } /** * Really Cheap-o string representation of our state. * * @return String of getCounters() rolled up in minimal space */ public String getQuickCounters() { return (prefix + "(" + counters[0] + ")"); } /** Cheap-o string representation of last URI we resolved. */ protected String lastItem = NOTHING_HANDLED; /** * 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; } /** Expected value(s) for URIs we may resolve, default=ITEM_DONT_CARE. */ protected String[] expected = { ITEM_DONT_CARE }; /** Counter used when expected is an ordered array. */ protected int expectedCtr = 0; /** * Ask us to report checkPass/Fail for certain URIs we resolve. * * @param itemType ignored, we only do one type * @param containsString a string to look for within whatever * item we handle - usually checked for by seeing if the actual * item we handle contains the containsString */ public void setExpected(int itemType, String containsString) { // Default to don't care on null if (null == containsString) containsString = ITEM_DONT_CARE; expected = new String[1]; expected[0] = containsString; } /** * Ask us to report checkPass/Fail for an ordered list of URIs * we may resolve. * * Users can specify an array of expected URIs we should be * resolving in order. Both the specific items and the exact * order must occour for us to call checkPass for each URI; * we call checkFail for any URI that doesn't match or is out * of order. After we run off the end of the array, we * go back to the defaul of ITEM_DONT_CARE. * Reset by reset(), of course. * * @param containsStrings[] and array of items to look for in * order: this allows you to test a stylesheet that has * three xsl:imports, for example */ public void setExpected(String[] containsStrings) { // Default to don't care on null if ((null == containsStrings) || (0 == containsStrings.length)) { expected = new String[1]; expected[0] = ITEM_DONT_CARE; } else { expected = new String[containsStrings.length]; System.arraycopy(containsStrings, 0, expected, 0, containsStrings.length); } expectedCtr = 0; } /** * Cheap-o worker method to get a string value. * //@todo improve string return value * * @param i InputSource to get a string from * @return some String representation thereof */ private String getString(InputSource i) { return i.toString(); } /** * Reset all items or counters we've handled. */ public void reset() { setLastItem(NOTHING_HANDLED); counters[0] = 0; expected = new String[1]; expected[0] = ITEM_DONT_CARE; expectedCtr = 0; } /** * Worker method to either log or call check* for this event. * A simple way to validate for any kind of event. * * @param desc detail info from this kind of message */ protected void checkExpected(String desc, String resolvedTo) { // Note the order of logging is important, which is why // we store these values and then log them later final int DONT_CARE = 0; final int PASS = 1; final int FAIL = 2; int checkResult = DONT_CARE; String checkDesc = null; StringBuffer extraInfo = new StringBuffer(""); Hashtable attrs = new Hashtable(); attrs.put("source", "LoggingURIResolver"); attrs.put("counters", getQuickCounters()); attrs.put("resolvedTo", resolvedTo); String tmp = getQuickCounters() + " " + desc; if (expectedCtr > expected.length) { // Sanity check: prevent AIOOBE expectedCtr = expected.length; extraInfo.append(getQuickCounters() + " error: array overbounds " + expectedCtr + "\n"); } // Either log the exception or call checkPass/checkFail // as requested by setExpected for this type if (ITEM_DONT_CARE == expected[expectedCtr]) { // We don't care about this, just log it extraInfo.append("ITEM_DONT_CARE(" + expectedCtr + ") " + tmp + "\n"); } else if (ITEM_CHECKFAIL == expected[expectedCtr]) { // We shouldn't have been called here, so fail checkResult = FAIL; checkDesc = tmp + " was unexpected"; } else if ((null != desc) && (desc.indexOf(expected[expectedCtr]) > -1)) { // We got a warning the user expected, so pass checkResult = PASS; checkDesc = tmp + " matched"; // Also reset this counter expected[expectedCtr] = ITEM_DONT_CARE; } else { // We got a warning the user didn't expect, so fail checkResult = FAIL; checkDesc = tmp + " did not match"; // Also reset this counter expected[expectedCtr] = ITEM_DONT_CARE; } // If we have a list of expected items, increment if (expected.length > 1) { expectedCtr++; // If we run off the end, reset all expected if (expectedCtr >= expected.length) { extraInfo.append("Ran off end of expected items, resetting\n"); expected = new String[1]; expected[0] = ITEM_DONT_CARE; expectedCtr = 0; } } logger.logElement(level, "loggingHandler", attrs, extraInfo); if (PASS == checkResult) logger.checkPass(checkDesc); else if (FAIL == checkResult) logger.checkFail(checkDesc); // else - DONT_CARE is no-op } ////////////////// Implement URIResolver ////////////////// /** * This will be called by the processor when it encounters * an xsl:include, xsl:import, or document() function. * * @param href An href attribute, which may be relative or absolute. * @param base The base URI in effect when the href attribute was encountered. * * @return A non-null Source object. * * @throws TransformerException */ public Source resolve(String href, String base) throws TransformerException { counters[0]++; setLastItem("{" + base + "}" + href); // Store the source we're about to resolve - note that the // order of logging and calling checkExpected is important Source resolvedSource = null; String resolvedTo = null; if (null != defaultHandler) { resolvedTo = "resolved by: " + defaultHandler; resolvedSource = defaultHandler.resolve(href, base); } else { // Note that we don't currently have a default URIResolver, // so the LoggingURIResolver class will just attempt // to use the SystemIDResolver class instead String sysId = SystemIDResolver.getAbsoluteURI(href, base); resolvedTo = "resolved into new StreamSource(" + sysId + ")"; resolvedSource = new StreamSource(sysId); } // Call worker method to log out various info and then // call check for us if needed checkExpected(getLast(), resolvedTo); return resolvedSource; } }