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 Class c
= cl
.loadClass( className
);
139 Method m
= c
.getMethod( "main", new Class
[] { String
[].class } );
140 m
.invoke( null, new Object
[] { args
} );
145 * Gets the customized class loader with the UNO jar files added to the
148 * @return the customized class loader
150 public static synchronized ClassLoader
getCustomLoader() {
152 final String CLASSESDIR
= "classes";
153 final String JUHJAR
= "juh.jar";
155 if ( m_Loader
== null ) {
157 // get the urls from which to load classes and resources
158 // from the class path
159 Vector vec
= new Vector();
160 String classpath
= null;
162 classpath
= System
.getProperty( "java.class.path" );
163 } catch ( SecurityException e
) {
164 // don't add the class path entries to the list of class
166 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
167 "getCustomLoader: cannot get system property " +
168 "java.class.path: " + e
);
170 if ( classpath
!= null ) {
171 addUrls(vec
, classpath
, File
.pathSeparator
);
174 // get the urls from which to load classes and resources
175 // from the UNO installation
176 String path
= InstallationFinder
.getPath();
177 if ( path
!= null ) {
178 File fClassesDir
= new File( path
, CLASSESDIR
);
179 File fJuh
= new File( fClassesDir
, JUHJAR
);
180 if ( fJuh
.exists() ) {
181 URL
[] clurls
= new URL
[1];
183 clurls
[0] = fJuh
.toURL();
184 ClassLoader cl
= new CustomURLClassLoader( clurls
);
185 Class c
= cl
.loadClass(
186 "com.sun.star.comp.helper.UnoInfo" );
187 Method m
= c
.getMethod( "getJars", (Class
[]) null );
188 URL
[] jarurls
= (URL
[]) m
.invoke(
189 null, (Object
[]) null );
190 for ( int i
= 0; i
< jarurls
.length
; i
++ ) {
191 vec
.add( jarurls
[i
] );
193 } catch ( MalformedURLException e
) {
194 // don't add the UNO jar files to the list of class
196 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
197 "getCustomLoader: cannot add UNO jar files: " + e
);
198 } catch ( ClassNotFoundException e
) {
199 // don't add the UNO jar files to the list of class
201 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
202 "getCustomLoader: cannot add UNO jar files: " + e
);
203 } catch ( NoSuchMethodException e
) {
204 // don't add the UNO jar files to the list of class
206 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
207 "getCustomLoader: cannot add UNO jar files: " + e
);
208 } catch ( IllegalAccessException e
) {
209 // don't add the UNO jar files to the list of class
211 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
212 "getCustomLoader: cannot add UNO jar files: " + e
);
213 } catch ( InvocationTargetException e
) {
214 // don't add the UNO jar files to the list of class
216 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
217 "getCustomLoader: cannot add UNO jar files: " + e
);
220 callUnoinfo(path
, vec
);
223 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
224 "getCustomLoader: no UNO installation found!" );
227 // copy urls to array
228 URL
[] urls
= new URL
[vec
.size()];
231 // instantiate class loader
232 m_Loader
= new CustomURLClassLoader( urls
);
238 private static void addUrls(Vector urls
, String data
, String delimiter
) {
239 StringTokenizer tokens
= new StringTokenizer( data
, delimiter
);
240 while ( tokens
.hasMoreTokens() ) {
242 urls
.add( new File( tokens
.nextToken() ).toURL() );
243 } catch ( MalformedURLException e
) {
244 // don't add this class path entry to the list of class loader
246 System
.err
.println( "com.sun.star.lib.loader.Loader::" +
247 "getCustomLoader: bad pathname: " + e
);
252 private static void callUnoinfo(String path
, Vector urls
) {
255 p
= Runtime
.getRuntime().exec(
256 new String
[] { new File(path
, "unoinfo").getPath(), "java" });
257 } catch (IOException e
) {
259 "com.sun.star.lib.loader.Loader::getCustomLoader: exec" +
263 new Drain(p
.getErrorStream()).start();
265 byte[] buf
= new byte[1000];
268 InputStream s
= p
.getInputStream();
271 if (n
== buf
.length
) {
272 if (n
> Integer
.MAX_VALUE
/ 2) {
274 "com.sun.star.lib.loader.Loader::getCustomLoader:" +
275 " too much unoinfo output");
278 byte[] buf2
= new byte[2 * n
];
279 for (int i
= 0; i
< n
; ++i
) {
284 int k
= s
.read(buf
, n
, buf
.length
- n
);
290 } catch (IOException e
) {
292 "com.sun.star.lib.loader.Loader::getCustomLoader: reading" +
293 " unoinfo output: " + e
);
299 } catch (InterruptedException e
) {
300 Thread
.currentThread().interrupt();
302 "com.sun.star.lib.loader.Loader::getCustomLoader: waiting for" +
308 "com.sun.star.lib.loader.Loader::getCustomLoader: unoinfo"
309 + " exit value " + n
);
315 } else if (code
== '1') {
317 s
= new String(buf
, "UTF-16LE");
318 } catch (UnsupportedEncodingException e
) {
320 "com.sun.star.lib.loader.Loader::getCustomLoader:" +
321 " transforming unoinfo output: " + e
);
326 "com.sun.star.lib.loader.Loader::getCustomLoader: bad unoinfo"
330 addUrls(urls
, s
, "\0");
333 private static final class Drain
extends Thread
{
334 public Drain(InputStream stream
) {
335 super("unoinfo stderr drain");
336 this.stream
= stream
;
341 while (stream
.read() != -1) {}
342 } catch (IOException e
) { /* ignored */ }
345 private final InputStream stream
;
349 * A customized class loader which is used to load classes and resources
350 * from a search path of user-defined URLs.
352 private static final class CustomURLClassLoader
extends URLClassLoader
{
354 public CustomURLClassLoader( URL
[] urls
) {
358 protected Class
findClass( String name
) throws ClassNotFoundException
{
359 // This is only called via this.loadClass -> super.loadClass ->
360 // this.findClass, after this.loadClass has already called
361 // super.findClass, so no need to call super.findClass again:
362 throw new ClassNotFoundException( name
);
365 protected Class
loadClass( String name
, boolean resolve
)
366 throws ClassNotFoundException
368 Class c
= findLoadedClass( name
);
371 c
= super.findClass( name
);
372 } catch ( ClassNotFoundException e
) {
373 return super.loadClass( name
, resolve
);
374 } catch ( SecurityException e
) {
375 // A SecurityException "Prohibited package name: java.lang"
376 // may occur when the user added the JVM's rt.jar to the
378 return super.loadClass( name
, resolve
);