| /************************************************************** |
| * |
| * 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.javascript; |
| |
| 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.frame.XModel; |
| import com.sun.star.registry.XRegistryKey; |
| import com.sun.star.comp.loader.FactoryHelper; |
| |
| import com.sun.star.document.XScriptInvocationContext; |
| import com.sun.star.reflection.InvocationTargetException; |
| |
| import java.net.URL; |
| |
| import com.sun.star.script.provider.XScript; |
| |
| 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.log.LogUtils; |
| import com.sun.star.script.framework.provider.ScriptContext; |
| import com.sun.star.script.framework.provider.ClassLoaderFactory; |
| import com.sun.star.script.framework.provider.ScriptProvider; |
| import com.sun.star.script.framework.provider.ScriptEditor; |
| import com.sun.star.script.framework.container.ScriptMetaData; |
| |
| import org.mozilla.javascript.Context; |
| import org.mozilla.javascript.ImporterTopLevel; |
| import org.mozilla.javascript.Scriptable; |
| import org.mozilla.javascript.JavaScriptException; |
| |
| public class ScriptProviderForJavaScript |
| { |
| public static class _ScriptProviderForJavaScript extends ScriptProvider |
| { |
| public _ScriptProviderForJavaScript(XComponentContext ctx) |
| { |
| super(ctx, "JavaScript"); |
| } |
| |
| 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 ScriptEditorForJavaScript.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( ScriptProviderForJavaScript._ScriptProviderForJavaScript.class.getName() ) ) |
| { |
| xSingleServiceFactory = FactoryHelper.getServiceFactory( |
| ScriptProviderForJavaScript._ScriptProviderForJavaScript.class, |
| "com.sun.star.script.provider.ScriptProviderForJavaScript", |
| 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 xInvocContext ) throws com.sun.star.uno.RuntimeException |
| { |
| this.metaData = metaData; |
| this.m_xContext = ctx; |
| this.m_xModel = xModel; |
| this.m_xInvocContext = xInvocContext; |
| 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: [javascript]"); |
| } |
| LogUtils.DEBUG("ScriptImpl [javascript] script data = " + metaData ); |
| } |
| |
| /** |
| * The invoke method of the ScriptProviderForJavaScript runs the |
| * JavaScript script specified in the URI |
| * |
| * |
| * |
| * @param params 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 ScriptFrameworkErrorException If there is no matching script name |
| * |
| * |
| * @throws InvocationTargetException If the running script throws |
| * an exception this information |
| * is captured and rethrown as |
| * ScriptErrorRaisedException or |
| * ScriptExceptionRaisedException |
| */ |
| |
| public Object invoke( |
| /*IN*/Object[] params, |
| /*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 ) |
| { |
| throw new ScriptFrameworkErrorException( |
| mfu.getMessage(), null, |
| metaData.getLanguageName(), metaData.getLanguage(), |
| ScriptFrameworkErrorType.MALFORMED_URL ); |
| } |
| catch ( com.sun.star.script.framework.provider.NoSuitableClassLoaderException nsc ) |
| { |
| // Framework error |
| throw new ScriptFrameworkErrorException( |
| nsc.getMessage(), null, |
| metaData.getLanguageName(), metaData.getLanguage(), |
| ScriptFrameworkErrorType.UNKNOWN ); |
| } |
| Context ctxt = null; |
| |
| try |
| { |
| String editorURL = sourceUrl.toString(); |
| Object result = null; |
| String source = null; |
| ScriptEditorForJavaScript editor = |
| ScriptEditorForJavaScript.getEditor( |
| metaData.getSourceURL() ); |
| |
| if (editor != null) |
| { |
| editorURL = editor.getURL(); |
| result = editor.execute(); |
| if ( result != null && |
| result.getClass().getName().equals( "org.mozilla.javascript.Undefined" ) ) |
| { |
| // Always return a string |
| // TODO revisit |
| return Context.toString( result ); |
| } |
| |
| } |
| |
| if (editor != null && editor.isModified() == true) |
| { |
| LogUtils.DEBUG("GOT A MODIFIED SOURCE"); |
| source = editor.getText(); |
| } |
| else |
| { |
| metaData.loadSource(); |
| source = metaData.getSource(); |
| |
| } |
| |
| if ( source == null || source.length() == 0 ) { |
| throw new ScriptFrameworkErrorException( |
| "Failed to read source data for script", null, |
| metaData.getLanguageName(), metaData.getLanguage(), |
| ScriptFrameworkErrorType.UNKNOWN ); |
| } |
| |
| /* Set the context ClassLoader on the current thread to |
| be our custom ClassLoader. This is the suggested method |
| for setting up a ClassLoader to be used by the Rhino |
| interpreter |
| */ |
| if (cl != null) { |
| Thread.currentThread().setContextClassLoader(cl); |
| } |
| |
| // Initialize a Rhino Context object |
| ctxt = Context.enter(); |
| ctxt.setLanguageVersion(Context.VERSION_1_8); |
| ctxt.setOptimizationLevel(9); |
| |
| /* The ImporterTopLevel ensures that importClass and |
| importPackage statements work in Javascript scripts |
| Make the XScriptContext available as a global variable |
| to the script |
| */ |
| ImporterTopLevel scope = new ImporterTopLevel(ctxt); |
| |
| Scriptable jsCtxt = Context.toObject( |
| ScriptContext.createContext( |
| m_xModel, m_xInvocContext, m_xContext, |
| m_xMultiComponentFactory), scope); |
| scope.put("XSCRIPTCONTEXT", scope, jsCtxt); |
| |
| Scriptable jsArgs = Context.toObject(params, scope); |
| scope.put("ARGUMENTS", scope, jsArgs); |
| |
| result = ctxt.evaluateString(scope, |
| source, "<stdin>", 1, null); |
| result = ctxt.toString(result); |
| return result; |
| } |
| catch (JavaScriptException jse) { |
| LogUtils.DEBUG( "Caught JavaScriptException exception for JavaScript type = " + jse.getClass() ); |
| String message = jse.getMessage(); |
| int lineNo = jse.lineNumber(); |
| Object wrap = jse.getValue(); |
| LogUtils.DEBUG( "\t message " + message ); |
| LogUtils.DEBUG( "\t wrapped type " + wrap.getClass() ); |
| LogUtils.DEBUG( "\t wrapped toString " + wrap.toString() ); |
| ScriptExceptionRaisedException se = new |
| ScriptExceptionRaisedException( message ); |
| se.lineNum = lineNo; |
| se.language = "JavaScript"; |
| se.scriptName = metaData.getLanguageName(); |
| se.exceptionType = wrap.getClass().getName(); |
| se.language = metaData.getLanguage(); |
| LogUtils.DEBUG( "ExceptionRaised exception " ); |
| LogUtils.DEBUG( "\t message " + se.getMessage() ); |
| LogUtils.DEBUG( "\t lineNum " + se.lineNum ); |
| LogUtils.DEBUG( "\t language " + se.language ); |
| LogUtils.DEBUG( "\t scriptName " + se.scriptName ); |
| raiseEditor( se.lineNum ); |
| throw new InvocationTargetException( "JavaScript uncaught exception" + metaData.getLanguageName(), null, se ); |
| } |
| catch (Exception ex) { |
| LogUtils.DEBUG("Caught Exception " + ex ); |
| LogUtils.DEBUG("rethrowing as ScriptFramework error" ); |
| throw new ScriptFrameworkErrorException( |
| ex.getMessage(), null, |
| metaData.getLanguageName(), metaData.getLanguage(), |
| ScriptFrameworkErrorType.UNKNOWN ); |
| } |
| finally { |
| if ( ctxt != null ) |
| { |
| Context.exit(); |
| } |
| } |
| } |
| |
| private void raiseEditor( int lineNum ) |
| { |
| ScriptEditorForJavaScript editor = null; |
| try |
| { |
| URL sourceUrl = metaData.getSourceURL(); |
| editor = ScriptEditorForJavaScript.getEditor( sourceUrl ); |
| if ( editor == null ) |
| { |
| editor = ScriptEditorForJavaScript.getEditor(); |
| editor.edit( |
| ScriptContext.createContext(m_xModel, m_xInvocContext, |
| m_xContext, m_xMultiComponentFactory), metaData ); |
| editor = ScriptEditorForJavaScript.getEditor( sourceUrl ); |
| } |
| if ( editor != null ) |
| { |
| System.out.println("** Have raised IDE for JavaScript, calling indicateErrorLine for line " + lineNum ); |
| editor.indicateErrorLine( lineNum ); |
| } |
| } |
| catch( Exception ignore ) |
| { |
| } |
| } |
| } |
| |