1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 package com.sun.star.script.framework.provider.javascript; 24 25 import com.sun.star.uno.XComponentContext; 26 import com.sun.star.lang.XMultiComponentFactory; 27 import com.sun.star.lang.XMultiServiceFactory; 28 import com.sun.star.lang.XSingleServiceFactory; 29 import com.sun.star.frame.XModel; 30 import com.sun.star.registry.XRegistryKey; 31 import com.sun.star.comp.loader.FactoryHelper; 32 33 import com.sun.star.document.XScriptInvocationContext; 34 import com.sun.star.reflection.InvocationTargetException; 35 36 import java.net.URL; 37 38 import com.sun.star.script.provider.XScript; 39 40 import com.sun.star.script.provider.ScriptExceptionRaisedException; 41 import com.sun.star.script.provider.ScriptFrameworkErrorException; 42 import com.sun.star.script.provider.ScriptFrameworkErrorType; 43 44 import com.sun.star.script.framework.log.LogUtils; 45 import com.sun.star.script.framework.provider.ScriptContext; 46 import com.sun.star.script.framework.provider.ClassLoaderFactory; 47 import com.sun.star.script.framework.provider.ScriptProvider; 48 import com.sun.star.script.framework.provider.ScriptEditor; 49 import com.sun.star.script.framework.container.ScriptMetaData; 50 51 import org.mozilla.javascript.Context; 52 import org.mozilla.javascript.ImporterTopLevel; 53 import org.mozilla.javascript.Scriptable; 54 import org.mozilla.javascript.JavaScriptException; 55 56 public class ScriptProviderForJavaScript 57 { 58 public static class _ScriptProviderForJavaScript extends ScriptProvider 59 { _ScriptProviderForJavaScript(XComponentContext ctx)60 public _ScriptProviderForJavaScript(XComponentContext ctx) 61 { 62 super(ctx, "JavaScript"); 63 } 64 getScript( String scriptURI )65 public XScript getScript( /*IN*/String scriptURI ) 66 throws com.sun.star.uno.RuntimeException, 67 ScriptFrameworkErrorException 68 { 69 ScriptMetaData scriptData = null; 70 try 71 { 72 scriptData = getScriptData( scriptURI ); 73 ScriptImpl script = new ScriptImpl( m_xContext, scriptData, m_xModel, m_xInvocContext ); 74 return script; 75 } 76 catch ( com.sun.star.uno.RuntimeException re ) 77 { 78 throw new ScriptFrameworkErrorException( "Failed to create script object: " + re.getMessage(), 79 null, scriptData.getLanguageName(), language, ScriptFrameworkErrorType.UNKNOWN ); 80 } 81 } 82 hasScriptEditor()83 public boolean hasScriptEditor() 84 { 85 return true; 86 } 87 getScriptEditor()88 public ScriptEditor getScriptEditor() 89 { 90 return ScriptEditorForJavaScript.getEditor(); 91 } 92 } 93 94 /** 95 * Returns a factory for creating the service. 96 * This method is called by the <code>JavaLoader</code> 97 * <p> 98 * 99 * @param implName the name of the implementation for which a service is desired 100 * @param multiFactory the service manager to be used if needed 101 * @param regKey the registryKey 102 * @return returns a <code>XSingleServiceFactory</code> for creating 103 * the component 104 * @see com.sun.star.comp.loader.JavaLoader 105 */ __getServiceFactory( String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey )106 public static XSingleServiceFactory __getServiceFactory( String implName, 107 XMultiServiceFactory multiFactory, 108 XRegistryKey regKey ) 109 { 110 XSingleServiceFactory xSingleServiceFactory = null; 111 112 if ( implName.equals( ScriptProviderForJavaScript._ScriptProviderForJavaScript.class.getName() ) ) 113 { 114 xSingleServiceFactory = FactoryHelper.getServiceFactory( 115 ScriptProviderForJavaScript._ScriptProviderForJavaScript.class, 116 "com.sun.star.script.provider.ScriptProviderForJavaScript", 117 multiFactory, 118 regKey ); 119 } 120 121 return xSingleServiceFactory; 122 } 123 } 124 class ScriptImpl implements XScript 125 { 126 private ScriptMetaData metaData; 127 private XComponentContext m_xContext; 128 private XMultiComponentFactory m_xMultiComponentFactory; 129 private XModel m_xModel; 130 private XScriptInvocationContext m_xInvocContext; 131 ScriptImpl( XComponentContext ctx, ScriptMetaData metaData, XModel xModel, XScriptInvocationContext xInvocContext )132 ScriptImpl( XComponentContext ctx, ScriptMetaData metaData, XModel xModel, XScriptInvocationContext xInvocContext ) throws com.sun.star.uno.RuntimeException 133 { 134 this.metaData = metaData; 135 this.m_xContext = ctx; 136 this.m_xModel = xModel; 137 this.m_xInvocContext = xInvocContext; 138 try 139 { 140 this.m_xMultiComponentFactory = m_xContext.getServiceManager(); 141 } 142 catch ( Exception e ) 143 { 144 LogUtils.DEBUG( LogUtils.getTrace( e ) ); 145 throw new com.sun.star.uno.RuntimeException( 146 "Error constructing ScriptImpl: [javascript]"); 147 } 148 LogUtils.DEBUG("ScriptImpl [javascript] script data = " + metaData ); 149 } 150 151 /** 152 * The invoke method of the ScriptProviderForJavaScript runs the 153 * JavaScript script specified in the URI 154 * 155 * 156 * 157 * @param params All parameters; pure, out params are 158 * undefined in sequence, i.e., the value 159 * has to be ignored by the callee 160 * 161 * @param aOutParamIndex Out indices 162 * 163 * @param aOutParam Out parameters 164 * 165 * @returns The value returned from the function 166 * being invoked 167 * 168 * @throws ScriptFrameworkErrorException If there is no matching script name 169 * 170 * 171 * @throws InvocationTargetException If the running script throws 172 * an exception this information 173 * is captured and rethrown as 174 * ScriptErrorRaisedException or 175 * ScriptExceptionRaisedException 176 */ 177 invoke( Object[] params, short[][] aOutParamIndex, Object[][] aOutParam )178 public Object invoke( 179 /*IN*/Object[] params, 180 /*OUT*/short[][] aOutParamIndex, 181 /*OUT*/Object[][] aOutParam ) 182 183 throws ScriptFrameworkErrorException, InvocationTargetException 184 { 185 // Initialise the out paramters - not used at the moment 186 aOutParamIndex[0] = new short[0]; 187 aOutParam[0] = new Object[0]; 188 189 190 191 ClassLoader cl = null; 192 URL sourceUrl = null; 193 try { 194 cl = ClassLoaderFactory.getURLClassLoader( metaData ); 195 sourceUrl = metaData.getSourceURL(); 196 } 197 catch ( java.net.MalformedURLException mfu ) 198 { 199 throw new ScriptFrameworkErrorException( 200 mfu.getMessage(), null, 201 metaData.getLanguageName(), metaData.getLanguage(), 202 ScriptFrameworkErrorType.MALFORMED_URL ); 203 } 204 catch ( com.sun.star.script.framework.provider.NoSuitableClassLoaderException nsc ) 205 { 206 // Framework error 207 throw new ScriptFrameworkErrorException( 208 nsc.getMessage(), null, 209 metaData.getLanguageName(), metaData.getLanguage(), 210 ScriptFrameworkErrorType.UNKNOWN ); 211 } 212 Context ctxt = null; 213 214 try 215 { 216 String editorURL = sourceUrl.toString(); 217 Object result = null; 218 String source = null; 219 ScriptEditorForJavaScript editor = 220 ScriptEditorForJavaScript.getEditor( 221 metaData.getSourceURL() ); 222 223 if (editor != null) 224 { 225 editorURL = editor.getURL(); 226 result = editor.execute(); 227 if ( result != null && 228 result.getClass().getName().equals( "org.mozilla.javascript.Undefined" ) ) 229 { 230 // Always return a string 231 // TODO revisit 232 return Context.toString( result ); 233 } 234 235 } 236 237 if (editor != null && editor.isModified() == true) 238 { 239 LogUtils.DEBUG("GOT A MODIFIED SOURCE"); 240 source = editor.getText(); 241 } 242 else 243 { 244 metaData.loadSource(); 245 source = metaData.getSource(); 246 247 } 248 249 if ( source == null || source.length() == 0 ) { 250 throw new ScriptFrameworkErrorException( 251 "Failed to read source data for script", null, 252 metaData.getLanguageName(), metaData.getLanguage(), 253 ScriptFrameworkErrorType.UNKNOWN ); 254 } 255 256 /* Set the context ClassLoader on the current thread to 257 be our custom ClassLoader. This is the suggested method 258 for setting up a ClassLoader to be used by the Rhino 259 interpreter 260 */ 261 if (cl != null) { 262 Thread.currentThread().setContextClassLoader(cl); 263 } 264 265 // Initialize a Rhino Context object 266 ctxt = Context.enter(); 267 ctxt.setLanguageVersion(Context.VERSION_1_8); 268 ctxt.setOptimizationLevel(9); 269 270 /* The ImporterTopLevel ensures that importClass and 271 importPackage statements work in Javascript scripts 272 Make the XScriptContext available as a global variable 273 to the script 274 */ 275 ImporterTopLevel scope = new ImporterTopLevel(ctxt); 276 277 Scriptable jsCtxt = Context.toObject( 278 ScriptContext.createContext( 279 m_xModel, m_xInvocContext, m_xContext, 280 m_xMultiComponentFactory), scope); 281 scope.put("XSCRIPTCONTEXT", scope, jsCtxt); 282 283 Scriptable jsArgs = Context.toObject(params, scope); 284 scope.put("ARGUMENTS", scope, jsArgs); 285 286 result = ctxt.evaluateString(scope, 287 source, "<stdin>", 1, null); 288 result = ctxt.toString(result); 289 return result; 290 } 291 catch (JavaScriptException jse) { 292 LogUtils.DEBUG( "Caught JavaScriptException exception for JavaScript type = " + jse.getClass() ); 293 String message = jse.getMessage(); 294 int lineNo = jse.lineNumber(); 295 Object wrap = jse.getValue(); 296 LogUtils.DEBUG( "\t message " + message ); 297 LogUtils.DEBUG( "\t wrapped type " + wrap.getClass() ); 298 LogUtils.DEBUG( "\t wrapped toString " + wrap.toString() ); 299 ScriptExceptionRaisedException se = new 300 ScriptExceptionRaisedException( message ); 301 se.lineNum = lineNo; 302 se.language = "JavaScript"; 303 se.scriptName = metaData.getLanguageName(); 304 se.exceptionType = wrap.getClass().getName(); 305 se.language = metaData.getLanguage(); 306 LogUtils.DEBUG( "ExceptionRaised exception " ); 307 LogUtils.DEBUG( "\t message " + se.getMessage() ); 308 LogUtils.DEBUG( "\t lineNum " + se.lineNum ); 309 LogUtils.DEBUG( "\t language " + se.language ); 310 LogUtils.DEBUG( "\t scriptName " + se.scriptName ); 311 raiseEditor( se.lineNum ); 312 throw new InvocationTargetException( "JavaScript uncaught exception" + metaData.getLanguageName(), null, se ); 313 } 314 catch (Exception ex) { 315 LogUtils.DEBUG("Caught Exception " + ex ); 316 LogUtils.DEBUG("rethrowing as ScriptFramework error" ); 317 throw new ScriptFrameworkErrorException( 318 ex.getMessage(), null, 319 metaData.getLanguageName(), metaData.getLanguage(), 320 ScriptFrameworkErrorType.UNKNOWN ); 321 } 322 finally { 323 if ( ctxt != null ) 324 { 325 Context.exit(); 326 } 327 } 328 } 329 raiseEditor( int lineNum )330 private void raiseEditor( int lineNum ) 331 { 332 ScriptEditorForJavaScript editor = null; 333 try 334 { 335 URL sourceUrl = metaData.getSourceURL(); 336 editor = ScriptEditorForJavaScript.getEditor( sourceUrl ); 337 if ( editor == null ) 338 { 339 editor = ScriptEditorForJavaScript.getEditor(); 340 editor.edit( 341 ScriptContext.createContext(m_xModel, m_xInvocContext, 342 m_xContext, m_xMultiComponentFactory), metaData ); 343 editor = ScriptEditorForJavaScript.getEditor( sourceUrl ); 344 } 345 if ( editor != null ) 346 { 347 System.out.println("** Have raised IDE for JavaScript, calling indicateErrorLine for line " + lineNum ); 348 editor.indicateErrorLine( lineNum ); 349 } 350 } 351 catch( Exception ignore ) 352 { 353 } 354 } 355 } 356 357