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