copy comm.jar                   \jdk1.3\jre\lib\ext
copy win32com.dll               \jdk1.3\bin
copy javax.comm.properties      \jdk1.3\jre\lib

DLL 만들기
new  - > win32 Dynamic-link Library -> A simple Dll project
하면 끝...
여기에 Java  include에 포함 시키고  설정한다음에 프로그램 작성하면 끝~~~
Jni 해더 파일은 만드는법은 인터넷 찾아보면 많으니까 찾아보시고.
그다음작업하면 완료 ~~`
class aaa
{
static {System.loadLibrary("로드할 DLL 이름");}
public native int diviceStateChange(int iState , byte[] blDiveName); /// 이부분은 C++ DLL과 이름이 동일해야한다.
public int diviceStateChange(int iState , String strDiveName) throws Exception
{
//내부코딩 리턴값 설정
int iRet = diviceStateChange(iState,getEndNullByte(strDiveName));
return iRet ; // 이정도 ?
}
}
///////
매인에서는 
aa _aa= new aa(); 
_aa.getInstance();
int  k  = _.aa.diviceStateChange(0,"COM3"); 
System.out.println(k);
 요런식으로 사용하면 끝



JNI 사용법 웹프로그램/java 2008. 10. 15. 13:26
휴 ~_~ 인터넷에 있는 방법보다 쉬운방법 ...

new ->다이나믹 ->an empty project
생성한뒤

file view 에 헤더 파일 및 라이브러리 등록 한다. 소스파일도 당연하고 ..

그뒤 jni.h 및 각종 헤더파일을 등록할려면
메뉴에서 tools -> 텝에 directiories 에 각종 헤더 파일및 라이브러리 위치를 등록한다.

아무 생각업이 코딩하면 끝 ~
Base 64 웹프로그램/java 2008. 9. 17. 09:46
참고 사이트를 이용해 servlet 공부를 하던중 base64 인코더와 디코더를 이용하는 예제가 있었다.

참고 사이트 구문중 'sun에서 이렇게 base64로 인코딩된 문자열을

디코딩해주기위한 sun.misc.BASE64 클래스를 제공합니다.' 라는 글과

코드중 import sun.misc.BASE64Decoder; 구문으로 인하여 나의 오해를 샀다....

검색결과 JDK에 기본으로 들어가있는 패키지란다.. ㅡㅡ;;

jdk/jre/lib/rt.jar
<== 요안에 있단다..

  /**
     * BASE64 Encoder
     *
     * @param str
     * @return
     * @throws java.io.IOException
  */
  public static String base64Encode(String str)
  {
      String result = "";
      sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
      byte[] b1 = str.getBytes();
      result = encoder.encode(b1);
      return result;
  }

   /**
     * BASE64 Decoder
     *
     * @param str
     * @return
     * @throws java.io.IOException
  */

  public static String base64Decode(String str)
  {
      String result = "";
      try
      {
          sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
          byte[] b1 = decoder.decodeBuffer(str);
          result = new String(b1);
      }
      catch (IOException ex)
      {
      }
      return result;
  }

퍼온곳 : http://lastmind.net/mt/mt-tb.cgi/419

Java 프로그램에서 외부 프로그램을 실행하고 싶을 때, Runtime.exec() 또는 Java 1.5에서 추가된 ProcessBuilder를 사용해 Process 객체를 얻을 수 있다. 처음으로 이런 프로그램을 짤 때, 실수한 것이 없어보이는데도 실행한 프로그램이 종료되지 않는 경우가 있다. 더군다가 어떤 경우엔 정상적으로 종료되고 어떤 경우엔 종료가 되지않는 경우도 보인다.

원인은 바로 Process 클래스의 API Reference에 있는 다음과 같은 설명에서 찾을 수 있다.

The created subprocess does not have its own terminal or console. All its standard io (i.e. stdin, stdout, stderr) operations will be redirected to the parent process through three streams (getOutputStream(), getInputStream(), getErrorStream()). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.

즉, Java에서는 Child 프로세스로의 표준 입출력을 Parent 프로세스가 다루어주어야 한다. 당연하게도, Child의 출력을 언제까지고 버퍼링할 수 없기 때문에, 다른 프로그램을 실행할 때는, 특히 표준 입출력이 존재하는 프로그램을 실행할 경우에는, 항상 이 스트림들의 입력 또는 출력을 제대로 다루어주어야 한다.

이러한 동작은 일반적으로 프로그래머들이 익숙한 시스템콜들, 이를테면 UNIX 계열의 fork()/exec()나 Windows의 CreateProcess()처럼, parent 프로세스의 터미널/콘솔을 공유하는 동작과는 다르기 때문에, 프로그래머들이 쉽게 간과하고 실수하기 쉽다. 더군다나 API Reference가 이러한 점을 명확히 설명하고 있지도 않다.

해결책은 당연하게도 표준 입력이 필요할 때는 Process.getOutputStream()을 이용하여 필요한 입력을 해주고 스트림을 닫아주어야하고, 표준 출력이 필요할 때는 Process.getInputStream() 그리고 Process.getErrorStream()을 이용하여 스트림을 비워주어야한다. 드물겠지만 만약 실행할 프로그램이 interactive한 프로그램일 경우에는 입출력에 좀 더 신경을 써야한다.

다음은 표준 출력을 비워주기 위한 코드가 들어간 간단한 예다.

  1. Runtime rt = Runtime.getRuntime();  
  2. try {  
  3.     Process proc = rt.exec("cmd /c dir");  
  4.     // Process proc = new ProcessBuilder().command("cmd", "/c", "dir").start();  
  5.     InputStream is = proc.getInputStream();  
  6.     BufferedReader reader = new BufferedReader(new InputStreamReader(is));  
  7.     String line;  
  8.     while ((line = reader.readLine()) != null) {  
  9.         System.out.println(line);  
  10.     }  
  11.     int exitVal = proc.waitFor();  
  12.     System.out.println("Process exited with " + exitVal);  
  13. } catch (Exception e) {  
  14.     System.err.println("Failed to execute: " + e.getMessage());  
  15. }  

표준 출력 뿐만 아니라 표준 에러까지도 처리를 할 수 있어야 좀 더 일반적인 코드일 것이다. 표준 에러의 버퍼가 차버리면 표준 출력을 비우려고 해도 블럭될 수 있다. 이러한 문제는 Java World의 When Runtime.exec() won't 라는 글에서 StreamGobbler라는 클래스를 도입해서 약간 더 우아하게 해결하고 있다. 하지만, 간단한 작업을 하기 위해 쓰레드를 사용하고 있기 때문에 좀 오버킬이라는 생각이 든다.

표준 출력과 표준 에러를 간단하게 무시하고 다른 프로그램을 실행할 수 있도록 하는 옵션이 있다면 자주 사용할 수 있으며 편리할 듯 하다. 또는, 디폴트 동작을 일반적인 시스템콜의 동작과 비슷하게 만들어주는 것도 괜찮을 듯하다. 시간이 나면 이런 방식의 Wrapper를 찾아보거나 만들어보아야겠다

객체들을 조작하기 위한 자료구조로 자바는 배열이나 Collection Framework 내의 여러클래스를 제공하고 있습니다.

Collection Framework는 크게 3가지 형태로 분류할 수 있는데 간단하게 살펴 보자면
  - Map : key와 Value를 가지는 자료구조입니다. HashMap, Hashtable, TreeMap과 같은 클래스들을 자주 쓰죠.
  - List : 순서가 있고 중복이 허용되는 자료구조입니다. ArrayList, LinkedList, Vector...
  - Set : 중복을 허용하지 않습니다.  HashSet, TreeSet...

이러한 자료구조 내에서 객체들을 컨트롤 할 때 정렬은 피할 수 없는 숙명이죠.


1. 정렬해야 하는데 정렬 알고리즘을 모르겠다. 누가 정렬 좀 안해주나?


버블소트는 간단하지만 퍼포먼스에 문제가 있고
일반적으로 가장 빠른 퀵소트는 구현하기가 까다롭습니다.
버블소트조차도 귀찮으신 분들을 위해 친절하게도 자바는 여러분에게 고성능(?)의 정렬기능을 제공하고 있습니다.
그러나 우리는 자바가 제공하는 정렬기능을 사용하기 위해서 한두가지는 해야 합니다. 공짜는 없는거죠.


먼저 정렬을 위한 두가지 인터페이스에 친숙해질 필요가 있습니다.

  java.lang.Comparable
  java.util.Comparator


  두 인터페이스가 서로 다른 패키지에 속해 있다는 사실에 유의하시구요.

Comparable 인터페이스는 객체의 고유한 순서를 제공하기 위한 것이라고 보면 되는데요.
우리말로 '비교할 수 있는' 정도로 풀 수 있겠죠.
그 뜻대로 이 인터페이스를 구현한 클래스의 객체들은 배열이나 컬렉션 프레임웤에서
자신과 딴넘을 비교할 수 있기 때문에 정렬의 기본조건을 충족시키고 있습니다.
정렬의 기본조건(객체간의 대소비교, 선후비교)이 준비되어 있기 때문에 정렬은 java API에 맡기면 되는 겁니다.


아래의 소스에서 우리는 Customer 클래스를 만들고 Comparable 인터페이스를 구현했습니다.
Comparable 인터페이스를 구현했기 때문에 그 인터페이스에서 정의한 compareTo 메쏘드를 반드시 오버라이딩 해야하죠.
이 메쏘드가 바로 자신과 딴넘을 비교해서
자기자신이 딴넘보다 앞에 와야하면 -1을, 똑같으면 0을, 뒤에 와야하면 1을 리턴하게 됩니다.
Customer 클래스에서는 디폴트로 한글이름으로 정렬되도록 compareTo를 재정의 했습니다.


이렇게만 구현을 해 놓으면 Customer로 이루어진 배열이 있다면
  Arrays.sort(arr);


Customer로 이루어진 리스트(컬렉션프레임웤)가 있다면
  Collections.sort(list);

를 호출하기만 하면 군말 없이 정렬해 줍니다.


자바API에서도 여러 클래스들이 이 Comparable을 구현하고 있는데요.

API문서를 참고하면

BigDecimal, BigInteger, Byte, ByteBuffer, Character, CharBuffer, Charset, CollationKey, Date, Double, DoubleBuffer, File, Float, FloatBuffer, IntBuffer, Integer, Long, LongBuffer, ObjectStreamField, Short, ShortBuffer, String, URI

등의 클래스들이 있습니다.

이러한 클래스들의 자료를 다룰때는 위의 sort 메쏘드를 자연스럽게 불러주면 되겠죠?


자바가 내부적으로 어떻게 정렬을 수행하는지 궁금하지 않으십니까?
그러면 SDK 설치 디렉토리 밑에 src.zip파일을 찾아 java.util.Arrays와 java.util.Collections의소스를 뜯어보십시오.
Collections의 sort(List)는 아규먼트로 들어온 list를 배열로 변환해서 다시 Arrays.sort(array)를 호출하며 Arrays.sort(array)는 합병정렬을 하고 있습니다

아마 합병정렬은 정렬성능도 우수하지만 정렬시간이 거의 일정하기 때문에 사용하는 것 같습니다.

(퀵소트는 최악의 경우 O(n^2) 의 시간이 걸릴수도 있습니다.)
단 메모리를 자기자신만큼, 그리고 절반씩 쪼개지는 크기들 만큼씩 더 사용한다는게 단점이죠.


우리는 Customer 클래스들이 배열로 되어 있건 리스트에 들어있건 한글이름으로는 정렬할  수는 있는데 그렇다면 나이순이라든지 영문이름순으로, 즉 다른 기준으로 정렬하고 싶을 땐 어떻게 할까요?

이럴때를 위해서 만들어 놓은 인터페이스가 Comparator입니다.
우리말로 '비교기', '비교측정기' 정도로 번역할 수 있는데 두 객체의 대소와 선후를 구현의도의 기준에 따라 판별해 줍니다.
이 인터페이스를 구현하는 클래스도 마찬가지로 compare 메쏘드를 구현해야 하는데요.
아규먼트로 들어오는 두개의 Object를 비교해서 역시 compareTo 와 같은 방식으로 리턴합니다.


그리고 아래처럼 사용하면 배열이나 리스트를  Comparator의 기준에 따라 정렬을 수행하게 됩니다.  
  Arrays.sort(arr, new YoungOrderComparator());
  Collections.sort(list, new EngNameComparator());


 

2. sort()를 부르기도 귀찮다. 그냥 알아서 줄 좀 서 봐라.

 

자바는 친절하게도 위의 요구까지 들어주고 있는데
TreeMap이나, TreeSet이 그 기대에 부응하는 클래스들입니다. (Tree~가 붙어 있죠? ^^)
TreeMap은 key로 정렬을 하게 되고 TreeSet은 그 원소들을 정렬합니다.
위의 컨테이너 객체에 원소들을 넣는 족족 알아서 정렬됩니다. 코딩할 일이 없습니다.


리스트 같은 객체들을 인자로 받아서 TreeSet을 만들면 알아서 기본순서로(compareTo에 정의된 대로) 정렬됩니다.
   Set set = new TreeSet(list);


정렬기준을 바꾸고 싶다면 Comparator를 구현한 객체를 생성자로 만든후 리스트를 집어넣어 줍니다.
   Set set2 = new TreeSet(new YoungOrderComparator());
   set2.addAll(list);


아래의 소스에 위에 언급한 사항을 간단하게 구현해 보았습니다.

자바의 컬렉션 프레임웤, 정렬기능 등을 차근차근 살펴보면 Interface, 다형성 등의 묘미를 만끽할 수 있죠.
이러한 객체지향적 언어로서의 매력은 이곳외에도 자바API의 여러부분에서 표현되어져 있습니다.
JAVA는 정말 아름다운 언어임에는 틀림없습니다.


import java.util.*;


public class A {
    public static void main(String args[]) {
      // 다섯명의 고객에 대한 배열 생성
      Customer[] arr = new Customer[] {
        new Customer("헤더 로클리어",1961, "Heather Deen Locklear"),
        new Customer("데미 무어", 1962, "Demetria Gene Guynes"),
        new Customer("안젤라 바셋", 1958, "Angela Bassett"),
        new Customer("신디 크로퍼드", 1966, "Cintia Ann Crawford"),
        new Customer("캐서린 제타 존스", 1969, "Catherine Jones")
      };
     
      printArray(arr, "Before Array sort Using Default sort");
       // 배열을 정렬 (클래스에 정의된 기본정렬)
      Arrays.sort(arr);
      printArray(arr, "\nAfter Array sort Using Default sort");

      // 배열을 어린 나이부터 정렬
      Arrays.sort(arr, new YoungOrderComparator());
      printArray(arr, "\nAfter Array sort Using YoungOrderComparator");


      List list = Arrays.asList(arr); // 배열을 리스트로
      Collections.shuffle(list); // 리스트의 순서를 마구 섞어 주세요.
      printList(list, "\nBefore List sort Using Default sort");


      // 리스트를 정렬  (클래스에 정의된 기본정렬)
      Collections.sort(list);
      printList(list, "\nAfter List sort Using Default sort");

      // 리스트를 영문이름으로 정렬
      Collections.sort(list, new EngNameComparator());
      printList(list, "\nAfter List sort Using EngNameComparator");


      // 디폴트 정렬할 수 있는 TreeSet을 만든다
      Set set = new TreeSet(list);
      System.out.println("\nAfter Making Set  Using Default sort\n" + set);


      // 어린 나이부터 정렬할 수 있는 TreeSet을 만든다
      Set set2 = new TreeSet(new YoungOrderComparator());
      set2.addAll(list);
      System.out.println("\nAfter Making Set  Using YoungOrderComparator\n" + set2);
    }


    static void printArray(Customer[] a , String title) {
      System.out.println(title);
      for (int i=0; i<a.length; i++)
        System.out.println(a[i]);
    }
   
    static void printList(List l, String title) {
      System.out.println(title);
      for (int i=0; i<l.size(); i++)
        System.out.println(l.get(i));
    }
   
}


 // 디폴트 소팅을 위해서 Comparable 인터페이스를 구현한다.
class Customer implements Comparable {
  String name;
  int birthYear;
  String engName;

   // Constructor
   public Customer(String name, int birthYear, String engName) {
     this.name = name;
     this.birthYear = birthYear;
     this.engName = engName;
   }


    // Object의 toString 메소드 overriding.. 객체의 문자적 표현
    public String toString() {
     return name + "(" + engName + ") " + birthYear + "년생";
   }


   // Comparable 인터페이스를 구현한 클래스에서 반드시 overriding 해야만 하는 비교 메쏘드
   public int compareTo(Object o) {
     // String의 compareTo 메소드를 호출(사전순서적( lexicographically)으로 비교)
     return name.compareTo(((Customer)o).name);
   }
}


// 젊은 순서대로 정렬하기 위해 Comparator 인터페이스를 구현
class YoungOrderComparator implements Comparator {
  public int compare(Object o1, Object o2) {
    int by1 = ((Customer)o1).birthYear;
    int by2 = ((Customer)o2).birthYear;
    return by1 > by2 ? -1 : (by1 == by2 ? 0 : 1); // descending 정렬.....
  }
}


// 영문이름으로 정렬하기 위해 Comparator 인터페이스를 구현
class EngNameComparator implements Comparator {
  public int compare(Object o1, Object o2) {
    String en1 = ((Customer)o1).engName;
    String en2 = ((Customer)o2).engName;
    return en1.compareTo(en2); // ascending 정렬
  }
}

Posted by 숭늉은셀프

트랙백 주소 :: http://yobaboom.tistory.com/trackback/17

  1. Subject



 

 




난이도 : 중급


 

2007 년 8 월 28 일

JDOM은 XML과 함께 작동하는 고유한 자바 툴킷으로서, XML 애플리케이션의 신속한 개발을 목적으로 설계되었습니다. JDOM의 디자인에는 자바 언어의 신택스부터 의미까지 포괄되어 있습니다. 하지만, 기존의 XML API보다 과연 얼마나 나을까요? 여러분이 직접 예제를 실행해 보고, 오픈 소스 프로젝트의 디자인 목표와 비교
하면서 판단해 봅시다.

  개발자인 여러분들도 80-20 규칙에 대해 들어봤을 것이다. 프로세스나 방법론이 모든
 상황의 80 퍼센트를 차지하고, 나머지 20 퍼센트는 상황 별로(case-by-case)
 다루어져야 한다. 소프트웨어 개발 세계에서 개발자가 주어진 기술을 사용하여
수행할 수 있는 일들의 80 퍼센트를 이룩하기는 매우 쉽다.

물론, 소프트웨어 제품과 표준이 80-20 규칙을 늘 따르는 것은 아니다.
특히 자바 XML 툴의 어긋난 부분은 이 규칙의 예외를 증명하고 있다.
자바 프로그래밍 세계는 수 많은 API들로 가득 차있다. 어떤 것은 자생한 것이고,
어떤 것은 대기업의 마케팅의 지원을 받기도 한다. XML의 보편성에 대한 약속으로서,
모든 새로운 태스크에는 새로운 기술이 있다. 하지만, 무엇이 접착제 역할을 하고,
 여러분은 80 퍼센트의 작업을 수행하는데 적합한 툴을 어떻게 찾겠는가?
JDOM은 이러한 질문을 염두 해 두고 구현된 XML API이다.

자바와 XML

여러 가지 면에서, 자바 언어는 XML을 위한 프로그래밍 언어가 되었다. Apache Software Foundation과 IBM alphaWorks의 노력으로 XML 문서의
생성, 조작, 변형, 파싱을 위한 완전한 툴 체인이 생겼다.

많은 자바 개발자들은 XML을 매일 사용하지만, Sun은 XML을 자바 플랫폼에
 적용하는데 뒤쳐졌다. Java 2 플랫폼은 XML이 비즈니스 대 비즈니스 통합부터
웹 사이트 콘텐트 스트리밍에 이르기까지 모든 것에 대한 핵심 기술이 되기 전에
가치 있는 것이 되었기 때문에 Sun은 폭넓은 채택성을 획득했던 기존 XML API의
 창시자가 되는 JSR 프로세스를 사용해왔다. 가장 중요한 것은 JAXP
(Java API for XML Parsing)의 추가이다. 여기에는 세 개의 패키지들이 포함된다.

  • org.w3c.dom: XML을 위한 표준 프로그래밍 방식의 Document Object Model의 W3C recommendation의 자바 구현.
  • org.xml.sax: XML 파싱을 위한 이벤트 중심의 API.
  • javax.xml.parsers: 애플리케이션 개발자들이 특정 파서 구현을 설정하고 획득할 수 있도록 해주는 팩토리 구현.

이러한 패키지들의 추가가 자바 개발자들에게는 좋은 일이지만, 고급의 자바-XML 상호 운용성으로 큰 도약을 이룬 것이 아닌 기존 API 표준에 대한 일반적인 순응을 나타낸다. 핵심 자바 플랫폼에서 부족한 것은 XML 문서를 자바 객체로서 조작할 수 있는 매력적인 인터페이스이다.

JDOM을 생각해 보자. 유명한 자바 개발자이자 작가인 Brett McLaughlin과 Jason Hunter의 생각의 산물인 JDOM은 2000년 초반에 Apache 계열의 라이센스 하에서 오픈 소스 프로젝트로서 시작되었다. 폭넓은 자바 개발자 베이스로부터 기여와 피드백, 버그 픽스를 받아들였고, 자바 코드에서 XML 데이터에 액세스 하여, 조작 및 결과를 만들어 내는 완벽한 자바 플랫폼 기반의 솔루션 구현을 목표로 설정했다.




위로


API로서의 JDOM

JDOM은 XML 문서들을 프로그래밍 방식으로 조작하는 org.w3c.dom 패키지에 대한 대안으로서 사용될 수 있다. 완벽한 대체는 아니고, 사실, JDOM과 DOM은 공존할 수 있다. 게다가, JDOM은 텍스트 인풋에서 XML을 파싱하는 것을 신경 쓰지 않는다. 파서 구현을 설정 및 실행하는데 도움이 되는 래퍼 클래스를 제공하기도 한다. JDOM은 기존 API를 기반으로 구현되었다.

대안 API의 필요성을 이해하려면, W3C DOM의 디자인 제약 조건에 대해 살펴보자.

  • 언어 독립성. DOM은 자바 언어를 염두 해 두고 설계되지 않았다. 이것의 접근 방식은 다양한 언어들 사이에서 매우 비슷한 API를 유지하지만, 자바의 이디엄에 익숙한 프로그래머에게는 성가신 API이다. 예를 들어, 자바 언어는 String 클래스가 언어에 구현되어 있지만, DOM 스팩은 고유의 Text 클래스를 정의한다.

  • 엄격한 계층. DOM의 API는 XML 스팩을 따른다. 따라서, 모든 것의 노드가 되는 XML에서, 모든 것이 확장하는 DOM에서 Node 기반 인터페이스와 Node를 리턴하는 메소드의 호스트를 찾는다. 이는 다형성의 관점에서 볼 때는 뛰어나지만, 자바 언어로 작업하기에는 불편하다. Node에서 리프(leaf) 유형으로의 변화는 장황하고 이해하기 어려운 코드를 만든다.

  • 인터페이스 중심. 퍼블릭 DOM API는 인터페이스들로만 구성된다. (한 가지 예외는 Exception 클래스이다.) W3C는 인터페이스를 정의할 때 구현을 제공하는 것에는 관심이 없다. 자바 프로그래머로서 API를 사용한다는 것은 XML 객체들을 생성할 때 어느 정도의 분리가 된다. W3C 표준은 일반적인 팩토리 클래스와 유연하지만 덜 직접적인 패턴들을 사용하기 때문이다. XML 문서들이 애플리케이션 레벨 코드가 아닌 파서에 의해서만 구현되는 특수한 경우, 이는 무관하다. 하지만, XML 사용이 널리 퍼지면서, 애플리케이션 개발자들은 XML 객체들을 프로그래밍 방식으로 구현하는 편리한 방법을 필요로 하게 되었다.

프로그래머에게, 이러한 제약 조건은 (메모리 사용과 인터페이스 규모 면에서) 무겁고 다루기 어렵다는 것을 의미한다. 반대로, JDOM은 자바 중심의, 경량의 API이다. DOM의 원리를 조정하여 위에 언급한 불편함을 해소시켰다.

  • JDOM은 자바 플랫폼 식이다. 이 API는 자바 언어의 빌트인 String 지원을 사용하기 때문에, 텍스트 값은 String으로서 언제나 사용할 수 있다. ListIterator 같은 Java 2 플랫폼 컬렉션 클래스도 활용하면서 자바 언어에 익숙한 프로그래머에게 풍부한 환경을 제공한다.

  • 계층이 없음. JDOM에서, XML 엘리먼트는 Element의 인스턴스이고, XML 애트리뷰트는 Attribute의 인스턴스이며, XML 문서는 Document의 인스턴스이다. 이 모든 것들이 XML에서 다른 개념들을 나타내기 때문에, 무정형의 "노드"로서가 아닌 고유의 유형으로서 참조된다.

  • 클래스 중심. JDOM 객체는 Document, Element, Attribute 같은 클래스들의 직접적인 인스턴스이므로, 이를 구현하는 것은 자바 언어에서 new 연산자를 사용하는 것만큼이나 쉽다. 또한 설정 할 팩토리 인터페이스가 없다. JDOM은 jar에서 직접 사용할 준비가 되어있다.



위로


JDOM 문서 구현 및 조작

JDOM은 표준 자바 코딩 패턴을 사용한다. 가능하다면, 복잡한 팩토리 패턴 대신에 자바 new 연산자를 사용하면서, 신참 사용자들도 객체를 쉽게 조작할 수 있게 해준다. JDOM을 사용하여 XML 문서를 구현하는 방법을 살펴보자. 우리가 구현할 구조는 Listing 1과 같다. (참고자료 섹션에서 전체 코드를 다운로드 할 수 있다.)


Listing 1. 구현할 XML 문서 샘플
                

<?xml version="1.0" encoding="UTF-8"?>
<car vin="123fhg5869705iop90">
  <!--Description of a car-->
  <make>Toyota</make>
  <model>Celica</model>
  <year>1997</year>
  <color>green</color>
  <license state="CA">1ABC234</license>
</car>

주: 아래 Listing 2부터 7까지 샘플 문서를 구현할 것이다.

먼저, 루트(root) 엘리먼트를 만들고 이를 문서에 추가한다.


Listing 2. Document 구현하기
                

Element carElement = new Element("car");
Document myDocument = new Document(carElement);

이 단계는 새로운 org.jdom.Element를 만들고, 이것을 org.jdom.Document myDocument의 루트 엘리먼트로 만든다. (참고자료 섹션에서 제공하는 샘플 코드를 사용하고 있다면 반드시 org.jdom.*을 반입하라.) XML 문서는 하나의 루트 엘리먼트를 가져야 하므로, Document는 생성자에 Element를 취한다.

다음에는, vin 애트리뷰트를 추가한다.


Listing 3. Attribute 추가하기
                

carElement.addAttribute(new Attribute("vin", "123fhg5869705iop90"));

엘리먼트를 추가하는 것도 매우 단순하다. make 엘리먼트를 추가한다.


Listing 4. 엘리먼트와 하위 엘리먼트
                

Element make = new Element("make");
make.addContent("Toyota");
carElement.addContent(make);

ElementaddContent 메소드가 Element를 리턴하므로, 이를 다음과 같이 작성할 수 있다.


Listing 5. 간결한 형식으로 엘리먼트 추가하기
                

carElement.addContent(new Element("make").addContent("Toyota"));

이 문장들 모두 같은 일을 수행한다. 첫 번째 예제는 보다 읽기 쉽지만, 두 번째는 많은 엘리먼트들을 한번에 구현한다면 더욱 읽기 쉬울 것이라고 말할 수도 있겠다. 문서 구현을 완료하려면 다음과 같이 한다.


Listing 6. 나머지 엘리먼트 추가하기
                

carElement.addContent(new Element("model").addContent("Celica"));
carElement.addContent(new Element("year").addContent("1997"));
carElement.addContent(new Element("color").addContent("green"));
carElement.addContent(new Element("license")
    .addContent("1ABC234").addAttribute("state", "CA"));

license 엘리먼트의 경우, 엘리먼트의 콘텐트를 추가했을 뿐만 아니라, 여기에 애트리뷰트도 추가하면서, 라이센스가 발행되었던 상태를 지정하고 있다. Element에 대한 addContent 메소드는 Element만 리턴하기 때문에 이것이 가능하다.

주석 섹션이나 기타 표준 XML 유형을 추가하는 것도 같은 방식이다.


Listing 7. 주석 추가하기
                

carElement.addContent(new Comment("Description of a car"));

문서 조작은 비슷한 방식으로 발생한다. 예를 들어, year 엘리먼트에 대한 레퍼런스를 획득하려면, ElementgetChild 메소드를 사용한다.


Listing 8. 자식 엘리먼트에 액세스 하기
                

Element yearElement = carElement.getChild("year");

이 문은 실제로 엘리먼트 이름 year를 가진 자식 Element를 리턴한다. year 엘리먼트가 없다면, 호출은 어떤 것도 리턴하지 않는다. DOM Node Node 인터페이스 같은 것에서 리턴 값을 던질 필요가 없었다. Element의 자식 들은 단순히 Element이다. 비슷한 방식으로, 문서에서 year 엘리먼트를 제거할 수 있다.


Listing 9. 자식 엘리먼트 제거하기
                

boolean removed = carElement.removeChild("year");

이 호출은 year 엘리먼트만 제거한다. 나머지 문서는 바뀌지 않은 채로 남아있다.

엘리먼트만 제거한다. 나머지 문서는 바뀌지 않은 채로 남아있다. XMLOutputter 클래스를 사용한다.


Listing 10. JDOM을 XML 텍스트로 바꾸기
                

try {
    XMLOutputter outputter = new XMLOutputter("  ", true);
    outputter.output(myDocument, System.out);
} catch (java.io.IOException e) {
    e.printStackTrace();
}

XMLOutputter는 포맷팅 옵션을 갖고 있다. 여기에서, 우리는 부모 엘리먼트에서 두 스페이스를 들여쓰기 한 자식 엘리먼트를 원한다고 지정했고, 엘리먼트들 사이에 새로운 라인을 원한다는 것을 지정했다. XMLOutputterWriter 또는 OutputStream을 출력한다. 파일로 출력하려면 아웃풋 라인을 다음과 같이 바꾼다.


Listing 11. FileWriter를 사용하여 XML 출력하기
                

FileWriter writer = new FileWriter("/some/directory/myFile.xml");
outputter.output(myDocument, writer);
writer.close();




위로


기존 XML 툴과 결합하기

JDOM의 재미있는 기능들 중 하나는 다른 API들과의 상호 운용성이다. JDOM을 사용하여, Stream 또는 Reader 뿐만 아니라, SAX Event Stream 또는 DOM Document로서도 문서를 출력할 수 있다. 이러한 유연성 때문에 JDOM이 이종의 환경에서 사용될 수 있고, XML을 핸들링 하는 또 다른 메소드를 이미 사용하고 있는 시스템에 추가될 수 있다. 나중에 예제에서 보겠지만, JDOM은 JDOM 데이터 구조를 인식하지 못하는 다른 XML 툴을 사용할 수 있다.

JDOM의 또 다른 사용법은 이미 존재하는 XML 데이터를 읽고 조작하는 기능이다. 잘 구성된 XML 파일을 읽는 것은 org.jdom.input의 클래스들 중 하나를 사용함으로써 수행된다. 이 예제에서, 우리는 SAXBuilder를 사용할 것이다.


Listing 12. SAXBuilder를 사용하여 XML 파일 파싱하기
                

try {
  SAXBuilder builder = new SAXBuilder();
  Document anotherDocument = 
    builder.build(new File("/some/directory/sample.xml"));
} catch(JDOMException e) {
  e.printStackTrace();
} catch(NullPointerException e) {
  e.printStackTrace();
}

Listing 2부터 7까지의 방식과 똑같이 이 프로세스를 통해 구현된 문서를 조작할 수 있다.

JDOM의 또 다른 적용은 이를 Apache의 Xalan 제품과 결합하는 것이다. (참고자료) 위 자동차 예제를 사용하여, 특정 자동차에 대한 상세를 제공하는 온라인 자동차 딜러용 웹 페이지를 구현할 것이다. 우선, 이 문서는 우리가 사용자에게 제공하고자 하는 자동차에 대한 정보를 나타낸다. 그런 다음, 이 JDOM Document를 XSL 스타일 시트로 결합하고, HTML 포맷의 결과를 서블릿의 OutputStream으로 출력할 수 있다.

이 경우, 우리가 사용할 XSL 스타일시트는 car.xsl이다.


Listing 13. 자동차 기록을 HTML로 변형하는 XSL 문서
                

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/car">
    <html>
        <head>
          <title><xsl:value-of select="make"/> <xsl:value-of select="model"/>
        </head>
        <body>
          <h1><xsl:value-of select="make"/></h1><br />
          <h2><xsl:value-of select="model"/></h2><br />
          <table border="0">
          <tr><td>VIN:</td><td><xsl:value-of select="@vin"/></td></tr>
          <tr><td>Year:</td><td><xsl:value-of select="year"/></td></tr>
          <tr><td>Color:</td><td><xsl:value-of select="color"/></td></tr>
          </table>
        </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

이제, org.jdom.Document를 DOM Document로 바꾸고, 이것을 Xalan에 제공한다. XSL과 가상의 애플리케이션 서버에서 가져온 OutputStream을 나타내는 파일도 함께 제공한다. (Listing 14)


Listing 14. JDOM과 Xalan을 사용하여 HTML 문서 생성하기
                

TransformerFactory tFactory = TransformerFactory.newInstance();

// Make the input sources for the XML and XSLT documents
org.jdom.output.DOMOutputter outputter = new org.jdom.output.DOMOutputter();
org.w3c.dom.Document domDocument = outputter.output(myDocument);
javax.xml.transform.Source xmlSource = 
  new javax.xml.transform.dom.DOMSource(domDocument);
StreamSource xsltSource = 
  new StreamSource(new FileInputStream("/some/directory/car.xsl"));

// Make the output result for the finished document using 
// the HTTPResponse OutputStream
StreamResult xmlResult = new StreamResult(response.getOutputStream());

// Get a XSLT transformer
Transformer transformer = tFactory.newTransformer(xsltSource);

// Do the transform
transformer.transform(xmlSource, xmlResult);

이 예제에서, 아웃풋은 자바 서블릿의 HTTPResponse OutputStream을 통해 체계화 된다. 하지만, 이 스트림은 XMLOutputter를 사용한 이전 예제처럼 쉽게 파일스트림이 될 수 있다. 우리는 DOMOutputter를 사용하여 Xalan용 XML 소스를 생성했다. 하지만, XMLOutputter를 사용하여 XML 문서를 String으로서 출력하고 이를 StreamSource로 만듦으로써 같은 인풋을 생성할 수 있었다. 유연성에 대해서 보자. JDOM은 그 구조를 String, SAX Event Stream, 또는 DOM Document로서 출력할 수 있다. 이는 JDOM이 인풋으로서 이러한 모델을 취할 수 있는 툴과 상호 작동할 수 있도록 해준다. (JDOM 웹 사이트에서 contrib 패키지를 참조하라. 여기에서 JDBC ResultSet-기반 빌더, XPATH 구현 같은 툴을 제공하는 JDOM 기반 유틸리티의 라이브러리를 찾을 수 있다.)

몇 줄의 코드로, JDOM은 다양한 기능을 실행한다. 우리는 XML에서 파싱하고 프로그래밍 방식으로 XML 문서를 생성하고, 그러한 문서들을 조작했고, XML 중심의 웹 페이지를 생성하는데 이를 사용했다.

int to String
String str = Integer.toString(i);
String str = "" + i;


String to int
int i = Integer.parseInt(str);
int i = Integer.valueOf(str).intValue();


double to String
String str = Double.toString(d);


long to String
String str = Long.toString(l);


float to String
String str = Float.toString(f);


String to double
double d = Double.valueOf(str).doubleValue();


String to long
long l = Long.valueOf(str).longValue();
long l = Long.parseLong(str);


String to float
float f = Float.valueOf(str).floatValue();


decimal to binary
String binstr = Integer.toBinaryString(i);


decimal to hexadecimal
String hexstr = Integer.toString(i, 16);
String hexstr = Integer.toHexString(i);
Integer.toHexString( 0x10000 | i).substring(1).toUpperCase());


hexadecimal(String) to int
int i = Integer.valueOf("B8DA3", 16).intValue();
int i = Integer.parseInt("B8DA3", 16);


ASCII Code to String
String char = new Character((char)i).toString();


Integer to ASCII Code
int i = (int) c;


Integer to boolean
boolean b = (i != 0);


boolean to Integer
int i = (b)? 1 : 0;