1 /*
2  * This file is part of the LibreOffice project.
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  *
8  * This file incorporates work covered by the following license notice:
9  *
10  *   Licensed to the Apache Software Foundation (ASF) under one or more
11  *   contributor license agreements. See the NOTICE file distributed
12  *   with this work for additional information regarding copyright
13  *   ownership. The ASF licenses this file to you under the Apache
14  *   License, Version 2.0 (the "License"); you may not use this file
15  *   except in compliance with the License. You may obtain a copy of
16  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
17  */
18 package com.sun.star.script.framework.provider.java;
19 
20 import com.sun.star.comp.loader.FactoryHelper;
21 
22 import com.sun.star.document.XScriptInvocationContext;
23 
24 import com.sun.star.frame.XModel;
25 
26 import com.sun.star.lang.XMultiComponentFactory;
27 import com.sun.star.lang.XMultiServiceFactory;
28 import com.sun.star.lang.XSingleServiceFactory;
29 
30 import com.sun.star.registry.XRegistryKey;
31 
32 import com.sun.star.script.framework.container.ScriptMetaData;
33 import com.sun.star.script.framework.log.LogUtils;
34 import com.sun.star.script.framework.provider.ClassLoaderFactory;
35 import com.sun.star.script.framework.provider.ScriptContext;
36 import com.sun.star.script.framework.provider.ScriptEditor;
37 import com.sun.star.script.framework.provider.ScriptProvider;
38 import com.sun.star.script.provider.ScriptExceptionRaisedException;
39 import com.sun.star.script.provider.ScriptFrameworkErrorException;
40 import com.sun.star.script.provider.ScriptFrameworkErrorType;
41 import com.sun.star.script.provider.XScript;
42 import com.sun.star.script.provider.XScriptContext;
43 
44 import com.sun.star.uno.Any;
45 import com.sun.star.uno.Type;
46 import com.sun.star.uno.XComponentContext;
47 
48 import java.io.IOException;
49 import java.net.URLClassLoader;
50 import java.util.ArrayList;
51 
52 public class ScriptProviderForJava {
53 
54     public static class _ScriptProviderForJava extends ScriptProvider {
55 
56         private final Resolver m_resolutionPolicy = new StrictResolver();
57 
_ScriptProviderForJava(XComponentContext ctx)58         public _ScriptProviderForJava(XComponentContext ctx) {
59             super(ctx, "Java");
60         }
61 
62         @Override
getScript( String scriptURI)63         public XScript getScript(/*IN*/String scriptURI) throws
64             com.sun.star.uno.RuntimeException, ScriptFrameworkErrorException {
65 
66             ScriptMetaData scriptData = getScriptData(scriptURI);
67 
68             try {
69 
70                 ScriptImpl script =
71                     new ScriptImpl(m_xContext, m_resolutionPolicy, scriptData, m_xModel,
72                                    m_xInvocContext);
73 
74                 return script;
75             } catch (com.sun.star.uno.RuntimeException re) {
76                 ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
77                     "Failed to create script object: " + re, null,
78                     scriptData.getLanguageName(), language,
79                     ScriptFrameworkErrorType.UNKNOWN);
80                 e2.initCause(re);
81                 throw e2;
82             }
83         }
84 
85         @Override
hasScriptEditor()86         public boolean hasScriptEditor() {
87             return false;
88         }
89 
90         @Override
getScriptEditor()91         public ScriptEditor getScriptEditor() {
92             return null;
93         }
94     }
95 
96     /**
97      * Returns a factory for creating the service.
98      * This method is called by the <code>JavaLoader</code>
99      * <p>
100      *
101      * @param  implName      the name of the implementation for which a service is desired
102      * @param  multiFactory  the service manager to be used if needed
103      * @param  regKey        the registryKey
104      * @return               returns a <code>XSingleServiceFactory</code> for creating
105      *                          the component
106      * @see                  com.sun.star.comp.loader.JavaLoader
107      */
__getServiceFactory( String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey)108     public static XSingleServiceFactory __getServiceFactory(
109         String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey) {
110 
111         XSingleServiceFactory xSingleServiceFactory = null;
112 
113         if (implName.equals(
114                 ScriptProviderForJava._ScriptProviderForJava.class.getName())) {
115 
116             xSingleServiceFactory =
117                 FactoryHelper.getServiceFactory(
118                     ScriptProviderForJava._ScriptProviderForJava.class,
119                     "com.sun.star.script.provider.ScriptProviderForJava",
120                     multiFactory, regKey);
121 
122         }
123 
124         return xSingleServiceFactory;
125     }
126 }
127 
128 class ScriptImpl implements XScript {
129 
130     private final ScriptMetaData metaData;
131     private final XComponentContext m_xContext;
132     private final XModel m_xModel;
133     private final XScriptInvocationContext m_xInvocContext;
134     private XMultiComponentFactory m_xMultiComponentFactory;
135     private final Resolver m_resolutionPolicy;
136 
ScriptImpl(XComponentContext ctx, Resolver resolver, ScriptMetaData metaData, XModel xModel, XScriptInvocationContext xInvocContext)137     ScriptImpl(XComponentContext ctx, Resolver resolver, ScriptMetaData metaData,
138                XModel xModel, XScriptInvocationContext xInvocContext) throws
139         com.sun.star.uno.RuntimeException {
140 
141         this.metaData = metaData;
142         this.m_xContext = ctx;
143         this.m_xModel = xModel;
144         this.m_xInvocContext = xInvocContext;
145         this.m_resolutionPolicy = resolver;
146 
147         try {
148             this.m_xMultiComponentFactory = m_xContext.getServiceManager();
149         } catch (Exception e) {
150             LogUtils.DEBUG(LogUtils.getTrace(e));
151             throw new com.sun.star.uno.RuntimeException(
152                 e, "Error constructing ScriptProvider: " + e);
153         }
154 
155         LogUtils.DEBUG("ScriptImpl [java] script data = " + metaData);
156     }
157 
158     /**
159      *  Invoke
160      *
161      *
162      * @param params            All parameters; pure, out params are undefined in
163      *                      sequence, i.e., the value has to be ignored by the callee
164      * @param aOutParamIndex    Out indices
165      * @param aOutParam         Out parameters
166      * @return                  The value returned from the function being invoked
167      * @throws IllegalArgumentException If there is no matching script name
168      * @throws com.sun.star.reflection.InvocationTargetException If the running script throws an exception
169      *              this information is captured and rethrown as this exception type.
170      */
invoke( Object[] params, short[][] aOutParamIndex, Object[][] aOutParam)171     public Object invoke(
172         /*IN*/Object[]  params,
173         /*OUT*/short[][]  aOutParamIndex,
174         /*OUT*/Object[][]  aOutParam) throws
175         ScriptFrameworkErrorException,
176         com.sun.star.reflection.InvocationTargetException {
177 
178         LogUtils.DEBUG("** ScriptProviderForJava::invoke: Starting...");
179 
180         // Initialise the out parameters - not used at the moment
181         aOutParamIndex[0] = new short[0];
182         aOutParam[0] = new Object[0];
183 
184         ScriptDescriptor scriptDesc =
185             new ScriptDescriptor(metaData.getLanguageName());
186 
187         Object[] invocationArgs = null;
188         ScriptProxy script = null;
189 
190         LogUtils.DEBUG("Classloader starting...");
191 
192         try (URLClassLoader scriptLoader = ClassLoaderFactory.getURLClassLoader(metaData)) {
193             LogUtils.DEBUG("Classloader finished...");
194 
195             ArrayList<Object> invocationArgList = new ArrayList<Object>();
196 
197             LogUtils.DEBUG("Parameter Mapping...");
198 
199             // Setup Context Object
200             XScriptContext xSc =
201                 ScriptContext.createContext(m_xModel, m_xInvocContext,
202                                             m_xContext, m_xMultiComponentFactory);
203 
204             scriptDesc.addArgumentType(XScriptContext.class);
205             invocationArgList.add(xSc);
206 
207             for (int i = 0; i < params.length; i++) {
208                 scriptDesc.addArgumentType(params[ i ].getClass());
209                 invocationArgList.add(params[ i ]);
210             }
211 
212             if (!invocationArgList.isEmpty()) {
213                 invocationArgs = invocationArgList.toArray();
214             }
215 
216             LogUtils.DEBUG("ScriptProxy starting... ");
217 
218             try {
219 
220                 String className = metaData.getLanguageName().substring(0,
221                                    metaData.getLanguageName().lastIndexOf('.'));
222 
223                 LogUtils.DEBUG("About to load Class " + className + " starting... ");
224 
225                 long start = new java.util.Date().getTime();
226                 Class<?> c = scriptLoader.loadClass(className);
227                 long end = new java.util.Date().getTime();
228 
229                 LogUtils.DEBUG("loadClass took: " + (end - start) + "milliseconds");
230 
231                 try {
232                     LogUtils.DEBUG("class loaded ... ");
233                     script = m_resolutionPolicy.getProxy(scriptDesc, c);
234                     LogUtils.DEBUG("script resolved ... ");
235                 } catch (NoSuchMethodException e) {
236                     // Framework error
237                     ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
238                         e.toString(), null, metaData.getLanguageName(),
239                         metaData.getLanguage(), ScriptFrameworkErrorType.NO_SUCH_SCRIPT);
240                     e2.initCause(e);
241                     throw e2;
242                 }
243             } catch (ClassNotFoundException e) {
244                 // Framework error
245                 ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
246                     e.toString(), null, metaData.getLanguageName(),
247                     metaData.getLanguage(), ScriptFrameworkErrorType.NO_SUCH_SCRIPT);
248                 e2.initCause(e);
249                 throw e2;
250             }
251         } catch (IOException e) {
252             // Framework error
253             ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
254                 e.toString(), null, metaData.getLanguageName(), metaData.getLanguage(),
255                 ScriptFrameworkErrorType.NO_SUCH_SCRIPT);
256             e2.initCause(e);
257             throw e2;
258         }
259 
260         LogUtils.DEBUG("Starting Invoke on Proxy ...");
261         Object result = null;
262 
263         try {
264             long start = new java.util.Date().getTime();
265             result = script.invoke(invocationArgs);
266             long end = new java.util.Date().getTime();
267             LogUtils.DEBUG("invoke took: " + (end - start) + "milliseconds");
268         } catch (java.lang.IllegalArgumentException iae) {
269             ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
270                 iae.getMessage(), null, metaData.getLanguageName(),
271                 metaData.getLanguage(), ScriptFrameworkErrorType.UNKNOWN);
272             e2.initCause(iae);
273             throw e2;
274         } catch (java.lang.IllegalAccessException ia) {
275             ScriptFrameworkErrorException e2 = new ScriptFrameworkErrorException(
276                 ia.toString(), null, metaData.getLanguageName(),
277                 metaData.getLanguage(), ScriptFrameworkErrorType.UNKNOWN);
278             e2.initCause(ia);
279             throw e2;
280         } catch (java.lang.reflect.InvocationTargetException ite) {
281             Throwable targetException = ite.getTargetException();
282 
283             ScriptExceptionRaisedException se =
284                 new ScriptExceptionRaisedException(targetException.toString());
285 
286             se.lineNum = -1;
287             se.scriptName = metaData.getLanguageName();
288             se.language = "Java";
289             se.exceptionType = targetException.getClass().getName();
290 
291             throw new com.sun.star.reflection.InvocationTargetException(
292                 "Scripting Framework error executing script ", null, se);
293 
294         } catch (Exception unknown) {
295             ScriptExceptionRaisedException se =
296                 new ScriptExceptionRaisedException(unknown.toString());
297             se.lineNum = -1;
298             se.scriptName = metaData.getLanguageName();
299             se.language = "Java";
300             se.exceptionType = unknown.getClass().getName();
301             throw new com.sun.star.reflection.InvocationTargetException(
302                 "Scripting Framework error executing script ", null, se);
303         }
304 
305         if (result == null) {
306             LogUtils.DEBUG("Got Nothing Back");
307             // in the case where there is no return type
308             Any voidAny = new Any(new Type(), null);
309             result = voidAny;
310         } else {
311             LogUtils.DEBUG("Got object " + result);
312         }
313 
314         return result;
315     }
316 }