1 /*
   2  * Copyright (c) 2014, 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.xslwrapper;
  21 
  22 import java.util.HashMap;
  23 import javax.xml.transform.Transformer;
  24 
  25 /**
  26  * A few default implementations of TransformWrapper methods.
  27  *
  28  * A TransformWrapperHelper implements a few of the common methods from
  29  * TransformWrapper that don't directly interact with the underlying processor.
  30  * Individual wrapper implementations are free to extend this class to get some
  31  * free code.
  32  */
  33 public abstract class TransformWrapperHelper implements TransformWrapper {
  34 
  35     /**
  36      * Constant denoting that indent should not be set.
  37      */
  38     private static final int NO_INDENT = -2;
  39 
  40     /**
  41      * Set of stylesheet parameters for use in transforms.
  42      */
  43     protected final HashMap<String,String> m_params = new HashMap<>();
  44 
  45     /**
  46      * If our wrapper has a built stylesheet ready.
  47      */
  48     protected volatile boolean m_stylesheetReady = false;
  49 
  50     /**
  51      * Current number of spaces to indent, default: NO_INDENT. Users call
  52      * setAttribute(ATTRIBUTE_INDENT, int) to set this. If it is set, it will be
  53      * applied to an underlying processor during each transform operation, where
  54      * supported.
  55      */
  56     protected int m_indent = NO_INDENT;
  57 
  58     /**
  59      * Reports if a pre-built/pre-compiled stylesheet is ready; presumably built
  60      * by calling buildStylesheet(xslName).
  61      *
  62      * @return true if one is ready; false otherwise
  63      *
  64      * @see #buildStylesheet(String xslName)
  65      */
  66     @Override
  67     public boolean isStylesheetReady() {
  68         return m_stylesheetReady;
  69     }
  70 
  71     /**
  72      * Set a stylesheet parameter for use in later transforms.
  73      *
  74      * This method merely stores the triple for use later in a transform
  75      * operation. Note that the actual mechanisims for setting parameters in
  76      * implementation differ, especially with regards to namespaces.
  77      *
  78      * Note that the namespace may not contain the "{" or "}" characters, since
  79      * these would be illegal XML namespaces anyways; an
  80      * IllegalArgumentException will be thrown. Note that the name may not begin
  81      * with the "{" character, since it would likely be an illegal XML name
  82      * anyways; an IllegalArgumentException will be thrown.
  83      *
  84      * @param namespace for the parameter
  85      * @param name of the parameter
  86      * @param value of the parameter
  87      *
  88      * @throws IllegalArgumentException thrown if the namespace appears to be
  89      * illegal.
  90      */
  91     @Override
  92     public void setParameter(String namespace, String name, String value)
  93             throws IllegalArgumentException {
  94         if (null != namespace) {
  95             if ((namespace.contains("{"))
  96                     || (namespace.contains("}"))) {
  97                 throw new IllegalArgumentException("setParameter: illegal namespace includes brackets: " + namespace);
  98             }
  99         }
 100         if (null != name) {
 101             if (name.startsWith("{")) {
 102                 throw new IllegalArgumentException(
 103                         "setParameter: illegal name begins with bracket: " + name);
 104             }
 105         }
 106 
 107         if (null != namespace) {
 108             m_params.put("{" + namespace + "}" + name, value);
 109         } else {
 110             m_params.put(name, value);
 111         }
 112     }
 113 
 114     /**
 115      * Get a parameter that was set with setParameter.
 116      *
 117      * Only returns parameters set locally, not parameters exposed by the
 118      * underlying processor implementation. Not terribly useful but I always
 119      * like providing gets for any sets I define.
 120      *
 121      * @param namespace for the parameter
 122      * @param name of the parameter
 123      */
 124     @Override
 125     public Object getParameter(String namespace, String name) {
 126         if (null == m_params) {
 127             return null;
 128         }
 129 
 130         if (null != namespace) {
 131             return m_params.get("{" + namespace + "}" + name);
 132         } else {
 133             return m_params.get(name);
 134         }
 135     }
 136 
 137     /**
 138      * Apply the parameters that were set with setParameter to our underlying
 139      * processor implementation.
 140      *
 141      * Subclasses may call this to apply all set parameters during each
 142      * transform if they override the applyParameter() method to set a single
 143      * parameter.
 144      *
 145      * This is a convenience method for getting data out of m_params that was
 146      * encoded by our setParameter().
 147      *
 148      * @param transformer a Transformer object.
 149      */
 150     protected void applyParameters(Transformer transformer) {
 151         m_params.forEach((key, value) -> {
 152             String namespace = null;
 153             String name;
 154             if (key.startsWith("{")) {
 155                 int idx = key.indexOf("}");
 156                 namespace = key.substring(1, idx);
 157                 name = key.substring(idx + 1);
 158             } else {
 159                 // namespace stays null
 160                 name = key;
 161             }
 162             // Call subclassed worker method for each parameter
 163             applyParameter(transformer, namespace, name, value);
 164         });
 165     }
 166 
 167     /**
 168      * Apply a single parameter to our underlying processor implementation: must
 169      * be overridden.
 170      *
 171      * Subclasses must override; this class will throw an IllegalStateException
 172      * since we can't do anything.
 173      *
 174      * @param transformer a Transformer object.
 175      * @param namespace for the parameter, may be null
 176      * @param name for the parameter, should not be null
 177      * @param value for the parameter, may be null
 178      */
 179     protected abstract void applyParameter(Transformer transformer, String namespace,
 180             String name, String value);
 181 
 182     /**
 183      * Reset our parameters and wrapper state, and optionally force creation of
 184      * a new underlying processor implementation.
 185      *
 186      * This class clears the indent and any parameters. Subclasses are free to
 187      * call us to get this default behavior or not. Note that subclasses must
 188      * clear m_stylesheetReady themselves if needed.
 189      *
 190      * @param newProcessor ignored in this class
 191      */
 192     @Override
 193     public void reset(boolean newProcessor) {
 194         m_params.clear();
 195         m_indent = NO_INDENT;
 196     }
 197 }