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 package org.apache.qetest.xslwrapper; 22 23 import java.util.Enumeration; 24 import java.util.Hashtable; 25 import java.util.Properties; 26 27 /** 28 * A few default implementations of TransformWrapper methods. 29 * 30 * A TransformWrapperHelper implements a few of the common methods 31 * from TransformWrapper that don't directly interact with the 32 * underlying processor. Individual wrapper implementations are 33 * free to extend this class to get some free code. 34 * 35 * @author Shane Curcuru 36 * @version $Id$ 37 */ 38 public abstract class TransformWrapperHelper implements TransformWrapper 39 { 40 41 /** Constant denoting that indent should not be set. */ 42 protected static final int NO_INDENT = -2; 43 44 45 /** 46 * Current number of spaces to indent, default: NO_INDENT. 47 * Users call setAttribute(ATTRIBUTE_INDENT, int) to set this. 48 * If it is set, it will be applied to an underlying processor 49 * during each transform operation, where supported. 50 */ 51 protected int m_indent = NO_INDENT; 52 53 54 /** 55 * Allows the user to ask the wrapper to set specific 56 * attributes on the underlying implementation. 57 * 58 * Supported attributes in this class include: 59 * ATTRIBUTE_INDENT 60 * 61 * //@todo define behavior for subclasses who want our default 62 * behavior but also want to throw the exception for 63 * attributes that are not recognized. 64 * 65 * @param name The name of the attribute. 66 * @param value The value of the attribute. 67 * 68 * @throws IllegalArgumentException thrown only if we can't 69 * parse an int from the value 70 * 71 * @see #ATTRIBUTE_INDENT 72 */ setAttribute(String name, Object value)73 public void setAttribute(String name, Object value) 74 throws IllegalArgumentException 75 { 76 if (ATTRIBUTE_INDENT.equals(name)) 77 { 78 try 79 { 80 m_indent = (new Integer((String)value)).intValue(); 81 } 82 catch (Exception e) 83 { 84 throw new IllegalArgumentException("setAttribute: bad value: " + value); 85 } 86 } 87 } 88 89 90 /** 91 * Allows the user to set specific attributes on the testing 92 * utility or it's underlying product object under test. 93 * 94 * This method should attempt to set any applicable attributes 95 * found in the given attrs onto itself, and will ignore any and 96 * all attributes it does not recognize. It should never 97 * throw exceptions. This method may overwrite any previous 98 * attributes that were set. Currently since this takes a 99 * Properties block you may only be able to set objects that 100 * are Strings, although individual implementations may 101 * attempt to use Hashtable.get() on only the local part. 102 * 103 * Currently unimplemented; no-op. 104 * 105 * @param attrs Props of various name, value attrs. 106 */ applyAttributes(Properties attrs)107 public void applyAttributes(Properties attrs) 108 { 109 /* no-op */; 110 } 111 112 113 /** 114 * Allows the user to retrieve specific attributes on the 115 * underlying implementation. 116 * 117 * This class merely returns the indent for ATTRIBUTE_INDENT. 118 * 119 * //@todo define behavior for subclasses who want our default 120 * behavior but also want to throw the exception for 121 * attributes that are not recognized. 122 * 123 * @param name The name of the attribute. 124 * @return value The value of the attribute. 125 * @throws IllegalArgumentException not thrown from this class 126 * 127 * @see #ATTRIBUTE_INDENT 128 */ getAttribute(String name)129 public Object getAttribute(String name) throws IllegalArgumentException 130 { 131 if (ATTRIBUTE_INDENT.equals(name)) 132 { 133 return new Integer(m_indent); 134 } 135 return null; 136 } 137 138 139 /** If our wrapper has a built stylesheet ready. */ 140 protected boolean m_stylesheetReady = false; 141 142 143 /** 144 * Reports if a pre-built/pre-compiled stylesheet is ready; 145 * presumably built by calling buildStylesheet(xslName). 146 * 147 * @return true if one is ready; false otherwise 148 * 149 * @see #buildStylesheet(String xslName) 150 */ isStylesheetReady()151 public boolean isStylesheetReady() 152 { 153 return m_stylesheetReady; 154 } 155 156 157 /** Set of stylesheet parameters for use in transforms. */ 158 protected Hashtable m_params = null; 159 160 161 /** 162 * Set a stylesheet parameter for use in later transforms. 163 * 164 * This method merely stores the triple for use later in a 165 * transform operation. Note that the actual mechanisims for 166 * setting parameters in implementation differ, especially with 167 * regards to namespaces. 168 * 169 * Note that the namespace may not contain the "{" or "}" 170 * characters, since these would be illegal XML namespaces 171 * anyways; an IllegalArgumentException will be thrown. 172 * Note that the name may not begin with the "{" 173 * character, since it would likely be an illegal XML name 174 * anyways; an IllegalArgumentException will be thrown. 175 * 176 * @param namespace for the parameter 177 * @param name of the parameter 178 * @param value of the parameter 179 * 180 * @throws IllegalArgumentException thrown if the namespace 181 * appears to be illegal. 182 */ setParameter(String namespace, String name, Object value)183 public void setParameter(String namespace, String name, Object value) 184 throws IllegalArgumentException 185 { 186 if (null != namespace) 187 { 188 if ((namespace.indexOf("{") > -1) 189 || (namespace.indexOf("}") > -1)) 190 throw new IllegalArgumentException( 191 "setParameter: illegal namespace includes brackets: " + namespace); 192 } 193 if (null != name) 194 { 195 if (name.startsWith("{")) 196 throw new IllegalArgumentException( 197 "setParameter: illegal name begins with bracket: " + name); 198 } 199 200 if (null == m_params) 201 m_params = new Hashtable(); 202 203 if (null != namespace) 204 { 205 m_params.put("{" + namespace + "}" + name, value); 206 } 207 else 208 { 209 m_params.put(name, value); 210 } 211 } 212 213 214 /** 215 * Get a parameter that was set with setParameter. 216 * 217 * Only returns parameters set locally, not parameters exposed 218 * by the underlying processor implementation. Not terribly useful 219 * but I always like providing gets for any sets I define. 220 * 221 * @param namespace for the parameter 222 * @param name of the parameter 223 * 224 * @param value of the parameter; null if not found 225 */ getParameter(String namespace, String name)226 public Object getParameter(String namespace, String name) 227 { 228 if (null == m_params) 229 return null; 230 231 if (null != namespace) 232 { 233 return m_params.get("{" + namespace + "}" + name); 234 } 235 else 236 { 237 return m_params.get(name); 238 } 239 } 240 241 242 /** 243 * Apply the parameters that were set with setParameter to 244 * our underlying processor implementation. 245 * 246 * Subclasses may call this to apply all set parameters during 247 * each transform if they override the applyParameter() method 248 * to set a single parameter. 249 * 250 * This is a convenience method for getting data out of 251 * m_params that was encoded by our setParameter(). 252 * 253 * @param passThru to be passed to each applyParameter() method 254 * call - for TrAX, you might pass a Transformer object. 255 */ applyParameters(Object passThru)256 protected void applyParameters(Object passThru) 257 { 258 if (null == m_params) 259 return; 260 261 for (Enumeration keys = m_params.keys(); 262 keys.hasMoreElements(); 263 /* no increment portion */ ) 264 { 265 String namespace = null; 266 String name = null; 267 String key = keys.nextElement().toString(); 268 //@todo compare with TransformerImpl.setParameter's use of a StringTokenizer(..., "{}"... 269 // Decode the namespace, if present 270 if (key.startsWith("{")) 271 { 272 int idx = key.indexOf("}"); 273 namespace = key.substring(1, idx); 274 name = key.substring(idx + 1); //@todo check for out of range? 275 } 276 else 277 { 278 // namespace stays null 279 name = key; 280 } 281 // Call subclassed worker method for each parameter 282 applyParameter(passThru, namespace, name, m_params.get(key)); 283 } 284 } 285 286 287 /** 288 * Apply a single parameter to our underlying processor 289 * implementation: must be overridden. 290 * 291 * Subclasses must override; this class will throw an 292 * IllegalStateException since we can't do anything. 293 * 294 * @param passThru to be passed to each applyParameter() method 295 * call - for TrAX, you might pass a Transformer object. 296 * @param namespace for the parameter, may be null 297 * @param name for the parameter, should not be null 298 * @param value for the parameter, may be null 299 */ applyParameter(Object passThru, String namespace, String name, Object value)300 protected void applyParameter(Object passThru, String namespace, 301 String name, Object value) 302 { 303 throw new IllegalStateException("TransformWrapperHelper.applyParameter must be overridden!"); 304 } 305 306 307 /** 308 * Reset our parameters and wrapper state, and optionally 309 * force creation of a new underlying processor implementation. 310 * 311 * This class clears the indent and any parameters. 312 * Subclasses are free to call us to get this default behavior 313 * or not. Note that subclasses must clear m_stylesheetReady 314 * themselves if needed. 315 * 316 * @param newProcessor ignored in this class 317 */ reset(boolean newProcessor)318 public void reset(boolean newProcessor) 319 { 320 m_params = null; 321 m_indent = NO_INDENT; 322 } 323 324 325 /** 326 * Static worker method to return default array of longs. 327 * 328 * Simply returns long[] pre-filled to TIME_UNUSED, suitable 329 * for returning from various transform API's. May be called 330 * by external callers to get pre-sized array. 331 * 332 * @return long[] = TIME_UNUSED 333 */ getTimeArray()334 public static long[] getTimeArray() 335 { 336 return new long[] 337 { 338 TIME_UNUSED, /* IDX_OVERALL */ 339 TIME_UNUSED, /* IDX_XSLREAD */ 340 TIME_UNUSED, /* IDX_XSLBUILD */ 341 TIME_UNUSED, /* IDX_XMLREAD */ 342 TIME_UNUSED, /* IDX_XMLBUILD */ 343 TIME_UNUSED, /* IDX_TRANSFORM */ 344 TIME_UNUSED, /* IDX_RESULTWRITE */ 345 TIME_UNUSED /* IDX_FIRSTLATENCY */ 346 }; 347 } 348 349 350 /** 351 * Static worker method to return description of timing slots. 352 * 353 * @return String describing this idx slot in a getTimeArray 354 */ getTimeArrayDesc(int idx)355 public static String getTimeArrayDesc(int idx) 356 { 357 switch (idx) 358 { 359 case IDX_OVERALL: 360 return "OVERALL"; 361 362 case IDX_XSLREAD: 363 return "XSLREAD"; 364 365 case IDX_XSLBUILD: 366 return "XSLBUILD"; 367 368 case IDX_XMLREAD: 369 return "XMLREAD"; 370 371 case IDX_XMLBUILD: 372 return "XMLBUILD"; 373 374 case IDX_TRANSFORM: 375 return "TRANSFORM"; 376 377 case IDX_RESULTWRITE: 378 return "RESULTWRITE"; 379 380 case IDX_FIRSTLATENCY: 381 return "FIRSTLATENCY"; 382 383 default: 384 return "ERROR:unknown-getTimeArrayDesc-idx"; 385 } 386 } 387 } 388