OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
180 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.openconcerto.utils.tools;
15
 
16
import org.openconcerto.utils.Log;
17
import org.openconcerto.utils.StreamUtils;
18
 
19
import java.io.File;
20
import java.io.IOException;
21
import java.io.InputStream;
22
import java.net.HttpURLConnection;
23
import java.net.MalformedURLException;
24
import java.net.URL;
25
import java.net.URLClassLoader;
26
import java.net.URLConnection;
27
import java.security.CodeSigner;
28
import java.security.CodeSource;
29
import java.security.SecureClassLoader;
30
import java.util.ArrayList;
31
import java.util.Collections;
32
import java.util.List;
33
import java.util.logging.Level;
34
 
35
/**
36
 * Class loader which supports any URL. {@link URLClassLoader} only supports directories and jar
37
 * files, but is more optimized (e.g. for finding which URL contains a resource)
38
 *
39
 * @author sylvain
40
 */
41
public class SimpleURLClassLoader extends SecureClassLoader {
42
 
43
    static public final URL toURL(final File f) {
44
        try {
45
            return f.toURI().toURL();
46
        } catch (MalformedURLException e) {
47
            // shouldn't happen since constructed from a file
48
            throw new IllegalStateException("Couldn't transform file to URL " + f, e);
49
        }
50
    }
51
 
52
    static public class URLCollector {
53
        private final List<URL> urls = new ArrayList<>();
54
 
55
        public final List<URL> copyToUnmodifiableList() {
56
            return Collections.unmodifiableList(new ArrayList<>(this.urls));
57
        }
58
 
59
        public final URLCollector add(final URL url) {
60
            this.urls.add(url);
61
            return this;
62
        }
63
 
64
        public final URLCollector addDirectory(final File dir) {
65
            if (!dir.isDirectory())
66
                throw new IllegalArgumentException("Not a directory : " + dir);
67
            return this.add(toURL(dir));
68
        }
69
 
70
        public final URLCollector addJar(final File jar) {
71
            if (!jar.isFile())
72
                throw new IllegalArgumentException("Not a file : " + jar);
73
            return this.addJar(toURL(jar));
74
        }
75
 
76
        public final URLCollector addJar(final URL u) {
77
            return this.add(org.openconcerto.utils.protocol.Helper.intoJar(u));
78
        }
79
 
80
        public final URLCollector addJars(final Iterable<URL> jars) {
81
            for (final URL jar : jars)
82
                this.addJar(jar);
83
            return this;
84
        }
85
    }
86
 
87
    // from ResourceBundle.Control
88
    static public final String toResourceName(String bundleName, String suffix) {
89
        StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
90
        sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
91
        return sb.toString();
92
    }
93
 
94
    static public final String toClassFile(String bundleName) {
95
        return toResourceName(bundleName, "class");
96
    }
97
 
98
    private final List<URL> urls;
99
 
100
    public SimpleURLClassLoader(final URLCollector urls) {
101
        super();
102
        this.urls = urls.copyToUnmodifiableList();
103
    }
104
 
105
    public SimpleURLClassLoader(final URLCollector urls, final ClassLoader parent) {
106
        super(parent);
107
        this.urls = urls.copyToUnmodifiableList();
108
    }
109
 
110
    protected URL createURL(final URL url, final String spec) throws MalformedURLException {
111
        return new URL(url, spec);
112
    }
113
 
114
    @Override
115
    protected Class<?> findClass(String name) throws ClassNotFoundException {
116
        for (final URL baseURL : this.urls) {
117
            try {
118
                final URL url = createURL(baseURL, toClassFile(name));
119
                try (final InputStream ins = url.openConnection().getInputStream()) {
120
                    try {
121
                        final byte[] bytes = StreamUtils.read(ins);
122
                        return this.defineClass(name, bytes, 0, bytes.length, new CodeSource(url, (CodeSigner[]) null));
123
                    } catch (IOException readExn) {
124
                        // same behaviour as URLClassLoader.findClass()
125
                        throw new ClassNotFoundException(name, readExn);
126
                    }
127
                }
128
            } catch (IOException connectExn) {
129
                Log.get().log(Level.FINE, connectExn, () -> "Couldn't connect to " + baseURL + " for " + name);
130
                // next
131
            }
132
        }
133
        return super.findClass(name);
134
    }
135
 
136
    @Override
137
    protected URL findResource(String name) {
138
        for (final URL baseURL : this.urls) {
139
            try {
140
                final URL url = createURL(baseURL, name);
141
                boolean exists = false;
142
                if (url.getProtocol().equals("file")) {
143
                    exists = new File(url.toURI()).exists();
144
                } else {
145
                    // From sun.misc.URLClassPath.Loader
146
                    URLConnection uc = url.openConnection();
147
                    if (uc instanceof HttpURLConnection) {
148
                        HttpURLConnection hconn = (HttpURLConnection) uc;
149
                        hconn.setRequestMethod("HEAD");
150
                        exists = hconn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST;
151
                    } else {
152
                        // our best guess for the other cases
153
                        uc.setUseCaches(false);
154
                        try (final InputStream ins = uc.getInputStream()) {
155
                            exists = true;
156
                        } catch (IOException e) {
157
                            exists = false;
158
                        }
159
                    }
160
                }
161
                if (exists)
162
                    return url;
163
            } catch (Exception e) {
164
                // next
165
            }
166
        }
167
        return super.findResource(name);
168
    }
169
}