OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 13 | Rev 61 | Go to most recent revision | Details | Compare with Previous | 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
 
19 ilm 71
    private static final String LOBundleID = "org.libreoffice.script";
13 ilm 72
    private static final String OOBundleID = "org.openoffice.script";
73
 
74
    // return the standard out (not the standard error)
75
    private static String cmdSubstitution(String... args) throws IOException {
76
        final ProcessBuilder pb = new ProcessBuilder(args);
77
        pb.redirectErrorStream(false);
78
        return DesktopEnvironment.cmdSubstitution(pb.start());
79
    }
80
 
81
    static final URL toURL(final File f) {
82
        try {
83
            return f.toURI().toURL();
84
        } catch (MalformedURLException e) {
85
            // shouldn't happen since constructed from a file
86
            throw new IllegalStateException("Couldn't transform to URL " + f, e);
87
        }
88
    }
89
 
90
    // handle windows x64
91
    private static String findRootPath() {
19 ilm 92
        final String[] rootPaths = { "HKEY_LOCAL_MACHINE\\SOFTWARE\\LibreOffice", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LibreOffice", "HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenOffice.org",
93
                "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\OpenOffice.org" };
13 ilm 94
        for (final String p : rootPaths) {
95
            if (DesktopEnvironment.test("reg", "query", p))
96
                return p;
97
        }
98
        return null;
99
    }
100
 
19 ilm 101
    private static String findBundleURL() throws IOException {
102
        for (final String bundleID : new String[] { LOBundleID, OOBundleID }) {
103
            // if not found prints nothing to out and a cryptic error to the standard error stream
104
            final String url = cmdSubstitution("osascript", "-e", "tell application id \"com.apple.Finder\" to URL of application file id \"" + bundleID + "\"").trim();
105
            if (url.length() > 0)
106
                return url;
107
        }
108
        return null;
109
    }
110
 
13 ilm 111
    // all string values for the passed registry path
112
    private static Map<String, String> getStringValues(final String path, final String option) throws IOException {
113
        final Map<String, String> values = new HashMap<String, String>();
114
        final String out = DesktopEnvironment.cmdSubstitution(Runtime.getRuntime().exec(new String[] { "reg", "query", path, option }));
115
        final Matcher matcher = stringValuePattern.matcher(out);
116
        while (matcher.find()) {
117
            values.put(matcher.group(1), matcher.group(2));
118
        }
119
        return values;
120
    }
121
 
122
    // add jar directories for OpenOffice 2 or 3
123
    private static final void addPaths(final List<File> cp, final File progDir, final String basisDir, final String ureDir) throws IOException {
124
        // oo2
125
        // all in C:\Program Files\OpenOffice.org 2.4\program\classes
126
        add(cp, new File(progDir, "classes"));
127
 
128
        // oo3
129
        // some in C:\Program Files\OpenOffice.org 3\URE\java
130
        // the rest in C:\Program Files\OpenOffice.org 3\Basis\program\classes
131
        if (ureDir != null) {
132
            // Windows
133
            add(cp, ureDir + File.separator + "java");
134
            // MacOS and Linux
135
            add(cp, ureDir + File.separator + "share" + File.separator + "java");
136
        }
137
        if (basisDir != null)
138
            add(cp, basisDir + File.separator + "program" + File.separator + "classes");
139
    }
140
 
141
    private static final void addUnixPaths(final List<File> cp, final File progDir) throws IOException {
142
        final File baseDir = progDir.getParentFile();
143
        final String basisDir = baseDir.getPath() + File.separator + "basis-link";
144
        final String ureDir = basisDir + File.separator + "ure-link";
145
        addPaths(cp, progDir, basisDir, ureDir);
146
    }
147
 
148
    private static void add(final List<File> res, final File f) {
149
        if (f != null && f.isDirectory()) {
150
            res.add(f);
151
        }
152
    }
153
 
154
    private static void add(final List<File> res, final String f) {
155
        if (f != null)
156
            add(res, new File(f));
157
    }
158
 
159
    private static OOInstallation detectInstall() throws IOException {
160
        final File exe;
161
        final List<File> cp = new ArrayList<File>(3);
162
 
163
        final String os = System.getProperty("os.name");
164
        if (os.startsWith("Windows")) {
165
            final String rootPath = findRootPath();
166
            // not installed
167
            if (rootPath == null)
168
                return null;
19 ilm 169
            final boolean libreOffice = rootPath.contains("LibreOffice");
13 ilm 170
 
171
            // Only the default value so pass '/ve'
172
            final Map<String, String> unoValues = getStringValues(rootPath + "\\UNO\\InstallPath", "/ve");
173
            if (unoValues.size() != 1)
174
                throw new IOException("No UNO install path: " + unoValues);
175
            // e.g. C:\Program Files\OpenOffice.org 2.4\program
176
            final File unoPath = new File(unoValues.values().iterator().next());
177
            if (!unoPath.isDirectory())
178
                throw new IOException(unoPath + " is not a directory");
179
            exe = new File(unoPath, "soffice.exe");
180
 
181
            // '/s' since variables are one level (the version) deeper
19 ilm 182
            final Map<String, String> layersValues = getStringValues(rootPath + (libreOffice ? "\\Layers_\\LibreOffice" : "\\Layers\\OpenOffice.org"), "/s");
13 ilm 183
            addPaths(cp, unoPath, layersValues.get("BASISINSTALLLOCATION"), layersValues.get("UREINSTALLLOCATION"));
184
        } else if (os.startsWith("Mac OS")) {
19 ilm 185
            final String url = findBundleURL();
186
            if (url == null)
13 ilm 187
                return null;
188
            try {
189
                final File appPkg = new File(new URI(url).getPath());
190
                // need to call soffice from the MacOS directory otherwise it fails
191
                exe = new File(appPkg, "Contents/MacOS/soffice");
192
                addUnixPaths(cp, new File(appPkg, "Contents/program"));
193
            } catch (URISyntaxException e) {
194
                throw new IOException(e);
195
            }
196
        } else if (os.startsWith("Linux")) {
197
            // soffice is usually a symlink in /usr/bin
198
            // if not found prints nothing at all
199
            final String binPath = cmdSubstitution("which", "soffice").trim();
200
            if (binPath.length() != 0) {
201
                exe = new File(binPath).getCanonicalFile();
202
            } else {
203
                // e.g. Ubuntu 6.06
204
                final File defaultInstall = new File("/usr/lib/openoffice/program/soffice");
205
                exe = defaultInstall.canExecute() ? defaultInstall : null;
206
            }
207
            if (exe != null)
208
                addUnixPaths(cp, exe.getParentFile());
209
        } else
210
            exe = null;
211
        return exe == null ? null : new OOInstallation(exe, cp);
212
    }
213
 
214
    private final File executable;
215
    private final List<File> classpath;
216
 
217
    // TODO parse program/version.ini
218
 
219
    private OOInstallation(File executable, List<File> classpath) throws IOException {
220
        super();
221
        if (!executable.isFile())
222
            throw new IOException("executable not found at " + executable);
223
 
224
        this.executable = executable;
225
        this.classpath = Collections.unmodifiableList(new ArrayList<File>(classpath));
226
    }
227
 
228
    public final File getExecutable() {
229
        return this.executable;
230
    }
231
 
232
    public final List<File> getClasspath() {
233
        return this.classpath;
234
    }
235
 
236
    public final List<URL> getURLs(final Set<String> jars) {
237
        final int stop = this.getClasspath().size();
238
        final List<URL> res = new ArrayList<URL>();
239
        for (int i = 0; i < stop; i++) {
240
            final File[] foundJars = this.getClasspath().get(i).listFiles(new FileFilter() {
241
                @Override
242
                public boolean accept(File f) {
243
                    return jars.contains(f.getName());
244
                }
245
            });
246
            for (final File foundJar : foundJars) {
247
                res.add(toURL(foundJar));
248
            }
249
        }
250
        return res;
251
    }
252
 
253
    @Override
254
    public String toString() {
255
        return this.getClass().getSimpleName() + " exe: " + this.getExecutable() + " classpath: " + this.getClasspath();
256
    }
257
 
258
    public static void main(String[] args) {
259
        try {
260
            final OOInstallation i = getInstance();
261
            System.out.println(i == null ? "Not installed" : i);
262
        } catch (IOException e) {
263
            System.out.println("Couldn't detect OpenOffice.org: " + e.getLocalizedMessage());
264
            e.printStackTrace();
265
        }
266
    }
267
}