/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ package com.sun.star.comp.loader; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.net.URLDecoder; import com.sun.star.loader.CannotActivateFactoryException; import com.sun.star.loader.XImplementationLoader; import com.sun.star.registry.CannotRegisterImplementationException; import com.sun.star.registry.XRegistryKey; import com.sun.star.lang.XSingleComponentFactory; import com.sun.star.lang.XSingleServiceFactory; import com.sun.star.lang.XMultiServiceFactory; import com.sun.star.lang.XServiceInfo; import com.sun.star.lang.XInitialization; import com.sun.star.uno.XComponentContext; import com.sun.star.beans.XPropertySet; import com.sun.star.util.XMacroExpander; import com.sun.star.uno.Type; import com.sun.star.uno.UnoRuntime; import com.sun.star.lib.util.StringHelper; import com.sun.star.uno.AnyConverter; /** * The JavaLoader class provides the functionality of the * com.sun.star.loader.Java service. * *

Therefore the JavaLoader activates external UNO components * which are implemented in Java.

* *

The loader is used by the ServiceManger.

* * @see com.sun.star.loader.XImplementationLoader * @see com.sun.star.loader.Java * @see com.sun.star.comp.servicemanager.ServiceManager * @since UDK1.0 */ public class JavaLoader implements XImplementationLoader, XServiceInfo, XInitialization { private static final boolean DEBUG = false; private static final void DEBUG(String dbg) { if (DEBUG) System.err.println( dbg ); } private static String[] supportedServices = { "com.sun.star.loader.Java" }; protected XMultiServiceFactory multiServiceFactory = null; private XMacroExpander m_xMacroExpander = null; private static final String EXPAND_PROTOCOL_PREFIX = "vnd.sun.star.expand:"; /** * Expands macrofied url using the macro expander singleton. */ private String expand_url( String url ) throws RuntimeException { if (url == null || !url.startsWith( EXPAND_PROTOCOL_PREFIX )) { return url; } try { if (m_xMacroExpander == null) { XPropertySet xProps = UnoRuntime.queryInterface( XPropertySet.class, multiServiceFactory ); if (xProps == null) { throw new com.sun.star.uno.RuntimeException( "service manager does not support XPropertySet!", this ); } XComponentContext xContext = (XComponentContext) AnyConverter.toObject( new Type( XComponentContext.class ), xProps.getPropertyValue( "DefaultContext" ) ); m_xMacroExpander = (XMacroExpander)AnyConverter.toObject( new Type( XMacroExpander.class ), xContext.getValueByName( "/singletons/com.sun.star.util.theMacroExpander" ) ); } // decode uric class chars String macro = URLDecoder.decode( StringHelper.replace( url.substring( EXPAND_PROTOCOL_PREFIX.length() ), '+', "%2B" ), "UTF-8" ); // expand macro string String ret = m_xMacroExpander.expandMacros( macro ); if (DEBUG) { System.err.println( "JavaLoader.expand_url(): " + url + " => " + macro + " => " + ret ); } return ret; } catch (com.sun.star.uno.Exception exc) { throw new com.sun.star.uno.RuntimeException(exc, exc.getMessage(), this ); } catch (java.lang.Exception exc) { throw new com.sun.star.uno.RuntimeException(exc, exc.getMessage(), this ); } } /** * Default constructor. * *

Creates a new instance of the JavaLoader class.

*/ public JavaLoader() {} /** * Creates a new JavaLoader object. * *

The specified com.sun.star.lang.XMultiServiceFactory is * the ServiceManager service which can be delivered to all * components the JavaLoader is loading.

* *

To set the MultiServiceFactory you can use the * com.sun.star.lang.XInitialization interface, either.

* * @param factory the ServiceManager. * @see com.sun.star.comp.servicemanager.ServiceManager * @see com.sun.star.lang.XInitialization */ public JavaLoader(XMultiServiceFactory factory) { multiServiceFactory = factory; } /** * Unlike the original intention, the method could be called every time a * new com.sun.star.lang.XMultiServiceFactory should be set at * the loader. * * @param args - the first parameter (args[0]) specifies the ServiceManager. * @see com.sun.star.lang.XInitialization * @see com.sun.star.comp.servicemanager.ServiceManager */ public void initialize( java.lang.Object[] args ) throws com.sun.star.uno.Exception, com.sun.star.uno.RuntimeException { if (args.length == 0) throw new com.sun.star.lang.IllegalArgumentException("No arguments specified"); try { multiServiceFactory = (XMultiServiceFactory) AnyConverter.toObject( new Type(XMultiServiceFactory.class), args[0]); } catch (ClassCastException castEx) { throw new com.sun.star.lang.IllegalArgumentException(castEx, "The argument must be an instance of XMultiServiceFactory"); } } /** * Supplies the implementation name of the component. * * @return the implementation name - here the class name. * @see com.sun.star.lang.XServiceInfo */ public String getImplementationName() throws com.sun.star.uno.RuntimeException { return getClass().getName(); } /** * Verifies if a given service is supported by the component. * * @param serviceName the name of the service that should be checked. * @return true,if service is supported - otherwise false. * * @see com.sun.star.lang.XServiceInfo */ public boolean supportsService(String serviceName) throws com.sun.star.uno.RuntimeException { for (String supportedService : supportedServices) { if (supportedService.equals(serviceName)) { return true; } } return false; } /** * Supplies a list of all service names supported by the component. * * @return a String array with all supported services. * @see com.sun.star.lang.XServiceInfo */ public String[] getSupportedServiceNames() throws com.sun.star.uno.RuntimeException { return supportedServices; } /** * Provides a components factory. * *

The JavaLoader tries to load the class first. If a * location URL is given the RegistrationClassFinder is used to load the * class. Otherwise the class is loaded through the Class.forName method.

* *

To get the factory the inspects the class for the optional static member * functions __getServiceFactory resp. getServiceFactory (DEPRECATED).

* * @param implementationName the implementation (class) name of the component. * @param implementationLoaderUrl the URL of the implementation loader. Not used. * @param locationUrl points to an archive (JAR file) which contains a component. * @param xKey registry key. * @return the factory for the component (@see com.sun.star.lang.XSingleServiceFactory) * * @see com.sun.star.loader.XImplementationLoader * @see com.sun.star.comp.loader.RegistrationClassFinder */ public java.lang.Object activate( String implementationName, String implementationLoaderUrl, String locationUrl, XRegistryKey xKey ) throws CannotActivateFactoryException, com.sun.star.uno.RuntimeException { locationUrl = expand_url( locationUrl ); Object returnObject = null; Class clazz ; DEBUG("try to get factory for " + implementationName); // First we must get the class of the implementation // 1. If a location URL is given it is assumed that this points to a JAR file. // The components class name is stored in the manifest file. // 2. If only the implementation name is given, the class is loaded with the // Class.forName() method. This is a hack to load bootstrap components. // Normally a string must no be null. try { if ( locationUrl != null ) { clazz = RegistrationClassFinder.find( locationUrl ); if (clazz == null) { throw new CannotActivateFactoryException( "Cannot activate jar " + locationUrl); } } else { clazz = Class.forName( implementationName ); if (clazz == null) { throw new CannotActivateFactoryException( "Cannot find class " + implementationName); } } } catch (java.net.MalformedURLException e) { throw new CannotActivateFactoryException(e, "Can not activate factory because " + e); } catch (java.io.IOException e) { throw new CannotActivateFactoryException(e, "Can not activate factory because " + e); } catch (java.lang.ClassNotFoundException e) { throw new CannotActivateFactoryException(e, "Can not activate factory because " + e); } Class[] paramTypes = {String.class, XMultiServiceFactory.class, XRegistryKey.class}; Object[] params = { implementationName, multiServiceFactory, xKey }; // try to get factory from implementation class // latest style: use the public static method __getComponentFactory // - new style: use the public static method __getServiceFactory // - old style: use the public static method getServiceFactory ( DEPRECATED ) Method compfac_method = null; try { compfac_method = clazz.getMethod( "__getComponentFactory", new Class [] { String.class } ); } catch ( NoSuchMethodException noSuchMethodEx) { } catch ( SecurityException secEx) { } Method method = null; if (null == compfac_method) { try { method = clazz.getMethod("__getServiceFactory", paramTypes); } catch ( NoSuchMethodException noSuchMethodEx) { } catch ( SecurityException secEx) { } } try { if (null != compfac_method) { Object ret = compfac_method.invoke( clazz, new Object [] { implementationName } ); if (!(ret instanceof XSingleComponentFactory)) throw new CannotActivateFactoryException( "No factory object for " + implementationName ); return ret; } else { if ( method == null ) method = clazz.getMethod("getServiceFactory", paramTypes); Object oRet = method.invoke(clazz, params); if ( (oRet != null) && (oRet instanceof XSingleServiceFactory) ) returnObject = oRet; } } catch ( NoSuchMethodException e) { throw new CannotActivateFactoryException(e, "Can not activate the factory for " + implementationName); } catch ( SecurityException e) { throw new CannotActivateFactoryException(e, "Can not activate the factory for " + implementationName); } catch ( IllegalAccessException e ) { throw new CannotActivateFactoryException(e, "Can not activate the factory for " + implementationName); } catch ( IllegalArgumentException e ) { throw new CannotActivateFactoryException(e, "Can not activate the factory for " + implementationName); } catch ( InvocationTargetException e ) { throw new CannotActivateFactoryException(e, "Can not activate the factory for " + implementationName); } return returnObject; } /** * Registers the component in a registry under a given root key. * *

If the component supports the optional * methods __writeRegistryServiceInfo, writeRegistryServiceInfo (DEPRECATED), * the call is delegated to that method. Otherwise a default registration * will be accomplished.

* * @param regKey the root key under that the component should be registered. * @param implementationLoaderUrl specifies the loader, the component is loaded by. * @param locationUrl points to an archive (JAR file) which contains a component. * @return true if registration is successfully - otherwise false. */ public boolean writeRegistryInfo( XRegistryKey regKey, String implementationLoaderUrl, String locationUrl ) throws CannotRegisterImplementationException, com.sun.star.uno.RuntimeException { locationUrl = expand_url( locationUrl ); boolean success = false; try { Class clazz = RegistrationClassFinder.find(locationUrl); if (null == clazz) throw new CannotRegisterImplementationException( "Cannot determine registration class!" ); Class[] paramTypes = { XRegistryKey.class }; Object[] params = { regKey }; Method method = clazz.getMethod("__writeRegistryServiceInfo", paramTypes); Object oRet = method.invoke(clazz, params); if ( (oRet != null) && (oRet instanceof Boolean) ) success = ((Boolean) oRet).booleanValue(); } catch (Exception e) { throw new CannotRegisterImplementationException(e, e.toString()); } return success; } /** * Supplies the factory for the JavaLoader. * * @param implName the name of the desired component. * @param multiFactory the ServiceManager is delivered to the factory. * @param regKey not used - can be null. * @return the factory for the JavaLoader. */ public static XSingleServiceFactory getServiceFactory( String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey) { if ( implName.equals(JavaLoader.class.getName()) ) return new JavaLoaderFactory( multiFactory ); return null; } /** * Registers the JavaLoader at the registry. * * @param regKey root key under which the JavaLoader should be registered. * @return true if registration succeeded - otherwise false. */ public static boolean writeRegistryServiceInfo(XRegistryKey regKey) { boolean result = false; try { XRegistryKey newKey = regKey.createKey("/" + JavaLoader.class.getName() + "/UNO/SERVICE"); for (String supportedService : supportedServices) { newKey.createKey(supportedService); } result = true; } catch (Exception ex) { if (DEBUG) System.err.println(">>>JavaLoader.writeRegistryServiceInfo " + ex); } return result; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */