Update ooo320-m1
[ooovba.git] / odk / source / com / sun / star / lib / loader / InstallationFinder.java
blobb72fa211973ae88287828317cd838196cc325df3
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: InstallationFinder.java,v $
10 * $Revision: 1.4 $
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.BufferedReader;
34 import java.io.File;
35 import java.io.FileInputStream;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.IOException;
39 import java.io.UnsupportedEncodingException;
40 import java.net.MalformedURLException;
41 import java.net.URL;
42 import java.util.StringTokenizer;
43 import java.util.Vector;
45 /**
46 * This class finds a UNO installation on the system.
48 * <p>A UNO installation can be specified by the user by either setting the
49 * com.sun.star.lib.loader.unopath system property or by setting the
50 * UNO_PATH environment variable to the program directory of a UNO
51 * installation.
52 * Note, that Java 1.3.1 and Java 1.4 don't support environment variables
53 * (System.getenv() throws java.lang.Error) and therefore setting the UNO_PATH
54 * enviroment variable won't work with those Java versions.
55 * If no UNO installation is specified by the user, the default installation
56 * on the system will be returned.</p>
58 * <p>On the Windows platform the default installation is read from the Windows
59 * Registry.</p>
61 * <p>On the Unix/Linux platforms the default installation is found from the
62 * PATH environment variable. Note, that for Java 1.3.1 and Java 1.4 the
63 * default installation is found by using the 'which' command, because
64 * environment variables are not supported with those Java versions.
65 * Both methods require that the 'soffice' executable or a symbolic
66 * link is in one of the directories listed in the PATH environment variable.
67 * For older versions than OOo 2.0 the above described methods may fail.
68 * In this case the default installation is taken from the .sversionrc file in
69 * the user's home directory. Note, that the .sversionrc file will be omitted
70 * for OOo 2.0</p>
72 final class InstallationFinder {
74 private static final String SYSPROP_NAME =
75 "com.sun.star.lib.loader.unopath";
76 private static final String ENVVAR_NAME = "UNO_PATH";
77 private static final String SOFFICE = "soffice"; // Unix/Linux only
79 private InstallationFinder() {} // do not instantiate
81 /**
82 * Gets the path of a UNO installation.
84 * @return the installation path or <code>null</code>, if no installation
85 * was specified or found, or if an error occured
86 */
87 public static String getPath() {
89 String path = null;
91 // get the installation path from the Java system property
92 // com.sun.star.lib.loader.unopath
93 // (all platforms)
94 path = getPathFromProperty( SYSPROP_NAME );
95 if ( path == null ) {
96 // get the installation path from the UNO_PATH environment variable
97 // (all platforms, not working for Java 1.3.1 and Java 1.4)
98 path = getPathFromEnvVar( ENVVAR_NAME );
99 if ( path == null ) {
100 String osname = null;
101 try {
102 osname = System.getProperty( "os.name" );
103 } catch ( SecurityException e ) {
104 // if a SecurityException was thrown,
105 // return <code>null</code>
106 return null;
108 if ( osname != null ) {
109 if ( osname.startsWith( "Windows" ) ) {
110 // get the installation path from the Windows Registry
111 // (Windows platform only)
112 path = getPathFromWindowsRegistry();
113 } else {
114 // get the installation path from the PATH environment
115 // variable (Unix/Linux platforms only, not working for
116 // Java 1.3.1 and Java 1.4)
117 path = getPathFromPathEnvVar();
118 if ( path == null ) {
119 // get the installation path from the 'which'
120 // command (Unix/Linux platforms only)
121 path = getPathFromWhich();
122 if ( path == null ) {
123 // get the installation path from the
124 // .sversionrc file (Unix/Linux platforms only,
125 // for older versions than OOo 2.0)
126 path = getPathFromSVersionFile();
134 return path;
138 * Gets the installation path from a Java system property.
140 * <p>This method is called on all platforms.
141 * The Java system property can be passed into the application by using
142 * the -D flag, e.g.
143 * java -D<property name>=<installation path> -jar application.jar.</p>
145 * @return the installation path or <code>null</code>, if no installation
146 * was specified in the Java system property or if an error occured
148 private static String getPathFromProperty( String prop ) {
150 String path = null;
152 try {
153 path = System.getProperty( prop );
154 } catch ( SecurityException e ) {
155 // if a SecurityException was thrown, return <code>null</code>
158 return path;
162 * Gets the installation path from an environment variable.
164 * <p>This method is called on all platforms.
165 * Note, that in Java 1.3.1 and Java 1.4 System.getenv() throws
166 * java.lang.Error and therefore this method returns null for those
167 * Java versions.</p>
169 * @return the installation path or <code>null</code>, if no installation
170 * was specified in the environment variable or if an error occured
172 private static String getPathFromEnvVar( String var ) {
174 String path = null;
176 try {
177 path = System.getenv( var );
178 } catch ( SecurityException e ) {
179 // if a SecurityException was thrown, return <code>null</code>
180 } catch ( java.lang.Error err ) {
181 // System.getenv() throws java.lang.Error in Java 1.3.1 and
182 // Java 1.4
185 return path;
189 * Gets the installation path from the Windows Registry.
191 * <p>This method is called on the Windows platform only.</p>
193 * @return the installation path or <code>null</code>, if no installation
194 * was found or if an error occured
196 private static String getPathFromWindowsRegistry() {
198 final String SUBKEYNAME = "Software\\OpenOffice.org\\UNO\\InstallPath";
200 String path = null;
202 try {
203 // read the key's default value from HKEY_CURRENT_USER
204 WinRegKey key = new WinRegKey( "HKEY_CURRENT_USER", SUBKEYNAME );
205 path = key.getStringValue( "" ); // default
206 } catch ( WinRegKeyException e ) {
207 try {
208 // read the key's default value from HKEY_LOCAL_MACHINE
209 WinRegKey key = new WinRegKey( "HKEY_LOCAL_MACHINE",
210 SUBKEYNAME );
211 path = key.getStringValue( "" ); // default
212 } catch ( WinRegKeyException we ) {
213 System.err.println( "com.sun.star.lib.loader." +
214 "InstallationFinder::getPathFromWindowsRegistry: " +
215 "reading key from Windows Registry failed: " + we );
219 return path;
223 * Gets the installation path from the PATH environment variable.
225 * <p>This method is called on Unix/Linux platforms only.
226 * An installation is found, if the executable 'soffice' or a symbolic link
227 * is in one of the directories listed in the PATH environment variable.
228 * Note, that in Java 1.3.1 and Java 1.4 System.getenv() throws
229 * java.lang.Error and therefore this method returns null for those
230 * Java versions.</p>
232 * @return the installation path or <code>null</code>, if no installation
233 * was found or if an error occured
235 private static String getPathFromPathEnvVar() {
237 final String PATH_ENVVAR_NAME = "PATH";
239 String path = null;
240 String str = null;
242 try {
243 str = System.getenv( PATH_ENVVAR_NAME );
244 } catch ( SecurityException e ) {
245 // if a SecurityException was thrown, return <code>null</code>
246 return null;
247 } catch ( java.lang.Error err ) {
248 // System.getenv() throws java.lang.Error in Java 1.3.1 and
249 // Java 1.4
250 return null;
253 if ( str != null ) {
254 StringTokenizer tokens = new StringTokenizer(
255 str, File.pathSeparator );
256 while ( tokens.hasMoreTokens() ) {
257 File file = new File( tokens.nextToken(), SOFFICE );
258 try {
259 if ( file.exists() ) {
260 try {
261 // resolve symlink
262 path = file.getCanonicalFile().getParent();
263 if ( path != null )
264 break;
265 } catch ( IOException e ) {
266 // if an I/O exception is thrown, ignore this
267 // path entry and try the next one
268 System.err.println( "com.sun.star.lib.loader." +
269 "InstallationFinder::getPathFromEnvVar: " +
270 "bad path: " + e );
273 } catch ( SecurityException e ) {
274 // if a SecurityException was thrown, ignore this path
275 // entry and try the next one
280 return path;
284 * Gets the installation path from the 'which' command on Unix/Linux
285 * platforms.
287 * <p>This method is called on Unix/Linux platforms only.
288 * An installation is found, if the executable 'soffice' or a symbolic link
289 * is in one of the directories listed in the PATH environment variable.</p>
291 * @return the installation path or <code>null</code>, if no installation
292 * was found or if an error occured
294 private static String getPathFromWhich() {
296 final String WHICH = "which";
298 String path = null;
300 // start the which process
301 String[] cmdArray = new String[2];
302 cmdArray[0] = WHICH;
303 cmdArray[1] = SOFFICE;
304 Process proc = null;
305 Runtime rt = Runtime.getRuntime();
306 try {
307 proc = rt.exec( cmdArray );
308 } catch ( SecurityException e ) {
309 return null;
310 } catch ( IOException e ) {
311 // if an I/O exception is thrown, return <code>null</null>
312 System.err.println( "com.sun.star.lib.loader." +
313 "InstallationFinder::getPathFromWhich: " +
314 "which command failed: " + e );
315 return null;
318 // empty standard error stream in a seperate thread
319 StreamGobbler gobbler = new StreamGobbler( proc.getErrorStream() );
320 gobbler.start();
322 // read the which output from standard input stream
323 BufferedReader br = new BufferedReader(
324 new InputStreamReader( proc.getInputStream() ) );
325 String line = null;
326 try {
327 while ( ( line = br.readLine() ) != null ) {
328 if ( path == null ) {
329 // get the path from the which output
330 int index = line.lastIndexOf( SOFFICE );
331 if ( index != -1 ) {
332 int end = index + SOFFICE.length();
333 for ( int i = 0; i <= index; i++ ) {
334 File file = new File( line.substring( i, end ) );
335 try {
336 if ( file.exists() ) {
337 // resolve symlink
338 path = file.getCanonicalFile().getParent();
339 if ( path != null )
340 break;
342 } catch ( SecurityException e ) {
343 return null;
349 } catch ( IOException e ) {
350 // if an I/O exception is thrown, return <code>null</null>
351 System.err.println( "com.sun.star.lib.loader." +
352 "InstallationFinder::getPathFromWhich: " +
353 "reading which command output failed: " + e );
354 return null;
355 } finally {
356 if ( br != null ) {
357 try {
358 br.close();
359 } catch ( IOException e ) {
360 // closing standard input stream failed, ignore
365 try {
366 // wait until the which process has terminated
367 proc.waitFor();
368 } catch ( InterruptedException e ) {
369 // the current thread was interrupted by another thread,
370 // kill the which process
371 proc.destroy();
372 // set the interrupted status
373 Thread.currentThread().interrupt();
376 return path;
380 * Gets the installation path from the .sverionrc file in the user's home
381 * directory.
383 * <p>This method is called on Unix/Linux platforms only.
384 * The .sversionrc file is written during setup and will be omitted for
385 * OOo 2.0.</p>
387 * @return the installation path or <code>null</code>, if no installation
388 * was found or if an error occured
390 private static String getPathFromSVersionFile() {
392 final String SVERSION = ".sversionrc"; // Unix/Linux only
393 final String VERSIONS = "[Versions]";
395 String path = null;
397 try {
398 File fSVersion = new File(
399 System.getProperty( "user.home" ) ,SVERSION );
400 if ( fSVersion.exists() ) {
401 Vector lines = new Vector();
402 BufferedReader br = null;
403 try {
404 br = new BufferedReader( new InputStreamReader(
405 new FileInputStream( fSVersion ), "UTF-8" ) );
406 String line = null;
407 while ( ( line = br.readLine() ) != null &&
408 ( line.equals( VERSIONS ) ) != true ) {
409 // read lines until [Versions] is found
411 while ( ( line = br.readLine() ) != null &&
412 line.length() != 0 ) {
413 if ( !line.startsWith( ";" ) )
414 lines.add( line );
416 } catch ( IOException e ) {
417 // if an I/O exception is thrown, try to analyze the lines
418 // read so far
419 System.err.println( "com.sun.star.lib.loader." +
420 "InstallationFinder::getPathFromSVersionFile: " +
421 "reading .sversionrc file failed: " + e );
422 } finally {
423 if ( br != null ) {
424 try {
425 br.close();
426 } catch ( IOException e ) {
427 // closing .sversionrc failed, ignore
431 for ( int i = lines.size() - 1; i >= 0; i-- ) {
432 StringTokenizer tokens = new StringTokenizer(
433 (String)lines.elementAt( i ), "=" );
434 if ( tokens.countTokens() != 2 )
435 continue;
436 String key = tokens.nextToken();
437 String url = tokens.nextToken();
438 path = getCanonicalPathFromFileURL( url );
439 if ( path != null )
440 break;
443 } catch ( SecurityException e ) {
444 return null;
447 return path;
451 * Translates an OOo-internal absolute file URL reference (encoded using
452 * UTF-8) into a Java canonical pathname.
454 * @param oooUrl any URL reference; any fragment part is ignored
456 * @return if the given URL is a valid absolute, local (that is, the host
457 * part is empty or equal to "localhost", ignoring case) file URL, it is
458 * converted into an absolute canonical pathname; otherwise,
459 * <code>null</code> is returned
461 private static String getCanonicalPathFromFileURL( String oooUrl ) {
463 String prefix = "file://";
464 if (oooUrl.length() < prefix.length()
465 || !oooUrl.substring(0, prefix.length()).toLowerCase().equals(
466 prefix))
468 return null;
470 StringBuffer buf = new StringBuffer(prefix);
471 int n = oooUrl.indexOf('/', prefix.length());
472 if (n < 0) {
473 n = oooUrl.length();
475 String host = oooUrl.substring(prefix.length(), n);
476 if (host.length() != 0 && !host.toLowerCase().equals("localhost")) {
477 return null;
479 buf.append(host);
480 if (n == oooUrl.length()) {
481 buf.append('/');
482 } else {
483 loop:
484 while (n < oooUrl.length()) {
485 buf.append('/');
486 ++n;
487 int n2 = oooUrl.indexOf('/', n);
488 if (n2 < 0) {
489 n2 = oooUrl.length();
491 while (n < n2) {
492 char c = oooUrl.charAt(n);
493 switch (c) {
494 case '%':
495 byte[] bytes = new byte[(n2 - n) / 3];
496 int len = 0;
497 while (oooUrl.length() - n > 2
498 && oooUrl.charAt(n) == '%')
500 int d1 = Character.digit(oooUrl.charAt(n + 1), 16);
501 int d2 = Character.digit(oooUrl.charAt(n + 2), 16);
502 if (d1 < 0 || d2 < 0) {
503 break;
505 int d = 16 * d1 + d2;
506 if (d == '/') {
507 return null;
509 bytes[len++] = (byte) d;
510 n += 3;
512 String s;
513 try {
514 s = new String(bytes, 0, len, "UTF-8");
515 } catch (UnsupportedEncodingException e) {
516 return null;
518 buf.append(s);
519 break;
521 case '#':
522 break loop;
524 default:
525 buf.append(c);
526 ++n;
527 break;
532 URL url;
533 try {
534 url = new URL(buf.toString());
535 } catch (MalformedURLException e) {
536 return null;
538 String path = url.getFile();
539 String fragment = url.getRef();
540 if (fragment != null) {
541 path += '#' + fragment;
543 String ret = null;
544 File file = new File( path, SOFFICE );
545 try {
546 if ( file.isAbsolute() && file.exists() ) {
547 try {
548 // resolve symlink
549 ret = file.getCanonicalFile().getParent();
550 } catch ( IOException e ) {
551 return null;
554 } catch ( SecurityException e ) {
555 return null;
558 return ret;
562 This class is used for emptying any stream which is passed into it in
563 a separate thread.
565 private static final class StreamGobbler extends Thread {
567 InputStream m_istream;
569 StreamGobbler( InputStream istream ) {
570 m_istream = istream;
573 public void run() {
574 try {
575 BufferedReader br = new BufferedReader(
576 new InputStreamReader( m_istream ) );
577 // read from input stream
578 while ( br.readLine() != null ) {
579 // don't handle line content
581 br.close();
582 } catch ( IOException e ) {
583 // stop reading from input stream