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: InstallationFinder.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
;
33 import java
.io
.BufferedReader
;
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
;
42 import java
.util
.StringTokenizer
;
43 import java
.util
.Vector
;
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
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
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
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
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
87 public static String
getPath() {
91 // get the installation path from the Java system property
92 // com.sun.star.lib.loader.unopath
94 path
= getPathFromProperty( SYSPROP_NAME
);
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
);
100 String osname
= null;
102 osname
= System
.getProperty( "os.name" );
103 } catch ( SecurityException e
) {
104 // if a SecurityException was thrown,
105 // return <code>null</code>
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();
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();
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
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
) {
153 path
= System
.getProperty( prop
);
154 } catch ( SecurityException e
) {
155 // if a SecurityException was thrown, return <code>null</code>
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
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
) {
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
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";
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
) {
208 // read the key's default value from HKEY_LOCAL_MACHINE
209 WinRegKey key
= new WinRegKey( "HKEY_LOCAL_MACHINE",
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
);
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
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";
243 str
= System
.getenv( PATH_ENVVAR_NAME
);
244 } catch ( SecurityException e
) {
245 // if a SecurityException was thrown, return <code>null</code>
247 } catch ( java
.lang
.Error err
) {
248 // System.getenv() throws java.lang.Error in Java 1.3.1 and
254 StringTokenizer tokens
= new StringTokenizer(
255 str
, File
.pathSeparator
);
256 while ( tokens
.hasMoreTokens() ) {
257 File file
= new File( tokens
.nextToken(), SOFFICE
);
259 if ( file
.exists() ) {
262 path
= file
.getCanonicalFile().getParent();
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: " +
273 } catch ( SecurityException e
) {
274 // if a SecurityException was thrown, ignore this path
275 // entry and try the next one
284 * Gets the installation path from the 'which' command on Unix/Linux
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";
300 // start the which process
301 String
[] cmdArray
= new String
[2];
303 cmdArray
[1] = SOFFICE
;
305 Runtime rt
= Runtime
.getRuntime();
307 proc
= rt
.exec( cmdArray
);
308 } catch ( SecurityException e
) {
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
);
318 // empty standard error stream in a seperate thread
319 StreamGobbler gobbler
= new StreamGobbler( proc
.getErrorStream() );
322 // read the which output from standard input stream
323 BufferedReader br
= new BufferedReader(
324 new InputStreamReader( proc
.getInputStream() ) );
327 while ( ( line
= br
.readLine() ) != null ) {
328 if ( path
== null ) {
329 // get the path from the which output
330 int index
= line
.lastIndexOf( SOFFICE
);
332 int end
= index
+ SOFFICE
.length();
333 for ( int i
= 0; i
<= index
; i
++ ) {
334 File file
= new File( line
.substring( i
, end
) );
336 if ( file
.exists() ) {
338 path
= file
.getCanonicalFile().getParent();
342 } catch ( SecurityException e
) {
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
);
359 } catch ( IOException e
) {
360 // closing standard input stream failed, ignore
366 // wait until the which process has terminated
368 } catch ( InterruptedException e
) {
369 // the current thread was interrupted by another thread,
370 // kill the which process
372 // set the interrupted status
373 Thread
.currentThread().interrupt();
380 * Gets the installation path from the .sverionrc file in the user's home
383 * <p>This method is called on Unix/Linux platforms only.
384 * The .sversionrc file is written during setup and will be omitted for
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]";
398 File fSVersion
= new File(
399 System
.getProperty( "user.home" ) ,SVERSION
);
400 if ( fSVersion
.exists() ) {
401 Vector lines
= new Vector();
402 BufferedReader br
= null;
404 br
= new BufferedReader( new InputStreamReader(
405 new FileInputStream( fSVersion
), "UTF-8" ) );
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( ";" ) )
416 } catch ( IOException e
) {
417 // if an I/O exception is thrown, try to analyze the lines
419 System
.err
.println( "com.sun.star.lib.loader." +
420 "InstallationFinder::getPathFromSVersionFile: " +
421 "reading .sversionrc file failed: " + e
);
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 )
436 String key
= tokens
.nextToken();
437 String url
= tokens
.nextToken();
438 path
= getCanonicalPathFromFileURL( url
);
443 } catch ( SecurityException e
) {
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(
470 StringBuffer buf
= new StringBuffer(prefix
);
471 int n
= oooUrl
.indexOf('/', prefix
.length());
475 String host
= oooUrl
.substring(prefix
.length(), n
);
476 if (host
.length() != 0 && !host
.toLowerCase().equals("localhost")) {
480 if (n
== oooUrl
.length()) {
484 while (n
< oooUrl
.length()) {
487 int n2
= oooUrl
.indexOf('/', n
);
489 n2
= oooUrl
.length();
492 char c
= oooUrl
.charAt(n
);
495 byte[] bytes
= new byte[(n2
- n
) / 3];
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) {
505 int d
= 16 * d1
+ d2
;
509 bytes
[len
++] = (byte) d
;
514 s
= new String(bytes
, 0, len
, "UTF-8");
515 } catch (UnsupportedEncodingException e
) {
534 url
= new URL(buf
.toString());
535 } catch (MalformedURLException e
) {
538 String path
= url
.getFile();
539 String fragment
= url
.getRef();
540 if (fragment
!= null) {
541 path
+= '#' + fragment
;
544 File file
= new File( path
, SOFFICE
);
546 if ( file
.isAbsolute() && file
.exists() ) {
549 ret
= file
.getCanonicalFile().getParent();
550 } catch ( IOException e
) {
554 } catch ( SecurityException e
) {
562 This class is used for emptying any stream which is passed into it in
565 private static final class StreamGobbler
extends Thread
{
567 InputStream m_istream
;
569 StreamGobbler( InputStream istream
) {
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
582 } catch ( IOException e
) {
583 // stop reading from input stream