1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xalan.extensions;
  58. import java.util.Hashtable;
  59. import java.util.Vector;
  60. import java.io.IOException;
  61. import java.net.URL;
  62. import java.net.URLConnection;
  63. import java.io.InputStream;
  64. //import org.w3c.dom.Element;
  65. //import org.w3c.dom.Node;
  66. import org.apache.xml.dtm.DTM;
  67. import org.apache.xalan.transformer.TransformerImpl;
  68. import org.apache.xalan.templates.Stylesheet;
  69. import org.apache.xalan.templates.ElemTemplateElement;
  70. import org.apache.xalan.res.XSLMessages;
  71. import org.apache.xalan.res.XSLTErrorResources;
  72. import org.apache.xml.utils.QName;
  73. import org.apache.xml.utils.SystemIDResolver;
  74. import javax.xml.transform.TransformerException;
  75. // Temp??
  76. import org.apache.xalan.transformer.TransformerImpl;
  77. import org.apache.xpath.objects.XObject;
  78. import org.apache.xpath.XPathProcessorException;
  79. import org.apache.xml.utils.StringVector;
  80. import java.lang.reflect.Method;
  81. import org.apache.xml.dtm.ref.DTMNodeIterator;
  82. import org.apache.xml.dtm.ref.DTMNodeList;
  83. import org.apache.xml.dtm.DTMIterator;
  84. /**
  85. * <meta name="usage" content="internal"/>
  86. * Class handling an extension namespace for XPath. Provides functions
  87. * to test a function's existence and call a function
  88. *
  89. * @author Sanjiva Weerawarana (sanjiva@watson.ibm.com)
  90. */
  91. public class ExtensionHandlerGeneral extends ExtensionHandler
  92. {
  93. /** script source to run (if any) */
  94. private String m_scriptSrc;
  95. /** URL of source of script (if any) */
  96. private String m_scriptSrcURL;
  97. /** functions of namespace */
  98. private Hashtable m_functions = new Hashtable();
  99. /** elements of namespace */
  100. private Hashtable m_elements = new Hashtable();
  101. // BSF objects used to invoke BSF by reflection. Do not import the BSF classes
  102. // since we don't want a compile dependency on BSF.
  103. /** Instance of Manager class */
  104. private Object m_mgr; //
  105. /** BSF manager used to run scripts */
  106. private Object m_engine;
  107. // static fields
  108. /** BSFManager package name */
  109. private static final String BSF_MANAGER = "com.ibm.bsf.BSFManager";
  110. /** Manager class */
  111. private static Class managerClass;
  112. /** Manager load scripting engine */
  113. private static Method mgrLoadScriptingEngine;
  114. /** BSFEngine package name */
  115. private static final String BSF_ENGINE = "com.ibm.bsf.BSFEngine";
  116. /** Engine call to "compile" scripts */
  117. private static Method engineExec;
  118. /** Engine call to invoke scripts */
  119. private static Method engineCall;
  120. /** Negative one integer */
  121. private static final Integer NEG1INT = new Integer(-1);
  122. static
  123. {
  124. try
  125. {
  126. //managerClass = Class.forName(BSF_MANAGER);
  127. managerClass = ExtensionHandler.getClassForName(BSF_MANAGER);
  128. mgrLoadScriptingEngine = managerClass.getMethod("loadScriptingEngine",
  129. new Class[]{ String.class });
  130. //Class engineClass = Class.forName(BSF_ENGINE);
  131. Class engineClass = ExtensionHandler.getClassForName(BSF_ENGINE);
  132. engineExec = engineClass.getMethod("exec", new Class[]{ String.class,
  133. Integer.TYPE,
  134. Integer.TYPE,
  135. Object.class });
  136. engineCall = engineClass.getMethod("call", new Class[]{ Object.class,
  137. String.class,
  138. Class.forName(
  139. "[Ljava.lang.Object;") });
  140. }
  141. catch (Exception e)
  142. {
  143. managerClass = null;
  144. mgrLoadScriptingEngine = null;
  145. engineExec = null;
  146. engineCall = null;
  147. e.printStackTrace();
  148. }
  149. }
  150. /**
  151. * Construct a new extension namespace handler given all the information
  152. * needed.
  153. *
  154. * @param namespaceUri the extension namespace URI that I'm implementing
  155. * @param elemNames Vector of element names
  156. * @param funcNames string containing list of functions of extension NS
  157. * @param lang language of code implementing the extension
  158. * @param srcURL value of src attribute (if any) - treated as a URL
  159. * or a classname depending on the value of lang. If
  160. * srcURL is not null, then scriptSrc is ignored.
  161. * @param scriptLang Scripting language of implementation
  162. * @param scriptSrcURL URL of source script
  163. * @param scriptSrc the actual script code (if any)
  164. *
  165. * @throws TransformerException
  166. */
  167. public ExtensionHandlerGeneral(
  168. String namespaceUri, StringVector elemNames, StringVector funcNames, String scriptLang, String scriptSrcURL, String scriptSrc, String systemId)
  169. throws TransformerException
  170. {
  171. super(namespaceUri, scriptLang);
  172. if (elemNames != null)
  173. {
  174. Object junk = new Object();
  175. int n = elemNames.size();
  176. for (int i = 0; i < n; i++)
  177. {
  178. String tok = elemNames.elementAt(i);
  179. m_elements.put(tok, junk); // just stick it in there basically
  180. }
  181. }
  182. if (funcNames != null)
  183. {
  184. Object junk = new Object();
  185. int n = funcNames.size();
  186. for (int i = 0; i < n; i++)
  187. {
  188. String tok = funcNames.elementAt(i);
  189. m_functions.put(tok, junk); // just stick it in there basically
  190. }
  191. }
  192. m_scriptSrcURL = scriptSrcURL;
  193. m_scriptSrc = scriptSrc;
  194. if (m_scriptSrcURL != null)
  195. {
  196. URL url = null;
  197. try{
  198. url = new URL(m_scriptSrcURL);
  199. }
  200. catch (java.net.MalformedURLException mue)
  201. {
  202. int indexOfColon = m_scriptSrcURL.indexOf(':');
  203. int indexOfSlash = m_scriptSrcURL.indexOf('/');
  204. if ((indexOfColon != -1) && (indexOfSlash != -1)
  205. && (indexOfColon < indexOfSlash))
  206. {
  207. // The url is absolute.
  208. url = null;
  209. throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_COULD_NOT_FIND_EXTERN_SCRIPT, new Object[]{m_scriptSrcURL}), mue); //"src attribute not yet supported for "
  210. //+ scriptLang);
  211. }
  212. else
  213. {
  214. try{
  215. url = new URL(new URL(SystemIDResolver.getAbsoluteURI(systemId)), m_scriptSrcURL);
  216. }
  217. catch (java.net.MalformedURLException mue2)
  218. {
  219. throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_COULD_NOT_FIND_EXTERN_SCRIPT, new Object[]{m_scriptSrcURL}), mue2); //"src attribute not yet supported for "
  220. //+ scriptLang);
  221. }
  222. }
  223. }
  224. if (url != null)
  225. {
  226. try
  227. {
  228. URLConnection uc = url.openConnection();
  229. InputStream is = uc.getInputStream();
  230. byte []bArray = new byte[uc.getContentLength()];
  231. is.read(bArray);
  232. m_scriptSrc = new String(bArray);
  233. }
  234. catch (IOException ioe)
  235. {
  236. throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_COULD_NOT_FIND_EXTERN_SCRIPT, new Object[]{m_scriptSrcURL}), ioe); //"src attribute not yet supported for "
  237. //+ scriptLang);
  238. }
  239. }
  240. }
  241. if (null == managerClass)
  242. throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_INIT_BSFMGR, null)); //"Could not initialize BSF manager");
  243. try
  244. {
  245. m_mgr = managerClass.newInstance();
  246. m_engine = mgrLoadScriptingEngine.invoke(m_mgr,
  247. new Object[]{ scriptLang });
  248. // "Compile" the program
  249. engineExec.invoke(m_engine, new Object[]{ "XalanScript", NEG1INT,
  250. NEG1INT, m_scriptSrc });
  251. }
  252. catch (Exception e)
  253. {
  254. e.printStackTrace();
  255. throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_CMPL_EXTENSN, null), e); //"Could not compile extension", e);
  256. }
  257. }
  258. /**
  259. * Tests whether a certain function name is known within this namespace.
  260. * @param function name of the function being tested
  261. * @return true if its known, false if not.
  262. */
  263. public boolean isFunctionAvailable(String function)
  264. {
  265. return (m_functions.get(function) != null);
  266. }
  267. /**
  268. * Tests whether a certain element name is known within this namespace.
  269. * @param function name of the function being tested
  270. *
  271. * @param element name of the element being tested
  272. * @return true if its known, false if not.
  273. */
  274. public boolean isElementAvailable(String element)
  275. {
  276. return (m_elements.get(element) != null);
  277. }
  278. /**
  279. * Process a call to a function.
  280. *
  281. * @param funcName Function name.
  282. * @param args The arguments of the function call.
  283. * @param methodKey A key that uniquely identifies this class and method call.
  284. * @param exprContext The context in which this expression is being executed.
  285. *
  286. * @return the return value of the function evaluation.
  287. *
  288. * @throws TransformerException if parsing trouble
  289. */
  290. public Object callFunction(
  291. String funcName, Vector args, Object methodKey, ExpressionContext exprContext)
  292. throws TransformerException
  293. {
  294. Object[] argArray;
  295. try
  296. {
  297. argArray = new Object[args.size()];
  298. for (int i = 0; i < argArray.length; i++)
  299. {
  300. Object o = args.elementAt(i);
  301. argArray[i] = (o instanceof XObject) ? ((XObject) o).object() : o;
  302. o = argArray[i];
  303. if(null != o && o instanceof DTMIterator)
  304. {
  305. argArray[i] = new DTMNodeList((DTMIterator)o);
  306. }
  307. }
  308. return engineCall.invoke(m_engine, new Object[]{ null, funcName,
  309. argArray });
  310. }
  311. catch (Exception e)
  312. {
  313. e.printStackTrace();
  314. String msg = e.getMessage();
  315. if (null != msg)
  316. {
  317. if (msg.startsWith("Stopping after fatal error:"))
  318. {
  319. msg = msg.substring("Stopping after fatal error:".length());
  320. }
  321. // System.out.println("Call to extension function failed: "+msg);
  322. throw new TransformerException(e);
  323. }
  324. else
  325. {
  326. // Should probably make a TRaX Extension Exception.
  327. throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_CREATE_EXTENSN, new Object[]{funcName, e })); //"Could not create extension: " + funcName
  328. //+ " because of: " + e);
  329. }
  330. }
  331. }
  332. /**
  333. * Process a call to this extension namespace via an element. As a side
  334. * effect, the results are sent to the TransformerImpl's result tree.
  335. *
  336. * @param localPart Element name's local part.
  337. * @param element The extension element being processed.
  338. * @param transformer Handle to TransformerImpl.
  339. * @param stylesheetTree The compiled stylesheet tree.
  340. * @param mode The current mode.
  341. * @param sourceTree The root of the source tree (but don't assume
  342. * it's a Document).
  343. * @param sourceNode The current context node.
  344. * @param methodKey A key that uniquely identifies this class and method call.
  345. *
  346. * @throws XSLProcessorException thrown if something goes wrong
  347. * while running the extension handler.
  348. * @throws MalformedURLException if loading trouble
  349. * @throws FileNotFoundException if loading trouble
  350. * @throws IOException if loading trouble
  351. * @throws TransformerException if parsing trouble
  352. */
  353. public void processElement(
  354. String localPart, ElemTemplateElement element, TransformerImpl transformer,
  355. Stylesheet stylesheetTree, Object methodKey)
  356. throws TransformerException, IOException
  357. {
  358. Object result = null;
  359. XSLProcessorContext xpc = new XSLProcessorContext(transformer, stylesheetTree);
  360. try
  361. {
  362. Vector argv = new Vector(2);
  363. argv.addElement(xpc);
  364. argv.addElement(element);
  365. result = callFunction(localPart, argv, methodKey,
  366. transformer.getXPathContext().getExpressionContext());
  367. }
  368. catch (XPathProcessorException e)
  369. {
  370. // e.printStackTrace ();
  371. throw new TransformerException(e.getMessage(), e);
  372. }
  373. if (result != null)
  374. {
  375. xpc.outputToResultTree(stylesheetTree, result);
  376. }
  377. }
  378. }