1*ae15d43aSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*ae15d43aSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*ae15d43aSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*ae15d43aSAndrew Rist * distributed with this work for additional information 6*ae15d43aSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*ae15d43aSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*ae15d43aSAndrew Rist * "License"); you may not use this file except in compliance 9*ae15d43aSAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*ae15d43aSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*ae15d43aSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*ae15d43aSAndrew Rist * software distributed under the License is distributed on an 15*ae15d43aSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*ae15d43aSAndrew Rist * KIND, either express or implied. See the License for the 17*ae15d43aSAndrew Rist * specific language governing permissions and limitations 18*ae15d43aSAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*ae15d43aSAndrew Rist *************************************************************/ 21*ae15d43aSAndrew Rist 22*ae15d43aSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir package com.sun.star.lib.loader; 25cdf0e10cSrcweir 26cdf0e10cSrcweir import java.io.File; 27cdf0e10cSrcweir import java.io.IOException; 28cdf0e10cSrcweir import java.io.InputStream; 29cdf0e10cSrcweir import java.io.UnsupportedEncodingException; 30cdf0e10cSrcweir import java.lang.reflect.InvocationTargetException; 31cdf0e10cSrcweir import java.lang.reflect.Method; 32cdf0e10cSrcweir import java.net.JarURLConnection; 33cdf0e10cSrcweir import java.net.MalformedURLException; 34cdf0e10cSrcweir import java.net.URL; 35cdf0e10cSrcweir import java.net.URLClassLoader; 36cdf0e10cSrcweir import java.util.Enumeration; 37cdf0e10cSrcweir import java.util.jar.Attributes; 38cdf0e10cSrcweir import java.util.jar.Manifest; 39cdf0e10cSrcweir import java.util.StringTokenizer; 40cdf0e10cSrcweir import java.util.Vector; 41cdf0e10cSrcweir 42cdf0e10cSrcweir /** 43cdf0e10cSrcweir * This class can be used as a loader for application classes which use UNO. 44cdf0e10cSrcweir * 45cdf0e10cSrcweir * <p>The Loader class detects a UNO installation on the system and adds the 46cdf0e10cSrcweir * UNO jar files to the search path of a customized class loader, which is used 47cdf0e10cSrcweir * for loading the application classes.</p> 48cdf0e10cSrcweir */ 49cdf0e10cSrcweir public final class Loader { 50cdf0e10cSrcweir 51cdf0e10cSrcweir private static ClassLoader m_Loader = null; 52cdf0e10cSrcweir 53cdf0e10cSrcweir /** 54cdf0e10cSrcweir * do not instantiate 55cdf0e10cSrcweir */ Loader()56cdf0e10cSrcweir private Loader() {} 57cdf0e10cSrcweir 58cdf0e10cSrcweir /** 59cdf0e10cSrcweir * The main method instantiates a customized class loader with the 60cdf0e10cSrcweir * UNO jar files added to the search path and loads the application class, 61cdf0e10cSrcweir * which is specified in the Main-Class attribute of the 62cdf0e10cSrcweir * com/sun/star/lib/Loader.class entry of the manifest file or 63cdf0e10cSrcweir * as first parameter in the argument list. 64cdf0e10cSrcweir */ main( String[] arguments )65cdf0e10cSrcweir public static void main( String[] arguments ) throws Exception { 66cdf0e10cSrcweir 67cdf0e10cSrcweir // get the name of the class to be loaded from the manifest 68cdf0e10cSrcweir String className = null; 69cdf0e10cSrcweir Class clazz = Loader.class; 70cdf0e10cSrcweir ClassLoader loader = clazz.getClassLoader(); 71cdf0e10cSrcweir Vector res = new Vector(); 72cdf0e10cSrcweir try { 73cdf0e10cSrcweir Enumeration en = loader.getResources( "META-INF/MANIFEST.MF" ); 74cdf0e10cSrcweir while ( en.hasMoreElements() ) { 75cdf0e10cSrcweir res.add( (URL) en.nextElement() ); 76cdf0e10cSrcweir } 77cdf0e10cSrcweir // the jarfile with the com/sun/star/lib/loader/Loader.class 78cdf0e10cSrcweir // per-entry attribute is most probably the last resource in the 79cdf0e10cSrcweir // list, therefore search backwards 80cdf0e10cSrcweir for ( int i = res.size() - 1; i >= 0; i-- ) { 81cdf0e10cSrcweir URL jarurl = (URL) res.elementAt( i ); 82cdf0e10cSrcweir try { 83cdf0e10cSrcweir JarURLConnection jarConnection = 84cdf0e10cSrcweir (JarURLConnection) jarurl.openConnection(); 85cdf0e10cSrcweir Manifest mf = jarConnection.getManifest(); 86cdf0e10cSrcweir Attributes attrs = (Attributes) mf.getAttributes( 87cdf0e10cSrcweir "com/sun/star/lib/loader/Loader.class" ); 88cdf0e10cSrcweir if ( attrs != null ) { 89cdf0e10cSrcweir className = attrs.getValue( "Application-Class" ); 90cdf0e10cSrcweir if ( className != null ) 91cdf0e10cSrcweir break; 92cdf0e10cSrcweir } 93cdf0e10cSrcweir } catch ( IOException e ) { 94cdf0e10cSrcweir // if an I/O error occurs when opening a new 95cdf0e10cSrcweir // JarURLConnection, ignore this manifest file 96cdf0e10cSrcweir System.err.println( "com.sun.star.lib.loader.Loader::" + 97cdf0e10cSrcweir "main: bad manifest file: " + e ); 98cdf0e10cSrcweir } 99cdf0e10cSrcweir } 100cdf0e10cSrcweir } catch ( IOException e ) { 101cdf0e10cSrcweir // if an I/O error occurs when getting the manifest resources, 102cdf0e10cSrcweir // try to get the name of the class to be loaded from the argument 103cdf0e10cSrcweir // list 104cdf0e10cSrcweir System.err.println( "com.sun.star.lib.loader.Loader::" + 105cdf0e10cSrcweir "main: cannot get manifest resources: " + e ); 106cdf0e10cSrcweir } 107cdf0e10cSrcweir 108cdf0e10cSrcweir // if no manifest entry was found, get the name of the class 109cdf0e10cSrcweir // to be loaded from the argument list 110cdf0e10cSrcweir String[] args; 111cdf0e10cSrcweir if ( className == null ) { 112cdf0e10cSrcweir if ( arguments.length > 0 ) { 113cdf0e10cSrcweir className = arguments[0]; 114cdf0e10cSrcweir args = new String[arguments.length - 1]; 115cdf0e10cSrcweir System.arraycopy( arguments, 1, args, 0, args.length ); 116cdf0e10cSrcweir } else { 117cdf0e10cSrcweir throw new IllegalArgumentException( 118cdf0e10cSrcweir "The name of the class to be loaded must be either " + 119cdf0e10cSrcweir "specified in the Main-Class attribute of the " + 120cdf0e10cSrcweir "com/sun/star/lib/loader/Loader.class entry " + 121cdf0e10cSrcweir "of the manifest file or as a command line argument." ); 122cdf0e10cSrcweir } 123cdf0e10cSrcweir } else { 124cdf0e10cSrcweir args = arguments; 125cdf0e10cSrcweir } 126cdf0e10cSrcweir 127cdf0e10cSrcweir // load the class with the customized class loader and 128cdf0e10cSrcweir // invoke the main method 129cdf0e10cSrcweir if ( className != null ) { 130cdf0e10cSrcweir ClassLoader cl = getCustomLoader(); 131cdf0e10cSrcweir Thread.currentThread().setContextClassLoader(cl); 132cdf0e10cSrcweir Class c = cl.loadClass( className ); 133cdf0e10cSrcweir Method m = c.getMethod( "main", new Class[] { String[].class } ); 134cdf0e10cSrcweir m.invoke( null, new Object[] { args } ); 135cdf0e10cSrcweir } 136cdf0e10cSrcweir } 137cdf0e10cSrcweir 138cdf0e10cSrcweir /** 139cdf0e10cSrcweir * Gets the customized class loader with the UNO jar files added to the 140cdf0e10cSrcweir * search path. 141cdf0e10cSrcweir * 142cdf0e10cSrcweir * @return the customized class loader 143cdf0e10cSrcweir */ getCustomLoader()144cdf0e10cSrcweir public static synchronized ClassLoader getCustomLoader() { 145cdf0e10cSrcweir 146cdf0e10cSrcweir final String CLASSESDIR = "classes"; 147cdf0e10cSrcweir final String JUHJAR = "juh.jar"; 148cdf0e10cSrcweir 149cdf0e10cSrcweir if ( m_Loader == null ) { 150cdf0e10cSrcweir 151cdf0e10cSrcweir // get the urls from which to load classes and resources 152cdf0e10cSrcweir // from the class path 153cdf0e10cSrcweir Vector vec = new Vector(); 154cdf0e10cSrcweir String classpath = null; 155cdf0e10cSrcweir try { 156cdf0e10cSrcweir classpath = System.getProperty( "java.class.path" ); 157cdf0e10cSrcweir } catch ( SecurityException e ) { 158cdf0e10cSrcweir // don't add the class path entries to the list of class 159cdf0e10cSrcweir // loader URLs 160cdf0e10cSrcweir System.err.println( "com.sun.star.lib.loader.Loader::" + 161cdf0e10cSrcweir "getCustomLoader: cannot get system property " + 162cdf0e10cSrcweir "java.class.path: " + e ); 163cdf0e10cSrcweir } 164cdf0e10cSrcweir if ( classpath != null ) { 165cdf0e10cSrcweir addUrls(vec, classpath, File.pathSeparator); 166cdf0e10cSrcweir } 167cdf0e10cSrcweir 168cdf0e10cSrcweir // get the urls from which to load classes and resources 169cdf0e10cSrcweir // from the UNO installation 170cdf0e10cSrcweir String path = InstallationFinder.getPath(); 171cdf0e10cSrcweir if ( path != null ) { 172cdf0e10cSrcweir File fClassesDir = new File( path, CLASSESDIR ); 173cdf0e10cSrcweir File fJuh = new File( fClassesDir, JUHJAR ); 174cdf0e10cSrcweir if ( fJuh.exists() ) { 175cdf0e10cSrcweir URL[] clurls = new URL[1]; 176cdf0e10cSrcweir try { 177cdf0e10cSrcweir clurls[0] = fJuh.toURL(); 178cdf0e10cSrcweir ClassLoader cl = new CustomURLClassLoader( clurls ); 179cdf0e10cSrcweir Class c = cl.loadClass( 180cdf0e10cSrcweir "com.sun.star.comp.helper.UnoInfo" ); 181cdf0e10cSrcweir Method m = c.getMethod( "getJars", (Class[]) null ); 182cdf0e10cSrcweir URL[] jarurls = (URL[]) m.invoke( 183cdf0e10cSrcweir null, (Object[]) null ); 184cdf0e10cSrcweir for ( int i = 0; i < jarurls.length; i++ ) { 185cdf0e10cSrcweir vec.add( jarurls[i] ); 186cdf0e10cSrcweir } 187cdf0e10cSrcweir } catch ( MalformedURLException e ) { 188cdf0e10cSrcweir // don't add the UNO jar files to the list of class 189cdf0e10cSrcweir // loader URLs 190cdf0e10cSrcweir System.err.println( "com.sun.star.lib.loader.Loader::" + 191cdf0e10cSrcweir "getCustomLoader: cannot add UNO jar files: " + e ); 192cdf0e10cSrcweir } catch ( ClassNotFoundException e ) { 193cdf0e10cSrcweir // don't add the UNO jar files to the list of class 194cdf0e10cSrcweir // loader URLs 195cdf0e10cSrcweir System.err.println( "com.sun.star.lib.loader.Loader::" + 196cdf0e10cSrcweir "getCustomLoader: cannot add UNO jar files: " + e ); 197cdf0e10cSrcweir } catch ( NoSuchMethodException e ) { 198cdf0e10cSrcweir // don't add the UNO jar files to the list of class 199cdf0e10cSrcweir // loader URLs 200cdf0e10cSrcweir System.err.println( "com.sun.star.lib.loader.Loader::" + 201cdf0e10cSrcweir "getCustomLoader: cannot add UNO jar files: " + e ); 202cdf0e10cSrcweir } catch ( IllegalAccessException e ) { 203cdf0e10cSrcweir // don't add the UNO jar files to the list of class 204cdf0e10cSrcweir // loader URLs 205cdf0e10cSrcweir System.err.println( "com.sun.star.lib.loader.Loader::" + 206cdf0e10cSrcweir "getCustomLoader: cannot add UNO jar files: " + e ); 207cdf0e10cSrcweir } catch ( InvocationTargetException e ) { 208cdf0e10cSrcweir // don't add the UNO jar files to the list of class 209cdf0e10cSrcweir // loader URLs 210cdf0e10cSrcweir System.err.println( "com.sun.star.lib.loader.Loader::" + 211cdf0e10cSrcweir "getCustomLoader: cannot add UNO jar files: " + e ); 212cdf0e10cSrcweir } 213cdf0e10cSrcweir } else { 214cdf0e10cSrcweir callUnoinfo(path, vec); 215cdf0e10cSrcweir } 216cdf0e10cSrcweir } else { 217cdf0e10cSrcweir System.err.println( "com.sun.star.lib.loader.Loader::" + 218cdf0e10cSrcweir "getCustomLoader: no UNO installation found!" ); 219cdf0e10cSrcweir } 220cdf0e10cSrcweir 221cdf0e10cSrcweir // copy urls to array 222cdf0e10cSrcweir URL[] urls = new URL[vec.size()]; 223cdf0e10cSrcweir vec.toArray( urls ); 224cdf0e10cSrcweir 225cdf0e10cSrcweir // instantiate class loader 226cdf0e10cSrcweir m_Loader = new CustomURLClassLoader( urls ); 227cdf0e10cSrcweir } 228cdf0e10cSrcweir 229cdf0e10cSrcweir return m_Loader; 230cdf0e10cSrcweir } 231cdf0e10cSrcweir addUrls(Vector urls, String data, String delimiter)232cdf0e10cSrcweir private static void addUrls(Vector urls, String data, String delimiter) { 233cdf0e10cSrcweir StringTokenizer tokens = new StringTokenizer( data, delimiter ); 234cdf0e10cSrcweir while ( tokens.hasMoreTokens() ) { 235cdf0e10cSrcweir try { 236cdf0e10cSrcweir urls.add( new File( tokens.nextToken() ).toURL() ); 237cdf0e10cSrcweir } catch ( MalformedURLException e ) { 238cdf0e10cSrcweir // don't add this class path entry to the list of class loader 239cdf0e10cSrcweir // URLs 240cdf0e10cSrcweir System.err.println( "com.sun.star.lib.loader.Loader::" + 241cdf0e10cSrcweir "getCustomLoader: bad pathname: " + e ); 242cdf0e10cSrcweir } 243cdf0e10cSrcweir } 244cdf0e10cSrcweir } 245cdf0e10cSrcweir callUnoinfo(String path, Vector urls)246cdf0e10cSrcweir private static void callUnoinfo(String path, Vector urls) { 247cdf0e10cSrcweir Process p; 248cdf0e10cSrcweir try { 249cdf0e10cSrcweir p = Runtime.getRuntime().exec( 250cdf0e10cSrcweir new String[] { new File(path, "unoinfo").getPath(), "java" }); 251cdf0e10cSrcweir } catch (IOException e) { 252cdf0e10cSrcweir System.err.println( 253cdf0e10cSrcweir "com.sun.star.lib.loader.Loader::getCustomLoader: exec" + 254cdf0e10cSrcweir " unoinfo: " + e); 255cdf0e10cSrcweir return; 256cdf0e10cSrcweir } 257cdf0e10cSrcweir new Drain(p.getErrorStream()).start(); 258cdf0e10cSrcweir int code; 259cdf0e10cSrcweir byte[] buf = new byte[1000]; 260cdf0e10cSrcweir int n = 0; 261cdf0e10cSrcweir try { 262cdf0e10cSrcweir InputStream s = p.getInputStream(); 263cdf0e10cSrcweir code = s.read(); 264cdf0e10cSrcweir for (;;) { 265cdf0e10cSrcweir if (n == buf.length) { 266cdf0e10cSrcweir if (n > Integer.MAX_VALUE / 2) { 267cdf0e10cSrcweir System.err.println( 268cdf0e10cSrcweir "com.sun.star.lib.loader.Loader::getCustomLoader:" + 269cdf0e10cSrcweir " too much unoinfo output"); 270cdf0e10cSrcweir return; 271cdf0e10cSrcweir } 272cdf0e10cSrcweir byte[] buf2 = new byte[2 * n]; 273cdf0e10cSrcweir for (int i = 0; i < n; ++i) { 274cdf0e10cSrcweir buf2[i] = buf[i]; 275cdf0e10cSrcweir } 276cdf0e10cSrcweir buf = buf2; 277cdf0e10cSrcweir } 278cdf0e10cSrcweir int k = s.read(buf, n, buf.length - n); 279cdf0e10cSrcweir if (k == -1) { 280cdf0e10cSrcweir break; 281cdf0e10cSrcweir } 282cdf0e10cSrcweir n += k; 283cdf0e10cSrcweir } 284cdf0e10cSrcweir } catch (IOException e) { 285cdf0e10cSrcweir System.err.println( 286cdf0e10cSrcweir "com.sun.star.lib.loader.Loader::getCustomLoader: reading" + 287cdf0e10cSrcweir " unoinfo output: " + e); 288cdf0e10cSrcweir return; 289cdf0e10cSrcweir } 290cdf0e10cSrcweir int ev; 291cdf0e10cSrcweir try { 292cdf0e10cSrcweir ev = p.waitFor(); 293cdf0e10cSrcweir } catch (InterruptedException e) { 294cdf0e10cSrcweir Thread.currentThread().interrupt(); 295cdf0e10cSrcweir System.err.println( 296cdf0e10cSrcweir "com.sun.star.lib.loader.Loader::getCustomLoader: waiting for" + 297cdf0e10cSrcweir " unoinfo: " + e); 298cdf0e10cSrcweir return; 299cdf0e10cSrcweir } 300cdf0e10cSrcweir if (ev != 0) { 301cdf0e10cSrcweir System.err.println( 302cdf0e10cSrcweir "com.sun.star.lib.loader.Loader::getCustomLoader: unoinfo" 303cdf0e10cSrcweir + " exit value " + n); 304cdf0e10cSrcweir return; 305cdf0e10cSrcweir } 306cdf0e10cSrcweir String s; 307cdf0e10cSrcweir if (code == '0') { 308cdf0e10cSrcweir s = new String(buf); 309cdf0e10cSrcweir } else if (code == '1') { 310cdf0e10cSrcweir try { 311cdf0e10cSrcweir s = new String(buf, "UTF-16LE"); 312cdf0e10cSrcweir } catch (UnsupportedEncodingException e) { 313cdf0e10cSrcweir System.err.println( 314cdf0e10cSrcweir "com.sun.star.lib.loader.Loader::getCustomLoader:" + 315cdf0e10cSrcweir " transforming unoinfo output: " + e); 316cdf0e10cSrcweir return; 317cdf0e10cSrcweir } 318cdf0e10cSrcweir } else { 319cdf0e10cSrcweir System.err.println( 320cdf0e10cSrcweir "com.sun.star.lib.loader.Loader::getCustomLoader: bad unoinfo" 321cdf0e10cSrcweir + " output"); 322cdf0e10cSrcweir return; 323cdf0e10cSrcweir } 324cdf0e10cSrcweir addUrls(urls, s, "\0"); 325cdf0e10cSrcweir } 326cdf0e10cSrcweir 327cdf0e10cSrcweir private static final class Drain extends Thread { Drain(InputStream stream)328cdf0e10cSrcweir public Drain(InputStream stream) { 329cdf0e10cSrcweir super("unoinfo stderr drain"); 330cdf0e10cSrcweir this.stream = stream; 331cdf0e10cSrcweir } 332cdf0e10cSrcweir run()333cdf0e10cSrcweir public void run() { 334cdf0e10cSrcweir try { 335cdf0e10cSrcweir while (stream.read() != -1) {} 336cdf0e10cSrcweir } catch (IOException e) { /* ignored */ } 337cdf0e10cSrcweir } 338cdf0e10cSrcweir 339cdf0e10cSrcweir private final InputStream stream; 340cdf0e10cSrcweir } 341cdf0e10cSrcweir 342cdf0e10cSrcweir /** 343cdf0e10cSrcweir * A customized class loader which is used to load classes and resources 344cdf0e10cSrcweir * from a search path of user-defined URLs. 345cdf0e10cSrcweir */ 346cdf0e10cSrcweir private static final class CustomURLClassLoader extends URLClassLoader { 347cdf0e10cSrcweir CustomURLClassLoader( URL[] urls )348cdf0e10cSrcweir public CustomURLClassLoader( URL[] urls ) { 349cdf0e10cSrcweir super( urls ); 350cdf0e10cSrcweir } 351cdf0e10cSrcweir findClass( String name )352cdf0e10cSrcweir protected Class findClass( String name ) throws ClassNotFoundException { 353cdf0e10cSrcweir // This is only called via this.loadClass -> super.loadClass -> 354cdf0e10cSrcweir // this.findClass, after this.loadClass has already called 355cdf0e10cSrcweir // super.findClass, so no need to call super.findClass again: 356cdf0e10cSrcweir throw new ClassNotFoundException( name ); 357cdf0e10cSrcweir } 358cdf0e10cSrcweir loadClass( String name, boolean resolve )359cdf0e10cSrcweir protected Class loadClass( String name, boolean resolve ) 360cdf0e10cSrcweir throws ClassNotFoundException 361cdf0e10cSrcweir { 362cdf0e10cSrcweir Class c = findLoadedClass( name ); 363cdf0e10cSrcweir if ( c == null ) { 364cdf0e10cSrcweir try { 365cdf0e10cSrcweir c = super.findClass( name ); 366cdf0e10cSrcweir } catch ( ClassNotFoundException e ) { 367cdf0e10cSrcweir return super.loadClass( name, resolve ); 368cdf0e10cSrcweir } catch ( SecurityException e ) { 369cdf0e10cSrcweir // A SecurityException "Prohibited package name: java.lang" 370cdf0e10cSrcweir // may occur when the user added the JVM's rt.jar to the 371cdf0e10cSrcweir // java.class.path: 372cdf0e10cSrcweir return super.loadClass( name, resolve ); 373cdf0e10cSrcweir } 374cdf0e10cSrcweir } 375cdf0e10cSrcweir if ( resolve ) { 376cdf0e10cSrcweir resolveClass( c ); 377cdf0e10cSrcweir } 378cdf0e10cSrcweir return c; 379cdf0e10cSrcweir } 380cdf0e10cSrcweir } 381cdf0e10cSrcweir } 382