| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| * |
| *************************************************************/ |
| |
| |
| package com.sun.star.script.framework.provider.beanshell; |
| |
| import com.sun.star.uno.XComponentContext; |
| import com.sun.star.lang.XMultiComponentFactory; |
| import com.sun.star.lang.XMultiServiceFactory; |
| import com.sun.star.lang.XSingleServiceFactory; |
| import com.sun.star.registry.XRegistryKey; |
| import com.sun.star.comp.loader.FactoryHelper; |
| import com.sun.star.frame.XModel; |
| import com.sun.star.uno.Type; |
| import com.sun.star.uno.Any; |
| |
| import com.sun.star.reflection.InvocationTargetException; |
| |
| import java.util.StringTokenizer; |
| |
| import java.net.URL; |
| |
| import bsh.Interpreter; |
| |
| import com.sun.star.document.XScriptInvocationContext; |
| import com.sun.star.script.provider.XScript; |
| import com.sun.star.script.provider.ScriptErrorRaisedException; |
| import com.sun.star.script.provider.ScriptExceptionRaisedException; |
| import com.sun.star.script.provider.ScriptFrameworkErrorException; |
| import com.sun.star.script.provider.ScriptFrameworkErrorType; |
| |
| |
| import com.sun.star.script.framework.provider.*; |
| import com.sun.star.script.framework.log.*; |
| import com.sun.star.script.framework.container.ScriptMetaData; |
| |
| public class ScriptProviderForBeanShell |
| { |
| public static class _ScriptProviderForBeanShell extends ScriptProvider |
| { |
| public _ScriptProviderForBeanShell(XComponentContext ctx) |
| { |
| super (ctx, "BeanShell"); |
| } |
| |
| public XScript getScript( /*IN*/String scriptURI ) |
| throws com.sun.star.uno.RuntimeException, |
| ScriptFrameworkErrorException |
| { |
| ScriptMetaData scriptData = null; |
| try |
| { |
| scriptData = getScriptData( scriptURI ); |
| ScriptImpl script = new ScriptImpl( m_xContext, scriptData, m_xModel, m_xInvocContext ); |
| return script; |
| } |
| catch ( com.sun.star.uno.RuntimeException re ) |
| { |
| throw new ScriptFrameworkErrorException( "Failed to create script object: " + re.getMessage(), |
| null, scriptData.getLanguageName(), language, ScriptFrameworkErrorType.UNKNOWN ); |
| } |
| } |
| |
| public boolean hasScriptEditor() |
| { |
| return true; |
| } |
| |
| public ScriptEditor getScriptEditor() |
| { |
| return ScriptEditorForBeanShell.getEditor(); |
| } |
| } |
| |
| /** |
| * Returns a factory for creating the service. |
| * This method is called by the <code>JavaLoader</code> |
| * <p> |
| * |
| * @param implName the name of the implementation for which a service is desired |
| * @param multiFactory the service manager to be used if needed |
| * @param regKey the registryKey |
| * @return returns a <code>XSingleServiceFactory</code> for creating |
| * the component |
| * @see com.sun.star.comp.loader.JavaLoader |
| */ |
| public static XSingleServiceFactory __getServiceFactory( String implName, |
| XMultiServiceFactory multiFactory, |
| XRegistryKey regKey ) |
| { |
| XSingleServiceFactory xSingleServiceFactory = null; |
| |
| if ( implName.equals( ScriptProviderForBeanShell._ScriptProviderForBeanShell.class.getName() ) ) |
| { |
| xSingleServiceFactory = FactoryHelper.getServiceFactory( |
| ScriptProviderForBeanShell._ScriptProviderForBeanShell.class, |
| "com.sun.star.script.ScriptProviderForBeanShell", |
| multiFactory, |
| regKey ); |
| } |
| |
| return xSingleServiceFactory; |
| } |
| } |
| |
| class ScriptImpl implements XScript |
| { |
| private ScriptMetaData metaData; |
| private XComponentContext m_xContext; |
| private XMultiComponentFactory m_xMultiComponentFactory; |
| private XModel m_xModel; |
| private XScriptInvocationContext m_xInvocContext; |
| |
| ScriptImpl( XComponentContext ctx, ScriptMetaData metaData, XModel xModel, |
| XScriptInvocationContext xContext ) throws com.sun.star.uno.RuntimeException |
| { |
| this.metaData = metaData; |
| this.m_xContext = ctx; |
| this.m_xModel = xModel; |
| this.m_xInvocContext = xContext; |
| |
| try |
| { |
| this.m_xMultiComponentFactory = m_xContext.getServiceManager(); |
| } |
| catch ( Exception e ) |
| { |
| LogUtils.DEBUG( LogUtils.getTrace( e ) ); |
| throw new com.sun.star.uno.RuntimeException( |
| "Error constructing ScriptImpl [beanshell]: " |
| + e.getMessage() ); |
| } |
| |
| LogUtils.DEBUG("ScriptImpl [beanshell] script data = " + metaData ); |
| } |
| /** |
| * documentStorageID and document reference |
| * for use in script name resolving |
| * |
| * @param aParams All parameters; pure, out params are |
| * undefined in sequence, i.e., the value |
| * has to be ignored by the callee |
| * |
| * @param aOutParamIndex Out indices |
| * |
| * @param aOutParam Out parameters |
| * |
| * @returns The value returned from the function |
| * being invoked |
| * |
| * @throws IllegalArgumentException If there is no matching script name |
| * |
| * @throws CannotConvertException If args do not match or cannot |
| * be converted the those of the |
| * invokee |
| * |
| * @throws InvocationTargetException If the running script throws |
| * an exception this information |
| * is captured and rethrown as |
| * this exception type. |
| */ |
| |
| public Object invoke( /*IN*/Object[] aParams, |
| /*OUT*/short[][] aOutParamIndex, |
| /*OUT*/Object[][] aOutParam ) |
| throws ScriptFrameworkErrorException, |
| InvocationTargetException |
| { |
| // Initialise the out paramters - not used at the moment |
| aOutParamIndex[0] = new short[0]; |
| aOutParam[0] = new Object[0]; |
| |
| |
| ClassLoader cl = null; |
| URL sourceUrl = null; |
| try { |
| cl = ClassLoaderFactory.getURLClassLoader( metaData ); |
| sourceUrl = metaData.getSourceURL(); |
| } |
| catch ( java.net.MalformedURLException mfu ) |
| { |
| // Framework error |
| throw new ScriptFrameworkErrorException( |
| mfu.getMessage(), null, |
| metaData.getLanguageName(), metaData.getLanguage(), |
| ScriptFrameworkErrorType.MALFORMED_URL ); |
| } |
| catch ( NoSuitableClassLoaderException nsc ) |
| { |
| // Framework error |
| throw new ScriptFrameworkErrorException( |
| nsc.getMessage(), null, |
| metaData.getLanguageName(), metaData.getLanguage(), |
| ScriptFrameworkErrorType.UNKNOWN ); |
| } |
| // Set class loader to be used for class files |
| // and jar files |
| Thread.currentThread().setContextClassLoader(cl); |
| Interpreter interpreter = new Interpreter(); |
| |
| interpreter.getNameSpace().clear(); |
| // Set class loader to be used by interpreter |
| // to look for classes by source e.g. interpreter |
| // will use this classloader to search classpath |
| // for source file ( bla.java ) on import or reference |
| interpreter.setClassLoader(cl); |
| try { |
| interpreter.set("XSCRIPTCONTEXT", |
| ScriptContext.createContext(m_xModel, m_xInvocContext, |
| m_xContext, m_xMultiComponentFactory)); |
| |
| interpreter.set("ARGUMENTS", aParams); |
| } |
| catch (bsh.EvalError e) { |
| // Framework error setting up context |
| throw new ScriptFrameworkErrorException( |
| e.getMessage(), null, |
| metaData.getLanguageName(), metaData.getLanguage(), |
| ScriptFrameworkErrorType.UNKNOWN ); |
| } |
| |
| try { |
| String source = null; |
| Object result = null; |
| |
| ScriptEditorForBeanShell editor = |
| ScriptEditorForBeanShell.getEditor( |
| sourceUrl ); |
| |
| if ( editor != null ) |
| { |
| result = editor.execute(); |
| |
| if (result == null) |
| { |
| return new Any(new Type(), null); |
| } |
| return result; |
| } |
| |
| metaData.loadSource(); |
| source = metaData.getSource(); |
| |
| if ( source == null || source.length() == 0 ) |
| { |
| throw new ScriptFrameworkErrorException( |
| "Failed to read script", null, |
| metaData.getLanguageName(), metaData.getLanguage(), |
| ScriptFrameworkErrorType.NO_SUCH_SCRIPT ); |
| } |
| result = interpreter.eval( source ); |
| |
| if (result == null) |
| { |
| return new Any(new Type(), null); |
| } |
| return result; |
| } |
| catch ( bsh.ParseException pe ) |
| { |
| throw new InvocationTargetException( "Beanshell failed to parse " + metaData.getLanguageName(), null, processBshException( pe, metaData.getLanguageName() ) ); |
| } |
| catch ( bsh.TargetError te ) |
| { |
| throw new InvocationTargetException( "Beanshell uncaught exception for " + metaData.getLanguageName(), null, processBshException( te, metaData.getLanguageName() ) ); |
| } |
| catch ( bsh.EvalError ex ) |
| { |
| throw new InvocationTargetException( "Beanshell error for " + metaData.getLanguageName(), null, processBshException( ex, metaData.getLanguageName() ) ); |
| } |
| catch ( Exception e ) |
| { |
| throw new ScriptFrameworkErrorException( |
| "Failed to read script", null, |
| metaData.getLanguageName(), metaData.getLanguage(), |
| ScriptFrameworkErrorType.UNKNOWN ); |
| } |
| } |
| private void raiseEditor( int lineNum ) |
| { |
| ScriptEditorForBeanShell editor = null; |
| try |
| { |
| URL sourceUrl = metaData.getSourceURL(); |
| editor = ScriptEditorForBeanShell.getEditor( sourceUrl ); |
| if ( editor == null ) |
| { |
| editor = ScriptEditorForBeanShell.getEditor(); |
| editor.edit( |
| ScriptContext.createContext(m_xModel, m_xInvocContext, |
| m_xContext, m_xMultiComponentFactory), metaData ); |
| editor = ScriptEditorForBeanShell.getEditor( sourceUrl ); |
| } |
| if ( editor != null ) |
| { |
| editor.indicateErrorLine( lineNum ); |
| } |
| } |
| catch( Exception ignore ) |
| { |
| } |
| } |
| |
| private ScriptErrorRaisedException processBshException( bsh.EvalError e, String script ) |
| { |
| LogUtils.DEBUG("Beanshell error RAW message " + e.getMessage()); |
| String message = e.getMessage(); |
| int usefullInfoIndex = message.lastIndexOf("\' :" ); |
| int lineNum = e.getErrorLineNumber(); |
| |
| raiseEditor( lineNum ); |
| |
| //String stackTrace = te.getScriptStackTrace(); // never seems to have any info?? |
| if ( usefullInfoIndex > -1 ) |
| { |
| message = message.substring( usefullInfoIndex + 2 ); |
| } |
| if ( e instanceof bsh.TargetError ) |
| { |
| LogUtils.DEBUG("got instance of TargetError"); |
| if ( usefullInfoIndex == -1 ) |
| { |
| message = ( ( bsh.TargetError)e ).getTarget().getMessage(); |
| } |
| String wrappedException = ""; |
| String full = e.toString(); |
| int index = full.indexOf( "Target exception:" ); |
| if ( index > -1 ) |
| { |
| String toParse = full.substring( index ); |
| LogUtils.DEBUG("About to parse " + toParse ); |
| StringTokenizer tokenizer = new StringTokenizer( full.substring( index ),":" ); |
| if ( tokenizer.countTokens() > 2 ) |
| { |
| LogUtils.DEBUG("First token = " + (String)tokenizer.nextElement()); |
| wrappedException = (String)tokenizer.nextElement(); |
| LogUtils.DEBUG("wrapped exception = = " + wrappedException ); |
| } |
| } |
| ScriptExceptionRaisedException se = new ScriptExceptionRaisedException( message); |
| se.lineNum = lineNum; |
| se.scriptName = script; |
| se.exceptionType = wrappedException; |
| se.language = "BeanShell"; |
| LogUtils.DEBUG("UnCaught Exception error: " ); |
| LogUtils.DEBUG("\tscript: " + script ); |
| LogUtils.DEBUG("\tline: " + lineNum ); |
| LogUtils.DEBUG("\twrapped exception: " + wrappedException ); |
| LogUtils.DEBUG("\tmessage: " + message ); |
| return se; |
| } |
| else |
| { |
| LogUtils.DEBUG("Error or ParseError Exception error: " ); |
| LogUtils.DEBUG("\tscript: " + script ); |
| LogUtils.DEBUG("\tline: " + lineNum ); |
| LogUtils.DEBUG("\tmessage: " + message ); |
| return new ScriptErrorRaisedException( message, null, script, "BeanShell", lineNum ); |
| } |
| } |
| } |