Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: e37e2670b1645c7495afef0a578f8629f061d734 (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
/*******************************************************************************
 * Copyright (c) 2010, 2016 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.weaving;

import java.util.*;
import org.eclipse.osgi.internal.framework.EquinoxContainer;
import org.eclipse.osgi.internal.hookregistry.ClassLoaderHook;
import org.eclipse.osgi.internal.loader.BundleLoader;
import org.eclipse.osgi.internal.loader.ModuleClassLoader;
import org.eclipse.osgi.internal.loader.classpath.ClasspathEntry;
import org.eclipse.osgi.internal.loader.classpath.ClasspathManager;
import org.eclipse.osgi.internal.serviceregistry.ServiceRegistry;
import org.eclipse.osgi.storage.bundlefile.BundleEntry;
import org.osgi.framework.*;

public class WeavingHookConfigurator extends ClassLoaderHook {
	// holds the map of black listed hooks.  Use weak map to avoid pinning and simplify cleanup.
	private final Map<ServiceRegistration<?>, Boolean> blackList = Collections.synchronizedMap(new WeakHashMap<ServiceRegistration<?>, Boolean>());
	// holds the stack of WovenClass objects currently being used to define classes
	private final ThreadLocal<List<WovenClassImpl>> wovenClassStack = new ThreadLocal<>();

	private final EquinoxContainer container;

	public WeavingHookConfigurator(EquinoxContainer container) {
		this.container = container;
	}

	private ServiceRegistry getRegistry() {
		return container.getServiceRegistry();
	}

	public byte[] processClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) {
		ServiceRegistry registry = getRegistry();
		if (registry == null)
			return null; // no registry somehow we are loading classes before the registry has been created
		ModuleClassLoader classLoader = manager.getClassLoader();
		BundleLoader loader = classLoader.getBundleLoader();
		// create a woven class object and add it to the thread local stack
		WovenClassImpl wovenClass = new WovenClassImpl(name, classbytes, entry, classpathEntry, loader, container, blackList);
		List<WovenClassImpl> wovenClasses = wovenClassStack.get();
		if (wovenClasses == null) {
			wovenClasses = new ArrayList<>(6);
			wovenClassStack.set(wovenClasses);
		}
		wovenClasses.add(wovenClass);
		// call the weaving hooks
		try {
			return wovenClass.callHooks();
		} catch (Throwable t) {
			ServiceRegistration<?> errorHook = wovenClass.getErrorHook();
			Bundle errorBundle = errorHook != null ? errorHook.getReference().getBundle() : manager.getGeneration().getRevision().getBundle();
			container.getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, errorBundle, t);
			// fail hard with a class loading error
			ClassFormatError error = new ClassFormatError("Unexpected error from weaving hook."); //$NON-NLS-1$
			error.initCause(t);
			throw error;
		}
	}

	public void recordClassDefine(String name, Class<?> clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) {
		// here we assume the stack contans a woven class with the same name as the class we are defining.
		List<WovenClassImpl> wovenClasses = wovenClassStack.get();
		if (wovenClasses == null || wovenClasses.size() == 0)
			return;
		WovenClassImpl wovenClass = wovenClasses.remove(wovenClasses.size() - 1);
		// inform the woven class about the class that was defined.
		wovenClass.setWeavingCompleted(clazz);
	}

}

Back to the top