## 설치 ("--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 (Streamstream = 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 실행하였다.