All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.osgi.internal.weaving.WeavingHookConfigurator Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2010, 2020 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.osgi.internal.weaving;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
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.Bundle;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.ServiceRegistration;

public class WeavingHookConfigurator extends ClassLoaderHook {
	static class WovenClassContext {
		List wovenClassStack = new ArrayList<>(6);
		List processClassNameStack = new ArrayList<>(6);
	}

	// holds the map of denied hooks. Use weak map to avoid pinning and simplify
	// cleanup.
	private final Map, Boolean> deniedHooks = Collections
			.synchronizedMap(new WeakHashMap, Boolean>());
	// holds the stack of WovenClass objects currently being used to define classes
	private final ThreadLocal wovenClassContext = new ThreadLocal<>();

	private final EquinoxContainer container;

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

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

	@Override
	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,
				deniedHooks);
		WovenClassContext context = wovenClassContext.get();
		if (context == null) {
			context = new WovenClassContext();
			wovenClassContext.set(context);
		}
		context.wovenClassStack.add(wovenClass);
		// If we detect recursion for the same class name then we will not call the
		// weaving hooks for the second request to load.
		// Note that this means the actual bytes that get used to define the class
		// will not have been woven at all.
		if (!context.processClassNameStack.contains(name)) {
			context.processClassNameStack.add(name);
			// 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;
			} finally {
				context.processClassNameStack.remove(name);
			}
		}
		return null;
	}

	@Override
	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.
		WovenClassContext context = wovenClassContext.get();
		if (context == null || context.wovenClassStack.size() == 0)
			return;
		WovenClassImpl wovenClass = context.wovenClassStack.remove(context.wovenClassStack.size() - 1);
		// inform the woven class about the class that was defined.
		wovenClass.setWeavingCompleted(clazz);
	}

	@Override
	public boolean isProcessClassRecursionSupported() {
		return true;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy