1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id$ 20 */ 21 22 /* 23 * 24 * ExtensionTestlet.java 25 * 26 */ 27 package org.apache.qetest.xsl; 28 29 import java.io.File; 30 import java.lang.reflect.Method; 31 32 import org.apache.qetest.Datalet; 33 import org.apache.qetest.Logger; 34 35 /** 36 * Testlet for testing xsl stylesheet extensions. 37 * 38 * This class provides the testing algorithim used for verifying 39 * Xalan-specific extensions, primarily by transforming stylesheets 40 * that use extensions and optionally by allowing any Java-based 41 * extension classes to verify themselves and log out info. 42 * 43 * @author Shane_Curcuru@lotus.com 44 * @version $Id$ 45 */ 46 public class ExtensionTestlet extends StylesheetTestlet 47 { 48 // Initialize our classname for TestletImpl's main() method 49 static { thisClassName = "org.apache.qetest.xsl.ExtensionTestlet"; } 50 51 // Initialize our defaultDatalet 52 { defaultDatalet = (Datalet)new StylesheetDatalet(); } 53 54 /** Convenience constant: Property key for Java classnames. */ 55 public static final String JAVA_CLASS_NAME = "java.class.name"; 56 57 /** Convenience constant: Property key for TestableExtension objects. */ 58 public static final String TESTABLE_EXTENSION = "testable.extension"; 59 60 /** 61 * Accesor method for a brief description of this test. 62 * @return String describing what this ExtensionTestlet does. 63 */ getDescription()64 public String getDescription() 65 { 66 return "ExtensionTestlet"; 67 } 68 69 70 /** 71 * Worker method to perform any pre-processing needed. 72 * 73 * This optionally does deleteOutFile, then attempts to load 74 * a matching TestableExtension class that matches the datalet's 75 * stylesheet. If one is found, we call preCheck on that too. 76 * 77 * @param datalet to test with 78 */ testletInit(StylesheetDatalet datalet)79 protected void testletInit(StylesheetDatalet datalet) 80 { 81 // Simply grab any superclass functionality first 82 super.testletInit(datalet); 83 84 // Now do custom initialization for extensions 85 86 // See if we have a Java-based extension class 87 // Side effect: fills in datalet.options 88 findExtensionClass(datalet); 89 90 // If found, ask the class to validate 91 Class extensionClazz = (Class)datalet.options.get(TESTABLE_EXTENSION); 92 if (null != extensionClazz) 93 { 94 boolean ignored = invokeMethodOn(extensionClazz, "preCheck", datalet); 95 } 96 else 97 { 98 logger.logMsg(Logger.TRACEMSG, "No extension class found"); 99 } 100 } 101 102 103 /** 104 * Worker method to validate output file with gold. 105 * 106 * Logs out applicable info while validating output file. 107 * Most commonly will call the underlying TestableExtension's 108 * postCheck method to get validation done. 109 * 110 * @param datalet to test with 111 * @throws allows any underlying exception to be thrown 112 */ checkDatalet(StylesheetDatalet datalet)113 protected void checkDatalet(StylesheetDatalet datalet) 114 throws Exception 115 { 116 // If we have an associated extension class, call postCheck 117 // If found, ask the class to validate 118 Class extensionClazz = (Class)datalet.options.get(TESTABLE_EXTENSION); 119 if (null != extensionClazz) 120 { 121 boolean ignored = invokeMethodOn(extensionClazz, "postCheck", datalet); 122 } 123 else 124 { 125 // Have our parent class do it's own validation 126 super.checkDatalet(datalet); 127 } 128 } 129 130 131 /** 132 * Worker method: Try to find a matching .class file for this .xsl. 133 * 134 * Accesses our class member logger. 135 * @param d datalet to use for testing 136 */ findExtensionClass(StylesheetDatalet datalet)137 protected void findExtensionClass(StylesheetDatalet datalet) 138 { 139 // Find the basename of the stylesheet 140 String classname = null; 141 if (null != datalet.inputName) 142 { 143 classname = datalet.inputName.substring(0, datalet.inputName.indexOf(".xsl")); 144 } 145 else 146 { 147 classname = datalet.xmlName.substring(0, datalet.xmlName.indexOf(".xml")); 148 } 149 150 // Also rip off any pathing info if it's found 151 classname = classname.substring(classname.lastIndexOf(File.separator) + 1); 152 153 try 154 { 155 //@todo future work: since these Java extensions are all 156 // packageless, figure out a better way to reduce name 157 // collisions - perhaps allow as org.apache.qetest.something 158 Class extensionClazz = Class.forName(classname); 159 logger.logMsg(Logger.TRACEMSG, "findExtensionClass found for " 160 + classname + " which is " + extensionClazz.getName()); 161 162 // Ensure the class is a TestableExtension 163 if ((TestableExtension.class).isAssignableFrom((Class)extensionClazz)) 164 { 165 // Store info about class in datalet 166 datalet.options.put(JAVA_CLASS_NAME, extensionClazz.getName()); 167 datalet.options.put(TESTABLE_EXTENSION, extensionClazz); 168 } 169 else 170 { 171 logger.logMsg(Logger.STATUSMSG, "findExtensionClass was not a TestableExtension, was: " + extensionClazz); 172 } 173 } 174 catch (Exception e) 175 { 176 logger.logMsg(Logger.INFOMSG, "findExtensionClass not found for " + classname); 177 } 178 } 179 180 181 /** 182 * Worker method: Call a method on this extension. 183 * Only works for preCheck/postCheck, since they have the 184 * proper method signatures. 185 * 186 * Accesses our class member logger. 187 * @param extensionClazz Class that's assumed to be a TestableExtension 188 * @param methodName method to invoke 189 * @param datalet to pass to method 190 */ invokeMethodOn(Class extensionClazz, String methodName, StylesheetDatalet datalet)191 protected boolean invokeMethodOn(Class extensionClazz, 192 String methodName, StylesheetDatalet datalet) 193 { 194 try 195 { 196 Class[] parameterTypes = new Class[2]; 197 parameterTypes[0] = Logger.class; 198 parameterTypes[1] = StylesheetDatalet.class; 199 Method method = extensionClazz.getMethod(methodName, parameterTypes); 200 201 // Call static method to perform pre-transform validation 202 // Pass on the datalet's options in case it uses them 203 Object[] parameters = new Object[2]; 204 parameters[0] = logger; 205 parameters[1] = datalet; 206 Object returnValue = method.invoke(null, parameters); 207 // If the method returned something, return that .. 208 if ((null != returnValue) 209 && (returnValue instanceof Boolean)) 210 { 211 return ((Boolean)returnValue).booleanValue(); 212 } 213 else 214 { 215 // .. otherwise just return true by default 216 return true; 217 } 218 } 219 catch (Exception e) 220 { 221 logger.logThrowable(Logger.WARNINGMSG, e, "invokeMethodOn(" + methodName + ") threw"); 222 logger.checkErr("invokeMethodOn(" + methodName + ") threw: " + e.toString()); 223 return false; 224 } 225 } 226 227 } // end of class ExtensionTestlet 228 229