2012년 1월 31일 화요일

Java 1.5 이상에서 ProcessBuilder를 이용해서 외부 프로그램 호출하기

Java 1.5부터 Runtime.exec()를 대신할 ProcessBuilder가 생겼다.

WAS에서 배치 프로그램을 시작할 수도 있고,
다른 시스템 프로그램을 호출 할 수도 있다.

아래 코드는  main() 메소드를 가지고 있는 자바 클래스를 실행하는 코드다.
실행 명령은 기존의 Runtime.exec와 다르게 명령행을 내용을 한 줄로 만드는 것이 아니라
space로 구분되는 내용을 각각의 문자열로 지정해야 한다.
아래 ProcessBuilder의 내용은 "java test.Callee a b=b c" 이렇게 명령행을 입력 하는 경우이다.
 // 각각의 command line argument까지 개별 항목으로 지정해야 한다.
 ProcessBuilder pb = new ProcessBuilder("java","test.Callee","a", "b=b" ,"c");
 Map env = pb.environment();
 // -classpath옵션은 ProcessBuilder에 직접 지정할 수 없다.
 // shell script를 만들때 처럼 환경 변수 CLASSPATH로 클래스 path를 지정한다.
 env.put("CLASSPATH", "C:/workspace/Test/bin");
 pb.directory(new File("C:/workspace/Test")); // 로그 파일이 생기는 기본 위치
 File log = new File("log"); // 로그 파일명
 pb.redirectErrorStream(true); // 에러도 로그에 출력되게 설정
  // redirectOutput과 Redirect는 java se 7 에서 추가된 내용 임. 
 pb.redirectOutput(Redirect.appendTo(log)); // System.out이 이 파일에 쓰여진다.
 Process p = pb.start(); // 프로그램을 실행한다.

위의 코드는 프로그램을 실행하고 바로 return 되는 코드다.

프로그램을 실행하고 끝날때 까지 기다리기를 원하면 p.waitFor();를 호출 한다.
이런 경우는 아래처럼 별도의 로그 파일을 쓰지 않고 직접 출력 할 수도 있다.

  ProcessBuilder pb = new ProcessBuilder("java","test.Callee","a", "b=b" ,"c");
  Map env = pb.environment();
  env.put("CLASSPATH", "C:/workspace/android/Test/bin");
  Process p = pb.start();
  p.waitFor();

  InputStream i = p.getInputStream();
  byte b[] = new byte[8192];
  int read=0;
  while( (read = i.read(b)) > 0 ){
   System.out.println("out : "+new String(b,0,read));
  }
  i= p.getErrorStream();
  while( (read = i.read(b)) > 0 ){
   System.out.println("err : "+new String(b,0,read));
  }
  System.out.printf("exit value : %s\n",p.exitValue()); // 0 이면 정상종료

간혹 명령이 잘못 되면 pb.start()에서 에러가 발생하기도 한다. 헌데, windows에서는 exception의 메시지에 포함된 한글이 깨지기도 한다. 이런경우 encoding값을 직접 지정하여 한글 메시지를 확인 하는 것이 도움이 된다. 또는 로그파일을 쓰면 된다.

 try {
  ProcessBuilder pb = new ProcessBuilder("java","test.Callee","a", "b=b" ,"c");
  Map env = pb.environment();
  env.put("CLASSPATH", "C:/workspace/android/Test/bin");
  Process p = pb.start();
  p.waitFor();
  InputStream i = p.getInputStream();
  byte b[] = new byte[8192];
  int read=0;
  while( (read = i.read(b)) > 0 ){
   System.out.println("out : "+new String(b,0,read));
  }
  i= p.getErrorStream();
  while( (read = i.read(b)) > 0 ){
   System.out.println("err : "+new String(b,0,read));
  }
  System.out.printf("exit value : %s\n",p.exitValue());
 } catch (IOException e) {
  try {
   System.out.println(
          new String( e.getMessage().getBytes("8859_1"), "euc-kr"));
  } catch (UnsupportedEncodingException e1) {
    e1.printStackTrace();
  }
  e.printStackTrace();
 } catch (InterruptedException e) {
  e.printStackTrace();
 }