package com.jsonde.client; import com.jsonde.api.Message; import com.jsonde.api.MessageListener; import com.jsonde.api.function.heap.ClassHeapDataDto; import com.jsonde.api.function.heap.DumpHeapFunctionRequest; import com.jsonde.api.function.heap.DumpHeapFunctionResponse; import com.jsonde.api.methodCall.*; import com.jsonde.api.telemetry.TelemetryDataDto; import com.jsonde.api.telemetry.TelemetryDataMessage; import com.jsonde.client.dao.*; import com.jsonde.client.domain.*; import com.jsonde.client.network.NetworkClient; import com.jsonde.client.network.NetworkClientException; import com.jsonde.client.network.NetworkClientImpl; import org.h2.jdbcx.JdbcConnectionPool; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.List; import java.util.Vector; import java.util.concurrent.atomic.AtomicLong; public class Client implements MessageListener { private NetworkClient networkClient; private Vector<MethodCallListener> methodCallListeners = new Vector<MethodCallListener>(); private Vector<ClassListener> classListeners = new Vector<ClassListener>(); public void addMethodCallListener(MethodCallListener methodCallListener) { methodCallListeners.add(methodCallListener); } public void addClassListener(ClassListener classListener) { classListeners.add(classListener); } private void fireMethodCallEvent(MethodCall methodCall) { for (MethodCallListener listener : methodCallListeners) { listener.onMethodCall(methodCall); } } private void fireRegisterClassEvent(Clazz clazz) { for (ClassListener classListener : classListeners) { classListener.onRegisterClass(clazz); } } public void loadMethodCalls() { try { for (TopMethodCall topMethodCall : DaoFactory.getTopMethodCallDao().getAll()) { fireMethodCallEvent( DaoFactory.getMethodCallDao().get(topMethodCall.getMethodCallId()) ); } } catch (DaoException e) { e.printStackTrace(); } } public void dumpHeap() { try { DumpHeapFunctionResponse dumpHeapFunctionResponse = networkClient.invokeFunction(new DumpHeapFunctionRequest()); for (ClassHeapDataDto classHeapDataDto : dumpHeapFunctionResponse.getClassHeapDataDtos()) { Method method = DaoFactory.getMethodDao().get(classHeapDataDto.getConstructorId()); long classId = method.getClassId(); ClazzDao clazzDao = DaoFactory.getClazzDao(); Clazz clazz = clazzDao.get(classId); clazz.setCreateCounter(classHeapDataDto.getCreateCounter()); clazz.setCollectCounter(classHeapDataDto.getCollectCounter()); clazz.setTotalCurrentSize(classHeapDataDto.getTotalCurrentSize()); clazzDao.update(clazz); } } catch (InterruptedException e) { e.printStackTrace(); } catch (DaoException e) { e.printStackTrace(); } } private final boolean online; private final JdbcConnectionPool jdbcConnectionPool; private final static String DB_CONNECTION_MODIFIERS = "LOCK_MODE=0;LOG=0;UNDO_LOG=0;CACHE_SIZE=65536"; public Client(String databaseFileName, String address, int port) { online = true; jdbcConnectionPool = JdbcConnectionPool.create( "jdbc:h2:" + databaseFileName + ";" + DB_CONNECTION_MODIFIERS, "sa", "sa"); jdbcConnectionPool.setMaxConnections(100); jdbcConnectionPool.setLoginTimeout(0); try { DaoFactory.initialize( jdbcConnectionPool ); DaoFactory.createSchema(); } catch (DaoException e) { e.printStackTrace(); } networkClient = new NetworkClientImpl(address, port); } public Client(String databaseFileName) { online = false; jdbcConnectionPool = JdbcConnectionPool.create( "jdbc:h2:" + databaseFileName + ";" + DB_CONNECTION_MODIFIERS, "sa", "sa"); jdbcConnectionPool.setMaxConnections(100); jdbcConnectionPool.setLoginTimeout(0); try { DaoFactory.initialize( jdbcConnectionPool ); } catch (DaoException e) { e.printStackTrace(); } } public boolean isOnline() { return online; } public void start() { networkClient.addMessageListener(this); try { networkClient.start(); } catch (NetworkClientException e) { e.printStackTrace(); } } public void stop() { try { networkClient.stop(); } catch (NetworkClientException e) { e.printStackTrace(); } networkClient.removeMessageListener(this); /*try { jdbcConnectionPool.dispose(); } catch (SQLException e) { e.printStackTrace(); }*/ } public void sendMessage(Message message) { networkClient.sendMessage(message); } public long getClassCount() { try { return DaoFactory.getClazzDao().count(); } catch (DaoException e) { e.printStackTrace(); return 0; } } public void onMessage(Message message) { if (message instanceof RegisterClassMessage) { RegisterClassMessage registerClassMessage = (RegisterClassMessage) message; Clazz clazz = new Clazz(); clazz.setId(registerClassMessage.getClassId()); clazz.setName(registerClassMessage.getName()); try { DaoFactory.getClazzDao().insert(clazz); } catch (DaoException e) { e.printStackTrace(); } fireRegisterClassEvent(clazz); } else if (message instanceof RegisterMethodMessage) { RegisterMethodMessage registerMethodMessage = (RegisterMethodMessage) message; Method method = new Method(); method.setId(registerMethodMessage.getMethodId()); method.setClassId(registerMethodMessage.getClassId()); method.setName(registerMethodMessage.getName()); try { DaoFactory.getMethodDao().insert(method); } catch (DaoException e) { e.printStackTrace(); } } else if (message instanceof MethodCallMessage) { MethodCallMessage methodCallMessage = (MethodCallMessage) message; boolean complete = methodCallMessage.isComplete(); MethodCallDto[] methodCallDtos = methodCallMessage.getMethodCallDtos(); MethodCall methodCall = null; try { methodCall = DaoFactory.getMethodCallDao(). persistMethodCallDtos(methodCallDtos); } catch (DaoException e) { e.printStackTrace(); } MethodCallSummaryDto methodCallSummaryDto = methodCallMessage.getMethodCallSummaryDto(); try { DaoFactory.getMethodCallSummaryDao().processMethodCallSummaryDto(methodCallSummaryDto); } catch (DaoException e) { e.printStackTrace(); } if (complete) { createTopMethodCall(methodCall); } } else if (message instanceof TelemetryDataMessage) { TelemetryDataMessage telemetryDataMessage = (TelemetryDataMessage) message; TelemetryDataDto dto = telemetryDataMessage.getTelemetryData(); TelemetryData telemetryData = new TelemetryData(); telemetryData.setId(telemetryDataIdGenerator.getAndIncrement()); telemetryData.setTime(dto.time); { // memory telemetryData.setFreeMemory(dto.freeMemory); telemetryData.setMaxMemory(dto.maxMemory); telemetryData.setTotalMemory(dto.totalMemory); } { // class loading telemetryData.setLoadedClassCount(dto.loadedClassCount); telemetryData.setClassCount(dto.classCount); telemetryData.setUnloadedClassCount(dto.unloadedClassCount); } { // compilation telemetryData.setTotalCompilationTime(dto.totalCompilationTime); } try { DaoFactory.getTelemetryDataDao().insert(telemetryData); } catch (DaoException e) { e.printStackTrace(); } } else if (message instanceof DescribeClassMessage) { DescribeClassMessage describeClassMessage = (DescribeClassMessage) message; try { long classId; if (describeClassMessage.isClassRedefined()) { classId = describeClassMessage.getClassId(); } else { long staticConstructorMethodId = describeClassMessage.getMethodId(); Method method = DaoFactory.getMethodDao().get(staticConstructorMethodId); classId = method.getClassId(); } ClazzDao clazzDao = DaoFactory.getClazzDao(); Clazz clazz = clazzDao.get(classId); { ClazzLoaderDao clazzLoaderDao = DaoFactory.getClazzLoaderDao(); ClazzLoader clazzLoader = clazzLoaderDao.get(describeClassMessage.getClassLoaderId()); if (null == clazzLoader) { clazzLoader = new ClazzLoader(); clazzLoader.setId(describeClassMessage.getClassLoaderId()); clazzLoaderDao.insert(clazzLoader); } clazz.setClassLoaderId(clazzLoader.getId()); } { CodeSourceDao codeSourceDao = DaoFactory.getCodeSourceDao(); CodeSource codeSource; List<CodeSource> codeSources = null == describeClassMessage.getCodeLocation() ? codeSourceDao.getByCondition("source is null") : codeSourceDao.getByCondition("source = ?", describeClassMessage.getCodeLocation()); if (codeSources.isEmpty()) { codeSource = new CodeSource(); codeSource.setId(codeSourceIdGenerator.getAndIncrement()); codeSource.setSource(describeClassMessage.getCodeLocation()); codeSourceDao.insert(codeSource); } else { codeSource = codeSources.get(0); } clazz.setCodeSourceId(codeSource.getId()); } clazzDao.update(clazz); } catch (DaoException e) { e.printStackTrace(); } } } private void createTopMethodCall(MethodCall methodCall) { //todo move this logic to thread local profiler TopMethodCallBuilder builder = new TopMethodCallBuilder(); try { builder.visitMethodCall(methodCall); } catch (DaoException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { TopMethodCallDao topMethodCallDao = DaoFactory.getTopMethodCallDao(); List<TopMethodCall> topMethodCalls = topMethodCallDao.getByCondition( "HASHCODE = ? AND COUNT = ?", builder.getHashCode(), builder.getCount()); if (0 == topMethodCalls.size()) { fireMethodCallEvent(methodCall); TopMethodCall topMethodCall = new TopMethodCall(); topMethodCall.setId(topMethodCallIdGenerator.getAndIncrement()); topMethodCall.setMethodCallId(methodCall.getId()); topMethodCall.setHashCode(builder.getHashCode()); topMethodCall.setCount(builder.getCount()); topMethodCallDao.insert(topMethodCall); } } catch (DaoException e) { e.printStackTrace(); } } private static class TopMethodCallBuilder { private int hashCode; private ByteArrayOutputStream outputStream; private int count; private TopMethodCallBuilder() { hashCode = 1; outputStream = new ByteArrayOutputStream(); } public void visitMethodCall(MethodCall methodCall) throws IOException, DaoException { count++; writeByte(0); long value = methodCall.getMethodId(); byte[] bytes = new byte[8]; for (int i = 0; i < bytes.length; ++i) { int offset = (bytes.length - i - 1) * 8; bytes[i] = (byte) ((value & (0xff << offset)) >>> offset); } writeByte(bytes); for (MethodCall callee : DaoFactory.getMethodCallDao().getByCondition("CALLERID = ?", methodCall.getMethodId())) { visitMethodCall(callee); } // traverse children writeByte(1); } private void writeByte(int b) { outputStream.write(b); hashCode = 31 * hashCode + (byte) b; } private void writeByte(byte[] bs) { for (byte b : bs) writeByte(b); } public int getHashCode() { return hashCode; } public ByteArrayOutputStream getOutputStream() { return outputStream; } public int getCount() { return count; } } private AtomicLong codeSourceIdGenerator = new AtomicLong(); private AtomicLong topMethodCallIdGenerator = new AtomicLong(); private AtomicLong telemetryDataIdGenerator = new AtomicLong(); }