blob: 21988899dfe938efaf71e8571c47f45a4806c988 [file] [log] [blame]
/*******************************************************************************
* 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);
}
}
}