/******************************************************************************* | |
* Copyright (c) 2007 Standards for Technology in Automotive Retail | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v10.html | |
* | |
* Contributors: | |
* David Carver - STAR - bug 224197 - initial API and implementation | |
* based on work from Apache Xalan 2.7.0 | |
*******************************************************************************/ | |
/* | |
* Copyright 1999-2004 The Apache Software Foundation. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
/* | |
* $Id: ExtensionHandlerGeneral.java,v 1.3 2008/03/28 02:38:18 dacarver Exp $ | |
*/ | |
package org.eclipse.wst.xsl.core.internal.compiler.xslt10.extensions; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.lang.reflect.Method; | |
import java.net.URL; | |
import java.net.URLConnection; | |
import java.util.Hashtable; | |
import java.util.Vector; | |
import javax.xml.transform.TransformerException; | |
import org.eclipse.wst.xsl.core.compiler.xslt10.res.Messages; | |
import org.eclipse.wst.xsl.core.compiler.xslt10.res.XSLTErrorResources; | |
import org.eclipse.wst.xsl.core.internal.compiler.xslt10.templates.ElemTemplateElement; | |
import org.eclipse.wst.xsl.core.internal.compiler.xslt10.templates.Stylesheet; | |
import org.eclipse.wst.xsl.core.internal.compiler.xslt10.transformer.TransformerImpl; | |
import org.apache.xml.dtm.DTMIterator; | |
import org.apache.xml.dtm.ref.DTMNodeList; | |
import org.apache.xml.utils.StringVector; | |
import org.apache.xml.utils.SystemIDResolver; | |
import org.apache.xpath.XPathProcessorException; | |
import org.apache.xpath.functions.FuncExtFunction; | |
import org.apache.xpath.objects.XObject; | |
/** | |
* Class handling an extension namespace for XPath. Provides functions to test a | |
* function's existence and call a function | |
* | |
* @author Sanjiva Weerawarana (sanjiva@watson.ibm.com) | |
* @xsl.usage internal | |
*/ | |
public class ExtensionHandlerGeneral extends ExtensionHandler { | |
/** script source to run (if any) */ | |
private String m_scriptSrc; | |
/** URL of source of script (if any) */ | |
private String m_scriptSrcURL; | |
/** functions of namespace */ | |
private Hashtable m_functions = new Hashtable(); | |
/** elements of namespace */ | |
private Hashtable m_elements = new Hashtable(); | |
// BSF objects used to invoke BSF by reflection. Do not import the BSF | |
// classes | |
// since we don't want a compile dependency on BSF. | |
/** BSF manager used to run scripts */ | |
private Object m_engine; | |
/** Engine call to invoke scripts */ | |
private Method m_engineCall = null; | |
// static fields | |
/** BSFManager package name */ | |
private static String BSF_MANAGER; | |
/** Default BSFManager name */ | |
private static final String DEFAULT_BSF_MANAGER = "org.apache.bsf.BSFManager"; | |
/** Property name to load the BSFManager class */ | |
private static final String propName = "org.apache.xalan.extensions.bsf.BSFManager"; | |
/** Integer Zero */ | |
private static final Integer ZEROINT = new Integer(0); | |
static { | |
BSF_MANAGER = ObjectFactory | |
.lookUpFactoryClassName(propName, null, null); | |
if (BSF_MANAGER == null) { | |
BSF_MANAGER = DEFAULT_BSF_MANAGER; | |
} | |
} | |
/** | |
* Construct a new extension namespace handler given all the information | |
* needed. | |
* | |
* @param namespaceUri | |
* the extension namespace URI that I'm implementing | |
* @param elemNames | |
* Vector of element names | |
* @param funcNames | |
* string containing list of functions of extension NS | |
* @param scriptLang | |
* Scripting language of implementation | |
* @param scriptSrcURL | |
* URL of source script | |
* @param scriptSrc | |
* the actual script code (if any) | |
* @param systemId | |
* | |
* @throws TransformerException | |
*/ | |
public ExtensionHandlerGeneral(String namespaceUri, StringVector elemNames, | |
StringVector funcNames, String scriptLang, String scriptSrcURL, | |
String scriptSrc, String systemId) throws TransformerException { | |
super(namespaceUri, scriptLang); | |
if (elemNames != null) { | |
Object junk = new Object(); | |
int n = elemNames.size(); | |
for (int i = 0; i < n; i++) { | |
String tok = elemNames.elementAt(i); | |
m_elements.put(tok, junk); // just stick it in there basically | |
} | |
} | |
if (funcNames != null) { | |
Object junk = new Object(); | |
int n = funcNames.size(); | |
for (int i = 0; i < n; i++) { | |
String tok = funcNames.elementAt(i); | |
m_functions.put(tok, junk); // just stick it in there basically | |
} | |
} | |
m_scriptSrcURL = scriptSrcURL; | |
m_scriptSrc = scriptSrc; | |
if (m_scriptSrcURL != null) { | |
URL url = null; | |
try { | |
url = new URL(m_scriptSrcURL); | |
} catch (java.net.MalformedURLException mue) { | |
int indexOfColon = m_scriptSrcURL.indexOf(':'); | |
int indexOfSlash = m_scriptSrcURL.indexOf('/'); | |
if ((indexOfColon != -1) && (indexOfSlash != -1) | |
&& (indexOfColon < indexOfSlash)) { | |
// The url is absolute. | |
url = null; | |
throw new TransformerException(Messages.createMessage( | |
XSLTErrorResources.ER_COULD_NOT_FIND_EXTERN_SCRIPT, | |
new Object[] { m_scriptSrcURL }), mue); // "src | |
// attribute | |
// not yet | |
// supported | |
// for " | |
// + scriptLang); | |
} else { | |
try { | |
url = new URL(new URL(SystemIDResolver | |
.getAbsoluteURI(systemId)), m_scriptSrcURL); | |
} catch (java.net.MalformedURLException mue2) { | |
throw new TransformerException( | |
Messages | |
.createMessage( | |
XSLTErrorResources.ER_COULD_NOT_FIND_EXTERN_SCRIPT, | |
new Object[] { m_scriptSrcURL }), | |
mue2); // "src attribute not yet supported for | |
// " | |
// + scriptLang); | |
} | |
} | |
} | |
if (url != null) { | |
try { | |
URLConnection uc = url.openConnection(); | |
InputStream is = uc.getInputStream(); | |
byte[] bArray = new byte[uc.getContentLength()]; | |
is.read(bArray); | |
m_scriptSrc = new String(bArray); | |
} catch (IOException ioe) { | |
throw new TransformerException(Messages.createMessage( | |
XSLTErrorResources.ER_COULD_NOT_FIND_EXTERN_SCRIPT, | |
new Object[] { m_scriptSrcURL }), ioe); // "src | |
// attribute | |
// not yet | |
// supported | |
// for " | |
// + scriptLang); | |
} | |
} | |
} | |
Object manager = null; | |
try { | |
manager = ObjectFactory.newInstance(BSF_MANAGER, ObjectFactory | |
.findClassLoader(), true); | |
} catch (ObjectFactory.ConfigurationError e) { | |
e.printStackTrace(); | |
} | |
if (manager == null) { | |
throw new TransformerException(Messages.createMessage( | |
XSLTErrorResources.ER_CANNOT_INIT_BSFMGR, null)); // "Could | |
// not | |
// initialize | |
// BSF | |
// manager"); | |
} | |
try { | |
Method loadScriptingEngine = manager.getClass().getMethod( | |
"loadScriptingEngine", new Class[] { String.class }); | |
m_engine = loadScriptingEngine.invoke(manager, | |
new Object[] { scriptLang }); | |
Method engineExec = m_engine.getClass().getMethod( | |
"exec", | |
new Class[] { String.class, Integer.TYPE, Integer.TYPE, | |
Object.class }); | |
// "Compile" the program | |
engineExec.invoke(m_engine, new Object[] { "XalanScript", ZEROINT, | |
ZEROINT, m_scriptSrc }); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
throw new TransformerException(Messages.createMessage( | |
XSLTErrorResources.ER_CANNOT_CMPL_EXTENSN, null), e); // "Could | |
// not | |
// compile | |
// extension", | |
// e); | |
} | |
} | |
/** | |
* Tests whether a certain function name is known within this namespace. | |
* | |
* @param function | |
* name of the function being tested | |
* @return true if its known, false if not. | |
*/ | |
@Override | |
public boolean isFunctionAvailable(String function) { | |
return (m_functions.get(function) != null); | |
} | |
/** | |
* Tests whether a certain element name is known within this namespace. | |
* | |
* @param element | |
* name of the element being tested | |
* @return true if its known, false if not. | |
*/ | |
@Override | |
public boolean isElementAvailable(String element) { | |
return (m_elements.get(element) != null); | |
} | |
/** | |
* Process a call to a function. | |
* | |
* @param funcName | |
* Function name. | |
* @param args | |
* The arguments of the function call. | |
* @param methodKey | |
* A key that uniquely identifies this class and method call. | |
* @param exprContext | |
* The context in which this expression is being executed. | |
* | |
* @return the return value of the function evaluation. | |
* | |
* @throws TransformerException | |
* if parsing trouble | |
*/ | |
@Override | |
public Object callFunction(String funcName, Vector args, Object methodKey, | |
ExpressionContext exprContext) throws TransformerException { | |
Object[] argArray; | |
try { | |
argArray = new Object[args.size()]; | |
for (int i = 0; i < argArray.length; i++) { | |
Object o = args.elementAt(i); | |
argArray[i] = (o instanceof XObject) ? ((XObject) o).object() | |
: o; | |
o = argArray[i]; | |
if (null != o && o instanceof DTMIterator) { | |
argArray[i] = new DTMNodeList((DTMIterator) o); | |
} | |
} | |
if (m_engineCall == null) { | |
m_engineCall = m_engine.getClass().getMethod( | |
"call", | |
new Class[] { Object.class, String.class, | |
Object[].class }); | |
} | |
return m_engineCall.invoke(m_engine, new Object[] { null, funcName, | |
argArray }); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
String msg = e.getMessage(); | |
if (null != msg) { | |
if (msg.startsWith("Stopping after fatal error:")) { | |
msg = msg.substring("Stopping after fatal error:".length()); | |
} | |
// System.out.println("Call to extension function failed: | |
// "+msg); | |
throw new TransformerException(e); | |
} else { | |
// Should probably make a TRaX Extension Exception. | |
throw new TransformerException(Messages.createMessage( | |
XSLTErrorResources.ER_CANNOT_CREATE_EXTENSN, | |
new Object[] { funcName, e })); // "Could not create | |
// extension: " + | |
// funcName | |
// + " because of: " + e); | |
} | |
} | |
} | |
/** | |
* Process a call to an XPath extension function | |
* | |
* @param extFunction | |
* The XPath extension function | |
* @param args | |
* The arguments of the function call. | |
* @param exprContext | |
* The context in which this expression is being executed. | |
* @return the return value of the function evaluation. | |
* @throws TransformerException | |
*/ | |
@Override | |
public Object callFunction(FuncExtFunction extFunction, Vector args, | |
ExpressionContext exprContext) throws TransformerException { | |
return callFunction(extFunction.getFunctionName(), args, extFunction | |
.getMethodKey(), exprContext); | |
} | |
/** | |
* Process a call to this extension namespace via an element. As a side | |
* effect, the results are sent to the TransformerImpl's result tree. | |
* | |
* @param localPart | |
* Element name's local part. | |
* @param element | |
* The extension element being processed. | |
* @param transformer | |
* Handle to TransformerImpl. | |
* @param stylesheetTree | |
* The compiled stylesheet tree. | |
* @param methodKey | |
* A key that uniquely identifies this class and method call. | |
* | |
* @throws XSLProcessorException | |
* thrown if something goes wrong while running the extension | |
* handler. | |
* @throws MalformedURLException | |
* if loading trouble | |
* @throws FileNotFoundException | |
* if loading trouble | |
* @throws IOException | |
* if loading trouble | |
* @throws TransformerException | |
* if parsing trouble | |
*/ | |
@Override | |
public void processElement(String localPart, ElemTemplateElement element, | |
TransformerImpl transformer, Stylesheet stylesheetTree, | |
Object methodKey) throws TransformerException, IOException { | |
Object result = null; | |
XSLProcessorContext xpc = new XSLProcessorContext(transformer, | |
stylesheetTree); | |
try { | |
Vector argv = new Vector(2); | |
argv.addElement(xpc); | |
argv.addElement(element); | |
result = callFunction(localPart, argv, methodKey, | |
(ExpressionContext) transformer.getXPathContext() | |
.getExpressionContext()); | |
} catch (XPathProcessorException e) { | |
// e.printStackTrace (); | |
throw new TransformerException(e.getMessage(), e); | |
} | |
if (result != null) { | |
xpc.outputToResultTree(stylesheetTree, result); | |
} | |
} | |
} |