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