기본 콘텐츠로 건너뛰기

Example of java class transform with java agent and BCI


Dynamic transform

 

예제 시나리오


  • 원하는 작업 
    • DB에 요청하는 모든 쿼리를 출력
  • 작업 순서
    1. Agent 작성
    2. ClassFileTransformer 구현

Agent 작성

Java Agent 구성도

Manifest 파일

Manifest-Version: 1.0
Premain-Class: sample.bci.Agent
Agent-Class: sample.bci.Agent
Can-Redefine-Classes: True

must be end with new line - http://docs.oracle.com/javase/tutorial/deployment/jar/modman.html

Agent.java

/**
 * example for bci with java agent
 */
package sample.bci;

import java.lang.instrument.Instrumentation;


/**
 * @author k
 *
 */
public class Agent {
 public static void premain(String args, Instrumentation inst) {
  inst.addTransformer(new JdbcQueryTransformer());
 }
 
 public static void agentmain(String args, Instrumentation inst) {
  inst.addTransformer(new JdbcQueryTransformer());
 }
}


JdbcQueryTransformer. java

/**
 * example for bci with java agent
 */
package sample.bci;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

/**
 * @author k
 *
 */
public class JdbcQueryTransformer implements ClassFileTransformer {

 public JdbcQueryTransformer() {
  super();
 }
 
 @Override
 public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
   ProtectionDomain protectionDomain, byte[] classfileBuffer)
   throws IllegalClassFormatException {
  
  byte[] byteCode = classfileBuffer;

        ClassPool pool = ClassPool.getDefault();
        CtClass currentClass = null;
        CtClass statement = null;
        
        try {
   currentClass = pool.makeClass(new java.io.ByteArrayInputStream(classfileBuffer));
            statement = pool.get("java.sql.Statement");
            if (currentClass.subtypeOf(statement) && !currentClass.isInterface()) {
             probeStatement(currentClass);
            }
            byteCode = currentClass.toBytecode();
        } catch (Exception e) {
         e.printStackTrace();
        } finally {
   if (currentClass != null) {
           currentClass.detach();
   }
        }
        return byteCode;
 }
 
 private void probeStatement(CtClass currentClass) throws NotFoundException, CannotCompileException {
   
        CtMethod executeQuery = null;

        try {
         executeQuery = currentClass.getDeclaredMethod("executeQuery");
        } catch (NotFoundException e) {
         return;
        }
        executeQuery.insertBefore("try {System.out.println($1);} catch (Exception e){System.out.println(\"no sql\");}");
 }

}




examplecodeusingsql. java

/**
 * http://www.tutorialspoint.com/jdbc/jdbc-sample-code.htm
 */
//STEP 1. Import required packages
import java.sql.*;

public class FirstExample {
   // JDBC driver name and database URL
   static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  
   static final String DB_URL = "jdbc:mysql://localhost/EMP";

   //  Database credentials
   static final String USER = "username";
   static final String PASS = "password";
   
   public static void main(String[] args) {
   Connection conn = null;
   Statement stmt = null;
   try{
      //STEP 2: Register JDBC driver
      Class.forName("com.mysql.jdbc.Driver");

      //STEP 3: Open a connection
      System.out.println("Connecting to database...");
      conn = DriverManager.getConnection(DB_URL,USER,PASS);

      //STEP 4: Execute a query
      System.out.println("Creating statement...");
      stmt = conn.createStatement();
      String sql;
      sql = "SELECT id, first, last, age FROM Employees";
      ResultSet rs = stmt.executeQuery(sql);

      //STEP 5: Extract data from result set
      while(rs.next()){
         //Retrieve by column name
         int id  = rs.getInt("id");
         int age = rs.getInt("age");
         String first = rs.getString("first");
         String last = rs.getString("last");

         //Display values
         System.out.print("ID: " + id);
         System.out.print(", Age: " + age);
         System.out.print(", First: " + first);
         System.out.println(", Last: " + last);
      }
      //STEP 6: Clean-up environment
      rs.close();
      stmt.close();
      conn.close();
   }catch(SQLException se){
      //Handle errors for JDBC
      se.printStackTrace();
   }catch(Exception e){
      //Handle errors for Class.forName
      e.printStackTrace();
   }finally{
      //finally block used to close resources
      try{
         if(stmt!=null)
            stmt.close();
      }catch(SQLException se2){
      }// nothing we can do
      try{
         if(conn!=null)
            conn.close();
      }catch(SQLException se){
         se.printStackTrace();
      }//end finally try
   }//end try
   System.out.println("Goodbye!");
}//end main

댓글

이 블로그의 인기 게시물

ubuntu 에서 원격 JMX(Java Management Extensions) 모니터링 가능하게 하기

원격 JMX 모니터링 가능하게 하기   정리  설정 파일 수정 관련 파일 $JAVA_HOME/jre/lib/management/management.properties  내용추가 com.sun.management.jmxremote.port=8991 com.sun.management.jmxremote.ssl=false 톰캣 설정 수정 관련 파일 /etc/default/tomcat7 JAVA_OPTS="-Djava.awt.headless=true -Xmx128m -XX:+UseConcMarkSweepGC -Dcom.sun.management.jmxremote   password 파일 소유자 및 권한 수정 sudo chown tomcat7.tomcat7 /etc/java-7-openjdk/management/jmxremote.password sudo chmod 600 /etc/java-7-openjdk/management/jmxremote.password    원격 JMX 모니터링 시 설정 설정이 필요한 파일 $JAVA_HOME/jre/lib/management/jmxremote.access $JAVA_HOME/jre/lib/management/jmxremote.password 두 파일이 필요하다는데. Ubuntu 14.04 Java Home Directory 에서 JAVA_HOME은 /usr/lib/jvm/default-java임을알아냈다. 물론, /usr/lib/jvm/default-java/jre/lib/management/jmxremote.access와 같은 직접적인 접근도 가능하다. linux의 주 설정파일 들이 모여있는 디렉토리는 /etc이며, 위의 파일 또한 실제로는 /etc/java-7-openjdk/management/jmxremote.access라는 실제 파일에 ...

[android] RecyclerView with Cursor

RecyclerView is new in Android 5.0 (Lollipop) . To use with support library add compile 'com.android.support:recyclerview-v7:21.0.0' in build.gradle file dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:21.0.0' compile 'com.android.support:recyclerview-v7:21.0.0' } and import import android.support.v7.widget.RecyclerView; Get from layout xml RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycle_list); Plug in LayoutManager recyclerView.setLayoutManager(layoutManager); Create Adapter NameRecyclerAdapter mAdapter; ... mAdapter = new NameRecyclerAdapter(); Plug in Adapter recyclerView.setAdapter(mAdapter); NameRecyclerViewAdapter.java import android.database.Cursor; import android.support.v7.widget.RecyclerView; import android.view.ViewGroup; import android.widget.TextView; /** * * Recycler Adapter for TestDB...