1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 package com
.sun
.star
.comp
.loader
;
22 import java
.lang
.reflect
.Method
;
23 import java
.lang
.reflect
.InvocationTargetException
;
24 import java
.net
.URLDecoder
;
26 import com
.sun
.star
.loader
.CannotActivateFactoryException
;
27 import com
.sun
.star
.loader
.XImplementationLoader
;
29 import com
.sun
.star
.registry
.CannotRegisterImplementationException
;
30 import com
.sun
.star
.registry
.XRegistryKey
;
32 import com
.sun
.star
.lang
.XSingleComponentFactory
;
33 import com
.sun
.star
.lang
.XSingleServiceFactory
;
34 import com
.sun
.star
.lang
.XMultiServiceFactory
;
35 import com
.sun
.star
.lang
.XServiceInfo
;
36 import com
.sun
.star
.lang
.XInitialization
;
38 import com
.sun
.star
.uno
.XComponentContext
;
39 import com
.sun
.star
.beans
.XPropertySet
;
40 import com
.sun
.star
.util
.XMacroExpander
;
42 import com
.sun
.star
.uno
.Type
;
43 import com
.sun
.star
.uno
.UnoRuntime
;
45 import com
.sun
.star
.lib
.util
.StringHelper
;
47 import com
.sun
.star
.uno
.AnyConverter
;
51 * The <code>JavaLoader</code> class provides the functionality of the
52 * <code>com.sun.star.loader.Java</code> service.
54 * <p>Therefore the <code>JavaLoader</code> activates external UNO components
55 * which are implemented in Java.</p>
57 * <p>The loader is used by the <code>ServiceManger</code>.</p>
59 * @see com.sun.star.loader.XImplementationLoader
60 * @see com.sun.star.loader.Java
61 * @see com.sun.star.comp.servicemanager.ServiceManager
64 public class JavaLoader
implements XImplementationLoader
,
68 private static final boolean DEBUG
= false;
70 private static final void DEBUG(String dbg
) {
71 if (DEBUG
) System
.err
.println( dbg
);
74 private static String
[] supportedServices
= {
75 "com.sun.star.loader.Java"
78 protected XMultiServiceFactory multiServiceFactory
= null;
80 private XMacroExpander m_xMacroExpander
= null;
81 private static final String EXPAND_PROTOCOL_PREFIX
= "vnd.sun.star.expand:";
84 * Expands macrofied url using the macro expander singleton.
86 private String
expand_url( String url
) throws RuntimeException
88 if (url
== null || !url
.startsWith( EXPAND_PROTOCOL_PREFIX
)) {
92 if (m_xMacroExpander
== null) {
94 UnoRuntime
.queryInterface(
95 XPropertySet
.class, multiServiceFactory
);
97 throw new com
.sun
.star
.uno
.RuntimeException(
98 "service manager does not support XPropertySet!",
101 XComponentContext xContext
= (XComponentContext
)
102 AnyConverter
.toObject(
103 new Type( XComponentContext
.class ),
104 xProps
.getPropertyValue( "DefaultContext" ) );
105 m_xMacroExpander
= (XMacroExpander
)AnyConverter
.toObject(
106 new Type( XMacroExpander
.class ),
107 xContext
.getValueByName(
108 "/singletons/com.sun.star.util.theMacroExpander" )
111 // decode uric class chars
112 String macro
= URLDecoder
.decode(
113 StringHelper
.replace(
114 url
.substring( EXPAND_PROTOCOL_PREFIX
.length() ),
115 '+', "%2B" ), "UTF-8" );
116 // expand macro string
117 String ret
= m_xMacroExpander
.expandMacros( macro
);
120 "JavaLoader.expand_url(): " + url
+ " => " +
121 macro
+ " => " + ret
);
124 } catch (com
.sun
.star
.uno
.Exception exc
) {
125 throw new com
.sun
.star
.uno
.RuntimeException(exc
,
126 exc
.getMessage(), this );
127 } catch (java
.lang
.Exception exc
) {
128 throw new com
.sun
.star
.uno
.RuntimeException(exc
,
129 exc
.getMessage(), this );
134 * Default constructor.
136 * <p>Creates a new instance of the <code>JavaLoader</code> class.</p>
138 public JavaLoader() {}
141 * Creates a new <code>JavaLoader</code> object.
143 * <p>The specified <code>com.sun.star.lang.XMultiServiceFactory</code> is
144 * the <code>ServiceManager</code> service which can be delivered to all
145 * components the <code>JavaLoader</code> is loading.</p>
147 * <p>To set the <code>MultiServiceFactory</code> you can use the
148 * <code>com.sun.star.lang.XInitialization</code> interface, either.</p>
150 * @param factory the <code>ServiceManager</code>.
151 * @see com.sun.star.comp.servicemanager.ServiceManager
152 * @see com.sun.star.lang.XInitialization
154 public JavaLoader(XMultiServiceFactory factory
) {
155 multiServiceFactory
= factory
;
159 * Unlike the original intention, the method could be called every time a
160 * new <code>com.sun.star.lang.XMultiServiceFactory</code> should be set at
163 * @param args - the first parameter (args[0]) specifies the <code>ServiceManager</code>.
164 * @see com.sun.star.lang.XInitialization
165 * @see com.sun.star.comp.servicemanager.ServiceManager
167 public void initialize( java
.lang
.Object
[] args
)
168 throws com
.sun
.star
.uno
.Exception
,
169 com
.sun
.star
.uno
.RuntimeException
171 if (args
.length
== 0)
172 throw new com
.sun
.star
.lang
.IllegalArgumentException("No arguments specified");
175 multiServiceFactory
= (XMultiServiceFactory
) AnyConverter
.toObject(
176 new Type(XMultiServiceFactory
.class), args
[0]);
177 } catch (ClassCastException castEx
) {
178 throw new com
.sun
.star
.lang
.IllegalArgumentException(castEx
,
179 "The argument must be an instance of XMultiServiceFactory");
184 * Supplies the implementation name of the component.
186 * @return the implementation name - here the class name.
187 * @see com.sun.star.lang.XServiceInfo
189 public String
getImplementationName()
190 throws com
.sun
.star
.uno
.RuntimeException
192 return getClass().getName();
196 * Verifies if a given service is supported by the component.
198 * @param serviceName the name of the service that should be checked.
199 * @return true,if service is supported - otherwise false.
201 * @see com.sun.star.lang.XServiceInfo
203 public boolean supportsService(String serviceName
)
204 throws com
.sun
.star
.uno
.RuntimeException
206 for (String supportedService
: supportedServices
) {
207 if (supportedService
.equals(serviceName
)) {
215 * Supplies a list of all service names supported by the component.
217 * @return a String array with all supported services.
218 * @see com.sun.star.lang.XServiceInfo
220 public String
[] getSupportedServiceNames()
221 throws com
.sun
.star
.uno
.RuntimeException
223 return supportedServices
;
227 * Provides a components factory.
229 * <p>The <code>JavaLoader</code> tries to load the class first. If a
230 * location URL is given the RegistrationClassFinder is used to load the
231 * class. Otherwise the class is loaded through the Class.forName method.</p>
233 * <p>To get the factory the inspects the class for the optional static member
234 * functions __getServiceFactory resp. getServiceFactory (DEPRECATED).</p>
236 * @param implementationName the implementation (class) name of the component.
237 * @param implementationLoaderUrl the URL of the implementation loader. Not used.
238 * @param locationUrl points to an archive (JAR file) which contains a component.
239 * @param xKey registry key.
240 * @return the factory for the component (@see com.sun.star.lang.XSingleServiceFactory)
242 * @see com.sun.star.loader.XImplementationLoader
243 * @see com.sun.star.comp.loader.RegistrationClassFinder
245 public java
.lang
.Object
activate( String implementationName
,
246 String implementationLoaderUrl
,
249 throws CannotActivateFactoryException
,
250 com
.sun
.star
.uno
.RuntimeException
252 locationUrl
= expand_url( locationUrl
);
254 Object returnObject
= null;
257 DEBUG("try to get factory for " + implementationName
);
259 // First we must get the class of the implementation
260 // 1. If a location URL is given it is assumed that this points to a JAR file.
261 // The components class name is stored in the manifest file.
262 // 2. If only the implementation name is given, the class is loaded with the
263 // Class.forName() method. This is a hack to load bootstrap components.
264 // Normally a string must no be null.
266 if ( locationUrl
!= null ) {
267 clazz
= RegistrationClassFinder
.find( locationUrl
);
269 throw new CannotActivateFactoryException(
270 "Cannot activate jar " + locationUrl
);
273 clazz
= Class
.forName( implementationName
);
275 throw new CannotActivateFactoryException(
276 "Cannot find class " + implementationName
);
279 } catch (java
.net
.MalformedURLException e
) {
280 throw new CannotActivateFactoryException(e
, "Can not activate factory because " + e
);
281 } catch (java
.io
.IOException e
) {
282 throw new CannotActivateFactoryException(e
, "Can not activate factory because " + e
);
283 } catch (java
.lang
.ClassNotFoundException e
) {
284 throw new CannotActivateFactoryException(e
, "Can not activate factory because " + e
);
287 Class
<?
>[] paramTypes
= {String
.class, XMultiServiceFactory
.class, XRegistryKey
.class};
288 Object
[] params
= { implementationName
, multiServiceFactory
, xKey
};
290 // try to get factory from implementation class
291 // latest style: use the public static method __getComponentFactory
292 // - new style: use the public static method __getServiceFactory
293 // - old style: use the public static method getServiceFactory ( DEPRECATED )
295 Method compfac_method
= null;
297 compfac_method
= clazz
.getMethod(
298 "__getComponentFactory", new Class
[] { String
.class } );
299 } catch ( NoSuchMethodException noSuchMethodEx
) {
300 } catch ( SecurityException secEx
) {
303 Method method
= null;
304 if (null == compfac_method
) {
306 method
= clazz
.getMethod("__getServiceFactory", paramTypes
);
307 } catch ( NoSuchMethodException noSuchMethodEx
) {
308 } catch ( SecurityException secEx
) {
313 if (null != compfac_method
) {
314 Object ret
= compfac_method
.invoke( clazz
, new Object
[] { implementationName
} );
315 if (!(ret
instanceof XSingleComponentFactory
))
316 throw new CannotActivateFactoryException(
317 "No factory object for " + implementationName
);
322 if ( method
== null )
323 method
= clazz
.getMethod("getServiceFactory", paramTypes
);
325 Object oRet
= method
.invoke(clazz
, params
);
327 if ( (oRet
!= null) && (oRet
instanceof XSingleServiceFactory
) )
330 } catch ( NoSuchMethodException e
) {
331 throw new CannotActivateFactoryException(e
, "Can not activate the factory for "
332 + implementationName
);
333 } catch ( SecurityException e
) {
334 throw new CannotActivateFactoryException(e
, "Can not activate the factory for "
335 + implementationName
);
336 } catch ( IllegalAccessException e
) {
337 throw new CannotActivateFactoryException(e
, "Can not activate the factory for "
338 + implementationName
);
340 catch ( IllegalArgumentException e
) {
341 throw new CannotActivateFactoryException(e
, "Can not activate the factory for "
342 + implementationName
);
343 } catch ( InvocationTargetException e
) {
344 throw new CannotActivateFactoryException(e
, "Can not activate the factory for "
345 + implementationName
);
352 * Registers the component in a registry under a given root key.
354 * <p>If the component supports the optional
355 * methods __writeRegistryServiceInfo, writeRegistryServiceInfo (DEPRECATED),
356 * the call is delegated to that method. Otherwise a default registration
357 * will be accomplished.</p>
359 * @param regKey the root key under that the component should be registered.
360 * @param implementationLoaderUrl specifies the loader, the component is loaded by.
361 * @param locationUrl points to an archive (JAR file) which contains a component.
362 * @return true if registration is successfully - otherwise false.
364 public boolean writeRegistryInfo( XRegistryKey regKey
,
365 String implementationLoaderUrl
,
367 throws CannotRegisterImplementationException
,
368 com
.sun
.star
.uno
.RuntimeException
370 locationUrl
= expand_url( locationUrl
);
372 boolean success
= false;
376 Class
<?
> clazz
= RegistrationClassFinder
.find(locationUrl
);
378 throw new CannotRegisterImplementationException(
379 "Cannot determine registration class!" );
381 Class
<?
>[] paramTypes
= { XRegistryKey
.class };
382 Object
[] params
= { regKey
};
384 Method method
= clazz
.getMethod("__writeRegistryServiceInfo", paramTypes
);
385 Object oRet
= method
.invoke(clazz
, params
);
387 if ( (oRet
!= null) && (oRet
instanceof Boolean
) )
388 success
= ((Boolean
) oRet
).booleanValue();
389 } catch (Exception e
) {
390 throw new CannotRegisterImplementationException(e
, e
.toString());
397 * Supplies the factory for the <code>JavaLoader</code>.
399 * @param implName the name of the desired component.
400 * @param multiFactory the <code>ServiceManager</code> is delivered to the factory.
401 * @param regKey not used - can be null.
402 * @return the factory for the <code>JavaLoader</code>.
404 public static XSingleServiceFactory
getServiceFactory( String implName
,
405 XMultiServiceFactory multiFactory
,
408 if ( implName
.equals(JavaLoader
.class.getName()) )
409 return new JavaLoaderFactory( multiFactory
);
415 * Registers the <code>JavaLoader</code> at the registry.
417 * @param regKey root key under which the <code>JavaLoader</code> should be registered.
418 * @return true if registration succeeded - otherwise false.
420 public static boolean writeRegistryServiceInfo(XRegistryKey regKey
) {
421 boolean result
= false;
424 XRegistryKey newKey
= regKey
.createKey("/" + JavaLoader
.class.getName() + "/UNO/SERVICE");
426 for (String supportedService
: supportedServices
) {
427 newKey
.createKey(supportedService
);
431 } catch (Exception ex
) {
432 if (DEBUG
) System
.err
.println(">>>JavaLoader.writeRegistryServiceInfo " + ex
);
439 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */