com.amadeus.session.agent.SessionSupportTransformer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of session-agent Show documentation
Show all versions of session-agent Show documentation
JVM agent that enables session support in a JEE container.
The newest version!
package com.amadeus.session.agent;
import static com.amadeus.session.agent.SessionAgent.debug;
import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static org.objectweb.asm.Opcodes.ASM5;
import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
import java.util.HashSet;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
/**
* This class finds javax.servlet.ServletContext
and
* javax.servlet.Filter
instances and applies transformations to
* them. See {@link ServletContextAdapter} and {@link FilterAdapter} for details
* of transformations. In case when the support for Servlet 2.5 containers is
* active, HttpSessionListeners and HttpSessionAttributeListeners are also
* insrumented. See {@link ListenerAdapter}.
*/
class SessionSupportTransformer implements ClassFileTransformer {
HashSet servletContextClasses = new HashSet<>();
HashSet filterClasses = new HashSet<>();
HashSet listenerClasses = new HashSet<>();
private final boolean interceptListeners;
SessionSupportTransformer(boolean interceptListeners) {
this.interceptListeners = interceptListeners;
}
@Override
public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) {
ClassReader cr = new ClassReader(classfileBuffer);
// We assume that class can only one of servlet context, filter or listener
ServletContextCandidateFinder sh = new ServletContextCandidateFinder();
cr.accept(sh, 0);
if (sh.candidate) {
debug("Transforming ServletContext implementation %s", className);
ClassWriter cw = new ClassWriter(cr, COMPUTE_FRAMES);
ClassVisitor cv = new ServletContextAdapter(cw);
cr.accept(cv, 0);
return cw.toByteArray();
}
FilterCandidateFinder filterFinder = new FilterCandidateFinder();
cr.accept(filterFinder, 0);
if (filterFinder.candidate) {
debug("Transforming Filter implementation %s", className);
ClassWriter cw = new ClassWriter(cr, COMPUTE_FRAMES);
ClassVisitor cv = new FilterAdapter(cw);
cr.accept(cv, 0);
return cw.toByteArray();
}
return interceptListenersIfNeeded(className, cr);
}
byte[] interceptListenersIfNeeded(String className, ClassReader cr) {
if (interceptListeners) {
ListenerCandidateFinder listenerFinder = new ListenerCandidateFinder();
cr.accept(listenerFinder, 0);
if (listenerFinder.candidate) {
listenerClasses.add(className);
debug("Transforming Listener implementation %s", className);
ClassWriter cw = new ClassWriter(cr, COMPUTE_FRAMES);
ClassVisitor cv = new ListenerWithInjectCalls(cw);
cr.accept(cv, 0);
return cw.toByteArray();
}
}
return null; // NOSONAR Transformer contract requires null if no changes
}
/**
* Utility class to identify if a class is a ServletContext implementation or
* if it inherits from a ServletContext implementation.
*/
class ServletContextCandidateFinder extends ClassVisitor {
private boolean candidate;
ServletContextCandidateFinder() {
super(ASM5);
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
// First check if super class has already been identified as servlet context
if (servletContextClasses.contains(superName)) {
candidate = true;
debug("ServletContext candidate by inheritance (%s extends %s)", name, superName);
} else {
// Then find if class implements ServletContext interface
for (String iface : interfaces) {
if ("javax/servlet/ServletContext".equals(iface)) {
candidate = true;
debug("ServletContext candidate by interface implementation (%s implements %s)", name, iface);
break;
}
}
}
// If candidate is an interface, ignore it
if (candidate) {
servletContextClasses.add(name);
if ((access & Opcodes.ACC_INTERFACE) != 0) {
candidate = false;
}
}
super.visit(version, access, name, signature, superName, interfaces);
}
}
/**
* Utility class to identify if a class is a Filter implementation or if it
* inherits from a Filter implementation. Note that class
* com.amadeus.session.servlet.SessionFilter
is not a candidate
* for transformation as it already contains necessary code.
*/
class FilterCandidateFinder extends ClassVisitor {
private static final String SESSION_FILTER = "com/amadeus/session/servlet/SessionFilter";
boolean candidate;
FilterCandidateFinder() {
super(ASM5);
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
// Ignore our filter
if (!name.equals(SESSION_FILTER)) {
// Check if super class has already been identified as a filter context
if (filterClasses.contains(superName)) {
candidate = true;
debug("Filter is candidate by inheritance (%s extends %s)", name, superName);
} else {
// Then find if class implements Filter interface
for (String iface : interfaces) {
if ("javax/servlet/Filter".equals(iface)) {
candidate = true;
debug("Filter is candidate by interface implementation (%s implements %s)", name, iface);
break;
}
}
}
} else {
SessionAgent.debug("Ignoring filter ", name);
}
// If candidate is an interface, ignore it
if (candidate) {
filterClasses.add(name);
if ((access & Opcodes.ACC_INTERFACE) != 0) {
candidate = false;
}
}
super.visit(version, access, name, signature, superName, interfaces);
}
}
/**
* Utility class to identify if a class is an HttpSessionListener or
* HttpSessionAttributeListener or if it
* inherits from an implementation of those.
*/
class ListenerCandidateFinder extends ClassVisitor {
boolean candidate;
ListenerCandidateFinder() {
super(ASM5);
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
// Check if super class has already been identified as a listener
if (listenerClasses.contains(superName)) {
candidate = true;
debug("Listener is candidate by inheritance (%s extends %s)", name, superName);
} else {
for (String iface : interfaces) {
// find if class implements one of listener interfaces
if ("javax/servlet/http/HttpSessionListener".equals(iface)
|| "javax/servlet/http/HttpSessionAttributeListener".equals(iface)) {
candidate = true;
debug("Listener is candidate by interface implementation (%s implements %s)", name, iface);
break;
}
}
}
// If candidate is an interface, ignore it
if (candidate) {
listenerClasses.add(name);
if ((access & Opcodes.ACC_INTERFACE) != 0) {
candidate = false;
}
}
super.visit(version, access, name, signature, superName, interfaces);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy