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 * LoggingLexicalHandler.java 25 * 26 */ 27 package org.apache.qetest.xsl; 28 29 import org.apache.qetest.Logger; 30 import org.apache.qetest.LoggingHandler; 31 import org.xml.sax.SAXException; 32 import org.xml.sax.ext.LexicalHandler; 33 34 /** 35 * Cheap-o LexicalHandler for use by API tests. 36 * <p>Implements LexicalHandler and dumps simplistic info 37 * everything to a Logger; a way to debug SAX stuff.</p> 38 * @author shane_curcuru@lotus.com 39 * @version $Id$ 40 */ 41 public class LoggingLexicalHandler extends LoggingHandler implements LexicalHandler 42 { 43 44 /** No-op sets logger to default. */ LoggingLexicalHandler()45 public LoggingLexicalHandler() 46 { 47 setLogger(getDefaultLogger()); 48 } 49 50 /** 51 * Ctor that calls setLogger automatically. 52 * 53 * @param l Logger we should log to 54 */ LoggingLexicalHandler(Logger l)55 public LoggingLexicalHandler(Logger l) 56 { 57 setLogger(l); 58 } 59 60 61 /** 62 * Our default handler that we pass all events through to. 63 */ 64 protected LexicalHandler defaultHandler = null; 65 66 67 /** 68 * Set a default handler for us to wrapper. 69 * Set a LexicalHandler for us to use. 70 * 71 * @param default Object of the correct type to pass-through to; 72 * throws IllegalArgumentException if null or incorrect type 73 */ setDefaultHandler(Object defaultH)74 public void setDefaultHandler(Object defaultH) 75 { 76 try 77 { 78 defaultHandler = (LexicalHandler)defaultH; 79 } 80 catch (Throwable t) 81 { 82 throw new java.lang.IllegalArgumentException("setDefaultHandler illegal type: " + t.toString()); 83 } 84 } 85 86 87 /** 88 * Accessor method for our default handler. 89 * 90 * @return default (Object) our default handler; null if unset 91 */ getDefaultHandler()92 public Object getDefaultHandler() 93 { 94 return (Object)defaultHandler; 95 } 96 97 98 /** Prefixed to all logger msg output. */ 99 public static final String prefix = "LLH:"; 100 101 /** Constant for items returned in getCounters: startDTD. */ 102 public static final int TYPE_STARTDTD = 0; 103 104 /** Constant for items returned in getCounters: endDTD. */ 105 public static final int TYPE_ENDDTD = 1; 106 107 /** Constant for items returned in getCounters: startEntity. */ 108 public static final int TYPE_STARTENTITY = 2; 109 110 /** Constant for items returned in getCounters: endEntity. */ 111 public static final int TYPE_ENDENTITY = 3; 112 113 /** Constant for items returned in getCounters: startCDATA. */ 114 public static final int TYPE_STARTCDATA = 4; 115 116 /** Constant for items returned in getCounters: endCDATA. */ 117 public static final int TYPE_ENDCDATA = 5; 118 119 /** Constant for items returned in getCounters: comment. */ 120 public static final int TYPE_COMMENT = 6; 121 122 123 /** 124 * Counters for how many events we've handled. 125 * Index into array are the TYPE_* constants. 126 */ 127 protected int[] counters = 128 { 129 0, /* startDTD */ 130 0, /* endDTD */ 131 0, /* startEntity */ 132 0, /* endEntity */ 133 0, /* startCDATA */ 134 0, /* endCDATA */ 135 0 /* comment */ 136 }; 137 138 139 /** 140 * Get a list of counters of all items we've logged. 141 * Returned in order as startDTD, endDTD, startEntity, 142 * endEntity, startCDATA, endCDATA, comment. 143 * Index into array are the TYPE_* constants. 144 * 145 * @return array of int counters for each item we log 146 */ getCounters()147 public int[] getCounters() 148 { 149 return counters; 150 } 151 152 153 /** 154 * Really Cheap-o string representation of our state. 155 * 156 * @return String of getCounters() rolled up in minimal space 157 */ getQuickCounters()158 public String getQuickCounters() 159 { 160 return (prefix + "(" 161 + counters[TYPE_STARTDTD] + ", " + counters[TYPE_ENDDTD] + "; " 162 + counters[TYPE_STARTENTITY] + ", " + counters[TYPE_ENDENTITY] + "; " 163 + counters[TYPE_STARTCDATA] + ", " + counters[TYPE_ENDCDATA] + "; " 164 + counters[TYPE_COMMENT] + ")"); 165 } 166 167 168 /** Expected values for events we may handle, default=ITEM_DONT_CARE. */ 169 protected String[] expected = 170 { 171 ITEM_DONT_CARE, /* startDTD */ 172 ITEM_DONT_CARE, /* endDTD */ 173 ITEM_DONT_CARE, /* startEntity */ 174 ITEM_DONT_CARE, /* endEntity */ 175 ITEM_DONT_CARE, /* startCDATA */ 176 ITEM_DONT_CARE, /* endCDATA */ 177 ITEM_DONT_CARE /* comment */ 178 }; 179 180 181 /** Cheap-o string representation of last event we got. */ 182 protected String lastItem = NOTHING_HANDLED; 183 184 185 /** 186 * Accessor for string representation of last event we got. 187 * @param s string to set 188 */ setLastItem(String s)189 protected void setLastItem(String s) 190 { 191 lastItem = s; 192 } 193 194 195 /** 196 * Accessor for string representation of last event we got. 197 * @return last event string we had 198 */ getLast()199 public String getLast() 200 { 201 return lastItem; 202 } 203 204 205 /** 206 * Ask us to report checkPass/Fail for certain events we handle. 207 * Since we may have to handle many events between when a test 208 * will be able to call us, testers can set this to have us 209 * automatically call checkPass when we see an item that matches, 210 * or to call checkFail when we get an unexpected item. 211 * Generally, we only call check* methods when: 212 * <ul> 213 * <li>containsString is not set, reset, or is ITEM_DONT_CARE, 214 * we do nothing (i.e. never call check* for this item)</li> 215 * <li>containsString is ITEM_CHECKFAIL, we will always call 216 * checkFail with the contents of any item if it occours</li> 217 * <li>containsString is anything else, we will grab a String 218 * representation of every item of that type that comes along, 219 * and if the containsString is found, case-sensitive, within 220 * the handled item's string, call checkPass, otherwise 221 * call checkFail</li> 222 * <ul> 223 * Note that any time we handle a particular event that was 224 * expected, we un-set the expected value for that item. This 225 * means that you can only ask us to validate one occourence 226 * of any particular event; all events after that one will 227 * be treated as ITEM_DONT_CARE. Callers can of course call 228 * setExpected again, of course, but this covers the case where 229 * we handle multiple events in a single block, perhaps out of 230 * the caller's direct control. 231 * Note that we first store the event via setLast(), then we 232 * validate the event as above, and then we potentially 233 * re-throw the exception as by setThrowWhen(). 234 * 235 * @param itemType which of the various types of items we might 236 * handle; should be defined as a constant by subclasses 237 * @param containsString a string to look for within whatever 238 * item we handle - usually checked for by seeing if the actual 239 * item we handle contains the containsString 240 */ setExpected(int itemType, String containsString)241 public void setExpected(int itemType, String containsString) 242 { 243 // Default to don't care on null 244 if (null == containsString) 245 containsString = ITEM_DONT_CARE; 246 247 try 248 { 249 expected[itemType] = containsString; 250 } 251 catch (ArrayIndexOutOfBoundsException aioobe) 252 { 253 // Just log it for callers reference and continue anyway 254 logger.logMsg(level, prefix + " setExpected called with illegal type:" + itemType); 255 } 256 } 257 258 259 /** 260 * Reset all items or counters we've handled. 261 */ reset()262 public void reset() 263 { 264 setLastItem(NOTHING_HANDLED); 265 for (int i = 0; i < counters.length; i++) 266 { 267 counters[i] = 0; 268 } 269 for (int j = 0; j < expected.length; j++) 270 { 271 expected[j] = ITEM_DONT_CARE; 272 } 273 } 274 275 276 /** 277 * Worker method to either log or call check* for this event. 278 * A simple way to validate for any kind of event. 279 * Note that various events may store the various arguments 280 * they get differently, so you should check the code to 281 * ensure you're specifying the correct containsString. 282 * 283 * @param type of event (startdtd|enddtd|etc) 284 * @param desc detail info from this kind of message 285 */ logOrCheck(int type, String desc)286 protected void logOrCheck(int type, String desc) 287 { 288 String tmp = getQuickCounters() + " " + desc; 289 // Either log the exception or call checkPass/checkFail 290 // as requested by setExpected for this type 291 if (ITEM_DONT_CARE == expected[type]) 292 { 293 // We don't care about this, just log it 294 logger.logMsg(level, tmp); 295 } 296 else if (ITEM_CHECKFAIL == expected[type]) 297 { 298 // We shouldn't have been called here, so fail 299 logger.checkFail(tmp + " was unexpected"); 300 } 301 else if ((null != desc) 302 && (desc.indexOf(expected[type]) > -1)) 303 { 304 // We got a warning the user expected, so pass 305 logger.checkPass(tmp + " matched"); 306 // Also reset this counter 307 //@todo needswork: this is very state-dependent, and 308 // might not be what the user expects, but at least it 309 // won't give lots of extra false fails or passes 310 expected[type] = ITEM_DONT_CARE; 311 } 312 else 313 { 314 // We got a warning the user didn't expect, so fail 315 logger.checkFail(tmp + " did not match"); 316 // Also reset this counter 317 expected[type] = ITEM_DONT_CARE; 318 } 319 } 320 321 322 ////////////////// Implement LexicalHandler ////////////////// startDTD(String name, String publicId, String systemId)323 public void startDTD (String name, String publicId, String systemId) 324 throws SAXException 325 { 326 // Note: this implies this class is !not! threadsafe 327 // Increment counter and save info 328 counters[TYPE_STARTDTD]++; 329 setLastItem("startDTD: " + name + ", " + publicId + ", " + systemId); 330 logOrCheck(TYPE_STARTDTD, getLast()); 331 if (null != defaultHandler) 332 defaultHandler.startDTD(name, publicId, systemId); 333 } 334 endDTD()335 public void endDTD () 336 throws SAXException 337 { 338 counters[TYPE_ENDDTD]++; 339 setLastItem("endDTD"); 340 logOrCheck(TYPE_ENDDTD, getLast()); 341 if (null != defaultHandler) 342 defaultHandler.endDTD(); 343 } 344 startEntity(String name)345 public void startEntity (String name) 346 throws SAXException 347 { 348 counters[TYPE_STARTENTITY]++; 349 setLastItem("startEntity: " + name); 350 logOrCheck(TYPE_STARTENTITY, getLast()); 351 if (null != defaultHandler) 352 defaultHandler.startEntity(name); 353 } 354 endEntity(String name)355 public void endEntity (String name) 356 throws SAXException 357 { 358 counters[TYPE_ENDENTITY]++; 359 setLastItem("endEntity: " + name); 360 logOrCheck(TYPE_ENDENTITY, getLast()); 361 if (null != defaultHandler) 362 defaultHandler.endEntity(name); 363 } 364 startCDATA()365 public void startCDATA () 366 throws SAXException 367 { 368 counters[TYPE_STARTCDATA]++; 369 setLastItem("startCDATA"); 370 logOrCheck(TYPE_STARTCDATA, getLast()); 371 if (null != defaultHandler) 372 defaultHandler.startCDATA(); 373 } 374 endCDATA()375 public void endCDATA () 376 throws SAXException 377 { 378 counters[TYPE_ENDCDATA]++; 379 setLastItem("endCDATA"); 380 logOrCheck(TYPE_ENDCDATA, getLast()); 381 if (null != defaultHandler) 382 defaultHandler.endCDATA(); 383 } 384 comment(char ch[], int start, int length)385 public void comment (char ch[], int start, int length) 386 throws SAXException 387 { 388 counters[TYPE_COMMENT]++; 389 StringBuffer buf = new StringBuffer("comment: "); 390 buf.append(ch); 391 buf.append(", "); 392 buf.append(start); 393 buf.append(", "); 394 buf.append(length); 395 396 setLastItem(buf.toString()); 397 logOrCheck(TYPE_COMMENT, getLast()); 398 if (null != defaultHandler) 399 defaultHandler.comment(ch, start, length); 400 } 401 402 } 403