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.beanshell; 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.registry.XRegistryKey; 30 import com.sun.star.comp.loader.FactoryHelper; 31 import com.sun.star.frame.XModel; 32 import com.sun.star.uno.Type; 33 import com.sun.star.uno.Any; 34 35 import com.sun.star.reflection.InvocationTargetException; 36 37 import java.util.StringTokenizer; 38 39 import java.net.URL; 40 41 import bsh.Interpreter; 42 43 import com.sun.star.document.XScriptInvocationContext; 44 import com.sun.star.script.provider.XScript; 45 import com.sun.star.script.provider.ScriptErrorRaisedException; 46 import com.sun.star.script.provider.ScriptExceptionRaisedException; 47 import com.sun.star.script.provider.ScriptFrameworkErrorException; 48 import com.sun.star.script.provider.ScriptFrameworkErrorType; 49 50 51 import com.sun.star.script.framework.provider.*; 52 import com.sun.star.script.framework.log.*; 53 import com.sun.star.script.framework.container.ScriptMetaData; 54 55 public class ScriptProviderForBeanShell 56 { 57 public static class _ScriptProviderForBeanShell extends ScriptProvider 58 { 59 public _ScriptProviderForBeanShell(XComponentContext ctx) 60 { 61 super (ctx, "BeanShell"); 62 } 63 64 public XScript getScript( /*IN*/String scriptURI ) 65 throws com.sun.star.uno.RuntimeException, 66 ScriptFrameworkErrorException 67 { 68 ScriptMetaData scriptData = null; 69 try 70 { 71 scriptData = getScriptData( scriptURI ); 72 ScriptImpl script = new ScriptImpl( m_xContext, scriptData, m_xModel, m_xInvocContext ); 73 return script; 74 } 75 catch ( com.sun.star.uno.RuntimeException re ) 76 { 77 throw new ScriptFrameworkErrorException( "Failed to create script object: " + re.getMessage(), 78 null, scriptData.getLanguageName(), language, ScriptFrameworkErrorType.UNKNOWN ); 79 } 80 } 81 82 public boolean hasScriptEditor() 83 { 84 return true; 85 } 86 87 public ScriptEditor getScriptEditor() 88 { 89 return ScriptEditorForBeanShell.getEditor(); 90 } 91 } 92 93 /** 94 * Returns a factory for creating the service. 95 * This method is called by the <code>JavaLoader</code> 96 * <p> 97 * 98 * @param implName the name of the implementation for which a service is desired 99 * @param multiFactory the service manager to be used if needed 100 * @param regKey the registryKey 101 * @return returns a <code>XSingleServiceFactory</code> for creating 102 * the component 103 * @see com.sun.star.comp.loader.JavaLoader 104 */ 105 public static XSingleServiceFactory __getServiceFactory( String implName, 106 XMultiServiceFactory multiFactory, 107 XRegistryKey regKey ) 108 { 109 XSingleServiceFactory xSingleServiceFactory = null; 110 111 if ( implName.equals( ScriptProviderForBeanShell._ScriptProviderForBeanShell.class.getName() ) ) 112 { 113 xSingleServiceFactory = FactoryHelper.getServiceFactory( 114 ScriptProviderForBeanShell._ScriptProviderForBeanShell.class, 115 "com.sun.star.script.ScriptProviderForBeanShell", 116 multiFactory, 117 regKey ); 118 } 119 120 return xSingleServiceFactory; 121 } 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 132 ScriptImpl( XComponentContext ctx, ScriptMetaData metaData, XModel xModel, 133 XScriptInvocationContext xContext ) throws com.sun.star.uno.RuntimeException 134 { 135 this.metaData = metaData; 136 this.m_xContext = ctx; 137 this.m_xModel = xModel; 138 this.m_xInvocContext = xContext; 139 140 try 141 { 142 this.m_xMultiComponentFactory = m_xContext.getServiceManager(); 143 } 144 catch ( Exception e ) 145 { 146 LogUtils.DEBUG( LogUtils.getTrace( e ) ); 147 throw new com.sun.star.uno.RuntimeException( 148 "Error constructing ScriptImpl [beanshell]: " 149 + e.getMessage() ); 150 } 151 152 LogUtils.DEBUG("ScriptImpl [beanshell] script data = " + metaData ); 153 } 154 /** 155 * documentStorageID and document reference 156 * for use in script name resolving 157 * 158 * @param aParams All parameters; pure, out params are 159 * undefined in sequence, i.e., the value 160 * has to be ignored by the callee 161 * 162 * @param aOutParamIndex Out indices 163 * 164 * @param aOutParam Out parameters 165 * 166 * @returns The value returned from the function 167 * being invoked 168 * 169 * @throws IllegalArgumentException If there is no matching script name 170 * 171 * @throws CannotConvertException If args do not match or cannot 172 * be converted the those of the 173 * invokee 174 * 175 * @throws InvocationTargetException If the running script throws 176 * an exception this information 177 * is captured and rethrown as 178 * this exception type. 179 */ 180 181 public Object invoke( /*IN*/Object[] aParams, 182 /*OUT*/short[][] aOutParamIndex, 183 /*OUT*/Object[][] aOutParam ) 184 throws ScriptFrameworkErrorException, 185 InvocationTargetException 186 { 187 // Initialise the out paramters - not used at the moment 188 aOutParamIndex[0] = new short[0]; 189 aOutParam[0] = new Object[0]; 190 191 192 ClassLoader cl = null; 193 URL sourceUrl = null; 194 try { 195 cl = ClassLoaderFactory.getURLClassLoader( metaData ); 196 sourceUrl = metaData.getSourceURL(); 197 } 198 catch ( java.net.MalformedURLException mfu ) 199 { 200 // Framework error 201 throw new ScriptFrameworkErrorException( 202 mfu.getMessage(), null, 203 metaData.getLanguageName(), metaData.getLanguage(), 204 ScriptFrameworkErrorType.MALFORMED_URL ); 205 } 206 catch ( NoSuitableClassLoaderException nsc ) 207 { 208 // Framework error 209 throw new ScriptFrameworkErrorException( 210 nsc.getMessage(), null, 211 metaData.getLanguageName(), metaData.getLanguage(), 212 ScriptFrameworkErrorType.UNKNOWN ); 213 } 214 // Set class loader to be used for class files 215 // and jar files 216 Thread.currentThread().setContextClassLoader(cl); 217 Interpreter interpreter = new Interpreter(); 218 219 interpreter.getNameSpace().clear(); 220 // Set class loader to be used by interpreter 221 // to look for classes by source e.g. interpreter 222 // will use this classloader to search classpath 223 // for source file ( bla.java ) on import or reference 224 interpreter.setClassLoader(cl); 225 try { 226 interpreter.set("XSCRIPTCONTEXT", 227 ScriptContext.createContext(m_xModel, m_xInvocContext, 228 m_xContext, m_xMultiComponentFactory)); 229 230 interpreter.set("ARGUMENTS", aParams); 231 } 232 catch (bsh.EvalError e) { 233 // Framework error setting up context 234 throw new ScriptFrameworkErrorException( 235 e.getMessage(), null, 236 metaData.getLanguageName(), metaData.getLanguage(), 237 ScriptFrameworkErrorType.UNKNOWN ); 238 } 239 240 try { 241 String source = null; 242 Object result = null; 243 244 ScriptEditorForBeanShell editor = 245 ScriptEditorForBeanShell.getEditor( 246 sourceUrl ); 247 248 if ( editor != null ) 249 { 250 result = editor.execute(); 251 252 if (result == null) 253 { 254 return new Any(new Type(), null); 255 } 256 return result; 257 } 258 259 metaData.loadSource(); 260 source = metaData.getSource(); 261 262 if ( source == null || source.length() == 0 ) 263 { 264 throw new ScriptFrameworkErrorException( 265 "Failed to read script", null, 266 metaData.getLanguageName(), metaData.getLanguage(), 267 ScriptFrameworkErrorType.NO_SUCH_SCRIPT ); 268 } 269 result = interpreter.eval( source ); 270 271 if (result == null) 272 { 273 return new Any(new Type(), null); 274 } 275 return result; 276 } 277 catch ( bsh.ParseException pe ) 278 { 279 throw new InvocationTargetException( "Beanshell failed to parse " + metaData.getLanguageName(), null, processBshException( pe, metaData.getLanguageName() ) ); 280 } 281 catch ( bsh.TargetError te ) 282 { 283 throw new InvocationTargetException( "Beanshell uncaught exception for " + metaData.getLanguageName(), null, processBshException( te, metaData.getLanguageName() ) ); 284 } 285 catch ( bsh.EvalError ex ) 286 { 287 throw new InvocationTargetException( "Beanshell error for " + metaData.getLanguageName(), null, processBshException( ex, metaData.getLanguageName() ) ); 288 } 289 catch ( Exception e ) 290 { 291 throw new ScriptFrameworkErrorException( 292 "Failed to read script", null, 293 metaData.getLanguageName(), metaData.getLanguage(), 294 ScriptFrameworkErrorType.UNKNOWN ); 295 } 296 } 297 private void raiseEditor( int lineNum ) 298 { 299 ScriptEditorForBeanShell editor = null; 300 try 301 { 302 URL sourceUrl = metaData.getSourceURL(); 303 editor = ScriptEditorForBeanShell.getEditor( sourceUrl ); 304 if ( editor == null ) 305 { 306 editor = ScriptEditorForBeanShell.getEditor(); 307 editor.edit( 308 ScriptContext.createContext(m_xModel, m_xInvocContext, 309 m_xContext, m_xMultiComponentFactory), metaData ); 310 editor = ScriptEditorForBeanShell.getEditor( sourceUrl ); 311 } 312 if ( editor != null ) 313 { 314 editor.indicateErrorLine( lineNum ); 315 } 316 } 317 catch( Exception ignore ) 318 { 319 } 320 } 321 322 private ScriptErrorRaisedException processBshException( bsh.EvalError e, String script ) 323 { 324 LogUtils.DEBUG("Beanshell error RAW message " + e.getMessage()); 325 String message = e.getMessage(); 326 int usefullInfoIndex = message.lastIndexOf("\' :" ); 327 int lineNum = e.getErrorLineNumber(); 328 329 raiseEditor( lineNum ); 330 331 //String stackTrace = te.getScriptStackTrace(); // never seems to have any info?? 332 if ( usefullInfoIndex > -1 ) 333 { 334 message = message.substring( usefullInfoIndex + 2 ); 335 } 336 if ( e instanceof bsh.TargetError ) 337 { 338 LogUtils.DEBUG("got instance of TargetError"); 339 if ( usefullInfoIndex == -1 ) 340 { 341 message = ( ( bsh.TargetError)e ).getTarget().getMessage(); 342 } 343 String wrappedException = ""; 344 String full = e.toString(); 345 int index = full.indexOf( "Target exception:" ); 346 if ( index > -1 ) 347 { 348 String toParse = full.substring( index ); 349 LogUtils.DEBUG("About to parse " + toParse ); 350 StringTokenizer tokenizer = new StringTokenizer( full.substring( index ),":" ); 351 if ( tokenizer.countTokens() > 2 ) 352 { 353 LogUtils.DEBUG("First token = " + (String)tokenizer.nextElement()); 354 wrappedException = (String)tokenizer.nextElement(); 355 LogUtils.DEBUG("wrapped exception = = " + wrappedException ); 356 } 357 } 358 ScriptExceptionRaisedException se = new ScriptExceptionRaisedException( message); 359 se.lineNum = lineNum; 360 se.scriptName = script; 361 se.exceptionType = wrappedException; 362 se.language = "BeanShell"; 363 LogUtils.DEBUG("UnCaught Exception error: " ); 364 LogUtils.DEBUG("\tscript: " + script ); 365 LogUtils.DEBUG("\tline: " + lineNum ); 366 LogUtils.DEBUG("\twrapped exception: " + wrappedException ); 367 LogUtils.DEBUG("\tmessage: " + message ); 368 return se; 369 } 370 else 371 { 372 LogUtils.DEBUG("Error or ParseError Exception error: " ); 373 LogUtils.DEBUG("\tscript: " + script ); 374 LogUtils.DEBUG("\tline: " + lineNum ); 375 LogUtils.DEBUG("\tmessage: " + message ); 376 return new ScriptErrorRaisedException( message, null, script, "BeanShell", lineNum ); 377 } 378 } 379 } 380