Update ooo320-m1
[ooovba.git] / odk / source / com / sun / star / lib / loader / Loader.java
blob348bdb65cbd4a3bf9c489409692e84b69269209f
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: Loader.java,v $
10 * $Revision: 1.6 $
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;
33 import java.io.File;
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;
41 import java.net.URL;
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;
49 /**
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;
60 /**
61 * do not instantiate
63 private Loader() {}
65 /**
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();
79 try {
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 );
89 try {
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 )
98 break;
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
110 // list
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
117 String[] args;
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 );
123 } else {
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." );
130 } else {
131 args = arguments;
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
147 * search path.
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;
162 try {
163 classpath = System.getProperty( "java.class.path" );
164 } catch ( SecurityException e ) {
165 // don't add the class path entries to the list of class
166 // loader URLs
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];
183 try {
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
196 // loader URLs
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
201 // loader URLs
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
206 // loader URLs
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
211 // loader URLs
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
216 // loader URLs
217 System.err.println( "com.sun.star.lib.loader.Loader::" +
218 "getCustomLoader: cannot add UNO jar files: " + e );
220 } else {
221 callUnoinfo(path, vec);
223 } else {
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()];
230 vec.toArray( urls );
232 // instantiate class loader
233 m_Loader = new CustomURLClassLoader( urls );
236 return m_Loader;
239 private static void addUrls(Vector urls, String data, String delimiter) {
240 StringTokenizer tokens = new StringTokenizer( data, delimiter );
241 while ( tokens.hasMoreTokens() ) {
242 try {
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
246 // URLs
247 System.err.println( "com.sun.star.lib.loader.Loader::" +
248 "getCustomLoader: bad pathname: " + e );
253 private static void callUnoinfo(String path, Vector urls) {
254 Process p;
255 try {
256 p = Runtime.getRuntime().exec(
257 new String[] { new File(path, "unoinfo").getPath(), "java" });
258 } catch (IOException e) {
259 System.err.println(
260 "com.sun.star.lib.loader.Loader::getCustomLoader: exec" +
261 " unoinfo: " + e);
262 return;
264 new Drain(p.getErrorStream()).start();
265 int code;
266 byte[] buf = new byte[1000];
267 int n = 0;
268 try {
269 InputStream s = p.getInputStream();
270 code = s.read();
271 for (;;) {
272 if (n == buf.length) {
273 if (n > Integer.MAX_VALUE / 2) {
274 System.err.println(
275 "com.sun.star.lib.loader.Loader::getCustomLoader:" +
276 " too much unoinfo output");
277 return;
279 byte[] buf2 = new byte[2 * n];
280 for (int i = 0; i < n; ++i) {
281 buf2[i] = buf[i];
283 buf = buf2;
285 int k = s.read(buf, n, buf.length - n);
286 if (k == -1) {
287 break;
289 n += k;
291 } catch (IOException e) {
292 System.err.println(
293 "com.sun.star.lib.loader.Loader::getCustomLoader: reading" +
294 " unoinfo output: " + e);
295 return;
297 int ev;
298 try {
299 ev = p.waitFor();
300 } catch (InterruptedException e) {
301 Thread.currentThread().interrupt();
302 System.err.println(
303 "com.sun.star.lib.loader.Loader::getCustomLoader: waiting for" +
304 " unoinfo: " + e);
305 return;
307 if (ev != 0) {
308 System.err.println(
309 "com.sun.star.lib.loader.Loader::getCustomLoader: unoinfo"
310 + " exit value " + n);
311 return;
313 String s;
314 if (code == '0') {
315 s = new String(buf);
316 } else if (code == '1') {
317 try {
318 s = new String(buf, "UTF-16LE");
319 } catch (UnsupportedEncodingException e) {
320 System.err.println(
321 "com.sun.star.lib.loader.Loader::getCustomLoader:" +
322 " transforming unoinfo output: " + e);
323 return;
325 } else {
326 System.err.println(
327 "com.sun.star.lib.loader.Loader::getCustomLoader: bad unoinfo"
328 + " output");
329 return;
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;
340 public void run() {
341 try {
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 ) {
356 super( 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 );
370 if ( c == null ) {
371 try {
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
378 // java.class.path:
379 return super.loadClass( name, resolve );
382 if ( resolve ) {
383 resolveClass( c );
385 return c;