Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 190279 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/equinox/servletbridge/FrameworkLauncher.java (-12 / +7 lines)
Lines 15-21 Link Here
15
import java.io.*;
15
import java.io.*;
16
import java.lang.reflect.InvocationTargetException;
16
import java.lang.reflect.InvocationTargetException;
17
import java.lang.reflect.Method;
17
import java.lang.reflect.Method;
18
import java.net.*;
18
import java.net.MalformedURLException;
19
import java.net.URL;
19
import java.security.*;
20
import java.security.*;
20
import java.util.*;
21
import java.util.*;
21
import java.util.jar.*;
22
import java.util.jar.*;
Lines 108-114 Link Here
108
	protected String resourceBase;
109
	protected String resourceBase;
109
	private File platformDirectory;
110
	private File platformDirectory;
110
	private ClassLoader frameworkContextClassLoader;
111
	private ClassLoader frameworkContextClassLoader;
111
	private URLClassLoader frameworkClassLoader;
112
	private CloseableURLClassLoader frameworkClassLoader;
112
113
113
	void init(ServletConfig servletConfig) {
114
	void init(ServletConfig servletConfig) {
114
		config = servletConfig;
115
		config = servletConfig;
Lines 495-504 Link Here
495
			} catch (ClassNotFoundException e) {
496
			} catch (ClassNotFoundException e) {
496
				// ignore, ACL is not being used
497
				// ignore, ACL is not being used
497
			}
498
			}
499
498
		} catch (Exception e) {
500
		} catch (Exception e) {
499
			context.log("Error while stopping Framework", e); //$NON-NLS-1$
501
			context.log("Error while stopping Framework", e); //$NON-NLS-1$
500
			return;
502
			return;
501
		} finally {
503
		} finally {
504
			frameworkClassLoader.close();
502
			frameworkClassLoader = null;
505
			frameworkClassLoader = null;
503
			frameworkContextClassLoader = null;
506
			frameworkContextClassLoader = null;
504
			Thread.currentThread().setContextClassLoader(original);
507
			Thread.currentThread().setContextClassLoader(original);
Lines 741-758 Link Here
741
	 * used in its initialization for matching classes before delegating to it's parent.
744
	 * used in its initialization for matching classes before delegating to it's parent.
742
	 * Sometimes also referred to as a ParentLastClassLoader
745
	 * Sometimes also referred to as a ParentLastClassLoader
743
	 */
746
	 */
744
	protected class ChildFirstURLClassLoader extends URLClassLoader {
747
	protected class ChildFirstURLClassLoader extends CloseableURLClassLoader {
745
746
		public ChildFirstURLClassLoader(URL[] urls) {
747
			super(urls);
748
		}
749
748
750
		public ChildFirstURLClassLoader(URL[] urls, ClassLoader parent) {
749
		public ChildFirstURLClassLoader(URL[] urls, ClassLoader parent) {
751
			super(urls, parent);
750
			super(urls, parent, false);
752
		}
753
754
		public ChildFirstURLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
755
			super(urls, parent, factory);
756
		}
751
		}
757
752
758
		public URL getResource(String name) {
753
		public URL getResource(String name) {
(-)src/org/eclipse/equinox/servletbridge/CloseableURLClassLoader.java (+347 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.equinox.servletbridge;
12
13
import java.io.*;
14
import java.net.*;
15
import java.security.*;
16
import java.util.*;
17
import java.util.jar.*;
18
import java.util.jar.Attributes.Name;
19
20
public class CloseableURLClassLoader extends URLClassLoader {
21
	static final String DOT_CLASS = ".class"; //$NON-NLS-1$
22
	static final String BANG_SLASH = "!/"; //$NON-NLS-1$
23
	static final String JAR = "jar"; //$NON-NLS-1$
24
25
	// @GuardedBy("loaders")
26
	final ArrayList loaders = new ArrayList(); // package private to avoid synthetic access.
27
	// @GuardedBy("loaders")
28
	private final ArrayList loaderURLs = new ArrayList(); // note: protected by loaders
29
	// @GuardedBy("loaders")
30
	boolean closed = false; // note: protected by loaders, package private to avoid synthetic access.
31
32
	private final AccessControlContext context;
33
	private final boolean verifyJars;
34
35
	public static class CloseableJarURLConnection extends JarURLConnection {
36
		private final JarFile jarFile;
37
		// @GuardedBy("this")
38
		private JarEntry entry;
39
40
		public CloseableJarURLConnection(URL url, JarFile jarFile) throws MalformedURLException {
41
			super(url);
42
			this.jarFile = jarFile;
43
		}
44
45
		/**
46
		 * @throws IOException
47
		 * Documented to avoid warning 
48
		 */
49
		public void connect() throws IOException {
50
			internalGetEntry();
51
		}
52
53
		private synchronized JarEntry internalGetEntry() throws IOException {
54
			if (entry != null)
55
				return entry;
56
			entry = jarFile.getJarEntry(getEntryName());
57
			if (entry == null)
58
				throw new FileNotFoundException(getEntryName());
59
			return entry;
60
		}
61
62
		public InputStream getInputStream() throws IOException {
63
			return jarFile.getInputStream(internalGetEntry());
64
		}
65
66
		/**
67
		 * @throws IOException
68
		 * Documented to avoid warning 
69
		 */
70
		public JarFile getJarFile() throws IOException {
71
			return jarFile;
72
		}
73
74
		public JarEntry getJarEntry() throws IOException {
75
			return internalGetEntry();
76
		}
77
	}
78
79
	public static class CloseableJarURLStreamHandler extends URLStreamHandler {
80
		private final JarFile jarFile;
81
82
		public CloseableJarURLStreamHandler(JarFile jarFile) {
83
			this.jarFile = jarFile;
84
		}
85
86
		protected URLConnection openConnection(URL u) throws IOException {
87
			return new CloseableJarURLConnection(u, jarFile);
88
		}
89
90
		protected void parseURL(URL u, String spec, int start, int limit) {
91
			setURL(u, JAR, null, 0, null, null, spec.substring(start, limit), null, null);
92
		}
93
	}
94
95
	public static class CloseableJarFileLoader {
96
		private final JarFile jarFile;
97
		private final Manifest manifest;
98
		private final CloseableJarURLStreamHandler jarURLStreamHandler;
99
		private final String jarFileURLPrefixString;
100
101
		public CloseableJarFileLoader(File file, boolean verify) throws IOException {
102
			this.jarFile = new JarFile(file, verify);
103
			this.manifest = jarFile.getManifest();
104
			this.jarURLStreamHandler = new CloseableJarURLStreamHandler(jarFile);
105
			this.jarFileURLPrefixString = file.toURL().toString() + BANG_SLASH;
106
		}
107
108
		public URL getURL(String name) {
109
			if (jarFile.getEntry(name) != null)
110
				try {
111
					return new URL(JAR, null, -1, jarFileURLPrefixString + name, jarURLStreamHandler);
112
				} catch (MalformedURLException e) {
113
					// ignore
114
				}
115
			return null;
116
		}
117
118
		public Manifest getManifest() {
119
			return manifest;
120
		}
121
122
		public void close() {
123
			try {
124
				jarFile.close();
125
			} catch (IOException e) {
126
				// ignore
127
			}
128
		}
129
	}
130
131
	public CloseableURLClassLoader(URL[] urls) {
132
		this(urls, ClassLoader.getSystemClassLoader(), true);
133
	}
134
135
	public CloseableURLClassLoader(URL[] urls, ClassLoader parent) {
136
		this(excludeFileJarURLS(urls), parent, true);
137
	}
138
139
	public CloseableURLClassLoader(URL[] urls, ClassLoader parent, boolean verifyJars) {
140
		super(excludeFileJarURLS(urls), parent);
141
		this.context = AccessController.getContext();
142
		this.verifyJars = verifyJars;
143
		for (int i = 0; i < urls.length; i++) {
144
			if (isFileJarURL(urls[i])) {
145
				loaderURLs.add(urls[i]);
146
				safeAddLoader(urls[i]);
147
			}
148
		}
149
	}
150
151
	// @GuardedBy("loaders")
152
	private void safeAddLoader(URL url) {
153
		String path = url.getPath();
154
		File file = new File(path);
155
		if (file.exists()) {
156
			try {
157
				loaders.add(new CloseableJarFileLoader(file, verifyJars));
158
			} catch (IOException e) {
159
				// ignore
160
			}
161
		}
162
	}
163
164
	private static URL[] excludeFileJarURLS(URL[] urls) {
165
		ArrayList urlList = new ArrayList();
166
		for (int i = 0; i < urls.length; i++) {
167
			if (!isFileJarURL(urls[i]))
168
				urlList.add(urls[i]);
169
		}
170
		return (URL[]) urlList.toArray(new URL[urlList.size()]);
171
	}
172
173
	private static boolean isFileJarURL(URL url) {
174
		if (!url.getProtocol().equals("file")) //$NON-NLS-1$
175
			return false;
176
177
		String path = url.getPath();
178
		if (path != null && path.endsWith("/")) //$NON-NLS-1$
179
			return false;
180
181
		return true;
182
	}
183
184
	protected Class findClass(final String name) throws ClassNotFoundException {
185
		try {
186
			Class clazz = (Class) AccessController.doPrivileged(new PrivilegedExceptionAction() {
187
				public Object run() throws ClassNotFoundException {
188
					String resourcePath = name.replace('.', '/') + DOT_CLASS;
189
					CloseableJarFileLoader loader = null;
190
					URL resourceURL = null;
191
					synchronized (loaders) {
192
						if (closed)
193
							return null;
194
						for (Iterator iterator = loaders.iterator(); iterator.hasNext();) {
195
							loader = (CloseableJarFileLoader) iterator.next();
196
							resourceURL = loader.getURL(resourcePath);
197
							if (resourceURL != null)
198
								break;
199
						}
200
					}
201
					if (resourceURL != null) {
202
						try {
203
							return defineClass(name, resourceURL, loader.getManifest());
204
						} catch (IOException e) {
205
							throw new ClassNotFoundException(name, e);
206
						}
207
					}
208
					return null;
209
				}
210
			}, context);
211
			if (clazz != null)
212
				return clazz;
213
		} catch (PrivilegedActionException e) {
214
			throw (ClassNotFoundException) e.getException();
215
		}
216
		return super.findClass(name);
217
	}
218
219
	// package private to avoid synthetic access.
220
	Class defineClass(String name, URL resourceURL, Manifest manifest) throws IOException {
221
		JarURLConnection connection = (JarURLConnection) resourceURL.openConnection();
222
		int lastDot = name.lastIndexOf('.');
223
		if (lastDot != -1) {
224
			String packageName = name.substring(0, lastDot + 1);
225
			Package pkg = getPackage(packageName);
226
			if (pkg != null) {
227
				checkForSealedPackage(pkg, packageName, manifest, connection.getJarFileURL());
228
			} else {
229
				definePackage(packageName, manifest, connection.getJarFileURL());
230
			}
231
		}
232
		JarEntry entry = connection.getJarEntry();
233
		byte[] bytes = new byte[(int) entry.getSize()];
234
		DataInputStream is = null;
235
		try {
236
			is = new DataInputStream(connection.getInputStream());
237
			is.readFully(bytes, 0, bytes.length);
238
			CodeSource cs = new CodeSource(connection.getJarFileURL(), entry.getCertificates());
239
			return defineClass(name, bytes, 0, bytes.length, cs);
240
		} finally {
241
			if (is != null)
242
				try {
243
					is.close();
244
				} catch (IOException e) {
245
					// ignore
246
				}
247
		}
248
	}
249
250
	private void checkForSealedPackage(Package pkg, String packageName, Manifest manifest, URL jarFileURL) {
251
		if (pkg.isSealed() && !pkg.isSealed(jarFileURL))
252
			throw new SecurityException("The package '" + packageName + "' was previously loaded and is already sealed."); //$NON-NLS-1$ //$NON-NLS-2$
253
254
		String entryPath = packageName.replace('.', '/') + "/"; //$NON-NLS-1$
255
		Attributes entryAttributes = manifest.getAttributes(entryPath);
256
		String sealed = null;
257
		if (entryAttributes != null)
258
			sealed = entryAttributes.getValue(Name.SEALED);
259
260
		if (sealed == null) {
261
			Attributes mainAttributes = manifest.getMainAttributes();
262
			if (mainAttributes != null)
263
				sealed = mainAttributes.getValue(Name.SEALED);
264
		}
265
		if (Boolean.valueOf(sealed).booleanValue())
266
			throw new SecurityException("The package '" + packageName + "' was previously loaded unsealed. Cannot seal package."); //$NON-NLS-1$ //$NON-NLS-2$
267
	}
268
269
	public URL findResource(final String name) {
270
		URL url = (URL) AccessController.doPrivileged(new PrivilegedAction() {
271
			public Object run() {
272
				synchronized (loaders) {
273
					if (closed)
274
						return null;
275
					for (Iterator iterator = loaders.iterator(); iterator.hasNext();) {
276
						CloseableJarFileLoader loader = (CloseableJarFileLoader) iterator.next();
277
						URL resourceURL = loader.getURL(name);
278
						if (resourceURL != null)
279
							return resourceURL;
280
					}
281
				}
282
				return null;
283
			}
284
		}, context);
285
		if (url != null)
286
			return url;
287
		return super.findResource(name);
288
	}
289
290
	public Enumeration findResources(final String name) throws IOException {
291
		final List resources = new ArrayList();
292
		AccessController.doPrivileged(new PrivilegedAction() {
293
			public Object run() {
294
				synchronized (loaders) {
295
					if (closed)
296
						return null;
297
					for (Iterator iterator = loaders.iterator(); iterator.hasNext();) {
298
						CloseableJarFileLoader loader = (CloseableJarFileLoader) iterator.next();
299
						URL resourceURL = loader.getURL(name);
300
						if (resourceURL != null)
301
							resources.add(resourceURL);
302
					}
303
				}
304
				return null;
305
			}
306
		}, context);
307
		Enumeration e = super.findResources(name);
308
		while (e.hasMoreElements())
309
			resources.add(e.nextElement());
310
311
		return Collections.enumeration(resources);
312
	}
313
314
	public void close() {
315
		synchronized (loaders) {
316
			if (closed)
317
				return;
318
			for (Iterator iterator = loaders.iterator(); iterator.hasNext();) {
319
				CloseableJarFileLoader loader = (CloseableJarFileLoader) iterator.next();
320
				loader.close();
321
			}
322
			closed = true;
323
		}
324
	}
325
326
	protected void addURL(URL url) {
327
		synchronized (loaders) {
328
			if (isFileJarURL(url)) {
329
				if (closed)
330
					throw new IllegalStateException("Cannot add url. CloseableURLClassLoader is closed."); //$NON-NLS-1$
331
				loaderURLs.add(url);
332
				safeAddLoader(url);
333
				return;
334
			}
335
		}
336
		super.addURL(url);
337
	}
338
339
	public URL[] getURLs() {
340
		List result = new ArrayList();
341
		synchronized (loaders) {
342
			result.addAll(loaderURLs);
343
		}
344
		result.addAll(Arrays.asList(super.getURLs()));
345
		return (URL[]) result.toArray(new URL[result.size()]);
346
	}
347
}

Return to bug 190279