Create a new entry with the given values.
+ *
+ * @param hash The code used to hash the object with
+ * @param key The key used to enter this in the table
+ * @param value The value for this key
+ * @param next A reference to the next entry in the table
+ */
+ protected Entry(int hash, int key, T value, Entry next) {
+ this.hash = hash;
+ this.key = key;
+ this.value = value;
+ this.next = next;
+ }
+ }
+
+ /**
+ * Constructs a new, empty hashtable with a default capacity and load
+ * factor, which is 20 and 0.75 respectively.
+ */
+ public IntHashMap() {
+ this(20, 0.75f);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial capacity
+ * and default load factor, which is 0.75.
+ *
+ * @param initialCapacity the initial capacity of the hashtable.
+ * @throws IllegalArgumentException if the initial capacity is less
+ * than zero.
+ */
+ public IntHashMap(int initialCapacity) {
+ this(initialCapacity, 0.75f);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial
+ * capacity and the specified load factor.
+ *
+ * @param initialCapacity the initial capacity of the hashtable.
+ * @param loadFactor the load factor of the hashtable.
+ * @throws IllegalArgumentException if the initial capacity is less
+ * than zero, or if the load factor is nonpositive.
+ */
+ public IntHashMap(int initialCapacity, float loadFactor) {
+ super();
+ if (initialCapacity < 0) {
+ throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
+ }
+ if (loadFactor <= 0) {
+ throw new IllegalArgumentException("Illegal Load: " + loadFactor);
+ }
+ if (initialCapacity == 0) {
+ initialCapacity = 1;
+ }
+
+ this.loadFactor = loadFactor;
+ table = new Entry[initialCapacity];
+ threshold = (int) (initialCapacity * loadFactor);
+ }
+
+ /**
+ * Returns the number of keys in this hashtable.
+ *
+ * @return the number of keys in this hashtable.
+ */
+ public int size() {
+ return count;
+ }
+
+ /**
+ * Tests if this hashtable maps no keys to values.
+ *
+ * @return true if this hashtable maps no keys to values;
+ * false otherwise.
+ */
+ public boolean isEmpty() {
+ return count == 0;
+ }
+
+
+ /**
+ * Returns the value to which the specified key is mapped in this map.
+ *
+ * @param key a key in the hashtable.
+ * @return the value to which the key is mapped in this hashtable;
+ * null if the key is not mapped to any value in
+ * this hashtable.
+ * @see #put(int, T)
+ */
+ public T get(int key) {
+ Entry tab[] = table;
+ int hash = key;
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ for (Entry e = tab[index]; e != null; e = e.next) {
+ if (e.hash == hash) {
+ return e.value;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Increases the capacity of and internally reorganizes this
+ * hashtable, in order to accommodate and access its entries more
+ * efficiently.
+ *
+ * This method is called automatically when the number of keys
+ * in the hashtable exceeds this hashtable's capacity and load
+ * factor.
+ */
+ protected void rehash() {
+ int oldCapacity = table.length;
+ Entry oldMap[] = table;
+
+ int newCapacity = oldCapacity * 2 + 1;
+ Entry newMap[] = new Entry[newCapacity];
+
+ threshold = (int) (newCapacity * loadFactor);
+ table = newMap;
+
+ for (int i = oldCapacity; i-- > 0;) {
+ for (Entry old = oldMap[i]; old != null;) {
+ Entry e = old;
+ old = old.next;
+
+ int index = (e.hash & 0x7FFFFFFF) % newCapacity;
+ e.next = newMap[index];
+ newMap[index] = e;
+ }
+ }
+ }
+
+ /**
+ * Maps the specified key to the specified
+ * value in this hashtable. The key cannot be
+ * null.
+ *
+ * The value can be retrieved by calling the get method
+ * with a key that is equal to the original key.
+ *
+ * @param key the hashtable key.
+ * @param value the value.
+ * @return the previous value of the specified key in this hashtable,
+ * or null if it did not have one.
+ * @throws NullPointerException if the key is null.
+ * @see #get(int)
+ */
+ public T put(int key, T value) {
+ // Makes sure the key is not already in the hashtable.
+ Entry tab[] = table;
+ int hash = key;
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ for (Entry e = tab[index]; e != null; e = e.next) {
+ if (e.hash == hash) {
+ T old = e.value;
+ e.value = value;
+ return old;
+ }
+ }
+
+ if (count >= threshold) {
+ // Rehash the table if the threshold is exceeded
+ rehash();
+
+ tab = table;
+ index = (hash & 0x7FFFFFFF) % tab.length;
+ }
+
+ // Creates the new entry.
+ Entry e = new Entry(hash, key, value, tab[index]);
+ tab[index] = e;
+ count++;
+ return null;
+ }
+
+
+
+}
+
diff --git a/src/main/java/com/nhn/pinpoint/common/JvmVersion.java b/src/main/java/com/nhn/pinpoint/common/JvmVersion.java
new file mode 100644
index 000000000..8873f4b3e
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/JvmVersion.java
@@ -0,0 +1,54 @@
+package com.nhn.pinpoint.common;
+
+/**
+ * @author hyungil.jeong
+ */
+public enum JvmVersion {
+ JAVA_5(1.5, 49),
+ JAVA_6(1.6, 50),
+ JAVA_7(1.7, 51),
+ JAVA_8(1.8, 52),
+ UNSUPPORTED(-1, -1);
+
+ private final double version;
+ private final int classVersion;
+
+ private JvmVersion(double version, int classVersion) {
+ this.version = version;
+ this.classVersion = classVersion;
+ }
+
+ public boolean onOrAfter(JvmVersion other) {
+ if (this == UNSUPPORTED || other == UNSUPPORTED) {
+ return false;
+ }
+ return this == other || this.version > other.version;
+ }
+
+ public static JvmVersion getFromVersion(String javaVersion) {
+ try {
+ double version = Double.parseDouble(javaVersion);
+ return getFromVersion(version);
+ } catch (NumberFormatException e) {
+ return UNSUPPORTED;
+ }
+ }
+
+ public static JvmVersion getFromVersion(double javaVersion) {
+ for (JvmVersion version : JvmVersion.values()) {
+ if (version.version == javaVersion) {
+ return version;
+ }
+ }
+ return JvmVersion.UNSUPPORTED;
+ }
+
+ public static JvmVersion getFromClassVersion(int classVersion) {
+ for (JvmVersion version : JvmVersion.values()) {
+ if (version.classVersion == classVersion) {
+ return version;
+ }
+ }
+ return JvmVersion.UNSUPPORTED;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/PinpointConstants.java b/src/main/java/com/nhn/pinpoint/common/PinpointConstants.java
new file mode 100644
index 000000000..638e66406
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/PinpointConstants.java
@@ -0,0 +1,12 @@
+package com.nhn.pinpoint.common;
+
+/**
+ * @author emeroad
+ */
+public final class PinpointConstants {
+
+ public static final int APPLICATION_NAME_MAX_LEN = 24;
+
+ public static final int AGENT_NAME_MAX_LEN = 24;
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/ServiceType.java b/src/main/java/com/nhn/pinpoint/common/ServiceType.java
new file mode 100644
index 000000000..3dc39c20e
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/ServiceType.java
@@ -0,0 +1,266 @@
+package com.nhn.pinpoint.common;
+
+import static com.nhn.pinpoint.common.HistogramSchema.FAST_SCHEMA;
+import static com.nhn.pinpoint.common.HistogramSchema.NORMAL_SCHEMA;
+import static com.nhn.pinpoint.common.ServiceTypeConstants.INCLUDE_DESTINATION;
+import static com.nhn.pinpoint.common.ServiceTypeConstants.RECORD_STATISTICS;
+import static com.nhn.pinpoint.common.ServiceTypeConstants.TERMINAL;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.nhn.pinpoint.common.util.RpcCodeRange;
+
+/**
+ * @author emeroad
+ * @author netspider
+ */
+public enum ServiceType {
+
+ /**
+ * 정의되지 않은 서비스 코드,
+ */
+ UNDEFINED((short) -1, "UNDEFINED", TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ /**
+ * agent가 설치되지 않은 피호출자.
+ */
+ UNKNOWN((short) 1, "UNKNOWN", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ /**
+ * 사용자
+ */
+ USER((short) 2, "USER", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ /**
+ * UNKNOWN의 그룹, UI에서만 사용함.
+ */
+ UNKNOWN_GROUP((short) 3, "UNKNOWN_GROUP", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ /**
+ * TEST의 그룹 - 테스트 실행 시 사용
+ */
+ TEST((short) 5, "TEST", !TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ /**
+ * Java applications, WAS
+ */
+ STAND_ALONE((short) 1000, "STAND_ALONE", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ TEST_STAND_ALONE((short) 1005, "TEST_STAND_ALONE", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ TOMCAT((short) 1010, "TOMCAT", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ BLOC((short) 1020, "BLOC", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ // BLOC4((short) 1030, "BLOC4", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ /**
+ * Database
+ * xxx_EXECUTE_QUERY만 server map통계정보에 집계된다.
+ */
+ // DB 2000
+ UNKNOWN_DB((short) 2050, "UNKNOWN_DB", TERMINAL, !RECORD_STATISTICS, INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ UNKNOWN_DB_EXECUTE_QUERY((short) 2051, "UNKNOWN_DB", TERMINAL, RECORD_STATISTICS, INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ MYSQL((short) 2100, "MYSQL", TERMINAL, !RECORD_STATISTICS, INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ MYSQL_EXECUTE_QUERY((short) 2101, "MYSQL", TERMINAL, RECORD_STATISTICS, INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ MSSQL((short) 2200, "MSSQL", TERMINAL, !RECORD_STATISTICS, INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ MSSQL_EXECUTE_QUERY((short) 2201, "MSSQL", TERMINAL, RECORD_STATISTICS, INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ ORACLE((short) 2300, "ORACLE", TERMINAL, !RECORD_STATISTICS, INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ ORACLE_EXECUTE_QUERY((short) 2301, "ORACLE", TERMINAL, RECORD_STATISTICS, INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ CUBRID((short) 2400, "CUBRID", TERMINAL, !RECORD_STATISTICS, INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ CUBRID_EXECUTE_QUERY((short) 2401, "CUBRID", TERMINAL, RECORD_STATISTICS, true, NORMAL_SCHEMA),
+
+ /**
+ * Internal method
+ */
+ // FIXME internal method를 여기에 넣기 애매하긴 하나.. 일단 그대로 둠.
+ INTERNAL_METHOD((short) 5000, "INTERNAL_METHOD", !TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ /**
+ * Spring framework
+ */
+ SPRING((short) 5050, "SPRING", !TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ SPRING_MVC((short) 5051, "SPRING", !TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ // FIXME 스프링 관련 코드들 어떻게 가져갈지 정리 필요
+ SPRING_ORM_IBATIS((short) 5061, "SPRING", !TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ /**
+ * xBatis
+ */
+ IBATIS((short) 5500, "IBATIS", !TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ MYBATIS((short) 5510, "MYBATIS", !TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ /**
+ * DBCP
+ */
+ DBCP((short) 6050, "DBCP", !TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+
+ /**
+ * Memory cache
+ */
+ MEMCACHED((short) 8050, "MEMCACHED", TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, FAST_SCHEMA),
+ MEMCACHED_FUTURE_GET((short) 8051, "MEMCACHED", TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, FAST_SCHEMA),
+ ARCUS((short) 8100, "ARCUS", TERMINAL, RECORD_STATISTICS, INCLUDE_DESTINATION, FAST_SCHEMA),
+ ARCUS_FUTURE_GET((short) 8101, "ARCUS", TERMINAL, !RECORD_STATISTICS, INCLUDE_DESTINATION, FAST_SCHEMA),
+ ARCUS_EHCACHE_FUTURE_GET((short) 8102, "ARCUS-EHCACHE", TERMINAL, !RECORD_STATISTICS, INCLUDE_DESTINATION, FAST_SCHEMA),
+
+ /**
+ * Connector, Client
+ */
+ HTTP_CLIENT((short) 9050, "HTTP_CLIENT", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ HTTP_CLIENT_INTERNAL((short) 9051, "HTTP_CLIENT", !TERMINAL, !RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ JDK_HTTPURLCONNECTOR((short) 9055, "JDK_HTTPCONNECTOR", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ NPC_CLIENT((short) 9060, "NPC_CLIENT", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA),
+ NIMM_CLIENT((short) 9070, "NIMM_CLIENT", !TERMINAL, RECORD_STATISTICS, !INCLUDE_DESTINATION, NORMAL_SCHEMA);
+
+ public static final short WAS_START_INDEX = 1000;
+ public static final short WAS_END_INDEX = 2000;
+
+ private final short code;
+ private final String desc;
+ private final boolean terminal;
+
+ // FIXME rpc 호출에 대해서만 통계정보를 남길 것이니, isRecordRpc()로 바꾸는건 어떨지???
+ private final boolean recordStatistics;
+
+ // DetinationId를 포함시켜 api를 출력하지 여부
+ private final boolean includeDestinationId;
+ private final HistogramSchema histogramSchema;
+
+ ServiceType(short code, String desc, boolean terminal, boolean recordStatistics, boolean includeDestinationId, HistogramSchema histogramSchema) {
+ this.code = code;
+ this.desc = desc;
+ this.terminal = terminal;
+ this.recordStatistics = recordStatistics;
+ this.includeDestinationId = includeDestinationId;
+ this.histogramSchema = histogramSchema;
+ }
+
+ // FIXME 이 메소드를 사용해서 ServiceType을 찾는건 좋지 않을 듯.
+ public static List findDesc(String desc) {
+ if (desc == null) {
+ throw new NullPointerException("desc must not be null");
+ }
+ return STATISTICS_LOOKUP_TABLE.get(desc);
+ }
+
+ public boolean isInternalMethod() {
+ return this == INTERNAL_METHOD;
+ }
+
+ public boolean isRpcClient() {
+ return RpcCodeRange.isRpcRange(code);
+ }
+
+ public boolean isIndexable() {
+ return !terminal && !isRpcClient() && code > 1000;
+ }
+
+ // FIXME rpc 호출에 대해서만 통계정보를 남길 것이니, isRecordRpc()로 바꾸는건 어떨지???
+ public boolean isRecordStatistics() {
+ return recordStatistics;
+ }
+
+ /**
+ * agent가 설치되어있지 않은 피호출자인가?
+ *
+ * @return
+ */
+ public boolean isUnknown() {
+ return this == ServiceType.UNKNOWN; // || this == ServiceType.UNKNOWN_CLOUD;
+ }
+
+ /**
+ * 사용자 또는 알 수 없는 호출자인가?
+ *
+ * @return
+ */
+ public boolean isUser() {
+ return this == ServiceType.USER;
+ }
+
+ public short getCode() {
+ return code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public boolean isTerminal() {
+ return terminal;
+ }
+
+ public boolean isIncludeDestinationId() {
+ return includeDestinationId;
+ }
+
+ public HistogramSchema getHistogramSchema() {
+ return histogramSchema;
+ }
+
+ public boolean isWas() {
+ return isWas(this.code);
+ }
+
+ public static boolean isWas(final short code) {
+ return code >= WAS_START_INDEX && code < WAS_END_INDEX;
+ }
+
+ @Override
+ public String toString() {
+ return desc;
+ }
+
+ public static ServiceType findServiceType(short code) {
+ ServiceType serviceType = CODE_LOOKUP_TABLE.get(code);
+ if (serviceType == null) {
+ return UNDEFINED;
+ //return UNKNOWN;
+ }
+ return serviceType;
+ }
+
+ private static final IntHashMap CODE_LOOKUP_TABLE = new IntHashMap(256);
+ private static final Map> STATISTICS_LOOKUP_TABLE = new HashMap>(64);
+
+ static {
+ initializeLookupTable();
+ initializeStatisticsLookupTable();
+ }
+
+ private static void initializeStatisticsLookupTable() {
+ ServiceType[] values = ServiceType.values();
+ final Map> temp = new HashMap>();
+ for (ServiceType serviceType : values) {
+ if(serviceType.isRecordStatistics()) {
+ List serviceTypeList = STATISTICS_LOOKUP_TABLE.get(serviceType.getDesc());
+ if (serviceTypeList == null) {
+ serviceTypeList = new ArrayList();
+ temp.put(serviceType.getDesc(), serviceTypeList);
+ }
+ serviceTypeList.add(serviceType);
+ }
+ }
+ // 수정하지 못하도록 한다.
+ for (Map.Entry> entry : temp.entrySet()) {
+ List serviceTypes = Collections.unmodifiableList(entry.getValue());
+ STATISTICS_LOOKUP_TABLE.put(entry.getKey(), serviceTypes);
+ }
+
+ }
+
+ private static void initializeLookupTable() {
+ ServiceType[] values = ServiceType.values();
+ for (ServiceType serviceType : values) {
+ ServiceType check = CODE_LOOKUP_TABLE.put(serviceType.code, serviceType);
+ if (check != null) {
+ throw new IllegalStateException("duplicated code found. code:" + serviceType.code);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/ServiceTypeConstants.java b/src/main/java/com/nhn/pinpoint/common/ServiceTypeConstants.java
new file mode 100644
index 000000000..f3f908aab
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/ServiceTypeConstants.java
@@ -0,0 +1,12 @@
+package com.nhn.pinpoint.common;
+
+/**
+ *
+ * @author netspider
+ *
+ */
+public class ServiceTypeConstants {
+ public static final boolean TERMINAL = true;
+ public static final boolean RECORD_STATISTICS = true;
+ public static final boolean INCLUDE_DESTINATION = true;
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/SlotType.java b/src/main/java/com/nhn/pinpoint/common/SlotType.java
new file mode 100644
index 000000000..2b6ecc9dc
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/SlotType.java
@@ -0,0 +1,6 @@
+package com.nhn.pinpoint.common;
+
+
+public enum SlotType {
+ FAST, NORMAL, SLOW, VERY_SLOW, ERROR
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/SystemPropertyKey.java b/src/main/java/com/nhn/pinpoint/common/SystemPropertyKey.java
new file mode 100644
index 000000000..9c07db3ef
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/SystemPropertyKey.java
@@ -0,0 +1,27 @@
+package com.nhn.pinpoint.common;
+
+/**
+ * @author hyungil.jeong
+ */
+public enum SystemPropertyKey {
+
+ JAVA_VERSION("java.version"),
+ JAVA_RUNTIME_VERSION("java.runtime.version"),
+ JAVA_RUNTIME_NAME("java.runtime.name"),
+ JAVA_SPECIFICATION_VERSION("java.specification.version"),
+ JAVA_CLASS_VERSION("java.class.version"),
+ JAVA_VM_NAME("java.vm.name"),
+ JAVA_VM_VERSION("java.vm.version"),
+ JAVA_VM_INFO("java.vm.info"),
+ JAVA_VM_SPECIFICATION_VERSION("java.vm.specification.version");
+
+ private final String key;
+
+ private SystemPropertyKey(String key) {
+ this.key = key;
+ }
+
+ public String getKey() {
+ return this.key;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/Version.java b/src/main/java/com/nhn/pinpoint/common/Version.java
new file mode 100644
index 000000000..a6ad2d1f1
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/Version.java
@@ -0,0 +1,4 @@
+package com.nhn.pinpoint.common;
+public final class Version {
+ public static final String VERSION = "1.0.2-SNAPSHOT";
+}
\ No newline at end of file
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/AgentInfoBo.java b/src/main/java/com/nhn/pinpoint/common/bo/AgentInfoBo.java
new file mode 100644
index 000000000..00be5a012
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/AgentInfoBo.java
@@ -0,0 +1,222 @@
+package com.nhn.pinpoint.common.bo;
+
+import com.nhn.pinpoint.common.ServiceType;
+import com.nhn.pinpoint.common.buffer.AutomaticBuffer;
+import com.nhn.pinpoint.common.buffer.Buffer;
+import com.nhn.pinpoint.common.buffer.FixedBuffer;
+import com.nhn.pinpoint.thrift.dto.TAgentInfo;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.Comparator;
+
+/**
+ * @author emeroad
+ */
+public class AgentInfoBo {
+
+ public static final Comparator AGENT_NAME_ASC_COMPARATOR = new Comparator() {
+ @Override
+ public int compare(AgentInfoBo that, AgentInfoBo other) {
+ // null 일때 상황이 애매할수 있어서 그냥 ""으로 처리함.
+ final String thatAgentId = StringUtils.defaultString(that.agentId);
+ final String otherAgentId = StringUtils.defaultString(other.agentId);
+ return thatAgentId.compareTo(otherAgentId);
+ }
+ };
+
+
+ private String hostname;
+ private String ip;
+ private String ports;
+ private String agentId;
+ private String applicationName;
+ private ServiceType serviceType;
+ private int pid;
+ private String version;
+
+ private long startTime;
+
+ private long endTimeStamp;
+ private int endStatus;
+
+ public AgentInfoBo(TAgentInfo agentInfo) {
+ if (agentInfo == null) {
+ throw new NullPointerException("agentInfo must not be null");
+ }
+ this.hostname = agentInfo.getHostname();
+ this.ip = agentInfo.getIp();
+ this.ports = agentInfo.getPorts();
+ this.agentId = agentInfo.getAgentId();
+ this.applicationName = agentInfo.getApplicationName();
+ this.serviceType = ServiceType.findServiceType(agentInfo.getServiceType());
+ this.pid = agentInfo.getPid();
+ this.version = agentInfo.getVersion();
+
+ this.startTime = agentInfo.getStartTimestamp();
+
+ this.endTimeStamp = agentInfo.getEndTimestamp();
+ this.endStatus = agentInfo.getEndStatus();
+ }
+
+ public AgentInfoBo() {
+ }
+
+ public String getIp() {
+ return ip;
+ }
+
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public String getPorts() {
+ return ports;
+ }
+
+ public void setPorts(String ports) {
+ this.ports = ports;
+ }
+
+ public String getAgentId() {
+ return agentId;
+ }
+
+ public void setAgentId(String agentId) {
+ this.agentId = agentId;
+ }
+
+ public String getApplicationName() {
+ return applicationName;
+ }
+
+ public void setApplicationName(String applicationName) {
+ this.applicationName = applicationName;
+ }
+
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ public long getEndTimeStamp() {
+ return endTimeStamp;
+ }
+
+ public int getEndStatus() {
+ return endStatus;
+ }
+
+ public int getPid() {
+ return pid;
+ }
+
+ public void setPid(int pid) {
+ this.pid = pid;
+ }
+
+ public ServiceType getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(ServiceType serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public byte[] writeValue() {
+ final Buffer buffer = new AutomaticBuffer();
+ buffer.putPrefixedString(this.getHostname());
+ buffer.putPrefixedString(this.getIp());
+ buffer.putPrefixedString(this.getPorts());
+ buffer.putPrefixedString(this.getApplicationName());
+ buffer.put(this.serviceType.getCode());
+ buffer.put(this.getPid());
+ buffer.putPrefixedString(this.getVersion());;
+
+ buffer.put(this.getStartTime());
+ buffer.put(this.getEndTimeStamp());
+ buffer.put(this.getEndStatus());
+
+ return buffer.getBuffer();
+ }
+
+ public int readValue(byte[] value) {
+ final Buffer buffer = new FixedBuffer(value);
+ this.hostname = buffer.readPrefixedString();
+ this.ip = buffer.readPrefixedString();
+ this.ports = buffer.readPrefixedString();
+ this.applicationName = buffer.readPrefixedString();
+ this.serviceType = ServiceType.findServiceType(buffer.readShort());
+ this.pid = buffer.readInt();
+ this.version = buffer.readPrefixedString();
+
+ this.startTime = buffer.readLong();
+ this.endTimeStamp = buffer.readLong();
+ this.endStatus = buffer.readInt();
+
+ return buffer.getOffset();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((agentId == null) ? 0 : agentId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ AgentInfoBo other = (AgentInfoBo) obj;
+ if (agentId == null) {
+ if (other.agentId != null)
+ return false;
+ } else if (!agentId.equals(other.agentId))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("AgentInfoBo{");
+ sb.append("hostname='").append(hostname).append('\'');
+ sb.append(", ip='").append(ip).append('\'');
+ sb.append(", ports='").append(ports).append('\'');
+ sb.append(", agentId='").append(agentId).append('\'');
+ sb.append(", applicationName='").append(applicationName).append('\'');
+ sb.append(", serviceType=").append(serviceType);
+ sb.append(", pid=").append(pid);
+ sb.append(", version='").append(version).append('\'');
+ sb.append(", startTime=").append(startTime);
+ sb.append(", endTimeStamp=").append(endTimeStamp);
+ sb.append(", endStatus=").append(endStatus);
+ sb.append('}');
+ return sb.toString();
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/AgentKeyBo.java b/src/main/java/com/nhn/pinpoint/common/bo/AgentKeyBo.java
new file mode 100644
index 000000000..4409150e5
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/AgentKeyBo.java
@@ -0,0 +1,34 @@
+package com.nhn.pinpoint.common.bo;
+
+/**
+ * @author emeroad
+ */
+public class AgentKeyBo {
+ private String agentId;
+ private String applicationName;
+ private long agentStartTime;
+
+ public String getAgentId() {
+ return agentId;
+ }
+
+ public void setAgentId(String agentId) {
+ this.agentId = agentId;
+ }
+
+ public String getApplicationName() {
+ return applicationName;
+ }
+
+ public void setApplicationName(String applicationName) {
+ this.applicationName = applicationName;
+ }
+
+ public long getAgentStartTime() {
+ return agentStartTime;
+ }
+
+ public void setAgentStartTime(long agentStartTime) {
+ this.agentStartTime = agentStartTime;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/AgentStatCpuLoadBo.java b/src/main/java/com/nhn/pinpoint/common/bo/AgentStatCpuLoadBo.java
new file mode 100644
index 000000000..b84c4ae92
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/AgentStatCpuLoadBo.java
@@ -0,0 +1,136 @@
+package com.nhn.pinpoint.common.bo;
+
+import com.nhn.pinpoint.common.buffer.AutomaticBuffer;
+import com.nhn.pinpoint.common.buffer.Buffer;
+import com.nhn.pinpoint.common.buffer.FixedBuffer;
+
+/**
+ * @author hyungil.jeong
+ */
+public class AgentStatCpuLoadBo {
+
+ private final String agentId;
+ private final long startTimestamp;
+ private final long timestamp;
+ private final double jvmCpuLoad;
+ private final double systemCpuLoad;
+
+ private AgentStatCpuLoadBo(Builder builder) {
+ this.agentId = builder.agentId;
+ this.startTimestamp = builder.startTimestamp;
+ this.timestamp = builder.timestamp;
+ this.jvmCpuLoad = builder.jvmCpuLoad;
+ this.systemCpuLoad = builder.systemCpuLoad;
+ }
+
+ public String getAgentId() {
+ return agentId;
+ }
+
+ public long getStartTimestamp() {
+ return startTimestamp;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public double getJvmCpuLoad() {
+ return jvmCpuLoad;
+ }
+
+ public double getSystemCpuLoad() {
+ return systemCpuLoad;
+ }
+
+ public byte[] writeValue() {
+ final Buffer buffer = new AutomaticBuffer();
+ buffer.putPrefixedString(this.agentId);
+ buffer.put(this.startTimestamp);
+ buffer.put(this.timestamp);
+ buffer.put(this.jvmCpuLoad);
+ buffer.put(this.systemCpuLoad);
+ return buffer.getBuffer();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("AgentStatCpuLoadBo{");
+ sb.append("agentId='").append(this.agentId).append('\'');
+ sb.append(", startTimestamp=").append(this.startTimestamp);
+ sb.append(", timestamp=").append(this.timestamp);
+ sb.append(", jvmCpuLoad=").append(this.jvmCpuLoad);
+ sb.append(", systemCpuLoad=").append(this.systemCpuLoad);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((agentId == null) ? 0 : agentId.hashCode());
+ result = prime * result + (int)(startTimestamp ^ (startTimestamp >>> 32));
+ result = prime * result + (int)(timestamp ^ (timestamp >>> 32));
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ AgentStatCpuLoadBo other = (AgentStatCpuLoadBo)obj;
+ if (agentId == null) {
+ if (other.agentId != null)
+ return false;
+ } else if (!agentId.equals(other.agentId))
+ return false;
+ if (startTimestamp != other.startTimestamp)
+ return false;
+ if (timestamp != other.timestamp)
+ return false;
+ return true;
+ }
+
+ public static class Builder {
+ private static final double UNSUPPORTED = -1.0D;
+ private final String agentId;
+ private final long startTimestamp;
+ private final long timestamp;
+ private double jvmCpuLoad = UNSUPPORTED;
+ private double systemCpuLoad = UNSUPPORTED;
+
+ public Builder(final byte[] value) {
+ final Buffer buffer = new FixedBuffer(value);
+ this.agentId = buffer.readPrefixedString();
+ this.startTimestamp = buffer.readLong();
+ this.timestamp = buffer.readLong();
+ this.jvmCpuLoad = buffer.readDouble();
+ this.systemCpuLoad = buffer.readDouble();
+ }
+
+ public Builder(String agentId, long startTimestamp, long timestamp) {
+ this.agentId = agentId;
+ this.startTimestamp = startTimestamp;
+ this.timestamp = timestamp;
+ }
+
+ public Builder jvmCpuLoad(double jvmCpuLoad) {
+ this.jvmCpuLoad = jvmCpuLoad;
+ return this;
+ }
+
+ public Builder systemCpuLoad(double systemCpuLoad) {
+ this.systemCpuLoad = systemCpuLoad;
+ return this;
+ }
+
+ public AgentStatCpuLoadBo build() {
+ return new AgentStatCpuLoadBo(this);
+ }
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/AgentStatMemoryGcBo.java b/src/main/java/com/nhn/pinpoint/common/bo/AgentStatMemoryGcBo.java
new file mode 100644
index 000000000..1fd3be4c0
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/AgentStatMemoryGcBo.java
@@ -0,0 +1,210 @@
+package com.nhn.pinpoint.common.bo;
+
+import com.nhn.pinpoint.common.buffer.AutomaticBuffer;
+import com.nhn.pinpoint.common.buffer.Buffer;
+import com.nhn.pinpoint.common.buffer.FixedBuffer;
+
+/**
+ * @author hyungil.jeong
+ */
+public class AgentStatMemoryGcBo {
+
+ private final String agentId;
+ private final long startTimestamp;
+ private final long timestamp;
+ private final String gcType;
+ private final long jvmMemoryHeapUsed;
+ private final long jvmMemoryHeapMax;
+ private final long jvmMemoryNonHeapUsed;
+ private final long jvmMemoryNonHeapMax;
+ private final long jvmGcOldCount;
+ private final long jvmGcOldTime;
+
+ private AgentStatMemoryGcBo(Builder builder) {
+ this.agentId = builder.agentId;
+ this.startTimestamp = builder.startTimestamp;
+ this.timestamp = builder.timestamp;
+ this.gcType = builder.gcType;
+ this.jvmMemoryHeapUsed = builder.jvmMemoryHeapUsed;
+ this.jvmMemoryHeapMax = builder.jvmMemoryHeapMax;
+ this.jvmMemoryNonHeapUsed = builder.jvmMemoryNonHeapUsed;
+ this.jvmMemoryNonHeapMax = builder.jvmMemoryNonHeapMax;
+ this.jvmGcOldCount = builder.jvmGcOldCount;
+ this.jvmGcOldTime = builder.jvmGcOldTime;
+ }
+
+ public String getAgentId() {
+ return agentId;
+ }
+
+ public long getStartTimestamp() {
+ return startTimestamp;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public String getGcType() {
+ return gcType;
+ }
+
+ public long getJvmMemoryHeapUsed() {
+ return jvmMemoryHeapUsed;
+ }
+
+ public long getJvmMemoryHeapMax() {
+ return jvmMemoryHeapMax;
+ }
+
+ public long getJvmMemoryNonHeapUsed() {
+ return jvmMemoryNonHeapUsed;
+ }
+
+ public long getJvmMemoryNonHeapMax() {
+ return jvmMemoryNonHeapMax;
+ }
+
+ public long getJvmGcOldCount() {
+ return jvmGcOldCount;
+ }
+
+ public long getJvmGcOldTime() {
+ return jvmGcOldTime;
+ }
+
+ public byte[] writeValue() {
+ final Buffer buffer = new AutomaticBuffer();
+ buffer.putPrefixedString(this.agentId);
+ buffer.put(this.startTimestamp);
+ buffer.put(this.timestamp);
+ buffer.putPrefixedString(this.gcType);
+ buffer.put(this.jvmMemoryHeapUsed);
+ buffer.put(this.jvmMemoryHeapMax);
+ buffer.put(this.jvmMemoryNonHeapUsed);
+ buffer.put(this.jvmMemoryNonHeapMax);
+ buffer.put(this.jvmGcOldCount);
+ buffer.put(this.jvmGcOldTime);
+ return buffer.getBuffer();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((agentId == null) ? 0 : agentId.hashCode());
+ result = prime * result + (int)(startTimestamp ^ (startTimestamp >>> 32));
+ result = prime * result + (int)(timestamp ^ (timestamp >>> 32));
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ AgentStatMemoryGcBo other = (AgentStatMemoryGcBo)obj;
+ if (agentId == null) {
+ if (other.agentId != null)
+ return false;
+ } else if (!agentId.equals(other.agentId))
+ return false;
+ if (startTimestamp != other.startTimestamp)
+ return false;
+ if (timestamp != other.timestamp)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("AgentStatMemoryGcBo{");
+ sb.append("agentId='").append(this.agentId).append('\'');
+ sb.append(", startTimestamp=").append(this.startTimestamp);
+ sb.append(", timestamp=").append(this.timestamp);
+ sb.append(", gcType='").append(this.gcType).append('\'');
+ sb.append(", jvmMemoryHeapUsed=").append(this.jvmMemoryHeapUsed);
+ sb.append(", jvmMemoryHeapMax=").append(this.jvmMemoryHeapMax);
+ sb.append(", jvmMemoryNonHeapUsed=").append(this.jvmMemoryNonHeapUsed);
+ sb.append(", jvmMemoryNonHeapMax=").append(this.jvmMemoryNonHeapMax);
+ sb.append(", jvmGcOldCount=").append(this.jvmGcOldCount);
+ sb.append(", jvmGcOldTime=").append(this.jvmGcOldTime);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public static class Builder {
+ private final String agentId;
+ private final long startTimestamp;
+ private final long timestamp;
+ private String gcType;
+ private long jvmMemoryHeapUsed;
+ private long jvmMemoryHeapMax;
+ private long jvmMemoryNonHeapUsed;
+ private long jvmMemoryNonHeapMax;
+ private long jvmGcOldCount;
+ private long jvmGcOldTime;
+
+ public Builder(final byte[] value) {
+ final Buffer buffer = new FixedBuffer(value);
+ this.agentId = buffer.readPrefixedString();
+ this.startTimestamp = buffer.readLong();
+ this.timestamp = buffer.readLong();
+ this.gcType = buffer.readPrefixedString();
+ this.jvmMemoryHeapUsed = buffer.readLong();
+ this.jvmMemoryHeapMax = buffer.readLong();
+ this.jvmMemoryNonHeapUsed = buffer.readLong();
+ this.jvmMemoryNonHeapMax = buffer.readLong();
+ this.jvmGcOldCount = buffer.readLong();
+ this.jvmGcOldTime = buffer.readLong();
+ }
+
+ public Builder(String agentId, long startTimestamp, long timestamp) {
+ this.agentId = agentId;
+ this.startTimestamp = startTimestamp;
+ this.timestamp = timestamp;
+ }
+
+ public Builder gcType(String gcType) {
+ this.gcType = gcType;
+ return this;
+ }
+
+ public Builder jvmMemoryHeapUsed(long jvmMemoryHeapUsed) {
+ this.jvmMemoryHeapUsed = jvmMemoryHeapUsed;
+ return this;
+ }
+
+ public Builder jvmMemoryHeapMax(long jvmMemoryHeapMax) {
+ this.jvmMemoryHeapMax = jvmMemoryHeapMax;
+ return this;
+ }
+
+ public Builder jvmMemoryNonHeapUsed(long jvmMemoryNonHeapUsed) {
+ this.jvmMemoryNonHeapUsed = jvmMemoryNonHeapUsed;
+ return this;
+ }
+
+ public Builder jvmMemoryNonHeapMax(long jvmMemoryNonHeapMax) {
+ this.jvmMemoryNonHeapMax = jvmMemoryNonHeapMax;
+ return this;
+ }
+
+ public Builder jvmGcOldCount(long jvmGcOldCount) {
+ this.jvmGcOldCount = jvmGcOldCount;
+ return this;
+ }
+
+ public Builder jvmGcOldTime(long jvmGcOldTime) {
+ this.jvmGcOldTime = jvmGcOldTime;
+ return this;
+ }
+
+ public AgentStatMemoryGcBo build() {
+ return new AgentStatMemoryGcBo(this);
+ }
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/AnnotationBo.java b/src/main/java/com/nhn/pinpoint/common/bo/AnnotationBo.java
new file mode 100644
index 000000000..148b90416
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/AnnotationBo.java
@@ -0,0 +1,138 @@
+package com.nhn.pinpoint.common.bo;
+
+import com.nhn.pinpoint.common.AnnotationKey;
+import com.nhn.pinpoint.thrift.dto.TAnnotation;
+import com.nhn.pinpoint.common.util.AnnotationTranscoder;
+import com.nhn.pinpoint.common.buffer.Buffer;
+
+/**
+ * @author emeroad
+ */
+public class AnnotationBo {
+
+ private static final AnnotationTranscoder transcoder = new AnnotationTranscoder();
+
+ private static final int VERSION_SIZE = 1;
+
+ private byte version = 0;
+ private long spanId;
+
+ private int key;
+
+ private byte valueType;
+ private byte[] byteValue;
+ private Object value;
+
+ public AnnotationBo() {
+ }
+
+ public AnnotationBo(TAnnotation annotation) {
+ if (annotation == null) {
+ throw new NullPointerException("annotation must not be null");
+ }
+ this.key = annotation.getKey();
+ Object value = transcoder.getMappingValue(annotation);
+ this.valueType = transcoder.getTypeCode(value);
+ this.byteValue = transcoder.encode(value, this.valueType);
+ }
+
+ public long getSpanId() {
+ return spanId;
+ }
+
+ public void setSpanId(long spanId) {
+ this.spanId = spanId;
+ }
+
+ public int getVersion() {
+ return version & 0xFF;
+ }
+
+ public void setVersion(int version) {
+ if (version < 0 || version > 255) {
+ throw new IllegalArgumentException("out of range (0~255) " + version);
+ }
+ // range 체크
+ this.version = (byte) (version & 0xFF);
+ }
+
+ public int getKey() {
+ return key;
+ }
+
+ public String getKeyName() {
+ return AnnotationKey.findAnnotationKey(this.key).getValue();
+ }
+
+ public void setKey(int key) {
+ this.key = key;
+ }
+
+
+ public int getValueType() {
+ return valueType;
+ }
+
+ public void setValueType(byte valueType) {
+ this.valueType = valueType;
+ }
+
+ public byte[] getByteValue() {
+ return byteValue;
+ }
+
+ public void setByteValue(byte[] byteValue) {
+ this.byteValue = byteValue;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ public void writeValue(Buffer buffer) {
+ // long timestamp; // required 8
+ // long duration; // optional 8
+ // int key; // required 4
+ // int valueTypeCode; // required 4
+ // ByteBuffer value; // optional 4 + buf.length
+ buffer.put(this.version);
+ buffer.putSVar(this.key);
+ buffer.put(this.valueType);
+ buffer.putPrefixedBytes(this.byteValue);
+ }
+
+// public int getBufferSize() {
+// // int key; // required 4+string.length
+// // int valueTypeCode; // required 4
+// // ByteBuffer value; // optional 4 + buf.length
+// int size = 0;
+// size += 1 + 4 + 4 + 4;
+// size += 4;
+// if (this.getByteValue() != null) {
+// size += this.getByteValue().length;
+// }
+// return size;
+// }
+
+
+ public void readValue(Buffer buffer) {
+ this.version = buffer.readByte();
+ this.key = buffer.readSVarInt();
+ this.valueType = buffer.readByte();
+ this.byteValue = buffer.readPrefixedBytes();
+ this.value = transcoder.decode(valueType, byteValue);
+ }
+
+ @Override
+ public String toString() {
+ if (value == null) {
+ return "AnnotationBo{" + "version=" + version + ", spanId=" + spanId + ", key='" + key + '\'' + ", valueType=" + valueType + '}';
+ }
+ return "AnnotationBo{" + "version=" + version + ", spanId=" + spanId + ", key='" + key + '\'' + ", value=" + value + '}';
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/AnnotationBoList.java b/src/main/java/com/nhn/pinpoint/common/bo/AnnotationBoList.java
new file mode 100644
index 000000000..540f2643c
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/AnnotationBoList.java
@@ -0,0 +1,72 @@
+package com.nhn.pinpoint.common.bo;
+
+import com.nhn.pinpoint.common.buffer.Buffer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author emeroad
+ */
+public class AnnotationBoList {
+ private List annotationBoList;
+
+ public AnnotationBoList() {
+ this.annotationBoList = new ArrayList();
+ }
+
+
+ public AnnotationBoList(int annotationBoListSize) {
+ this.annotationBoList = new ArrayList(annotationBoListSize);
+ }
+
+ public AnnotationBoList(List annotationBoList) {
+ if (annotationBoList == null) {
+ this.annotationBoList = Collections.emptyList();
+ return;
+ }
+ this.annotationBoList = annotationBoList;
+ }
+
+ public List getAnnotationBoList() {
+ return annotationBoList;
+ }
+
+ public void addAnnotationBo(AnnotationBo annotationBo) {
+ this.annotationBoList.add(annotationBo);
+ }
+
+ public void writeValue(Buffer writer){
+
+ int size = this.annotationBoList.size();
+ writer.putVar(size);
+ for (AnnotationBo annotationBo : this.annotationBoList) {
+ annotationBo.writeValue(writer);
+ }
+ }
+
+ public void readValue(Buffer reader) {
+ int size = reader.readVarInt();
+ if (size == 0) {
+ return;
+ }
+ this.annotationBoList = new ArrayList(size);
+ for (int i = 0; i < size; i++) {
+ AnnotationBo bo = new AnnotationBo();
+ bo.readValue(reader);
+ this.annotationBoList.add(bo);
+ }
+ }
+
+ public int size() {
+ return this.annotationBoList.size();
+ }
+
+
+ public void setSpanId(long spanId) {
+ for (AnnotationBo annotationBo : this.annotationBoList) {
+ annotationBo.setSpanId(spanId);
+ }
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/ApiMetaDataBo.java b/src/main/java/com/nhn/pinpoint/common/bo/ApiMetaDataBo.java
new file mode 100644
index 000000000..83a4d5a33
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/ApiMetaDataBo.java
@@ -0,0 +1,106 @@
+package com.nhn.pinpoint.common.bo;
+
+import com.nhn.pinpoint.common.util.BytesUtils;
+import com.nhn.pinpoint.common.util.RowKeyUtils;
+import com.nhn.pinpoint.common.util.TimeUtils;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import static com.nhn.pinpoint.common.PinpointConstants.AGENT_NAME_MAX_LEN;
+import static com.nhn.pinpoint.common.util.BytesUtils.LONG_BYTE_LENGTH;
+
+/**
+ * @author emeroad
+ */
+public class ApiMetaDataBo {
+ private String agentId;
+ private long startTime;
+
+ private int apiId;
+
+ private String apiInfo;
+ private int lineNumber;
+
+ public ApiMetaDataBo() {
+ }
+
+ public ApiMetaDataBo(String agentId, long startTime, int apiId) {
+ if (agentId == null) {
+ throw new NullPointerException("agentId must not be null");
+ }
+
+ this.agentId = agentId;
+ this.startTime = startTime;
+ this.apiId = apiId;
+ }
+
+ public String getAgentId() {
+ return agentId;
+ }
+
+ public void setAgentId(String agentId) {
+ this.agentId = agentId;
+ }
+
+ public int getApiId() {
+ return apiId;
+ }
+
+ public void setApiId(int apiId) {
+ this.apiId = apiId;
+ }
+
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ public String getApiInfo() {
+ return apiInfo;
+ }
+
+ public void setApiInfo(String apiInfo) {
+ this.apiInfo = apiInfo;
+ }
+
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ public void setLineNumber(int lineNumber) {
+ this.lineNumber = lineNumber;
+ }
+
+ public void readRowKey(byte[] bytes) {
+ this.agentId = Bytes.toString(bytes, 0, AGENT_NAME_MAX_LEN).trim();
+ this.startTime = TimeUtils.recoveryTimeMillis(readTime(bytes));
+ this.apiId = readKeyCode(bytes);
+ }
+
+ private static long readTime(byte[] rowKey) {
+ return BytesUtils.bytesToLong(rowKey, AGENT_NAME_MAX_LEN);
+ }
+
+ private static int readKeyCode(byte[] rowKey) {
+ return BytesUtils.bytesToInt(rowKey, AGENT_NAME_MAX_LEN + LONG_BYTE_LENGTH);
+ }
+
+ public byte[] toRowKey() {
+ return RowKeyUtils.getMetaInfoRowKey(this.agentId, this.startTime, this.apiId);
+ }
+
+ @Override
+ public String toString() {
+ return "ApiMetaDataBo{" +
+ "agentId='" + agentId + '\'' +
+ ", apiId=" + apiId +
+ ", startTime=" + startTime +
+ ", apiInfo='" + apiInfo + '\'' +
+ ", lineNumber=" + lineNumber +
+ '}';
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/IntStringStringValue.java b/src/main/java/com/nhn/pinpoint/common/bo/IntStringStringValue.java
new file mode 100644
index 000000000..9f4febe55
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/IntStringStringValue.java
@@ -0,0 +1,28 @@
+package com.nhn.pinpoint.common.bo;
+
+/**
+ * @author emeroad
+ */
+public class IntStringStringValue {
+ private final int intValue;
+ private final String stringValue1;
+ private final String stringValue2;
+
+ public IntStringStringValue(int intValue, String stringValue1, String stringValue2) {
+ this.intValue = intValue;
+ this.stringValue1 = stringValue1;
+ this.stringValue2 = stringValue2;
+ }
+
+ public int getIntValue() {
+ return intValue;
+ }
+
+ public String getStringValue1() {
+ return stringValue1;
+ }
+
+ public String getStringValue2() {
+ return stringValue2;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/IntStringValue.java b/src/main/java/com/nhn/pinpoint/common/bo/IntStringValue.java
new file mode 100644
index 000000000..2fc3e68f4
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/IntStringValue.java
@@ -0,0 +1,22 @@
+package com.nhn.pinpoint.common.bo;
+
+/**
+ * @author emeroad
+ */
+public class IntStringValue {
+ private final int intValue;
+ private final String stringValue;
+
+ public IntStringValue(int intValue, String stringValue) {
+ this.intValue = intValue;
+ this.stringValue = stringValue;
+ }
+
+ public String getStringValue() {
+ return stringValue;
+ }
+
+ public int getIntValue() {
+ return intValue;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/Span.java b/src/main/java/com/nhn/pinpoint/common/bo/Span.java
new file mode 100644
index 000000000..a7b0d3386
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/Span.java
@@ -0,0 +1,18 @@
+package com.nhn.pinpoint.common.bo;
+
+import java.util.List;
+
+import com.nhn.pinpoint.common.ServiceType;
+
+/**
+ * @author emeroad
+ */
+public interface Span {
+ ServiceType getServiceType();
+
+ String getRpc();
+
+ String getEndPoint();
+
+ List getAnnotationBoList();
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/SpanBo.java b/src/main/java/com/nhn/pinpoint/common/bo/SpanBo.java
new file mode 100644
index 000000000..cc994ac1f
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/SpanBo.java
@@ -0,0 +1,463 @@
+package com.nhn.pinpoint.common.bo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.nhn.pinpoint.common.ServiceType;
+import com.nhn.pinpoint.common.buffer.AutomaticBuffer;
+import com.nhn.pinpoint.common.buffer.OffsetFixedBuffer;
+import com.nhn.pinpoint.common.util.TransactionId;
+import com.nhn.pinpoint.common.util.TransactionIdUtils;
+import com.nhn.pinpoint.thrift.dto.TAnnotation;
+import com.nhn.pinpoint.thrift.dto.TIntStringValue;
+import com.nhn.pinpoint.thrift.dto.TSpan;
+import com.nhn.pinpoint.common.buffer.Buffer;
+
+/**
+ * @author emeroad
+ */
+public class SpanBo implements com.nhn.pinpoint.common.bo.Span {
+
+ private static final int VERSION_SIZE = 1;
+ // version 0 = prefix의 사이즈를 int로
+
+ private byte version = 0;
+
+
+// private AgentKeyBo agentKeyBo;
+ private String agentId;
+ private String applicationId;
+ private long agentStartTime;
+
+ private String traceAgentId;
+ private long traceAgentStartTime;
+ private long traceTransactionSequence;
+ private long spanId;
+ private long parentSpanId;
+
+ private long startTime;
+ private int elapsed;
+
+ private String rpc;
+ private ServiceType serviceType;
+ private String endPoint;
+ private int apiId;
+
+ private List annotationBoList;
+ private short flag; // optional
+ private int errCode;
+
+ private List spanEventBoList;
+
+ private long collectorAcceptTime;
+
+ private boolean hasException = false;
+ private int exceptionId;
+ private String exceptionMessage;
+ private String exceptionClass;
+
+
+ private String remoteAddr; // optional
+
+ public SpanBo(TSpan span) {
+ if (span == null) {
+ throw new NullPointerException("span must not be null");
+ }
+ this.agentId = span.getAgentId();
+ this.applicationId = span.getApplicationName();
+ this.agentStartTime = span.getAgentStartTime();
+
+ final TransactionId transactionId = TransactionIdUtils.parseTransactionId(span.getTransactionId());
+ this.traceAgentId = transactionId.getAgentId();
+ if (traceAgentId == null) {
+ traceAgentId = this.agentId;
+ }
+ this.traceAgentStartTime = transactionId.getAgentStartTime();
+ this.traceTransactionSequence = transactionId.getTransactionSequence();
+
+ this.spanId = span.getSpanId();
+ this.parentSpanId = span.getParentSpanId();
+
+ this.startTime = span.getStartTime();
+ this.elapsed = span.getElapsed();
+
+ this.rpc = span.getRpc();
+
+ this.serviceType = ServiceType.findServiceType(span.getServiceType());
+ this.endPoint = span.getEndPoint();
+ this.flag = span.getFlag();
+ this.apiId = span.getApiId();
+
+ this.errCode = span.getErr();
+
+ this.remoteAddr = span.getRemoteAddr();
+
+
+ // FIXME span.errCode는 span과 spanEvent의 에러를 모두 포함한 값.
+ // exceptionInfo는 span자체의 에러정보이기 때문에 errCode가 0이 아니더라도 exceptionInfo는 null일 수 있음.
+ final TIntStringValue exceptionInfo = span.getExceptionInfo();
+ if (exceptionInfo != null) {
+ this.hasException = true;
+ this.exceptionId = exceptionInfo.getIntValue();
+ this.exceptionMessage = exceptionInfo.getStringValue();
+ }
+
+ setAnnotationList(span.getAnnotations());
+ }
+
+ public SpanBo(String traceAgentId, long traceAgentStartTime, long traceTransactionSequence, long startTime, int elapsed, long spanId) {
+ if (traceAgentId == null) {
+ throw new NullPointerException("traceAgentId must not be null");
+ }
+ this.traceAgentId = traceAgentId;
+ this.traceAgentStartTime = traceAgentStartTime;
+ this.traceTransactionSequence = traceTransactionSequence;
+
+ this.startTime = startTime;
+ this.elapsed = elapsed;
+
+ this.spanId = spanId;
+ }
+
+ public SpanBo() {
+ }
+
+ public int getVersion() {
+ return version & 0xFF;
+ }
+
+ public void setVersion(int version) {
+ if (version < 0 || version > 255) {
+ throw new IllegalArgumentException("out of range (0~255)");
+ }
+ // range 체크
+ this.version = (byte) (version & 0xFF);
+ }
+
+ public String getTransactionId() {
+ return TransactionIdUtils.formatString(traceAgentId, traceAgentStartTime, traceTransactionSequence);
+ }
+
+ public String getAgentId() {
+ return agentId;
+ }
+
+ public void setAgentId(String agentId) {
+ this.agentId = agentId;
+ }
+
+ public String getApplicationId() {
+ return applicationId;
+ }
+
+ public void setApplicationId(String applicationId) {
+ this.applicationId = applicationId;
+ }
+
+ public long getAgentStartTime() {
+ return agentStartTime;
+ }
+
+ public void setAgentStartTime(long agentStartTime) {
+ this.agentStartTime = agentStartTime;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+
+ public int getElapsed() {
+ return elapsed;
+ }
+
+ public void setElapsed(int elapsed) {
+ this.elapsed = elapsed;
+ }
+
+
+ public String getTraceAgentId() {
+ return traceAgentId;
+ }
+
+ public void setTraceAgentId(String traceAgentId) {
+ this.traceAgentId = traceAgentId;
+ }
+
+ public long getTraceAgentStartTime() {
+ return traceAgentStartTime;
+ }
+
+ public void setTraceAgentStartTime(long traceAgentStartTime) {
+ this.traceAgentStartTime = traceAgentStartTime;
+ }
+
+
+ public long getTraceTransactionSequence() {
+ return traceTransactionSequence;
+ }
+
+ public void setTraceTransactionSequence(long traceTransactionSequence) {
+ this.traceTransactionSequence = traceTransactionSequence;
+ }
+
+
+ public String getRpc() {
+ return rpc;
+ }
+
+ public void setRpc(String rpc) {
+ this.rpc = rpc;
+ }
+
+
+ public long getSpanId() {
+ return spanId;
+ }
+
+ public void setSpanID(long spanId) {
+ this.spanId = spanId;
+ }
+
+ public long getParentSpanId() {
+ return parentSpanId;
+ }
+
+ public void setParentSpanId(long parentSpanId) {
+ this.parentSpanId = parentSpanId;
+ }
+
+ public int getFlag() {
+ return flag;
+ }
+
+ public void setFlag(short flag) {
+ this.flag = flag;
+ }
+
+ public String getEndPoint() {
+ return endPoint;
+ }
+
+ public void setEndPoint(String endPoint) {
+ this.endPoint = endPoint;
+ }
+
+ public int getApiId() {
+ return apiId;
+ }
+
+ public void setApiId(int apiId) {
+ this.apiId = apiId;
+ }
+
+ public List getAnnotationBoList() {
+ return annotationBoList;
+ }
+
+ public void setAnnotationList(List anoList) {
+ if (anoList == null) {
+ return;
+ }
+ List boList = new ArrayList(anoList.size());
+ for (TAnnotation ano : anoList) {
+ boList.add(new AnnotationBo(ano));
+ }
+ this.annotationBoList = boList;
+ }
+
+ public void setAnnotationBoList(List anoList) {
+ if (anoList == null) {
+ return;
+ }
+ this.annotationBoList = anoList;
+ }
+
+ public void addSpanEvent(SpanEventBo spanEventBo) {
+ if (spanEventBoList == null) {
+ spanEventBoList = new ArrayList();
+ }
+ spanEventBoList.add(spanEventBo);
+ }
+
+ public List getSpanEventBoList() {
+ return spanEventBoList;
+ }
+
+ public ServiceType getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(ServiceType serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public int getErrCode() {
+ return errCode;
+ }
+
+ public void setErrCode(int errCode) {
+ this.errCode = errCode;
+ }
+
+ public String getRemoteAddr() {
+ return remoteAddr;
+ }
+
+ public void setRemoteAddr(String remoteAddr) {
+ this.remoteAddr = remoteAddr;
+ }
+
+ public long getCollectorAcceptTime() {
+ return collectorAcceptTime;
+ }
+
+ public void setCollectorAcceptTime(long collectorAcceptTime) {
+ this.collectorAcceptTime = collectorAcceptTime;
+ }
+
+ public boolean isRoot() {
+ return -1L == parentSpanId;
+ }
+
+ public boolean hasException() {
+ return hasException;
+ }
+
+ public int getExceptionId() {
+ return exceptionId;
+ }
+
+ public String getExceptionMessage() {
+ return exceptionMessage;
+ }
+
+ public String getExceptionClass() {
+ return exceptionClass;
+ }
+
+ public void setExceptionClass(String exceptionClass) {
+ this.exceptionClass = exceptionClass;
+ }
+
+
+ // io wirte시 variable encoding을 추가함.
+ // 약 10%정도 byte 사이즈가 줄어드는 효과가 있음.
+ public byte[] writeValue() {
+ // var encoding 사용시 사이즈를 측정하기 어려움. 안되는것음 아님 편의상 그냥 자동 증가 buffer를 사용한다.
+ // 향후 더 효율적으로 메모리를 사용하게 한다면 getBufferLength를 다시 부활 시키는것을 고려한다.
+ final Buffer buffer = new AutomaticBuffer(256);
+
+ buffer.put(version);
+
+ // buffer.put(mostTraceID);
+ // buffer.put(leastTraceID);
+
+ buffer.putPrefixedString(agentId);
+ // time의 경우도 현재 시간을 기준으로 var를 사용하는게 사이즈가 더 작음 6byte를 먹음.
+ buffer.putVar(agentStartTime);
+
+ // rowkey에 들어감.
+ // buffer.put(spanID);
+ buffer.put(parentSpanId);
+
+ // 현재 시간이 기준이므로 var encoding
+ buffer.putVar(startTime);
+ buffer.putVar(elapsed);
+
+ buffer.putPrefixedString(rpc);
+ buffer.putPrefixedString(applicationId);
+ buffer.put(serviceType.getCode());
+ buffer.putPrefixedString(endPoint);
+ buffer.putPrefixedString(remoteAddr);
+ buffer.putSVar(apiId);
+
+ // errCode code는 음수가 될수 있음.
+ buffer.putSVar(errCode);
+
+ if (hasException){
+ buffer.put(true);
+ buffer.putSVar(exceptionId);
+ buffer.putPrefixedString(exceptionMessage);
+ } else {
+ buffer.put(false);
+ }
+
+ buffer.put(flag);
+
+ return buffer.getBuffer();
+ }
+
+ public int readValue(byte[] bytes, int offset) {
+ final Buffer buffer = new OffsetFixedBuffer(bytes, offset);
+
+ this.version = buffer.readByte();
+
+ // this.mostTraceID = buffer.readLong();
+ // this.leastTraceID = buffer.readLong();
+
+ this.agentId = buffer.readPrefixedString();
+ this.agentStartTime = buffer.readVarLong();
+
+ // this.spanID = buffer.readLong();
+ this.parentSpanId = buffer.readLong();
+
+ this.startTime = buffer.readVarLong();
+ this.elapsed = buffer.readVarInt();
+
+ this.rpc = buffer.readPrefixedString();
+ this.applicationId = buffer.readPrefixedString();
+ this.serviceType = ServiceType.findServiceType(buffer.readShort());
+ this.endPoint = buffer.readPrefixedString();
+ this.remoteAddr = buffer.readPrefixedString();
+ this.apiId = buffer.readSVarInt();
+
+ this.errCode = buffer.readSVarInt();
+
+ this.hasException = buffer.readBoolean();
+ if (hasException) {
+ this.exceptionId = buffer.readSVarInt();
+ this.exceptionMessage = buffer.readPrefixedString();
+ }
+
+ this.flag = buffer.readShort();
+
+ return buffer.getOffset();
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(256);
+ sb.append("SpanBo{");
+ sb.append("version=").append(version);
+ sb.append(", agentId='").append(agentId).append('\'');
+ sb.append(", applicationId='").append(applicationId).append('\'');
+ sb.append(", agentStartTime=").append(agentStartTime);
+ sb.append(", traceAgentId='").append(traceAgentId).append('\'');
+ sb.append(", traceAgentStartTime=").append(traceAgentStartTime);
+ sb.append(", traceTransactionSequence=").append(traceTransactionSequence);
+ sb.append(", spanId=").append(spanId);
+ sb.append(", parentSpanId=").append(parentSpanId);
+ sb.append(", startTime=").append(startTime);
+ sb.append(", elapsed=").append(elapsed);
+ sb.append(", rpc='").append(rpc).append('\'');
+ sb.append(", serviceType=").append(serviceType);
+ sb.append(", endPoint='").append(endPoint).append('\'');
+ sb.append(", apiId=").append(apiId);
+ sb.append(", annotationBoList=").append(annotationBoList);
+ sb.append(", flag=").append(flag);
+ sb.append(", errCode=").append(errCode);
+ sb.append(", spanEventBoList=").append(spanEventBoList);
+ sb.append(", collectorAcceptTime=").append(collectorAcceptTime);
+ sb.append(", hasException=").append(hasException);
+ sb.append(", exceptionId=").append(exceptionId);
+ sb.append(", exceptionMessage='").append(exceptionMessage).append('\'');
+ sb.append(", remoteAddr='").append(remoteAddr).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/SpanEventBo.java b/src/main/java/com/nhn/pinpoint/common/bo/SpanEventBo.java
new file mode 100644
index 000000000..f5b2b76e0
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/SpanEventBo.java
@@ -0,0 +1,460 @@
+package com.nhn.pinpoint.common.bo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.nhn.pinpoint.common.ServiceType;
+import com.nhn.pinpoint.common.buffer.AutomaticBuffer;
+import com.nhn.pinpoint.common.buffer.OffsetFixedBuffer;
+import com.nhn.pinpoint.common.util.TransactionId;
+import com.nhn.pinpoint.common.util.TransactionIdUtils;
+import com.nhn.pinpoint.thrift.dto.*;
+import com.nhn.pinpoint.common.buffer.Buffer;
+
+/**
+ * @author emeroad
+ */
+public class SpanEventBo implements Span {
+ private static final int VERSION_SIZE = 1;
+ // version 0 = prefix의 사이즈를 int로
+
+ private byte version = 0;
+
+ private String agentId;
+ private String applicationId;
+ private long agentStartTime;
+
+ private String traceAgentId;
+ private long traceAgentStartTime;
+ private long traceTransactionSequence;
+
+ private long spanId;
+ private short sequence;
+
+ private int startElapsed;
+ private int endElapsed;
+
+ private String rpc;
+ private ServiceType serviceType;
+
+ private String destinationId;
+ private String endPoint;
+ private int apiId;
+
+ private List annotationBoList;
+
+ private int depth = -1;
+ private long nextSpanId = -1;
+
+ private boolean hasException;
+ private int exceptionId;
+ private String exceptionMessage;
+ // dao에서 찾아야 함.
+ private String exceptionClass;
+
+
+ public SpanEventBo() {
+ }
+
+ public SpanEventBo(TSpan tSpan, TSpanEvent tSpanEvent) {
+ if (tSpan == null) {
+ throw new NullPointerException("tSpan must not be null");
+ }
+ if (tSpanEvent == null) {
+ throw new NullPointerException("tSpanEvent must not be null");
+ }
+
+ this.agentId = tSpan.getAgentId();
+ this.applicationId = tSpan.getApplicationName();
+ this.agentStartTime = tSpan.getAgentStartTime();
+
+ final TransactionId transactionId = TransactionIdUtils.parseTransactionId(tSpan.getTransactionId());
+ this.traceAgentId = transactionId.getAgentId();
+ if (traceAgentId == null) {
+ traceAgentId = this.agentId;
+ }
+ this.traceAgentStartTime = transactionId.getAgentStartTime();
+ this.traceTransactionSequence = transactionId.getTransactionSequence();
+
+ this.spanId = tSpan.getSpanId();
+ this.sequence = tSpanEvent.getSequence();
+
+ this.startElapsed = tSpanEvent.getStartElapsed();
+ this.endElapsed = tSpanEvent.getEndElapsed();
+
+ this.rpc = tSpanEvent.getRpc();
+ this.serviceType = ServiceType.findServiceType(tSpanEvent.getServiceType());
+
+
+ this.destinationId = tSpanEvent.getDestinationId();
+
+ this.endPoint = tSpanEvent.getEndPoint();
+ this.apiId = tSpanEvent.getApiId();
+
+ if (tSpanEvent.isSetDepth()) {
+ this.depth = tSpanEvent.getDepth();
+ }
+
+ if (tSpanEvent.isSetNextSpanId()) {
+ this.nextSpanId = tSpanEvent.getNextSpanId();
+ }
+
+ setAnnotationBoList(tSpanEvent.getAnnotations());
+
+ final TIntStringValue exceptionInfo = tSpanEvent.getExceptionInfo();
+ if (exceptionInfo != null) {
+ this.hasException = true;
+ this.exceptionId = exceptionInfo.getIntValue();
+ this.exceptionMessage = exceptionInfo.getStringValue();
+ }
+ }
+
+ public SpanEventBo(TSpanChunk spanChunk, TSpanEvent spanEvent) {
+ if (spanChunk == null) {
+ throw new NullPointerException("spanChunk must not be null");
+ }
+ if (spanEvent == null) {
+ throw new NullPointerException("spanEvent must not be null");
+ }
+
+ this.agentId = spanChunk.getAgentId();
+ this.applicationId = spanChunk.getApplicationName();
+ this.agentStartTime = spanChunk.getAgentStartTime();
+
+ final TransactionId transactionId = TransactionIdUtils.parseTransactionId(spanChunk.getTransactionId());
+ this.traceAgentId = transactionId.getAgentId();
+ if (traceAgentId == null) {
+ traceAgentId = this.agentId;
+ }
+ this.traceAgentStartTime = transactionId.getAgentStartTime();
+ this.traceTransactionSequence = transactionId.getTransactionSequence();
+
+ this.spanId = spanChunk.getSpanId();
+ this.sequence = spanEvent.getSequence();
+
+ this.startElapsed = spanEvent.getStartElapsed();
+ this.endElapsed = spanEvent.getEndElapsed();
+
+ this.rpc = spanEvent.getRpc();
+ this.serviceType = ServiceType.findServiceType(spanEvent.getServiceType());
+
+ this.destinationId = spanEvent.getDestinationId();
+
+ this.endPoint = spanEvent.getEndPoint();
+ this.apiId = spanEvent.getApiId();
+
+ if (spanEvent.isSetDepth()) {
+ this.depth = spanEvent.getDepth();
+ }
+
+ if (spanEvent.isSetNextSpanId()) {
+ this.nextSpanId = spanEvent.getNextSpanId();
+ }
+
+ setAnnotationBoList(spanEvent.getAnnotations());
+
+ final TIntStringValue exceptionInfo = spanEvent.getExceptionInfo();
+ if (exceptionInfo != null) {
+ this.hasException = true;
+ this.exceptionId = exceptionInfo.getIntValue();
+ this.exceptionMessage = exceptionInfo.getStringValue();
+ }
+ }
+
+
+
+ public byte getVersion() {
+ return version;
+ }
+
+ public void setVersion(byte version) {
+ this.version = version;
+ }
+
+ public String getAgentId() {
+ return agentId;
+ }
+
+ public void setAgentId(String agentId) {
+ this.agentId = agentId;
+ }
+
+ public long getAgentStartTime() {
+ return this.agentStartTime;
+ }
+
+ public void setAgentStartTime(long agentStartTime) {
+ this.agentStartTime = agentStartTime;
+ }
+
+ public String getTraceAgentId() {
+ return traceAgentId;
+ }
+
+ public void setTraceAgentId(String traceAgentId) {
+ this.traceAgentId = traceAgentId;
+ }
+
+ public long getTraceAgentStartTime() {
+ return traceAgentStartTime;
+ }
+
+ public void setTraceAgentStartTime(long traceAgentStartTime) {
+ this.traceAgentStartTime = traceAgentStartTime;
+ }
+
+ public long getTraceTransactionSequence() {
+ return traceTransactionSequence;
+ }
+
+ public void setTraceTransactionSequence(long traceTransactionSequence) {
+ this.traceTransactionSequence = traceTransactionSequence;
+ }
+
+ public void setSpanId(long spanId) {
+ this.spanId = spanId;
+ }
+
+ public long getSpanId() {
+ return this.spanId;
+ }
+
+ public short getSequence() {
+ return sequence;
+ }
+
+ public void setSequence(short sequence) {
+ this.sequence = sequence;
+ }
+
+ public int getStartElapsed() {
+ return startElapsed;
+ }
+
+ public void setStartElapsed(int startElapsed) {
+ this.startElapsed = startElapsed;
+ }
+
+ public int getEndElapsed() {
+ return endElapsed;
+ }
+
+ public void setEndElapsed(int endElapsed) {
+ this.endElapsed = endElapsed;
+ }
+
+ public String getRpc() {
+ return rpc;
+ }
+
+ public void setRpc(String rpc) {
+ this.rpc = rpc;
+ }
+
+ public ServiceType getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(ServiceType serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public String getEndPoint() {
+ return endPoint;
+ }
+
+ public void setEndPoint(String endPoint) {
+ this.endPoint = endPoint;
+ }
+
+ public int getApiId() {
+ return apiId;
+ }
+
+ public void setApiId(int apiId) {
+ this.apiId = apiId;
+ }
+
+ public String getDestinationId() {
+ return destinationId;
+ }
+
+ public void setDestinationId(String destinationId) {
+ this.destinationId = destinationId;
+ }
+
+
+ public List getAnnotationBoList() {
+ return annotationBoList;
+ }
+
+ public int getDepth() {
+ return depth;
+ }
+
+ public void setDepth(int depth) {
+ this.depth = depth;
+ }
+
+ public long getNextSpanId() {
+ return nextSpanId;
+ }
+
+ public void setNextSpanId(long nextSpanId) {
+ this.nextSpanId = nextSpanId;
+ }
+
+ private void setAnnotationBoList(List annotations) {
+ if (annotations == null) {
+ return;
+ }
+ List boList = new ArrayList(annotations.size());
+ for (TAnnotation ano : annotations) {
+ boList.add(new AnnotationBo(ano));
+ }
+ this.annotationBoList = boList;
+ }
+
+ public boolean hasException() {
+ return hasException;
+ }
+
+ public int getExceptionId() {
+ return exceptionId;
+ }
+
+ public String getExceptionMessage() {
+ return exceptionMessage;
+ }
+
+ public String getExceptionClass() {
+ return exceptionClass;
+ }
+
+ public void setExceptionClass(String exceptionClass) {
+ this.exceptionClass = exceptionClass;
+ }
+
+
+
+ public byte[] writeValue() {
+ final Buffer buffer = new AutomaticBuffer(512);
+
+ buffer.put(version);
+
+ // buffer.put(mostTraceID);
+ // buffer.put(leastTraceID);
+
+ buffer.putPrefixedString(agentId);
+ buffer.putPrefixedString(applicationId);
+ buffer.putVar(agentStartTime);
+
+ buffer.putVar(startElapsed);
+ buffer.putVar(endElapsed);
+ // Qualifier에서 읽어서 set하므로 필요 없음.
+ // buffer.put(sequence);
+
+ buffer.putPrefixedString(rpc);
+ buffer.put(serviceType.getCode());
+ buffer.putPrefixedString(endPoint);
+ buffer.putPrefixedString(destinationId);
+ buffer.putSVar(apiId);
+
+ buffer.putSVar(depth);
+ buffer.put(nextSpanId);
+
+ if (hasException) {
+ buffer.put(true);
+ buffer.putSVar(exceptionId);
+ buffer.putPrefixedString(exceptionMessage);
+ } else {
+ buffer.put(false);
+ }
+
+ writeAnnotation(buffer);
+
+
+ return buffer.getBuffer();
+ }
+
+
+
+ private void writeAnnotation(Buffer buffer) {
+ AnnotationBoList annotationBo = new AnnotationBoList(this.annotationBoList);
+ annotationBo.writeValue(buffer);
+ }
+
+
+ public int readValue(byte[] bytes, int offset) {
+ final Buffer buffer = new OffsetFixedBuffer(bytes, offset);
+
+ this.version = buffer.readByte();
+
+ // this.mostTraceID = buffer.readLong();
+ // this.leastTraceID = buffer.readLong();
+
+ this.agentId = buffer.readPrefixedString();
+ this.applicationId = buffer.readPrefixedString();
+ this.agentStartTime = buffer.readVarLong();
+
+ this.startElapsed = buffer.readVarInt();
+ this.endElapsed = buffer.readVarInt();
+ // Qualifier에서 읽어서 가져오므로 하지 않아도 됨.
+ // this.sequence = buffer.readShort();
+
+
+ this.rpc = buffer.readPrefixedString();
+ this.serviceType = ServiceType.findServiceType(buffer.readShort());
+ this.endPoint = buffer.readPrefixedString();
+ this.destinationId = buffer.readPrefixedString();
+ this.apiId = buffer.readSVarInt();
+
+ this.depth = buffer.readSVarInt();
+ this.nextSpanId = buffer.readLong();
+
+ this.hasException = buffer.readBoolean();
+ if (hasException) {
+ this.exceptionId = buffer.readSVarInt();
+ this.exceptionMessage = buffer.readPrefixedString();
+ }
+
+ this.annotationBoList = readAnnotation(buffer);
+ return buffer.getOffset();
+ }
+
+ private List readAnnotation(Buffer buffer) {
+ AnnotationBoList annotationBoList = new AnnotationBoList();
+ annotationBoList.readValue(buffer);
+ return annotationBoList.getAnnotationBoList();
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder(256);
+ sb.append("SpanEventBo{");
+ sb.append("version=").append(version);
+ sb.append(", agentId='").append(agentId).append('\'');
+ sb.append(", applicationId='").append(applicationId).append('\'');
+ sb.append(", agentStartTime=").append(agentStartTime);
+ sb.append(", traceAgentId='").append(traceAgentId).append('\'');
+ sb.append(", traceAgentStartTime=").append(traceAgentStartTime);
+ sb.append(", traceTransactionSequence=").append(traceTransactionSequence);
+ sb.append(", spanId=").append(spanId);
+ sb.append(", sequence=").append(sequence);
+ sb.append(", startElapsed=").append(startElapsed);
+ sb.append(", endElapsed=").append(endElapsed);
+ sb.append(", rpc='").append(rpc).append('\'');
+ sb.append(", serviceType=").append(serviceType);
+ sb.append(", destinationId='").append(destinationId).append('\'');
+ sb.append(", endPoint='").append(endPoint).append('\'');
+ sb.append(", apiId=").append(apiId);
+ sb.append(", annotationBoList=").append(annotationBoList);
+ sb.append(", depth=").append(depth);
+ sb.append(", nextSpanId=").append(nextSpanId);
+ sb.append(", hasException=").append(hasException);
+ sb.append(", exceptionId=").append(exceptionId);
+ sb.append(", exceptionMessage='").append(exceptionMessage).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/SqlMetaDataBo.java b/src/main/java/com/nhn/pinpoint/common/bo/SqlMetaDataBo.java
new file mode 100644
index 000000000..ad7968e57
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/SqlMetaDataBo.java
@@ -0,0 +1,97 @@
+package com.nhn.pinpoint.common.bo;
+
+import com.nhn.pinpoint.common.util.BytesUtils;
+import com.nhn.pinpoint.common.util.RowKeyUtils;
+import com.nhn.pinpoint.common.util.TimeUtils;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import static com.nhn.pinpoint.common.PinpointConstants.AGENT_NAME_MAX_LEN;
+import static com.nhn.pinpoint.common.util.BytesUtils.LONG_BYTE_LENGTH;
+
+/**
+ * @author emeroad
+ */
+public class SqlMetaDataBo {
+ private String agentId;
+ private long startTime;
+
+ private int hashCode;
+
+ private String sql;
+
+ public SqlMetaDataBo() {
+ }
+
+
+ public SqlMetaDataBo(String agentId, long startTime, int hashCode) {
+ if (agentId == null) {
+ throw new NullPointerException("agentId must not be null");
+ }
+ this.agentId = agentId;
+ this.hashCode = hashCode;
+ this.startTime = startTime;
+ }
+
+ public String getAgentId() {
+ return agentId;
+ }
+
+ public void setAgentId(String agentId) {
+ this.agentId = agentId;
+ }
+
+
+ public int getHashCode() {
+ return hashCode;
+ }
+
+ public void setHashCode(int hashCode) {
+ this.hashCode = hashCode;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ public String getSql() {
+ return sql;
+ }
+
+ public void setSql(String sql) {
+ this.sql = sql;
+ }
+
+ public void readRowKey(byte[] rowKey) {
+ this.agentId = Bytes.toString(rowKey, 0, AGENT_NAME_MAX_LEN).trim();
+ this.startTime = TimeUtils.recoveryTimeMillis(readTime(rowKey));
+ this.hashCode = readKeyCode(rowKey);
+ }
+
+
+ private static long readTime(byte[] rowKey) {
+ return BytesUtils.bytesToLong(rowKey, AGENT_NAME_MAX_LEN);
+ }
+
+ private static int readKeyCode(byte[] rowKey) {
+ return BytesUtils.bytesToInt(rowKey, AGENT_NAME_MAX_LEN + LONG_BYTE_LENGTH);
+ }
+
+ public byte[] toRowKey() {
+ return RowKeyUtils.getMetaInfoRowKey(this.agentId, this.startTime, this.hashCode);
+ }
+
+ @Override
+ public String toString() {
+ return "SqlMetaDataBo{" +
+ "agentId='" + agentId + '\'' +
+ ", startTime=" + startTime +
+ ", hashCode=" + hashCode +
+ ", sql='" + sql + '\'' +
+ '}';
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/bo/StringMetaDataBo.java b/src/main/java/com/nhn/pinpoint/common/bo/StringMetaDataBo.java
new file mode 100644
index 000000000..90fe4dbba
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/bo/StringMetaDataBo.java
@@ -0,0 +1,97 @@
+package com.nhn.pinpoint.common.bo;
+
+import com.nhn.pinpoint.common.util.BytesUtils;
+import com.nhn.pinpoint.common.util.RowKeyUtils;
+import com.nhn.pinpoint.common.util.TimeUtils;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import static com.nhn.pinpoint.common.PinpointConstants.AGENT_NAME_MAX_LEN;
+import static com.nhn.pinpoint.common.util.BytesUtils.LONG_BYTE_LENGTH;
+
+/**
+ * @author emeroad
+ */
+public class StringMetaDataBo {
+ private String agentId;
+ private long startTime;
+
+ private int stringId;
+
+ private String stringValue;
+
+ public StringMetaDataBo() {
+ }
+
+
+ public StringMetaDataBo(String agentId, long startTime, int stringId) {
+ if (agentId == null) {
+ throw new NullPointerException("agentId must not be null");
+ }
+ this.agentId = agentId;
+ this.stringId = stringId;
+ this.startTime = startTime;
+ }
+
+ public String getAgentId() {
+ return agentId;
+ }
+
+ public void setAgentId(String agentId) {
+ this.agentId = agentId;
+ }
+
+
+ public int getStringId() {
+ return stringId;
+ }
+
+ public void setStringId(int stringId) {
+ this.stringId = stringId;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ public String getStringValue() {
+ return stringValue;
+ }
+
+ public void setStringValue(String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ public void readRowKey(byte[] rowKey) {
+ this.agentId = Bytes.toString(rowKey, 0, AGENT_NAME_MAX_LEN).trim();
+ this.startTime = TimeUtils.recoveryTimeMillis(readTime(rowKey));
+ this.stringId = readKeyCode(rowKey);
+ }
+
+
+ private static long readTime(byte[] rowKey) {
+ return BytesUtils.bytesToLong(rowKey, AGENT_NAME_MAX_LEN);
+ }
+
+ private static int readKeyCode(byte[] rowKey) {
+ return BytesUtils.bytesToInt(rowKey, AGENT_NAME_MAX_LEN + LONG_BYTE_LENGTH);
+ }
+
+ public byte[] toRowKey() {
+ return RowKeyUtils.getMetaInfoRowKey(this.agentId, this.startTime, this.stringId);
+ }
+
+ @Override
+ public String toString() {
+ return "StringMetaDataBo{" +
+ "agentId='" + agentId + '\'' +
+ ", startTime=" + startTime +
+ ", stringId=" + stringId +
+ ", stringValue='" + stringValue + '\'' +
+ '}';
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/buffer/AutomaticBuffer.java b/src/main/java/com/nhn/pinpoint/common/buffer/AutomaticBuffer.java
new file mode 100644
index 000000000..de004a314
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/buffer/AutomaticBuffer.java
@@ -0,0 +1,182 @@
+package com.nhn.pinpoint.common.buffer;
+
+import com.nhn.pinpoint.common.util.BytesUtils;
+
+/**
+ * 버퍼사이즈가 자동으로 확장되는 buffer
+ * @author emeroad
+ */
+public class AutomaticBuffer extends FixedBuffer {
+
+ public AutomaticBuffer() {
+ super(32);
+ }
+
+ public AutomaticBuffer(final int size) {
+ super(size);
+ }
+
+ public AutomaticBuffer(final byte[] buffer) {
+ super(buffer);
+ }
+
+
+ private void checkExpend(final int size) {
+ int length = buffer.length;
+ final int remain = length - offset;
+ if (remain >= size) {
+ return;
+ }
+
+ if (length == 0) {
+ length = 1;
+ }
+
+ // 사이즈 계산을 먼저한 후에 buffer를 한번만 할당하도록 변경.
+ final int expendBufferSize = computeExpendBufferSize(size, length, remain);
+ // allocate buffer
+ final byte[] expendBuffer = new byte[expendBufferSize];
+ System.arraycopy(buffer, 0, expendBuffer, 0, buffer.length);
+ buffer = expendBuffer;
+ }
+
+ private int computeExpendBufferSize(final int size, int length, int remain) {
+ int expendBufferSize = 0;
+ while (remain < size) {
+ length <<= 2;
+ expendBufferSize = length;
+ remain = expendBufferSize - offset;
+ }
+ return expendBufferSize;
+ }
+
+ @Override
+ public void putPadBytes(byte[] bytes, int totalLength) {
+ checkExpend(totalLength);
+ super.putPadBytes(bytes, totalLength);
+ }
+
+
+ @Override
+ public void putPrefixedBytes(final byte[] bytes) {
+ if (bytes == null) {
+ checkExpend(1);
+ super.putSVar(NULL);
+ } else {
+ checkExpend(bytes.length + BytesUtils.VINT_MAX_SIZE);
+ super.putSVar(bytes.length);
+ super.put(bytes);
+ }
+ }
+
+ @Override
+ public void put2PrefixedBytes(final byte[] bytes) {
+ if (bytes == null) {
+ checkExpend(BytesUtils.SHORT_BYTE_LENGTH);
+ super.put((short)NULL);
+ } else {
+ if (bytes.length > Short.MAX_VALUE) {
+ throw new IllegalArgumentException("too large bytes length:" + bytes.length);
+ }
+ checkExpend(bytes.length + BytesUtils.SHORT_BYTE_LENGTH);
+ super.put((short)bytes.length);
+ super.put(bytes);
+ }
+ }
+
+ @Override
+ public void put4PrefixedBytes(final byte[] bytes) {
+ if (bytes == null) {
+ checkExpend(BytesUtils.INT_BYTE_LENGTH);
+ super.put(NULL);
+ } else {
+ checkExpend(bytes.length + BytesUtils.INT_BYTE_LENGTH);
+ super.put(bytes.length);
+ super.put(bytes);
+ }
+ }
+
+ @Override
+ public void putPadString(String string, int totalLength) {
+ checkExpend(totalLength);
+ super.putPadString(string, totalLength);
+ }
+
+
+ @Override
+ public void putPrefixedString(final String string) {
+ byte[] bytes = BytesUtils.toBytes(string);
+ this.putPrefixedBytes(bytes);
+ }
+
+ @Override
+ public void put2PrefixedString(final String string) {
+ byte[] bytes = BytesUtils.toBytes(string);
+ this.put2PrefixedBytes(bytes);
+ }
+
+ @Override
+ public void put4PrefixedString(final String string) {
+ byte[] bytes = BytesUtils.toBytes(string);
+ this.put4PrefixedBytes(bytes);
+ }
+
+ @Override
+ public void put(final byte v) {
+ checkExpend(1);
+ super.put(v);
+ }
+
+ @Override
+ public void put(final boolean v) {
+ checkExpend(1);
+ super.put(v);
+ }
+
+ @Override
+ public void put(final short v) {
+ checkExpend(2);
+ super.put(v);
+ }
+
+ @Override
+ public void put(final int v) {
+ checkExpend(4);
+ super.put(v);
+ }
+
+ public void putVar(final int v) {
+ checkExpend(BytesUtils.VLONG_MAX_SIZE);
+ super.putVar(v);
+ }
+
+ public void putSVar(final int v) {
+ checkExpend(BytesUtils.VINT_MAX_SIZE);
+ super.putSVar(v);
+ }
+
+ public void putVar(final long v) {
+ checkExpend(BytesUtils.VLONG_MAX_SIZE);
+ super.putVar(v);
+ }
+
+ public void putSVar(final long v) {
+ checkExpend(BytesUtils.VLONG_MAX_SIZE);
+ super.putSVar(v);
+ }
+
+ @Override
+ public void put(final long v) {
+ checkExpend(8);
+ super.put(v);
+ }
+
+ @Override
+ public void put(final byte[] v) {
+ if (v == null) {
+ throw new NullPointerException("v must not be null");
+ }
+ checkExpend(v.length);
+ super.put(v);
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/buffer/Buffer.java b/src/main/java/com/nhn/pinpoint/common/buffer/Buffer.java
new file mode 100644
index 000000000..9a7e2115b
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/buffer/Buffer.java
@@ -0,0 +1,154 @@
+package com.nhn.pinpoint.common.buffer;
+
+/**
+ * @author emeroad
+ */
+public interface Buffer {
+
+ public static final int BOOLEAN_FALSE = 0;
+ public static final int BOOLEAN_TRUE = 1;
+
+ public static final byte[] EMPTY = new byte[0];
+
+ public static final String UTF8 = "UTF-8";
+
+ void putPadBytes(byte[] bytes, int totalLength);
+
+ void putPrefixedBytes(byte[] bytes);
+
+ void put2PrefixedBytes(byte[] bytes);
+
+ void put4PrefixedBytes(byte[] bytes);
+
+ void putPadString(String string, int totalLength);
+
+ void putPrefixedString(String string);
+
+ void put2PrefixedString(String string);
+
+ void put4PrefixedString(String string);
+
+ void put(byte v);
+
+ void put(boolean v);
+
+ void put(int v);
+
+ /**
+ * 가변인코딩을 사용하여 저장한다.
+ * 상수값에 강한 인코딩을 한다.
+ * 음수값이 들어갈 경우 사이즈가 fixint 인코딩 보다 더 커짐, 음수값의 분포가 많을 경우 매우 비효율적임.
+ * 이 경우 putSVar를 사용한다. putSVar에 비해서 zigzag연산이 없어 cpu를 약간 덜사용하는 이점 뿐이 없음.
+ * 음수가 조금이라도 들어갈 가능성이 있다면 putSVar를 사용하는 것이 이득이다..
+ * 1~10 byte사용
+ * max : 5, min 10
+ * @param v
+ */
+ void putVar(int v);
+
+ /**
+ * 가변인코딩을 사용하여 저장한다.
+ * 상수, 음수의 분포가 동일한 데이터 일 경우 사용한다.
+ * 1~5 사용
+ * max : 5, min :5
+ * @param v
+ */
+ void putSVar(int v);
+
+ void put(short v);
+
+ void put(long v);
+
+ /**
+ * 가변인코딩을 사용하여 저장한다.
+ * 상수값에 강한 인코딩을 한다.
+ * 음수값이 들어갈 경우 사이즈가 fixint 인코딩 보다 더 커짐
+ * 이경우 putSVar를 사용한다.
+ * @param v
+ */
+ void putVar(long v);
+
+ /**
+ * 가변인코딩을 사용하여 저장한다.
+ * 상수, 음수의 분포가 동일한 데이터 일 경우 사용한다.
+ * @param v
+ */
+ void putSVar(long v);
+
+ void put(double v);
+
+ /**
+ * 가변인코딩을 사용하여 저장한다.
+ * 상수값에 강한 인코딩을 한다.
+ * 음수값이 들어갈 경우 사이즈가 fixint 인코딩 보다 더 커짐
+ * 이경우 putSVar를 사용한다.
+ * @param v
+ */
+ void putVar(double v);
+
+ /**
+ * 가변인코딩을 사용하여 저장한다.
+ * 상수, 음수의 분포가 동일한 데이터 일 경우 사용한다.
+ * @param v
+ */
+ void putSVar(double v);
+
+ void put(byte[] v);
+
+ byte readByte();
+
+ int readUnsignedByte();
+
+ boolean readBoolean();
+
+ int readInt();
+
+ int readVarInt();
+
+ int readSVarInt();
+
+
+ short readShort();
+
+ long readLong();
+
+ long readVarLong();
+
+ long readSVarLong();
+
+ double readDouble();
+
+ double readVarDouble();
+
+ double readSVarDouble();
+
+ byte[] readPadBytes(int totalLength);
+
+ String readPadString(int totalLength);
+
+ String readPadStringAndRightTrim(int totalLength);
+
+ byte[] readPrefixedBytes();
+
+ byte[] read2PrefixedBytes();
+
+ byte[] read4PrefixedBytes();
+
+ String readPrefixedString();
+
+ String read2PrefixedString();
+
+ String read4PrefixedString();
+
+ byte[] getBuffer();
+
+ byte[] copyBuffer();
+
+ byte[] getInternalBuffer();
+
+ void setOffset(int offset);
+
+ int getOffset();
+
+ int limit();
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/buffer/FixedBuffer.java b/src/main/java/com/nhn/pinpoint/common/buffer/FixedBuffer.java
new file mode 100644
index 000000000..804f37e3f
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/buffer/FixedBuffer.java
@@ -0,0 +1,479 @@
+package com.nhn.pinpoint.common.buffer;
+
+import com.nhn.pinpoint.common.util.BytesUtils;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * @author emeroad
+ */
+public class FixedBuffer implements Buffer {
+ protected static final int NULL = -1;
+ protected byte[] buffer;
+ protected int offset;
+
+ public FixedBuffer() {
+ this(32);
+ }
+
+ public FixedBuffer(final int bufferSize) {
+ if (bufferSize < 0) {
+ throw new IllegalArgumentException("negative bufferSize:" + bufferSize);
+ }
+ this.buffer = new byte[bufferSize];
+ this.offset = 0;
+ }
+
+ public FixedBuffer(final byte[] buffer) {
+ if (buffer == null) {
+ throw new NullPointerException("buffer must not be null");
+ }
+ this.buffer = buffer;
+ this.offset = 0;
+ }
+
+ @Override
+ public void putPadBytes(byte[] bytes, int totalLength) {
+ if (bytes == null) {
+ bytes = EMPTY;
+ }
+ if (bytes.length > totalLength) {
+ throw new IllegalArgumentException("bytes too big:" + bytes.length + " totalLength:" + totalLength);
+ }
+ put(bytes);
+ final int padSize = totalLength - bytes.length;
+ if (padSize > 0) {
+ putPad(padSize);
+ }
+ }
+
+ private void putPad(int padSize) {
+ for (int i = 0; i < padSize; i++) {
+ put((byte)0);
+ }
+ }
+
+
+ @Override
+ public void putPrefixedBytes(final byte[] bytes) {
+ if (bytes == null) {
+ putSVar(NULL);
+ } else {
+ putSVar(bytes.length);
+ put(bytes);
+ }
+ }
+
+ @Override
+ public void put2PrefixedBytes(final byte[] bytes) {
+ if (bytes == null) {
+ put((short)NULL);
+ } else {
+ if (bytes.length > Short.MAX_VALUE) {
+ throw new IllegalArgumentException("too large bytes length:" + bytes.length);
+ }
+ put((short)bytes.length);
+ put(bytes);
+ }
+ }
+
+ @Override
+ public void put4PrefixedBytes(final byte[] bytes) {
+ if (bytes == null) {
+ put(NULL);
+ } else {
+ put(bytes.length);
+ put(bytes);
+ }
+ }
+
+ @Override
+ public void putPadString(String string, int totalLength) {
+ final byte[] bytes = BytesUtils.toBytes(string);
+ putPadBytes(bytes, totalLength);
+ }
+
+ @Override
+ public void putPrefixedString(final String string) {
+ final byte[] bytes = BytesUtils.toBytes(string);
+ putPrefixedBytes(bytes);
+ }
+
+ @Override
+ public void put2PrefixedString(final String string) {
+ final byte[] bytes = BytesUtils.toBytes(string);
+ if (bytes == null) {
+ put((short)NULL);
+ return;
+ }
+ if (bytes.length > Short.MAX_VALUE) {
+ throw new IllegalArgumentException("too large String size:" + bytes.length);
+ }
+ put2PrefixedBytes(bytes);
+ }
+
+ @Override
+ public void put4PrefixedString(final String string) {
+ final byte[] bytes = BytesUtils.toBytes(string);
+ if (bytes == null) {
+ put(NULL);
+ return;
+ }
+ put4PrefixedBytes(bytes);
+ }
+
+ @Override
+ public void put(final byte v) {
+ this.buffer[offset++] = v;
+ }
+
+ @Override
+ public void put(final boolean v) {
+ if (v) {
+ this.buffer[offset++] = BOOLEAN_TRUE;
+ } else {
+ this.buffer[offset++] = BOOLEAN_FALSE;
+ }
+ }
+
+ @Override
+ public void put(final int v) {
+ this.offset = BytesUtils.writeInt(v, buffer, offset);
+ }
+
+ public void putVar(int v) {
+ if (v >= 0) {
+ putVar32(v);
+ } else {
+ putVar64((long) v);
+ }
+ }
+
+ public void putSVar(int v) {
+ this.offset = BytesUtils.writeSVar32(v, buffer, offset);
+ }
+
+ private void putVar32(int v) {
+ this.offset = BytesUtils.writeVar32(v, buffer, offset);
+ }
+
+ @Override
+ public void put(final short v) {
+ this.offset = BytesUtils.writeShort(v, buffer, offset);
+ }
+
+ @Override
+ public void put(final long v) {
+ this.offset = BytesUtils.writeLong(v, buffer, offset);
+ }
+
+ @Override
+ public void putVar(long v) {
+ putVar64(v);
+ }
+
+ @Override
+ public void putSVar(long v) {
+ putVar64(BytesUtils.longToZigZag(v));
+ }
+
+ private void putVar64(long v) {
+ this.offset = BytesUtils.writeVar64(v, buffer, offset);
+ }
+
+ @Override
+ public void put(double v) {
+ put(Double.doubleToRawLongBits(v));
+ }
+
+ @Override
+ public void putVar(double v) {
+ putVar(Double.doubleToRawLongBits(v));
+ }
+
+ @Override
+ public void putSVar(double v) {
+ putSVar(Double.doubleToRawLongBits(v));
+ }
+
+ @Override
+ public void put(final byte[] v) {
+ if (v == null) {
+ throw new NullPointerException("v must not be null");
+ }
+ System.arraycopy(v, 0, buffer, offset, v.length);
+ this.offset = offset + v.length;
+ }
+
+ @Override
+ public byte readByte() {
+ return this.buffer[offset++];
+ }
+
+ @Override
+ public int readUnsignedByte() {
+ return readByte() & 0xff;
+ }
+
+ @Override
+ public boolean readBoolean() {
+ final byte b = readByte();
+ return b == BOOLEAN_TRUE;
+ }
+
+ @Override
+ public int readInt() {
+ final int i = BytesUtils.bytesToInt(buffer, offset);
+ this.offset = this.offset + 4;
+ return i;
+ }
+
+ @Override
+ public int readVarInt() {
+ // protocol buffer의 var encoding 차용.
+ byte v = readByte();
+ if (v >= 0) {
+ return v;
+ }
+ int result = v & 0x7f;
+ if ((v = readByte()) >= 0) {
+ result |= v << 7;
+ } else {
+ result |= (v & 0x7f) << 7;
+ if ((v = readByte()) >= 0) {
+ result |= v << 14;
+ } else {
+ result |= (v & 0x7f) << 14;
+ if ((v = readByte()) >= 0) {
+ result |= v << 21;
+ } else {
+ result |= (v & 0x7f) << 21;
+ result |= (v = readByte()) << 28;
+ if (v < 0) {
+ for (int i = 0; i < 5; i++) {
+ if (readByte() >= 0) {
+ return result;
+ }
+ }
+ throw new IllegalArgumentException("invalid varInt");
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ public int readSVarInt() {
+ return BytesUtils.zigzagToInt(readVarInt());
+ }
+
+ @Override
+ public short readShort() {
+ final short i = BytesUtils.bytesToShort(buffer, offset);
+ this.offset = this.offset + 2;
+ return i;
+ }
+
+ public int readUnsignedShort() {
+ return readShort() & 0xFFFF;
+ }
+
+ @Override
+ public long readLong() {
+ final long l = BytesUtils.bytesToLong(buffer, offset);
+ this.offset = this.offset + 8;
+ return l;
+ }
+
+ @Override
+ public long readVarLong() {
+ int shift = 0;
+ long result = 0;
+ while (shift < 64) {
+ final byte v = readByte();
+ result |= (long)(v & 0x7F) << shift;
+ if ((v & 0x80) == 0) {
+ return result;
+ }
+ shift += 7;
+ }
+ throw new IllegalArgumentException("invalid varLong");
+ }
+
+ @Override
+ public long readSVarLong() {
+ return BytesUtils.zigzagToLong(readVarLong());
+ }
+
+ @Override
+ public double readDouble() {
+ return Double.longBitsToDouble(this.readLong());
+ }
+
+ @Override
+ public double readVarDouble() {
+ return Double.longBitsToDouble(this.readVarLong());
+ }
+
+ @Override
+ public double readSVarDouble() {
+ return Double.longBitsToDouble(this.readSVarLong());
+ }
+
+ @Override
+ public byte[] readPadBytes(int totalLength) {
+ return readBytes(totalLength);
+ }
+
+ @Override
+ public String readPadString(int totalLength) {
+ return readString(totalLength);
+ }
+
+ @Override
+ public String readPadStringAndRightTrim(int totalLength) {
+ String string = BytesUtils.toStringAndRightTrim(buffer, offset, totalLength);
+ this.offset = offset + totalLength;
+ return string ;
+ }
+
+
+ @Override
+ public byte[] readPrefixedBytes() {
+ final int size = readSVarInt();
+ if (size == NULL) {
+ return null;
+ }
+ if (size == 0) {
+ return EMPTY;
+ }
+ return readBytes(size);
+ }
+
+ @Override
+ public byte[] read2PrefixedBytes() {
+ final int size = readShort();
+ if (size == NULL) {
+ return null;
+ }
+ if (size == 0) {
+ return EMPTY;
+ }
+ return readBytes(size);
+ }
+
+ @Override
+ public byte[] read4PrefixedBytes() {
+ final int size = readInt();
+ if (size == NULL) {
+ return null;
+ }
+ if (size == 0) {
+ return EMPTY;
+ }
+ return readBytes(size);
+ }
+
+
+ private byte[] readBytes(int size) {
+ final byte[] b = new byte[size];
+ System.arraycopy(buffer, offset, b, 0, size);
+ this.offset = offset + size;
+ return b;
+ }
+
+ @Override
+ public String readPrefixedString() {
+ final int size = readSVarInt();
+ if (size == NULL) {
+ return null;
+ }
+ if (size == 0) {
+ return "";
+ }
+ return readString(size);
+ }
+
+ @Override
+ public String read2PrefixedString() {
+ final int size = readShort();
+ if (size == NULL) {
+ return null;
+ }
+ if (size == 0) {
+ return "";
+ }
+ return readString(size);
+ }
+
+ @Override
+ public String read4PrefixedString() {
+ final int size = readInt();
+ if (size == NULL) {
+ return null;
+ }
+ if (size == 0) {
+ return "";
+ }
+ return readString(size);
+ }
+
+
+ private String readString(final int size) {
+ final String s = newString(size);
+ this.offset = offset + size;
+ return s;
+ }
+
+ private String newString(final int size) {
+ try {
+ return new String(buffer, offset, size, UTF8);
+ } catch (UnsupportedEncodingException ue) {
+ throw new RuntimeException(ue.getMessage(), ue);
+ }
+ }
+
+ /**
+ * 암묵적으로 성능을 내부 buffe length와 offset의 사이즈가 같으면 메모리 copy를 하지 않고 그냥 internal buffer를 리턴하므로 주의해야 한다.
+ * @return
+ */
+ @Override
+ public byte[] getBuffer() {
+ if (offset == buffer.length) {
+ return this.buffer;
+ } else {
+ return copyBuffer();
+ }
+ }
+
+ @Override
+ public byte[] copyBuffer() {
+ final byte[] copy = new byte[offset];
+ System.arraycopy(buffer, 0, copy, 0, offset);
+ return copy;
+ }
+
+ /**
+ * 내부 buffer를 리턴한다.
+ * @return
+ */
+ @Override
+ public byte[] getInternalBuffer() {
+ return this.buffer;
+ }
+
+ @Override
+ public void setOffset(int offset) {
+ this.offset = offset;
+ }
+
+ @Override
+ public int getOffset() {
+ return offset;
+ }
+
+ @Override
+ public int limit() {
+ return buffer.length - offset;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/buffer/OffsetAutomaticBuffer.java b/src/main/java/com/nhn/pinpoint/common/buffer/OffsetAutomaticBuffer.java
new file mode 100644
index 000000000..4c2b9ba33
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/buffer/OffsetAutomaticBuffer.java
@@ -0,0 +1,32 @@
+package com.nhn.pinpoint.common.buffer;
+
+/**
+ * @author emeroad
+ */
+public class OffsetAutomaticBuffer extends AutomaticBuffer {
+
+ protected final int startOffset;
+
+ public OffsetAutomaticBuffer(final byte[] buffer, final int offset) {
+ if (buffer == null) {
+ throw new NullPointerException("buffer must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ if (offset > buffer.length) {
+ throw new IllegalArgumentException("offset:" + offset + " > buffer.length:" + buffer.length);
+ }
+ this.buffer = buffer;
+ this.offset = offset;
+ this.startOffset = offset;
+ }
+
+ @Override
+ public byte[] getBuffer() {
+ final int bufferSize = offset - startOffset;
+ final byte[] copy = new byte[bufferSize];
+ System.arraycopy(buffer, startOffset, copy, 0, bufferSize);
+ return copy;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/buffer/OffsetFixedBuffer.java b/src/main/java/com/nhn/pinpoint/common/buffer/OffsetFixedBuffer.java
new file mode 100644
index 000000000..ee3f6c60c
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/buffer/OffsetFixedBuffer.java
@@ -0,0 +1,32 @@
+package com.nhn.pinpoint.common.buffer;
+
+/**
+ * @author emeroad
+ */
+public class OffsetFixedBuffer extends FixedBuffer {
+
+ protected final int startOffset;
+
+ public OffsetFixedBuffer(final byte[] buffer, final int offset) {
+ if (buffer == null) {
+ throw new NullPointerException("buffer must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ if (offset > buffer.length) {
+ throw new IllegalArgumentException("offset:" + offset + " > buffer.length:" + buffer.length);
+ }
+ this.buffer = buffer;
+ this.offset = offset;
+ this.startOffset = offset;
+ }
+
+ @Override
+ public byte[] getBuffer() {
+ final int bufferSize = offset - startOffset;
+ final byte[] copy = new byte[bufferSize];
+ System.arraycopy(buffer, startOffset, copy, 0, bufferSize);
+ return copy;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/EmptyLimitEventHandler.java b/src/main/java/com/nhn/pinpoint/common/hbase/EmptyLimitEventHandler.java
new file mode 100644
index 000000000..f05b771cc
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/EmptyLimitEventHandler.java
@@ -0,0 +1,13 @@
+package com.nhn.pinpoint.common.hbase;
+
+import org.apache.hadoop.hbase.client.Result;
+
+/**
+ * @author emeroad
+ */
+public class EmptyLimitEventHandler implements LimitEventHandler{
+
+ @Override
+ public void handleLastResult(Result lastResult) {
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/HBaseAdminTemplate.java b/src/main/java/com/nhn/pinpoint/common/hbase/HBaseAdminTemplate.java
new file mode 100644
index 000000000..784f14d8a
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/HBaseAdminTemplate.java
@@ -0,0 +1,78 @@
+package com.nhn.pinpoint.common.hbase;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.MasterNotRunningException;
+import org.apache.hadoop.hbase.ZooKeeperConnectionException;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.springframework.data.hadoop.hbase.HbaseSystemException;
+
+import java.io.IOException;
+
+/**
+ * @author emeroad
+ */
+public class HBaseAdminTemplate {
+
+ private final HBaseAdmin hBaseAdmin;
+
+ public HBaseAdminTemplate(Configuration configuration) {
+ try {
+ this.hBaseAdmin = new HBaseAdmin(configuration);
+ } catch (MasterNotRunningException e) {
+ throw new HbaseSystemException(e);
+ } catch (ZooKeeperConnectionException e) {
+ throw new HbaseSystemException(e);
+ }
+ }
+
+ public boolean createTableIfNotExist(HTableDescriptor htd) {
+ try {
+ if (!hBaseAdmin.tableExists(htd.getName())) {
+ this.hBaseAdmin.createTable(htd);
+ return true;
+ }
+ return false;
+ } catch (IOException e) {
+ throw new HbaseSystemException(e);
+ }
+ }
+
+ public boolean tableExists(String tableName) {
+ try {
+ return hBaseAdmin.tableExists(tableName);
+ } catch (IOException e) {
+ throw new HbaseSystemException(e);
+ }
+ }
+
+ public boolean dropTableIfExist(String tableName) {
+ try {
+ if (hBaseAdmin.tableExists(tableName)) {
+ this.hBaseAdmin.disableTable(tableName);
+ this.hBaseAdmin.deleteTable(tableName);
+ return true;
+ }
+ return false;
+ } catch (IOException e) {
+ throw new HbaseSystemException(e);
+ }
+ }
+
+ public void dropTable(String tableName) {
+ try {
+ this.hBaseAdmin.disableTable(tableName);
+ this.hBaseAdmin.deleteTable(tableName);
+ } catch (IOException e) {
+ throw new HbaseSystemException(e);
+ }
+ }
+
+ public void close() {
+ try {
+ this.hBaseAdmin.close();
+ } catch (IOException e) {
+ throw new HbaseSystemException(e);
+ }
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/HBaseTables.java b/src/main/java/com/nhn/pinpoint/common/hbase/HBaseTables.java
new file mode 100644
index 000000000..5b9765101
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/HBaseTables.java
@@ -0,0 +1,74 @@
+package com.nhn.pinpoint.common.hbase;
+
+import com.nhn.pinpoint.common.PinpointConstants;
+import org.apache.hadoop.hbase.util.Bytes;
+
+/**
+ * @author emeroad
+ */
+public final class HBaseTables {
+
+ public static final int APPLICATION_NAME_MAX_LEN = PinpointConstants.APPLICATION_NAME_MAX_LEN;
+ public static final int AGENT_NAME_MAX_LEN = PinpointConstants.AGENT_NAME_MAX_LEN;
+
+
+ public static final String APPLICATION_TRACE_INDEX = "ApplicationTraceIndex";
+ public static final byte[] APPLICATION_TRACE_INDEX_CF_TRACE = Bytes.toBytes("I"); // applicationIndex
+ public static final int APPLICATION_TRACE_INDEX_ROW_DISTRIBUTE_SIZE = 1; // applicationIndex hash size
+
+ public static final String AGENT_STAT = "AgentStat";
+ public static final byte[] AGENT_STAT_CF_STATISTICS = Bytes.toBytes("S"); // agent statistics column family
+ public static final byte[] AGENT_STAT_CF_STATISTICS_V1 = Bytes.toBytes("V1"); // qualifier
+ public static final byte[] AGENT_STAT_CF_STATISTICS_MEMORY_GC = Bytes.toBytes("Gc"); // qualifier for Heap Memory/Gc statistics
+ public static final byte[] AGENT_STAT_CF_STATISTICS_CPU_LOAD = Bytes.toBytes("Cpu"); // qualifier for CPU load statistics
+ public static final int AGENT_STAT_ROW_DISTRIBUTE_SIZE = 1; // agent statistics hash size
+
+ public static final String TRACES = "Traces";
+ public static final byte[] TRACES_CF_SPAN = Bytes.toBytes("S"); //Span
+ public static final byte[] TRACES_CF_ANNOTATION = Bytes.toBytes("A"); //Annotation
+ public static final byte[] TRACES_CF_TERMINALSPAN = Bytes.toBytes("T"); //TerminalSpan
+
+ public static final String APPLICATION_INDEX = "ApplicationIndex";
+ public static final byte[] APPLICATION_INDEX_CF_AGENTS = Bytes.toBytes("Agents");
+
+ public static final String AGENTINFO = "AgentInfo";
+ public static final byte[] AGENTINFO_CF_INFO = Bytes.toBytes("Info");
+ public static final byte[] AGENTINFO_CF_INFO_IDENTIFIER = Bytes.toBytes("i");
+
+ @Deprecated
+ public static final String AGENTID_APPLICATION_INDEX = "AgentIdApplicationIndex";
+ @Deprecated
+ public static final byte[] AGENTID_APPLICATION_INDEX_CF_APPLICATION = Bytes.toBytes("Application");
+
+
+ public static final String SQL_METADATA = "SqlMetaData";
+ public static final byte[] SQL_METADATA_CF_SQL = Bytes.toBytes("Sql");
+
+ public static final String STRING_METADATA = "StringMetaData";
+ public static final byte[] STRING_METADATA_CF_STR = Bytes.toBytes("Str");
+
+ public static final String API_METADATA = "ApiMetaData";
+ public static final byte[] API_METADATA_CF_API = Bytes.toBytes("Api");
+
+ public static final String MAP_STATISTICS_CALLER = "ApplicationMapStatisticsCaller";
+ public static final byte[] MAP_STATISTICS_CALLER_CF_COUNTER = Bytes.toBytes("C");
+
+ public static final String MAP_STATISTICS_CALLEE = "ApplicationMapStatisticsCallee";
+ // 나중에 삭제할것. 관련 코드도같이 제거해도 됨.
+ public static final byte[] MAP_STATISTICS_CALLEE_CF_COUNTER = Bytes.toBytes("C");
+ // 신버전의 column Name저장용.
+ public static final byte[] MAP_STATISTICS_CALLEE_CF_VER2_COUNTER = Bytes.toBytes("D");
+
+ public static final String MAP_STATISTICS_SELF = "ApplicationMapStatisticsSelf";
+ public static final byte[] MAP_STATISTICS_SELF_CF_COUNTER = Bytes.toBytes("C");
+
+ public static final String HOST_APPLICATION_MAP = "HostApplicationMap";
+ public static final byte[] HOST_APPLICATION_MAP_CF_MAP = Bytes.toBytes("M");
+
+ public static final String HOST_APPLICATION_MAP_VER2 = "HostApplicationMap_Ver2";
+ public static final byte[] HOST_APPLICATION_MAP_VER2_CF_MAP = Bytes.toBytes("M");
+
+
+ public static final short STATISTICS_CQ_ERROR_SLOT_NUMBER = -1;
+ public static final byte[] STATISTICS_CQ_ERROR_SLOT = Bytes.toBytes(STATISTICS_CQ_ERROR_SLOT_NUMBER);
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/HTableCallBack.java b/src/main/java/com/nhn/pinpoint/common/hbase/HTableCallBack.java
new file mode 100644
index 000000000..83b213720
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/HTableCallBack.java
@@ -0,0 +1,14 @@
+package com.nhn.pinpoint.common.hbase;
+
+import org.apache.hadoop.hbase.client.HTable;
+
+import java.io.IOException;
+
+/**
+ * @author emeroad
+ */
+public interface HTableCallBack {
+ void doExecute(HTable hTable) throws IOException;
+
+// void doMultiExecute(HTable... tables) throws IOException;
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/HbaseOperations2.java b/src/main/java/com/nhn/pinpoint/common/hbase/HbaseOperations2.java
new file mode 100644
index 000000000..a330bc5f8
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/HbaseOperations2.java
@@ -0,0 +1,96 @@
+package com.nhn.pinpoint.common.hbase;
+
+import java.util.List;
+
+import com.sematext.hbase.wd.AbstractRowKeyDistributor;
+import org.apache.hadoop.hbase.client.*;
+import org.springframework.data.hadoop.hbase.HbaseOperations;
+import org.springframework.data.hadoop.hbase.ResultsExtractor;
+import org.springframework.data.hadoop.hbase.RowMapper;
+
+/**
+ * @author emeroad
+ */
+public interface HbaseOperations2 extends HbaseOperations {
+ /**
+ * Gets an individual row from the given table. The content is mapped by the given action.
+ *
+ * @param tableName target table
+ * @param rowName row name
+ * @param mapper row mapper
+ * @return object mapping the target row
+ */
+ T get(String tableName, byte[] rowName, final RowMapper mapper);
+
+ /**
+ * Gets an individual row from the given table. The content is mapped by the given action.
+ *
+ * @param tableName target table
+ * @param rowName row name
+ * @param familyName column family
+ * @param mapper row mapper
+ * @return object mapping the target row
+ */
+ T get(String tableName, byte[] rowName, byte[] familyName, final RowMapper mapper);
+
+ /**
+ * Gets an individual row from the given table. The content is mapped by the given action.
+ *
+ * @param tableName target table
+ * @param rowName row name
+ * @param familyName family
+ * @param qualifier column qualifier
+ * @param mapper row mapper
+ * @return object mapping the target row
+ */
+ T get(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final RowMapper mapper);
+
+ T get(String tableName, final Get get, final RowMapper mapper);
+
+ List get(String tableName, final List get, final RowMapper mapper);
+
+
+ void put(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final byte[] value);
+
+ void put(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final Long timestamp, final byte[] value);
+
+ void put(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final T value, final ValueMapper mapper);
+
+ void put(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final Long timestamp, final T value, final ValueMapper mapper);
+
+ void put(String tableName, final Put put);
+
+ void put(String tableName, final List puts);
+
+ void delete(String tableName, final Delete delete);
+
+ void delete(String tableName, final List deletes);
+
+ List find(String tableName, final List scans, final ResultsExtractor action);
+
+ List> find(String tableName, final List scans, final RowMapper action);
+
+ List find(String tableName, final Scan scan, AbstractRowKeyDistributor rowKeyDistributor, final RowMapper action);
+
+ List find(String tableName, final Scan scan, AbstractRowKeyDistributor rowKeyDistributor, int limit, final RowMapper action);
+
+ List find(String tableName, final Scan scan, final AbstractRowKeyDistributor rowKeyDistributor, int limit, final RowMapper action, final LimitEventHandler limitEventHandler);
+
+ T find(String tableName, final Scan scan, final AbstractRowKeyDistributor rowKeyDistributor, final ResultsExtractor action);
+
+ Result increment(String tableName, final Increment increment);
+
+ /**
+ * increment list는 부분적으로 exception이 throw될수 있다. 이 경우 lastException이 사용에게 던져진다.
+ * 특정 increment에서 오류를 감지 해서 재시도 한다하는 로직의 경우 lastException던지는 문제 인해 어느게 실패 했는지 알수 없는 한계가 있다.
+ * @param tableName
+ * @param incrementList
+ * @return
+ */
+ List increment(String tableName, final List incrementList);
+
+ long incrementColumnValue(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final long amount);
+
+ long incrementColumnValue(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final long amount, final boolean writeToWAL);
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/HbaseTemplate2.java b/src/main/java/com/nhn/pinpoint/common/hbase/HbaseTemplate2.java
new file mode 100644
index 000000000..fdfd4f80e
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/HbaseTemplate2.java
@@ -0,0 +1,560 @@
+package com.nhn.pinpoint.common.hbase;
+
+import com.nhn.pinpoint.common.util.StopWatch;
+import com.sematext.hbase.wd.AbstractRowKeyDistributor;
+import com.sematext.hbase.wd.DistributedScanner;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.client.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.data.hadoop.hbase.*;
+import org.springframework.util.Assert;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * @author emeroad
+ */
+public class HbaseTemplate2 extends HbaseTemplate implements HbaseOperations2, InitializingBean, DisposableBean {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private PooledHTableFactory pooledHTableFactory;
+ private int poolSize = PooledHTableFactory.DEFAULT_POOL_SIZE;
+
+ private ExecutorService executor = newCachedThreadPool();
+
+ public HbaseTemplate2() {
+ }
+
+ public ExecutorService newCachedThreadPool() {
+ return new ThreadPoolExecutor(0, 128,
+ 60L, TimeUnit.SECONDS,
+ new LinkedBlockingQueue());
+ }
+
+// public Executor getExecutor() {
+// return executor;
+// }
+
+// public void setExecutor(Executor executor) {
+// this.executor = executor;
+// }
+
+ public HbaseTemplate2(Configuration configuration) {
+ Assert.notNull(configuration);
+ }
+
+ public HbaseTemplate2(Configuration configuration, int poolSize) {
+ Assert.notNull(configuration);
+ this.poolSize = poolSize;
+ }
+
+ public int getPoolSize() {
+ return poolSize;
+ }
+
+ public void setPoolSize(int hTablePoolSize) {
+ this.poolSize = hTablePoolSize;
+ }
+
+ @Override
+ public void afterPropertiesSet() {
+ Configuration configuration = getConfiguration();
+ Assert.notNull(configuration, "configuration is required");
+ this.pooledHTableFactory = new PooledHTableFactory(configuration, poolSize);
+ this.setTableFactory(pooledHTableFactory);
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ if (pooledHTableFactory != null) {
+ this.pooledHTableFactory.destroy();
+ }
+
+ final ExecutorService executor = this.executor;
+ if (executor != null) {
+ executor.shutdown();
+ try {
+ executor.awaitTermination(2000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ @Override
+ public T find(String tableName, String family, final ResultsExtractor action) {
+ Scan scan = new Scan();
+ scan.addFamily(family.getBytes(getCharset()));
+ return find(tableName, scan, action);
+ }
+
+ @Override
+ public T find(String tableName, String family, String qualifier, final ResultsExtractor action) {
+ Scan scan = new Scan();
+ scan.addColumn(family.getBytes(getCharset()), qualifier.getBytes(getCharset()));
+ return find(tableName, scan, action);
+ }
+
+ @Override
+ public T find(String tableName, final Scan scan, final ResultsExtractor action) {
+ return execute(tableName, new TableCallback() {
+ @Override
+ public T doInTable(HTableInterface htable) throws Throwable {
+ final ResultScanner scanner = htable.getScanner(scan);
+ try {
+ return action.extractData(scanner);
+ } finally {
+ scanner.close();
+ }
+ }
+ });
+ }
+
+ @Override
+ public List find(String tableName, String family, final RowMapper action) {
+ Scan scan = new Scan();
+ scan.addFamily(family.getBytes(getCharset()));
+ return find(tableName, scan, action);
+ }
+
+ @Override
+ public List find(String tableName, String family, String qualifier, final RowMapper action) {
+ Scan scan = new Scan();
+ scan.addColumn(family.getBytes(getCharset()), qualifier.getBytes(getCharset()));
+ return find(tableName, scan, action);
+ }
+
+ @Override
+ public List find(String tableName, final Scan scan, final RowMapper action) {
+ return find(tableName, scan, new RowMapperResultsExtractor(action));
+ }
+
+// public class ParallelScan {
+// private String tableName;
+// private Scan scan;
+// private RowMapper mapper;
+//
+// public String getTableName() {
+// return tableName;
+// }
+//
+// public void setTableName(String tableName) {
+// this.tableName = tableName;
+// }
+//
+// public Scan getScan() {
+// return scan;
+// }
+//
+// public void setScan(Scan scan) {
+// this.scan = scan;
+// }
+//
+// public RowMapper getMapper() {
+// return mapper;
+// }
+//
+// public void setMapper(RowMapper action) {
+// this.mapper = action;
+// }
+// }
+//
+// /**
+// * sanner를 병렬로 돌리기 위한 api
+// * scanner 구현 자체가 얼마나 병렬인지 애매해서 무조껀 만들기도 그러니 일단 주석처리.
+// * @return
+// */
+// public List>> findParallel(final ParallelScan parallelScans) {
+// Callable> tCallable = new Callable>() {
+// @Override
+// public List call() throws Exception {
+// return find(parallelScans.getTableName(), parallelScans.getScan(), parallelScans.getMapper());
+// }
+// };
+// ArrayList>> callables = new ArrayList>>();
+// callables.add(tCallable);
+//
+// List>> futures = null;
+// try {
+// futures = this.executor.invokeAll(callables);
+// } catch (InterruptedException e) {
+// Thread.currentThread().interrupt();
+// }
+// return futures;
+// }
+
+ @Override
+ public T get(String tableName, String rowName, final RowMapper mapper) {
+ return get(tableName, rowName, null, null, mapper);
+ }
+
+ @Override
+ public T get(String tableName, String rowName, String familyName, final RowMapper mapper) {
+ return get(tableName, rowName, familyName, null, mapper);
+ }
+
+ @Override
+ public T get(String tableName, final String rowName, final String familyName, final String qualifier, final RowMapper mapper) {
+ return execute(tableName, new TableCallback() {
+ @Override
+ public T doInTable(HTableInterface htable) throws Throwable {
+ Get get = new Get(rowName.getBytes(getCharset()));
+ if (familyName != null) {
+ byte[] family = familyName.getBytes(getCharset());
+
+ if (qualifier != null) {
+ get.addColumn(family, qualifier.getBytes(getCharset()));
+ } else {
+ get.addFamily(family);
+ }
+ }
+ Result result = htable.get(get);
+ return mapper.mapRow(result, 0);
+ }
+ });
+ }
+
+
+ @Override
+ public T get(String tableName, byte[] rowName, RowMapper mapper) {
+ return get(tableName, rowName, null, null, mapper);
+ }
+
+ @Override
+ public T get(String tableName, byte[] rowName, byte[] familyName, RowMapper mapper) {
+ return get(tableName, rowName, familyName, null, mapper);
+ }
+
+ @Override
+ public T get(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final RowMapper mapper) {
+ return execute(tableName, new TableCallback() {
+ @Override
+ public T doInTable(HTableInterface htable) throws Throwable {
+ Get get = new Get(rowName);
+ if (familyName != null) {
+ if (qualifier != null) {
+ get.addColumn(familyName, qualifier);
+ } else {
+ get.addFamily(familyName);
+ }
+ }
+ Result result = htable.get(get);
+ return mapper.mapRow(result, 0);
+ }
+ });
+ }
+
+ @Override
+ public T get(String tableName, final Get get, final RowMapper mapper) {
+ return execute(tableName, new TableCallback() {
+ @Override
+ public T doInTable(HTableInterface htable) throws Throwable {
+ Result result = htable.get(get);
+ return mapper.mapRow(result, 0);
+ }
+ });
+ }
+
+ @Override
+ public List get(String tableName, final List getList, final RowMapper mapper) {
+ return execute(tableName, new TableCallback>() {
+ @Override
+ public List doInTable(HTableInterface htable) throws Throwable {
+ Result[] result = htable.get(getList);
+ List list = new ArrayList(result.length);
+ for (int i = 0; i < result.length; i++) {
+ T t = mapper.mapRow(result[i], i);
+ list.add(t);
+ }
+ return list;
+ }
+ });
+ }
+
+
+ public void put(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final byte[] value) {
+ put(tableName, rowName, familyName, qualifier, null, value);
+ }
+
+ public void put(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final Long timestamp, final byte[] value) {
+ execute(tableName, new TableCallback() {
+ @Override
+ public Object doInTable(HTableInterface htable) throws Throwable {
+ Put put = new Put(rowName);
+ if (familyName != null) {
+ if (timestamp == null) {
+ put.add(familyName, qualifier, value);
+ } else {
+ put.add(familyName, qualifier, timestamp, value);
+ }
+ }
+ htable.put(put);
+ return null;
+ }
+ });
+ }
+
+ public void put(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final T value, final ValueMapper mapper) {
+ put(tableName, rowName, familyName, qualifier, null, value, mapper);
+ }
+
+ public void put(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final Long timestamp, final T value, final ValueMapper mapper) {
+ execute(tableName, new TableCallback() {
+ @Override
+ public T doInTable(HTableInterface htable) throws Throwable {
+ Put put = new Put(rowName);
+ byte[] bytes = mapper.mapValue(value);
+ if (familyName != null) {
+ if (timestamp == null) {
+ put.add(familyName, qualifier, bytes);
+ } else {
+ put.add(familyName, qualifier, timestamp, bytes);
+ }
+ }
+ htable.put(put);
+ return null;
+ }
+ });
+ }
+
+ public void put(String tableName, final Put put) {
+ execute(tableName, new TableCallback() {
+ @Override
+ public Object doInTable(HTableInterface htable) throws Throwable {
+ htable.put(put);
+ return null;
+ }
+ });
+ }
+
+ public void put(String tableName, final List puts) {
+ execute(tableName, new TableCallback() {
+ @Override
+ public Object doInTable(HTableInterface htable) throws Throwable {
+ htable.put(puts);
+ return null;
+ }
+ });
+ }
+
+ public void delete(String tableName, final Delete delete) {
+ execute(tableName, new TableCallback() {
+ @Override
+ public Object doInTable(HTableInterface htable) throws Throwable {
+ htable.delete(delete);
+ return null;
+ }
+ });
+ }
+
+ public void delete(String tableName, final List deletes) {
+ execute(tableName, new TableCallback() {
+ @Override
+ public Object doInTable(HTableInterface htable) throws Throwable {
+ htable.delete(deletes);
+ return null;
+ }
+ });
+ }
+
+ @Override
+ public List find(String tableName, final List scanList, final ResultsExtractor action) {
+ return execute(tableName, new TableCallback>() {
+ @Override
+ public List doInTable(HTableInterface htable) throws Throwable {
+ List result = new ArrayList(scanList.size());
+ for (Scan scan : scanList) {
+ final ResultScanner scanner = htable.getScanner(scan);
+ try {
+ T t = action.extractData(scanner);
+ result.add(t);
+ } finally {
+ scanner.close();
+ }
+ }
+ return result;
+ }
+ });
+ }
+
+ @Override
+ public List> find(String tableName, List scanList, RowMapper action) {
+ return find(tableName, scanList, new RowMapperResultsExtractor(action));
+ }
+
+ public List find(String tableName, final Scan scan, final AbstractRowKeyDistributor rowKeyDistributor, final RowMapper action) {
+ final ResultsExtractor> resultsExtractor = new RowMapperResultsExtractor(action);
+ return execute(tableName, new TableCallback>() {
+ @Override
+ public List doInTable(HTableInterface htable) throws Throwable {
+ final ResultScanner scanner = createDistributeScanner(htable, scan, rowKeyDistributor);
+ try {
+ return resultsExtractor.extractData(scanner);
+ } finally {
+ scanner.close();
+ }
+ }
+ });
+ }
+
+ public List find(String tableName, final Scan scan, final AbstractRowKeyDistributor rowKeyDistributor, int limit, final RowMapper action) {
+ final ResultsExtractor> resultsExtractor = new LimitRowMapperResultsExtractor(action, limit);
+ return execute(tableName, new TableCallback>() {
+ @Override
+ public List doInTable(HTableInterface htable) throws Throwable {
+ final ResultScanner scanner = createDistributeScanner(htable, scan, rowKeyDistributor);
+ try {
+ return resultsExtractor.extractData(scanner);
+ } finally {
+ scanner.close();
+ }
+ }
+ });
+ }
+
+ public List find(String tableName, final Scan scan, final AbstractRowKeyDistributor rowKeyDistributor, int limit, final RowMapper action, final LimitEventHandler limitEventHandler) {
+ final LimitRowMapperResultsExtractor resultsExtractor = new LimitRowMapperResultsExtractor(action, limit, limitEventHandler);
+ return execute(tableName, new TableCallback>() {
+ @Override
+ public List doInTable(HTableInterface htable) throws Throwable {
+ final ResultScanner scanner = createDistributeScanner(htable, scan, rowKeyDistributor);
+ try {
+ return resultsExtractor.extractData(scanner);
+ } finally {
+ scanner.close();
+ }
+ }
+ });
+ }
+
+
+ @Override
+ public T find(String tableName, final Scan scan, final AbstractRowKeyDistributor rowKeyDistributor, final ResultsExtractor action) {
+
+ return execute(tableName, new TableCallback() {
+ @Override
+ public T doInTable(HTableInterface htable) throws Throwable {
+ final boolean debugEnabled = logger.isDebugEnabled();
+ StopWatch watch = null;
+ if (debugEnabled) {
+ watch = new StopWatch();
+ watch.start();
+ }
+ final ResultScanner scanner = createDistributeScanner(htable, scan, rowKeyDistributor);
+ if (debugEnabled) {
+ logger.debug("DistributeScanner createTime:{}", watch.stop());
+ }
+ if (debugEnabled) {
+ watch.start();
+ }
+ try {
+ return action.extractData(scanner);
+ } finally {
+ scanner.close();
+ if (debugEnabled) {
+ logger.debug("DistributeScanner scanTime:{}", watch.stop());
+ }
+ }
+ }
+ });
+ }
+
+ public ResultScanner createDistributeScanner(HTableInterface htable, Scan originalScan, AbstractRowKeyDistributor rowKeyDistributor) throws IOException {
+
+ Scan[] scans = rowKeyDistributor.getDistributedScans(originalScan);
+ final int length = scans.length;
+ for(int i = 0; i < length; i++) {
+ Scan scan = scans[i];
+ scan.setId(originalScan.getId() + "-" + i);
+ // caching만 넣으면 되나?
+ scan.setCaching(originalScan.getCaching());
+ }
+
+ ResultScanner[] scanner = new ResultScanner[length];
+ boolean success = false;
+ try {
+ for (int i = 0; i < length; i++) {
+ scanner[i] = htable.getScanner(scans[i]);
+ }
+ success = true;
+ } finally {
+ if (!success) {
+ closeScanner(scanner);
+ }
+ }
+
+ return new DistributedScanner(rowKeyDistributor, scanner);
+ }
+
+ private void closeScanner(ResultScanner[] scannerList ) {
+ for (ResultScanner scanner : scannerList) {
+ if (scanner != null) {
+ try {
+ scanner.close();
+ } catch (Exception e) {
+ logger.warn("Scanner.close() error Caused:{}", e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ public Result increment(String tableName, final Increment increment) {
+ return execute(tableName, new TableCallback() {
+ @Override
+ public Result doInTable(HTableInterface htable) throws Throwable {
+ return htable.increment(increment);
+ }
+ });
+ }
+
+ public List increment(final String tableName, final List incrementList) {
+ return execute(tableName, new TableCallback>() {
+ @Override
+ public List doInTable(HTableInterface htable) throws Throwable {
+ final List resultList = new ArrayList(incrementList.size());
+
+ Exception lastException = null;
+ for (Increment increment : incrementList) {
+ try {
+ Result result = htable.increment(increment);
+ resultList.add(result);
+ } catch (IOException e) {
+ logger.warn("{} increment error Caused:{}", tableName, e.getMessage(), e);
+ lastException = e;
+ }
+ }
+ if (lastException != null) {
+ throw lastException;
+ }
+ return resultList;
+ }
+ });
+ }
+
+ public long incrementColumnValue(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final long amount) {
+ return execute(tableName, new TableCallback() {
+ @Override
+ public Long doInTable(HTableInterface htable) throws Throwable {
+ return htable.incrementColumnValue(rowName, familyName, qualifier, amount);
+ }
+ });
+ }
+
+ public long incrementColumnValue(String tableName, final byte[] rowName, final byte[] familyName, final byte[] qualifier, final long amount, final boolean writeToWAL) {
+ return execute(tableName, new TableCallback() {
+ @Override
+ public Long doInTable(HTableInterface htable) throws Throwable {
+ return htable.incrementColumnValue(rowName, familyName, qualifier, amount, writeToWAL);
+ }
+ });
+ }
+
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/LimitEventHandler.java b/src/main/java/com/nhn/pinpoint/common/hbase/LimitEventHandler.java
new file mode 100644
index 000000000..cd95e4573
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/LimitEventHandler.java
@@ -0,0 +1,10 @@
+package com.nhn.pinpoint.common.hbase;
+
+import org.apache.hadoop.hbase.client.Result;
+
+/**
+ * @author emeroad
+ */
+public interface LimitEventHandler {
+ void handleLastResult(Result lastResult);
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/LimitRowMapperResultsExtractor.java b/src/main/java/com/nhn/pinpoint/common/hbase/LimitRowMapperResultsExtractor.java
new file mode 100644
index 000000000..df3f60ca1
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/LimitRowMapperResultsExtractor.java
@@ -0,0 +1,84 @@
+package com.nhn.pinpoint.common.hbase;
+
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.client.ResultScanner;
+import org.springframework.data.hadoop.hbase.ResultsExtractor;
+import org.springframework.data.hadoop.hbase.RowMapper;
+import org.springframework.util.Assert;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author emeroad
+ */
+public class LimitRowMapperResultsExtractor implements ResultsExtractor> {
+
+ private static final LimitEventHandler EMPTY = new EmptyLimitEventHandler();
+
+ private int limit = Integer.MAX_VALUE;
+ private final RowMapper rowMapper;
+ private LimitEventHandler eventHandler;
+
+ public int getLimit() {
+ return limit;
+ }
+
+ public void setLimit(int limit) {
+ this.limit = limit;
+ }
+
+ /**
+ * Create a new RowMapperResultSetExtractor.
+ *
+ * @param rowMapper the RowMapper which creates an object for each row
+ */
+ public LimitRowMapperResultsExtractor(RowMapper rowMapper, int limit) {
+ this(rowMapper, limit, EMPTY);
+ }
+
+ /**
+ * Create a new RowMapperResultSetExtractor.
+ *
+ * @param rowMapper the RowMapper which creates an object for each row
+ */
+ public LimitRowMapperResultsExtractor(RowMapper rowMapper, int limit, LimitEventHandler eventHandler) {
+ Assert.notNull(rowMapper, "RowMapper is required");
+ Assert.notNull(eventHandler, "LimitEventHandler is required");
+ this.rowMapper = rowMapper;
+ this.limit = limit;
+ this.eventHandler = eventHandler;
+ }
+
+ public List extractData(ResultScanner results) throws Exception {
+ final List rs = new ArrayList();
+ int rowNum = 0;
+ Result lastResult = null;
+
+ for (Result result : results) {
+ final T t = this.rowMapper.mapRow(result, rowNum);
+ lastResult = result;
+ if (t instanceof Collection) {
+ rowNum += ((Collection>) t).size();
+ } else if (t instanceof Map) {
+ rowNum += ((Map, ?>) t).size();
+ } else if (t == null) {
+ // empty
+ } else if (t.getClass().isArray()) {
+ rowNum += Array.getLength(t);
+ } else {
+ rowNum++;
+ }
+ rs.add(t);
+ if (rowNum >= limit) {
+ break;
+ }
+ }
+
+ eventHandler.handleLastResult(lastResult);
+ return rs;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/PooledHTableFactory.java b/src/main/java/com/nhn/pinpoint/common/hbase/PooledHTableFactory.java
new file mode 100644
index 000000000..dd3ab4f2c
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/PooledHTableFactory.java
@@ -0,0 +1,48 @@
+package com.nhn.pinpoint.common.hbase;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.client.HTableInterface;
+import org.apache.hadoop.hbase.client.HTableInterfaceFactory;
+import org.apache.hadoop.hbase.client.HTablePool;
+import org.springframework.beans.factory.DisposableBean;
+
+import java.io.IOException;
+
+/**
+ * HTablePool 기반의 HTableInterfaceFactory.
+ * @author emeroad
+ */
+public class PooledHTableFactory implements HTableInterfaceFactory, DisposableBean {
+
+ private HTablePool hTablePool;
+ public static final int DEFAULT_POOL_SIZE = 256;
+
+ public PooledHTableFactory(Configuration config) {
+ this.hTablePool = new HTablePool(config, DEFAULT_POOL_SIZE);
+ }
+
+ public PooledHTableFactory(Configuration config, int poolSize) {
+ this.hTablePool = new HTablePool(config, poolSize);
+ }
+
+
+ @Override
+ public HTableInterface createHTableInterface(Configuration config, byte[] tableName) {
+ return hTablePool.getTable(tableName);
+ }
+
+ @Override
+ public void releaseHTableInterface(HTableInterface table) throws IOException {
+ if (table != null) {
+ table.close();
+ }
+ }
+
+
+ @Override
+ public void destroy() throws Exception {
+ if (hTablePool != null) {
+ this.hTablePool.close();
+ }
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/RowMapperResultsExtractor.java b/src/main/java/com/nhn/pinpoint/common/hbase/RowMapperResultsExtractor.java
new file mode 100644
index 000000000..960fc82b9
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/RowMapperResultsExtractor.java
@@ -0,0 +1,41 @@
+package com.nhn.pinpoint.common.hbase;
+
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.client.ResultScanner;
+import org.springframework.data.hadoop.hbase.ResultsExtractor;
+import org.springframework.data.hadoop.hbase.RowMapper;
+import org.springframework.util.Assert;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Spring꺼가 package라서 그냥 복사해옴.
+ * copy->Spring
+ * Adapter encapsulating the RowMapper callback.
+ *
+ * @author Costin Leau
+ */
+class RowMapperResultsExtractor implements ResultsExtractor> {
+
+ private final RowMapper rowMapper;
+
+ /**
+ * Create a new RowMapperResultSetExtractor.
+ *
+ * @param rowMapper the RowMapper which creates an object for each row
+ */
+ public RowMapperResultsExtractor(RowMapper rowMapper) {
+ Assert.notNull(rowMapper, "RowMapper is required");
+ this.rowMapper = rowMapper;
+ }
+
+ public List extractData(ResultScanner results) throws Exception {
+ List rs = new ArrayList();
+ int rowNum = 0;
+ for (Result result : results) {
+ rs.add(this.rowMapper.mapRow(result, rowNum++));
+ }
+ return rs;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/ValueMapper.java b/src/main/java/com/nhn/pinpoint/common/hbase/ValueMapper.java
new file mode 100644
index 000000000..e41551d69
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/ValueMapper.java
@@ -0,0 +1,8 @@
+package com.nhn.pinpoint.common.hbase;
+
+/**
+ * @author emeroad
+ */
+public interface ValueMapper {
+ byte[] mapValue(T value);
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/distributor/RangeOneByteSimpleHash.java b/src/main/java/com/nhn/pinpoint/common/hbase/distributor/RangeOneByteSimpleHash.java
new file mode 100644
index 000000000..cf2b453b2
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/distributor/RangeOneByteSimpleHash.java
@@ -0,0 +1,74 @@
+package com.nhn.pinpoint.common.hbase.distributor;
+
+
+import com.nhn.pinpoint.common.util.MathUtils;
+import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix;
+
+import java.util.Arrays;
+
+/**
+ * @author emeroad
+ */
+public class RangeOneByteSimpleHash implements RowKeyDistributorByHashPrefix.Hasher {
+ private final int start;
+ private final int end;
+ private int mod;
+
+ // Used to minimize # of created object instances
+ // Should not be changed. TODO: secure that
+ private static final byte[][] PREFIXES;
+
+ static {
+ PREFIXES = new byte[256][];
+ for (int i = 0; i < 256; i++) {
+ PREFIXES[i] = new byte[] {(byte) i};
+ }
+ }
+
+
+ public RangeOneByteSimpleHash(int start, int end, int maxBuckets) {
+ if (maxBuckets < 1 || maxBuckets > 256) {
+ throw new IllegalArgumentException("maxBuckets should be in 1..256 range");
+ }
+ this.start = start;
+ this.end = end;
+ // i.e. "real" maxBuckets value = maxBuckets or maxBuckets-1
+ this.mod = maxBuckets;
+ }
+
+ @Override
+ public byte[] getHashPrefix(byte[] originalKey) {
+ long hash = MathUtils.fastAbs(hashBytes(originalKey));
+ return new byte[] {(byte) (hash % mod)};
+ }
+
+ /** Compute hash for binary data. */
+ private int hashBytes(byte[] bytes) {
+ int min = Math.min(bytes.length, end);
+ int hash = 1;
+ for (int i = start; i < min; i++)
+ hash = (31 * hash) + (int) bytes[i];
+ return hash;
+ }
+
+ @Override
+ public byte[][] getAllPossiblePrefixes() {
+ return Arrays.copyOfRange(PREFIXES, 0, mod);
+ }
+
+ @Override
+ public int getPrefixLength(byte[] adjustedKey) {
+ return 1;
+ }
+
+ @Override
+ public String getParamsToStore() {
+ return String.valueOf(mod);
+ }
+
+ @Override
+ public void init(String storedParams) {
+ this.mod = Integer.valueOf(storedParams);
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/hbase/filter/ApplicationTraceIndexResponseTimeFilter.java b/src/main/java/com/nhn/pinpoint/common/hbase/filter/ApplicationTraceIndexResponseTimeFilter.java
new file mode 100644
index 000000000..798e75de7
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/hbase/filter/ApplicationTraceIndexResponseTimeFilter.java
@@ -0,0 +1,73 @@
+package com.nhn.pinpoint.common.hbase.filter;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.filter.FilterBase;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import com.nhn.pinpoint.common.buffer.Buffer;
+import com.nhn.pinpoint.common.buffer.OffsetFixedBuffer;
+
+/**
+ * value filter보다 column name에 prefix 붙여 filter하는것이 나을 듯하여 일단 deprecated 처리 함.
+ *
+ * @author netspider
+ *
+ */
+@Deprecated
+public class ApplicationTraceIndexResponseTimeFilter extends FilterBase {
+
+ private byte[] value = null;
+ private boolean filterRow = true;
+
+ private final int responseTimeFrom;
+ private final int responseTimeTo;
+
+ public ApplicationTraceIndexResponseTimeFilter(int responseTimeFrom, int responseTimeTo) {
+ super();
+ this.responseTimeFrom = responseTimeFrom;
+ this.responseTimeTo = responseTimeTo;
+ }
+
+ @Override
+ public void reset() {
+ // 새로운 값을 비교할 때마다 플래그 재설정.
+ this.filterRow = true;
+ }
+
+ @Override
+ public ReturnCode filterKeyValue(KeyValue kv) {
+ final byte[] buffer = kv.getBuffer();
+
+ final int valueOffset = kv.getValueOffset();
+ final Buffer valueBuffer = new OffsetFixedBuffer(buffer, valueOffset);
+ int elapsed = valueBuffer.readVarInt();
+
+ if (elapsed < responseTimeFrom || elapsed > responseTimeTo) {
+ // 조건에 맞지 않으면 row를 통과
+ filterRow = false;
+ }
+
+ // 실제 결정은 나중에 하기 때문에 항상 이 값을 반환
+ return ReturnCode.INCLUDE;
+ }
+
+ @Override
+ public boolean filterRow() {
+ // 실제 결정은 플래그 상태에 따라 이곳에서 이루어진다.
+ return filterRow;
+ }
+
+ @Override
+ public void readFields(DataInput dataInput) throws IOException {
+ this.value = Bytes.readByteArray(dataInput);
+ }
+
+ @Override
+ public void write(DataOutput dataOutput) throws IOException {
+ Bytes.writeByteArray(dataOutput, this.value);
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/AnnotationTranscoder.java b/src/main/java/com/nhn/pinpoint/common/util/AnnotationTranscoder.java
new file mode 100644
index 000000000..94f61a4c2
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/AnnotationTranscoder.java
@@ -0,0 +1,252 @@
+package com.nhn.pinpoint.common.util;
+
+
+import com.nhn.pinpoint.common.bo.IntStringStringValue;
+import com.nhn.pinpoint.common.bo.IntStringValue;
+import com.nhn.pinpoint.common.buffer.AutomaticBuffer;
+import com.nhn.pinpoint.common.buffer.Buffer;
+import com.nhn.pinpoint.common.buffer.FixedBuffer;
+import com.nhn.pinpoint.thrift.dto.TAnnotation;
+import com.nhn.pinpoint.thrift.dto.TAnnotationValue;
+import com.nhn.pinpoint.thrift.dto.TIntStringStringValue;
+import com.nhn.pinpoint.thrift.dto.TIntStringValue;
+
+/**
+ * @author emeroad
+ */
+public class AnnotationTranscoder {
+
+ static final byte CODE_STRING = 0;
+ static final byte CODE_NULL = 1;
+ static final byte CODE_INT = 2;
+ static final byte CODE_LONG = 3;
+
+ static final byte CODE_BOOLEAN_TRUE = 4;
+ static final byte CODE_BOOLEAN_FALSE = 5;
+
+ static final byte CODE_BYTEARRAY = 6;
+ static final byte CODE_BYTE = 7;
+
+ static final byte CODE_SHORT = 8;
+ static final byte CODE_FLOAT = 9;
+ static final byte CODE_DOUBLE = 10;
+ static final byte CODE_TOSTRING = 11;
+ // multivalue
+ static final byte CODE_INT_STRING = 20;
+ static final byte CODE_INT_STRING_STRING = 21;
+
+
+ public Object getMappingValue(TAnnotation annotation) {
+ final TAnnotationValue value = annotation.getValue();
+ if (value == null) {
+ return null;
+ }
+ return value.getFieldValue();
+ }
+
+
+ public Object decode(final byte dataType, final byte[] data) {
+ switch (dataType) {
+ case CODE_STRING:
+ return decodeString(data);
+ case CODE_BOOLEAN_TRUE:
+ return Boolean.TRUE;
+ case CODE_BOOLEAN_FALSE:
+ return Boolean.FALSE;
+ case CODE_INT: {
+ final Buffer buffer = new FixedBuffer(data);
+ return buffer.readSVarInt();
+ }
+ case CODE_LONG: {
+ final Buffer buffer = new FixedBuffer(data);
+ return buffer.readSVarLong();
+ }
+ case CODE_BYTE:
+ return data[0];
+ case CODE_SHORT:
+ final Buffer buffer = new FixedBuffer(data);
+ return (short)buffer.readSVarInt();
+ case CODE_FLOAT:
+ return Float.intBitsToFloat(BytesUtils.bytesToInt(data, 0));
+ case CODE_DOUBLE:
+ return Double.longBitsToDouble(BytesUtils.bytesToLong(data, 0));
+ case CODE_BYTEARRAY:
+ return data;
+ case CODE_NULL:
+ return null;
+ case CODE_TOSTRING:
+ return decodeString(data);
+ case CODE_INT_STRING:
+ return decodeIntStringValue(data);
+ case CODE_INT_STRING_STRING:
+ return decodeIntStringStringValue(data);
+ }
+ throw new IllegalArgumentException("unsupported DataType:" + dataType);
+ }
+
+ public byte getTypeCode(Object o) {
+ if (o == null) {
+ return CODE_NULL;
+ }
+ if (o instanceof String) {
+ return CODE_STRING;
+ } else if (o instanceof Long) {
+ return CODE_LONG;
+ } else if (o instanceof Integer) {
+ return CODE_INT;
+ } else if (o instanceof Boolean) {
+ if (Boolean.TRUE.equals(o)) {
+ return CODE_BOOLEAN_TRUE;
+ }
+ return CODE_BOOLEAN_FALSE;
+ } else if (o instanceof Byte) {
+ return CODE_BYTE;
+ } else if (o instanceof Short) {
+ return CODE_SHORT;
+ } else if (o instanceof Float) {
+ // thrift에서 지원안함.
+ return CODE_FLOAT;
+ } else if (o instanceof Double) {
+ return CODE_DOUBLE;
+ } else if (o instanceof byte[]) {
+ return CODE_BYTEARRAY;
+ } else if(o instanceof TIntStringValue) {
+ return CODE_INT_STRING;
+ } else if(o instanceof TIntStringStringValue) {
+ return CODE_INT_STRING_STRING;
+ }
+ return CODE_TOSTRING;
+ }
+
+ public byte[] encode(Object o, int typeCode) {
+ switch (typeCode) {
+ case CODE_STRING:
+ return encodeString((String) o);
+ case CODE_INT: {
+ final Buffer buffer = new FixedBuffer(BytesUtils.VINT_MAX_SIZE);
+ buffer.putSVar((Integer)o);
+ return buffer.getBuffer();
+ }
+ case CODE_BOOLEAN_TRUE: {
+ return new byte[0];
+ }
+ case CODE_BOOLEAN_FALSE: {
+ return new byte[0];
+ }
+ case CODE_LONG: {
+ final Buffer buffer = new FixedBuffer(BytesUtils.VLONG_MAX_SIZE);
+ buffer.putSVar((Long)o);
+ return buffer.getBuffer();
+ }
+ case CODE_BYTE: {
+ final byte[] bytes = new byte[1];
+ bytes[0] = (Byte)o;
+ return bytes;
+ }
+ case CODE_SHORT: {
+ final Buffer buffer = new FixedBuffer(BytesUtils.VINT_MAX_SIZE);
+ buffer.putSVar((Short) o);
+ return buffer.getBuffer();
+ }
+ case CODE_FLOAT: {
+ final byte[] buffer = new byte[4];
+ BytesUtils.writeInt(Float.floatToRawIntBits((Float) o), buffer, 0);
+ return buffer;
+ }
+ case CODE_DOUBLE: {
+ final byte[] buffer = new byte[8];
+ BytesUtils.writeLong(Double.doubleToRawLongBits((Double) o), buffer, 0);
+ return buffer;
+ }
+ case CODE_BYTEARRAY:
+ return (byte[]) o;
+ case CODE_NULL:
+ return null;
+ case CODE_TOSTRING:
+ final String str = o.toString();
+ return encodeString(str);
+ case CODE_INT_STRING:
+ return encodeIntStringValue(o);
+ case CODE_INT_STRING_STRING:
+ return encodeIntStringStringValue(o);
+ }
+ throw new IllegalArgumentException("unsupported DataType:" + typeCode + " data:" + o);
+ }
+
+
+ private Object decodeIntStringValue(byte[] data) {
+ final Buffer buffer = new FixedBuffer(data);
+ final int intValue = buffer.readSVarInt();
+ final String stringValue = BytesUtils.toString(buffer.readPrefixedBytes());
+ return new IntStringValue(intValue, stringValue);
+ }
+
+ private byte[] encodeIntStringValue(Object value) {
+ final TIntStringValue tIntStringValue = (TIntStringValue) value;
+ final int intValue = tIntStringValue.getIntValue();
+ final byte[] stringValue = BytesUtils.toBytes(tIntStringValue.getStringValue());
+ // 대충 크기 더함. 나중에 좀더 정교하게 계산하자.
+ final int bufferSize = getBufferSize(stringValue, 4 + 8);
+ final Buffer buffer = new AutomaticBuffer(bufferSize);
+ buffer.putSVar(intValue);
+ buffer.putPrefixedBytes(stringValue);
+ return buffer.getBuffer();
+ }
+
+ private int getBufferSize(byte[] stringValue, int reserve) {
+ if (stringValue == null) {
+ return reserve;
+ } else {
+ return stringValue.length + reserve;
+ }
+ }
+
+ private Object decodeIntStringStringValue(byte[] data) {
+ final Buffer buffer = new FixedBuffer(data);
+ final int intValue = buffer.readSVarInt();
+ final String stringValue1 = BytesUtils.toString(buffer.readPrefixedBytes());
+ final String stringValue2 = BytesUtils.toString(buffer.readPrefixedBytes());
+ return new IntStringStringValue(intValue, stringValue1, stringValue2);
+ }
+
+ private byte[] encodeIntStringStringValue(Object o) {
+ final TIntStringStringValue tIntStringStringValue = (TIntStringStringValue) o;
+ final int intValue = tIntStringStringValue.getIntValue();
+ final byte[] stringValue1 = BytesUtils.toBytes(tIntStringStringValue.getStringValue1());
+ final byte[] stringValue2 = BytesUtils.toBytes(tIntStringStringValue.getStringValue2());
+ // 대충 크기 더함. 나중에 좀더 정교하게 계산하자.
+ final int bufferSize = getBufferSize(stringValue1, stringValue2, 4 + 8);
+ final Buffer buffer = new AutomaticBuffer(bufferSize);
+ buffer.putSVar(intValue);
+ buffer.putPrefixedBytes(stringValue1);
+ buffer.putPrefixedBytes(stringValue2);
+ return buffer.getBuffer();
+ }
+
+ private int getBufferSize(byte[] stringValue1, byte[] stringValue2, int reserve) {
+ int length = 0;
+ if (stringValue1 != null) {
+ length += stringValue1.length;
+ }
+ if (stringValue2 != null) {
+ length += stringValue2.length;
+
+ }
+ return length + reserve;
+ }
+
+
+ /**
+ * Decode the string with the current character set.
+ */
+ protected String decodeString(byte[] data) {
+ return BytesUtils.toString(data);
+ }
+
+ /**
+ * Encode a string into the current character set.
+ */
+ protected byte[] encodeString(String in) {
+ return BytesUtils.toBytes(in);
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/AnnotationUtils.java b/src/main/java/com/nhn/pinpoint/common/util/AnnotationUtils.java
new file mode 100644
index 000000000..eb2295c5a
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/AnnotationUtils.java
@@ -0,0 +1,125 @@
+package com.nhn.pinpoint.common.util;
+
+import java.util.*;
+
+import com.nhn.pinpoint.common.AnnotationKey;
+import com.nhn.pinpoint.common.ServiceType;
+import com.nhn.pinpoint.common.bo.AnnotationBo;
+import com.nhn.pinpoint.common.bo.Span;
+
+/**
+ * @author emeroad
+ */
+public class AnnotationUtils {
+
+ public static String findApiAnnotation(List list) {
+ if (list == null) {
+ return null;
+ }
+ AnnotationBo annotationBo = findAnnotationBo(list, AnnotationKey.API);
+ if (annotationBo != null) {
+ return (String) annotationBo.getValue();
+ }
+ return null;
+ }
+
+ public static AnnotationBo findAnnotationBo(List annotationBoList, AnnotationKey annotationKey) {
+ for (AnnotationBo annotation : annotationBoList) {
+ int key = annotation.getKey();
+ if (annotationKey.getCode() == key) {
+ return annotation;
+ }
+ }
+ return null;
+ }
+
+ public static AnnotationBo findArgsAnnotationBo(List annotationBoList) {
+ for (AnnotationBo annotation : annotationBoList) {
+ if (AnnotationKey.isArgsKey(annotation.getKey())) {
+ return annotation;
+ }
+ }
+ return null;
+ }
+
+ public static AnnotationBo getDisplayArgument(Span span) {
+ // arcus 관련 일반화 필요.
+ List list = span.getAnnotationBoList();
+ if (list == null) {
+ return null;
+ }
+ final ServiceType serviceType = span.getServiceType();
+ if (serviceType == ServiceType.ARCUS || serviceType == ServiceType.MEMCACHED) {
+ // 첫번째 args아무거나 하나를 디스플레이에 뿌린다.
+ // TODO 2개 이상일 경우의 케이스 일때 비기는 하나, 현재 arucs쪽 파라미터 덤프키는 일단 1개뿐이라 괜찮을듯하다.
+ return findArgsAnnotationBo(list);
+ }
+
+ // rpc connector의 경우 보여주는 code일반화 필요.
+ if (serviceType == ServiceType.HTTP_CLIENT || serviceType == ServiceType.JDK_HTTPURLCONNECTOR) {
+ return findAnnotationBo(list, AnnotationKey.HTTP_URL);
+ }
+
+
+// span에 해당하는 Tomcat의 경우 Span에 포함된 rpc 필드를 사용하므로 annotation에서 찾을필요가 없음.
+// if (span.getServiceType() == ServiceType.TOMCAT) {
+// return findAnnotationBo(list, AnnotationKey.HTTP_URL);
+// }
+//
+ // TODO 먼가 고쳐야 함.
+ if (serviceType == ServiceType.MYSQL || serviceType == ServiceType.MYSQL_EXECUTE_QUERY
+ || serviceType == ServiceType.ORACLE || serviceType == ServiceType.ORACLE_EXECUTE_QUERY
+ || serviceType == ServiceType.MSSQL || serviceType == ServiceType.MSSQL_EXECUTE_QUERY
+ || serviceType == ServiceType.CUBRID || serviceType == ServiceType.CUBRID_EXECUTE_QUERY) {
+ // args 0의 경우 연결string이다
+ // 구현 방법이 매우 구림 좀더 개선 필요.
+ return findAnnotationBo(list, AnnotationKey.ARGS0);
+ }
+
+ if (serviceType == ServiceType.IBATIS || serviceType == ServiceType.MYBATIS) {
+ return findAnnotationBo(list, AnnotationKey.ARGS0);
+ }
+
+ if (serviceType == ServiceType.SPRING_ORM_IBATIS) {
+ return findAnnotationBo(list, AnnotationKey.ARGS0);
+ }
+
+ return null;
+ }
+
+ private static List API_META_DATA_ERROR;
+ static {
+ API_META_DATA_ERROR = loadApiMetaDataError();
+ }
+
+ static List loadApiMetaDataError() {
+ List apiMetaData = new ArrayList();
+ for (AnnotationKey annotationKey : AnnotationKey.values()) {
+ if (annotationKey.name().startsWith("ERROR_API_METADATA_")) {
+ apiMetaData.add(annotationKey);
+ }
+ }
+ return apiMetaData;
+ }
+
+ public static AnnotationKey getApiMetaDataError(List annotationBoList) {
+ for (AnnotationBo bo : annotationBoList) {
+ AnnotationKey apiErrorCode = findApiErrorCode(bo);
+ if (apiErrorCode != null) {
+ return apiErrorCode;
+ }
+ }
+ // 정확한 에러 코드를 못찾음. 퉁쳐서 에러 처리
+ return AnnotationKey.ERROR_API_METADATA_ERROR;
+ }
+
+ private static AnnotationKey findApiErrorCode(AnnotationBo bo) {
+ for (AnnotationKey annotationKey : API_META_DATA_ERROR) {
+ if (bo.getKey() == annotationKey.getCode()) {
+ return annotationKey;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/ApiDescription.java b/src/main/java/com/nhn/pinpoint/common/util/ApiDescription.java
new file mode 100644
index 000000000..3e84fa32c
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/ApiDescription.java
@@ -0,0 +1,80 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+public class ApiDescription {
+
+ private String className;
+
+ private String methodName;
+
+ private String[] simpleParameter;
+
+ private int line = -1;
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public String getSimpleClassName() {
+ int classNameStartIndex = className.lastIndexOf('.') + 1;
+ return className.substring(classNameStartIndex, className.length());
+ }
+
+ public String getPackageNameName() {
+ int packageNameIndex = className.lastIndexOf('.');
+ if (packageNameIndex == -1) {
+ return "";
+ }
+ return className.substring(0, packageNameIndex);
+ }
+
+
+ public void setMethodName(String methodName) {
+ this.methodName = methodName;
+ }
+
+ public String getMethodName() {
+ return this.methodName;
+ }
+
+ public void setSimpleParameter(String[] simpleParameter) {
+ this.simpleParameter = simpleParameter;
+ }
+
+ public String[] getSimpleParameter() {
+ return simpleParameter;
+ }
+
+ public void setLine(int line) {
+ this.line = line;
+ }
+
+ public String getSimpleMethodDescription() {
+ String simpleParameterDescription = concateLine(simpleParameter, ", ");
+ return methodName + simpleParameterDescription;
+ }
+
+ public String concateLine(String[] stringList, String separator) {
+ if (stringList == null || stringList.length == 0) {
+ return "()";
+ }
+
+ StringBuilder sb = new StringBuilder();
+ if (stringList.length > 0) {
+ sb.append('(');
+ sb.append(stringList[0]);
+ for (int i = 1; i < stringList.length; i++) {
+ sb.append(separator);
+ sb.append(stringList[i]);
+ }
+ sb.append(')');
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/ApiDescriptionParser.java b/src/main/java/com/nhn/pinpoint/common/util/ApiDescriptionParser.java
new file mode 100644
index 000000000..9da123105
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/ApiDescriptionParser.java
@@ -0,0 +1,109 @@
+package com.nhn.pinpoint.common.util;
+
+import org.slf4j.LoggerFactory;
+
+import java.util.regex.Pattern;
+
+/**
+ * MethodDescriptor 과 비슷한데. 문자열을 기반으로 parsing하여 생성하므로 따로 만들었음.
+ * @author emeroad
+ */
+public class ApiDescriptionParser {
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+ private static final char DOT = '.';
+ private static final char METHOD_PARAM_START = '(';
+ private static final char METHOD_PARAM_END = ')';
+ private static final char PARAMETER_SP = ',';
+ private static Pattern PARAMETER_REGEX = Pattern.compile(", |,");
+ // org.springframework.web.servlet.FrameworkServlet.doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
+// com.mysql.jdbc.ConnectionImpl.setAutoCommit(boolean autoCommitFlag)
+// com.mysql.jdbc.ConnectionImpl.commit()
+
+ // org.apache.catalina.core.StandardHostValve.invoke(org.apache.catalina.connector.Request request, org.apache.catalina.connector.Response response):110
+ public ApiDescription parse(String apiDescriptionString) {
+ if (apiDescriptionString == null) {
+ throw new NullPointerException("apiDescriptionString must not be null");
+ }
+
+ final int methodStart = apiDescriptionString.lastIndexOf(METHOD_PARAM_START);
+ if (methodStart == -1) {
+ throw new IllegalArgumentException("'(' not found. invalid apiDescriptionString:" + apiDescriptionString);
+ }
+
+ final int methodEnd = apiDescriptionString.lastIndexOf(METHOD_PARAM_END);
+ if (methodEnd == -1) {
+ throw new IllegalArgumentException("')' not found. invalid apiDescriptionString:" + apiDescriptionString);
+ }
+
+ final int classIndex = apiDescriptionString.lastIndexOf(DOT, methodStart);
+ if (classIndex == -1) {
+ throw new IllegalArgumentException("'.' not found. invalid apiDescriptionString:" + apiDescriptionString);
+ }
+
+ String className = parseClassName(apiDescriptionString, classIndex);
+ ApiDescription api = new ApiDescription();
+ api.setClassName(className);
+
+ String methodName = parseMethodName(apiDescriptionString, methodStart, classIndex);
+ api.setMethodName(methodName);
+
+ String parameterDescriptor = apiDescriptionString.substring(methodStart + 1, methodEnd);
+ String[] parameterList = parseParameter(parameterDescriptor);
+ String[] simpleParameterList = parseSimpleParameter(parameterList);
+ api.setSimpleParameter(simpleParameterList);
+
+ int lineIndex = apiDescriptionString.lastIndexOf(':');
+ // 일단 땜방으로 lineNumber체크해서 lineNumber를 뿌려주도록 하자.
+ if (lineIndex != -1) {
+ try {
+ int line = Integer.parseInt(apiDescriptionString.substring(lineIndex + 1, apiDescriptionString.length()));
+ api.setLine(line);
+ } catch (NumberFormatException e) {
+ LoggerFactory.getLogger(this.getClass()).warn("line number parse error {}", e);
+ }
+ }
+
+ return api;
+ }
+
+ private String[] parseSimpleParameter(String[] parameterList) {
+ if (parameterList == null || parameterList.length == 0) {
+ return EMPTY_STRING_ARRAY;
+ }
+ String[] simple = new String[parameterList.length];
+ for (int i = 0; i < parameterList.length; i++) {
+ simple[i] = simepleParameter(parameterList[i]);
+ }
+ return simple;
+ }
+
+ private String simepleParameter(String parameter) {
+ int packageIndex = parameter.lastIndexOf(DOT);
+ if (packageIndex == -1) {
+ // 없을 경우 아래 로직가 동일하나 추후 뭔가 변경사항이 생길수 있어 명시적으로 체크하는 로직으로 구현.
+ packageIndex = 0;
+ } else {
+ packageIndex += 1;
+ }
+
+
+ return parameter.substring(packageIndex, parameter.length());
+ }
+
+ private String[] parseParameter(String parameterDescriptor) {
+ if (parameterDescriptor == null || parameterDescriptor.length() == 0) {
+ return EMPTY_STRING_ARRAY;
+ }
+ return PARAMETER_REGEX.split(parameterDescriptor);
+
+ }
+
+ private String parseClassName(String apiDescriptionString, int classIndex) {
+ return apiDescriptionString.substring(0, classIndex);
+ }
+
+ private String parseMethodName(String apiDescriptionString, int methodStart, int classIndex) {
+ return apiDescriptionString.substring(classIndex + 1, methodStart);
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/ApplicationMapStatisticsUtils.java b/src/main/java/com/nhn/pinpoint/common/util/ApplicationMapStatisticsUtils.java
new file mode 100644
index 000000000..7e3f48147
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/ApplicationMapStatisticsUtils.java
@@ -0,0 +1,151 @@
+package com.nhn.pinpoint.common.util;
+
+import com.nhn.pinpoint.common.HistogramSchema;
+import com.nhn.pinpoint.common.HistogramSlot;
+import com.nhn.pinpoint.common.ServiceType;
+import com.nhn.pinpoint.common.buffer.AutomaticBuffer;
+import com.nhn.pinpoint.common.buffer.Buffer;
+import com.nhn.pinpoint.common.hbase.HBaseTables;
+import org.apache.hadoop.hbase.util.Bytes;
+
+
+/**
+ *
+ * columnName format = SERVICETYPE(2bytes) + SLOT(2bytes) + APPNAMELEN(2bytes) + APPLICATIONNAME(str) + HOST(str)
+ *
+ *
+ * @author netspider
+ * @author emeroad
+ */
+public class ApplicationMapStatisticsUtils {
+
+ public static byte[] makeColumnName(short serviceType, String applicationName, String destHost, short slotNumber) {
+ if (applicationName == null) {
+ throw new NullPointerException("applicationName must not be null");
+ }
+ if (destHost == null) {
+ // throw new NullPointerException("destHost must not be null");
+ destHost = "";
+ }
+ byte[] serviceTypeBytes = Bytes.toBytes(serviceType);
+ byte[] slotNumberBytes = Bytes.toBytes(slotNumber);
+ byte[] applicationNameBytes = Bytes.toBytes(applicationName);
+ byte[] applicationNameLenBytes = Bytes.toBytes((short) applicationNameBytes.length);
+ byte[] destHostBytes = Bytes.toBytes(destHost);
+
+ return BytesUtils.concat(serviceTypeBytes, slotNumberBytes, applicationNameLenBytes, applicationNameBytes, destHostBytes);
+ }
+
+ public static short getSlotNumber(short serviceType, int elapsed, boolean isError) {
+ if (isError) {
+ return HBaseTables.STATISTICS_CQ_ERROR_SLOT_NUMBER;
+ } else {
+ return findResponseHistogramSlotNo(serviceType, elapsed);
+ }
+ }
+
+
+ public static byte[] makeColumnName(String agentId, short columnSlotNumber) {
+ if (agentId == null) {
+ agentId = "";
+ }
+ final byte[] slotNumber = Bytes.toBytes(columnSlotNumber);
+ final byte[] agentIdBytes = Bytes.toBytes(agentId);
+
+ return BytesUtils.concat(slotNumber, agentIdBytes);
+ }
+
+
+ private static short findResponseHistogramSlotNo(short serviceType, int elapsed) {
+ final HistogramSchema histogramSchema = ServiceType.findServiceType(serviceType).getHistogramSchema();
+ final HistogramSlot histogramSlot = histogramSchema.findHistogramSlot(elapsed);
+ return histogramSlot.getSlotTime();
+ }
+
+ public static short getDestServiceTypeFromColumnName(byte[] bytes) {
+ return BytesUtils.bytesToShort(bytes, 0);
+ }
+
+ /**
+ * @param bytes
+ * @return
+ * 0 > : ms
+ * 0 : slow
+ * -1 : error
+ *
+ */
+ public static short getHistogramSlotFromColumnName(byte[] bytes) {
+ return BytesUtils.bytesToShort(bytes, 2);
+ }
+
+ public static String getDestApplicationNameFromColumnName(byte[] bytes) {
+ final short length = BytesUtils.bytesToShort(bytes, 4);
+ return BytesUtils.toStringAndRightTrim(bytes, 6, length);
+ }
+
+ public static String getHost(byte[] bytes) {
+ int offset = 6 + BytesUtils.bytesToShort(bytes, 4);
+
+ if (offset == bytes.length) {
+ return null;
+ }
+ return BytesUtils.toStringAndRightTrim(bytes, offset, bytes.length - offset);
+ }
+
+ /**
+ *
+ * rowkey format = "APPLICATIONNAME(max 24bytes)" + apptype(2byte) + "TIMESTAMP(8byte)"
+ *
+ *
+ * @param applicationName
+ * @param timestamp
+ * @return
+ */
+ public static byte[] makeRowKey(String applicationName, short applicationType, long timestamp) {
+ if (applicationName == null) {
+ throw new NullPointerException("applicationName must not be null");
+ }
+ final byte[] applicationNameBytes= BytesUtils.toBytes(applicationName);
+
+ final Buffer buffer = new AutomaticBuffer(2 + applicationNameBytes.length + 2 + 8);
+// buffer.put2PrefixedString(applicationName);
+ buffer.put((short)applicationNameBytes.length);
+ buffer.put(applicationNameBytes);
+ buffer.put(applicationType);
+ long reverseTimeMillis = TimeUtils.reverseTimeMillis(timestamp);
+ buffer.put(reverseTimeMillis);
+ return buffer.getBuffer();
+ }
+
+ public static String getApplicationNameFromRowKey(byte[] bytes, int offset) {
+ if (bytes == null) {
+ throw new NullPointerException("bytes must not be null");
+ }
+ short applicationNameLength = BytesUtils.bytesToShort(bytes, offset);
+ return BytesUtils.toString(bytes, offset + 2, applicationNameLength); //.trim();
+ }
+
+ public static String getApplicationNameFromRowKey(byte[] bytes) {
+ return getApplicationNameFromRowKey(bytes, 0);
+ }
+
+ public static short getApplicationTypeFromRowKey(byte[] bytes) {
+ return getApplicationTypeFromRowKey(bytes, 0);
+ }
+
+ public static short getApplicationTypeFromRowKey(byte[] bytes, int offset) {
+ if (bytes == null) {
+ throw new NullPointerException("bytes must not be null");
+ }
+ short applicationNameLength = BytesUtils.bytesToShort(bytes, offset);
+ return BytesUtils.bytesToShort(bytes, offset + applicationNameLength + 2);
+ }
+
+ public static long getTimestampFromRowKey(byte[] bytes) {
+ if (bytes == null) {
+ throw new NullPointerException("bytes must not be null");
+ }
+ short applicationNameLength = BytesUtils.bytesToShort(bytes, 0);
+ return TimeUtils.recoveryTimeMillis(BytesUtils.bytesToLong(bytes, applicationNameLength + 4));
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/BytesUtils.java b/src/main/java/com/nhn/pinpoint/common/util/BytesUtils.java
new file mode 100644
index 000000000..e2b0f986f
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/BytesUtils.java
@@ -0,0 +1,530 @@
+package com.nhn.pinpoint.common.util;
+
+
+import java.io.UnsupportedEncodingException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author emeroad
+ */
+public final class BytesUtils {
+ public static final int SHORT_BYTE_LENGTH = 2;
+ public static final int INT_BYTE_LENGTH = 4;
+ public static final int LONG_BYTE_LENGTH = 8;
+ public static final int LONG_LONG_BYTE_LENGTH = 16;
+
+ public static final int VLONG_MAX_SIZE = 10;
+ public static final int VINT_MAX_SIZE = 5;
+
+ private static final byte[] EMPTY_BYTES = new byte[0];
+ private static final String UTF8 = "UTF-8";
+ private static final Logger LOGGER = Logger.getLogger(BytesUtils.class.getName());
+
+ @Deprecated
+ public static byte[] longLongToBytes(final long value1, final long value2) {
+ final byte[] buffer = new byte[LONG_LONG_BYTE_LENGTH];
+ writeFirstLong0(value1, buffer);
+ writeSecondLong0(value2, buffer);
+ return buffer;
+ }
+
+ public static byte[] stringLongLongToBytes(final String string, final int maxStringSize, final long value1, final long value2) {
+ if (string == null) {
+ throw new NullPointerException("string must not be null");
+ }
+ if (maxStringSize < 0) {
+ throw new IllegalArgumentException("maxStringSize");
+ }
+ final byte[] stringBytes = toBytes(string);
+ if (stringBytes.length > maxStringSize) {
+ throw new IllegalArgumentException("string is max " + stringBytes.length + ", string='" + string + "'");
+ }
+ final byte[] buffer = new byte[LONG_LONG_BYTE_LENGTH + maxStringSize];
+ writeBytes(buffer, 0, stringBytes);
+ writeFirstLong0(value1, buffer, maxStringSize);
+ writeSecondLong0(value2, buffer, maxStringSize);
+ return buffer;
+ }
+
+ public static void writeBytes(final byte[] buffer, int offset, final byte[] stringBytes) {
+ if (buffer == null) {
+ throw new NullPointerException("buffer must not be null");
+ }
+ if (stringBytes == null) {
+ throw new NullPointerException("stringBytes must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ System.arraycopy(stringBytes, 0, buffer, offset, stringBytes.length);
+ }
+
+ @Deprecated
+ public static long[] bytesToLongLong(final byte[] buf) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (buf.length < LONG_LONG_BYTE_LENGTH) {
+ throw new IllegalArgumentException("Illegal buf size.");
+ }
+ final long[] result = new long[2];
+
+ result[0] = bytesToFirstLong0(buf);
+ result[1] = bytesToSecondLong0(buf);
+
+ return result;
+ }
+
+ public static long bytesToLong(final byte[] buf, final int offset) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ if (buf.length < offset + LONG_BYTE_LENGTH) {
+ throw new IllegalArgumentException("buf.length is too small. buf.length:" + buf.length + " offset:" + (offset + 8));
+ }
+
+ final long rv = (((long) buf[offset] & 0xff) << 56)
+ | (((long) buf[offset + 1] & 0xff) << 48)
+ | (((long) buf[offset + 2] & 0xff) << 40)
+ | (((long) buf[offset + 3] & 0xff) << 32)
+ | (((long) buf[offset + 4] & 0xff) << 24)
+ | (((long) buf[offset + 5] & 0xff) << 16)
+ | (((long) buf[offset + 6] & 0xff) << 8)
+ | (((long) buf[offset + 7] & 0xff));
+ return rv;
+ }
+
+ public static int bytesToInt(final byte[] buf, final int offset) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ if (buf.length < offset + INT_BYTE_LENGTH) {
+ throw new IllegalArgumentException("buf.length is too small. buf.length:" + buf.length + " offset:" + (offset + 4));
+ }
+
+ final int v = ((buf[offset] & 0xff) << 24)
+ | ((buf[offset + 1] & 0xff) << 16)
+ | ((buf[offset + 2] & 0xff) << 8)
+ | ((buf[offset + 3] & 0xff));
+
+ return v;
+ }
+
+ public static short bytesToShort(final byte[] buf, final int offset) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ if (buf.length < offset + SHORT_BYTE_LENGTH) {
+ throw new IllegalArgumentException("buf.length is too small. buf.length:" + buf.length + " offset:" + (offset + 2));
+ }
+
+ final short v = (short) (((buf[offset] & 0xff) << 8) | ((buf[offset + 1] & 0xff)));
+
+ return v;
+ }
+
+ public static short bytesToShort(final byte byte1, final byte byte2) {
+ return (short) (((byte1 & 0xff) << 8) | ((byte2 & 0xff)));
+ }
+
+ public static long bytesToFirstLong(final byte[] buf) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (buf.length < LONG_BYTE_LENGTH) {
+ throw new IllegalArgumentException("buf.length is too small(8). buf.length:" + buf.length);
+ }
+
+ return bytesToFirstLong0(buf);
+ }
+
+ private static long bytesToFirstLong0(byte[] buf) {
+ final long rv = (((long) buf[0] & 0xff) << 56)
+ | (((long) buf[1] & 0xff) << 48)
+ | (((long) buf[2] & 0xff) << 40)
+ | (((long) buf[3] & 0xff) << 32)
+ | (((long) buf[4] & 0xff) << 24)
+ | (((long) buf[5] & 0xff) << 16)
+ | (((long) buf[6] & 0xff) << 8)
+ | (((long) buf[7] & 0xff));
+ return rv;
+ }
+
+ public static long bytesToSecondLong(final byte[] buf) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (buf.length < LONG_LONG_BYTE_LENGTH) {
+ throw new IllegalArgumentException("buf.length is too small(16). buf.length:" + buf.length);
+ }
+
+ return bytesToSecondLong0(buf);
+ }
+
+ private static long bytesToSecondLong0(final byte[] buf) {
+ final long rv = (((long) buf[8] & 0xff) << 56)
+ | (((long) buf[9] & 0xff) << 48)
+ | (((long) buf[10] & 0xff) << 40)
+ | (((long) buf[11] & 0xff) << 32)
+ | (((long) buf[12] & 0xff) << 24)
+ | (((long) buf[13] & 0xff) << 16)
+ | (((long) buf[14] & 0xff) << 8)
+ | (((long) buf[15] & 0xff));
+ return rv;
+ }
+
+ public static int writeLong(final long value, final byte[] buf, int offset) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ if (buf.length < offset + LONG_BYTE_LENGTH) {
+ throw new IllegalArgumentException("buf.length is too small. buf.length:" + buf.length + " offset:" + (offset + 8));
+ }
+ buf[offset++] = (byte) (value >> 56);
+ buf[offset++] = (byte) (value >> 48);
+ buf[offset++] = (byte) (value >> 40);
+ buf[offset++] = (byte) (value >> 32);
+ buf[offset++] = (byte) (value >> 24);
+ buf[offset++] = (byte) (value >> 16);
+ buf[offset++] = (byte) (value >> 8);
+ buf[offset++] = (byte) (value);
+ return offset;
+ }
+
+ public static byte writeShort1(final short value) {
+ return (byte) (value >> 8);
+ }
+
+ public static byte writeShort2(final short value) {
+ return (byte) (value);
+ }
+
+ public static int writeShort(final short value, final byte[] buf, int offset) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ if (buf.length < offset + SHORT_BYTE_LENGTH) {
+ throw new IllegalArgumentException("buf.length is too small. buf.length:" + buf.length + " offset:" + (offset + 2));
+ }
+ buf[offset++] = (byte) (value >> 8);
+ buf[offset++] = (byte) (value);
+ return offset;
+ }
+
+ public static int writeInt(final int value, final byte[] buf, int offset) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ if (buf.length < offset + INT_BYTE_LENGTH) {
+ throw new IllegalArgumentException("buf.length is too small. buf.length:" + buf.length + " offset:" + (offset + 4));
+ }
+ buf[offset++] = (byte) (value >> 24);
+ buf[offset++] = (byte) (value >> 16);
+ buf[offset++] = (byte) (value >> 8);
+ buf[offset++] = (byte) (value);
+ return offset;
+ }
+
+ public static int writeSVar32(final int value, final byte[] buf, final int offset) {
+ return writeVar32(intToZigZag(value), buf, offset);
+ }
+
+ public static int writeVar32(int value, final byte[] buf, int offset) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ while (true) {
+ if ((value & ~0x7F) == 0) {
+ buf[offset++] = (byte)value;
+ return offset;
+ } else {
+ buf[offset++] = (byte)((value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ }
+
+ public static int writeVar64(long value, final byte[] buf, int offset) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ while (true) {
+ if ((value & ~0x7FL) == 0) {
+ buf[offset++] = (byte)value;
+ return offset;
+ } else {
+ buf[offset++] = (byte)(((int)value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ }
+
+ @Deprecated
+ public static void writeFirstLong(final long value, final byte[] buf) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (buf.length < LONG_BYTE_LENGTH) {
+ throw new IllegalArgumentException("buf.length is too small(8). buf.length:" + buf.length);
+ }
+ writeFirstLong0(value, buf);
+ }
+
+ private static void writeFirstLong0(final long value, final byte[] buf) {
+ buf[0] = (byte) (value >> 56);
+ buf[1] = (byte) (value >> 48);
+ buf[2] = (byte) (value >> 40);
+ buf[3] = (byte) (value >> 32);
+ buf[4] = (byte) (value >> 24);
+ buf[5] = (byte) (value >> 16);
+ buf[6] = (byte) (value >> 8);
+ buf[7] = (byte) (value);
+ }
+
+ private static void writeFirstLong0(final long value, final byte[] buf, int offset) {
+ buf[0 + offset] = (byte) (value >> 56);
+ buf[1 + offset] = (byte) (value >> 48);
+ buf[2 + offset] = (byte) (value >> 40);
+ buf[3 + offset] = (byte) (value >> 32);
+ buf[4 + offset] = (byte) (value >> 24);
+ buf[5 + offset] = (byte) (value >> 16);
+ buf[6 + offset] = (byte) (value >> 8);
+ buf[7 + offset] = (byte) (value);
+ }
+
+ @Deprecated
+ public static void writeSecondLong(final long value, final byte[] buf) {
+ if (buf == null) {
+ throw new NullPointerException("buf must not be null");
+ }
+ if (buf.length < LONG_LONG_BYTE_LENGTH) {
+ throw new IllegalArgumentException("buf.length is too small(16). buf.length:" + buf.length);
+ }
+ writeSecondLong0(value, buf);
+ }
+
+
+ private static Logger getLogger() {
+ return Logger.getLogger(BytesUtils.class.getName());
+ }
+
+ private static void writeSecondLong0(final long value, final byte[] buf) {
+ buf[8] = (byte) (value >> 56);
+ buf[9] = (byte) (value >> 48);
+ buf[10] = (byte) (value >> 40);
+ buf[11] = (byte) (value >> 32);
+ buf[12] = (byte) (value >> 24);
+ buf[13] = (byte) (value >> 16);
+ buf[14] = (byte) (value >> 8);
+ buf[15] = (byte) (value);
+ }
+
+ private static void writeSecondLong0(final long value, final byte[] buf, int offset) {
+ buf[8 + offset] = (byte) (value >> 56);
+ buf[9 + offset] = (byte) (value >> 48);
+ buf[10 + offset] = (byte) (value >> 40);
+ buf[11 + offset] = (byte) (value >> 32);
+ buf[12 + offset] = (byte) (value >> 24);
+ buf[13 + offset] = (byte) (value >> 16);
+ buf[14 + offset] = (byte) (value >> 8);
+ buf[15 + offset] = (byte) (value);
+ }
+
+ public static byte[] add(final String prefix, final long postfix) {
+ if (prefix == null) {
+ throw new NullPointerException("prefix must not be null");
+ }
+ byte[] agentByte = toBytes(prefix);
+ return add(agentByte, postfix);
+ }
+
+ public static byte[] add(final byte[] preFix, final long postfix) {
+ byte[] buf = new byte[preFix.length + LONG_BYTE_LENGTH];
+ System.arraycopy(preFix, 0, buf, 0, preFix.length);
+ writeLong(postfix, buf, preFix.length);
+ return buf;
+ }
+
+ public static byte[] add(final byte[] preFix, final short postfix) {
+ byte[] buf = new byte[preFix.length + SHORT_BYTE_LENGTH];
+ System.arraycopy(preFix, 0, buf, 0, preFix.length);
+ writeShort(postfix, buf, preFix.length);
+ return buf;
+ }
+
+ public static byte[] add(final int preFix, final short postFix) {
+ byte[] buf = new byte[INT_BYTE_LENGTH + SHORT_BYTE_LENGTH];
+ writeInt(preFix, buf, 0);
+ writeShort(postFix, buf, 4);
+ return buf;
+ }
+
+
+ public static byte[] add(final long preFix, final short postFix) {
+ byte[] buf = new byte[LONG_BYTE_LENGTH + SHORT_BYTE_LENGTH];
+ writeLong(preFix, buf, 0);
+ writeShort(postFix, buf, 8);
+ return buf;
+ }
+
+ public static byte[] toBytes(final String value) {
+ if (value == null) {
+ return null;
+ }
+ try {
+ return value.getBytes(UTF8);
+ } catch (UnsupportedEncodingException e) {
+ final Logger logger = getLogger();
+ logger.log(Level.SEVERE, "String encoding fail. value:" + value + " Caused:" + e.getMessage(), e);
+ return EMPTY_BYTES;
+ }
+ }
+
+ public static byte[] merge(final byte[] b1, final byte[] b2) {
+ if (b1 == null) {
+ throw new NullPointerException("b1 must not be null");
+ }
+ if (b2 == null) {
+ throw new NullPointerException("b2 must not be null");
+ }
+ final byte[] result = new byte[b1.length + b2.length];
+
+ System.arraycopy(b1, 0, result, 0, b1.length);
+ System.arraycopy(b2, 0, result, b1.length, b2.length);
+
+ return result;
+ }
+
+ public static byte[] toFixedLengthBytes(final String str, final int length) {
+ if (length < 0) {
+ throw new IllegalArgumentException("negative length:" + length);
+ }
+ final byte[] b1 = toBytes(str);
+ if (b1 == null) {
+ return new byte[length];
+ }
+
+ if (b1.length > length) {
+ throw new IllegalArgumentException("String is longer then target length of bytes.");
+ }
+ byte[] b = new byte[length];
+ System.arraycopy(b1, 0, b, 0, b1.length);
+
+ return b;
+ }
+
+
+ public static int intToZigZag(final int n) {
+ return (n << 1) ^ (n >> 31);
+ }
+
+ public static int zigzagToInt(final int n) {
+ return (n >>> 1) ^ -(n & 1);
+ }
+
+
+ public static long longToZigZag(final long n) {
+ return (n << 1) ^ (n >> 63);
+ }
+
+ public static long zigzagToLong(final long n) {
+ return (n >>> 1) ^ -(n & 1);
+ }
+
+ public static byte[] concat(final byte[]... arrays) {
+ int totalLength = 0;
+
+ for (int i = 0; i < arrays.length; i++) {
+ totalLength += arrays[i].length;
+ }
+
+ byte[] result = new byte[totalLength];
+
+ int currentIndex = 0;
+ for (int i = 0; i < arrays.length; i++) {
+ System.arraycopy(arrays[i], 0, result, currentIndex, arrays[i].length);
+ currentIndex += arrays[i].length;
+ }
+
+ return result;
+ }
+
+ public static String safeTrim(final String string) {
+ if (string == null) {
+ return null;
+ }
+ return string.trim();
+ }
+
+ public static String toString(final byte[] bytes) {
+ if (bytes == null) {
+ return null;
+ }
+ return toString(bytes, 0, bytes.length);
+ }
+
+ public static String toString(final byte [] bytes, final int offset, final int length) {
+ if (bytes == null) {
+ return null;
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("negative offset:" + offset);
+ }
+ if (length == 0) {
+ return "";
+ }
+ try {
+ return new String(bytes, offset, length, UTF8);
+ } catch (UnsupportedEncodingException e) {
+ LOGGER.log(Level.SEVERE, "UTF-8 encoding fail.", e);
+ return null;
+ }
+ }
+
+ public static String toStringAndRightTrim(final byte[] bytes, final int offset, final int length) {
+ String string = toString(bytes, offset, length);
+ return trimRight(string);
+ }
+
+ public static String trimRight(final String string) {
+ if (string == null) {
+ return null;
+ }
+ final int length = string.length();
+ int index = length;
+// Character.isWhitespace() 로 해야 하는 의문이 생김?? 안해도 될것 같기는 함.
+ while (string.charAt(index - 1) <= ' ') {
+ index--;
+ }
+ if (index == length) {
+ return string;
+ } else {
+ return string.substring(0, index);
+ }
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/DateUtils.java b/src/main/java/com/nhn/pinpoint/common/util/DateUtils.java
new file mode 100644
index 000000000..55309bf95
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/DateUtils.java
@@ -0,0 +1,36 @@
+package com.nhn.pinpoint.common.util;
+
+import org.springframework.core.NamedThreadLocal;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author emeroad
+ */
+public final class DateUtils {
+
+ private static final NamedThreadLocal CACHE = new NamedThreadLocal(DateUtils.class.getName()) {
+ @Override
+ protected DateFormat initialValue() {
+ return new SimpleDateFormat(FORMAT);
+ }
+ };
+
+ private static final String FORMAT = "yyyy-MM-dd HH:mm:ss SSS";
+
+ private DateUtils() {
+ }
+
+ public static String longToDateStr(long date) {
+ final DateFormat dateFormat = CACHE.get();
+ return dateFormat.format(date);
+ }
+
+ public static String longToDateStr(long date, String fmt) {
+ String pattern = (fmt == null) ? FORMAT : fmt;
+ final SimpleDateFormat format = new SimpleDateFormat(pattern);
+ return format.format(new Date(date));
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/DefaultParsingResult.java b/src/main/java/com/nhn/pinpoint/common/util/DefaultParsingResult.java
new file mode 100644
index 000000000..60db1765b
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/DefaultParsingResult.java
@@ -0,0 +1,83 @@
+package com.nhn.pinpoint.common.util;
+
+
+/**
+ * @author emeroad
+ */
+public class DefaultParsingResult implements ParsingResult {
+ public static final char SEPARATOR = ',';
+ private String sql;
+ private StringBuilder output;
+ private int id;
+
+
+ public DefaultParsingResult() {
+
+ }
+
+ public DefaultParsingResult(String sql, StringBuilder output) {
+ this.output = output;
+ this.sql = sql;
+ }
+
+ @Override
+ public String getSql() {
+ return sql;
+ }
+
+ public void setSql(String sql) {
+ this.sql = sql;
+ }
+
+ @Override
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ @Override
+ public String getOutput() {
+ if (output == null) {
+ return "";
+ }
+ return output.toString();
+ }
+
+ /**
+ * 최초 한번은 불려야 된다 안불리고 appendOutputParam을 호출하면 nullpointer exception
+ */
+ void appendOutputSeparator() {
+ if (output == null) {
+ this.output = new StringBuilder();
+ } else {
+ this.output.append(SEPARATOR);
+ }
+ }
+
+ void appendOutputParam(String str) {
+ this.output.append(str);
+ }
+
+ void appendSeparatorCheckOutputParam(char ch) {
+ if (ch == ',') {
+ this.output.append(",,");
+ } else {
+ this.output.append(ch);
+ }
+ }
+
+ void appendOutputParam(char ch) {
+ this.output.append(ch);
+ }
+
+ @Override
+ public String toString() {
+ return "ParsingResult{" +
+ "sql='" + sql + '\'' +
+ ", output=" + output +
+ '}';
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/DefaultTimeSlot.java b/src/main/java/com/nhn/pinpoint/common/util/DefaultTimeSlot.java
new file mode 100644
index 000000000..02eebec18
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/DefaultTimeSlot.java
@@ -0,0 +1,27 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+//@Component
+// spring 디펜던시를 걸어야 되서 그냥 안함.
+public class DefaultTimeSlot implements TimeSlot {
+
+ private static final long ONE_MIN_RESOLUTION = 60000; // 1min
+
+ private final long resolution;
+
+ public DefaultTimeSlot() {
+ this(ONE_MIN_RESOLUTION);
+ }
+
+ public DefaultTimeSlot(long resolution) {
+ this.resolution = resolution;
+ }
+
+ @Override
+ public long getTimeSlot(long time) {
+ // 과거 time을 기준으로 얻어오나, 모두 동일하게 과거 시간의 슬롯을 얻어오게 되므로 + RESOLUTION을 하지 않아도 된다.
+ return (time / resolution) * resolution;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/ExecutorFactory.java b/src/main/java/com/nhn/pinpoint/common/util/ExecutorFactory.java
new file mode 100644
index 000000000..ac6333b86
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/ExecutorFactory.java
@@ -0,0 +1,28 @@
+package com.nhn.pinpoint.common.util;
+
+import java.util.concurrent.*;
+
+/**
+ * @author emeroad
+ */
+public final class ExecutorFactory {
+
+ private static final ThreadFactory DEFAULT_THREAD_FACTORY = new PinpointThreadFactory("Pinpoint-defaultThreadFactory", true);
+
+ private ExecutorFactory() {
+ }
+
+ public static ThreadPoolExecutor newFixedThreadPool(int nThreads, int workQueueMaxSize, ThreadFactory threadFactory) {
+ return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(workQueueMaxSize), threadFactory);
+ }
+
+ public static ThreadPoolExecutor newFixedThreadPool(int nThreads, int workQueueMaxSize) {
+ return newFixedThreadPool(nThreads, workQueueMaxSize, DEFAULT_THREAD_FACTORY);
+ }
+
+ public static ThreadPoolExecutor newFixedThreadPool(int nThreads, int workQueueMaxSize, String threadFactoryName, boolean daemon) {
+ ThreadFactory threadFactory = new PinpointThreadFactory(threadFactoryName, daemon);
+ return newFixedThreadPool(nThreads, workQueueMaxSize, threadFactory);
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/HttpUtils.java b/src/main/java/com/nhn/pinpoint/common/util/HttpUtils.java
new file mode 100644
index 000000000..865aa51f7
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/HttpUtils.java
@@ -0,0 +1,36 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+public class HttpUtils {
+
+ private static final String UTF8 = "UTF-8";
+
+ private static final String CHARSET = "charset=";
+
+ public static String parseContentTypeCharset(String contentType) {
+ return parseContentTypeCharset(contentType, UTF8);
+ }
+
+ public static String parseContentTypeCharset(String contentType, String defaultCharset) {
+ if (contentType == null) {
+ // 스펙상으로는 iso-8859-1 이나 요즘 대부분 was에서 UTF-8 고치기 때문에 애매하다. 옵션 설정에서 고칠수 있게 해야 될지도 모름.
+ return defaultCharset;
+ }
+ int charsetStart = contentType.indexOf(CHARSET);
+ if (charsetStart == -1) {
+ // 없음.
+ return defaultCharset;
+ }
+ // 요기가 시작점.
+ charsetStart = charsetStart + CHARSET.length();
+ int charsetEnd = contentType.indexOf(';', charsetStart);
+ if (charsetEnd == -1) {
+ charsetEnd = contentType.length();
+ }
+ contentType = contentType.substring(charsetStart, charsetEnd);
+
+ return contentType.trim();
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/JvmUtils.java b/src/main/java/com/nhn/pinpoint/common/util/JvmUtils.java
new file mode 100644
index 000000000..7d248e2e2
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/JvmUtils.java
@@ -0,0 +1,43 @@
+package com.nhn.pinpoint.common.util;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.util.Map;
+
+import com.nhn.pinpoint.common.SystemPropertyKey;
+import com.nhn.pinpoint.common.JvmVersion;
+
+/**
+ * @author hyungil.jeong
+ */
+public class JvmUtils {
+ private static final RuntimeMXBean RUNTIME_MX_BEAN = ManagementFactory.getRuntimeMXBean();
+ private static final Map SYSTEM_PROPERTIES = RUNTIME_MX_BEAN.getSystemProperties();
+
+ private static final JvmVersion JVM_VERSION = _getVersion();
+
+ private JvmUtils() {
+ throw new IllegalAccessError();
+ }
+
+ public static JvmVersion getVersion() {
+ return JVM_VERSION;
+ }
+
+ public static boolean supportsVersion(JvmVersion other) {
+ return JVM_VERSION.onOrAfter(other);
+ }
+
+ public static String getSystemProperty(SystemPropertyKey systemPropertyKey) {
+ String key = systemPropertyKey.getKey();
+ if (SYSTEM_PROPERTIES.containsKey(key)) {
+ return SYSTEM_PROPERTIES.get(key);
+ }
+ return "";
+ }
+
+ private static JvmVersion _getVersion() {
+ String javaVersion = getSystemProperty(SystemPropertyKey.JAVA_SPECIFICATION_VERSION);
+ return JvmVersion.getFromVersion(javaVersion);
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/MathUtils.java b/src/main/java/com/nhn/pinpoint/common/util/MathUtils.java
new file mode 100644
index 000000000..e5f1c76c1
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/MathUtils.java
@@ -0,0 +1,14 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+public final class MathUtils {
+ private MathUtils() {
+ }
+
+ public static int fastAbs(final int value) {
+ return value & Integer.MAX_VALUE;
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/OutputParameterParser.java b/src/main/java/com/nhn/pinpoint/common/util/OutputParameterParser.java
new file mode 100644
index 000000000..aa89dd434
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/OutputParameterParser.java
@@ -0,0 +1,51 @@
+package com.nhn.pinpoint.common.util;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author emeroad
+ */
+public class OutputParameterParser {
+
+ public static final char SEPARATOR = DefaultParsingResult.SEPARATOR;
+
+ public List parseOutputParameter(String outputParams) {
+ // 추가적으로 parsing result를 알수 있어야 될거 같음.
+ if (outputParams == null || outputParams.length() == 0) {
+ return Collections.emptyList();
+ }
+
+ final List result = new LinkedList();
+ StringBuilder params = new StringBuilder();
+ for (int index = 0; index < outputParams.length(); index++) {
+ final char ch = outputParams.charAt(index);
+ if (ch == SEPARATOR) {
+ if (lookAhead1(outputParams, index) == SEPARATOR) {
+ params.append(SEPARATOR);
+ index++;
+ } else {
+ result.add(params.toString());
+ params = new StringBuilder();
+ }
+ } else {
+ params.append(ch);
+ }
+ }
+
+ result.add(params.toString());
+
+ return result;
+ }
+
+ private int lookAhead1(String sql, int index) {
+ index++;
+ if (index < sql.length()) {
+ return sql.charAt(index);
+ } else {
+ return -1;
+ }
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/ParsingResult.java b/src/main/java/com/nhn/pinpoint/common/util/ParsingResult.java
new file mode 100644
index 000000000..0d924bead
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/ParsingResult.java
@@ -0,0 +1,12 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+public interface ParsingResult {
+ String getSql();
+
+ String getOutput();
+
+ int getId();
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/PinpointThreadFactory.java b/src/main/java/com/nhn/pinpoint/common/util/PinpointThreadFactory.java
new file mode 100644
index 000000000..3bd00836c
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/PinpointThreadFactory.java
@@ -0,0 +1,68 @@
+package com.nhn.pinpoint.common.util;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author emeroad
+ */
+public class PinpointThreadFactory implements ThreadFactory {
+
+ private final static AtomicInteger FACTORY_NUMBER = new AtomicInteger(0);
+ private final AtomicInteger threadNumber = new AtomicInteger(0);
+
+ private final String threadPrefix;
+ private final boolean daemon;
+
+
+ public PinpointThreadFactory() {
+ this("Pinpoint", false);
+ }
+
+ public PinpointThreadFactory(String threadName) {
+ this(threadName, false);
+ }
+
+ public PinpointThreadFactory(String threadName, boolean daemon) {
+ if (threadName == null) {
+ throw new NullPointerException("threadName");
+ }
+ this.threadPrefix = prefix(threadName, FACTORY_NUMBER.getAndIncrement());
+ this.daemon = daemon;
+ }
+
+ private String prefix(String threadName, int factoryId) {
+ final StringBuilder buffer = new StringBuilder(32);
+ buffer.append(threadName);
+ buffer.append('(');
+ buffer.append(factoryId);
+ buffer.append('-');
+ return buffer.toString();
+ }
+
+ @Override
+ public Thread newThread(Runnable job) {
+ String newThreadName = createThreadName();
+ Thread thread = new Thread(job, newThreadName);
+ if (daemon) {
+ thread.setDaemon(daemon);
+ }
+ return thread;
+ }
+
+ private String createThreadName() {
+ StringBuilder buffer = new StringBuilder(threadPrefix.length() + 8);
+ buffer.append(threadPrefix);
+ buffer.append(threadNumber.getAndIncrement());
+ buffer.append(')');
+ return buffer.toString();
+ }
+
+ public static ThreadFactory createThreadFactory(String threadName) {
+ return createThreadFactory(threadName, false);
+ }
+
+ public static ThreadFactory createThreadFactory(String threadName, boolean daemon) {
+ return new PinpointThreadFactory(threadName, daemon);
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/PropertyUtils.java b/src/main/java/com/nhn/pinpoint/common/util/PropertyUtils.java
new file mode 100644
index 000000000..ba4d2483c
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/PropertyUtils.java
@@ -0,0 +1,35 @@
+package com.nhn.pinpoint.common.util;
+
+import java.io.*;
+import java.util.Properties;
+
+/**
+ * @author emeroad
+ */
+public class PropertyUtils {
+
+ public static Properties readProperties(String propertyPath) throws IOException {
+ Properties properties = new Properties();
+ InputStream in = null;
+ Reader reader = null;
+ try {
+ in = new FileInputStream(propertyPath);
+ reader = new InputStreamReader(in, "UTF-8");
+ properties.load(reader);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException ignore) {
+ }
+ }
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException ignore) {
+ }
+ }
+ }
+ return properties;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/RowKeyUtils.java b/src/main/java/com/nhn/pinpoint/common/util/RowKeyUtils.java
new file mode 100644
index 000000000..88a4cba72
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/RowKeyUtils.java
@@ -0,0 +1,50 @@
+package com.nhn.pinpoint.common.util;
+
+import static com.nhn.pinpoint.common.PinpointConstants.AGENT_NAME_MAX_LEN;
+import static com.nhn.pinpoint.common.util.BytesUtils.INT_BYTE_LENGTH;
+import static com.nhn.pinpoint.common.util.BytesUtils.LONG_BYTE_LENGTH;
+
+import org.apache.hadoop.hbase.util.Bytes;
+
+/**
+ * @author emeroad
+ */
+public class RowKeyUtils {
+
+ public static byte[] concatFixedByteAndLong(byte[] fixedBytes, int maxFixedLength, long l) {
+ if (fixedBytes == null) {
+ throw new NullPointerException("fixedBytes must not null");
+ }
+ if (fixedBytes.length > maxFixedLength) {
+ throw new IllegalArgumentException("fixedBytes.length too big. length:" + fixedBytes.length);
+ }
+ byte[] rowKey = new byte[maxFixedLength + LONG_BYTE_LENGTH];
+ Bytes.putBytes(rowKey, 0, fixedBytes, 0, fixedBytes.length);
+ BytesUtils.writeLong(l, rowKey, maxFixedLength);
+ return rowKey;
+ }
+
+
+ public static byte[] getMetaInfoRowKey(String agentId, long agentStartTime, int keyCode) {
+ // TODO 일단 agent의 조회 시간 로직을 따로 만들어야 되므로 그냥0으로 하자.
+ if (agentId == null) {
+ throw new NullPointerException("agentId must not be null");
+ }
+
+ final byte[] agentBytes = Bytes.toBytes(agentId);
+ if (agentBytes.length > AGENT_NAME_MAX_LEN) {
+ throw new IllegalArgumentException("agent.length too big. agent:" + agentId + " length:" + agentId.length());
+ }
+
+ final byte[] buffer = new byte[AGENT_NAME_MAX_LEN + LONG_BYTE_LENGTH + INT_BYTE_LENGTH];
+ Bytes.putBytes(buffer, 0, agentBytes, 0, agentBytes.length);
+
+ long reverseCurrentTimeMillis = TimeUtils.reverseTimeMillis(agentStartTime);
+ BytesUtils.writeLong(reverseCurrentTimeMillis, buffer, AGENT_NAME_MAX_LEN);
+
+ BytesUtils.writeInt(keyCode, buffer, AGENT_NAME_MAX_LEN + LONG_BYTE_LENGTH);
+ return buffer;
+ }
+
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/RpcCodeRange.java b/src/main/java/com/nhn/pinpoint/common/util/RpcCodeRange.java
new file mode 100644
index 000000000..d5c4ab0f9
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/RpcCodeRange.java
@@ -0,0 +1,15 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+public final class RpcCodeRange {
+
+ public static final short RPC_START = 9000;
+ public static final short RPC_END = 10000;
+
+ public static boolean isRpcRange(short code) {
+ return code >= RPC_START && code < RPC_END;
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/SpanEventUtils.java b/src/main/java/com/nhn/pinpoint/common/util/SpanEventUtils.java
new file mode 100644
index 000000000..4f76bd653
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/SpanEventUtils.java
@@ -0,0 +1,20 @@
+package com.nhn.pinpoint.common.util;
+
+import com.nhn.pinpoint.common.AnnotationKey;
+import com.nhn.pinpoint.thrift.dto.TAnnotation;
+import com.nhn.pinpoint.thrift.dto.TSpanEvent;
+
+import java.util.List;
+
+/**
+ * @author emeroad
+ */
+public class SpanEventUtils {
+
+ public static boolean hasException(TSpanEvent spanEvent) {
+ if (spanEvent.isSetExceptionInfo()) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/SpanUtils.java b/src/main/java/com/nhn/pinpoint/common/util/SpanUtils.java
new file mode 100644
index 000000000..ffe3f2214
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/SpanUtils.java
@@ -0,0 +1,82 @@
+package com.nhn.pinpoint.common.util;
+
+import static com.nhn.pinpoint.common.PinpointConstants.AGENT_NAME_MAX_LEN;
+
+import com.nhn.pinpoint.common.buffer.AutomaticBuffer;
+import com.nhn.pinpoint.common.buffer.Buffer;
+import com.nhn.pinpoint.thrift.dto.TSpan;
+import com.nhn.pinpoint.thrift.dto.TSpanChunk;
+
+/**
+ * @author emeroad
+ */
+public class SpanUtils {
+ @Deprecated
+ public static byte[] getAgentIdTraceIndexRowKey(String agentId, long timestamp) {
+ if (agentId == null) {
+ throw new IllegalArgumentException("agentId must not null");
+ }
+ final byte[] bAgentId = BytesUtils.toBytes(agentId);
+ return RowKeyUtils.concatFixedByteAndLong(bAgentId, AGENT_NAME_MAX_LEN, TimeUtils.reverseTimeMillis(timestamp));
+ }
+
+ public static byte[] getApplicationTraceIndexRowKey(String applicationName, long timestamp) {
+ if (applicationName == null) {
+ throw new IllegalArgumentException("agentId must not null");
+ }
+ final byte[] bApplicationName = BytesUtils.toBytes(applicationName);
+ return RowKeyUtils.concatFixedByteAndLong(bApplicationName, AGENT_NAME_MAX_LEN, TimeUtils.reverseTimeMillis(timestamp));
+ }
+
+ public static byte[] getTraceIndexRowKey(byte[] agentId, long timestamp) {
+ if (agentId == null) {
+ throw new NullPointerException("agentId must not be null");
+ }
+ return RowKeyUtils.concatFixedByteAndLong(agentId, AGENT_NAME_MAX_LEN, TimeUtils.reverseTimeMillis(timestamp));
+ }
+
+ public static byte[] getVarTransactionId(TSpan span) {
+ if (span == null) {
+ throw new NullPointerException("span must not be null");
+ }
+ final byte[] transactionIdBytes = span.getTransactionId();
+ TransactionId transactionId = TransactionIdUtils.parseTransactionId(transactionIdBytes);
+ String agentId = transactionId.getAgentId();
+ if (agentId == null) {
+ agentId = span.getAgentId();
+ }
+
+ final Buffer buffer= new AutomaticBuffer(32);
+ buffer.putPrefixedString(agentId);
+ buffer.putSVar(transactionId.getAgentStartTime());
+ buffer.putVar(transactionId.getTransactionSequence());
+ return buffer.getBuffer();
+ }
+
+ public static byte[] getTransactionId(TSpan span) {
+ if (span == null) {
+ throw new NullPointerException("span must not be null");
+ }
+ final byte[] transactionIdBytes = span.getTransactionId();
+ TransactionId transactionId = TransactionIdUtils.parseTransactionId(transactionIdBytes);
+ String agentId = transactionId.getAgentId();
+ if (agentId == null) {
+ agentId = span.getAgentId();
+ }
+ return BytesUtils.stringLongLongToBytes(agentId, AGENT_NAME_MAX_LEN, transactionId.getAgentStartTime(), transactionId.getTransactionSequence());
+
+ }
+
+ public static byte[] getTransactionId(TSpanChunk spanChunk) {
+ if (spanChunk == null) {
+ throw new NullPointerException("spanChunk must not be null");
+ }
+ final byte[] transactionIdBytes = spanChunk.getTransactionId();
+ final TransactionId transactionId = TransactionIdUtils.parseTransactionId(transactionIdBytes);
+ String agentId = transactionId.getAgentId();
+ if (agentId == null) {
+ agentId = spanChunk.getAgentId();
+ }
+ return BytesUtils.stringLongLongToBytes(agentId, AGENT_NAME_MAX_LEN, transactionId.getAgentStartTime(), transactionId.getTransactionSequence());
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/SqlParser.java b/src/main/java/com/nhn/pinpoint/common/util/SqlParser.java
new file mode 100644
index 000000000..41a398d4b
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/SqlParser.java
@@ -0,0 +1,415 @@
+package com.nhn.pinpoint.common.util;
+
+import java.util.List;
+
+/**
+ * @author emeroad
+ */
+public class SqlParser {
+
+ public static final char SYMBOL_REPLACE = '$';
+ public static final char NUMBER_REPLACE = '#';
+
+ private static final DefaultParsingResult NULL = new DefaultParsingResult("", new StringBuilder());
+ private static final int NEXT_TOKEN_NOT_EXIST = -1;
+
+
+ public SqlParser() {
+ }
+
+ public DefaultParsingResult normalizedSql(String sql) {
+ if (sql == null) {
+ return NULL;
+ }
+
+ DefaultParsingResult parsingResult = new DefaultParsingResult();
+ final int length = sql.length();
+ final StringBuilder normalized = new StringBuilder(length + 16);
+ boolean change = false;
+ int replaceIndex = 0;
+ boolean numberTokenStartEnable = true;
+ for (int i = 0; i < length; i++) {
+ final char ch = sql.charAt(i);
+ switch (ch) {
+ // COMMENT start check
+ case '/':
+ // comment state
+ int lookAhead1Char = lookAhead1(sql, i);
+ // multi line comment and oracle hint /*+ */
+ if (lookAhead1Char == '*') {
+ normalized.append("/*");
+ i += 2;
+ for (; i < length; i++) {
+ char stateCh = sql.charAt(i);
+ if (stateCh == '*') {
+ if (lookAhead1(sql, i) == '/') {
+ normalized.append("*/");
+ i++;
+ break;
+ }
+ }
+ normalized.append(stateCh);
+ }
+ break;
+ // single line comment
+ } else if (lookAhead1Char == '/') {
+ normalized.append("//");
+ i += 2;
+ i = readLine(sql, normalized, i);
+ break;
+
+ } else {
+ // unary operator
+ numberTokenStartEnable = true;
+ normalized.append(ch);
+ break;
+ }
+// case '#'
+// mysql 에서는 #도 한줄 짜리 comment이다.
+ case '-':
+ // single line comment state
+ if (lookAhead1(sql, i) == '-') {
+ normalized.append("--");
+ i += 2;
+ i = readLine(sql, normalized, i);
+ break;
+ } else {
+ // unary operator
+ numberTokenStartEnable = true;
+ normalized.append(ch);
+ break;
+ }
+
+ // SYMBOL start check
+ case '\'':
+ // empty symbol
+ if (lookAhead1(sql, i) == '\'') {
+ normalized.append("''");
+ // $로 치환하지 않으므로 output에 파라미터를 넣을필요가 없다
+ i += 2;
+ break;
+ } else {
+ change = true;
+ normalized.append('\'');
+ i++;
+ parsingResult.appendOutputSeparator();
+ for (; i < length; i++) {
+ char stateCh = sql.charAt(i);
+ if (stateCh == '\'') {
+ // '' 이 연속으로 나왔을 경우는 \' 이므로 그대로 넣는다.
+ if (lookAhead1(sql, i) == '\'') {
+ i++;
+ parsingResult.appendOutputParam("''");
+ continue;
+ } else {
+ normalized.append(replaceIndex++);
+ normalized.append(SYMBOL_REPLACE);
+ normalized.append('\'');
+// outputParam.append(',');
+ break;
+ }
+ }
+ parsingResult.appendSeparatorCheckOutputParam(stateCh);
+ }
+ break;
+ }
+
+ // number start check
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ // http://www.h2database.com/html/grammar.html 추가로 state machine을 더볼것.
+ if (numberTokenStartEnable) {
+ change = true;
+ normalized.append(replaceIndex++);
+ normalized.append(NUMBER_REPLACE);
+ // number token start
+ parsingResult.appendOutputSeparator();
+ parsingResult.appendOutputParam(ch);
+ i++;
+ tokenEnd:
+ for (; i < length; i++) {
+ char stateCh = sql.charAt(i);
+ switch (stateCh) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '.':
+ case 'E':
+ case 'e':
+ parsingResult.appendOutputParam(stateCh);
+ break;
+ default:
+ // 여기서 처리하지 말고 루프 바깥으로 나가서 다시 token을 봐야 된다.
+// outputParam.append(SEPARATOR);
+ i--;
+ break tokenEnd;
+ }
+ }
+ break;
+ } else {
+ normalized.append(ch);
+ break;
+ }
+
+ // 공백 space를 만남
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ numberTokenStartEnable = true;
+ normalized.append(ch);
+ break;
+ // http://msdn.microsoft.com/en-us/library/ms174986.aspx 참조.
+ case '*':
+ case '+':
+ case '%':
+ case '=':
+ case '<':
+ case '>':
+ case '&':
+ case '|':
+ case '^':
+ case '~':
+ case '!':
+ numberTokenStartEnable = true;
+ normalized.append(ch);
+ break;
+
+ case '(':
+ case ')':
+ case ',':
+ case ';':
+ numberTokenStartEnable = true;
+ normalized.append(ch);
+ break;
+
+ case '.':
+ case '_':
+ case '@': // Assignment Operator
+ case ':': // 오라클쪽의 bind 변수는 :bindvalue로도 가능.
+ numberTokenStartEnable = false;
+ normalized.append(ch);
+ break;
+
+ default:
+ // 한글이면 ??
+ if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {
+ numberTokenStartEnable = false;
+ } else {
+ numberTokenStartEnable = true;
+ }
+ normalized.append(ch);
+ break;
+ }
+ }
+ if (change) {
+ parsingResult.setSql(normalized.toString());
+ return parsingResult;
+ } else {
+ // 수정되지 않았을 경우의 재활용.
+ // 1. 성능향상을 위해 string을 생성하지 않도록.
+ // 2. hash code재활용.
+ parsingResult.setSql(sql);
+ return parsingResult;
+ }
+ }
+
+ private int readLine(String sql, StringBuilder normalized, int index) {
+ final int length = sql.length();
+ for (; index < length; index++) {
+ char ch = sql.charAt(index);
+ normalized.append(ch);
+ if (ch == '\n') {
+ break;
+ }
+ }
+ return index;
+ }
+
+ /**
+ * 미리 다음 문자열 하나를 까본다.
+ *
+ * @param sql
+ * @param index
+ * @return
+ */
+ private int lookAhead1(String sql, int index) {
+ index++;
+ if (index < sql.length()) {
+ return sql.charAt(index);
+ } else {
+ return NEXT_TOKEN_NOT_EXIST;
+ }
+ }
+
+ public String combineOutputParams(String sql, List outputParams) {
+
+ final int length = sql.length();
+ final StringBuilder normalized = new StringBuilder(length + 16);
+ for (int i = 0; i < length; i++) {
+ final char ch = sql.charAt(i);
+ switch (ch) {
+ // COMMENT start check
+ case '/':
+ // comment state
+ int lookAhead1Char = lookAhead1(sql, i);
+ // multi line comment and oracle hint /*+ */
+ if (lookAhead1Char == '*') {
+ normalized.append("/*");
+ i += 2;
+ for (; i < length; i++) {
+ char stateCh = sql.charAt(i);
+ if (stateCh == '*') {
+ if (lookAhead1(sql, i) == '/') {
+ normalized.append("*/");
+ i++;
+ break;
+ }
+ }
+ normalized.append(stateCh);
+ }
+ break;
+ // single line comment
+ } else if (lookAhead1Char == '/') {
+ normalized.append("//");
+ i += 2;
+ i = readLine(sql, normalized, i);
+ break;
+
+ } else {
+ // unary operator
+// numberTokenStartEnable = true;
+ normalized.append(ch);
+ break;
+ }
+// case '#'
+// mysql 에서는 #도 한줄 짜리 comment이다.
+ case '-':
+ // single line comment state
+ if (lookAhead1(sql, i) == '-') {
+ normalized.append("--");
+ i += 2;
+ i = readLine(sql, normalized, i);
+ break;
+ } else {
+ // unary operator
+// numberTokenStartEnable = true;
+ normalized.append(ch);
+ break;
+ }
+
+ // number start check
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ // http://www.h2database.com/html/grammar.html 추가로 state machine을 더볼것.
+ if (lookAhead1(sql, i) == NEXT_TOKEN_NOT_EXIST) {
+ normalized.append(ch);
+ break;
+ }
+ StringBuilder outputIndex = new StringBuilder();
+ outputIndex.append(ch);
+ // number token start
+ i++;
+ tokenEnd:
+ for (; i < length; i++) {
+ char stateCh = sql.charAt(i);
+ switch (stateCh) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (lookAhead1(sql, i) == NEXT_TOKEN_NOT_EXIST) {
+ outputIndex.append(stateCh);
+ normalized.append(outputIndex.toString());
+ break tokenEnd;
+ }
+ outputIndex.append(stateCh);
+ break;
+ case NUMBER_REPLACE:
+ int numberIndex = 0;
+ try {
+ numberIndex = Integer.parseInt(outputIndex.toString());
+ } catch (NumberFormatException e) {
+ // 잘못된 파라미터일 경우 그냥 쓰자.
+ normalized.append(outputIndex.toString());
+ normalized.append(NUMBER_REPLACE);
+ break tokenEnd;
+ }
+ try {
+ String replaceNumber = outputParams.get(numberIndex);
+ normalized.append(replaceNumber);
+ } catch (IndexOutOfBoundsException e) {
+ // 잘못된 파라미터일 경우 그냥 쓰자.
+ normalized.append(outputIndex.toString());
+ normalized.append(NUMBER_REPLACE);
+ break tokenEnd;
+ }
+ break tokenEnd;
+
+ case SYMBOL_REPLACE:
+ int symbolIndex = 0;
+ try {
+ symbolIndex = Integer.parseInt(outputIndex.toString());
+ } catch (NumberFormatException e) {
+ // 잘못된 파라미터일 경우 그냥 쓰자.
+ normalized.append(outputIndex.toString());
+ normalized.append(SYMBOL_REPLACE);
+ }
+ try {
+ String replaceSymbol = outputParams.get(symbolIndex);
+ normalized.append(replaceSymbol);
+ } catch (IndexOutOfBoundsException e) {
+ normalized.append(outputIndex.toString());
+ normalized.append(SYMBOL_REPLACE);
+ }
+ break tokenEnd;
+
+ default:
+ // 여기서 처리하지 말고 루프 바깥으로 나가서 다시 token을 봐야 된다.
+// outputParam.append(SEPARATOR);
+ normalized.append(outputIndex.toString());
+ i--;
+ break tokenEnd;
+ }
+ }
+ break;
+
+ default:
+ normalized.append(ch);
+ break;
+ }
+ }
+
+ return normalized.toString();
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/StopWatch.java b/src/main/java/com/nhn/pinpoint/common/util/StopWatch.java
new file mode 100644
index 000000000..81c97048c
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/StopWatch.java
@@ -0,0 +1,18 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * 단순한 stopwatch
+ * @author emeroad
+ */
+public class StopWatch {
+ private long start;
+
+ public void start() {
+ this.start = System.currentTimeMillis();
+ }
+
+ public long stop() {
+ return System.currentTimeMillis() - this.start;
+ }
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/StringTraceHeaderParser.java b/src/main/java/com/nhn/pinpoint/common/util/StringTraceHeaderParser.java
new file mode 100644
index 000000000..1a379eee0
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/StringTraceHeaderParser.java
@@ -0,0 +1,71 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+public class StringTraceHeaderParser {
+
+ // request.addHeader(Header.HTTP_TRACE_ID.toString(), nextId.getId().toString());
+// request.addHeader(Header.HTTP_SPAN_ID.toString(), Long.toString(nextId.getSpanId()));
+// request.addHeader(Header.HTTP_PARENT_SPAN_ID.toString(), Long.toString(nextId.getParentSpanId()));
+// request.addHeader(Header.HTTP_SAMPLED.toString(), String.valueOf(nextId.isSampled()));
+// request.addHeader(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags()));
+ public static final char DELIMITER_STRING = ':';
+ public static final int ID_INDEX = 36;
+
+ public String createHeader(String uuid, int spanId, int parentSpanId, int sampling, short flag) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append(uuid);
+ sb.append(DELIMITER_STRING);
+ sb.append(spanId);
+ sb.append(DELIMITER_STRING);
+ sb.append(parentSpanId);
+ sb.append(DELIMITER_STRING);
+ sb.append(sampling);
+ sb.append(DELIMITER_STRING);
+ sb.append(flag);
+ return sb.toString();
+ }
+
+ public TraceHeader parseHeader(String traceHeader) {
+ if (traceHeader == null) {
+ return null;
+ }
+
+ char c = traceHeader.charAt(ID_INDEX);
+ if (c != DELIMITER_STRING) {
+ return null;
+ }
+ String id = traceHeader.substring(0, ID_INDEX);
+
+ int spanIdStartIndex = ID_INDEX + 1;
+ int spanIdEndIndex = traceHeader.indexOf(DELIMITER_STRING, spanIdStartIndex);
+ String spanId = traceHeader.substring(spanIdStartIndex, spanIdEndIndex);
+
+ int parentSpanIdStartIndex = spanIdEndIndex + 1;
+ int parentSpanIdEndIndex = traceHeader.indexOf(DELIMITER_STRING, parentSpanIdStartIndex);
+ String parentSpanId = traceHeader.substring(parentSpanIdStartIndex, parentSpanIdEndIndex);
+
+ int samplingStartIndex = parentSpanIdEndIndex + 1;
+ int samplingEndIndex = traceHeader.indexOf(DELIMITER_STRING, samplingStartIndex);
+ if (samplingEndIndex == -1) {
+ return new TraceHeader(id, spanId, parentSpanId, "", "");
+ }
+ String sampling = traceHeader.substring(samplingStartIndex, samplingEndIndex);
+
+
+ int flagStartIndex = samplingEndIndex + 1;
+ if (flagStartIndex == -1) {
+ return new TraceHeader(id, spanId, parentSpanId, sampling, "");
+ }
+ int flagEndIndex = traceHeader.indexOf(DELIMITER_STRING, flagStartIndex);
+ if (flagEndIndex == -1) {
+ String flag = traceHeader.substring(flagStartIndex);
+ return new TraceHeader(id, spanId, parentSpanId, sampling, flag);
+ }
+ String flag = traceHeader.substring(flagStartIndex, flagEndIndex);
+ return new TraceHeader(id, spanId, parentSpanId, sampling, flag);
+ }
+
+
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/TimeSlot.java b/src/main/java/com/nhn/pinpoint/common/util/TimeSlot.java
new file mode 100644
index 000000000..a25781169
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/TimeSlot.java
@@ -0,0 +1,8 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+public interface TimeSlot {
+ public long getTimeSlot(long time);
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/TimeUtils.java b/src/main/java/com/nhn/pinpoint/common/util/TimeUtils.java
new file mode 100644
index 000000000..fa357ffe8
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/TimeUtils.java
@@ -0,0 +1,19 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+public final class TimeUtils {
+
+ public static long reverseTimeMillis(long currentTimeMillis) {
+ return Long.MAX_VALUE - currentTimeMillis;
+ }
+
+ public static long reverseCurrentTimeMillis() {
+ return reverseTimeMillis(System.currentTimeMillis());
+ }
+
+ public static long recoveryTimeMillis(long reverseCurrentTimeMillis) {
+ return Long.MAX_VALUE - reverseCurrentTimeMillis;
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/TraceHeader.java b/src/main/java/com/nhn/pinpoint/common/util/TraceHeader.java
new file mode 100644
index 000000000..7674a5486
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/TraceHeader.java
@@ -0,0 +1,74 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+public class TraceHeader {
+ private String id;
+ private String spanId;
+ private String parentSpanId;
+ private String sampling;
+ private String flag;
+
+ public TraceHeader() {
+ }
+
+ public TraceHeader(String id, String spanId, String parentSpanId, String sampling, String flag) {
+ this.id = id;
+ this.spanId = spanId;
+ this.parentSpanId = parentSpanId;
+ this.sampling = sampling;
+ this.flag = flag;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getSpanId() {
+ return spanId;
+ }
+
+ public void setSpanId(String spanId) {
+ this.spanId = spanId;
+ }
+
+ public String getParentSpanId() {
+ return parentSpanId;
+ }
+
+ public void setParentSpanId(String parentSpanId) {
+ this.parentSpanId = parentSpanId;
+ }
+
+ public String getSampling() {
+ return sampling;
+ }
+
+ public void setSampling(String sampling) {
+ this.sampling = sampling;
+ }
+
+ public String getFlag() {
+ return flag;
+ }
+
+ public void setFlag(String flag) {
+ this.flag = flag;
+ }
+
+ @Override
+ public String toString() {
+ return "TraceHeader{" +
+ "id='" + id + '\'' +
+ ", spanId='" + spanId + '\'' +
+ ", parentSpanId='" + parentSpanId + '\'' +
+ ", sampling='" + sampling + '\'' +
+ ", flag='" + flag + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/TransactionId.java b/src/main/java/com/nhn/pinpoint/common/util/TransactionId.java
new file mode 100644
index 000000000..9484e4b0b
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/TransactionId.java
@@ -0,0 +1,70 @@
+package com.nhn.pinpoint.common.util;
+
+/**
+ * @author emeroad
+ */
+public class TransactionId {
+
+ protected String agentId;
+ protected long agentStartTime;
+ protected long transactionSequence;
+
+ public TransactionId(String agentId, long agentStartTime, long transactionSequence) {
+ if (agentId == null) {
+ throw new NullPointerException("agentId must not be null");
+ }
+ this.agentId = agentId;
+ this.agentStartTime = agentStartTime;
+ this.transactionSequence = transactionSequence;
+ }
+
+ public TransactionId(long agentStartTime, long transactionSequence) {
+ this.agentStartTime = agentStartTime;
+ this.transactionSequence = transactionSequence;
+ }
+
+ public String getAgentId() {
+ return agentId;
+ }
+
+ public long getAgentStartTime() {
+ return agentStartTime;
+ }
+
+ public long getTransactionSequence() {
+ return transactionSequence;
+ }
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ TransactionId that = (TransactionId) o;
+
+ if (agentStartTime != that.agentStartTime) return false;
+ if (transactionSequence != that.transactionSequence) return false;
+ if (!agentId.equals(that.agentId)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = agentId.hashCode();
+ result = 31 * result + (int) (agentStartTime ^ (agentStartTime >>> 32));
+ result = 31 * result + (int) (transactionSequence ^ (transactionSequence >>> 32));
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("TransactionId{");
+ sb.append("agentId='").append(agentId).append('\'');
+ sb.append(", agentStartTime=").append(agentStartTime);
+ sb.append(", transactionSequence=").append(transactionSequence);
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/com/nhn/pinpoint/common/util/TransactionIdUtils.java b/src/main/java/com/nhn/pinpoint/common/util/TransactionIdUtils.java
new file mode 100644
index 000000000..076a6bb99
--- /dev/null
+++ b/src/main/java/com/nhn/pinpoint/common/util/TransactionIdUtils.java
@@ -0,0 +1,92 @@
+package com.nhn.pinpoint.common.util;
+
+import com.nhn.pinpoint.common.buffer.AutomaticBuffer;
+import com.nhn.pinpoint.common.buffer.Buffer;
+import com.nhn.pinpoint.common.buffer.FixedBuffer;
+
+/**
+ * @author emeroad
+ */
+public final class TransactionIdUtils {
+ // html 에서 표시되는 값이라. html 상에서 해석이 다르게 되는 문자열은 사용하면 안됨.
+ public static final String TRANSACTION_ID_DELIMITER = "^";
+ public static final byte VERSION = 0;
+
+ public static String formatString(String agentId, long agentStartTime, long transactionSequence) {
+ if (agentId == null) {
+ throw new NullPointerException("agentId must not be null");
+ }
+ StringBuilder sb = new StringBuilder(64);
+ sb.append(agentId);
+ sb.append(TRANSACTION_ID_DELIMITER);
+ sb.append(agentStartTime);
+ sb.append(TRANSACTION_ID_DELIMITER);
+ sb.append(transactionSequence);
+ return sb.toString();
+ }
+
+ public static byte[] formatBytes(String agentId, long agentStartTime, long transactionSequence) {
+ // agentId는 null이 될수 있음.
+ // vesion + prefixed size + string + long + long
+ final Buffer buffer = new AutomaticBuffer(1 + 5 + 24 + 10 + 10);
+ buffer.put(VERSION);
+ buffer.putPrefixedString(agentId);
+ buffer.putVar(agentStartTime);
+ buffer.putVar(transactionSequence);
+ return buffer.getBuffer();
+ }
+
+ public static TransactionId parseTransactionId(final byte[] transactionId) {
+ if (transactionId == null) {
+ throw new NullPointerException("transactionId must not be null");
+ }
+ final Buffer buffer = new FixedBuffer(transactionId);
+ final byte version = buffer.readByte();
+ if (version != VERSION) {
+ throw new IllegalArgumentException("invalid Version");
+ }
+
+ final String agentId = buffer.readPrefixedString();
+ final long agentStartTime = buffer.readVarLong();
+ final long transactionSequence = buffer.readVarLong();
+ if (agentId == null) {
+ return new TransactionId(agentStartTime, transactionSequence);
+ } else {
+ return new TransactionId(agentId, agentStartTime,transactionSequence);
+ }
+ }
+
+ public static TransactionId parseTransactionId(final String transactionId) {
+ if (transactionId == null) {
+ throw new NullPointerException("transactionId must not be null");
+ }
+
+ final int agentIdIndex = transactionId.indexOf(TRANSACTION_ID_DELIMITER);
+ if (agentIdIndex == -1) {
+ throw new IllegalArgumentException("agentIndex not found:" + transactionId);
+ }
+ final String agentId = transactionId.substring(0, agentIdIndex);
+
+ final int agentStartTimeIndex = transactionId.indexOf(TRANSACTION_ID_DELIMITER, agentIdIndex + 1);
+ if (agentStartTimeIndex == -1) {
+ throw new IllegalArgumentException("agentStartTimeIndex not found:" + transactionId);
+ }
+ final long agentStartTime = parseLong(transactionId.substring(agentIdIndex + 1, agentStartTimeIndex));
+
+ int transactionSequenceIndex = transactionId.indexOf(TRANSACTION_ID_DELIMITER, agentStartTimeIndex + 1);
+ if (transactionSequenceIndex == -1) {
+ // 이거는 없을수 있음. transactionSequence 다음에 델리미터가 일단 없는게 기본값임. 향후 추가 아이디 스펙이 확장가능하므로 보완한다.
+ transactionSequenceIndex = transactionId.length();
+ }
+ final long transactionSequence = parseLong(transactionId.substring(agentStartTimeIndex + 1, transactionSequenceIndex));
+ return new TransactionId(agentId, agentStartTime, transactionSequence);
+ }
+
+ private static long parseLong(String longString) {
+ try {
+ return Long.parseLong(longString);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("parseError. " + longString);
+ }
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/AnnotationKeyTest.java b/src/test/java/com/nhn/pinpoint/common/AnnotationKeyTest.java
new file mode 100644
index 000000000..73d6f3dcf
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/AnnotationKeyTest.java
@@ -0,0 +1,46 @@
+package com.nhn.pinpoint.common;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+/**
+ * @author emeroad
+ */
+public class AnnotationKeyTest {
+
+ @Test
+ public void getCode() {
+
+ AnnotationKey annotationKey = AnnotationKey.findAnnotationKey(AnnotationKey.API.getCode());
+ Assert.assertEquals(annotationKey, AnnotationKey.API);
+ }
+
+// @Test
+ public void intSize() {
+// 2147483647
+ System.out.println(Integer.MAX_VALUE);
+// -2147483648
+ System.out.println(Integer.MIN_VALUE);
+ }
+
+ @Test
+ public void isArgsKey() {
+ Assert.assertTrue(AnnotationKey.isArgsKey(AnnotationKey.ARGS0.getCode()));
+ Assert.assertTrue(AnnotationKey.isArgsKey(AnnotationKey.ARGSN.getCode()));
+ Assert.assertTrue(AnnotationKey.isArgsKey(AnnotationKey.ARGS5.getCode()));
+
+ Assert.assertFalse(AnnotationKey.isArgsKey(AnnotationKey.ARGS0.getCode() +1));
+ Assert.assertFalse(AnnotationKey.isArgsKey(AnnotationKey.ARGSN.getCode() -1));
+ Assert.assertFalse(AnnotationKey.isArgsKey(Integer.MAX_VALUE));
+ Assert.assertFalse(AnnotationKey.isArgsKey(Integer.MIN_VALUE));
+
+ }
+
+ @Test
+ public void isCachedArgsToArgs() {
+ int i = AnnotationKey.cachedArgsToArgs(AnnotationKey.CACHE_ARGS0.getCode());
+ Assert.assertEquals(i, AnnotationKey.ARGS0.getCode());
+
+
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/HistogramSchemaTest.java b/src/test/java/com/nhn/pinpoint/common/HistogramSchemaTest.java
new file mode 100644
index 000000000..a6b2ec1f3
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/HistogramSchemaTest.java
@@ -0,0 +1,39 @@
+package com.nhn.pinpoint.common;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author emeroad
+ */
+public class HistogramSchemaTest {
+ @Test
+ public void testAddHistogramSlot() throws Exception {
+
+ }
+
+ @Test
+ public void testGetHistogramSlotList() throws Exception {
+
+ }
+
+ @Test
+ public void testCreateNode() throws Exception {
+
+ }
+
+ @Test
+ public void testFindHistogramSlot() throws Exception {
+ HistogramSchema histogramSchema = ServiceType.TOMCAT.getHistogramSchema();
+ Assert.assertEquals(histogramSchema.findHistogramSlot(999).getSlotTime(), 1000);
+ Assert.assertEquals(histogramSchema.findHistogramSlot(1000).getSlotTime(), 1000);
+ Assert.assertEquals(histogramSchema.findHistogramSlot(1111).getSlotTime(), 3000);
+ }
+
+
+
+ @Test
+ public void testGetHistogramSlotIndex() throws Exception {
+
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/JvmVersionTest.java b/src/test/java/com/nhn/pinpoint/common/JvmVersionTest.java
new file mode 100644
index 000000000..0ebb0b312
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/JvmVersionTest.java
@@ -0,0 +1,103 @@
+package com.nhn.pinpoint.common;
+
+import static org.junit.Assert.*;
+import static com.nhn.pinpoint.common.JvmVersion.*;
+
+import org.junit.Test;
+
+/**
+ * @author hyungil.jeong
+ */
+public class JvmVersionTest {
+
+ @Test
+ public void testOnOrAfter() {
+ // JDK 5
+ assertTrue(JAVA_5.onOrAfter(JAVA_5));
+ assertFalse(JAVA_5.onOrAfter(JAVA_6));
+ assertFalse(JAVA_5.onOrAfter(JAVA_7));
+ assertFalse(JAVA_5.onOrAfter(JAVA_8));
+ assertFalse(JAVA_5.onOrAfter(UNSUPPORTED));
+ // JDK 6
+ assertTrue(JAVA_6.onOrAfter(JAVA_5));
+ assertTrue(JAVA_6.onOrAfter(JAVA_6));
+ assertFalse(JAVA_6.onOrAfter(JAVA_7));
+ assertFalse(JAVA_6.onOrAfter(JAVA_8));
+ assertFalse(JAVA_6.onOrAfter(UNSUPPORTED));
+ // JDK 7
+ assertTrue(JAVA_7.onOrAfter(JAVA_5));
+ assertTrue(JAVA_7.onOrAfter(JAVA_6));
+ assertTrue(JAVA_7.onOrAfter(JAVA_7));
+ assertFalse(JAVA_7.onOrAfter(JAVA_8));
+ assertFalse(JAVA_7.onOrAfter(UNSUPPORTED));
+ // JDK 8
+ assertTrue(JAVA_8.onOrAfter(JAVA_5));
+ assertTrue(JAVA_8.onOrAfter(JAVA_6));
+ assertTrue(JAVA_8.onOrAfter(JAVA_7));
+ assertTrue(JAVA_8.onOrAfter(JAVA_8));
+ assertFalse(JAVA_8.onOrAfter(UNSUPPORTED));
+ // Unsupported
+ assertFalse(UNSUPPORTED.onOrAfter(JAVA_5));
+ assertFalse(UNSUPPORTED.onOrAfter(JAVA_6));
+ assertFalse(UNSUPPORTED.onOrAfter(JAVA_7));
+ assertFalse(UNSUPPORTED.onOrAfter(JAVA_8));
+ assertFalse(UNSUPPORTED.onOrAfter(UNSUPPORTED));
+ }
+
+ @Test
+ public void testGetFromDoubleVersion() {
+ // JDK 5
+ final JvmVersion java_5 = JvmVersion.getFromVersion(1.5);
+ assertSame(java_5, JAVA_5);
+ // JDK 6
+ final JvmVersion java_6 = JvmVersion.getFromVersion(1.6);
+ assertSame(java_6, JAVA_6);
+ // JDK 7
+ final JvmVersion java_7 = JvmVersion.getFromVersion(1.7);
+ assertSame(java_7, JAVA_7);
+ // JDK 8
+ final JvmVersion java_8 = JvmVersion.getFromVersion(1.8);
+ assertSame(java_8, JAVA_8);
+ // Unsupported
+ final JvmVersion java_unsupported = JvmVersion.getFromVersion(0.9);
+ assertSame(java_unsupported, UNSUPPORTED);
+ }
+
+ @Test
+ public void testGetFromStringVersion() {
+ // JDK 5
+ final JvmVersion java_5 = JvmVersion.getFromVersion("1.5");
+ assertSame(java_5, JAVA_5);
+ // JDK 6
+ final JvmVersion java_6 = JvmVersion.getFromVersion("1.6");
+ assertSame(java_6, JAVA_6);
+ // JDK 7
+ final JvmVersion java_7 = JvmVersion.getFromVersion("1.7");
+ assertSame(java_7, JAVA_7);
+ // JDK 8
+ final JvmVersion java_8 = JvmVersion.getFromVersion("1.8");
+ assertSame(java_8, JAVA_8);
+ // Unsupported
+ final JvmVersion java_unsupported = JvmVersion.getFromVersion("abc");
+ assertSame(java_unsupported, UNSUPPORTED);
+ }
+
+ @Test
+ public void testGetFromClassVersion() {
+ // JDK 5
+ final JvmVersion java_5 = JvmVersion.getFromClassVersion(49);
+ assertSame(java_5, JAVA_5);
+ // JDK 6
+ final JvmVersion java_6 = JvmVersion.getFromClassVersion(50);
+ assertSame(java_6, JAVA_6);
+ // JDK 7
+ final JvmVersion java_7 = JvmVersion.getFromClassVersion(51);
+ assertSame(java_7, JAVA_7);
+ // JDK 8
+ final JvmVersion java_8 = JvmVersion.getFromClassVersion(52);
+ assertSame(java_8, JAVA_8);
+ // Unsupported
+ final JvmVersion java_unsupported = JvmVersion.getFromClassVersion(-1);
+ assertSame(java_unsupported, UNSUPPORTED);
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/ServiceTypeTest.java b/src/test/java/com/nhn/pinpoint/common/ServiceTypeTest.java
new file mode 100644
index 000000000..a09be2b72
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/ServiceTypeTest.java
@@ -0,0 +1,56 @@
+package com.nhn.pinpoint.common;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class ServiceTypeTest {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+
+ @Test
+ public void testIndexable() {
+ System.out.println(ServiceType.TOMCAT.isIndexable());
+ System.out.println(ServiceType.BLOC.isIndexable());
+ System.out.println(ServiceType.ARCUS.isIndexable());
+ }
+
+ @Test
+ public void findDesc() {
+ String desc = "MYSQL";
+ List mysqlList = ServiceType.findDesc(desc);
+ boolean find = false;
+ for (ServiceType serviceType : mysqlList) {
+ if(serviceType.getDesc().equals(desc)) {
+ find = true;
+ }
+ }
+ Assert.assertTrue(find);
+
+ try {
+ mysqlList.add(ServiceType.ARCUS);
+ Assert.fail();
+ } catch (Exception e) {
+ }
+ }
+
+ @Test
+ public void child() {
+ ServiceType oracle = ServiceType.ORACLE;
+
+
+ }
+
+ @Test
+ public void test() {
+ ServiceType[] values = ServiceType.values();
+ for (ServiceType value : values) {
+ logger.debug(value.toString() + " " + value.getCode());
+ }
+
+ }
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/bo/AgentStatCpuLoadBoTest.java b/src/test/java/com/nhn/pinpoint/common/bo/AgentStatCpuLoadBoTest.java
new file mode 100644
index 000000000..ebf34eaf3
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/bo/AgentStatCpuLoadBoTest.java
@@ -0,0 +1,82 @@
+package com.nhn.pinpoint.common.bo;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+/**
+ * @author hyungil.jeong
+ */
+public class AgentStatCpuLoadBoTest {
+
+ // CPU 사용량 소수점 2자리 표시
+ private static final double DELTA = 1e-4;
+
+ @Test
+ public void testByteArrayConversion() {
+ // Given
+ final AgentStatCpuLoadBo testBo = createTestBo(0.22871734201908112D, 0.23790152370929718D);
+ // When
+ final byte[] serializedBo = testBo.writeValue();
+ final AgentStatCpuLoadBo deserializedBo = new AgentStatCpuLoadBo.Builder(serializedBo).build();
+ // Then
+ assertEquals(testBo.getAgentId(), deserializedBo.getAgentId());
+ assertEquals(testBo.getStartTimestamp(), deserializedBo.getStartTimestamp());
+ assertEquals(testBo.getTimestamp(), deserializedBo.getTimestamp());
+ assertEquals(testBo.getJvmCpuLoad(), deserializedBo.getJvmCpuLoad(), DELTA);
+ assertEquals(testBo.getSystemCpuLoad(), deserializedBo.getSystemCpuLoad(), DELTA);
+ }
+
+ @Test
+ public void testByteArrayConversionEdges() {
+ // Given
+ final AgentStatCpuLoadBo testBo = createTestBo(Double.MIN_VALUE, Double.MAX_VALUE);
+ // When
+ final byte[] serializedBo = testBo.writeValue();
+ final AgentStatCpuLoadBo deserializedBo = new AgentStatCpuLoadBo.Builder(serializedBo).build();
+ // Then
+ assertEquals(testBo.getAgentId(), deserializedBo.getAgentId());
+ assertEquals(testBo.getStartTimestamp(), deserializedBo.getStartTimestamp());
+ assertEquals(testBo.getTimestamp(), deserializedBo.getTimestamp());
+ assertEquals(testBo.getJvmCpuLoad(), deserializedBo.getJvmCpuLoad(), DELTA);
+ assertEquals(testBo.getSystemCpuLoad(), deserializedBo.getSystemCpuLoad(), DELTA);
+ }
+
+ @Test
+ public void testByteArrayConversionNanValues() {
+ // Given
+ final AgentStatCpuLoadBo testBo = createTestBo(Double.NaN, Double.NaN);
+ // When
+ final byte[] serializedBo = testBo.writeValue();
+ final AgentStatCpuLoadBo deserializedBo = new AgentStatCpuLoadBo.Builder(serializedBo).build();
+ // Then
+ assertEquals(testBo.getAgentId(), deserializedBo.getAgentId());
+ assertEquals(testBo.getStartTimestamp(), deserializedBo.getStartTimestamp());
+ assertEquals(testBo.getTimestamp(), deserializedBo.getTimestamp());
+ assertEquals(testBo.getJvmCpuLoad(), deserializedBo.getJvmCpuLoad(), DELTA);
+ assertEquals(testBo.getSystemCpuLoad(), deserializedBo.getSystemCpuLoad(), DELTA);
+ }
+
+ @Test
+ public void testByteArrayConversionInfiniteValues() {
+ // Given
+ final AgentStatCpuLoadBo testBo = createTestBo(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY);
+ // When
+ final byte[] serializedBo = testBo.writeValue();
+ final AgentStatCpuLoadBo deserializedBo = new AgentStatCpuLoadBo.Builder(serializedBo).build();
+ // Then
+ assertEquals(testBo.getAgentId(), deserializedBo.getAgentId());
+ assertEquals(testBo.getStartTimestamp(), deserializedBo.getStartTimestamp());
+ assertEquals(testBo.getTimestamp(), deserializedBo.getTimestamp());
+ assertEquals(testBo.getJvmCpuLoad(), deserializedBo.getJvmCpuLoad(), DELTA);
+ assertEquals(testBo.getSystemCpuLoad(), deserializedBo.getSystemCpuLoad(), DELTA);
+ }
+
+ private AgentStatCpuLoadBo createTestBo(double jvmCpuLoad, double systemCpuLoad) {
+ final AgentStatCpuLoadBo.Builder builder = new AgentStatCpuLoadBo.Builder("agentId", 0L, 0L);
+ builder.jvmCpuLoad(jvmCpuLoad);
+ builder.systemCpuLoad(systemCpuLoad);
+ return builder.build();
+ }
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/bo/AgentStatMemoryGcBoTest.java b/src/test/java/com/nhn/pinpoint/common/bo/AgentStatMemoryGcBoTest.java
new file mode 100644
index 000000000..3bff52451
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/bo/AgentStatMemoryGcBoTest.java
@@ -0,0 +1,42 @@
+package com.nhn.pinpoint.common.bo;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import com.nhn.pinpoint.thrift.dto.TJvmGcType;
+
+/**
+ * @author hyungil.jeong
+ */
+public class AgentStatMemoryGcBoTest {
+
+ @Test
+ public void testByteArrayConversion() {
+ // Given
+ final AgentStatMemoryGcBo.Builder builder = new AgentStatMemoryGcBo.Builder("agentId", 0L, 1L);
+ builder.gcType(TJvmGcType.G1.name());
+ builder.jvmMemoryHeapUsed(Long.MIN_VALUE);
+ builder.jvmMemoryHeapMax(Long.MAX_VALUE);
+ builder.jvmMemoryNonHeapUsed(Long.MIN_VALUE);
+ builder.jvmMemoryNonHeapMax(Long.MAX_VALUE);
+ builder.jvmGcOldCount(1L);
+ builder.jvmGcOldTime(2L);
+ final AgentStatMemoryGcBo testBo = builder.build();
+ // When
+ final byte[] serializedBo = testBo.writeValue();
+ final AgentStatMemoryGcBo deserializedBo = new AgentStatMemoryGcBo.Builder(serializedBo).build();
+ // Then
+ assertEquals(testBo.getAgentId(), deserializedBo.getAgentId());
+ assertEquals(testBo.getStartTimestamp(), deserializedBo.getStartTimestamp());
+ assertEquals(testBo.getTimestamp(), deserializedBo.getTimestamp());
+ assertEquals(testBo.getGcType(), deserializedBo.getGcType());
+ assertEquals(testBo.getJvmMemoryHeapUsed(), deserializedBo.getJvmMemoryHeapUsed());
+ assertEquals(testBo.getJvmMemoryHeapMax(), deserializedBo.getJvmMemoryHeapMax());
+ assertEquals(testBo.getJvmMemoryNonHeapUsed(), deserializedBo.getJvmMemoryNonHeapUsed());
+ assertEquals(testBo.getJvmMemoryNonHeapMax(), deserializedBo.getJvmMemoryNonHeapMax());
+ assertEquals(testBo.getJvmGcOldCount(), deserializedBo.getJvmGcOldCount());
+ assertEquals(testBo.getJvmGcOldTime(), deserializedBo.getJvmGcOldTime());
+ }
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/bo/AnnotationBoTest.java b/src/test/java/com/nhn/pinpoint/common/bo/AnnotationBoTest.java
new file mode 100644
index 000000000..148839950
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/bo/AnnotationBoTest.java
@@ -0,0 +1,41 @@
+package com.nhn.pinpoint.common.bo;
+
+import com.nhn.pinpoint.common.AnnotationKey;
+import com.nhn.pinpoint.common.buffer.AutomaticBuffer;
+import com.nhn.pinpoint.common.buffer.Buffer;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author emeroad
+ */
+public class AnnotationBoTest {
+ @Test
+ public void testGetVersion() throws Exception {
+
+ }
+
+ @Test
+ public void testSetVersion() throws Exception {
+
+ }
+
+ @Test
+ public void testWriteValue() throws Exception {
+ AnnotationBo bo = new AnnotationBo();
+ bo.setKey(AnnotationKey.API.getCode());
+ bo.setByteValue("value".getBytes("UTF-8"));
+// int bufferSize = bo.getBufferSize();
+
+ Buffer buffer = new AutomaticBuffer(128);
+ bo.writeValue(buffer);
+
+ AnnotationBo bo2 = new AnnotationBo();
+ buffer.setOffset(0);
+ bo2.readValue(buffer);
+ Assert.assertEquals(bo.getKey(), bo2.getKey());
+ Assert.assertEquals(bo.getValueType(), bo2.getValueType());
+ Assert.assertArrayEquals(bo.getByteValue(), bo2.getByteValue());
+ }
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/bo/SpanBoTest.java b/src/test/java/com/nhn/pinpoint/common/bo/SpanBoTest.java
new file mode 100644
index 000000000..bed9f0093
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/bo/SpanBoTest.java
@@ -0,0 +1,111 @@
+package com.nhn.pinpoint.common.bo;
+
+
+import com.nhn.pinpoint.common.ServiceType;
+import junit.framework.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author emeroad
+ */
+public class SpanBoTest {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Test
+ public void testVersion() {
+ SpanBo spanBo = new SpanBo();
+ check(spanBo, 0);
+ check(spanBo, 254);
+ check(spanBo, 255);
+ try {
+ check(spanBo, 256);
+ Assert.fail();
+ } catch (Exception e) {
+ }
+
+
+ }
+
+ private void check(SpanBo spanBo, int v) {
+ spanBo.setVersion(v);
+ int version = spanBo.getVersion();
+
+ Assert.assertEquals(v, version);
+ }
+
+ @Test
+ public void serialize() {
+ SpanBo spanBo = new SpanBo();
+ spanBo.setAgentId("agentId");
+ spanBo.setApplicationId("applicationId");
+ spanBo.setEndPoint("end");
+ spanBo.setRpc("rpc");
+
+ spanBo.setParentSpanId(5);
+
+ spanBo.setAgentStartTime(1);
+ spanBo.setTraceAgentStartTime(2);
+ spanBo.setTraceTransactionSequence(3);
+ spanBo.setElapsed(4);
+ spanBo.setStartTime(5);
+
+
+ spanBo.setServiceType(ServiceType.BLOC);
+ byte[] bytes = spanBo.writeValue();
+ logger.info("length:{}", bytes.length);
+
+ SpanBo newSpanBo = new SpanBo();
+ int i = newSpanBo.readValue(bytes, 0);
+ logger.info("length:{}", i);
+ Assert.assertEquals(bytes.length, i);
+ Assert.assertEquals(newSpanBo.getAgentId(), spanBo.getAgentId());
+ Assert.assertEquals(newSpanBo.getApplicationId(), spanBo.getApplicationId());
+ Assert.assertEquals(newSpanBo.getAgentStartTime(), spanBo.getAgentStartTime());
+ Assert.assertEquals(newSpanBo.getElapsed(), spanBo.getElapsed());
+ Assert.assertEquals(newSpanBo.getEndPoint(), spanBo.getEndPoint());
+ Assert.assertEquals(newSpanBo.getErrCode(), spanBo.getErrCode());
+ Assert.assertEquals(newSpanBo.getFlag(), spanBo.getFlag());
+
+// 이건 serialize에서 안가져옴.
+// Assert.assertEquals(newSpanBo.getTraceAgentStartTime(), spanBo.getTraceAgentStartTime());
+// Assert.assertEquals(newSpanBo.getTraceTransactionSequence(), spanBo.getTraceTransactionSequence());
+ Assert.assertEquals(newSpanBo.getParentSpanId(), spanBo.getParentSpanId());
+
+ Assert.assertEquals(newSpanBo.getVersion(), spanBo.getVersion());
+
+
+ }
+
+ @Test
+ public void serialize2() {
+ SpanBo spanBo = new SpanBo();
+ spanBo.setAgentId("agent");
+ String service = createString(5);
+ spanBo.setApplicationId(service);
+ String endPoint = createString(127);
+ spanBo.setEndPoint(endPoint);
+ String rpc = createString(255);
+ spanBo.setRpc(rpc);
+
+ spanBo.setServiceType(ServiceType.BLOC);
+
+ byte[] bytes = spanBo.writeValue();
+ logger.info("length:{}", bytes.length);
+
+ SpanBo newSpanBo = new SpanBo();
+ int i = newSpanBo.readValue(bytes, 0);
+ logger.info("length:{}", i);
+ Assert.assertEquals(bytes.length, i);
+ }
+
+ private String createString(int size) {
+ StringBuilder sb = new StringBuilder(size);
+ for (int i = 0; i < size; i++) {
+ sb.append('a');
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/bo/SpanEventBoTest.java b/src/test/java/com/nhn/pinpoint/common/bo/SpanEventBoTest.java
new file mode 100644
index 000000000..eaa72b4be
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/bo/SpanEventBoTest.java
@@ -0,0 +1,67 @@
+package com.nhn.pinpoint.common.bo;
+
+import com.nhn.pinpoint.common.ServiceType;
+import junit.framework.Assert;
+import org.junit.Test;
+
+/**
+ * @author emeroad
+ */
+public class SpanEventBoTest {
+
+ @Test
+ public void testSerialize() throws Exception {
+ SpanEventBo spanEventBo = new SpanEventBo();
+ spanEventBo.setAgentId("test");
+ spanEventBo.setAgentStartTime(1);
+ spanEventBo.setDepth(3);
+ spanEventBo.setDestinationId("testdest");
+ spanEventBo.setEndElapsed(2);
+ spanEventBo.setEndPoint("endpoint");
+
+ spanEventBo.setNextSpanId(4);
+ spanEventBo.setRpc("rpc");
+
+ spanEventBo.setServiceType(ServiceType.TOMCAT);
+ spanEventBo.setSpanId(12);
+ spanEventBo.setStartElapsed(100);
+
+ byte[] bytes = spanEventBo.writeValue();
+
+ SpanEventBo newSpanEventBo = new SpanEventBo();
+ int i = newSpanEventBo.readValue(bytes, 0);
+ Assert.assertEquals(bytes.length, i);
+
+
+ Assert.assertEquals(spanEventBo.getAgentId(), newSpanEventBo.getAgentId());
+ Assert.assertEquals(spanEventBo.getAgentStartTime(), newSpanEventBo.getAgentStartTime());
+ Assert.assertEquals(spanEventBo.getDepth(), newSpanEventBo.getDepth());
+ Assert.assertEquals(spanEventBo.getDestinationId(), newSpanEventBo.getDestinationId());
+ Assert.assertEquals(spanEventBo.getEndElapsed(), newSpanEventBo.getEndElapsed());
+ Assert.assertEquals(spanEventBo.getEndPoint(), newSpanEventBo.getEndPoint());
+
+
+ Assert.assertEquals(spanEventBo.getNextSpanId(), newSpanEventBo.getNextSpanId());
+ Assert.assertEquals(spanEventBo.getRpc(), newSpanEventBo.getRpc());
+ Assert.assertEquals(spanEventBo.getServiceType(), newSpanEventBo.getServiceType());
+ Assert.assertEquals(spanEventBo.getStartElapsed(), newSpanEventBo.getStartElapsed());
+
+
+ // 아래는 rowKeye에서 가져 오는값.
+ spanEventBo.setSpanId(1);
+ newSpanEventBo.setSpanId(1);
+ Assert.assertEquals(spanEventBo.getSpanId(), newSpanEventBo.getSpanId());
+
+ spanEventBo.setTraceTransactionSequence(1);
+ newSpanEventBo.setTraceTransactionSequence(1);
+ Assert.assertEquals(spanEventBo.getTraceTransactionSequence(), newSpanEventBo.getTraceTransactionSequence());
+
+ spanEventBo.setTraceAgentStartTime(3);
+ newSpanEventBo.setTraceAgentStartTime(3);
+ Assert.assertEquals(spanEventBo.getTraceAgentStartTime(), newSpanEventBo.getTraceAgentStartTime());
+
+ spanEventBo.setSequence((short) 3);
+ newSpanEventBo.setSequence((short) 3);
+ Assert.assertEquals(spanEventBo.getSequence(), newSpanEventBo.getSequence());
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/buffer/AutomaticBufferTest.java b/src/test/java/com/nhn/pinpoint/common/buffer/AutomaticBufferTest.java
new file mode 100644
index 000000000..516a96bd1
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/buffer/AutomaticBufferTest.java
@@ -0,0 +1,294 @@
+package com.nhn.pinpoint.common.buffer;
+
+import com.nhn.pinpoint.common.util.BytesUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.charset.Charset;
+import java.util.Random;
+
+/**
+ * @author emeroad
+ */
+public class AutomaticBufferTest {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private Random random = new Random();
+
+ @Test
+ public void testPutPrefixedBytes() throws Exception {
+ Buffer buffer = new AutomaticBuffer(0);
+ buffer.put(1);
+ byte[] buf = buffer.getBuffer();
+ Assert.assertEquals(buf.length, 4);
+ Assert.assertEquals(1, BytesUtils.bytesToInt(buf, 0));
+ }
+
+
+ @Test
+ public void testPadBytes() throws Exception {
+ int TOTAL_LENGTH = 20;
+ int TEST_SIZE = 10;
+ int PAD_SIZE = TOTAL_LENGTH - TEST_SIZE;
+ Buffer buffer = new AutomaticBuffer(10);
+ byte[] test = new byte[10];
+
+ random.nextBytes(test);
+
+ buffer.putPadBytes(test, TOTAL_LENGTH);
+
+ byte[] result = buffer.getBuffer();
+ junit.framework.Assert.assertEquals(result.length, TOTAL_LENGTH);
+ junit.framework.Assert.assertTrue("check data", Bytes.equals(test, 0, TEST_SIZE, result, 0, TEST_SIZE));
+ byte[] padBytes = new byte[TOTAL_LENGTH - TEST_SIZE];
+ junit.framework.Assert.assertTrue("check pad", Bytes.equals(padBytes, 0, TEST_SIZE, result, TEST_SIZE, PAD_SIZE));
+
+ }
+
+ @Test
+ public void testPadBytes_Error() throws Exception {
+
+ Buffer buffer1_1 = new AutomaticBuffer(32);
+ try {
+ buffer1_1.putPadBytes(new byte[11], 10);
+ } catch (Exception e) {
+ }
+
+ Buffer buffer1_2 = new AutomaticBuffer(32);
+ try {
+ buffer1_2.putPadBytes(new byte[20], 10);
+ junit.framework.Assert.fail("error");
+ } catch (Exception e) {
+ }
+
+ Buffer buffer2 = new AutomaticBuffer(32);
+ buffer2.putPadBytes(new byte[10], 10);
+
+
+ Buffer buffer3 = new AutomaticBuffer(5);
+ buffer3.putPadBytes(new byte[10], 10);
+ }
+
+
+ @Test
+ public void testPadString() throws Exception {
+ int TOTAL_LENGTH = 20;
+ int TEST_SIZE = 10;
+ int PAD_SIZE = TOTAL_LENGTH - TEST_SIZE;
+ Buffer buffer = new AutomaticBuffer(32);
+ String test = StringUtils.repeat('a', TEST_SIZE);
+
+ buffer.putPadString(test, TOTAL_LENGTH);
+
+ byte[] result = buffer.getBuffer();
+ String decodedString = new String(result);
+ String trimString = decodedString.trim();
+ junit.framework.Assert.assertEquals(result.length, TOTAL_LENGTH);
+
+ junit.framework.Assert.assertEquals("check data", test, trimString);
+
+ String padString = new String(result, TOTAL_LENGTH - TEST_SIZE, PAD_SIZE, "UTF-8");
+ byte[] padBytes = new byte[TOTAL_LENGTH - TEST_SIZE];
+ junit.framework.Assert.assertEquals("check pad", padString, new String(padBytes, Charset.forName("UTF-8")));
+
+ }
+
+ @Test
+ public void testPadString_Error() throws Exception {
+
+ Buffer buffer1_1 = new AutomaticBuffer(32);
+ try {
+ buffer1_1.putPadString(StringUtils.repeat('a', 11), 10);
+ } catch (Exception e) {
+ }
+
+ Buffer buffer1_2 = new AutomaticBuffer(32);
+ try {
+ buffer1_2.putPadString(StringUtils.repeat('a', 20), 10);
+ junit.framework.Assert.fail("error");
+ } catch (Exception e) {
+ }
+
+ Buffer buffer2 = new AutomaticBuffer(32);
+ buffer2.putPadString(StringUtils.repeat('a', 10), 10);
+
+ Buffer buffer3 = new AutomaticBuffer(5);
+ buffer3.putPadString(StringUtils.repeat('a', 10), 10);
+ }
+
+ @Test
+ public void testPut2PrefixedBytes() throws Exception {
+ byte[] bytes1 = new byte[2];
+ checkPut2PrefixedBytes(bytes1);
+
+ byte[] bytes2 = new byte[0];
+ checkPut2PrefixedBytes(bytes2);
+
+ byte[] bytes3 = new byte[Short.MAX_VALUE];
+ checkPut2PrefixedBytes(bytes3);
+
+ checkPut2PrefixedBytes(null);
+
+ try {
+ byte[] bytes4 = new byte[Short.MAX_VALUE+1];
+ checkPut2PrefixedBytes(bytes4);
+ Assert.fail("too large bytes");
+ } catch (Exception e) {
+ }
+ }
+
+ private void checkPut2PrefixedBytes(byte[] bytes) {
+ Buffer buffer = new AutomaticBuffer(0);
+ buffer.put2PrefixedBytes(bytes);
+
+ Buffer copy = new FixedBuffer(buffer.getBuffer());
+ Assert.assertArrayEquals(bytes, copy.read2PrefixedBytes());
+ }
+
+ @Test
+ public void testPut4PrefixedBytes() throws Exception {
+ byte[] bytes1 = new byte[2];
+ checkPut4PrefixedBytes(bytes1);
+
+ byte[] bytes2 = new byte[0];
+ checkPut4PrefixedBytes(bytes2);
+
+ checkPut4PrefixedBytes(null);
+
+ }
+
+ private void checkPut4PrefixedBytes(byte[] bytes) {
+ Buffer buffer = new AutomaticBuffer(0);
+ buffer.put4PrefixedBytes(bytes);
+
+ Buffer copy = new FixedBuffer(buffer.getBuffer());
+ Assert.assertArrayEquals(bytes, copy.read4PrefixedBytes());
+ }
+
+ @Test
+ public void testPutPrefixedBytesCheckRange() throws Exception {
+ Buffer buffer = new AutomaticBuffer(1);
+ buffer.putPrefixedString(null);
+ byte[] internalBuffer = buffer.getInternalBuffer();
+ // 상속 관계에 의해서 강제로 버퍼 사이즈를 늘어나지 않아도 되는데 사이즈가 늘어남.
+ Assert.assertEquals(1, internalBuffer.length);
+ }
+
+
+
+ @Test
+ public void testCurrentTime() throws InterruptedException {
+ Buffer buffer = new AutomaticBuffer(32);
+
+ long l = System.currentTimeMillis();
+ buffer.putSVar(l);
+ logger.trace("currentTime size:{}", buffer.getOffset());
+ buffer.setOffset(0);
+ Assert.assertEquals(buffer.readSVarLong(), l);
+
+
+ }
+
+ @Test
+ public void testPutVarInt() throws Exception {
+ Buffer buffer = new AutomaticBuffer(0);
+ buffer.putVar(Integer.MAX_VALUE);
+ buffer.putVar(Integer.MIN_VALUE);
+ buffer.putVar(0);
+ buffer.putVar(1);
+ buffer.putVar(12345);
+
+ buffer.setOffset(0);
+ Assert.assertEquals(buffer.readVarInt(), Integer.MAX_VALUE);
+ Assert.assertEquals(buffer.readVarInt(), Integer.MIN_VALUE);
+ Assert.assertEquals(buffer.readVarInt(), 0);
+ Assert.assertEquals(buffer.readVarInt(), 1);
+ Assert.assertEquals(buffer.readVarInt(), 12345);
+ }
+
+ @Test
+ public void testPutVarLong() throws Exception {
+ Buffer buffer = new AutomaticBuffer(0);
+ buffer.putVar(Long.MAX_VALUE);
+ buffer.putVar(Long.MIN_VALUE);
+ buffer.putVar(0L);
+ buffer.putVar(1L);
+ buffer.putVar(12345L);
+
+ buffer.setOffset(0);
+ Assert.assertEquals(buffer.readVarLong(), Long.MAX_VALUE);
+ Assert.assertEquals(buffer.readVarLong(), Long.MIN_VALUE);
+ Assert.assertEquals(buffer.readVarLong(), 0L);
+ Assert.assertEquals(buffer.readVarLong(), 1L);
+ Assert.assertEquals(buffer.readVarLong(), 12345L);
+ }
+
+ @Test
+ public void testPutSVarLong() throws Exception {
+ Buffer buffer = new AutomaticBuffer(32);
+ buffer.putSVar(Long.MAX_VALUE);
+ buffer.putSVar(Long.MIN_VALUE);
+ buffer.putSVar(0L);
+ buffer.putSVar(1L);
+ buffer.putSVar(12345L);
+
+ buffer.setOffset(0);
+ Assert.assertEquals(buffer.readSVarLong(), Long.MAX_VALUE);
+ Assert.assertEquals(buffer.readSVarLong(), Long.MIN_VALUE);
+ Assert.assertEquals(buffer.readSVarLong(), 0L);
+ Assert.assertEquals(buffer.readSVarLong(), 1L);
+ Assert.assertEquals(buffer.readSVarLong(), 12345L);
+ }
+
+ @Test
+ public void testPutSVarInt() throws Exception {
+ Buffer buffer = new AutomaticBuffer(32);
+ buffer.putSVar(Integer.MAX_VALUE);
+ buffer.putSVar(Integer.MIN_VALUE);
+ buffer.putSVar(0);
+ buffer.putSVar(1);
+ buffer.putSVar(12345);
+
+ buffer.setOffset(0);
+ Assert.assertEquals(buffer.readSVarInt(), Integer.MAX_VALUE);
+ Assert.assertEquals(buffer.readSVarInt(), Integer.MIN_VALUE);
+ Assert.assertEquals(buffer.readSVarInt(), 0);
+ Assert.assertEquals(buffer.readSVarInt(), 1);
+ Assert.assertEquals(buffer.readSVarInt(), 12345);
+ }
+
+ @Test
+ public void testPut() throws Exception {
+ Buffer buffer = new AutomaticBuffer(0);
+ buffer.put(1);
+ buffer.put(1L);
+ buffer.putPrefixedBytes(new byte[10]);
+ buffer.put((byte)1);
+
+
+ }
+
+ @Ignore
+ @Test
+ public void testUdp() throws Exception {
+ // Signature:Header{signature=85, version=100, type=28704}
+ Buffer buffer = new AutomaticBuffer(10);
+ buffer.put((byte)85);
+ buffer.put((byte) 100);
+ buffer.put((short)28704);
+
+ Buffer read = new FixedBuffer(buffer.getBuffer());
+ logger.info("{}", (char)read.readByte());
+ logger.info("{}", (char)read.readByte());
+ logger.info("{}", (char)read.readByte());
+ logger.info("{}", (char)read.readByte());
+
+ }
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/buffer/FixedBufferTest.java b/src/test/java/com/nhn/pinpoint/common/buffer/FixedBufferTest.java
new file mode 100644
index 000000000..f5b1ba7f9
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/buffer/FixedBufferTest.java
@@ -0,0 +1,444 @@
+package com.nhn.pinpoint.common.buffer;
+
+import com.nhn.pinpoint.common.util.BytesUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * @author emeroad
+ */
+public class FixedBufferTest {
+ private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private Random random = new Random();
+
+ @Test
+ public void testPutPrefixedBytes() throws Exception {
+ String test = "test";
+ int endExpected = 3333;
+ testPutPrefixedBytes(test, endExpected);
+ testPutPrefixedBytes(null, endExpected);
+ testPutPrefixedBytes("", endExpected);
+ }
+
+ private void testPutPrefixedBytes(String test, int expected) throws UnsupportedEncodingException {
+ Buffer buffer = new FixedBuffer(1024);
+ if (test != null) {
+ buffer.putPrefixedBytes(test.getBytes("UTF-8"));
+ } else {
+ buffer.putPrefixedString(null);
+ }
+
+ buffer.put(expected);
+ byte[] buffer1 = buffer.getBuffer();
+
+ Buffer actual = new FixedBuffer(buffer1);
+ String s = actual.readPrefixedString();
+ Assert.assertEquals(test, s);
+
+ int i = actual.readInt();
+ Assert.assertEquals(expected, i);
+ }
+
+ @Test
+ public void testPadBytes() throws Exception {
+ int TOTAL_LENGTH = 20;
+ int TEST_SIZE = 10;
+ int PAD_SIZE = TOTAL_LENGTH - TEST_SIZE;
+ Buffer buffer = new FixedBuffer(32);
+ byte[] test = new byte[10];
+
+ random.nextBytes(test);
+
+ buffer.putPadBytes(test, TOTAL_LENGTH);
+
+ byte[] result = buffer.getBuffer();
+ Assert.assertEquals(result.length, TOTAL_LENGTH);
+ Assert.assertTrue("check data", Bytes.equals(test, 0, TEST_SIZE, result, 0, TEST_SIZE));
+ byte[] padBytes = new byte[TOTAL_LENGTH - TEST_SIZE];
+ Assert.assertTrue("check pad", Bytes.equals(padBytes, 0, TEST_SIZE, result, TEST_SIZE, PAD_SIZE));
+
+ }
+
+ @Test
+ public void readPadBytes() {
+ byte[] bytes = new byte[10];
+ random.nextBytes(bytes);
+ Buffer writeBuffer = new FixedBuffer(32);
+ writeBuffer.putPadBytes(bytes, 20);
+ writeBuffer.put(255);
+
+ Buffer readBuffer = new FixedBuffer(writeBuffer.getBuffer());
+ byte[] readPadBytes = readBuffer.readPadBytes(20);
+ Assert.assertArrayEquals(bytes, Arrays.copyOf(readPadBytes, 10));
+ int readInt = readBuffer.readInt();
+ Assert.assertEquals(255, readInt);
+ }
+
+
+ @Test
+ public void testPadBytes_Error() throws Exception {
+
+ Buffer buffer1_1 = new FixedBuffer(32);
+ try {
+ buffer1_1.putPadBytes(new byte[11], 10);
+ } catch (Exception e) {
+ }
+
+ Buffer buffer1_2 = new FixedBuffer(32);
+ try {
+ buffer1_2.putPadBytes(new byte[20], 10);
+ Assert.fail("error");
+ } catch (Exception e) {
+ }
+
+ Buffer buffer2 = new FixedBuffer(32);
+ buffer2.putPadBytes(new byte[10], 10);
+
+ }
+
+ @Test
+ public void testPadString() throws Exception {
+ int TOTAL_LENGTH = 20;
+ int TEST_SIZE = 10;
+ int PAD_SIZE = TOTAL_LENGTH - TEST_SIZE;
+ Buffer buffer= new FixedBuffer(32);
+ String test = StringUtils.repeat('a', TEST_SIZE);
+
+ buffer.putPadString(test, TOTAL_LENGTH);
+
+ byte[] result = buffer.getBuffer();
+ String decodedString = new String(result);
+ String trimString = decodedString.trim();
+ Assert.assertEquals(result.length, TOTAL_LENGTH);
+
+ Assert.assertEquals("check data", test, trimString);
+
+ String padString = new String(result, TOTAL_LENGTH - TEST_SIZE, PAD_SIZE, "UTF-8");
+ byte[] padBytes = new byte[TOTAL_LENGTH - TEST_SIZE];
+ Assert.assertEquals("check pad", padString, new String(padBytes, Charset.forName("UTF-8")));
+
+ }
+
+ @Test
+ public void readPadString() {
+ String testString = StringUtils.repeat('a', 10);
+ Buffer writeBuffer = new FixedBuffer(32);
+ writeBuffer.putPadString(testString, 20);
+ writeBuffer.put(255);
+
+ Buffer readBuffer = new FixedBuffer(writeBuffer.getBuffer());
+ String readPadString = readBuffer.readPadString(20);
+ Assert.assertEquals(testString, readPadString.substring(0, 10));
+ int readInt = readBuffer.readInt();
+ Assert.assertEquals(255, readInt);
+ }
+
+ @Test
+ public void readPadStringAndRightTrim() {
+ String testString = StringUtils.repeat('a', 10);
+ Buffer writeBuffer = new FixedBuffer(32);
+ writeBuffer.putPadString(testString, 20);
+ writeBuffer.put(255);
+
+ Buffer readBuffer = new FixedBuffer(writeBuffer.getBuffer());
+ String readPadString = readBuffer.readPadStringAndRightTrim(20);
+ Assert.assertEquals(testString, readPadString);
+ int readInt = readBuffer.readInt();
+ Assert.assertEquals(255, readInt);
+ }
+
+ @Test
+ public void testPadString_Error() throws Exception {
+
+ Buffer buffer1_1 = new FixedBuffer(32);
+ try {
+ buffer1_1.putPadString(StringUtils.repeat('a', 11), 10);
+ } catch (Exception e) {
+ }
+
+ Buffer buffer1_2 = new FixedBuffer(32);
+ try {
+ buffer1_2.putPadString(StringUtils.repeat('a', 20), 10);
+ Assert.fail("error");
+ } catch (Exception e) {
+ }
+
+ Buffer buffer2 = new FixedBuffer(32);
+ buffer2.putPadString(StringUtils.repeat('a', 10), 10);
+ }
+
+ @Test
+ public void testPut2PrefixedBytes() throws Exception {
+ String test = "test";
+ int endExpected = 3333;
+
+ checkPut2PrefixedBytes(test, endExpected);
+ checkPut2PrefixedBytes(null, endExpected);
+ checkPut2PrefixedBytes("", endExpected);
+
+ byte[] bytes = new byte[Short.MAX_VALUE];
+ checkPut2PrefixedBytes(BytesUtils.toString(bytes), endExpected, Short.MAX_VALUE * 2);
+
+ try {
+ byte[] bytes2 = new byte[Short.MAX_VALUE + 1];
+ checkPut2PrefixedBytes(BytesUtils.toString(bytes2), endExpected, Short.MAX_VALUE * 2);
+ Assert.fail("too large bytes");
+ } catch (Exception e) {
+ }
+
+ }
+
+ private void checkPut2PrefixedBytes(String test, int expected) throws UnsupportedEncodingException {
+ checkPut2PrefixedBytes(test, expected, 1024);
+ }
+
+ private void checkPut2PrefixedBytes(String test, int expected, int bufferSize) throws UnsupportedEncodingException {
+ Buffer buffer = new FixedBuffer(bufferSize);
+ if (test != null) {
+ buffer.put2PrefixedBytes(test.getBytes("UTF-8"));
+ } else {
+ buffer.put2PrefixedBytes(null);
+ }
+
+ buffer.put(expected);
+ byte[] buffer1 = buffer.getBuffer();
+
+ Buffer actual = new FixedBuffer(buffer1);
+ String s = actual.read2PrefixedString();
+ Assert.assertEquals(test, s);
+
+ int i = actual.readInt();
+ Assert.assertEquals(expected, i);
+ }
+
+ @Test
+ public void testPut4PrefixedBytes() throws Exception {
+ String test = "test";
+ int endExpected = 3333;
+
+ checkPut4PrefixedBytes(test, endExpected);
+ checkPut4PrefixedBytes(null, endExpected);
+ checkPut4PrefixedBytes("", endExpected);
+
+ }
+
+ private void checkPut4PrefixedBytes(String test, int expected) throws UnsupportedEncodingException {
+ Buffer buffer = new FixedBuffer(1024);
+ if (test != null) {
+ buffer.put4PrefixedBytes(test.getBytes("UTF-8"));
+ } else {
+ buffer.put4PrefixedBytes(null);
+ }
+
+ buffer.put(expected);
+ byte[] buffer1 = buffer.getBuffer();
+
+ Buffer actual = new FixedBuffer(buffer1);
+ String s = actual.read4PrefixedString();
+ Assert.assertEquals(test, s);
+
+ int i = actual.readInt();
+ Assert.assertEquals(expected, i);
+ }
+
+ @Test
+ public void testReadByte() throws Exception {
+
+ }
+
+ @Test
+ public void testReadBoolean() throws Exception {
+
+ }
+
+ @Test
+ public void testReadInt() throws Exception {
+
+ }
+
+ @Test
+ public void testReadLong() throws Exception {
+
+ }
+
+
+
+
+ @Test
+ public void testReadPrefixedString() throws Exception {
+
+ }
+
+ @Test
+ public void testRead4PrefixedString() throws Exception {
+ String value = "test";
+ byte[] length = Bytes.toBytes(value.length());
+ byte[] string = Bytes.toBytes(value);
+ byte[] result = Bytes.add(length, string);
+
+
+ Buffer buffer = new FixedBuffer(result);
+ String prefixedString = buffer.read4PrefixedString();
+ Assert.assertEquals(prefixedString, value);
+
+ }
+
+ @Test
+ public void testRead4PrefixedString_Null() throws Exception {
+ byte[] length = Bytes.toBytes(-1);
+
+
+ Buffer buffer = new FixedBuffer(length);
+ String prefixedString = buffer.read4PrefixedString();
+ Assert.assertEquals(prefixedString, null);
+
+ }
+
+ @Test
+ public void testPut() throws Exception {
+ checkUnsignedByte(255);
+
+ checkUnsignedByte(0);
+ }
+
+ @Test
+ public void testPutVar32() throws Exception {
+ checkVarInt(Integer.MAX_VALUE, 5);
+ checkVarInt(25, 1);
+ checkVarInt(100, 1);
+
+ checkVarInt(Integer.MIN_VALUE, 10);
+
+ checkVarInt(0, -1);
+ checkVarInt(Integer.MAX_VALUE / 2, -1);
+ checkVarInt(Integer.MAX_VALUE / 10, -1);
+ checkVarInt(Integer.MAX_VALUE / 10000, -1);
+
+ checkVarInt(Integer.MIN_VALUE / 2, -1);
+ checkVarInt(Integer.MIN_VALUE / 10, -1);
+ checkVarInt(Integer.MIN_VALUE / 10000, -1);
+
+ }
+
+ private void checkVarInt(int v, int offset) {
+ Buffer buffer = new FixedBuffer(32);
+ buffer.putVar(v);
+ if (offset != -1) {
+ Assert.assertEquals(buffer.getOffset(), offset);
+ } else {
+ logger.info("{} offsetSize:{}", v, buffer.getOffset());
+ }
+ buffer.setOffset(0);
+ int readV = buffer.readVarInt();
+ Assert.assertEquals(readV, v);
+ }
+
+ @Test
+ public void testPutSVar32() throws Exception {
+ // 63이 1바이트 경계.
+ checkSVarInt(63, -1);
+ // 8191이 2바이트 경계
+ checkSVarInt((1024*8)-1, -1);
+
+ checkSVarInt(3, -1);
+
+ checkSVarInt(Integer.MAX_VALUE, 5);
+
+ checkSVarInt(Integer.MIN_VALUE, 5);
+
+ checkSVarInt(0, -1);
+ checkSVarInt(Integer.MAX_VALUE / 2, -1);
+ checkSVarInt(Integer.MAX_VALUE / 10, -1);
+ checkSVarInt(Integer.MAX_VALUE / 10000, -1);
+
+ checkSVarInt(Integer.MIN_VALUE / 2, -1);
+ checkSVarInt(Integer.MIN_VALUE / 10, -1);
+ checkSVarInt(Integer.MIN_VALUE / 10000, -1);
+
+
+ }
+
+ private void checkSVarInt(int v, int offset) {
+ Buffer buffer = new FixedBuffer(32);
+ buffer.putSVar(v);
+ if (offset != -1) {
+ Assert.assertEquals(buffer.getOffset(), offset);
+ } else {
+ logger.info("{} offsetSize:{}", v, buffer.getOffset());
+ }
+ buffer.setOffset(0);
+ int readV = buffer.readSVarInt();
+ Assert.assertEquals(readV, v);
+ }
+
+ @Test
+ public void testPutVar64() throws Exception {
+
+ }
+
+ private void checkUnsignedByte(int value) {
+ Buffer buffer = new FixedBuffer(1024);
+ buffer.put((byte) value);
+ byte[] buffer1 = buffer.getBuffer();
+
+ Buffer reader = new FixedBuffer(buffer1);
+ int i = reader.readUnsignedByte();
+ Assert.assertEquals(value, i);
+ }
+
+
+ @Test
+ public void testGetBuffer() throws Exception {
+ Buffer buffer = new FixedBuffer(4);
+ buffer.put(1);
+ Assert.assertEquals(buffer.getOffset(), 4);
+ Assert.assertEquals(buffer.getBuffer().length, 4);
+ }
+
+ @Test
+ public void testSliceGetBuffer() throws Exception {
+ Buffer buffer = new FixedBuffer(5);
+ buffer.put(1);
+ Assert.assertEquals(buffer.getOffset(), 4);
+ Assert.assertEquals(buffer.getBuffer().length, 4);
+
+ byte[] buffer1 = buffer.getBuffer();
+ byte[] buffer2 = buffer.getBuffer();
+ Assert.assertTrue(buffer1 != buffer2);
+
+ }
+
+ @Test
+ public void testBoolean() {
+ Buffer buffer = new FixedBuffer(16);
+ buffer.put(true);
+ buffer.put(false);
+
+ Buffer read = new FixedBuffer(buffer.getBuffer());
+ boolean b = read.readBoolean();
+ Assert.assertEquals(true, b);
+
+ boolean c = read.readBoolean();
+ Assert.assertEquals(false, c);
+ }
+
+ @Test
+ public void testGetOffset() throws Exception {
+ Buffer buffer = new FixedBuffer();
+ Assert.assertEquals(buffer.getOffset(), 0);
+
+ buffer.put(4);
+ Assert.assertEquals(buffer.getOffset(), 4);
+
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/buffer/OffsetAutomaticBufferTest.java b/src/test/java/com/nhn/pinpoint/common/buffer/OffsetAutomaticBufferTest.java
new file mode 100644
index 000000000..ff7eebde4
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/buffer/OffsetAutomaticBufferTest.java
@@ -0,0 +1,22 @@
+package com.nhn.pinpoint.common.buffer;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+/**
+ * @author emeroad
+ */
+public class OffsetAutomaticBufferTest {
+ @Test
+ public void testGetBuffer() throws Exception {
+ final int putValue = 10;
+ Buffer buffer = new OffsetAutomaticBuffer(new byte[10], 2);
+ buffer.put(putValue);
+ byte[] intBuffer = buffer.getBuffer();
+ Assert.assertEquals(intBuffer.length, 4);
+
+ Buffer read = new FixedBuffer(intBuffer);
+ int value = read.readInt();
+ Assert.assertEquals(putValue, value);
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/buffer/OffsetFixedBufferTest.java b/src/test/java/com/nhn/pinpoint/common/buffer/OffsetFixedBufferTest.java
new file mode 100644
index 000000000..b4e21e8b7
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/buffer/OffsetFixedBufferTest.java
@@ -0,0 +1,38 @@
+package com.nhn.pinpoint.common.buffer;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+/**
+ * @author emeroad
+ */
+public class OffsetFixedBufferTest {
+
+ @Test
+ public void testFixedBuffer() throws Exception {
+ new OffsetFixedBuffer(new byte[10], 10);
+ try {
+ new OffsetFixedBuffer(new byte[10], 11);
+ Assert.fail();
+ } catch (Exception e) {
+ }
+ try {
+ new OffsetFixedBuffer(new byte[10], -1);
+ Assert.fail();
+ } catch (Exception e) {
+ }
+ }
+
+ @Test
+ public void testGetBuffer() throws Exception {
+ final int putValue = 10;
+ Buffer buffer = new OffsetFixedBuffer(new byte[10], 2);
+ buffer.put(putValue);
+ byte[] intBuffer = buffer.getBuffer();
+ Assert.assertEquals(intBuffer.length, 4);
+
+ Buffer read = new FixedBuffer(intBuffer);
+ int value = read.readInt();
+ Assert.assertEquals(putValue, value);
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/hbase/HbaseTemplate2Test.java b/src/test/java/com/nhn/pinpoint/common/hbase/HbaseTemplate2Test.java
new file mode 100644
index 000000000..6658d093b
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/hbase/HbaseTemplate2Test.java
@@ -0,0 +1,70 @@
+package com.nhn.pinpoint.common.hbase;
+
+import com.nhn.pinpoint.common.util.PropertyUtils;
+import junit.framework.Assert;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.TableNotFoundException;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.hadoop.hbase.HbaseConfigurationFactoryBean;
+import org.springframework.data.hadoop.hbase.HbaseSystemException;
+
+import java.io.IOException;
+import java.util.Properties;
+
+
+/**
+ * @author emeroad
+ */
+public class HbaseTemplate2Test {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private static HbaseConfigurationFactoryBean hbaseConfigurationFactoryBean;
+
+ @BeforeClass
+ public static void beforeClass() throws IOException {
+ String path = HbaseTemplate2Test.class.getClassLoader().getResource("test-hbase.properties").getPath();
+ Properties properties = PropertyUtils.readProperties(path);
+
+ Configuration cfg = HBaseConfiguration.create();
+ cfg.set("hbase.zookeeper.quorum", properties.getProperty("hbase.client.host"));
+ cfg.set("hbase.zookeeper.property.clientPort", properties.getProperty("hbase.client.port"));
+ hbaseConfigurationFactoryBean = new HbaseConfigurationFactoryBean();
+ hbaseConfigurationFactoryBean.setConfiguration(cfg);
+ hbaseConfigurationFactoryBean.afterPropertiesSet();
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ if (hbaseConfigurationFactoryBean != null) {
+ hbaseConfigurationFactoryBean.destroy();
+ }
+
+ }
+
+
+ @Test
+ public void notExist() throws Exception {
+
+ HbaseTemplate2 hbaseTemplate2 = new HbaseTemplate2();
+ hbaseTemplate2.setConfiguration(hbaseConfigurationFactoryBean.getObject());
+ hbaseTemplate2.afterPropertiesSet();
+
+ try {
+ hbaseTemplate2.put("NOT_EXIST", new byte[0], "familyName".getBytes(), "columnName".getBytes(), new byte[0]);
+ Assert.fail("exceptions");
+ } catch (HbaseSystemException e) {
+ if (!(e.getCause().getCause() instanceof TableNotFoundException)) {
+ Assert.fail("unexpected exception :" + e.getCause());
+ }
+ } finally {
+ hbaseTemplate2.destroy();
+ }
+
+
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/AnnotationTranscoderTest.java b/src/test/java/com/nhn/pinpoint/common/util/AnnotationTranscoderTest.java
new file mode 100644
index 000000000..355a2df55
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/AnnotationTranscoderTest.java
@@ -0,0 +1,146 @@
+package com.nhn.pinpoint.common.util;
+
+
+import com.nhn.pinpoint.common.bo.IntStringValue;
+import com.nhn.pinpoint.thrift.dto.TIntStringValue;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TIOStreamTransport;
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+ * @author emeroad
+ */
+public class AnnotationTranscoderTest {
+
+ private Logger logger = LoggerFactory.getLogger(this.getClass().getName());
+
+ @Test
+ public void testDecode() throws Exception {
+ typeCode("test");
+ typeCode("");
+ typeCode("adfesdfsesdfsdfserfsdfsdfe");
+
+ typeCode(1);
+ typeCode(0);
+ typeCode(-1212);
+
+ typeCode((short) 4);
+ typeCode((short) -124);
+
+ typeCode(2L);
+ typeCode(-22342342L);
+
+ typeCode(3f);
+ typeCode(123.3f);
+
+ typeCode(4D);
+ typeCode(-124D);
+
+ typeCode((byte) 4);
+ typeCode((byte) -14);
+
+ typeCode(true);
+ typeCode(false);
+
+ typeCode(null);
+
+ typeUnsupportCode(new Date());
+
+ typeBinaryCode(new byte[]{12, 3, 4, 1, 23, 4, 1, 2, 3, 4, 4});
+
+ }
+
+ private void typeCode(Object value) {
+ AnnotationTranscoder transcoder = new AnnotationTranscoder();
+
+ byte typeCode = transcoder.getTypeCode(value);
+ byte[] bytes = transcoder.encode(value, typeCode);
+ Object decode = transcoder.decode(typeCode, bytes);
+
+ Assert.assertEquals(value, decode);
+ }
+
+ private void typeUnsupportCode(Object value) {
+ AnnotationTranscoder transcoder = new AnnotationTranscoder();
+
+ byte typeCode = transcoder.getTypeCode(value);
+ byte[] bytes = transcoder.encode(value, typeCode);
+ Object decode = transcoder.decode(typeCode, bytes);
+
+ Assert.assertEquals(value.toString(), decode.toString());
+ }
+
+ private void typeBinaryCode(byte[] value) {
+ AnnotationTranscoder transcoder = new AnnotationTranscoder();
+
+ byte typeCode = transcoder.getTypeCode(value);
+ byte[] bytes = transcoder.encode(value, typeCode);
+ Object decode = transcoder.decode(typeCode, bytes);
+
+ Assert.assertArrayEquals(value, (byte[]) decode);
+ }
+
+ @Test
+ public void testGetTypeCode() throws Exception {
+ int i = 2 << 8;
+ System.out.println(i);
+ write(i);
+ int j = 3 << 8;
+ System.out.println(j);
+ write(j);
+ write(10);
+ write(512);
+ write(256);
+
+
+ }
+
+ @Test
+ public void testIntString() {
+
+ testIntString(-1, "");
+ testIntString(0, "");
+ testIntString(1, "");
+ testIntString(Integer.MAX_VALUE, "test");
+ testIntString(Integer.MIN_VALUE, "test");
+
+ // null일때 0인자열로 생각하는 문제점이 있음.
+ testIntString(2, null);
+ }
+
+ private void testIntString(int intValue, String stringValue) {
+ AnnotationTranscoder transcoder = new AnnotationTranscoder();
+ TIntStringValue tIntStringValue = new TIntStringValue(intValue);
+ tIntStringValue.setStringValue(stringValue);
+ byte[] encode = transcoder.encode(tIntStringValue, AnnotationTranscoder.CODE_INT_STRING);
+ IntStringValue decode = (IntStringValue) transcoder.decode(AnnotationTranscoder.CODE_INT_STRING, encode);
+ Assert.assertEquals(tIntStringValue.getIntValue(), decode.getIntValue());
+ Assert.assertEquals(tIntStringValue.getStringValue(), decode.getStringValue());
+ }
+
+ private void write(int value) throws TException {
+ TCompactProtocol.Factory factory = new TCompactProtocol.Factory();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(16);
+ TIOStreamTransport transport = new TIOStreamTransport(baos);
+ TProtocol protocol = factory.getProtocol(transport);
+
+ protocol.writeI32(value);
+ byte[] buffer = baos.toByteArray();
+ logger.info(Arrays.toString(buffer));
+ }
+
+ @Test
+ public void testEncode() throws Exception {
+
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/ApiDescriptionParserTest.java b/src/test/java/com/nhn/pinpoint/common/util/ApiDescriptionParserTest.java
new file mode 100644
index 000000000..4a7184247
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/ApiDescriptionParserTest.java
@@ -0,0 +1,75 @@
+package com.nhn.pinpoint.common.util;
+
+
+import org.junit.Assert;
+import org.junit.Test;
+
+
+/**
+ * @author emeroad
+ */
+public class ApiDescriptionParserTest {
+ private ApiDescriptionParser apiParser = new ApiDescriptionParser();
+
+ @Test
+ public void parse() {
+// org.springframework.web.servlet.FrameworkServlet.doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
+// com.mysql.jdbc.ConnectionImpl.setAutoCommit(boolean autoCommitFlag)
+// com.mysql.jdbc.ConnectionImpl.commit()
+// org.apache.catalina.core.StandardHostValve.invoke(org.apache.catalina.connector.Request request, org.apache.catalina.connector.Response response):110
+ String api = "a.StandardHostValve.invoke(b.Request request, b.Response response)";
+ ApiDescription result = apiParser.parse(api);
+
+ Assert.assertEquals("a.StandardHostValve", result.getClassName());
+ Assert.assertEquals("StandardHostValve", result.getSimpleClassName());
+ Assert.assertEquals("a", result.getPackageNameName());
+
+ Assert.assertEquals("invoke", result.getMethodName());
+
+ Assert.assertEquals("invoke(Request request, Response response)", result.getSimpleMethodDescription());
+ Assert.assertEquals("StandardHostValve", result.getSimpleClassName());
+
+ Assert.assertArrayEquals(new String[]{"Request request", "Response response"}, result.getSimpleParameter());
+ }
+
+
+ @Test
+ public void parseNoArgs() {
+ String api = "a.StandardHostValve.invoke()";
+ ApiDescription result = apiParser.parse(api);
+
+ Assert.assertEquals("a.StandardHostValve", result.getClassName());
+ Assert.assertEquals("StandardHostValve", result.getSimpleClassName());
+ Assert.assertEquals("a", result.getPackageNameName());
+
+ Assert.assertEquals("invoke", result.getMethodName());
+
+ Assert.assertEquals("invoke()", result.getSimpleMethodDescription());
+ Assert.assertEquals("StandardHostValve", result.getSimpleClassName());
+
+ Assert.assertArrayEquals(new String[]{}, result.getSimpleParameter());
+ }
+
+
+ @Test
+ public void parseNoPackage() {
+
+ String api = "StandardHostValve.invoke(Request request, Response response)";
+ ApiDescription result = apiParser.parse(api);
+
+ Assert.assertEquals("StandardHostValve", result.getClassName());
+ Assert.assertEquals("StandardHostValve", result.getSimpleClassName());
+ Assert.assertEquals("", result.getPackageNameName());
+
+ Assert.assertEquals("invoke", result.getMethodName());
+
+ Assert.assertEquals("invoke(Request request, Response response)", result.getSimpleMethodDescription());
+ Assert.assertEquals("StandardHostValve", result.getSimpleClassName());
+
+ Assert.assertArrayEquals(new String[]{"Request request", "Response response"}, result.getSimpleParameter());
+
+ }
+
+
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/ApplicationMapStatisticsUtilsTest.java b/src/test/java/com/nhn/pinpoint/common/util/ApplicationMapStatisticsUtilsTest.java
new file mode 100644
index 000000000..5dff69f5e
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/ApplicationMapStatisticsUtilsTest.java
@@ -0,0 +1,20 @@
+package com.nhn.pinpoint.common.util;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class ApplicationMapStatisticsUtilsTest {
+
+ @Test
+ public void makeRowKey() {
+ String applicationName = "TESTAPP";
+ short serviceType = 123;
+ long time = System.currentTimeMillis();
+
+ byte[] bytes = ApplicationMapStatisticsUtils.makeRowKey(applicationName, serviceType, time);
+
+ Assert.assertEquals(applicationName, ApplicationMapStatisticsUtils.getApplicationNameFromRowKey(bytes));
+ Assert.assertEquals(serviceType, ApplicationMapStatisticsUtils.getApplicationTypeFromRowKey(bytes));
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/ByteSizeTest.java b/src/test/java/com/nhn/pinpoint/common/util/ByteSizeTest.java
new file mode 100644
index 000000000..1abe69d06
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/ByteSizeTest.java
@@ -0,0 +1,36 @@
+package com.nhn.pinpoint.common.util;
+
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.transport.TIOStreamTransport;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *
+ */
+public class ByteSizeTest {
+ @Test
+ public void test() throws TException {
+ TCompactProtocol.Factory factory = new TCompactProtocol.Factory();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(16);
+ TIOStreamTransport transport = new TIOStreamTransport(baos);
+ TProtocol protocol = factory.getProtocol(transport);
+
+ long l = TimeUnit.DAYS.toMillis(1);
+ System.out.println("day:" + l);
+ long currentTime = System.currentTimeMillis();
+ System.out.println("currentTime:" + currentTime);
+ protocol.writeI64(l);
+ byte[] buffer = baos.toByteArray();
+ System.out.println(buffer.length);
+
+ }
+
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/BytesUtilsTest.java b/src/test/java/com/nhn/pinpoint/common/util/BytesUtilsTest.java
new file mode 100644
index 000000000..c09d78f28
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/BytesUtilsTest.java
@@ -0,0 +1,187 @@
+package com.nhn.pinpoint.common.util;
+
+import java.util.Arrays;
+import java.util.UUID;
+
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.transport.TMemoryBuffer;
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class BytesUtilsTest {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Test
+ public void testLongLongToBytes() throws Exception {
+ long most = Long.MAX_VALUE;
+ long least = Long.MAX_VALUE - 1;
+
+ test(most, least);
+
+ UUID uuid = UUID.randomUUID();
+ test(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
+ }
+
+ @Test
+ public void testStringLongLongToBytes() throws Exception {
+ BytesUtils.stringLongLongToBytes("123", 3, 1, 2);
+ try {
+ BytesUtils.stringLongLongToBytes("123", 2, 1, 2);
+ Assert.fail();
+ } catch (Exception e) {
+ }
+ }
+
+ @Test
+ public void testStringLongLongToBytes2() throws Exception {
+ byte[] bytes = BytesUtils.stringLongLongToBytes("123", 10, 1, 2);
+ String s = BytesUtils.toStringAndRightTrim(bytes, 0, 10);
+ Assert.assertEquals("123", s);
+ long l = BytesUtils.bytesToLong(bytes, 10);
+ Assert.assertEquals(l, 1);
+ long l2 = BytesUtils.bytesToLong(bytes, 10 + BytesUtils.LONG_BYTE_LENGTH);
+ Assert.assertEquals(l2, 2);
+ }
+
+ @Test
+ public void testRightTrim() throws Exception {
+ String trim = BytesUtils.trimRight("test ");
+ Assert.assertEquals("test", trim);
+
+ String trim1 = BytesUtils.trimRight("test");
+ Assert.assertEquals("test", trim1);
+
+ String trim2 = BytesUtils.trimRight(" test");
+ Assert.assertEquals(" test", trim2);
+
+ }
+
+
+ @Test
+ public void testInt() {
+ int i = Integer.MAX_VALUE - 5;
+ checkInt(i);
+ checkInt(23464);
+ }
+
+ private void checkInt(int i) {
+ byte[] bytes = Bytes.toBytes(i);
+ int i2 = BytesUtils.bytesToInt(bytes, 0);
+ Assert.assertEquals(i, i2);
+ int i3 = Bytes.toInt(bytes);
+ Assert.assertEquals(i, i3);
+ }
+
+ private void test(long most, long least) {
+ byte[] bytes1 = Bytes.toBytes(most);
+ byte[] bytes2 = Bytes.toBytes(least);
+ byte[] add = Bytes.add(bytes1, bytes2);
+ byte[] bytes = BytesUtils.longLongToBytes(most, least);
+ Assert.assertArrayEquals(add, bytes);
+
+
+ long[] longLong = BytesUtils.bytesToLongLong(bytes);
+ Assert.assertEquals(most, longLong[0]);
+ Assert.assertEquals(least, longLong[1]);
+
+
+ long bMost = BytesUtils.bytesToLong(bytes, 0);
+ long bLeast = BytesUtils.bytesToLong(bytes, 8);
+ Assert.assertEquals(most, bMost);
+ Assert.assertEquals(least, bLeast);
+
+ byte bBytes[] = new byte[16];
+ BytesUtils.writeLong(most, bBytes, 0);
+ BytesUtils.writeLong(least, bBytes, 8);
+ Assert.assertArrayEquals(add, bBytes);
+ }
+
+ @Test
+ public void testAddStringLong() throws Exception {
+ byte[] testAgents = BytesUtils.add("testAgent", 11L);
+ byte[] buf = Bytes.add(Bytes.toBytes("testAgent"), Bytes.toBytes(11L));
+ Assert.assertArrayEquals(testAgents, buf);
+ }
+
+ @Test
+ public void testAddStringLong_NullError() throws Exception {
+ try {
+ BytesUtils.add((String)null, 11L);
+ Assert.fail();
+ } catch (Exception e) {
+ }
+ }
+
+ @Test
+ public void testToFixedLengthBytes() {
+ byte[] testValue = BytesUtils.toFixedLengthBytes("test", 10);
+ Assert.assertEquals(testValue.length, 10);
+ Assert.assertEquals(testValue[5], 0);
+
+ try {
+ BytesUtils.toFixedLengthBytes("test", 2);
+ Assert.fail();
+ } catch (Exception e) {
+ }
+
+ try {
+ BytesUtils.toFixedLengthBytes("test", -1);
+ Assert.fail();
+ } catch (Exception e) {
+ }
+
+ byte[] testValue2 = BytesUtils.toFixedLengthBytes(null, 10);
+ Assert.assertEquals(testValue2.length, 10);
+
+ }
+
+ @Test
+ public void testMerge() {
+ byte[] b1 = new byte[] { 1, 2 };
+ byte[] b2 = new byte[] { 3, 4 };
+
+ byte[] b3 = BytesUtils.merge(b1, b2);
+
+ Assert.assertTrue(Arrays.equals(new byte[] { 1, 2, 3, 4 }, b3));
+ }
+
+ @Test
+ public void testZigZag() throws Exception {
+ testEncodingDecodingZigZag(0);
+ testEncodingDecodingZigZag(1);
+ testEncodingDecodingZigZag(2);
+ testEncodingDecodingZigZag(3);
+ }
+
+
+ private void testEncodingDecodingZigZag(int value) {
+ int encode = BytesUtils.intToZigZag(value);
+ int decode = BytesUtils.zigzagToInt(encode);
+ Assert.assertEquals(value, decode);
+ }
+
+
+ @Test
+ public void compactProtocolVint() throws TException {
+ TMemoryBuffer tMemoryBuffer = writeVInt32(BytesUtils.zigzagToInt(64));
+ logger.debug("length:{}", tMemoryBuffer.length());
+
+ TMemoryBuffer tMemoryBuffer2 = writeVInt32(64);
+ logger.debug("length:{}", tMemoryBuffer2.length());
+
+ }
+
+ private TMemoryBuffer writeVInt32(int i) throws TException {
+ TMemoryBuffer tMemoryBuffer = new TMemoryBuffer(10);
+ TCompactProtocol tCompactProtocol = new TCompactProtocol(tMemoryBuffer);
+ tCompactProtocol.writeI32(i);
+ return tMemoryBuffer;
+ }
+
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/HashCodeTest.java b/src/test/java/com/nhn/pinpoint/common/util/HashCodeTest.java
new file mode 100644
index 000000000..900e844de
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/HashCodeTest.java
@@ -0,0 +1,121 @@
+package com.nhn.pinpoint.common.util;
+
+import org.junit.Test;
+
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * test를 위해 hashcode를 찾을때 돌려볼수 있는 코드
+ */
+public class HashCodeTest {
+ // @Test
+ public void test2() throws InterruptedException {
+// "test"
+// "tetU"
+// "uGTt"
+// System.out.println((int)'A');
+// System.out.println((int)'Z');
+ System.out.println("test".hashCode());
+ System.out.println("tfUU".hashCode());
+ String a = "23 123";
+ System.out.println(a.hashCode());
+ System.out.println("test:" + a.hashCode());
+ final int hashCode = a.hashCode();
+ final ExecutorService es = Executors.newFixedThreadPool(4);
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ execute(hashCode);
+ }
+ };
+ es.execute(runnable);
+ es.execute(runnable);
+ es.execute(runnable);
+ es.execute(runnable);
+ es.awaitTermination(1, TimeUnit.HOURS);
+// execute(hashCode, random);
+// test
+// -1757224452
+
+
+ }
+
+ private void execute(int hashCode) {
+ Random random = new Random();
+ while (true) {
+ int i = random.nextInt(30);
+// System.out.println(i);
+ StringBuilder sb = new StringBuilder();
+// sb.append("12 ");
+ for (int j = 0; j < i; j++) {
+ char c = get(random);
+ sb.append(c);
+ }
+ sb.append(" 7");
+ String s = sb.toString();
+// System.out.println(s.hashCode());
+// System.out.println(s);
+ if (hashCode == s.hashCode()) {
+// if(a.equals(s)) {
+// continue;
+// }
+ System.out.println("find!!! equals:" + s);
+ break;
+ }
+ }
+ }
+
+ // @Test
+ public void test() {
+// "test"
+// "tetU"
+// "uGTt"
+// System.out.println((int)'A');
+// System.out.println((int)'Z');
+ String a = "test";
+ System.out.println("test:" + a.hashCode());
+ int hashCode = a.hashCode();
+ Random random = new Random();
+ while (true) {
+ int i = random.nextInt(50);
+// System.out.println(i);
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < i; j++) {
+ char c = get(random);
+ sb.append(c);
+ }
+ String s = sb.toString();
+// System.out.println(s);
+ if (hashCode == s.hashCode()) {
+ if ("test".equals(s)) {
+ continue;
+ }
+ System.out.println("equals:" + s);
+ break;
+ }
+ }
+// test
+// -1757224452
+ }
+
+ char get(Random rand) {
+// 65->90 : 25
+// 97->122; 25
+ int choice = (char) rand.nextInt(2);
+ char ch;
+ if (choice == 0) {
+ ch = (char) ((rand.nextInt(25)) + 97);
+ } else {
+ ch = (char) ((rand.nextInt(25)) + 65);
+ }
+
+ while (true) {
+ if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {
+ return ch;
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/HttpUtilsTest.java b/src/test/java/com/nhn/pinpoint/common/util/HttpUtilsTest.java
new file mode 100644
index 000000000..93a04330c
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/HttpUtilsTest.java
@@ -0,0 +1,39 @@
+package com.nhn.pinpoint.common.util;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+public class HttpUtilsTest {
+ @Test
+ public void contentTypeCharset1() {
+ String test = "text/plain; charset=UTF-8";
+
+ String charset = HttpUtils.parseContentTypeCharset(test);
+ Assert.assertEquals("UTF-8", charset);
+ }
+
+ @Test
+ public void contentTypeCharset2() {
+ String test = "text/plain; charset=UTF-8;";
+
+ String charset = HttpUtils.parseContentTypeCharset(test);
+ Assert.assertEquals("UTF-8", charset);
+ }
+
+ @Test
+ public void contentTypeCharset3() {
+ String test = "text/plain; charset=UTF-8; test=a";
+
+ String charset = HttpUtils.parseContentTypeCharset(test);
+ Assert.assertEquals("UTF-8", charset);
+ }
+
+ @Test
+ public void contentTypeCharset4() {
+ String test = "text/plain; charset= UTF-8 ; test=a";
+
+ String charset = HttpUtils.parseContentTypeCharset(test);
+ Assert.assertEquals("UTF-8", charset);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/nhn/pinpoint/common/util/InetAddressUtilsTest.java b/src/test/java/com/nhn/pinpoint/common/util/InetAddressUtilsTest.java
new file mode 100644
index 000000000..42da6f270
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/InetAddressUtilsTest.java
@@ -0,0 +1,22 @@
+package com.nhn.pinpoint.common.util;
+
+import org.junit.Test;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ *
+ */
+public class InetAddressUtilsTest {
+ @Test
+ public void test() throws UnknownHostException {
+ InetAddress byName = InetAddress.getByName("0:0:0:0:0:0:0:1");
+
+ System.out.println(byName);
+ System.out.println(byName.getAddress().length);
+
+ InetAddress ipv4= InetAddress.getByName("127.0.0.1");
+ System.out.println(ipv4);
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/MathUtilsTest.java b/src/test/java/com/nhn/pinpoint/common/util/MathUtilsTest.java
new file mode 100644
index 000000000..d66113d9f
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/MathUtilsTest.java
@@ -0,0 +1,47 @@
+package com.nhn.pinpoint.common.util;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author emeroad
+ */
+public class MathUtilsTest {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Test
+ public void fastAbs() {
+ Assert.assertTrue(MathUtils.fastAbs(-1) > 0);
+ Assert.assertTrue(MathUtils.fastAbs(0) == 0);
+ Assert.assertTrue(MathUtils.fastAbs(1) > 0);
+ }
+
+
+ @Test
+ public void overflow() {
+
+
+ logger.debug("abs:{}", Math.abs(Integer.MIN_VALUE));
+ logger.debug("fastabs:{}", MathUtils.fastAbs(Integer.MIN_VALUE));
+
+ int index = Integer.MIN_VALUE -2;
+ for(int i =0; i<5; i++) {
+ logger.debug("{}------------", i);
+ logger.debug("{}", index);
+ logger.debug("mod:{}", index % 3);
+ logger.debug("abs:{}", Math.abs(index));
+ logger.debug("fastabs:{}", MathUtils.fastAbs(index));
+
+ index++;
+ }
+
+
+
+ }
+
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/OutputParameterParserTest.java b/src/test/java/com/nhn/pinpoint/common/util/OutputParameterParserTest.java
new file mode 100644
index 000000000..c3fbe0674
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/OutputParameterParserTest.java
@@ -0,0 +1,45 @@
+package com.nhn.pinpoint.common.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * @author emeroad
+ */
+public class OutputParameterParserTest {
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private final OutputParameterParser parser = new OutputParameterParser();
+
+ @Test
+ public void testParseOutputParameter() throws Exception {
+ assertOutputParameter("12,34", "12", "34");
+ assertOutputParameter("12,,34", "12,34");
+
+ assertOutputParameter("12,,", "12,");
+
+ assertOutputParameter("12,,34,123", "12,34", "123");
+
+ assertOutputParameter("12,", "12", "");
+
+ assertOutputParameter("");
+
+ }
+
+ private void assertOutputParameter(String outputParam, String... params) {
+ List result = parser.parseOutputParameter(outputParam);
+ logger.info("parseResult:{}", result);
+ try {
+ Assert.assertArrayEquals(result.toArray(new String[result.size()]), params);
+ } catch (AssertionError e) {
+ logger.warn("parseResult:{}", result);
+ logger.warn("params:{}", params);
+ throw e;
+ }
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/PinpointThreadFactoryTest.java b/src/test/java/com/nhn/pinpoint/common/util/PinpointThreadFactoryTest.java
new file mode 100644
index 000000000..2b8cd34aa
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/PinpointThreadFactoryTest.java
@@ -0,0 +1,43 @@
+package com.nhn.pinpoint.common.util;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author emeroad
+ */
+public class PinpointThreadFactoryTest {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ @Test
+ public void testCreateThreadFactory() throws Exception {
+ final AtomicInteger test = new AtomicInteger(0);
+
+ PinpointThreadFactory pinpoint = new PinpointThreadFactory("pinpoint");
+ Thread thread = pinpoint.newThread(new Runnable() {
+ @Override
+ public void run() {
+ test.getAndIncrement();
+ }
+ });
+ thread.start();
+ thread.join();
+ Assert.assertEquals(test.get(), 1);
+ String threadName = thread.getName();
+ logger.info(threadName);
+ Assert.assertTrue(threadName.startsWith("pinpoint("));
+ Assert.assertTrue(threadName.endsWith(")"));
+
+ Thread thread2 = pinpoint.newThread(new Runnable() {
+ @Override
+ public void run() {
+ }
+ });
+ logger.info(thread2.getName());
+
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/RowKeyUtilsTest.java b/src/test/java/com/nhn/pinpoint/common/util/RowKeyUtilsTest.java
new file mode 100644
index 000000000..94227c761
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/RowKeyUtilsTest.java
@@ -0,0 +1,25 @@
+package com.nhn.pinpoint.common.util;
+
+import com.nhn.pinpoint.common.bo.SqlMetaDataBo;
+import junit.framework.Assert;
+import org.junit.Test;
+
+/**
+ * @author emeroad
+ */
+public class RowKeyUtilsTest {
+ @Test
+ public void testGetSqlId() throws Exception {
+ long startTime = System.currentTimeMillis();
+ SqlMetaDataBo sqlMetaDataBo = new SqlMetaDataBo("agent", startTime, 1);
+ byte[] agents = sqlMetaDataBo.toRowKey();
+
+
+ SqlMetaDataBo sqlId = new SqlMetaDataBo();
+ sqlId.readRowKey(agents);
+
+ Assert.assertEquals(sqlId.getAgentId(), "agent");
+ Assert.assertEquals(sqlId.getHashCode(), 1);
+ Assert.assertEquals(sqlId.getStartTime(), startTime);
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/RpcCodeRangeTest.java b/src/test/java/com/nhn/pinpoint/common/util/RpcCodeRangeTest.java
new file mode 100644
index 000000000..354e46921
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/RpcCodeRangeTest.java
@@ -0,0 +1,17 @@
+package com.nhn.pinpoint.common.util;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class RpcCodeRangeTest {
+
+ @Test
+ public void testIsRpcRange() throws Exception {
+ Assert.assertTrue(RpcCodeRange.isRpcRange(RpcCodeRange.RPC_START));
+ Assert.assertTrue(RpcCodeRange.isRpcRange((short) (RpcCodeRange.RPC_END - 1)));
+ Assert.assertFalse(RpcCodeRange.isRpcRange((short) 1));
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/nhn/pinpoint/common/util/SpanUtilsTest.java b/src/test/java/com/nhn/pinpoint/common/util/SpanUtilsTest.java
new file mode 100644
index 000000000..47d6b5b33
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/SpanUtilsTest.java
@@ -0,0 +1,67 @@
+package com.nhn.pinpoint.common.util;
+
+import com.nhn.pinpoint.common.PinpointConstants;
+import com.nhn.pinpoint.thrift.dto.TSpan;
+
+import junit.framework.Assert;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.Test;
+
+/**
+ * @author emeroad
+ */
+public class SpanUtilsTest {
+ @Test
+ public void testGetTraceIndexRowKeyWhiteSpace() throws Exception {
+ String agentId = "test test";
+ long time = System.currentTimeMillis();
+ check(agentId, time);
+ }
+
+ @Test
+ public void testGetTraceIndexRowKey1() throws Exception {
+ String agentId = "test";
+ long time = System.currentTimeMillis();
+ check(agentId, time);
+ }
+
+ @Test
+ public void testGetTraceIndexRowKey2() throws Exception {
+ String agentId = "";
+ for (int i = 0; i < PinpointConstants.AGENT_NAME_MAX_LEN; i++) {
+ agentId += "1";
+ }
+
+ long time = System.currentTimeMillis();
+ check(agentId, time);
+ }
+
+ @Test
+ public void testGetTraceIndexRowKey3() throws Exception {
+ String agentId = "";
+ for (int i = 0; i < PinpointConstants.AGENT_NAME_MAX_LEN + 1; i++) {
+ agentId += "1";
+ }
+
+ long time = System.currentTimeMillis();
+ try {
+ check(agentId, time);
+ Assert.fail();
+ } catch (Exception e) {
+ }
+ }
+
+ private void check(String agentId0, long l1) {
+ TSpan span = new TSpan();
+ span.setAgentId(agentId0);
+ span.setStartTime(l1);
+
+ byte[] traceIndexRowKey = SpanUtils.getAgentIdTraceIndexRowKey(span.getAgentId(), span.getStartTime());
+
+ String agentId = Bytes.toString(traceIndexRowKey, 0, PinpointConstants.AGENT_NAME_MAX_LEN).trim();
+ Assert.assertEquals(agentId0, agentId);
+
+ long time = TimeUtils.recoveryTimeMillis(Bytes.toLong(traceIndexRowKey, PinpointConstants.AGENT_NAME_MAX_LEN));
+ Assert.assertEquals(time, l1);
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/SqlParserTest.java b/src/test/java/com/nhn/pinpoint/common/util/SqlParserTest.java
new file mode 100644
index 000000000..c75bb9e16
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/SqlParserTest.java
@@ -0,0 +1,305 @@
+package com.nhn.pinpoint.common.util;
+
+import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * @author emeroad
+ */
+public class SqlParserTest {
+ private SqlParser sqlParser = new SqlParser();
+ private OutputParameterParser outputParameterParser = new OutputParameterParser();
+
+ @Test
+ public void normalizedSql() {
+
+ ParsingResult parsingResult = sqlParser.normalizedSql("select * from table a = 1 and b=50 and c=? and d='11'");
+ String s = parsingResult.getSql();
+
+ System.out.println(s);
+ System.out.println(parsingResult.getOutput());
+
+ ParsingResult parsingResult2 = sqlParser.normalizedSql(" ");
+ String s2 = parsingResult2.getSql();
+ System.out.println(s2);
+
+ System.out.println((char) -1);
+ String str = "s";
+ System.out.println(str.codePointAt(0));
+ System.out.println((int) str.charAt(0));
+ System.out.println("high" + (char) Character.MAX_HIGH_SURROGATE);
+ System.out.println("low" + (char) Character.MIN_LOW_SURROGATE);
+
+ System.out.println((int) Character.MIN_LOW_SURROGATE);
+ System.out.println((int) Character.MAX_HIGH_SURROGATE);
+
+ ParsingResult parsingResult3 = sqlParser.normalizedSql("''");
+ String s3 = parsingResult3.getSql();
+ System.out.println("s3:" + s3);
+ System.out.println("sb3:" + parsingResult3.getOutput());
+ }
+
+ @Test
+ public void nullCheck() {
+ sqlParser.normalizedSql(null);
+ }
+
+ @Test
+ public void complex() {
+
+ assertEqual("select * from table a = 1 and b=50 and c=? and d='11'",
+ "select * from table a = 0# and b=1# and c=? and d='2$'", "1,50,11");
+
+ assertEqual("select * from table a = -1 and b=-50 and c=? and d='-11'",
+ "select * from table a = -0# and b=-1# and c=? and d='2$'", "1,50,-11");
+
+ assertEqual("select * from table a = +1 and b=+50 and c=? and d='+11'",
+ "select * from table a = +0# and b=+1# and c=? and d='2$'", "1,50,+11");
+
+ assertEqual("select * from table a = 1/*test*/ and b=50/*test*/ and c=? and d='11'",
+ "select * from table a = 0#/*test*/ and b=1#/*test*/ and c=? and d='2$'", "1,50,11");
+
+ assertEqual("select ZIPCODE,CITY from ZIPCODE");
+ assertEqual("select a.ZIPCODE,a.CITY from ZIPCODE as a");
+ assertEqual("select ZIPCODE,123 from ZIPCODE",
+ "select ZIPCODE,0# from ZIPCODE", "123");
+
+ assertEqual("SELECT * from table a=123 and b='abc' and c=1-3",
+ "SELECT * from table a=0# and b='1$' and c=2#-3#", "123,abc,1,3");
+
+ assertEqual("SYSTEM_RANGE(1, 10)",
+ "SYSTEM_RANGE(0#, 1#)", "1,10");
+
+ }
+
+ @Test
+ public void etcState() {
+
+ assertEqual("test.abc", "test.abc", "");
+ assertEqual("test.abc123", "test.abc123", "");
+ assertEqual("test.123", "test.123", "");
+
+ }
+
+ @Test
+ public void objectEquals() {
+
+ assertEqualObject("test.abc");
+ assertEqualObject("test.abc123");
+ assertEqualObject("test.123");
+
+ }
+
+
+ @Test
+ public void numberState() {
+ assertEqual("123", "0#", "123");
+ // -가 진짜 숫자의 -인지 알려면 구문분석이 필요하므로 그냥 숫자만 치환한다.
+ assertEqual("-123", "-0#", "123");
+ assertEqual("+123", "+0#", "123");
+ assertEqual("1.23", "0#", "1.23");
+ assertEqual("1.23.34", "0#", "1.23.34");
+ assertEqual("123 456", "0# 1#", "123,456");
+ assertEqual("1.23 4.56", "0# 1#", "1.23,4.56");
+ assertEqual("1.23-4.56", "0#-1#", "1.23,4.56");
+
+ assertEqual("1<2", "0#<1#", "1,2");
+ assertEqual("1< 2", "0#< 1#", "1,2");
+ assertEqual("(1< 2)", "(0#< 1#)", "1,2");
+
+ assertEqual("-- 1.23", "-- 1.23", "");
+ assertEqual("- -1.23", "- -0#", "1.23");
+ assertEqual("--1.23", "--1.23", "");
+ assertEqual("/* 1.23 */", "/* 1.23 */", "");
+ assertEqual("/*1.23*/", "/*1.23*/", "");
+ assertEqual("/* 1.23 \n*/", "/* 1.23 \n*/", "");
+
+ assertEqual("test123", "test123", "");
+ assertEqual("test_123", "test_123", "");
+ assertEqual("test_ 123", "test_ 0#", "123");
+
+ // 사실 이건 불가능한 토큰임.
+ assertEqual("123tst", "0#tst", "123");
+ }
+
+ @Test
+ public void numberState2() {
+ assertEqual("1.23e", "0#", "1.23e");
+ assertEqual("1.23E", "0#", "1.23E");
+ // -가 진짜 숫자의 -인지 알려면 구문분석이 필요하므로 그냥 숫자만 치환한다.
+ assertEqual("1.4e-10", "0#-1#", "1.4e,10");
+
+ }
+
+
+ @Test
+ public void singleLineCommentState() {
+ assertEqual("--", "--", "");
+ assertEqual("//", "//", "");
+ assertEqual("--123", "--123", "");
+ assertEqual("//123", "//123", "");
+ assertEqual("--test", "--test");
+ assertEqual("//test", "//test");
+ assertEqual("--test\ntest", "--test\ntest", "");
+ assertEqual("--test\t\n", "--test\t\n", "");
+ assertEqual("--test\n123 test", "--test\n0# test", "123");
+ }
+
+
+ @Test
+ public void multiLineCommentState() {
+ assertEqual("/**/", "/**/", "");
+ assertEqual("/* */", "/* */", "");
+ assertEqual("/* */abc", "/* */abc", "");
+ assertEqual("/* * */", "/* * */", "");
+ assertEqual("/* * */", "/* * */", "");
+
+ assertEqual("/* abc", "/* abc", "");
+
+ assertEqual("select * from table", "select * from table", "");
+ }
+
+ @Test
+ public void symbolState() {
+ assertEqual("''", "''", "");
+ assertEqual("'abc'", "'0$'", "abc");
+ assertEqual("'a''bc'", "'0$'", "a''bc");
+ assertEqual("'a' 'bc'", "'0$' '1$'", "a,bc");
+
+ assertEqual("'a''bc' 'a''bc'", "'0$' '1$'", "a''bc,a''bc");
+
+
+ assertEqual("select * from table where a='a'", "select * from table where a='0$'", "a");
+ }
+
+ // @Test
+ public void charout() {
+ for (int i = 11; i < 67; i++) {
+ System.out.println((char) i);
+ }
+ }
+
+ @Test
+ public void commentAndSymbolCombine() {
+ assertEqual("/* 'test' */", "/* 'test' */", "");
+ assertEqual("/* 'test'' */", "/* 'test'' */", "");
+ assertEqual("/* '' */", "/* '' */");
+
+ assertEqual("/* */ 123 */", "/* */ 0# */", "123");
+
+ assertEqual("' /* */'", "'0$'", " /* */");
+
+ }
+
+ @Test
+ public void sepratorTest() {
+
+ assertEqual("1234 456,7", "0# 1#,2#", "1234,456,7");
+
+ assertEqual("'1234 456,7'", "'0$'", "1234 456,,7");
+
+ assertEqual("'1234''456,7'", "'0$'", "1234''456,,7");
+ ParsingResult parsingResult2 = this.sqlParser.normalizedSql("'1234''456,7'");
+ System.out.println(parsingResult2);
+ // 문자열 토큰
+
+
+ assertEqual("'1234' '456,7'", "'0$' '1$'", "1234,456,,7");
+ }
+
+
+ @Test
+ public void combineTest() {
+ assertCombine("123 345", "0# 1#", "123,345");
+ assertCombine("123 345 'test'", "0# 1# '2$'", "123,345,test");
+ assertCombine("1 2 3 4 5 6 7 8 9 10 11", "0# 1# 2# 3# 4# 5# 6# 7# 8# 9# 10#", "1,2,3,4,5,6,7,8,9,10,11");
+ }
+
+ @Test
+ public void combineErrorTest() {
+ assertCombineErrorCase("123 10#", "0# 10#", "123,345");
+
+ assertCombineErrorCase("1 3 10#", "0# 2# 10#", "1,2,3");
+
+ assertCombineErrorCase("1 2 3", "0# 2 3", "1,2,3");
+ assertCombineErrorCase("1 2 10", "0# 2 10", "1,2,3");
+ assertCombineErrorCase("1 2 201", "0# 2 201", "1,2,3");
+
+ assertCombineErrorCase("1 2 11", "0# 2 10#", "1,2,3,4,5,6,7,8,9,10,11");
+
+ }
+
+ private void assertCombine(String result, String sql, String outputParams) {
+ List output = this.outputParameterParser.parseOutputParameter(outputParams);
+
+ ParsingResult parsingResult = this.sqlParser.normalizedSql(result);
+ Assert.assertEquals("sql", parsingResult.getSql(), sql);
+ String combine = this.sqlParser.combineOutputParams(sql, output);
+ Assert.assertEquals("combine", result, combine);
+ }
+
+ private void assertCombineErrorCase(String expectedError, String sql, String outputParams) {
+ List output = this.outputParameterParser.parseOutputParameter(outputParams);
+// ParsingResult parsingResult = this.sqlParser.normalizedSql(result);
+ String combine = this.sqlParser.combineOutputParams(sql, output);
+ Assert.assertEquals("combine", expectedError, combine);
+ }
+
+
+ private void assertEqual(String expected) {
+ ParsingResult parsingResult = sqlParser.normalizedSql(expected);
+ String normalizedSql = parsingResult.getSql();
+ try {
+ Assert.assertEquals(expected, normalizedSql);
+ } catch (AssertionFailedError e) {
+ System.err.println("Original :" + expected);
+ throw e;
+ }
+ }
+
+ private void assertEqual(String expected, String actual) {
+ ParsingResult parsingResult = sqlParser.normalizedSql(expected);
+ String normalizedSql = parsingResult.getSql();
+ try {
+ Assert.assertEquals(actual, normalizedSql);
+ } catch (AssertionFailedError e) {
+ System.err.println("Original :" + expected);
+ throw e;
+ }
+ }
+
+ private void assertEqual(String expected, String actual, String ouputExpected) {
+ ParsingResult parsingResult = sqlParser.normalizedSql(expected);
+ String normalizedSql = parsingResult.getSql();
+ String output = parsingResult.getOutput();
+ List outputParams = outputParameterParser.parseOutputParameter(output);
+ String s = sqlParser.combineOutputParams(normalizedSql, outputParams);
+ System.out.println("combine:" + s);
+ try {
+ Assert.assertEquals("normalizedSql check", actual, normalizedSql);
+ } catch (AssertionFailedError e) {
+ System.err.println("Original :" + expected);
+ throw e;
+ }
+
+ Assert.assertEquals("outputParam check", ouputExpected, parsingResult.getOutput());
+ }
+
+ private void assertEqualObject(String expected) {
+ ParsingResult parsingResult = sqlParser.normalizedSql(expected);
+ String normalizedSql = parsingResult.getSql();
+ try {
+ Assert.assertEquals("normalizedSql check", expected, normalizedSql);
+ Assert.assertSame(expected, normalizedSql);
+ } catch (AssertionFailedError e) {
+ System.err.println("Original :" + expected);
+ throw e;
+ }
+
+ }
+
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/StringTraceHeaderParserTest.java b/src/test/java/com/nhn/pinpoint/common/util/StringTraceHeaderParserTest.java
new file mode 100644
index 000000000..acd12b145
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/StringTraceHeaderParserTest.java
@@ -0,0 +1,46 @@
+package com.nhn.pinpoint.common.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.UUID;
+
+/**
+ * @author emeroad
+ */
+public class StringTraceHeaderParserTest {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private StringTraceHeaderParser parser= new StringTraceHeaderParser();
+
+ @Test
+ public void getIdSize() {
+ String test = "3ccb94f3-a8fe-4464-bfbd-d35490afab3d";
+ logger.info("idSize={}", test.length());
+ }
+
+
+ @Test
+ public void createStringBaseTraceHeader() {
+ createAndParser(UUID.randomUUID().toString(), 123, 345, 23423, (short) 22);
+ createAndParser(UUID.randomUUID().toString(), -1, 2, 0, (short) 0);
+ createAndParser(UUID.randomUUID().toString(), 234, 2, 0, (short) 0);
+ }
+
+
+
+ private void createAndParser(String uuid, int spanId, int pSpanId, int sampling, short flag) {
+ String traceHeader = parser.createHeader(uuid, spanId, pSpanId, sampling, (short) flag);
+
+ TraceHeader header = parser.parseHeader(traceHeader);
+ Assert.assertEquals("id", uuid, header.getId());
+ Assert.assertEquals("spanId", String.valueOf(spanId), header.getSpanId());
+ Assert.assertEquals("pSpanId", String.valueOf(pSpanId), header.getParentSpanId());
+ Assert.assertEquals("sampling", String.valueOf(sampling), header.getSampling());
+ Assert.assertEquals("flag", String.valueOf(flag), header.getFlag());
+ logger.info("{}, parse:" + header);
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/TimeSlotTest.java b/src/test/java/com/nhn/pinpoint/common/util/TimeSlotTest.java
new file mode 100644
index 000000000..6a21aa378
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/TimeSlotTest.java
@@ -0,0 +1,53 @@
+package com.nhn.pinpoint.common.util;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class TimeSlotTest {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final TimeSlot timeSlot = new DefaultTimeSlot();
+
+ @Test
+ public void testGetTimeSlot() throws Exception {
+ long currentTime = System.currentTimeMillis();
+ // 슬롯 넘버를 알아온다.
+ long timeSlot = this.timeSlot.getTimeSlot(currentTime);
+
+ logger.info("{} currentTime ", currentTime);
+ logger.info("{} timeSlot", timeSlot);
+ Assert.assertTrue(currentTime >= timeSlot);
+ }
+
+ @Test
+ public void testSlotTime1() throws Exception {
+ int slotTest = 60 * 1000;
+
+ // 슬롯 넘버를 알아온다.
+ long timeSlot = this.timeSlot.getTimeSlot(slotTest);
+
+ logger.info("{} slotTest ", slotTest);
+ logger.info("{} timeSlot", timeSlot);
+ Assert.assertEquals(slotTest, timeSlot);
+ }
+
+ @Test
+ public void testSlotTime2() throws Exception {
+ int sourceTest = 60 * 1000;
+ int slotTest = sourceTest + 1;
+
+
+ // 슬롯 넘버를 알아온다.
+ long timeSlot = this.timeSlot.getTimeSlot(slotTest);
+
+ logger.info("{} slotTest ", slotTest);
+ logger.info("{} timeSlot", timeSlot);
+ Assert.assertEquals(sourceTest, timeSlot);
+ }
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/TimeUtilsTest.java b/src/test/java/com/nhn/pinpoint/common/util/TimeUtilsTest.java
new file mode 100644
index 000000000..af0ff83d2
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/TimeUtilsTest.java
@@ -0,0 +1,28 @@
+package com.nhn.pinpoint.common.util;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+/**
+ * @author emeroad
+ */
+public class TimeUtilsTest {
+ @Test
+ public void testReverseCurrentTimeMillis() throws Exception {
+ long currentTime = System.currentTimeMillis();
+ long reverseTime = TimeUtils.reverseTimeMillis(currentTime);
+ long recoveryTime = TimeUtils.recoveryTimeMillis(reverseTime);
+
+ Assert.assertEquals(currentTime, recoveryTime);
+ }
+
+ @Test
+ public void testTimeOrder() throws InterruptedException {
+ long l1 = TimeUtils.reverseCurrentTimeMillis();
+ Thread.sleep(5);
+ long l2 = TimeUtils.reverseCurrentTimeMillis();
+
+ Assert.assertTrue(l1 > l2);
+ }
+
+}
diff --git a/src/test/java/com/nhn/pinpoint/common/util/TransactionIdUtilsTest.java b/src/test/java/com/nhn/pinpoint/common/util/TransactionIdUtilsTest.java
new file mode 100644
index 000000000..f62de88a1
--- /dev/null
+++ b/src/test/java/com/nhn/pinpoint/common/util/TransactionIdUtilsTest.java
@@ -0,0 +1,47 @@
+package com.nhn.pinpoint.common.util;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+/**
+ * @author emeroad
+ */
+public class TransactionIdUtilsTest {
+ @Test
+ public void testParseTransactionId() {
+ TransactionId transactionId = TransactionIdUtils.parseTransactionId("test" + TransactionIdUtils.TRANSACTION_ID_DELIMITER + "1" + TransactionIdUtils.TRANSACTION_ID_DELIMITER + "2");
+ Assert.assertEquals(transactionId.getAgentId(), "test");
+ Assert.assertEquals(transactionId.getAgentStartTime(), 1L);
+ Assert.assertEquals(transactionId.getTransactionSequence(), 2L);
+ }
+
+ @Test
+ public void testParseTransactionId2() {
+ TransactionId transactionId = TransactionIdUtils.parseTransactionId("test" + TransactionIdUtils.TRANSACTION_ID_DELIMITER + "1" + TransactionIdUtils.TRANSACTION_ID_DELIMITER + "2" + TransactionIdUtils.TRANSACTION_ID_DELIMITER);
+ Assert.assertEquals(transactionId.getAgentId(), "test");
+ Assert.assertEquals(transactionId.getAgentStartTime(), 1L);
+ Assert.assertEquals(transactionId.getTransactionSequence(), 2L);
+ }
+
+
+ @Test
+ public void testParseTransactionIdByte() {
+ long time = System.currentTimeMillis();
+ byte[] bytes = TransactionIdUtils.formatBytes("test", time, 2);
+ TransactionId transactionId = TransactionIdUtils.parseTransactionId(bytes);
+ Assert.assertEquals(transactionId.getAgentId(), "test");
+ Assert.assertEquals(transactionId.getAgentStartTime(), time);
+ Assert.assertEquals(transactionId.getTransactionSequence(), 2L);
+ }
+
+ @Test
+ public void testParseTransactionIdByte_AgentIdisNull() {
+ long time = System.currentTimeMillis();
+ byte[] bytes = TransactionIdUtils.formatBytes(null, time, 1);
+ TransactionId transactionId = TransactionIdUtils.parseTransactionId(bytes);
+ Assert.assertEquals(transactionId.getAgentId(), null);
+ Assert.assertEquals(transactionId.getAgentStartTime(), time);
+ Assert.assertEquals(transactionId.getTransactionSequence(), 1L);
+ }
+
+}
diff --git a/src/test/resources/log4j.xml b/src/test/resources/log4j.xml
new file mode 100644
index 000000000..7067a1bb8
--- /dev/null
+++ b/src/test/resources/log4j.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/test-hbase.properties b/src/test/resources/test-hbase.properties
new file mode 100644
index 000000000..121a25f03
--- /dev/null
+++ b/src/test/resources/test-hbase.properties
@@ -0,0 +1,8 @@
+#hbase.client.host=localhost
+#hbase.client.host=10.64.84.188
+#dev-hippo002.ncl
+hbase.client.host=10.101.17.108
+
+hbase.client.port=2181
+
+hbase.htable.threads.max=32
\ No newline at end of file