/* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ package com.sun.star.script.framework.provider.beanshell; import bsh.Interpreter; import com.sun.star.comp.loader.FactoryHelper; import com.sun.star.document.XScriptInvocationContext; import com.sun.star.frame.XModel; import com.sun.star.lang.XMultiComponentFactory; import com.sun.star.lang.XMultiServiceFactory; import com.sun.star.lang.XSingleServiceFactory; import com.sun.star.reflection.InvocationTargetException; import com.sun.star.registry.XRegistryKey; import com.sun.star.script.framework.container.ScriptMetaData; import com.sun.star.script.framework.log.LogUtils; import com.sun.star.script.framework.provider.ClassLoaderFactory; import com.sun.star.script.framework.provider.ScriptContext; import com.sun.star.script.framework.provider.ScriptEditor; import com.sun.star.script.framework.provider.ScriptProvider; 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.provider.XScript; import com.sun.star.uno.Any; import com.sun.star.uno.Type; import com.sun.star.uno.XComponentContext; import java.net.URL; import java.util.StringTokenizer; public class ScriptProviderForBeanShell { public static class ScriptProviderForBeanShell_2 extends ScriptProvider { public ScriptProviderForBeanShell_2(XComponentContext ctx) { super(ctx, "BeanShell"); } @Override public XScript getScript(/*IN*/String scriptURI) throws com.sun.star.uno.RuntimeException, ScriptFrameworkErrorException { ScriptMetaData scriptData = getScriptData(scriptURI); try { 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); } } @Override public boolean hasScriptEditor() { return true; } @Override public ScriptEditor getScriptEditor() { return ScriptEditorForBeanShell.getEditor(); } } /** * Returns a factory for creating the service. * This method is called by the JavaLoader *

* * @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 XSingleServiceFactory 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_2.class.getName())) { xSingleServiceFactory = FactoryHelper.getServiceFactory( ScriptProviderForBeanShell.ScriptProviderForBeanShell_2.class, "com.sun.star.script.provider.ScriptProviderForBeanShell", multiFactory, regKey); } return xSingleServiceFactory; } } class ScriptImpl implements XScript { private final ScriptMetaData metaData; private final XComponentContext m_xContext; private XMultiComponentFactory m_xMultiComponentFactory; private final XModel m_xModel; private final 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) { throw new com.sun.star.uno.RuntimeException(e); } 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 * * @return The value returned from the function * being invoked * * @throws IllegalArgumentException If there is no matching script name * * @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 parameters - 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); } // 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 { Object result; ScriptEditorForBeanShell editor = ScriptEditorForBeanShell.getEditor(sourceUrl); if (editor != null) { result = editor.execute(); if (result == null) { return new Any(new Type(), null); } return result; } metaData.loadSource(); String 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) { try { URL sourceUrl = metaData.getSourceURL(); ScriptEditorForBeanShell 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 (java.net.MalformedURLException ignore) { } } private ScriptErrorRaisedException processBshException( bsh.EvalError e, String script) { LogUtils.DEBUG("Beanshell error RAW message " + e.getMessage()); String message = e.getMessage(); int usefulInfoIndex = message.lastIndexOf("\' :"); int lineNum = e.getErrorLineNumber(); raiseEditor(lineNum); if (usefulInfoIndex > -1) { message = message.substring(usefulInfoIndex + 2); } if (e instanceof bsh.TargetError) { LogUtils.DEBUG("got instance of TargetError"); if (usefulInfoIndex == -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 = " + tokenizer.nextToken()); wrappedException = tokenizer.nextToken(); 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); } } }