OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 180 | 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
 *
185 ilm 4
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
13 ilm 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.CollectionUtils;
180 ilm 17
import org.openconcerto.utils.tools.SimpleURLClassLoader;
18
import org.openconcerto.utils.tools.SimpleURLClassLoader.URLCollector;
13 ilm 19
 
20
import java.io.File;
21
import java.io.FileNotFoundException;
73 ilm 22
import java.io.FilePermission;
13 ilm 23
import java.io.IOException;
24
import java.net.MalformedURLException;
73 ilm 25
import java.net.SocketPermission;
13 ilm 26
import java.net.URL;
27
import java.net.URLClassLoader;
73 ilm 28
import java.security.CodeSource;
29
import java.security.PermissionCollection;
185 ilm 30
import java.util.Collections;
13 ilm 31
import java.util.List;
32
import java.util.Map;
73 ilm 33
import java.util.PropertyPermission;
13 ilm 34
import java.util.WeakHashMap;
35
 
36
/**
37
 * Connexion avec une instance d'OO
38
 *
39
 * @author Administrateur
40
 */
144 ilm 41
public abstract class OOConnexion implements AutoCloseable {
13 ilm 42
 
43
    // weak to let go OOInstallation instances
44
    private static final Map<OOInstallation, ClassLoader> loaders = new WeakHashMap<OOInstallation, ClassLoader>(2);
45
    // TODO use OOInstallation.getVersion()
46
    // for now only one version (but also works with OO2)
47
    private static final String OO_VERSION = "3";
73 ilm 48
 
49
    protected static final int PORT = 8100;
144 ilm 50
    protected static final int PORT_MAX = 8250;
73 ilm 51
 
13 ilm 52
    static {
53
        // needed to access .class inside a jar inside a jar.
54
        org.openconcerto.utils.protocol.Helper.register();
55
    }
56
 
57
    static private final URL[] getURLs(final OOInstallation ooInstall) {
185 ilm 58
        final List<URL> from_v7 = ooInstall.getURLs(Collections.singleton("libreoffice.jar"));
59
        final List<URL> res = from_v7.isEmpty() ? ooInstall.getURLs(CollectionUtils.createSet("ridl.jar", "jurt.jar", "juh.jar", "unoil.jar")) : from_v7;
180 ilm 60
        return res.toArray(new URL[res.size()]);
61
    }
13 ilm 62
 
180 ilm 63
    static private final URL getFwkURL(final OOInstallation ooInstall) {
13 ilm 64
        final String jarName = "OO" + OO_VERSION + "-link.jar";
65
        final URL resource = OOConnexion.class.getResource(jarName);
66
        if (resource == null)
67
            // Did you run ant in the OO3Link project (or in ours) ?
68
            throw new IllegalStateException("Missing " + jarName);
69
 
180 ilm 70
        return resource;
13 ilm 71
    }
72
 
180 ilm 73
    static private final PermissionCollection addPermissions(final PermissionCollection perms, final OOInstallation ooInstall) {
74
        perms.add(new FilePermission(ooInstall.getExecutable().getAbsolutePath(), "execute"));
75
        perms.add(new SocketPermission("localhost:" + PORT + "-" + PORT_MAX, "connect"));
76
        // needed by OO jars
77
        perms.add(new PropertyPermission("*", "read"));
78
        // to be able to open any document
79
        perms.add(new FilePermission("<<ALL FILES>>", "read"));
80
        // needed by ThreadPoolExecutor.shutdown()
81
        perms.add(new RuntimePermission("modifyThread"));
82
        // needed by PrinterJob.getPrinterJob()
83
        perms.add(new RuntimePermission("queuePrintJob"));
84
 
85
        // ProcessBuilder.start() calls SecurityManager.checkExec() which requires
86
        // absolute path (or execute on "<<ALL FILES>>")
87
 
88
        // needed by OOConnexion.init() to find the port
89
        perms.add(new FilePermission("/usr/bin/lsof", "execute"));
90
        // macOS path
91
        perms.add(new FilePermission("/usr/sbin/lsof", "execute"));
92
        perms.add(new FilePermission("/bin/ps", "execute"));
93
        perms.add(new FilePermission("C:/Windows/System32/tasklist.exe", "execute"));
94
        perms.add(new RuntimePermission("getenv.*"));
95
        // needed by OOConnexion.convertToUrl()
96
        perms.add(new FilePermission("/usr/bin/gvfs-info", "execute"));
97
 
98
        return perms;
99
    }
100
 
101
    static synchronized private final ClassLoader getLoader(final OOInstallation ooInstall) {
13 ilm 102
        ClassLoader res = loaders.get(ooInstall);
103
        if (res == null) {
104
            // pass our classloader otherwise the system class loader will be used. This won't work
105
            // in webstart since the classpath is loaded by JNLPClassLoader, thus a class loaded by
106
            // res couldn't refer to the classpath (e.g. this class) but only to the java library.
180 ilm 107
            final URLClassLoader officeLoader = new URLClassLoader(getURLs(ooInstall), OOConnexion.class.getClassLoader()) {
73 ilm 108
                @Override
109
                protected PermissionCollection getPermissions(CodeSource codesource) {
180 ilm 110
                    return addPermissions(super.getPermissions(codesource), ooInstall);
73 ilm 111
                }
112
            };
180 ilm 113
            // only use SimpleURLClassLoader when really needed since it is less optimized
114
            res = new SimpleURLClassLoader(new URLCollector().addJar(getFwkURL(ooInstall)), officeLoader) {
115
                @Override
116
                protected PermissionCollection getPermissions(CodeSource codesource) {
117
                    return addPermissions(super.getPermissions(codesource), ooInstall);
118
                }
119
            };
13 ilm 120
            loaders.put(ooInstall, res);
121
        }
122
        return res;
123
    }
124
 
125
    /**
126
     * Return a connection to the default OpenOffice installation.
127
     *
128
     * @return a connection to the default OpenOffice or <code>null</code> if none is found.
129
     * @throws IllegalStateException if an error occurs while searching.
130
     */
131
    static public OOConnexion create() throws IllegalStateException {
132
        final OOInstallation ooInstall;
133
        try {
134
            ooInstall = OOInstallation.getInstance();
135
        } catch (IOException e) {
136
            throw new IllegalStateException("Couldn't find default OO installation", e);
137
        }
138
        return create(ooInstall);
139
    }
140
 
141
    static public OOConnexion create(final OOInstallation ooInstall) throws IllegalStateException {
142
        if (ooInstall == null)
143
            return null;
144
        try {
145
            final Class<?> c = getLoader(ooInstall).loadClass("org.jopendocument.link" + OO_VERSION + ".OOConnexion");
146
            return (OOConnexion) c.getConstructor(OOInstallation.class).newInstance(ooInstall);
147
        } catch (Exception e) {
148
            throw new IllegalStateException("Couldn't create OOCOnnexion", e);
149
        }
150
    }
151
 
73 ilm 152
    public static void main(String[] args) throws IOException {
142 ilm 153
        if (args.length == 0 || args.length > 2) {
154
            System.out.println("Usage : " + OOConnexion.class.getName() + " officeFile | --type param");
73 ilm 155
            System.out.println("Open officeFile in the default installation of LibreOffice");
142 ilm 156
            System.out.println("--type is either file or url");
73 ilm 157
            System.exit(1);
158
        }
144 ilm 159
        try (final OOConnexion conn = OOConnexion.create()) {
160
            if (conn == null)
161
                throw new IllegalStateException("No Office found");
162
            final boolean file;
163
            final String arg;
164
            if (args.length == 1) {
165
                file = true;
166
                arg = args[0];
167
            } else if (args[0].equals("--file")) {
168
                file = true;
169
                arg = args[1];
170
            } else if (args[0].equals("--url")) {
171
                file = false;
172
                arg = args[1];
173
            } else {
174
                throw new IllegalArgumentException("Type not valid : " + args[0]);
175
            }
176
            if (file)
177
                conn.loadDocument(new File(arg), false);
178
            else
179
                conn.loadDocumentFromURLAsync(arg, false);
142 ilm 180
        }
73 ilm 181
    }
182
 
13 ilm 183
    protected abstract Component loadDocumentFromURLAsync(final String url, final boolean hidden);
184
 
185
    /**
186
     * Load a document in OpenOffice.
187
     *
188
     * @param f the file to load.
189
     * @param hidden <code>true</code> if no frame should be visible.
190
     * @return the new component.
191
     * @throws IOException if an error occurs.
192
     */
193
    public final Component loadDocument(final File f, final boolean hidden) throws IOException {
194
        if (!f.exists())
195
            throw new FileNotFoundException(f.getAbsolutePath());
196
 
197
        return loadDocumentFromURLAsync(convertToUrl(f.getAbsolutePath()), hidden);
198
    }
199
 
200
    protected abstract String convertToUrl(String path) throws MalformedURLException;
201
 
144 ilm 202
    @Override
203
    public final void close() {
204
        this.closeConnexion();
205
    }
206
 
13 ilm 207
    public abstract void closeConnexion();
208
 
209
    /**
210
     * Whether the bridge is closed.
211
     *
212
     * @return <code>true</code> if {@link #closeConnexion()} was called or OpenOffice is now longer
213
     *         running.
214
     */
215
    public abstract boolean isClosed();
216
}