/* * Copyright 2001-2008 Geert Bevin <gbevin[remove] at uwyn dot com> * Licensed under the Apache License, Version 2.0 (the "License") * $Id: ContinuationsBytecodeTransformer.java 3918 2008-04-14 17:35:35Z gbevin $ */ package com.uwyn.rife.continuations.instrument; import com.uwyn.rife.asm.ClassReader; import com.uwyn.rife.asm.ClassVisitor; import com.uwyn.rife.asm.ClassWriter; import com.uwyn.rife.continuations.ContinuationConfigInstrument; import com.uwyn.rife.continuations.instrument.ContinuationDebug; import com.uwyn.rife.continuations.instrument.MetricsClassVisitor; import com.uwyn.rife.continuations.instrument.ResumableClassAdapter; import com.uwyn.rife.continuations.instrument.TypesClassVisitor; import java.util.logging.Level; /** * Abstract class that transforms the bytecode of regular classes so that * they support continuations functionalities. * * @author Geert Bevin (gbevin[remove] at uwyn dot com) * @version $Revision: 3918 $ * @since 1.6 */ public abstract class ContinuationsBytecodeTransformer { /** * Perform the class transformation. * <p>If the class doesn't implement the marker interface that is setup * in the instrumentation config, the original bytes will be returned. * * @param configInstrument the configuration for the instrumentation * @param rawBytes the raw bytes of the class to instrument * @param classname the name of the class to instrument * @return a byte array with the instrumented bytecode; or * <p>the original raw byte array if the class didn't need to be * instrumented * @throws ClassNotFoundException when an error occurs during the * inspection or transformation * @since 1.6 */ public static byte[] transformIntoResumableBytes(ContinuationConfigInstrument configInstrument, byte[] rawBytes, String classname) throws ClassNotFoundException { // adapts the class on the fly byte[] resumable_bytes = null; int reader_flags = ClassReader.SKIP_FRAMES; try { ContinuationDebug.LOGGER.finest("METRICS:"); ClassReader metrics_reader = new ClassReader(rawBytes); MetricsClassVisitor metrics_visitor = new MetricsClassVisitor(configInstrument, classname); metrics_reader.accept(metrics_visitor, reader_flags); ContinuationDebug.LOGGER.finest("\n"); if (metrics_visitor.makeResumable()) { ContinuationDebug.LOGGER.finest("TYPES:"); ClassReader types_reader = new ClassReader(rawBytes); TypesClassVisitor types_visitor = new TypesClassVisitor(configInstrument, metrics_visitor, classname); types_reader.accept(types_visitor, reader_flags); ContinuationDebug.LOGGER.finest("\n"); ContinuationDebug.LOGGER.finest("SOURCE:"); ClassReader resumable_reader = new ClassReader(rawBytes); ClassWriter resumable_writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassVisitor resumable_visitor = new ResumableClassAdapter(configInstrument, metrics_visitor, types_visitor, classname, resumable_writer); resumable_reader.accept(resumable_visitor, reader_flags); resumable_bytes = resumable_writer.toByteArray(); ContinuationDebug.LOGGER.finest("\n"); ///CLOVER:OFF if (ContinuationDebug.LOGGER.isLoggable(Level.FINEST)) { ContinuationDebug.LOGGER.finest("RESULT:"); ClassReader reporting_reader = new ClassReader(resumable_bytes); ClassVisitor reporting_visitor = new ResumableClassAdapter(configInstrument, null, null, classname, null); reporting_reader.accept(reporting_visitor, reader_flags); } ///CLOVER:ON } } catch (Exception e) { throw new ClassNotFoundException(classname, e); } return resumable_bytes; } }