1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 package org.apache.qetest.trax;
  21 
  22 import javax.xml.transform.ErrorListener;
  23 import javax.xml.transform.TransformerException;
  24 import org.apache.qetest.CheckingHandler;
  25 import static org.apache.qetest.CheckingHandler.Expectation.ITEM_CHECKPASS;
  26 import static org.apache.qetest.CheckingHandler.Expectation.ITEM_DONT_CARE;
  27 import static org.testng.Assert.fail;
  28 
  29 /**
  30  * Cheap-o ErrorListener for use by API tests.
  31  * <p>
  32  * Implements javax.xml.transform.ErrorListener and dumps everything to a
  33  * Logger; is separately settable as to when it will throw an exception; also
  34  * separately settable as to when we should validate specific events that we
  35  * handle.</p>
  36  */
  37 public class CheckingErrorListener implements CheckingHandler, ErrorListener {
  38 
  39     /**
  40      * Constants determining when we should throw exceptions.
  41      * <ul>Flags are combineable like a bitfield.
  42      * <li>THROW_NEVER - never ever (always continue - note this may have
  43      * unexpected effects when fatalErrors happen, see
  44      * {@link javax.xml.transform.ErrorListener#fatalError(javax.xml.transform.TransformerException)}</li>
  45      * <li>THROW_ON_WARNING - throw only on warnings</li>
  46      * <li>THROW_ON_ERROR - throw only on errors</li>
  47      * <li>THROW_ON_FATAL - throw only on fatalErrors - default</li>
  48      * <li>THROW_ALWAYS - always throw exceptions</li>
  49      * </ul>
  50      */
  51     public static final int THROW_NEVER = 0;
  52 
  53     /**
  54      * THROW_ON_WARNING - throw only on warnings.
  55      */
  56     public static final int THROW_ON_WARNING = 1;
  57 
  58     /**
  59      * THROW_ON_ERROR - throw only on errors.
  60      */
  61     public static final int THROW_ON_ERROR = 2;
  62 
  63     /**
  64      * THROW_ON_FATAL - throw only on fatalErrors - default.
  65      */
  66     public static final int THROW_ON_FATAL = 4;
  67 
  68     /**
  69      * THROW_ALWAYS - always throw exceptions.
  70      */
  71     public static final int THROW_ALWAYS = THROW_ON_WARNING | THROW_ON_ERROR
  72             | THROW_ON_FATAL;
  73 
  74     /**
  75      * If we should throw an exception for each message type.
  76      */
  77     protected final int throwWhen;
  78 
  79     /**
  80      * Constructor set when we should re-throw exceptions.
  81      *
  82      * @param t THROW_WHEN_* constant as to when we should re-throw an exception
  83      * when we are called.
  84      */
  85     public CheckingErrorListener(int t) {
  86         throwWhen = t;
  87     }
  88     
  89     /**
  90      * Default constructor will behave as default. Throw only when there is 
  91      * non-recoverable error.
  92      */
  93     public CheckingErrorListener() {
  94         this(THROW_ON_FATAL);
  95     }
  96 
  97     /**
  98      * Tells us when we should re-throw exceptions.
  99      *
 100      * @return THROW_WHEN_* constant as to when we should re-throw an exception
 101      * when we are called
 102      */
 103     public int getThrowWhen() {
 104         return throwWhen;
 105     }
 106 
 107     /**
 108      * Constant for items returned in getCounters: messages.
 109      */
 110     public static final int TYPE_WARNING = 0;
 111 
 112     /**
 113      * Constant for items returned in getCounters: errors.
 114      */
 115     public static final int TYPE_ERROR = 1;
 116 
 117     /**
 118      * Constant for items returned in getCounters: fatalErrors.
 119      */
 120     public static final int TYPE_FATALERROR = 2;
 121 
 122     /**
 123      * Expected values for events we may handle, default=ITEM_DONT_CARE.
 124      */
 125     private final Expectation[] expected = {
 126                 ITEM_DONT_CARE, /* warning */
 127                 ITEM_DONT_CARE, /* error */
 128                 ITEM_DONT_CARE /* fatalError */};
 129 
 130     /**
 131      * Ask us to report checkPass/Fail for certain events we handle. Since we
 132      * may have to handle many events between when a test will be able to call
 133      * us, testers can set this to have us automatically call checkPass when we
 134      * see an item that matches, or to call checkFail when we get an unexpected
 135      * item. Generally, we only call check* methods when:
 136      * <ul>
 137      * <li>containsString is not set, reset, or is ITEM_DONT_CARE, we do nothing
 138      * (i.e. never call check* for this item)</li>
 139      * <li>containsString is ITEM_CHECKFAIL, we will always call checkFail with
 140      * the contents of any item if it occurs</li>
 141      * <li>containsString is anything else, we will grab a String representation
 142      * of every item of that type that comes along, and if the containsString is
 143      * found, case-sensitive, within the handled item's string, call checkPass,
 144      * otherwise call checkFail</li>
 145      * </ul>
 146      * Note that any time we handle a particular event that was expected, we
 147      * un-set the expected value for that item. This means that you can only ask
 148      * us to validate one occurrence of any particular event; all events after
 149      * that one will be treated as ITEM_DONT_CARE. Callers can of course call
 150      * setExpected again, of course, but this covers the case where we handle
 151      * multiple events in a single block, perhaps out of the caller's direct
 152      * control. Note that we first store the event via setLast(), then we
 153      * validate the event as above, and then we potentially re-throw the
 154      * exception as by setThrowWhen().
 155      *
 156      * @param itemType which of the various types of items we might handle;
 157      * should be defined as a constant by subclasses
 158      * @param expectation expectation if we need check or not.
 159      */
 160     @Override
 161     public void setExpected(int itemType, Expectation expectation) {
 162         expected[itemType] = expectation;
 163     }
 164 
 165     /**
 166      * Reset all items or counters we've handled.
 167      */
 168     @Override
 169     public void reset() {
 170         for (int j = 0; j < expected.length; j++) {
 171             expected[j] = ITEM_DONT_CARE;
 172         }
 173     }
 174 
 175     /**
 176      * Grab basic info out of a TransformerException. Worker method to hide
 177      * implementation; currently just calls exception.getMessageAndLocation().
 178      *
 179      * @param exception to get information from
 180      * @return simple string describing the exception (getMessageAndLocation())
 181      */
 182     public String getTransformerExceptionInfo(TransformerException exception) {
 183         if (exception == null) {
 184             return "";  // Don't return null, just to make other code here simpler
 185         }
 186         return exception.getMessageAndLocation();
 187     }
 188 
 189     /**
 190      * Implementation of warning; calls logMsg with info contained in exception.
 191      *
 192      * @param exception provided by Transformer
 193      * @exception TransformerException thrown only if asked to or if loggers are
 194      * bad
 195      */
 196     @Override
 197     public void warning(TransformerException exception) throws TransformerException {
 198         // Log or validate the exception
 199         if(expected[TYPE_WARNING] == ITEM_CHECKPASS)
 200             fail("Unexpected error: ex " + exception);
 201 
 202         // Also re-throw the exception if asked to
 203         if ((throwWhen & THROW_ON_WARNING) == THROW_ON_WARNING) {
 204             // Note: re-throw the SAME exception, not a new one!
 205             throw exception;
 206         }
 207     }
 208 
 209     /**
 210      * Implementation of error; calls logMsg with info contained in exception.
 211      * Only ever throws an exception itself if asked to or if loggers are bad.
 212      *
 213      * @param exception provided by Transformer
 214      * @exception TransformerException thrown only if asked to.
 215      */
 216     @Override
 217     public void error(TransformerException exception) throws TransformerException {
 218         // validate the exception
 219         if(expected[TYPE_ERROR] == ITEM_CHECKPASS)
 220             fail("Unexpected error: ex " + exception);
 221 
 222         // Also re-throw the exception if asked to
 223         if ((throwWhen & THROW_ON_ERROR) == THROW_ON_ERROR) {
 224             // Note: re-throw the SAME exception, not a new one!
 225             throw exception;
 226         }
 227     }
 228 
 229     /**
 230      * Implementation of error; calls logMsg with info contained in exception.
 231      * Only ever throws an exception itself if asked to or if loggers are bad.
 232      * Note that this may cause unusual behavior since we may not actually
 233      * re-throw the exception, even though it was 'fatal'.
 234      *
 235      * @param exception provided by Transformer
 236      * @exception TransformerException thrown only if asked to.
 237      */
 238     @Override
 239     public void fatalError(TransformerException exception) throws TransformerException {
 240         // validate the exception
 241         if(expected[TYPE_FATALERROR] == ITEM_CHECKPASS)
 242             fail("Unexpected fatal error: ex " + exception);
 243 
 244         // Also re-throw the exception if asked to
 245         if ((throwWhen & THROW_ON_FATAL) == THROW_ON_FATAL) {
 246             // Note: re-throw the SAME exception, not a new one!
 247             throw exception;
 248         }
 249     }
 250 }