Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2013 mgm technology partners GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mgmtp.perfload.agent;
import static com.google.common.collect.Lists.newArrayListWithCapacity;
import static org.apache.commons.io.FileUtils.writeByteArrayToFile;
import static org.apache.commons.lang3.StringUtils.substringAfterLast;
import static org.apache.commons.lang3.StringUtils.substringBeforeLast;
import java.io.File;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import com.mgmtp.perfload.agent.annotations.AgentDir;
import com.mgmtp.perfload.agent.config.Config;
import com.mgmtp.perfload.agent.config.EntryPoints;
import com.mgmtp.perfload.agent.config.MethodInstrumentations;
import com.mgmtp.perfload.agent.hook.MeasuringHookMethodVisitor;
import com.mgmtp.perfload.agent.hook.ServletApiHookMethodVisitor;
/**
* @author rnaegele
*/
@Singleton
public class Transformer implements ClassFileTransformer {
// method descriptor for servlets because service method is overloaded
private static final String SERVLET_SERVICE_DESC = "(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V";
private final Config config;
private final AgentLogger logger;
private final File agentDir;
@Inject
public Transformer(final Config config, final AgentLogger logger, @AgentDir final File agentDir) {
this.config = config;
this.logger = logger;
this.agentDir = agentDir;
}
@Override
public byte[] transform(final ClassLoader loader, final String className, final Class> classBeingRedefined,
final ProtectionDomain protectionDomain, final byte[] classfileBuffer) throws IllegalClassFormatException {
final String classNameWithDots = className.replace('/', '.');
EntryPoints entryPoints = config.getEntryPoints();
final Map methodsConfig = config.getInstrumentations().get(classNameWithDots);
final boolean isFilter = entryPoints.hasFilter(classNameWithDots);
final boolean isServlet = entryPoints.hasServlet(classNameWithDots);
if (methodsConfig == null && !isFilter && !isServlet) {
// no instrumentation configured for this class
// return null, so no transformation is done
return null;
}
logger.writeln("Transforming class: " + classNameWithDots);
// flag for storing if at least one hook is weaved in
final MutableBoolean weaveFlag = new MutableBoolean();
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM4, cw) {
@Override
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature,
final String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if (mv != null) {
if (isFilter && "doFilter".equals(name)
|| isServlet && "service".equals(name) && SERVLET_SERVICE_DESC.equals(desc)) {
mv = createServletApiHookVisitor(access, name, desc, mv);
}
if (methodsConfig != null) {
MethodInstrumentations methodInstrumentations = methodsConfig.get(name);
if (methodInstrumentations != null) {
mv = createMeasuringHookVisitor(access, name, desc, mv, methodInstrumentations);
}
}
}
return mv;
}
private MethodVisitor createMeasuringHookVisitor(final int access, final String methodName, final String desc,
final MethodVisitor mv, final MethodInstrumentations methodInstrumentations) {
boolean weave = false;
if (methodInstrumentations.isEmpty()) {
// no params configured, so we just weave the hook into any method with this name
weave = true;
} else {
// weave if params match
for (List paramClassNames : methodInstrumentations) {
Type[] argumentTypes = Type.getArgumentTypes(desc);
List classNames = newArrayListWithCapacity(argumentTypes.length);
for (Type argumentType : argumentTypes) {
classNames.add(argumentType.getClassName());
}
if (classNames.equals(paramClassNames)) {
weave = true;
break;
}
}
}
if (weave) {
logger.writeln("Instrumenting method: " + classNameWithDots + "." + methodName);
weaveFlag.setValue(true);
return new MeasuringHookMethodVisitor(access, classNameWithDots, methodName, desc, mv);
}
return mv;
}
private MethodVisitor createServletApiHookVisitor(final int access, final String methodName, final String desc,
final MethodVisitor mv) {
logger.writeln("Adding servlet api hook: " + classNameWithDots + "." + methodName);
weaveFlag.setValue(true);
return new ServletApiHookMethodVisitor(access, methodName, desc, mv);
}
};
// accept the visitor in order to perform weaving
cr.accept(cv, ClassReader.EXPAND_FRAMES);
if (weaveFlag.isTrue()) {
byte[] transformedclassBytes = cw.toByteArray();
dumpTransformedClassFile(className, transformedclassBytes);
return transformedclassBytes;
}
// no transformation
return null;
}
private void dumpTransformedClassFile(final String className, final byte[] transformedclassBytes) {
String filePath = substringBeforeLast(className, ".").replace('.', '/');
String fileName = substringAfterLast(className, ".") + ".class";
File dir = new File(new File(agentDir, "classdump"), filePath);
dir.mkdirs();
File classFile = new File(dir, fileName);
try {
writeByteArrayToFile(classFile, transformedclassBytes);
} catch (IOException ex) {
logger.writeln(ex.getMessage() + "-" + classFile, ex);
}
}
}