xref: /AOO41X/main/jurt/com/sun/star/comp/loader/JavaLoader.java (revision 2be432768a66cc90838f6a32e76ec156f587e741)
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 
24 package com.sun.star.comp.loader;
25 
26 import java.lang.reflect.Method;
27 
28 import java.lang.reflect.InvocationTargetException;
29 
30 import java.net.URLDecoder;
31 
32 import com.sun.star.loader.CannotActivateFactoryException;
33 import com.sun.star.loader.XImplementationLoader;
34 
35 import com.sun.star.registry.CannotRegisterImplementationException;
36 import com.sun.star.registry.XRegistryKey;
37 
38 import com.sun.star.lang.XSingleComponentFactory;
39 import com.sun.star.lang.XSingleServiceFactory;
40 import com.sun.star.lang.XMultiServiceFactory;
41 import com.sun.star.lang.XServiceInfo;
42 import com.sun.star.lang.XInitialization;
43 
44 import com.sun.star.uno.XComponentContext;
45 import com.sun.star.beans.XPropertySet;
46 import com.sun.star.util.XMacroExpander;
47 
48 import com.sun.star.uno.Type;
49 import com.sun.star.uno.UnoRuntime;
50 
51 import com.sun.star.lib.util.StringHelper;
52 
53 import com.sun.star.uno.AnyConverter;
54 
55 
56 /**
57  * The <code>JavaLoader</code> class provides the functionality of the <code>com.sun.star.loader.Java</code>
58  * service. Therefor the <code>JavaLoader</code> activates external UNO components which are implemented in Java.
59  * The loader is used by the <code>ServiceManger</code>.
60  * <p>
61  * @version     $Revision: 1.16 $ $ $Date: 2008-04-11 11:10:31 $
62  * @author      Markus Herzog
63  * @see         com.sun.star.loader.XImplementationLoader
64  * @see         com.sun.star.loader.Java
65  * @see         com.sun.star.comp.servicemanager.ServiceManager
66  * @see         com.sun.star.lang.ServiceManager
67  * @since       UDK1.0
68  */
69 public class JavaLoader implements XImplementationLoader,
70                                    XServiceInfo,
71                                    XInitialization
72 {
73     private static final boolean DEBUG = false;
74 
DEBUG(String dbg)75     private static final void DEBUG(String dbg) {
76         if (DEBUG) System.err.println( dbg );
77     }
78 
79     private static String[] supportedServices = {
80         "com.sun.star.loader.Java"
81     };
82 
83     protected XMultiServiceFactory multiServiceFactory = null;
84 
85     private XMacroExpander m_xMacroExpander = null;
86     private static final String EXPAND_PROTOCOL_PREFIX = "vnd.sun.star.expand:";
87 
88     /** Expands macrofied url using the macro expander singleton.
89      */
expand_url( String url )90     private String expand_url( String url ) throws RuntimeException
91     {
92         if (url != null && url.startsWith( EXPAND_PROTOCOL_PREFIX ))
93         {
94             try
95             {
96                 if (m_xMacroExpander == null)
97                 {
98                     XPropertySet xProps =
99                         UnoRuntime.queryInterface(
100                             XPropertySet.class, multiServiceFactory );
101                     if (xProps == null)
102                     {
103                         throw new com.sun.star.uno.RuntimeException(
104                             "service manager does not support XPropertySet!",
105                             this );
106                     }
107                     XComponentContext xContext = (XComponentContext)
108                         AnyConverter.toObject(
109                             new Type( XComponentContext.class ),
110                             xProps.getPropertyValue( "DefaultContext" ) );
111                     m_xMacroExpander = (XMacroExpander)AnyConverter.toObject(
112                         new Type( XMacroExpander.class ),
113                         xContext.getValueByName(
114                             "/singletons/com.sun.star.util.theMacroExpander" )
115                         );
116                 }
117                 // decode uric class chars
118                 String macro = URLDecoder.decode(
119                     StringHelper.replace(
120                         url.substring( EXPAND_PROTOCOL_PREFIX.length() ),
121                         '+', "%2B" ) );
122                 // expand macro string
123                 String ret = m_xMacroExpander.expandMacros( macro );
124                 if (DEBUG)
125                 {
126                     System.err.println(
127                         "JavaLoader.expand_url(): " + url + " => " +
128                         macro + " => " + ret );
129                 }
130                 return ret;
131             }
132             catch (com.sun.star.uno.Exception exc)
133             {
134                 throw new com.sun.star.uno.RuntimeException(
135                     exc.getMessage(), this );
136             }
137             catch (java.lang.Exception exc)
138             {
139                 throw new com.sun.star.uno.RuntimeException(
140                     exc.getMessage(), this );
141             }
142         }
143         return url;
144     }
145 
146     /** default constructor
147      */
148 
149     /**
150      * Creates a new instance of the <code>JavaLoader</code> class.
151      * <p>
152      * @return  new instance
153      */
JavaLoader()154     public JavaLoader() {}
155 
156     /**
157      * Creates a new <code>JavaLoader</code> object. The specified <code>com.sun.star.lang.XMultiServiceFactory</code>
158      * is the <code>ServiceManager</code> service which can be deliviert to all components the <code>JavaLoader</code> is
159      * loading.
160      * To set the <code>MultiServiceFactory</code> you can use the <code>com.sun.star.lang.XInitialization</code> interface, either.
161      * <p>
162      * @return  new instance
163      * @param   factory     the <code>ServiceManager</code>
164      * @see     com.sun.star.lang.ServiceManager
165      * @see     com.sun.star.lang.ServiceManager
166      * @see     com.sun.star.lang.XInitialization
167      */
JavaLoader(XMultiServiceFactory factory)168     public JavaLoader(XMultiServiceFactory factory) {
169         multiServiceFactory = factory;
170     }
171 
172     /**
173      * Unlike the original intention, the method could be called every time a new
174      * <code>com.sun.star.lang.XMultiServiceFactory</code> should be set at the loader.
175      * <p>
176      * @param       args - the first parameter (args[0]) specifices the <code>ServiceManager</code>
177      * @see         com.sun.star.lang.XInitialization
178      * @see         com.sun.star.lang.ServiceManager
179      */
initialize( java.lang.Object[] args )180     public void initialize( java.lang.Object[] args )
181             throws com.sun.star.uno.Exception,
182                    com.sun.star.uno.RuntimeException
183     {
184         if (args.length == 0) throw new com.sun.star.lang.IllegalArgumentException("No arguments specified");
185 
186         try {
187             multiServiceFactory = (XMultiServiceFactory) AnyConverter.toObject(
188                 new Type(XMultiServiceFactory.class), args[0]);
189         }
190         catch (ClassCastException castEx) {
191             throw new com.sun.star.lang.IllegalArgumentException(
192                 "The argument must be an instance of XMultiServiceFactory");
193         }
194     }
195 
196     /**
197      * Supplies the implementation name of the component.
198      * <p>
199      * @return      the implementation name - here the class name
200      * @see         com.sun.star.lang.XServiceInfo
201      */
getImplementationName()202     public String getImplementationName()
203             throws com.sun.star.uno.RuntimeException
204     {
205         return getClass().getName();
206     }
207 
208     /**
209      * Verifies if a given service is supported by the component.
210      * <p>
211      * @return      true,if service is suported - otherwise false
212      * @param       serviceName     the name of the service that should be checked
213      * @see         com.sun.star.lang.XServiceInfo
214      */
supportsService(String serviceName)215     public boolean supportsService(String serviceName)
216             throws com.sun.star.uno.RuntimeException
217     {
218         for ( int i = 0; i < supportedServices.length; i++ ) {
219             if ( supportedServices[i].equals(serviceName) )
220                 return true;
221         }
222         return false;
223     }
224 
225     /**
226      * Supplies a list of all service names supported by the component
227      * <p>
228      * @return      a String array with all supported services
229      * @see         com.sun.star.lang.XServiceInfo
230      */
getSupportedServiceNames()231     public String[] getSupportedServiceNames()
232             throws com.sun.star.uno.RuntimeException
233     {
234         return supportedServices;
235     }
236 
237     /**
238      * Provides a components factory.
239      * The <code>JavaLoader</code> tries to load the class first. If a loacation URL is given the
240      * RegistrationClassFinder is used to load the class. Otherwise the class is loaded thru the Class.forName
241      * method.
242      * To get the factory the inspects the class for the optional static member functions __getServiceFactory resp.
243      * getServiceFactory (DEPRECATED).
244      * If the function can not be found a default factory @see ComponentFactoryWrapper will be created.
245      * <p>
246      * @return      the factory for the component (@see com.sun.star.lang.XSingleServiceFactory)
247      * @param       implementationName          the implementation (class) name of the component
248      * @param       implementationLoaderUrl     the URL of the implementation loader. Not used.
249      * @param       locationUrl                 points to an archive (JAR file) which contains a component
250      * @param       xKey
251      * @see         com.sun.star.lang.XImplementationLoader
252      * @see         com.sun.star.com.loader.RegistrationClassFinder
253      */
activate( String implementationName, String implementationLoaderUrl, String locationUrl, XRegistryKey xKey )254     public java.lang.Object activate( String implementationName,
255                                       String implementationLoaderUrl,
256                                       String locationUrl,
257                                       XRegistryKey xKey )
258         throws CannotActivateFactoryException,
259                com.sun.star.uno.RuntimeException
260     {
261         locationUrl = expand_url( locationUrl );
262 
263         Object returnObject  = null;
264         Class clazz  ;
265 
266         DEBUG("try to get factory for " + implementationName);
267 
268         // first we must get the class of the implementation
269         // 1. If a location URL is given it is assumed that this points to a JAR file.
270         //    The components class name is stored in the manifest file.
271         // 2. If only the implementation name is given, the class is loaded with the
272         //    Class.forName() method. This is a hack to load bootstrap components.
273         //    Normally a string must no be null.
274         try {
275             if ( locationUrl != null ) {
276                 // 1.
277                 clazz = RegistrationClassFinder.find( locationUrl );
278             }
279             else {
280                 // 2.
281                 clazz = Class.forName( implementationName );
282             }
283         }
284         catch (java.net.MalformedURLException e) {
285             CannotActivateFactoryException cae = new CannotActivateFactoryException(
286                     "Can not activate factory because " + e.toString() );
287             cae.fillInStackTrace();
288             throw cae;
289         }
290         catch (java.io.IOException e) {
291             CannotActivateFactoryException cae = new CannotActivateFactoryException(
292                     "Can not activate factory because " + e.toString() );
293             cae.fillInStackTrace();
294             throw cae;
295         }
296         catch (java.lang.ClassNotFoundException e) {
297             CannotActivateFactoryException cae = new CannotActivateFactoryException(
298                     "Can not activate factory because " + e.toString() );
299             cae.fillInStackTrace();
300             throw cae;
301         }
302 
303         if (null == clazz)
304         {
305             CannotActivateFactoryException cae =
306                 new CannotActivateFactoryException(
307                     "Cannot determine activation class!" );
308             cae.fillInStackTrace();
309             throw cae;
310         }
311 
312         Class[] paramTypes = {String.class, XMultiServiceFactory.class, XRegistryKey.class};
313         Object[] params = { implementationName, multiServiceFactory, xKey };
314 
315         // try to get factory from implemetation class
316         // latest style: use the public static method __getComponentFactory
317         // - new style: use the public static method __getServiceFactory
318         // - old style: use the public static method getServiceFactory ( DEPRECATED )
319 
320         Method compfac_method = null;
321         try
322         {
323             compfac_method = clazz.getMethod(
324                 "__getComponentFactory", new Class [] { String.class } );
325         }
326         catch ( NoSuchMethodException noSuchMethodEx) {}
327         catch ( SecurityException secEx) {}
328 
329         Method method = null;
330         if (null == compfac_method)
331         {
332             try {
333                 method = clazz.getMethod("__getServiceFactory", paramTypes);
334             }
335             catch ( NoSuchMethodException noSuchMethodEx) {
336                 method = null;
337             }
338             catch ( SecurityException secEx) {
339                 method = null;
340             }
341         }
342 
343         try {
344             if (null != compfac_method)
345             {
346                 Object ret = compfac_method.invoke( clazz, new Object [] { implementationName } );
347                 if (null == ret || !(ret instanceof XSingleComponentFactory))
348                 {
349                     throw new CannotActivateFactoryException(
350                         "No factory object for " + implementationName );
351                 }
352                 return (XSingleComponentFactory)ret;
353             }
354             else
355             {
356                 if ( method == null ) {
357                     method = clazz.getMethod("getServiceFactory", paramTypes);
358                 }
359 
360                 Object oRet = method.invoke(clazz, params);
361 
362                 if ( (oRet != null) && (oRet instanceof XSingleServiceFactory) ) {
363                     returnObject = (XSingleServiceFactory) oRet;
364                 }
365             }
366         }
367         catch ( NoSuchMethodException e) {
368             throw new CannotActivateFactoryException("Can not activate the factory for "
369                         + implementationName + " because " + e.toString() );
370         }
371         catch ( SecurityException e) {
372             throw new CannotActivateFactoryException("Can not activate the factory for "
373                         + implementationName + " because " + e.toString() );
374         }
375         catch ( IllegalAccessException e ) {
376             throw new CannotActivateFactoryException("Can not activate the factory for "
377                         + implementationName + " because " + e.toString() );
378         }
379         catch ( IllegalArgumentException e ) {
380             throw new CannotActivateFactoryException("Can not activate the factory for "
381                         + implementationName + " because " + e.toString() );
382         }
383         catch ( InvocationTargetException e ) {
384             throw new CannotActivateFactoryException("Can not activate the factory for "
385                         + implementationName + " because " + e.getTargetException().toString() );
386         }
387 
388         return returnObject;
389     }
390 
391     /**
392      * Registers the component in a registry under a given root key. If the component supports the optional
393      * methods __writeRegistryServiceInfo, writeRegistryServiceInfo (DEPRECATED), the call is delegated to that
394      * method. Otherwise a default registration will be accomplished.
395      * <p>
396      * @return      true if registration is successfully - otherwise false
397      * @param       regKey                  the root key under that the component should be registred.
398      * @param       implementationLoaderUrl specifies the loader, the component is loaded by.
399      * @param       locationUrl             points to an archive (JAR file) which contains a component
400      * @see         ComponentFactoryWrapper
401      */
writeRegistryInfo( XRegistryKey regKey, String implementationLoaderUrl, String locationUrl )402     public boolean writeRegistryInfo( XRegistryKey regKey,
403                                       String implementationLoaderUrl,
404                                       String locationUrl )
405             throws CannotRegisterImplementationException,
406                    com.sun.star.uno.RuntimeException
407     {
408         locationUrl = expand_url( locationUrl );
409 
410         boolean success = false;
411 
412         try {
413 
414             Class clazz = RegistrationClassFinder.find(locationUrl);
415             if (null == clazz)
416             {
417                 throw new CannotRegisterImplementationException(
418                     "Cannot determine registration class!" );
419             }
420 
421             Class[] paramTypes = { XRegistryKey.class };
422             Object[] params = { regKey };
423 
424             Method method  = clazz.getMethod("__writeRegistryServiceInfo", paramTypes);
425             Object oRet = method.invoke(clazz, params);
426 
427             if ( (oRet != null) && (oRet instanceof Boolean) )
428                 success = ((Boolean) oRet).booleanValue();
429         }
430         catch (Exception e) {
431             throw new CannotRegisterImplementationException( e.getMessage());
432         }
433 
434         return success;
435     }
436 
437     /**
438      * Supplies the factory for the <code>JavaLoader</code>
439      * <p>
440      * @return  the factory for the <code>JavaLoader</code>
441      * @param   implName        the name of the desired component
442      * @param   multiFactory    the <code>ServiceManager</code> is delivered to the factory
443      * @param   regKey          not used - can be null
444      */
getServiceFactory( String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey)445     public static XSingleServiceFactory getServiceFactory( String implName,
446                                                            XMultiServiceFactory multiFactory,
447                                                            XRegistryKey regKey)
448     {
449         if ( implName.equals(JavaLoader.class.getName()) )
450             return new JavaLoaderFactory( multiFactory );
451 
452         return null;
453     }
454 
455     /**
456      * Registers the <code>JavaLoader</code> at the registry.
457      * <p>
458      * @return     true if registration succseeded - otherwise false
459      * @param      regKey   root key under which the <code>JavaLoader</code> should be regidstered
460      */
writeRegistryServiceInfo(XRegistryKey regKey)461     public static boolean writeRegistryServiceInfo(XRegistryKey regKey) {
462         boolean result = false;
463 
464         try {
465             XRegistryKey newKey = regKey.createKey("/" + JavaLoader.class.getName() + "/UNO/SERVICE");
466 
467             for (int i=0; i<supportedServices.length; i++)
468                 newKey.createKey(supportedServices[i]);
469 
470             result = true;
471         }
472         catch (Exception ex) {
473             if (DEBUG) System.err.println(">>>JavaLoader.writeRegistryServiceInfo " + ex);
474         }
475 
476         return result;
477     }
478 }
479 
480