/* * 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$ */ /* * * ExtensionTestlet.java * */ package org.apache.qetest.xsl; import java.io.File; import java.lang.reflect.Method; import org.apache.qetest.Datalet; import org.apache.qetest.Logger; /** * Testlet for testing xsl stylesheet extensions. * * This class provides the testing algorithim used for verifying * Xalan-specific extensions, primarily by transforming stylesheets * that use extensions and optionally by allowing any Java-based * extension classes to verify themselves and log out info. * * @author Shane_Curcuru@lotus.com * @version $Id$ */ public class ExtensionTestlet extends StylesheetTestlet { // Initialize our classname for TestletImpl's main() method static { thisClassName = "org.apache.qetest.xsl.ExtensionTestlet"; } // Initialize our defaultDatalet { defaultDatalet = (Datalet)new StylesheetDatalet(); } /** Convenience constant: Property key for Java classnames. */ public static final String JAVA_CLASS_NAME = "java.class.name"; /** Convenience constant: Property key for TestableExtension objects. */ public static final String TESTABLE_EXTENSION = "testable.extension"; /** * Accesor method for a brief description of this test. * @return String describing what this ExtensionTestlet does. */ public String getDescription() { return "ExtensionTestlet"; } /** * Worker method to perform any pre-processing needed. * * This optionally does deleteOutFile, then attempts to load * a matching TestableExtension class that matches the datalet's * stylesheet. If one is found, we call preCheck on that too. * * @param datalet to test with */ protected void testletInit(StylesheetDatalet datalet) { // Simply grab any superclass functionality first super.testletInit(datalet); // Now do custom initialization for extensions // See if we have a Java-based extension class // Side effect: fills in datalet.options findExtensionClass(datalet); // If found, ask the class to validate Class extensionClazz = (Class)datalet.options.get(TESTABLE_EXTENSION); if (null != extensionClazz) { boolean ignored = invokeMethodOn(extensionClazz, "preCheck", datalet); } else { logger.logMsg(Logger.TRACEMSG, "No extension class found"); } } /** * Worker method to validate output file with gold. * * Logs out applicable info while validating output file. * Most commonly will call the underlying TestableExtension's * postCheck method to get validation done. * * @param datalet to test with * @throws allows any underlying exception to be thrown */ protected void checkDatalet(StylesheetDatalet datalet) throws Exception { // If we have an associated extension class, call postCheck // If found, ask the class to validate Class extensionClazz = (Class)datalet.options.get(TESTABLE_EXTENSION); if (null != extensionClazz) { boolean ignored = invokeMethodOn(extensionClazz, "postCheck", datalet); } else { // Have our parent class do it's own validation super.checkDatalet(datalet); } } /** * Worker method: Try to find a matching .class file for this .xsl. * * Accesses our class member logger. * @param d datalet to use for testing */ protected void findExtensionClass(StylesheetDatalet datalet) { // Find the basename of the stylesheet String classname = null; if (null != datalet.inputName) { classname = datalet.inputName.substring(0, datalet.inputName.indexOf(".xsl")); } else { classname = datalet.xmlName.substring(0, datalet.xmlName.indexOf(".xml")); } // Also rip off any pathing info if it's found classname = classname.substring(classname.lastIndexOf(File.separator) + 1); try { //@todo future work: since these Java extensions are all // packageless, figure out a better way to reduce name // collisions - perhaps allow as org.apache.qetest.something Class extensionClazz = Class.forName(classname); logger.logMsg(Logger.TRACEMSG, "findExtensionClass found for " + classname + " which is " + extensionClazz.getName()); // Ensure the class is a TestableExtension if ((TestableExtension.class).isAssignableFrom((Class)extensionClazz)) { // Store info about class in datalet datalet.options.put(JAVA_CLASS_NAME, extensionClazz.getName()); datalet.options.put(TESTABLE_EXTENSION, extensionClazz); } else { logger.logMsg(Logger.STATUSMSG, "findExtensionClass was not a TestableExtension, was: " + extensionClazz); } } catch (Exception e) { logger.logMsg(Logger.INFOMSG, "findExtensionClass not found for " + classname); } } /** * Worker method: Call a method on this extension. * Only works for preCheck/postCheck, since they have the * proper method signatures. * * Accesses our class member logger. * @param extensionClazz Class that's assumed to be a TestableExtension * @param methodName method to invoke * @param datalet to pass to method */ protected boolean invokeMethodOn(Class extensionClazz, String methodName, StylesheetDatalet datalet) { try { Class[] parameterTypes = new Class[2]; parameterTypes[0] = Logger.class; parameterTypes[1] = StylesheetDatalet.class; Method method = extensionClazz.getMethod(methodName, parameterTypes); // Call static method to perform pre-transform validation // Pass on the datalet's options in case it uses them Object[] parameters = new Object[2]; parameters[0] = logger; parameters[1] = datalet; Object returnValue = method.invoke(null, parameters); // If the method returned something, return that .. if ((null != returnValue) && (returnValue instanceof Boolean)) { return ((Boolean)returnValue).booleanValue(); } else { // .. otherwise just return true by default return true; } } catch (Exception e) { logger.logThrowable(Logger.WARNINGMSG, e, "invokeMethodOn(" + methodName + ") threw"); logger.checkErr("invokeMethodOn(" + methodName + ") threw: " + e.toString()); return false; } } } // end of class ExtensionTestlet