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 * LoggingURIResolver.java 25 * 26 */ 27 package org.apache.qetest.trax; 28 29 import java.util.Hashtable; 30 31 import javax.xml.transform.Source; 32 import javax.xml.transform.TransformerException; 33 import javax.xml.transform.URIResolver; 34 import javax.xml.transform.stream.StreamSource; 35 36 import org.apache.qetest.Logger; 37 import org.apache.qetest.LoggingHandler; 38 import org.apache.xml.utils.SystemIDResolver; 39 import org.xml.sax.InputSource; 40 //------------------------------------------------------------------------- 41 42 /** 43 * Implementation of URIResolver that logs all calls. 44 * Currently just provides default service; returns null. 45 * @author shane_curcuru@lotus.com 46 * @version $Id$ 47 */ 48 public class LoggingURIResolver extends LoggingHandler implements URIResolver 49 { 50 51 /** No-op sets logger to default. */ LoggingURIResolver()52 public LoggingURIResolver() 53 { 54 setLogger(getDefaultLogger()); 55 } 56 57 /** 58 * Ctor that calls setLogger automatically. 59 * 60 * @param l Logger we should log to 61 */ LoggingURIResolver(Logger l)62 public LoggingURIResolver(Logger l) 63 { 64 setLogger(l); 65 } 66 67 68 /** 69 * Our default handler that we pass all events through to. 70 */ 71 protected URIResolver defaultHandler = null; 72 73 74 /** 75 * Set a default handler for us to wrapper. 76 * Set a URIResolver for us to use. 77 * // Note that we don't currently have a default URIResolver, 78 * // so the LoggingURIResolver class will just attempt 79 * // to use the SystemIDResolver class instead 80 * 81 * @param default Object of the correct type to pass-through to; 82 * throws IllegalArgumentException if null or incorrect type 83 */ setDefaultHandler(Object defaultU)84 public void setDefaultHandler(Object defaultU) 85 { 86 try 87 { 88 defaultHandler = (URIResolver)defaultU; 89 } 90 catch (Throwable t) 91 { 92 throw new java.lang.IllegalArgumentException("setDefaultHandler illegal type: " + t.toString()); 93 } 94 } 95 96 97 /** 98 * Accessor method for our default handler. 99 * 100 * @return default (Object) our default handler; null if unset 101 */ getDefaultHandler()102 public Object getDefaultHandler() 103 { 104 return (Object)defaultHandler; 105 } 106 107 108 /** Prefixed to all logger msg output. */ 109 public static final String prefix = "LUR:"; 110 111 112 /** 113 * Counter for how many URIs we've resolved. 114 */ 115 protected int[] counters = { 0 }; 116 117 118 /** 119 * Get a list of counters of all items we've logged. 120 * Only a single array item is returned. 121 * 122 * @return array of int counter for each item we log 123 */ getCounters()124 public int[] getCounters() 125 { 126 return counters; 127 } 128 129 130 /** 131 * Really Cheap-o string representation of our state. 132 * 133 * @return String of getCounters() rolled up in minimal space 134 */ getQuickCounters()135 public String getQuickCounters() 136 { 137 return (prefix + "(" + counters[0] + ")"); 138 } 139 140 141 /** Cheap-o string representation of last URI we resolved. */ 142 protected String lastItem = NOTHING_HANDLED; 143 144 145 /** 146 * Accessor for string representation of last event we got. 147 * @param s string to set 148 */ setLastItem(String s)149 protected void setLastItem(String s) 150 { 151 lastItem = s; 152 } 153 154 155 /** 156 * Accessor for string representation of last event we got. 157 * @return last event string we had 158 */ getLast()159 public String getLast() 160 { 161 return lastItem; 162 } 163 164 165 /** Expected value(s) for URIs we may resolve, default=ITEM_DONT_CARE. */ 166 protected String[] expected = { ITEM_DONT_CARE }; 167 168 169 /** Counter used when expected is an ordered array. */ 170 protected int expectedCtr = 0; 171 172 173 /** 174 * Ask us to report checkPass/Fail for certain URIs we resolve. 175 * 176 * @param itemType ignored, we only do one type 177 * @param containsString a string to look for within whatever 178 * item we handle - usually checked for by seeing if the actual 179 * item we handle contains the containsString 180 */ setExpected(int itemType, String containsString)181 public void setExpected(int itemType, String containsString) 182 { 183 // Default to don't care on null 184 if (null == containsString) 185 containsString = ITEM_DONT_CARE; 186 187 expected = new String[1]; 188 expected[0] = containsString; 189 } 190 191 /** 192 * Ask us to report checkPass/Fail for an ordered list of URIs 193 * we may resolve. 194 * 195 * Users can specify an array of expected URIs we should be 196 * resolving in order. Both the specific items and the exact 197 * order must occour for us to call checkPass for each URI; 198 * we call checkFail for any URI that doesn't match or is out 199 * of order. After we run off the end of the array, we 200 * go back to the defaul of ITEM_DONT_CARE. 201 * Reset by reset(), of course. 202 * 203 * @param containsStrings[] and array of items to look for in 204 * order: this allows you to test a stylesheet that has 205 * three xsl:imports, for example 206 */ setExpected(String[] containsStrings)207 public void setExpected(String[] containsStrings) 208 { 209 // Default to don't care on null 210 if ((null == containsStrings) || (0 == containsStrings.length)) 211 { 212 expected = new String[1]; 213 expected[0] = ITEM_DONT_CARE; 214 } 215 else 216 { 217 expected = new String[containsStrings.length]; 218 System.arraycopy(containsStrings, 0, expected, 0, containsStrings.length); 219 } 220 expectedCtr = 0; 221 } 222 223 /** 224 * Cheap-o worker method to get a string value. 225 * //@todo improve string return value 226 * 227 * @param i InputSource to get a string from 228 * @return some String representation thereof 229 */ getString(InputSource i)230 private String getString(InputSource i) 231 { 232 return i.toString(); 233 } 234 235 236 /** 237 * Reset all items or counters we've handled. 238 */ reset()239 public void reset() 240 { 241 setLastItem(NOTHING_HANDLED); 242 counters[0] = 0; 243 expected = new String[1]; 244 expected[0] = ITEM_DONT_CARE; 245 expectedCtr = 0; 246 } 247 248 249 /** 250 * Worker method to either log or call check* for this event. 251 * A simple way to validate for any kind of event. 252 * 253 * @param desc detail info from this kind of message 254 */ checkExpected(String desc, String resolvedTo)255 protected void checkExpected(String desc, String resolvedTo) 256 { 257 // Note the order of logging is important, which is why 258 // we store these values and then log them later 259 final int DONT_CARE = 0; 260 final int PASS = 1; 261 final int FAIL = 2; 262 int checkResult = DONT_CARE; 263 String checkDesc = null; 264 StringBuffer extraInfo = new StringBuffer(""); 265 Hashtable attrs = new Hashtable(); 266 attrs.put("source", "LoggingURIResolver"); 267 attrs.put("counters", getQuickCounters()); 268 attrs.put("resolvedTo", resolvedTo); 269 270 String tmp = getQuickCounters() + " " + desc; 271 if (expectedCtr > expected.length) 272 { 273 // Sanity check: prevent AIOOBE 274 expectedCtr = expected.length; 275 extraInfo.append(getQuickCounters() 276 + " error: array overbounds " + expectedCtr + "\n"); 277 } 278 // Either log the exception or call checkPass/checkFail 279 // as requested by setExpected for this type 280 if (ITEM_DONT_CARE == expected[expectedCtr]) 281 { 282 // We don't care about this, just log it 283 extraInfo.append("ITEM_DONT_CARE(" + expectedCtr + ") " + tmp + "\n"); 284 } 285 else if (ITEM_CHECKFAIL == expected[expectedCtr]) 286 { 287 // We shouldn't have been called here, so fail 288 checkResult = FAIL; 289 checkDesc = tmp + " was unexpected"; 290 } 291 else if ((null != desc) 292 && (desc.indexOf(expected[expectedCtr]) > -1)) 293 { 294 // We got a warning the user expected, so pass 295 checkResult = PASS; 296 checkDesc = tmp + " matched"; 297 // Also reset this counter 298 expected[expectedCtr] = ITEM_DONT_CARE; 299 } 300 else 301 { 302 // We got a warning the user didn't expect, so fail 303 checkResult = FAIL; 304 checkDesc = tmp + " did not match"; 305 // Also reset this counter 306 expected[expectedCtr] = ITEM_DONT_CARE; 307 } 308 // If we have a list of expected items, increment 309 if (expected.length > 1) 310 { 311 expectedCtr++; 312 // If we run off the end, reset all expected 313 if (expectedCtr >= expected.length) 314 { 315 extraInfo.append("Ran off end of expected items, resetting\n"); 316 expected = new String[1]; 317 expected[0] = ITEM_DONT_CARE; 318 expectedCtr = 0; 319 } 320 } 321 logger.logElement(level, "loggingHandler", attrs, extraInfo); 322 if (PASS == checkResult) 323 logger.checkPass(checkDesc); 324 else if (FAIL == checkResult) 325 logger.checkFail(checkDesc); 326 // else - DONT_CARE is no-op 327 } 328 329 330 ////////////////// Implement URIResolver ////////////////// 331 /** 332 * This will be called by the processor when it encounters 333 * an xsl:include, xsl:import, or document() function. 334 * 335 * @param href An href attribute, which may be relative or absolute. 336 * @param base The base URI in effect when the href attribute was encountered. 337 * 338 * @return A non-null Source object. 339 * 340 * @throws TransformerException 341 */ resolve(String href, String base)342 public Source resolve(String href, String base) 343 throws TransformerException 344 { 345 counters[0]++; 346 setLastItem("{" + base + "}" + href); 347 // Store the source we're about to resolve - note that the 348 // order of logging and calling checkExpected is important 349 Source resolvedSource = null; 350 String resolvedTo = null; 351 352 if (null != defaultHandler) 353 { 354 resolvedTo = "resolved by: " + defaultHandler; 355 resolvedSource = defaultHandler.resolve(href, base); 356 } 357 else 358 { 359 // Note that we don't currently have a default URIResolver, 360 // so the LoggingURIResolver class will just attempt 361 // to use the SystemIDResolver class instead 362 String sysId = SystemIDResolver.getAbsoluteURI(href, base); 363 resolvedTo = "resolved into new StreamSource(" + sysId + ")"; 364 resolvedSource = new StreamSource(sysId); 365 } 366 367 // Call worker method to log out various info and then 368 // call check for us if needed 369 checkExpected(getLast(), resolvedTo); 370 return resolvedSource; 371 } 372 } 373