OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 19 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
13 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.jopendocument.link;
15
 
16
import org.openconcerto.utils.DesktopEnvironment;
17
 
18
import java.io.File;
19
import java.io.FileFilter;
20
import java.io.IOException;
21
import java.net.MalformedURLException;
22
import java.net.URI;
23
import java.net.URISyntaxException;
24
import java.net.URL;
25
import java.util.ArrayList;
26
import java.util.Collections;
27
import java.util.HashMap;
28
import java.util.List;
29
import java.util.Map;
30
import java.util.Set;
31
import java.util.regex.Matcher;
32
import java.util.regex.Pattern;
33
 
34
/**
35
 * This class finds out where OpenOffice.org is installed.
36
 *
37
 * @author Sylvain CUAZ
38
 * @see #getInstance()
39
 */
40
public class OOInstallation {
41
 
42
    private static OOInstallation instance;
43
 
44
    /**
45
     * Return the installation for this machine.
46
     *
47
     * @return the installation for this machine, <code>null</code> if not installed.
48
     * @throws IOException if an error occurs while searching.
49
     */
50
    public static OOInstallation getInstance() throws IOException {
51
        // since null means never detected or not installed, this will keep searching when not
52
        // installed
53
        if (instance == null) {
54
            instance = detectInstall();
55
        }
56
        return instance;
57
    }
58
 
59
    /**
60
     * Forget the current installation to pick up a change (e.g. updated version).
61
     */
62
    public static void reset() {
63
        instance = null;
64
    }
65
 
66
    // UREINSTALLLOCATION REG_SZ C:\Program Files\OpenOffice.org 3\URE\
67
    // \1 is the name, \2 the value
68
    // cannot use \p{} since some names/values can be non-ASCII
69
    private static final Pattern stringValuePattern = Pattern.compile("^\\s*(.+?)\\s+REG_SZ\\s+(.+?)$", Pattern.MULTILINE);
70
 
71
    private static final String OOBundleID = "org.openoffice.script";
72
 
73
    // return the standard out (not the standard error)
74
    private static String cmdSubstitution(String... args) throws IOException {
75
        final ProcessBuilder pb = new ProcessBuilder(args);
76
        pb.redirectErrorStream(false);
77
        return DesktopEnvironment.cmdSubstitution(pb.start());
78
    }
79
 
80
    static final URL toURL(final File f) {
81
        try {
82
            return f.toURI().toURL();
83
        } catch (MalformedURLException e) {
84
            // shouldn't happen since constructed from a file
85
            throw new IllegalStateException("Couldn't transform to URL " + f, e);
86
        }
87
    }
88
 
89
    // handle windows x64
90
    private static String findRootPath() {
91
        final String[] rootPaths = { "HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenOffice.org", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\OpenOffice.org" };
92
        for (final String p : rootPaths) {
93
            if (DesktopEnvironment.test("reg", "query", p))
94
                return p;
95
        }
96
        return null;
97
    }
98
 
99
    // all string values for the passed registry path
100
    private static Map<String, String> getStringValues(final String path, final String option) throws IOException {
101
        final Map<String, String> values = new HashMap<String, String>();
102
        final String out = DesktopEnvironment.cmdSubstitution(Runtime.getRuntime().exec(new String[] { "reg", "query", path, option }));
103
        final Matcher matcher = stringValuePattern.matcher(out);
104
        while (matcher.find()) {
105
            values.put(matcher.group(1), matcher.group(2));
106
        }
107
        return values;
108
    }
109
 
110
    // add jar directories for OpenOffice 2 or 3
111
    private static final void addPaths(final List<File> cp, final File progDir, final String basisDir, final String ureDir) throws IOException {
112
        // oo2
113
        // all in C:\Program Files\OpenOffice.org 2.4\program\classes
114
        add(cp, new File(progDir, "classes"));
115
 
116
        // oo3
117
        // some in C:\Program Files\OpenOffice.org 3\URE\java
118
        // the rest in C:\Program Files\OpenOffice.org 3\Basis\program\classes
119
        if (ureDir != null) {
120
            // Windows
121
            add(cp, ureDir + File.separator + "java");
122
            // MacOS and Linux
123
            add(cp, ureDir + File.separator + "share" + File.separator + "java");
124
        }
125
        if (basisDir != null)
126
            add(cp, basisDir + File.separator + "program" + File.separator + "classes");
127
    }
128
 
129
    private static final void addUnixPaths(final List<File> cp, final File progDir) throws IOException {
130
        final File baseDir = progDir.getParentFile();
131
        final String basisDir = baseDir.getPath() + File.separator + "basis-link";
132
        final String ureDir = basisDir + File.separator + "ure-link";
133
        addPaths(cp, progDir, basisDir, ureDir);
134
    }
135
 
136
    private static void add(final List<File> res, final File f) {
137
        if (f != null && f.isDirectory()) {
138
            res.add(f);
139
        }
140
    }
141
 
142
    private static void add(final List<File> res, final String f) {
143
        if (f != null)
144
            add(res, new File(f));
145
    }
146
 
147
    private static OOInstallation detectInstall() throws IOException {
148
        final File exe;
149
        final List<File> cp = new ArrayList<File>(3);
150
 
151
        final String os = System.getProperty("os.name");
152
        if (os.startsWith("Windows")) {
153
            final String rootPath = findRootPath();
154
            // not installed
155
            if (rootPath == null)
156
                return null;
157
 
158
            // Only the default value so pass '/ve'
159
            final Map<String, String> unoValues = getStringValues(rootPath + "\\UNO\\InstallPath", "/ve");
160
            if (unoValues.size() != 1)
161
                throw new IOException("No UNO install path: " + unoValues);
162
            // e.g. C:\Program Files\OpenOffice.org 2.4\program
163
            final File unoPath = new File(unoValues.values().iterator().next());
164
            if (!unoPath.isDirectory())
165
                throw new IOException(unoPath + " is not a directory");
166
            exe = new File(unoPath, "soffice.exe");
167
 
168
            // '/s' since variables are one level (the version) deeper
169
            final Map<String, String> layersValues = getStringValues(rootPath + "\\Layers\\OpenOffice.org", "/s");
170
            addPaths(cp, unoPath, layersValues.get("BASISINSTALLLOCATION"), layersValues.get("UREINSTALLLOCATION"));
171
        } else if (os.startsWith("Mac OS")) {
172
            // if not found prints nothing to out and a cryptic error to the standard error stream
173
            final String url = cmdSubstitution("osascript", "-e", "tell application id \"com.apple.Finder\" to URL of application file id \"" + OOBundleID + "\"").trim();
174
            if (url.length() == 0)
175
                return null;
176
            try {
177
                final File appPkg = new File(new URI(url).getPath());
178
                // need to call soffice from the MacOS directory otherwise it fails
179
                exe = new File(appPkg, "Contents/MacOS/soffice");
180
                addUnixPaths(cp, new File(appPkg, "Contents/program"));
181
            } catch (URISyntaxException e) {
182
                throw new IOException(e);
183
            }
184
        } else if (os.startsWith("Linux")) {
185
            // soffice is usually a symlink in /usr/bin
186
            // if not found prints nothing at all
187
            final String binPath = cmdSubstitution("which", "soffice").trim();
188
            if (binPath.length() != 0) {
189
                exe = new File(binPath).getCanonicalFile();
190
            } else {
191
                // e.g. Ubuntu 6.06
192
                final File defaultInstall = new File("/usr/lib/openoffice/program/soffice");
193
                exe = defaultInstall.canExecute() ? defaultInstall : null;
194
            }
195
            if (exe != null)
196
                addUnixPaths(cp, exe.getParentFile());
197
        } else
198
            exe = null;
199
        return exe == null ? null : new OOInstallation(exe, cp);
200
    }
201
 
202
    private final File executable;
203
    private final List<File> classpath;
204
 
205
    // TODO parse program/version.ini
206
 
207
    private OOInstallation(File executable, List<File> classpath) throws IOException {
208
        super();
209
        if (!executable.isFile())
210
            throw new IOException("executable not found at " + executable);
211
 
212
        this.executable = executable;
213
        this.classpath = Collections.unmodifiableList(new ArrayList<File>(classpath));
214
    }
215
 
216
    public final File getExecutable() {
217
        return this.executable;
218
    }
219
 
220
    public final List<File> getClasspath() {
221
        return this.classpath;
222
    }
223
 
224
    public final List<URL> getURLs(final Set<String> jars) {
225
        final int stop = this.getClasspath().size();
226
        final List<URL> res = new ArrayList<URL>();
227
        for (int i = 0; i < stop; i++) {
228
            final File[] foundJars = this.getClasspath().get(i).listFiles(new FileFilter() {
229
                @Override
230
                public boolean accept(File f) {
231
                    return jars.contains(f.getName());
232
                }
233
            });
234
            for (final File foundJar : foundJars) {
235
                res.add(toURL(foundJar));
236
            }
237
        }
238
        return res;
239
    }
240
 
241
    @Override
242
    public String toString() {
243
        return this.getClass().getSimpleName() + " exe: " + this.getExecutable() + " classpath: " + this.getClasspath();
244
    }
245
 
246
    public static void main(String[] args) {
247
        try {
248
            final OOInstallation i = getInstance();
249
            System.out.println(i == null ? "Not installed" : i);
250
        } catch (IOException e) {
251
            System.out.println("Couldn't detect OpenOffice.org: " + e.getLocalizedMessage());
252
            e.printStackTrace();
253
        }
254
    }
255
}