## 설치 ("--enable-web-dashboard","false")
$ claude mcp add-json "serena" '{"command":"uvx","args":["--from","git+https://github.com/oraios/serena","serena-mcp-server","--enable-web-dashboard","false"]}'
## 삭제
$ claude mcp remove serena
## 설치 ("--enable-web-dashboard","false")
$ claude mcp add-json "serena" '{"command":"uvx","args":["--from","git+https://github.com/oraios/serena","serena-mcp-server","--enable-web-dashboard","false"]}'
## 삭제
$ claude mcp remove serena
// https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js
// https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/pbkdf2.js
var passphrase = "key...변경";
var iv = CryptoJS.lib.WordArray.random(128/8);
var key = CryptoJS.enc.Hex.parse(CryptoJS.SHA1(passphrase).toString().substring(0,32));
console.log("key: ", key)
var ct = CryptoJS.AES.encrypt(str, key, { iv: iv });
var enc = iv.concat(ct.ciphertext).toString();
console.log("enc: ", enc)
## enc: b3ff8dd004bb643f0aba857baccb0d45e1565d2f4a1d727c9a268580d3a2031b
console.log("Result: " + CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Hex.parse(enc.substring(32))
}, CryptoJS.enc.Hex.parse(CryptoJS.SHA1(passphrase).toString().substring(0,32)),
{
iv: CryptoJS.enc.Hex.parse(enc.substring(0,32)),
}).toString(CryptoJS.enc.Utf8));
## Result: abcd
enc = "B8160A9EDCA2CFECE3E6444BFDE09B780D8DD2D873B93080E7F5A6F4B5644217";
console.log("JAVA 에서 암호화한 문자열 복호화 Result: " + CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Hex.parse(enc.substring(32))
}, CryptoJS.enc.Hex.parse(CryptoJS.SHA1(passphrase).toString().substring(0,32)),
{
iv: CryptoJS.enc.Hex.parse(enc.substring(0,32)),
}).toString(CryptoJS.enc.Utf8));
## JAVA 에서 암호화한 문자열 복호화 Result: abcd
// com.google.guava:guava:29.0-jre
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.AlgorithmParameters;
import java.util.Arrays;
public class AesCryptUtil {
private static Logger logger = LoggerFactory.getLogger(AesCryptUtil.class);
public static String encryptAES(String data, String secretKey) {
try {
byte[] secretKeys = Arrays.copyOfRange(Hashing.sha1().hashString(secretKey, Charsets.UTF_8).asBytes(), 0, 16);
SecretKey secret = new SecretKeySpec(secretKeys, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] cipherText = cipher.doFinal(data.getBytes(Charsets.UTF_8));
return DatatypeConverter.printHexBinary(iv) + DatatypeConverter.printHexBinary(cipherText);
} catch (Exception e) {
logger.error("===== exception", e);
throw new RuntimeException(e);
}
}
public static String decryptAES(String data, String secretKey) {
try {
byte[] secretKeys = Arrays.copyOfRange(Hashing.sha1().hashString(secretKey, Charsets.UTF_8).asBytes(), 0, 16);
String hexedIv = data.substring(0, 32);
String hexedCipherText = data.substring(32);
byte[] iv = DatatypeConverter.parseHexBinary(hexedIv);
byte[] cipherText = DatatypeConverter.parseHexBinary(hexedCipherText);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKeys, "AES"), new IvParameterSpec(iv));
return new String(cipher.doFinal(cipherText), Charsets.UTF_8);
}catch (Exception e) {
logger.error("===== exception", e);
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
String key = "key...변경";
String abcd = AesCryptUtil.encryptAES("abcd", key);
System.out.println("enc: " + abcd);
System.out.println("dec: " + AesCryptUtil.decryptAES(abcd, key));
System.out.println("javascript 암호화한 문자열 복호화 dec: " + AesCryptUtil.decryptAES("b3ff8dd004bb643f0aba857baccb0d45e1565d2f4a1d727c9a268580d3a2031b", key));
}
}
[참고] https://stackoverflow.com/questions/37368710/decrypt-aes-cbc-pkcs5padding-with-cryptojs
Decrypt AES/CBC/PKCS5Padding with CryptoJS
I generate 128bit AES/CBC/PKCS5Padding key using Java javax.crypto API. Here is the algorithm that I use: public static String encryptAES(String data, String secretKey) { try { byte[]
stackoverflow.com
## HttpClient 4.x
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, (certificate, authType) -> true);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build(),
NoopHostnameVerifier.INSTANCE);
httpClientBuilder.setSSLSocketFactory(sslsf);


javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1564)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:347)
at UrlConTest.main(UrlConTest.java:15)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
at sun.security.validator.Validator.validate(Validator.java:262)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
... 14 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
... 20 more
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class TextTest {
public static void main(String[] args) {
Path path1 = Paths.get("test.log");
Path path2 = Paths.get("test.log-2");
try (Stream stream = Files.lines(path1)) {
Files.write(path2, (Iterable)stream.filter(s->s.trim().startsWith("{")).filter(s->s.trim().endsWith("}"))::iterator);
} catch (IOException e) {
e.printStackTrace();
}
}
}
json-lib, com.fasterxml.jackson 둘의 차이점을 비교해본다.
별다른 옵션 없는 심플한 상황이다.
json-lib의 경우 Object형의 NULL 변환에 문제가 있어보인다.
[JsonTest .java]
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
public class JsonTest {
@Test
public void test_jsonlib_BeanCase() {
try {
TestBean inBean = new TestBean();
inBean.setA("a Value");
inBean.setB("");
inBean.setC(null);
//inBean.setD();
inBean.setInt11(1);
//inBean.setInt12();
inBean.setInt21(1);
inBean.setInt21(null);
inBean.setBool11(true);
//inBean.setBool12();
inBean.setBool21(true);
inBean.setBool21(null);
JSONObject jsonObj = JSONObject.fromObject( JSONSerializer.toJSON(inBean) );
String jsonStr = jsonObj.toString();
System.out.println("jsonStr: " + jsonStr);
jsonObj = (JSONObject) JSONObject.fromObject(jsonStr);
TestBean outBean = (TestBean) JSONObject.toBean(jsonObj, TestBean.class);
System.out.println(outBean);
assertEquals(inBean.getA(), outBean.getA());
assertEquals(inBean.getB(), outBean.getB());
//assertEquals(inBean.getC(), outBean.getC()); // 문제 소지
//assertEquals(inBean.getD(), outBean.getD()); // 문제 소지
assertEquals(outBean.getC(), "");
assertEquals(outBean.getD(), "");
assertEquals(inBean.getInt11(), outBean.getInt11());
assertEquals(inBean.getInt12(), outBean.getInt12());
//assertEquals(inBean.getInt21(), outBean.getInt21()); // 문제 소지(아예 변환 안됨)
//assertEquals(inBean.getInt22(), outBean.getInt22()); // 문제 소지(아예 변환 안됨)
assertEquals(outBean.getInt21(), new Integer(0));
assertEquals(outBean.getInt22(), new Integer(0));
assertEquals(inBean.isBool11(), outBean.isBool11());
assertEquals(inBean.isBool12(), outBean.isBool12());
//assertEquals(inBean.getBool21(), outBean.getBool21()); // 문제 소지(아예 변환 안됨)
//assertEquals(inBean.getBool22(), outBean.getBool22()); // 문제 소지(아예 변환 안됨)
assertEquals(outBean.getBool21(), new Boolean(false));
assertEquals(outBean.getBool22(), new Boolean(false));
} catch (Exception e) {
System.err.println("-- e: " + e);
}
}
@Test
public void test_jackson_BeanCase() {
try {
ObjectMapper jacksonMapper = new ObjectMapper();
TestBean inBean = new TestBean();
inBean.setA("a Value");
inBean.setB("");
inBean.setC(null);
//inBean.setD();
inBean.setInt11(1);
//inBean.setInt12();
inBean.setInt21(1);
inBean.setInt21(null);
inBean.setBool11(true);
//inBean.setBool12();
inBean.setBool21(true);
inBean.setBool21(null);
System.out.println(inBean);
String jsonStr = jacksonMapper.writeValueAsString(inBean);
System.out.println("jsonStr: " + jsonStr);
TestBean outBean = jacksonMapper.readValue(jsonStr, TestBean.class);
assertEquals(inBean.getA(), outBean.getA());
assertEquals(inBean.getB(), outBean.getB());
assertEquals(inBean.getC(), outBean.getC());
assertEquals(inBean.getD(), outBean.getD());
assertEquals(outBean.getC(), null);
assertEquals(outBean.getD(), null);
assertEquals(inBean.getInt11(), outBean.getInt11());
assertEquals(inBean.getInt12(), outBean.getInt12());
assertEquals(inBean.getInt21(), outBean.getInt21());
assertEquals(inBean.getInt22(), outBean.getInt22());
assertEquals(inBean.isBool11(), outBean.isBool11());
assertEquals(inBean.isBool12(), outBean.isBool12());
assertEquals(inBean.getBool21(), outBean.getBool21());
assertEquals(inBean.getBool22(), outBean.getBool22());
} catch (IOException e) {
System.err.println("-- e: " + e);
}
}
}
[TestBean.java]
import lombok.Getter;
import lombok.Setter;
@Setter @Getter
public class TestBean {
String a;
String b;
String c;
String d;
int int11;
int int12;
Integer int21;
Integer int22;
boolean bool11;
boolean bool12;
Boolean bool21;
Boolean bool22;
}
[build.gradle]
sourceCompatibility='1.7'
dependencies {
//compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
//compile 'org.apache.maven.plugins:maven-war-plugin:+'
compile 'net.sf.json-lib:json-lib:2.4:jdk15@jar'
compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.6.4'
compile 'commons-lang:commons-lang:2.6'
compile 'commons-logging:commons-logging:1.2'
compile 'commons-collections:commons-collections:3.2.2'
compile 'commons-beanutils:commons-beanutils:1.9.2'
compile 'net.sf.ezmorph:ezmorph:1.0.6'
testCompile 'junit:junit:4.11'
testCompile 'org.hamcrest:hamcrest-all:1.3'
}
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.StringUtils;
// 자연수 + 공백
assertFalse(StringUtils.isNumeric(null));
assertTrue (StringUtils.isNumeric(""));
assertFalse(StringUtils.isNumeric(" "));
assertTrue (StringUtils.isNumeric("0"));
assertTrue (StringUtils.isNumeric("123"));
assertFalse(StringUtils.isNumeric("12 3"));
assertFalse(StringUtils.isNumeric("ab2c"));
assertFalse(StringUtils.isNumeric("12-3"));
assertFalse(StringUtils.isNumeric("12.3"));
assertFalse(StringUtils.isNumeric("-123"));
assertFalse(StringUtils.isNumeric("+123"));
// 자연수
assertFalse(NumberUtils.isDigits(null));
assertFalse(NumberUtils.isDigits(""));
assertFalse(NumberUtils.isDigits(" "));
assertTrue (NumberUtils.isDigits("0"));
assertTrue (NumberUtils.isDigits("123"));
assertFalse(NumberUtils.isDigits("12 3"));
assertFalse(NumberUtils.isDigits("ab2c"));
assertFalse(NumberUtils.isDigits("12-3"));
assertFalse(NumberUtils.isDigits("12.3"));
assertFalse(NumberUtils.isDigits("-123"));
assertFalse(NumberUtils.isDigits("+123"));
// 정수 + 실수 (+ 앞에 붙으면 안됨)
assertFalse(NumberUtils.isNumber(null));
assertFalse(NumberUtils.isNumber(""));
assertFalse(NumberUtils.isNumber(" "));
assertTrue (NumberUtils.isNumber("0"));
assertTrue (NumberUtils.isNumber("123"));
assertFalse(NumberUtils.isNumber("12 3"));
assertFalse(NumberUtils.isNumber("ab2c"));
assertFalse(NumberUtils.isNumber("12-3"));
assertTrue (NumberUtils.isNumber("12.3"));
assertTrue (NumberUtils.isNumber("-123"));
assertFalse(NumberUtils.isNumber("+123"));
Cluster 된 개별 WAS들이 모두 정상적으로 가동되고 있는지 모니터링 화면에서 표현해보자.
기준은 각 WAS의 Memory MBean 정보를 활용해서 WAS가 정상적인지도 체크 하고, 현재 Memory 상황은 어떤지 파악도 함께 할 수 있게 해본다.
[각각의 WAS Agent] -> vertx Net-> [모니터링 서버] -> vertx SockJs -> [Client Broswer] 방향으로 Memory 정보를 보낸다.
장애판단 기준은 WAS Agent에서 현재 5초 기준으로 모니터링 서버쪽으로 보내주고 있다.
그에 따라 Client Borswer 부분에서는 해당 정보가 (5초*1.5) 이후에도 정보가 오지 않으면 서버가 내려갔다고 판단한다.
또한 이 정보를 DB화 하여, Memory 증가량을 파악하고, GC 이후에도 Memory 가 부족하지는 않은지 판단해본다.
[MonitorAgent.java]
import java.lang.instrument.Instrumentation;
import java.util.Timer;
import pe.kr.ddakker.monitor.agent.timer.MBeanTimer;
public class MonitorAgent {
Timer timer = new Timer("ddakker Agent Timer", true);
Instrumentation instrumentation;
static MonitorAgent monitorAgent;
public static boolean isDebug = false;
public static void premain(String args, Instrumentation instrumentation) throws Exception {
//instrumentation.addTransformer(new TomcatTransformer());
monitorAgent = new MonitorAgent(instrumentation);
monitorAgent.start();
}
public final void start(boolean isRequest, boolean isMBean) {
MBeanTimer mBeanTimer = new MBeanTimer();
timer.scheduleAtFixedRate(mBeanTimer, 5000, 5000);
}
}
[MBeanTimer.java]
import java.lang.management.ManagementFactory;
import java.util.TimerTask;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import pe.kr.ddakker.monitor.agent.send.VertxClient;
public class MBeanTimer extends TimerTask {
public void run() {
try {
ObjectName om = new ObjectName("java.lang:type=Memory");
MBeanServer connection = ManagementFactory.getPlatformMBeanServer();
Object attrValue = connection.getAttribute(om, "HeapMemoryUsage");
long max = Long.parseLong(((CompositeData)attrValue).get("max").toString());
long used = Long.parseLong(((CompositeData)attrValue).get("used").toString());
long heapUsedPercent = Math.round((used*1.0 / max*1.0) * 100.0);
String msg = "{name: '" + System.getProperty("jvmRoute") + "', heapUsedPercent: '" + heapUsedPercent + "', time: '" + System.currentTimeMillis() + "'}";
msg = "{result: '0000', grp: 'grp_was', msg: '성공', data: " + msg + "}";
VertxClient.send(msg);
} catch (Exception e) {
System.err.println();
}
}
}
slf4j + logback 환경에서 이니지스 결재 모듈(INIpay50.jar) 사용 시 이니시스 로깅에 문제가 발생한다.
이니시스측에서도 log4j 를 사용하라고 권고한 상황..
하지만 쓰고 싶다면...
'org.slf4j:log4j-over-slf4j' 부분을 exclude 하면 된다.
※ 'org.slf4j:log4j-over-slf4j' 는 기존 라이브러리가 log4j를 사용하고 있을때, slf4j로 넘겨주는 역할은 하는거란다.
현재 겉모습은 제니퍼의 X-View 와 비슷하게 따라 하려는중이다.ㅎㅎ
1차적으로 요청 URI, 요청 시간, 종료 시간, 처리 시간, HttpStatus 값 정도만 차트에 표현하였다.
구조는 Tomat에 Agent를 띄운 후 Agent에서 모니터링툴 WAS에 WebSocket 로 보낸 후 데이터를 받은 모니터링툴에서 모니터링에 접속한 Client Browser 에 WebSocket로 데이터를 보내주는 방식이다.
모니터링툴에 붙은 Client가 많았을 경우 어떻게 될지 아직 잘 모르겠다.
상황봐서 Queue에 담아서 한다던가 고려해볼 생각이고 현재에는 비슷하게 구현만 하는게 목적이다.
인터넷의 자료를 통해서 javassist 를 활용하여 Byte Code Instrumentation 시도해보았지만, 일반적인 Java Main Program은 잘 되는데 Tomcat 의 특정 Class를 제어 하려고 했더니 잘 되지 않았다.
많은 삽질 끝에 ClassPool을 얻어 오는 부분을 조금 수정 하니 잘 되었다.
(이 부분때문에 몇일을 삽질 하다.. 포기도 할까 하고, Application Level Servlet Filter를 이용하는 방법으로 선회 할까도 했음...)
검색을 하두 해서 어디서 이 정보를 얻었는지 기억이 안나네요.
[해결 부분]
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new LoaderClassPath(classLoader));
[2015. 7. 6.]
WAS Application 요청시 org.apache.catalina.core.StandardEngineValve.invoke(Request request, Response response) 부분을 잡아 처리 하였다.
(만들어 가며 바뀔 수도 있는 부분임..)
이렇게 함으로 인해서 어떠한 문제가 발생할지는 미지수임...
HttpStatus=302 케이스에서 문제 발생
[2015. 8. 10.]
javax.servlet.http.HttpServlet.service(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse 으로 변경
이러면.. JSP Direct 호출이 안 잡히는군.. 쉽지 않구만...
다시 org.apache.catalina.core.StandardEngineValve.invoke(Request request, Response response) 원복!!
Spring Security LOGOUT HttpStatus 302일때문 문제가 발생!!
문제 발생 부분 request.getSession().getId()
이 부분을 Before 일때만 하고, After 일때는 주석
Before, After 요청 정보 맵핑을 Thread.currentThread().getId() 로 처리
우선 잘 된다...
[MonitorAgent.java]
package pe.kr.ddakker.monitor.agent;
import java.lang.instrument.Instrumentation;
import pe.kr.ddakker.monitor.agent.transformer.TomcatTransformer;
public class MonitorAgent {
public static void premain(String args, Instrumentation inst) throws Exception {
inst.addTransformer(new TomcatTransformer());
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
premain(args, inst);
}
}
[TomcatTransformer.java]
package pe.kr.ddakker.monitor.agent.transformer;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
/**
* Tomcat 요청 가로채서 수정!!
* @author ddakker 2015. 6. 14.
*/
public class TomcatTransformer implements ClassFileTransformer {
ClassPool pool = null;
public TomcatTransformer() {
this.pool = ClassPool.getDefault();
}
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain,
byte[] bytes) throws IllegalClassFormatException {
if (className.contains("StandardEngineValve")) {
System.out.println("className: " + className);
return transformClass(redefiningClass, bytes);
} else {
return bytes;
}
}
private byte[] transformClass(Class classToTransform, byte[] b) {
CtClass cl = null;
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new LoaderClassPath(classLoader));
if (pool != null) {
cl = pool.makeClass(new java.io.ByteArrayInputStream(b));
if (cl.isInterface() == false) {
CtBehavior[] methods = cl.getDeclaredBehaviors();
for (int i = 0; i < methods.length; i++) {
System.out.println("methods[" + i + "]: " + methods[i]);
if (methods[i].isEmpty() == false) {
doTransform(methods[i]);
}
}
}
b = cl.toBytecode();
}
} catch (Exception e) {
System.err.println("e111: " + e);
} finally {
if (cl != null) {
cl.detach();
}
}
return b;
}
private void doTransform(CtBehavior method) throws NotFoundException, CannotCompileException {
if (method.getName().equals("invoke")) {
System.out.println("0");
try {
System.out.println("1");
method.insertBefore(""
+ "String jvmRoute = System.getProperty(\"jvmRoute\");"
+ "String sessionId = $1.getSession().getId();"
+ "String uri = $1.getRequestURI();"
+ "pe.kr.ddakker.monitor.websocket.WSClient.send(\"{"
+ "server: '\" + jvmRoute + \"' "
+ ", sessionId: '\" + sessionId + \"' "
+ ", uri: '\" + uri + \"' "
+ ", stTime: '\" + System.currentTimeMillis() + \"' "
+ "}\");");
System.out.println("2");
method.insertAfter(""
+ "String jvmRoute = System.getProperty(\"jvmRoute\");"
+ "String sessionId = $1.getSession().getId();"
+ "String uri = $1.getRequestURI();"
+ "pe.kr.ddakker.monitor.websocket.WSClient.send(\"{"
+ "server: '\" + jvmRoute + \"' "
+ ", sessionId: '\" + sessionId + \"' "
+ ", uri: '\" + uri + \"' "
+ ", edTime: '\" + System.currentTimeMillis() + \"' "
+ ", status: '\" + $2.getStatus() + \"' "
+ "}\");");
System.out.println("3");
} catch (Exception e) {
System.err.println("Aa e: " + e);
}
System.out.println("4");
}
}
}
[build.gradle]
jar {
manifest {
attributes 'Implementation-Title': 'Gradle Quickstart',
'Implementation-Version': version,
'Premain-Class': 'pe.kr.ddakker.monitor.agent.MonitorAgent',
'Agent-Class': 'pe.kr.ddakker.monitor.agent.MonitorAgent',
'Can-Redefine-Classes': true
}
}
instrument 시 필요한 외부 Library들은 Agent jar에 포함 시켰다.
[실행]
-javaagent:D:\..\tomcat-monitor-agent-1.0.jar
최근 fastjson 이란 알리바바에서 공개한 JSON Parser 을 보게되어 현재 회사에서 사용중인 Library 들을 비교해 보았다.
jackson-databind-2.1.3.jar
json-lib-2.2.1-jdk15.jar
fastjson-1.2.5.jar
[테스트 상황]
Vo 안에 2개의 Vo가 있는 객체 활용하여, to JSON String, to JAVA Object 로 변환 및 역변환을 10,000 실행하였다.