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