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