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

Return to bug 190279