OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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