package com.jsonde.profiler;
import com.jsonde.api.Message;
import com.jsonde.api.MessageListener;
import com.jsonde.api.methodCall.MethodCallDto;
import com.jsonde.api.methodCall.MethodCallSummaryDto;
import com.jsonde.profiler.network.NetworkServerException;
import com.jsonde.util.CurrentClassGetter;
import com.jsonde.util.log.Log;
import java.lang.instrument.Instrumentation;
import java.util.Collection;
import java.util.List;
public abstract class Profiler {
public static final String CLASS_CANONICAL_NAME = Profiler.class.getCanonicalName();
private static final Log log = Log.getLog(Profiler.class);
public static final long UNDEFINED_CLASS_ID = -1;
public static final long UNDEFINED_METHOD_ID = -1;
private static volatile Profiler profiler;
public static Profiler initializeProfiler(Instrumentation instrumentation, int port) {
profiler = new ProfilerImpl(instrumentation, port);
return profiler;
}
public static void initializeProfiler(Profiler profiler) {
Profiler.profiler = profiler;
}
public static Profiler getProfiler() {
if (null == profiler) {
profiler = new ProfilerImpl();
}
return profiler;
}
public static final String ENTER_METHOD_METHOD_NAME =
"enterMethod";
public static final String ENTER_METHOD_METHOD_DESCRIPTOR =
"(JLjava/lang/Object;[Ljava/lang/Object;)V";
private static final String ENTER_METHOD_METHOD_NAME_WITH_DESCRIPTOR =
ENTER_METHOD_METHOD_NAME + ENTER_METHOD_METHOD_DESCRIPTOR;
public static void enterMethod(long methodId, Object object, Object[] arguments) {
try {
if (log.isTraceEnabled()) {
log.entering(
ENTER_METHOD_METHOD_NAME_WITH_DESCRIPTOR,
methodId,
object,
arguments
);
}
getProfiler().enterMethodImpl(methodId, object, arguments);
log.exiting(ENTER_METHOD_METHOD_NAME_WITH_DESCRIPTOR);
} catch (Throwable e) {
log.error(ENTER_METHOD_METHOD_NAME_WITH_DESCRIPTOR, e);
} finally {
log.exiting(ENTER_METHOD_METHOD_NAME_WITH_DESCRIPTOR);
}
}
public static final String ENTER_CONSTRUCTOR_METHOD_NAME =
"enterConstructor";
public static final String ENTER_CONSTRUCTOR_METHOD_DESCRIPTOR =
"(JLjava/lang/Object;[Ljava/lang/Object;)V";
private static final String ENTER_CONSTRUCTOR_METHOD_NAME_WITH_DESCRIPTOR =
ENTER_CONSTRUCTOR_METHOD_NAME + ENTER_CONSTRUCTOR_METHOD_DESCRIPTOR;
public static void enterConstructor(long methodId, Object object, Object[] arguments) {
try {
if (log.isTraceEnabled()) {
log.entering(
ENTER_CONSTRUCTOR_METHOD_NAME_WITH_DESCRIPTOR,
methodId,
object,
arguments
);
}
getProfiler().enterConstructorImpl(methodId, object, arguments);
log.exiting(ENTER_CONSTRUCTOR_METHOD_NAME_WITH_DESCRIPTOR);
} catch (Throwable e) {
log.error(ENTER_CONSTRUCTOR_METHOD_NAME_WITH_DESCRIPTOR, e);
} finally {
log.exiting(ENTER_CONSTRUCTOR_METHOD_NAME_WITH_DESCRIPTOR);
}
}
public static final String PRE_ENTER_CONSTRUCTOR_METHOD_NAME =
"preEnterConstructor";
public static final String PRE_ENTER_CONSTRUCTOR_METHOD_DESCRIPTOR =
"(J)V";
public static final String PRE_ENTER_CONSTRUCTOR_METHOD_NAME_WITH_DESCRIPTOR =
PRE_ENTER_CONSTRUCTOR_METHOD_NAME + PRE_ENTER_CONSTRUCTOR_METHOD_DESCRIPTOR;
public static void preEnterConstructor(long methodId) {
try {
if (log.isTraceEnabled()) {
log.entering(
PRE_ENTER_CONSTRUCTOR_METHOD_NAME_WITH_DESCRIPTOR,
methodId
);
}
getProfiler().preEnterConstructorImpl(methodId);
log.exiting(PRE_ENTER_CONSTRUCTOR_METHOD_NAME_WITH_DESCRIPTOR);
} catch (Throwable e) {
log.error(PRE_ENTER_CONSTRUCTOR_METHOD_NAME_WITH_DESCRIPTOR, e);
} finally {
log.exiting(PRE_ENTER_CONSTRUCTOR_METHOD_NAME_WITH_DESCRIPTOR);
}
}
public static final String LEAVE_METHOD_METHOD_NAME =
"leaveMethod";
public static final String LEAVE_METHOD_METHOD_DESCRIPTOR =
"()V";
public static final String LEAVE_METHOD_METHOD_NAME_WITH_DESCRIPTOR =
LEAVE_METHOD_METHOD_NAME + LEAVE_METHOD_METHOD_DESCRIPTOR;
public static void leaveMethod() {
try {
if (log.isTraceEnabled()) {
log.entering(LEAVE_METHOD_METHOD_NAME_WITH_DESCRIPTOR);
}
getProfiler().leaveMethodImpl(true, false, null);
log.exiting(LEAVE_METHOD_METHOD_NAME_WITH_DESCRIPTOR);
} catch (Throwable e) {
e.printStackTrace();
log.error(LEAVE_METHOD_METHOD_NAME_WITH_DESCRIPTOR, e);
} finally {
log.exiting(LEAVE_METHOD_METHOD_NAME_WITH_DESCRIPTOR);
}
}
public static final String LEAVE_METHOD_RETURN_VALUE_METHOD_NAME =
"leaveMethodReturnValue";
public static final String LEAVE_METHOD_RETURN_VALUE_METHOD_DESCRIPTOR =
"(Ljava/lang/Object;)V";
public static final String LEAVE_METHOD_RETURN_VALUE_METHOD_NAME_WITH_DESCRIPTOR =
LEAVE_METHOD_RETURN_VALUE_METHOD_NAME + LEAVE_METHOD_RETURN_VALUE_METHOD_DESCRIPTOR;
public static void leaveMethodReturnValue(Object returnValue) {
try {
if (log.isTraceEnabled()) {
log.entering(
LEAVE_METHOD_RETURN_VALUE_METHOD_NAME_WITH_DESCRIPTOR,
returnValue
);
}
getProfiler().leaveMethodImpl(false, false, returnValue);
log.exiting(LEAVE_METHOD_RETURN_VALUE_METHOD_NAME_WITH_DESCRIPTOR);
} catch (Throwable e) {
log.error(LEAVE_METHOD_RETURN_VALUE_METHOD_NAME_WITH_DESCRIPTOR, e);
} finally {
log.exiting(LEAVE_METHOD_RETURN_VALUE_METHOD_NAME_WITH_DESCRIPTOR);
}
}
public static final String LEAVE_METHOD_THROW_EXCEPTION_METHOD_NAME =
"leaveMethodThrowException";
public static final String LEAVE_METHOD_THROW_EXCEPTION_METHOD_DESCRIPTOR =
"(Ljava/lang/Throwable;)V";
public static final String LEAVE_METHOD_THROW_EXCEPTION_METHOD_NAME_WITH_DESCRIPTOR =
LEAVE_METHOD_THROW_EXCEPTION_METHOD_NAME + LEAVE_METHOD_THROW_EXCEPTION_METHOD_DESCRIPTOR;
public static void leaveMethodThrowException(Throwable throwable) {
try {
if (log.isTraceEnabled()) {
log.entering(
LEAVE_METHOD_THROW_EXCEPTION_METHOD_NAME_WITH_DESCRIPTOR,
throwable
);
}
getProfiler().leaveMethodImpl(false, true, throwable);
log.exiting(LEAVE_METHOD_THROW_EXCEPTION_METHOD_NAME_WITH_DESCRIPTOR);
} catch (Throwable e) {
log.error(LEAVE_METHOD_THROW_EXCEPTION_METHOD_NAME_WITH_DESCRIPTOR, e);
} finally {
log.exiting(LEAVE_METHOD_THROW_EXCEPTION_METHOD_NAME_WITH_DESCRIPTOR);
}
}
public static final String DESCRIBE_CLASS_METHOD_NAME =
"describeClass";
public static final String DESCRIBE_CLASS_METHOD_DESCRIPTOR =
"(J)V";
public static final String DESCRIBE_CLASS_METHOD_NAME_WITH_DESCRIPTOR =
DESCRIBE_CLASS_METHOD_NAME + DESCRIBE_CLASS_METHOD_DESCRIPTOR;
public static void describeClass(
final long methodId) {
Class clazz = new CurrentClassGetter().getCallerClass(1);
try {
if (log.isTraceEnabled()) {
log.entering(
DESCRIBE_CLASS_METHOD_NAME_WITH_DESCRIPTOR,
methodId,
clazz
);
}
getProfiler().describeClassImpl(methodId, clazz);
log.exiting(DESCRIBE_CLASS_METHOD_NAME_WITH_DESCRIPTOR);
} catch (Throwable e) {
log.error(DESCRIBE_CLASS_METHOD_NAME_WITH_DESCRIPTOR, e);
} finally {
log.exiting(DESCRIBE_CLASS_METHOD_NAME_WITH_DESCRIPTOR);
}
}
public void start() throws NetworkServerException {
Runtime.getRuntime().addShutdownHook(new Thread(
new Runnable() {
public void run() {
int threadsCount = Thread.activeCount();
Thread[] threads = new Thread[threadsCount];
Thread.enumerate(threads);
try {
for (int i = 0; i < 1000; i++) {
Thread.yield();
}
for (Thread thread : threads) {
if (Thread.currentThread() == thread || null == thread)
continue;
if (thread.isAlive()) {
thread.join(250);
}
}
if (Thread.activeCount() > 1) {
Thread.sleep(500);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("Profiler Shutdown Hook", e);
}
try {
stop();
} catch (NetworkServerException e) {
log.error("Profiler Shutdown Hook", e);
}
}
}
));
startServer();
}
public void stop() throws NetworkServerException {
stopServer();
}
protected abstract void describeClassImpl(long methodId, Class clazz);
public abstract void describeRedefinableClass(long classId, Class clazz);
protected abstract void enterMethodImpl(long methodId, Object object, Object[] arguments);
protected abstract void enterConstructorImpl(long methodId, Object object, Object[] arguments);
protected abstract void preEnterConstructorImpl(long methodId);
protected abstract void leaveMethodImpl(boolean isVoid, boolean isThrowsException, Object result);
public abstract void sendMessage(Message registerMethodMessage);
protected abstract void processMethodCall(
List<MethodCallDto> methodCallDtos,
MethodCallSummaryDto methodCallSummaryDto,
boolean complete);
public abstract long registerMethod(
long classId,
int access,
String name,
String desc,
String signature,
String[] exceptions);
public abstract long generateClassId(ClassLoader classLoader, String className);
public abstract long generateClassIdAndRegisterIfAbsent(Class clazz);
public abstract long registerClass(
int version,
int access,
String name,
String signature,
String superName,
String[] interfaces,
ClassLoader classLoader);
public abstract void startServer() throws NetworkServerException;
public abstract void stopServer() throws NetworkServerException;
public abstract void addMessageListener(MessageListener messageListener);
public abstract void removeMessageListener(MessageListener messageListener);
public abstract void redefineClass(byte[] bytecode, String className, ClassLoader classLoader);
public abstract Collection<Long> getProfilerThreadIds();
public abstract long generateMethodCallId();
}