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 (-7 / +6 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-747 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
748
746
		public ChildFirstURLClassLoader(URL[] urls) {
749
		public ChildFirstURLClassLoader(URL[] urls) {
747
			super(urls);
750
			super(urls);
Lines 751-760 Link Here
751
			super(urls, parent);
754
			super(urls, parent);
752
		}
755
		}
753
756
754
		public ChildFirstURLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
755
			super(urls, parent, factory);
756
		}
757
758
		public URL getResource(String name) {
757
		public URL getResource(String name) {
759
			URL resource = findResource(name);
758
			URL resource = findResource(name);
760
			if (resource == null) {
759
			if (resource == null) {
(-)src/org/eclipse/equinox/servletbridge/CloseableURLClassLoader.java (+338 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
	final ArrayList loaders = new ArrayList(); // package private to avoid synthetic access.
26
	private final ArrayList loaderURLs = new ArrayList(); // note: protected by loaders
27
	boolean closed = false; // note: protected by loaders, package private to avoid synthetic access.
28
29
	private final AccessControlContext context;
30
31
	public static class CloseableJarURLConnection extends JarURLConnection {
32
		private final JarFile jarFile;
33
		private JarEntry entry;
34
35
		public CloseableJarURLConnection(URL url, JarFile jarFile) throws MalformedURLException {
36
			super(url);
37
			this.jarFile = jarFile;
38
		}
39
40
		/**
41
		 * @throws IOException
42
		 * Documented to avoid warning 
43
		 */
44
		public synchronized void connect() throws IOException {
45
			if (entry != null)
46
				return;
47
			entry = jarFile.getJarEntry(getEntryName());
48
		}
49
50
		public InputStream getInputStream() throws IOException {
51
			connect();
52
			return jarFile.getInputStream(entry);
53
		}
54
55
		/**
56
		 * @throws IOException
57
		 * Documented to avoid warning 
58
		 */
59
		public JarFile getJarFile() throws IOException {
60
			return jarFile;
61
		}
62
63
		public JarEntry getJarEntry() throws IOException {
64
			connect();
65
			return entry;
66
		}
67
	}
68
69
	public static class CloseableJarURLStreamHandler extends URLStreamHandler {
70
		private final JarFile jarFile;
71
72
		public CloseableJarURLStreamHandler(JarFile jarFile) {
73
			this.jarFile = jarFile;
74
		}
75
76
		protected URLConnection openConnection(URL u) throws IOException {
77
			return new CloseableJarURLConnection(u, jarFile);
78
		}
79
80
		protected void parseURL(URL u, String spec, int start, int limit) {
81
			setURL(u, JAR, null, 0, null, null, spec.substring(start, limit), null, null);
82
		}
83
	}
84
85
	public static class CloseableJarFileLoader {
86
		private final JarFile jarFile;
87
		private final Manifest manifest;
88
		private final CloseableJarURLStreamHandler jarURLStreamHandler;
89
		private final String jarFileURLPrefixString;
90
		private final ArrayList entries = new ArrayList();
91
92
		public CloseableJarFileLoader(File file) throws IOException {
93
			this.jarFile = new JarFile(file);
94
			this.manifest = jarFile.getManifest();
95
			this.jarURLStreamHandler = new CloseableJarURLStreamHandler(jarFile);
96
			this.jarFileURLPrefixString = file.toURL().toString() + BANG_SLASH;
97
			Enumeration e = jarFile.entries();
98
			while (e.hasMoreElements()) {
99
				JarEntry entry = (JarEntry) e.nextElement();
100
				if (!entry.isDirectory())
101
					entries.add(entry.getName());
102
			}
103
		}
104
105
		public URL getURL(String name) {
106
			if (entries.contains(name))
107
				try {
108
					return new URL(JAR, null, -1, jarFileURLPrefixString + name, jarURLStreamHandler);
109
				} catch (MalformedURLException e) {
110
					// ignore
111
				}
112
			return null;
113
		}
114
115
		public Manifest getManifest() {
116
			return manifest;
117
		}
118
119
		public void close() {
120
			try {
121
				jarFile.close();
122
			} catch (IOException e) {
123
				// ignore
124
			}
125
		}
126
	}
127
128
	public CloseableURLClassLoader(URL[] urls) {
129
		this(urls, ClassLoader.getSystemClassLoader());
130
	}
131
132
	public CloseableURLClassLoader(URL[] urls, ClassLoader parent) {
133
		super(excludeFileJarURLS(urls), parent);
134
		context = AccessController.getContext();
135
		for (int i = 0; i < urls.length; i++) {
136
			if (isFileJarURL(urls[i])) {
137
				loaderURLs.add(urls[i]);
138
				safeAddLoader(urls[i]);
139
			}
140
		}
141
	}
142
143
	private void safeAddLoader(URL url) {
144
		String path = url.getPath();
145
		File file = new File(path);
146
		if (file.exists()) {
147
			try {
148
				loaders.add(new CloseableJarFileLoader(file));
149
			} catch (IOException e) {
150
				// ignore
151
			}
152
		}
153
	}
154
155
	private static URL[] excludeFileJarURLS(URL[] urls) {
156
		ArrayList urlList = new ArrayList();
157
		for (int i = 0; i < urls.length; i++) {
158
			if (!isFileJarURL(urls[i]))
159
				urlList.add(urls[i]);
160
		}
161
		return (URL[]) urlList.toArray(new URL[urlList.size()]);
162
	}
163
164
	private static boolean isFileJarURL(URL url) {
165
		if (!url.getProtocol().equals("file")) //$NON-NLS-1$
166
			return false;
167
168
		String path = url.getPath();
169
		if (path != null && path.endsWith("/")) //$NON-NLS-1$
170
			return false;
171
172
		return true;
173
	}
174
175
	protected Class findClass(final String name) throws ClassNotFoundException {
176
		try {
177
			Class clazz = (Class) AccessController.doPrivileged(new PrivilegedExceptionAction() {
178
				public Object run() throws ClassNotFoundException {
179
					String resourcePath = name.replace('.', '/') + DOT_CLASS;
180
					CloseableJarFileLoader loader = null;
181
					URL resourceURL = null;
182
					synchronized (loaders) {
183
						if (closed)
184
							return null;
185
						for (Iterator iterator = loaders.iterator(); iterator.hasNext();) {
186
							loader = (CloseableJarFileLoader) iterator.next();
187
							resourceURL = loader.getURL(resourcePath);
188
							if (resourceURL != null)
189
								break;
190
						}
191
					}
192
					if (resourceURL != null) {
193
						try {
194
							return defineClass(name, resourceURL, loader.getManifest());
195
						} catch (IOException e) {
196
							throw new ClassNotFoundException(name, e);
197
						}
198
					}
199
					return null;
200
				}
201
			}, context);
202
			if (clazz != null)
203
				return clazz;
204
		} catch (PrivilegedActionException e) {
205
			throw (ClassNotFoundException) e.getException();
206
		}
207
		return super.findClass(name);
208
	}
209
210
	// package private to avoid synthetic access.
211
	Class defineClass(String name, URL resourceURL, Manifest manifest) throws IOException {
212
		JarURLConnection connection = (JarURLConnection) resourceURL.openConnection();
213
		int lastDot = name.lastIndexOf('.');
214
		if (lastDot != -1) {
215
			String packageName = name.substring(0, lastDot + 1);
216
			Package pkg = getPackage(packageName);
217
			if (pkg != null) {
218
				checkForSealedPackage(pkg, packageName, manifest, connection.getJarFileURL());
219
			} else {
220
				definePackage(packageName, manifest, connection.getJarFileURL());
221
			}
222
		}
223
		JarEntry entry = connection.getJarEntry();
224
		byte[] bytes = new byte[(int) entry.getSize()];
225
		DataInputStream is = null;
226
		try {
227
			is = new DataInputStream(connection.getInputStream());
228
			is.readFully(bytes, 0, bytes.length);
229
			CodeSource cs = new CodeSource(connection.getJarFileURL(), entry.getCertificates());
230
			return defineClass(name, bytes, 0, bytes.length, cs);
231
		} finally {
232
			if (is != null)
233
				try {
234
					is.close();
235
				} catch (IOException e) {
236
					// ignore
237
				}
238
		}
239
	}
240
241
	private void checkForSealedPackage(Package pkg, String packageName, Manifest manifest, URL jarFileURL) {
242
		if (pkg.isSealed() && !pkg.isSealed(jarFileURL))
243
			throw new SecurityException("The package '" + packageName + "' was previously loaded and is already sealed."); //$NON-NLS-1$ //$NON-NLS-2$
244
245
		String entryPath = packageName.replace('.', '/') + "/"; //$NON-NLS-1$
246
		Attributes entryAttributes = manifest.getAttributes(entryPath);
247
		String sealed = null;
248
		if (entryAttributes != null)
249
			sealed = entryAttributes.getValue(Name.SEALED);
250
251
		if (sealed == null) {
252
			Attributes mainAttributes = manifest.getMainAttributes();
253
			if (mainAttributes != null)
254
				sealed = mainAttributes.getValue(Name.SEALED);
255
		}
256
		if (Boolean.valueOf(sealed).booleanValue())
257
			throw new SecurityException("The package '" + packageName + "' was previously loaded unsealed. Cannot seal package."); //$NON-NLS-1$ //$NON-NLS-2$
258
	}
259
260
	public URL findResource(final String name) {
261
		URL url = (URL) AccessController.doPrivileged(new PrivilegedAction() {
262
			public Object run() {
263
				synchronized (loaders) {
264
					if (closed)
265
						return null;
266
					for (Iterator iterator = loaders.iterator(); iterator.hasNext();) {
267
						CloseableJarFileLoader loader = (CloseableJarFileLoader) iterator.next();
268
						URL resourceURL = loader.getURL(name);
269
						if (resourceURL != null)
270
							return resourceURL;
271
					}
272
				}
273
				return null;
274
			}
275
		}, context);
276
		if (url != null)
277
			return url;
278
		return super.findResource(name);
279
	}
280
281
	public Enumeration findResources(final String name) throws IOException {
282
		final List resources = new ArrayList();
283
		AccessController.doPrivileged(new PrivilegedAction() {
284
			public Object run() {
285
				synchronized (loaders) {
286
					if (closed)
287
						return null;
288
					for (Iterator iterator = loaders.iterator(); iterator.hasNext();) {
289
						CloseableJarFileLoader loader = (CloseableJarFileLoader) iterator.next();
290
						URL resourceURL = loader.getURL(name);
291
						if (resourceURL != null)
292
							resources.add(resourceURL);
293
					}
294
				}
295
				return null;
296
			}
297
		}, context);
298
		Enumeration e = super.findResources(name);
299
		while (e.hasMoreElements())
300
			resources.add(e.nextElement());
301
302
		return Collections.enumeration(resources);
303
	}
304
305
	public void close() {
306
		synchronized (loaders) {
307
			if (closed)
308
				return;
309
			for (Iterator iterator = loaders.iterator(); iterator.hasNext();) {
310
				CloseableJarFileLoader loader = (CloseableJarFileLoader) iterator.next();
311
				loader.close();
312
			}
313
			closed = true;
314
		}
315
	}
316
317
	protected void addURL(URL url) {
318
		synchronized (loaders) {
319
			if (isFileJarURL(url)) {
320
				if (closed)
321
					throw new IllegalStateException("Cannot add url. CloseableURLClassLoader is closed."); //$NON-NLS-1$
322
				loaderURLs.add(url);
323
				safeAddLoader(url);
324
				return;
325
			}
326
		}
327
		super.addURL(url);
328
	}
329
330
	public URL[] getURLs() {
331
		List result = new ArrayList();
332
		synchronized (loaders) {
333
			result.addAll(loaderURLs);
334
		}
335
		result.addAll(Arrays.asList(super.getURLs()));
336
		return (URL[]) result.toArray(new URL[result.size()]);
337
	}
338
}

Return to bug 190279