Skip to main content
summaryrefslogtreecommitdiffstats
blob: 7e2e4f848d4618dc5bc6bea9b8dc4f74e7967745 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*******************************************************************************
 * Copyright (c) 2005, 2011 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.osgi.internal.baseadaptor;

import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.*;
import java.security.cert.Certificate;
import java.util.*;
import org.eclipse.osgi.baseadaptor.BaseData;
import org.eclipse.osgi.baseadaptor.bundlefile.*;
import org.eclipse.osgi.baseadaptor.loader.*;
import org.eclipse.osgi.framework.adaptor.*;
import org.eclipse.osgi.framework.debug.Debug;
import org.eclipse.osgi.framework.internal.core.FrameworkProperties;
import org.eclipse.osgi.signedcontent.SignedContent;
import org.eclipse.osgi.signedcontent.SignerInfo;
import org.osgi.framework.Bundle;

/**
 * The default implementation of <code>BaseClassLoader</code>.  This implementation extends
 * <code>ClassLoader</code>.
 * @see BaseClassLoader
 * @see ClasspathManager
 */
public class DefaultClassLoader extends ClassLoader implements ParallelClassLoader {
	/**
	 * A PermissionCollection for AllPermissions; shared across all ProtectionDomains when security is disabled
	 */
	protected static final PermissionCollection ALLPERMISSIONS;
	private final static String CLASS_CERTIFICATE_SUPPORT = "osgi.support.class.certificate"; //$NON-NLS-1$
	private final static String CLASS_LOADER_TYPE = "osgi.classloader.type"; //$NON-NLS-1$
	private final static String CLASS_LOADER_TYPE_PARALLEL = "parallel"; //$NON-NLS-1$
	private static final boolean CLASS_CERTIFICATE;
	private static final boolean PARALLEL_CAPABLE;
	@SuppressWarnings("unchecked")
	private static final Enumeration<URL> EMPTY_ENUMERATION = Collections.enumeration(Collections.EMPTY_LIST);

	static {
		CLASS_CERTIFICATE = Boolean.valueOf(FrameworkProperties.getProperty(CLASS_CERTIFICATE_SUPPORT, "true")).booleanValue(); //$NON-NLS-1$
		AllPermission allPerm = new AllPermission();
		ALLPERMISSIONS = allPerm.newPermissionCollection();
		if (ALLPERMISSIONS != null)
			ALLPERMISSIONS.add(allPerm);
		boolean typeParallel = CLASS_LOADER_TYPE_PARALLEL.equals(FrameworkProperties.getProperty(CLASS_LOADER_TYPE, CLASS_LOADER_TYPE_PARALLEL));
		boolean parallelCapable = false;
		try {
			if (typeParallel) {
				Method parallelCapableMetod = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable", (Class[]) null); //$NON-NLS-1$
				parallelCapableMetod.setAccessible(true);
				parallelCapable = ((Boolean) parallelCapableMetod.invoke(null, (Object[]) null)).booleanValue();
			}
		} catch (Throwable e) {
			// must do everything to avoid failing in clinit
			parallelCapable = false;
		}
		PARALLEL_CAPABLE = parallelCapable;
	}

	protected ClassLoaderDelegate delegate;
	protected ProtectionDomain domain;
	// Note that PDE has internal dependency on this field type/name (bug 267238)
	protected ClasspathManager manager;

	/**
	 * Constructs a new DefaultClassLoader.
	 * @param parent the parent classloader
	 * @param delegate the delegate for this classloader
	 * @param domain the domain for this classloader
	 * @param bundledata the bundledata for this classloader
	 * @param classpath the classpath for this classloader
	 */
	public DefaultClassLoader(ClassLoader parent, ClassLoaderDelegate delegate, ProtectionDomain domain, BaseData bundledata, String[] classpath) {
		super(parent);
		this.delegate = delegate;
		this.domain = domain;
		this.manager = new ClasspathManager(bundledata, classpath, this);
	}

	/**
	 * Loads a class for the bundle.  First delegate.findClass(name) is called.
	 * The delegate will query the system class loader, bundle imports, bundle
	 * local classes, bundle hosts and fragments.  The delegate will call 
	 * BundleClassLoader.findLocalClass(name) to find a class local to this 
	 * bundle.  
	 * @param name the name of the class to load.
	 * @param resolve indicates whether to resolve the loaded class or not.
	 * @return The Class object.
	 * @throws ClassNotFoundException if the class is not found.
	 */
	protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
		if (Debug.DEBUG_LOADER)
			Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
		try {
			// Just ask the delegate.  This could result in findLocalClass(name) being called.
			Class<?> clazz = delegate.findClass(name);
			// resolve the class if asked to.
			if (resolve)
				resolveClass(clazz);
			return (clazz);
		} catch (Error e) {
			if (Debug.DEBUG_LOADER) {
				Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ") failed."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				Debug.printStackTrace(e);
			}
			throw e;
		} catch (ClassNotFoundException e) {
			// If the class is not found do not try to look for it locally.
			// The delegate would have already done that for us.
			if (Debug.DEBUG_LOADER) {
				Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ") failed."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				Debug.printStackTrace(e);
			}
			throw e;
		}
	}

	/**
	 * Gets a resource for the bundle.  First delegate.findResource(name) is 
	 * called. The delegate will query the system class loader, bundle imports,
	 * bundle local resources, bundle hosts and fragments.  The delegate will 
	 * call BundleClassLoader.findLocalResource(name) to find a resource local 
	 * to this bundle.  
	 * @param name The resource path to get.
	 * @return The URL of the resource or null if it does not exist.
	 */
	public URL getResource(String name) {
		if (Debug.DEBUG_LOADER) {
			Debug.println("BundleClassLoader[" + delegate + "].getResource(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		}

		URL url = delegate.findResource(name);
		if (url != null)
			return (url);

		if (Debug.DEBUG_LOADER) {
			Debug.println("BundleClassLoader[" + delegate + "].getResource(" + name + ") failed."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		}

		return (null);
	}

	/**
	 * Gets resources for the bundle.  First delegate.findResources(name) is
	 * called. The delegate will query the system class loader, bundle imports,
	 * bundle local resources, bundle hosts and fragments.  The delegate will
	 * call BundleClassLoader.findLocalResources(name) to find a resource local
	 * to this bundle.
	 * @param name The resource path to get.
	 * @return The Enumeration of the resource URLs.
	 */
	public Enumeration<URL> getResources(String name) throws IOException {
		if (Debug.DEBUG_LOADER) {
			Debug.println("BundleClassLoader[" + delegate + "].getResources(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		}
		Enumeration<URL> result = delegate.findResources(name);
		if (Debug.DEBUG_LOADER) {
			if (result == null || !result.hasMoreElements()) {
				Debug.println("BundleClassLoader[" + delegate + "].getResources(" + name + ") failed."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
			}
		}
		return result;
	}

	/**
	 * Finds a library for this bundle.  Simply calls 
	 * manager.findLibrary(libname) to find the library.
	 * @param libname The library to find.
	 * @return The absolution path to the library or null if not found
	 */
	protected String findLibrary(String libname) {
		// let the manager find the library for us
		return manager.findLibrary(libname);
	}

	public ProtectionDomain getDomain() {
		return domain;
	}

	public ClasspathEntry createClassPathEntry(BundleFile bundlefile, ProtectionDomain cpDomain) {
		return new ClasspathEntry(bundlefile, createProtectionDomain(bundlefile, cpDomain));
	}

	public Class<?> defineClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry) {
		return defineClass(name, classbytes, 0, classbytes.length, classpathEntry.getDomain());
	}

	public Class<?> publicFindLoaded(String classname) {
		return findLoadedClass(classname);
	}

	public Object publicGetPackage(String pkgname) {
		return getPackage(pkgname);
	}

	public Object publicDefinePackage(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase) {
		return definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase);
	}

	public void initialize() {
		manager.initialize();
	}

	public URL findLocalResource(String resource) {
		return manager.findLocalResource(resource);
	}

	public Enumeration<URL> findLocalResources(String resource) {
		return manager.findLocalResources(resource);
	}

	public Class<?> findLocalClass(String classname) throws ClassNotFoundException {
		return manager.findLocalClass(classname);
	}

	public void close() {
		manager.close();
	}

	public void attachFragment(BundleData sourcedata, ProtectionDomain sourcedomain, String[] sourceclasspath) {
		manager.attachFragment(sourcedata, sourcedomain, sourceclasspath);
	}

	public ClassLoaderDelegate getDelegate() {
		return delegate;
	}

	/**
	 * Creates a ProtectionDomain which uses specified BundleFile and the permissions of the baseDomain
	 * @param bundlefile The source bundlefile the domain is for.
	 * @param baseDomain The source domain.
	 * @return a ProtectionDomain which uses specified BundleFile and the permissions of the baseDomain 
	 */
	@SuppressWarnings("deprecation")
	public static ProtectionDomain createProtectionDomain(BundleFile bundlefile, ProtectionDomain baseDomain) {
		// create a protection domain which knows about the codesource for this classpath entry (bug 89904)
		try {
			// use the permissions supplied by the domain passed in from the framework
			PermissionCollection permissions;
			if (baseDomain != null)
				permissions = baseDomain.getPermissions();
			else
				// no domain specified.  Better use a collection that has all permissions
				// this is done just incase someone sets the security manager later
				permissions = ALLPERMISSIONS;
			Certificate[] certs = null;
			SignedContent signedContent = null;
			if (bundlefile instanceof BundleFileWrapperChain) {
				BundleFileWrapperChain wrapper = (BundleFileWrapperChain) bundlefile;
				while (wrapper != null && (!(wrapper.getWrapped() instanceof SignedContent)))
					wrapper = wrapper.getNext();
				signedContent = wrapper == null ? null : (SignedContent) wrapper.getWrapped();
			}
			if (CLASS_CERTIFICATE && signedContent != null && signedContent.isSigned()) {
				SignerInfo[] signers = signedContent.getSignerInfos();
				if (signers.length > 0)
					certs = signers[0].getCertificateChain();
			}
			return new BundleProtectionDomain(permissions, new CodeSource(bundlefile.getBaseFile().toURL(), certs), null);
		} catch (MalformedURLException e) {
			// Failed to create our own domain; just return the baseDomain
			return baseDomain;
		}
	}

	public ClasspathManager getClasspathManager() {
		return manager;
	}

	public Bundle getBundle() {
		return manager.getBaseData().getBundle();
	}

	public boolean isParallelCapable() {
		return PARALLEL_CAPABLE;
	}

	public List<URL> findEntries(String path, String filePattern, int options) {
		return manager.findEntries(path, filePattern, options);
	}

	public Collection<String> listResources(String path, String filePattern, int options) {
		return delegate.listResources(path, filePattern, options);
	}

	public Collection<String> listLocalResources(String path, String filePattern, int options) {
		return manager.listLocalResources(path, filePattern, options);
	}

	public String toString() {
		Bundle b = getBundle();
		StringBuffer result = new StringBuffer(super.toString());
		if (b == null)
			return result.toString();
		return result.append('[').append(b.getSymbolicName()).append(':').append(b.getVersion()).append("(id=").append(b.getBundleId()).append(")]").toString(); //$NON-NLS-1$//$NON-NLS-2$
	}
}

Back to the top