1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: Loader.java,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 package com
.sun
.star
.lib
.loader
;
34 import java
.io
.IOException
;
35 import java
.io
.InputStream
;
36 import java
.io
.UnsupportedEncodingException
;
37 import java
.lang
.reflect
.InvocationTargetException
;
38 import java
.lang
.reflect
.Method
;
39 import java
.net
.JarURLConnection
;
40 import java
.net
.MalformedURLException
;
42 import java
.net
.URLClassLoader
;
43 import java
.util
.Enumeration
;
44 import java
.util
.jar
.Attributes
;
45 import java
.util
.jar
.Manifest
;
46 import java
.util
.StringTokenizer
;
47 import java
.util
.Vector
;
50 * This class can be used as a loader for application classes which use UNO.
52 * <p>The Loader class detects a UNO installation on the system and adds the
53 * UNO jar files to the search path of a customized class loader, which is used
54 * for loading the application classes.</p>
56 public final class Loader
{
58 private static ClassLoader m_Loader
= null;
66 * The main method instantiates a customized class loader with the
67 * UNO jar files added to the search path and loads the application class,
68 * which is specified in the Main-Class attribute of the
69 * com/sun/star/lib/Loader.class entry of the manifest file or
70 * as first parameter in the argument list.
72 public static void main( String
[] arguments
) throws Exception
{
74 // get the name of the class to be loaded from the manifest
75 String className
= null;
76 Class clazz
= Loader
.class;
77 ClassLoader loader
= clazz
.getClassLoader();
78 Vector res
= new Vector();
80 Enumeration en
= loader
.getResources( "META-INF/MANIFEST.MF" );
81 while ( en
.hasMoreElements() ) {
82 res
.add( (URL
) en
.nextElement() );
84 // the jarfile with the com/sun/star/lib/loader/Loader.class
85 // per-entry attribute is most probably the last resource in the
86 // list, therefore search backwards
87 for ( int i
= res
.size() - 1; i
>= 0; i
-- ) {
88 URL jarurl
= (URL
) res
.elementAt( i
);
90 JarURLConnection jarConnection
=
91 (JarURLConnection
) jarurl
.openConnection();
92 Manifest mf
= jarConnection
.getManifest();
93 Attributes attrs
= (Attributes
) mf
.getAttributes(
94 "com/sun/star/lib/loader/Loader.class" );
95 if ( attrs
!= null ) {
96 className
= attrs
.getValue( "Application-Class" );
97 if ( className
!= null )
100 } catch ( IOException e
) {
101 // if an I/O error occurs when opening a new
102 // JarURLConnection, ignore this manifest file
103 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
104 "main: bad manifest file: " + e
);
107 } catch ( IOException e
) {
108 // if an I/O error occurs when getting the manifest resources,
109 // try to get the name of the class to be loaded from the argument
111 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
112 "main: cannot get manifest resources: " + e
);
115 // if no manifest entry was found, get the name of the class
116 // to be loaded from the argument list
118 if ( className
== null ) {
119 if ( arguments
.length
> 0 ) {
120 className
= arguments
[0];
121 args
= new String
[arguments
.length
- 1];
122 System
.arraycopy( arguments
, 1, args
, 0, args
.length
);
124 throw new IllegalArgumentException(
125 "The name of the class to be loaded must be either " +
126 "specified in the Main-Class attribute of the " +
127 "com/sun/star/lib/loader/Loader.class entry " +
128 "of the manifest file or as a command line argument." );
134 // load the class with the customized class loader and
135 // invoke the main method
136 if ( className
!= null ) {
137 ClassLoader cl
= getCustomLoader();
138 Thread
.currentThread().setContextClassLoader(cl
);
139 Class c
= cl
.loadClass( className
);
140 Method m
= c
.getMethod( "main", new Class
[] { String
[].class } );
141 m
.invoke( null, new Object
[] { args
} );
146 * Gets the customized class loader with the UNO jar files added to the
149 * @return the customized class loader
151 public static synchronized ClassLoader
getCustomLoader() {
153 final String CLASSESDIR
= "classes";
154 final String JUHJAR
= "juh.jar";
156 if ( m_Loader
== null ) {
158 // get the urls from which to load classes and resources
159 // from the class path
160 Vector vec
= new Vector();
161 String classpath
= null;
163 classpath
= System
.getProperty( "java.class.path" );
164 } catch ( SecurityException e
) {
165 // don't add the class path entries to the list of class
167 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
168 "getCustomLoader: cannot get system property " +
169 "java.class.path: " + e
);
171 if ( classpath
!= null ) {
172 addUrls(vec
, classpath
, File
.pathSeparator
);
175 // get the urls from which to load classes and resources
176 // from the UNO installation
177 String path
= InstallationFinder
.getPath();
178 if ( path
!= null ) {
179 File fClassesDir
= new File( path
, CLASSESDIR
);
180 File fJuh
= new File( fClassesDir
, JUHJAR
);
181 if ( fJuh
.exists() ) {
182 URL
[] clurls
= new URL
[1];
184 clurls
[0] = fJuh
.toURL();
185 ClassLoader cl
= new CustomURLClassLoader( clurls
);
186 Class c
= cl
.loadClass(
187 "com.sun.star.comp.helper.UnoInfo" );
188 Method m
= c
.getMethod( "getJars", (Class
[]) null );
189 URL
[] jarurls
= (URL
[]) m
.invoke(
190 null, (Object
[]) null );
191 for ( int i
= 0; i
< jarurls
.length
; i
++ ) {
192 vec
.add( jarurls
[i
] );
194 } catch ( MalformedURLException e
) {
195 // don't add the UNO jar files to the list of class
197 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
198 "getCustomLoader: cannot add UNO jar files: " + e
);
199 } catch ( ClassNotFoundException e
) {
200 // don't add the UNO jar files to the list of class
202 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
203 "getCustomLoader: cannot add UNO jar files: " + e
);
204 } catch ( NoSuchMethodException e
) {
205 // don't add the UNO jar files to the list of class
207 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
208 "getCustomLoader: cannot add UNO jar files: " + e
);
209 } catch ( IllegalAccessException e
) {
210 // don't add the UNO jar files to the list of class
212 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
213 "getCustomLoader: cannot add UNO jar files: " + e
);
214 } catch ( InvocationTargetException e
) {
215 // don't add the UNO jar files to the list of class
217 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
218 "getCustomLoader: cannot add UNO jar files: " + e
);
221 callUnoinfo(path
, vec
);
224 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
225 "getCustomLoader: no UNO installation found!" );
228 // copy urls to array
229 URL
[] urls
= new URL
[vec
.size()];
232 // instantiate class loader
233 m_Loader
= new CustomURLClassLoader( urls
);
239 private static void addUrls(Vector urls
, String data
, String delimiter
) {
240 StringTokenizer tokens
= new StringTokenizer( data
, delimiter
);
241 while ( tokens
.hasMoreTokens() ) {
243 urls
.add( new File( tokens
.nextToken() ).toURL() );
244 } catch ( MalformedURLException e
) {
245 // don't add this class path entry to the list of class loader
247 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
248 "getCustomLoader: bad pathname: " + e
);
253 private static void callUnoinfo(String path
, Vector urls
) {
256 p
= Runtime
.getRuntime().exec(
257 new String
[] { new File(path
, "unoinfo").getPath(), "java" });
258 } catch (IOException e
) {
260 "com.sun.star.lib.loader.Loader::getCustomLoader: exec" +
264 new Drain(p
.getErrorStream()).start();
266 byte[] buf
= new byte[1000];
269 InputStream s
= p
.getInputStream();
272 if (n
== buf
.length
) {
273 if (n
> Integer
.MAX_VALUE
/ 2) {
275 "com.sun.star.lib.loader.Loader::getCustomLoader:" +
276 " too much unoinfo output");
279 byte[] buf2
= new byte[2 * n
];
280 for (int i
= 0; i
< n
; ++i
) {
285 int k
= s
.read(buf
, n
, buf
.length
- n
);
291 } catch (IOException e
) {
293 "com.sun.star.lib.loader.Loader::getCustomLoader: reading" +
294 " unoinfo output: " + e
);
300 } catch (InterruptedException e
) {
301 Thread
.currentThread().interrupt();
303 "com.sun.star.lib.loader.Loader::getCustomLoader: waiting for" +
309 "com.sun.star.lib.loader.Loader::getCustomLoader: unoinfo"
310 + " exit value " + n
);
316 } else if (code
== '1') {
318 s
= new String(buf
, "UTF-16LE");
319 } catch (UnsupportedEncodingException e
) {
321 "com.sun.star.lib.loader.Loader::getCustomLoader:" +
322 " transforming unoinfo output: " + e
);
327 "com.sun.star.lib.loader.Loader::getCustomLoader: bad unoinfo"
331 addUrls(urls
, s
, "\0");
334 private static final class Drain
extends Thread
{
335 public Drain(InputStream stream
) {
336 super("unoinfo stderr drain");
337 this.stream
= stream
;
342 while (stream
.read() != -1) {}
343 } catch (IOException e
) { /* ignored */ }
346 private final InputStream stream
;
350 * A customized class loader which is used to load classes and resources
351 * from a search path of user-defined URLs.
353 private static final class CustomURLClassLoader
extends URLClassLoader
{
355 public CustomURLClassLoader( URL
[] urls
) {
359 protected Class
findClass( String name
) throws ClassNotFoundException
{
360 // This is only called via this.loadClass -> super.loadClass ->
361 // this.findClass, after this.loadClass has already called
362 // super.findClass, so no need to call super.findClass again:
363 throw new ClassNotFoundException( name
);
366 protected Class
loadClass( String name
, boolean resolve
)
367 throws ClassNotFoundException
369 Class c
= findLoadedClass( name
);
372 c
= super.findClass( name
);
373 } catch ( ClassNotFoundException e
) {
374 return super.loadClass( name
, resolve
);
375 } catch ( SecurityException e
) {
376 // A SecurityException "Prohibited package name: java.lang"
377 // may occur when the user added the JVM's rt.jar to the
379 return super.loadClass( name
, resolve
);