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

org.hotswap.agent.plugin.proxy.MultistepProxyTransformer Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
package org.hotswap.agent.plugin.proxy;

import java.util.Map;

import org.hotswap.agent.javassist.ClassPool;
import org.hotswap.agent.logging.AgentLogger;

/**
 * Multistep proxy redefinition strategy. Uses Instrumentation to schedule and run next steps.
 * 
 * @author Erki Ehtla
 * 
 */
public abstract class MultistepProxyTransformer extends AbstractProxyTransformer {
	private static final AgentLogger LOGGER = AgentLogger.getLogger(MultistepProxyTransformer.class);
	public static boolean addThirdStep = false;
	
	protected byte[] classfileBuffer;
	protected Map, TransformationState> transformationStates;
	protected ProxyBytecodeGenerator generator;
	protected ProxyBytecodeTransformer transformer;
	
	public MultistepProxyTransformer(Class classBeingRedefined, ClassPool classPool, byte[] classfileBuffer,
			Map, TransformationState> transformationStates) {
		super(classBeingRedefined, classPool);
		this.classPool = classPool;
		this.transformationStates = transformationStates;
		this.classfileBuffer = classfileBuffer;
	}
	
	/**
	 * Handles the current transformation state
	 * 
	 * @return
	 * @throws Exception
	 */
	public byte[] transformRedefine() throws Exception {
		switch (getTransformationstate()) {
			case NEW:
				if (!isTransformingNeeded()) {
					return classfileBuffer;
				}
				setClassAsWaiting();
				// We can't do the transformation in this event, because we can't see the changes in the class
				// definitons. Schedule a new redefinition event.
				scheduleRedefinition();
				return classfileBuffer;
			case WAITING:
				classfileBuffer = getTransformer().transform(getGenerator().generate());
				LOGGER.reload("Class '{}' has been reloaded.", classBeingRedefined.getName());
				if (addThirdStep) {
					setClassAsFinished();
					scheduleRedefinition();
				} else
					removeClassState();
				return classfileBuffer;
			case FINISHED:
				removeClassState();
				return classfileBuffer;
			default:
				throw new RuntimeException("Unhandeled TransformationState!");
		}
	}
	
	/**
	 * @return Current transformation state of the classBeingRedefined
	 */
	protected TransformationState getTransformationstate() {
		TransformationState transformationState = transformationStates.get(classBeingRedefined);
		if (transformationState == null)
			transformationState = TransformationState.NEW;
		return transformationState;
	}
	
	/**
	 * Generate new redefinition event for current classBeingRedefined
	 */
	protected void scheduleRedefinition() {
		RedefinitionScheduler.schedule(this);
	}
	
	/**
	 * Set classBeingRedefined as waiting
	 * 
	 * @return
	 */
	protected TransformationState setClassAsWaiting() {
		return transformationStates.put(classBeingRedefined, TransformationState.WAITING);
	}
	
	/**
	 * Set classBeingRedefined as finished
	 * 
	 * @return
	 */
	protected TransformationState setClassAsFinished() {
		return transformationStates.put(classBeingRedefined, TransformationState.FINISHED);
	}
	
	/**
	 * Remove any state associated with classBeingRedefined
	 * 
	 * @return
	 */
	protected TransformationState removeClassState() {
		return transformationStates.remove(classBeingRedefined);
	}
	
	/**
	 * The Class this instance is redefining
	 * 
	 * @return
	 */
	public Class getClassBeingRedefined() {
		return classBeingRedefined;
	}
	
	/**
	 * Bytecode of the Class this instance is redefining.
	 * 
	 * @return
	 */
	public byte[] getClassfileBuffer() {
		return classfileBuffer;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy