'01.JAVA/Java'에 해당되는 글 199건

  1. 2008.11.12 INETADDRESS를 이용한 호스트 이름 검색(룩업) 및 호스트 도달 능력
  2. 2008.11.12 CookieHandler를 이용한 쿠키 관리
  3. 2008.11.12 java swing table 정렬 및 필터링
  4. 2008.11.12 캐치되지 않은 예외 캐치하기
  5. 2008.11.12 Java SE의 정규 표현식
  6. 2008.11.12 java 에서 쿠키 처리
  7. 2008.11.12 문자열 정렬
  8. 2008.11.12 경량화 DB의 꿈 JavaDB
  9. 2008.11.12 JDBC 연습하기
  10. 2008.11.12 JAVA 트랜잭션 API 소개
  11. 2008.11.12 자바 기술을 이용한 AJAX의 활용
  12. 2008.11.12 향상된 루프문
  13. 2008.11.11 html 파싱...
  14. 2008.11.10 시작하는 JAVA프로그래머를 위해 자바강좌 (특히 비 전공자분들께)
  15. 2008.11.05 class 파일 내부 들여다 보기
  16. 2008.11.05 String 더하기 보다 StringBuffer append가 빠르다!?"
  17. 2008.10.27 java.lang.OutOfMemoryError
  18. 2008.10.27 java.lang.OutOfMemoryError: PermGen space 1
  19. 2008.10.27 예외 문제 해결: System.StackOverflowException
  20. 2008.10.27 복구할 수 없는 StackOverFlow
  21. 2008.10.10 James mail server 설치
  22. 2008.10.10 JavaMail
  23. 2008.09.17 java 환경설정 1
  24. 2008.08.28 java.lang.UnsupportedClassVersionError
  25. 2008.08.25 FCKeditor java 버전 설치
  26. 2008.08.20 자바 Security 알고리즘 보기 1
  27. 2008.08.20 서버이전시 생긴 문제!!! <<org.apache.jasper.JasperException: Unable to compile class for JSP>>
  28. 2008.08.20 자바에러메세지정리
  29. 2008.08.19 java에서 properties 활용 가이드 라인
  30. 2008.08.19 파일이 어떤 포맷인지 알아볼때..
01.JAVA/Java2008. 11. 12. 17:24
반응형

InetAddress 클래스는 자바 플랫폼이 처음 출시된 이래로 줄곧 사용되어 왔으며, 이 클래스의 역할은 인터넷 프로토콜(IP) 주소를 통해 호스트의 ID를 알려주는 것이다. 다시 말해서, 가령 yahoo.com 같은 이름을 입력하면 InetAddress 클래스의 도움으로 그 IP 주소를 알아낼 수 있다.

InetAddress 클래스 디자인은 다소 기묘해 보일 수도 있다. 클래스에는 static 선언만 있고 public 생성자가 없으며, 인스턴스는 불변, 즉 일단 클래스의 인스턴스를 가지면 변경할 수 없다. 하지만 그 디자인은 자바 보안의 목적을 위한 것으로서 사용자는 검색 간의 결과를 변경할 수 없다.

다음은 InetAddress 클래스의 사용 예제이다. 아래의 프로그램 Lookup은 명령어 라인에서 전달하는 아규먼트의 이름과 IP 주소를 알려준다.

   import java.net.*;

   public class Lookup {

     public static void main(String args[]) {
       for (String name: args) {
         try {
           InetAddress address = InetAddress.getByName(name);
           System.out.println("Name: " + address.getHostName());
           System.out.println("Addr: " + address.getHostAddress());
         } catch (UnknownHostException e) {
           System.err.println("Unable to lookup " + name);
         }
       }
     }
   }

이 프로그램에서 getByName() 메소드는 Microsoft Windows와 Unix의 nslookup 명령어와 같은 역할을 한다. 명령어 라인 아규먼트에 지정된 이름을 가져온 다음, 시스템에 지정된 네임 서버에서 룩업을 수행한다. 룩업을 수행할 때는 일반적으로 도메인 네임 시스템(DNS)을 이용한다. 룩업 작업은 yahoo.com 같은 이름이나 66.94.234.13 같은 IP 주소를 대상으로 이루어지는데, yahoo.com을 입력하면 66.94.234.13을 얻게 되고, 66.94.234.13을 입력하면 Yahoo의 호스트 팜(farm) 이름 목록을 얻게 된다. 이 경우 호스트의 퍼블릭 이름은 w2.rc.vip.scd.yahoo.com이다.

   > java Lookup sun.com yahoo.com 66.94.234.13

     Name: sun.com
     Addr: 209.249.116.195
     Name: yahoo.com
     Addr: 216.109.112.135
     Name: w2.rc.vip.scd.yahoo.com
     Addr: 66.94.234.13
	 

일부 호스트 이름은 복수의 IP 주소로 변환된다. InetAddressgetByName() 메소드를 이용해서 하나의 이름을 룩업하는 대신 getAllByName() 메소드를 이용하여 일련의 InetAddress 오브젝트를 얻어낼 수 있다.

아울러, InetAddress 클래스는 역순 이름 해석을 지원한다. 이는 특정 호스트에 대해 IP 주소를 룩업한 다음 그 IP 주소를 이용하여 호스트 이름을 룩업할 수 있음을 의미한다. 두 가지가 일치하지 않더라도 이것이 반드시 잘못되었다고 볼 수는 없겠지만, 만약 이 두 가지가 일치해야 하고 여러분이 그 사실을 알고 있는 상태라면 불일치 현상은 스푸핑 공격의 징후로 간주될 수 있다.

아래의 LookupAll 프로그램은 getAllByName() 메소드를 이용하여 호스트에 대한 모든 주소를 룩업한다. 그런 다음 getCanonicalHostName() 메소드를 이용하여 호스트에 대해 완전한 자격을 갖춘 도메인 이름을 룩업한다.

   import java.net.*;

   public class LookupAll {
     public static void main(String args[]) {
       for (String name: args) {
         try {
           InetAddress address[] = 
               InetAddress.getAllByName(name);
           for (InetAddress each: address) {
             System.out.println("Name: " + each.getHostName());
             System.out.println("Addr: " + 
                 each.getHostAddress());
             System.out.println("Canonical: " + 
                 each.getCanonicalHostName());
           }
           System.out.println("----");
         } catch (UnknownHostException e) {
           System.err.println("Unable to lookup " + name);
         }
       }
     }
   }

복수의 주소를 가지는 호스트의 하나로 google.com을 들 수 있는데, 다음 예제에는 google.com과 yahoo.com이 아규먼트로 포함되어 있다. 예제는 어떻게 yahoo.com에 대한 IP 주소의 역 룩업이 다른 호스트 이름으로 해석되는지를 잘 보여주고 있다.

   >> java LookupAll yahoo.com google.com

      Name: yahoo.com
      Addr: 216.109.112.135
      Canonical: w2.rc.vip.dcn.yahoo.com
      Name: yahoo.com
      Addr: 66.94.234.13
      Canonical: w2.rc.vip.scd.yahoo.com
      ----
      Name: google.com
      Addr: 216.239.39.99
      Canonical: 216.239.39.99
      Name: google.com
      Addr: 216.239.57.99
      Canonical: 216.239.57.99
      Name: google.com
      Addr: 216.239.37.99
      Canonical: 216.239.37.99
      ----

J2SE 플랫폼의 1.4 버전에는 getCanonicalHostName() 메소드가 추가되었다.

J2SE 5.0에서는 InetAddress를 이용하여 호스트의 도달 능력(reachability)을 확인할 수도 있다. 다시 말해서 호스트가 ‘살아있는지(즉, 활성화되어있는지)’의 여부를 결정할 수 있는 것이다. 이 테스트는 일반적으로 명령어 라인에서 ‘ping’ 명령어나 간단한 TCP ECHO 요청을 통해 수행된다. 그러나, 가령 2005년 9월 13일자 테크팁 Runtime.exe에서 ProcessBuilder까지 에서 설명했던 ProcessBuilder 클래스를 이용하여 굳이 명령어 라인 프롬프트를 열어야 할 필요가 있을까라는 질문을 던져본다. 그 대신 우리는 InetAddress에서 isReachable() 메소드를 이용하기만 하면 된다.

isReachable() 메소드에는 다음 두 가지 형태가 있다:

  • public boolean isReachable(int timeout) throws IOException
  • public boolean isReachable(NetworkInterface netif, int ttl, int timeout) throws IOException

대부분의 경우에는 첫 번째 버전의 isReachable로도 충분하다. 이 포맷에서는 단순히 검사(check)를 위한 타임아웃을 제공하는데, 타임아웃은 대상 호스트가 살아있는지 알아보기 위해 기다려야 하는 밀리초의 수를 나타낸다. 호스트가 죽어있으면 메소드는 ‘false’를 반환하고 핑 서비스는 사용 불능 상태로 되거나 요청은 방화벽에서 차단된다. 도달 가능한 호스트를 찾을 경우에는 메소드는 ‘true’를 반환하고, 네트워크 오류가 발행할 경우에는 메소드는 IOException을 전달한다

두 번째 버전의 isReachable은 테스트에 어떤 NetworkInterface를 이용할지 확인할 수 있게 해준다. 또한 특정 호스트에 도달하기 위해 시도하는 최대 호프(hop) 수를 지정할 수도 있다. 하나의 네트워크 인터페이스만을 가지고 있지만 호프 수를 지정하고자 한다면 임의의 인터페이스에 대해 null을 전달하면 된다. 첫 번째 버전의 isReachable과 마찬가지로, 타임아웃 값도 지정한다. 이 버전의 isReachable에서 가능한 반환 값은 원(1) 아규먼트 버전의 경우와 동일하다.

다음 프로그램 LookupReach는 이전의 단일 이름 룩업에 도달 가능 검사(check)를 추가한다.

   import java.io.*;
   import java.net.*;

   public class LookupReach {
     public static void main(String args[]) {
       for (String name: args) {
         try {
           InetAddress address = InetAddress.getByName(name);
           System.out.println("Name: " + address.getHostName());
           System.out.println("Addr: " + 
               address.getHostAddress());
           System.out.println("Reach: " + 
               address.isReachable(3000));
         } catch (UnknownHostException e) {
           System.err.println("Unable to lookup " + name);
         } catch (IOException e) {
           System.err.println("Unable to reach " + name);
         }
       }
     }
   }

yahoo.com, sun.com, goole.com 등을 아규먼트로 하여 LookupReach를 실행해 본다. 프로그램이 ‘false’를 반환하는 것을 보게 될 것이다. 거대 웹 기업들은 대부분 자사의 인터넷 사이트에서 이 서비스를 사용 불능으로 하거나 요청을 차단하고 있다. 다시 web.mit.edu 같은 대학교 사이트에 대한 아규먼트로 프로그램을 실행해 본다. 대부분의 대학교 사이트는 요청을 허용한다.

   > java LookupReach yahoo.com sun.com google.com web.mit.edu
   
     Name: yahoo.com
     Addr: 216.109.112.135
     Reach: false
     Name: sun.com
     Addr: 209.249.116.195
     Reach: false
     Name: google.com
     Addr: 216.239.37.99
     Reach: false
     Name: web.mit.edu
     Addr: 18.7.22.69
     Reach: true

InetAddress 클래스를 이용할 때는 일반적으로 사용되는 a.b.c.d. 형태로 된 IPv4 이름을 지정할 수 있다는 것을 염두에 두어야 한다. 또한 더 최근의 x:x:x:x:x:x:x:x형태로 이루어진 IPv6 이름도 지정할 수 있는데, 여기서 ‘x’는 8개의 16비트 주소에 대한 헥스(hex) 값이다. IPv6 아키텍처에 관한 자세한 내용은 RFC 2373을 참조하도록 한다.

이름이 어떤 버전을 나타내는지 확실치 않으면 InetAddressInet4Address 또는 Inet6Address의 인스턴스인지 확인하면 되는데, 이 작업은 주로 사용자가 제공한 주소에 대해서 수행된다.

마지막으로 짚고 넘어가야 한 사항은 이름 룩업과 역 룩업은 비용이 많이 드는 연산이라는 점이다. 시스템은 성능과 보안의 두 가지 이유에서 캐시 메커니즘을 이용한다. 일단 호스트를 룩업하면 동일한 결과를 얻게 되고 룩업 간에 결과를 변경할 수 없다는 점을 여러분은 잘 알고 있을 것이다.

"Java SE" 카테고리의 다른 글

Posted by 1010
01.JAVA/Java2008. 11. 12. 17:24
반응형

자바 플랫폼의 경우, URL을 통한 오브젝트 액세스는 일련의 프로토콜 핸들러에 의해 관리된다. URL의 첫 부분은 사용되는 프로토콜을 알려주는데, 예를 들어 URL이 file:로 시작되면 로컬 파일 시스템 상에서 리소스를 액세스할 수 있다. 또, URL이 http:로 시작되면 인터넷을 통해 리소스 액세스가 이루어진다. 한편, J2SE 5.0은 시스템 내에 반드시 존재해야 하는 프로토콜 핸들러(http, https, file, ftp, jar 등)를 정의한다.

J2SE 5.0은 http 프로토콜 핸들러 구현의 일부로 CookieHandler를 추가하는데, 이 클래스는 쿠키를 통해 시스템 내에서 상태(state)가 어떻게 관리될 수 있는지를 보여준다. 쿠키는 브라우저의 캐시에 저장된 데이터의 단편이며, 한번 방문한 웹 사이트를 다시 방문할 경우 쿠키 데이터를 이용하여 재방문자임을 식별한다. 쿠키는 가령 온라인 쇼핑 카트 같은 상태 정보를 기억할 수 있게 해준다. 쿠키에는 브라우저를 종료할 때까지 단일 웹 세션 동안 데이터를 보유하는 단기 쿠키와 1주 또는 1년 동안 데이터를 보유하는 장기 쿠키가 있다.

J2SE 5.0에서 기본값으로 설치되는 핸들러는 없으나, 핸들러를 등록하여 애플리케이션이 쿠키를 기억했다가 http 접속 시에 이를 반송하도록 할 수는 있다.

CookieHandler 클래스는 두 쌍의 관련 메소드를 가지는 추상 클래스이다. 첫 번째 쌍의 메소드는 현재 설치된 핸들러를 찾아내고 각자의 핸들러를 설치할 수 있게 한다.

  • getDefault()
  • setDefault(CookieHandler)

보안 매니저가 설치된 애플리케이션의 경우, 핸들러를 얻고 이를 설정하려면 특별 허가를 받아야 한다. 현재의 핸들러를 제거하려면 핸들러로 null을 입력한다. 또한 앞서 얘기했듯이 기본값으로 설정되어 있는 핸들러는 없다.

두 번째 쌍의 메소드는 각자가 관리하는 쿠키 캐시로부터 쿠키를 얻고 이를 설정할 수 있게 한다.

  • get(URI uri, Map<String, List<String>> requestHeaders)
  • put(URI uri, Map<String, List<String>> responseHeaders)

get() 메소드는 캐시에서 저장된 쿠기를 검색하여 requestHeaders를 추가하고, put() 메소드는 응답 헤더에서 쿠키를 찾아내어 캐시에 저장한다.

여기서 보듯이 핸들러를 작성하는 일은 실제로는 간단하다. 그러나 캐시를 정의하는 데는 약간의 추가 작업이 더 필요하다. 일례로, 커스텀 CookieHandler, 쿠키 캐시, 테스트 프로그램을 사용해 보기로 하자. 테스트 프로그램은 아래와 같은 형태를 띠고 있다.

   import java.io.*;
   import java.net.*;
   import java.util.*;

   public class Fetch {
     public static void main(String args[]) throws Exception {
       if (args.length == 0) {
         System.err.println("URL missing");
         System.exit(-1);
       }
       String urlString = args[0];
       CookieHandler.setDefault(new ListCookieHandler());
       URL url = new URL(urlString);
       URLConnection connection = url.openConnection();
       Object obj = connection.getContent();
       url = new URL(urlString);
       connection = url.openConnection();
       obj = connection.getContent();
     }
   }

먼저 이 프로그램은 간략하게 정의될 ListCookieHandler를 작성하고 설치한다. 그런 다음 URL(명령어 라인에서 입력)의 접속을 열어 내용을 읽는다. 이어서 프로그램은 또 다른 URL의 접속을 열고 동일한 내용을 읽는다. 첫 번째 내용을 읽을 때 응답에는 저장될 쿠키가, 두 번째 요청에는 앞서 저장된 쿠키가 포함된다.

이제 이것을 관리하는 방법에 대해 알아보기로 하자. 처음에는 URLConnection 클래스를 이용한다. 웹 상의 리소스는 URL을 통해 액세스할 수 있으며, URL 작성 후에는 URLConnection 클래스의 도움을 받아 사이트와의 통신을 위한 인풋 또는 아웃풋 스트림을 얻을 수 있다.

   String urlString = ...;
   URL url = new URL(urlString);
   URLConnection connection = url.openConnection();
   InputStream is = connection.getInputStream();
   // .. read content from stream

접속으로부터 이용 가능한 정보에는 일련의 헤더들이 포함될 수 있는데, 이는 사용중인 프로토콜에 의해 결정된다. 헤더를 찾으려면 URLConnection 클래스를 사용하면 된다. 한편, 클래스는 헤더 정보 검색을 위한 다양한 메소드를 가지는데, 여기에는 다음 사항들이 포함된다.

  • getHeaderFields() - 가용한 필드의 Map을 얻는다.
  • getHeaderField(String name) - 이름 별로 헤더 필드를 얻는다.
  • getHeaderFieldDate(String name, long default) - 날짜로 된 헤더 필드를 얻는다.
  • getHeaderFieldInt(String name, int default) - 숫자로 된 헤더 필드를 얻는다.
  • getHeaderFieldKey(int n) or getHeaderField(int n) - 위치 별로 헤더 필드를 얻는다.

일례로, 다음 프로그램은 주어진 URL의 모든 헤더를 열거한다

   import java.net.*;
   import java.util.*;

   public class ListHeaders {
     public static void main(String args[]) throws Exception {
       if (args.length == 0) {
         System.err.println("URL missing");
       }
       String urlString = args[0];
       URL url = new URL(urlString);
       URLConnection connection = url.openConnection();
       Map<String,List<String>> headerFields = 
         connection.getHeaderFields();
       Set<String> set = headerFields.keySet();
       Iterator<String> itor = set.iterator();
       while (itor.hasNext()) {
         String key = itor.next();
         System.out.println("Key: " + key + " / " + 
           headerFields.get(key));
       }
     }
   }

ListHeaders 프로그램은 가령 http://java.sun.com 같은 URL을 아규먼트로 취하고 사이트로부터 수신한 모든 헤더를 표시한다. 각 헤더는 아래의 형태로 표시된다.

   Key: <key> / [<value>]

따라서 다음을 입력하면,

  >> java ListHeaders http://java.sun.com

다음과 유사한 내용이 표시되어야 한다.

   Key: Set-Cookie / [SUN_ID=192.168.0.1:269421125489956; 
   EXPIRES=Wednesday, 31- Dec-2025 23:59:59 GMT; 
   DOMAIN=.sun.com; PATH=/]
   Key: Set-cookie / 
   [JSESSIONID=688047FA45065E07D8792CF650B8F0EA;Path=/]
   Key: null / [HTTP/1.1 200 OK]
   Key: Transfer-encoding / [chunked]
   Key: Date / [Wed, 31 Aug 2005 12:05:56 GMT]
   Key: Server / [Sun-ONE-Web-Server/6.1]
   Key: Content-type / [text/html;charset=ISO-8859-1]   

(위에 표시된 결과에서 긴 행은 수동으로 줄바꿈한 것임)

이는 해당 URL에 대한 헤더들만을 표시하며, 그곳에 위치한 HTML 페이지는 표시하지 않는다. 표시되는 정보에는 사이트에서 사용하는 웹 서버와 로컬 시스템의 날짜 및 시간이 포함되는 사실에 유의할 것. 아울러 2개의 ‘Set-Cookie’ 행에도 유의해야 한다. 이들은 쿠키와 관련된 헤더들이며, 쿠키는 헤더로부터 저장된 뒤 다음의 요청과 함께 전송될 수 있다.

이제 CookieHandler를 작성해 보자. 이를 위해서는 두 추상 메소드 CookieHandler: get() 과ㅓ put()을 구현해야 한다.

  •   public void put(
        URI uri,
        Map<String, List<String>> responseHeaders)
          throws IOException
    
  •   public Map<String, List<String>> get(
        URI uri,
        Map<String, List<String>> requestHeaders)
          throws IOException
    

우선 put() 메소드로 시작한다. 이 경우 응답 헤더에 포함된 모든 쿠키가 캐시에 저장된다.put()을 구현하기 위해서는 먼저 ‘Set-Cookie’ 헤더의 List를 얻어야한다. 이는 Set-cookieSet-Cookie2 같은 다른 해당 헤더로 확장될 수 있다.

   List<String> setCookieList =
     responseHeaders.get("Set-Cookie");

쿠키의 리스트를 확보한 후 각 쿠키를 반복(loop)하고 저장한다. 쿠키가 이미 존재할 경우에는 기존의 것을 교체하도록 한다.

    if (setCookieList != null) {
      for (String item : setCookieList) {
        Cookie cookie = new Cookie(uri, item);
        // Remove cookie if it already exists in cache
        // New one will replace it
        for (Cookie existingCookie : cache) {
          ...
        }
        System.out.println("Adding to cache: " + cookie);
        cache.add(cookie);
      }
    }

여기서 ‘캐시’는 데이터베이스에서 Collections Framework에서 List에 이르기까지 어떤 것이든 될 수 있다. Cookie 클래스는 나중에 정의되는데, 이는 사전 정의되는 클래스에 속하지 않는다.

본질적으로, 그것이 put() 메소드에 대해 주어진 전부이며, 응답 헤더 내의 각 쿠키에 대해 메소드는 쿠키를 캐시에 저장한다.

get() 메소드는 정반대로 작동한다. URI에 해당되는 캐시 내의 각 쿠키에 대해, get() 메소드는 이를 요청 헤더에 추가한다. 복수의 쿠키에 대해서는 콤마로 구분된(comma-delimited) 리스트를 작성한다. get() 메소드는 맵을 반환하며, 따라서 메소드는 기존의 헤더 세트로 Map 아규먼트를 취하게 된다. 그 아규먼트에 캐시 내의 해당 쿠키를 추가해야 하지만 아규먼트는 불변의 맵이며, 또 다른 불변의 맵을 반환해야만 한다. 따라서 기존의 맵을 유효한 카피에 복사한 다음 추가를 마친 후 불변의 맵을 반환해야 한다.

get() 메소드를 구현하기 위해서는 먼저 캐시를 살펴보고 일치하는 쿠키를 얻은 다음 만료된 쿠키를 모두 제거하도록 한다.

    // Retrieve all the cookies for matching URI
    // Put in comma-separated list
    StringBuilder cookies = new StringBuilder();
    for (Cookie cookie : cache) {
      // Remove cookies that have expired
      if (cookie.hasExpired()) {
        cache.remove(cookie);
      } else if (cookie.matches(uri)) {
        if (cookies.length() > 0) {
          cookies.append(", ");
        }
        cookies.append(cookie.toString());
      }
    }

이 경우에도 Cookie 클래스는 간략하게 정의되는데, 여기에는 hasExpired()matches() 등 2개의 요청된 메소드가 표시되어 있다. hasExpired() 메소드는 특정 쿠키의 만료 여부를 보고하고, matches() 메소드는 쿠키가 메소드에 패스된 URI에 적합한지 여부를 보고한다.

get() 메소드의 다음 부분은 작성된 StringBuilder 오브젝트를 취하고 그 스트링필드 버전을 수정 불가능한 Map에 put한다(이 경우에는 해당 키 ‘Cookie’를 이용).

    // Map to return
    Map<String, List<String>> cookieMap =
      new HashMap<String, List<String>>(requestHeaders);

    // Convert StringBuilder to List, store in map
    if (cookies.length() > 0) {
      List<String> list =
        Collections.singletonList(cookies.toString());
      cookieMap.put("Cookie", list);
    }
    return Collections.unmodifiableMap(cookieMap);

다음은 런타임의 정보 표시를 위해 println이 일부 추가되어 완성된 CookieHandler 정의이다.

   import java.io.*;
   import java.net.*;
   import java.util.*;

   public class ListCookieHandler extends CookieHandler {

     // "Long" term storage for cookies, not serialized so only
     // for current JVM instance
     private List<Cookie> cache = new LinkedList<Cookie>();

     /**
      * Saves all applicable cookies present in the response 
      * headers into cache.
      * @param uri URI source of cookies
      * @param responseHeaders Immutable map from field names to 
      * lists of field
      *   values representing the response header fields returned
      */

     public void put(
         URI uri,
         Map<String, List<String>> responseHeaders)
           throws IOException {

       System.out.println("Cache: " + cache);
       List<String> setCookieList = 
         responseHeaders.get("Set-Cookie");
       if (setCookieList != null) {
         for (String item : setCookieList) {
           Cookie cookie = new Cookie(uri, item);
           // Remove cookie if it already exists
           // New one will replace
           for (Cookie existingCookie : cache) {
             if((cookie.getURI().equals(
               existingCookie.getURI())) &&
                (cookie.getName().equals(
                  existingCookie.getName()))) {
              cache.remove(existingCookie);
              break;
            }
          }
          System.out.println("Adding to cache: " + cookie);
          cache.add(cookie);
        }
      }
    }

    /**
     * Gets all the applicable cookies from a cookie cache for 
     * the specified uri in the request header.
     *
     * @param uri URI to send cookies to in a request
     * @param requestHeaders Map from request header field names 
     * to lists of field values representing the current request 
     * headers
     * @return Immutable map, with field name "Cookie" to a list 
     * of cookies
     */

    public Map<String, List<String>> get(
        URI uri,
        Map<String, List<String>> requestHeaders)
          throws IOException {

      // Retrieve all the cookies for matching URI
      // Put in comma-separated list
      StringBuilder cookies = new StringBuilder();
      for (Cookie cookie : cache) {
        // Remove cookies that have expired
        if (cookie.hasExpired()) {
          cache.remove(cookie);
        } else if (cookie.matches(uri)) {
          if (cookies.length() > 0) {
            cookies.append(", ");
          }
          cookies.append(cookie.toString());
        }
      }

      // Map to return
      Map<String, List<String>> cookieMap =
        new HashMap<String, List<String>>(requestHeaders);

      // Convert StringBuilder to List, store in map
      if (cookies.length() > 0) {
        List<String> list =
          Collections.singletonList(cookies.toString());
        cookieMap.put("Cookie", list);
      }
        System.out.println("Cookies: " + cookieMap);
    return Collections.unmodifiableMap(cookieMap);
    }
  }

퍼즐의 마지막 조각은 Cookie 클래스 그 자체이며, 대부분의 정보는 생성자(constructor) 내에 존재한다. 생성자 내의 정보 조각(비트)들을 uri 및 헤더 필드로부터 파싱해야 한다. 만료일에는 하나의 포맷이 사용되어야 하지만 인기 있는 웹 사이트에서는 복수의 포맷이 사용되는 경우를 볼 수 있다. 여기서는 그다지 까다로운 점은 없고, 쿠키 경로, 만료일, 도메인 등과 같은 다양한 정보 조각을 저장하기만 하면 된다.

   public Cookie(URI uri, String header) {
     String attributes[] = header.split(";");
     String nameValue = attributes[0].trim();
     this.uri = uri;
     this.name = nameValue.substring(0, nameValue.indexOf('='));
     this.value = nameValue.substring(nameValue.indexOf('=')+1);
     this.path = "/";
     this.domain = uri.getHost();

     for (int i=1; i < attributes.length; i++) {
       nameValue = attributes[i].trim();
       int equals = nameValue.indexOf('=');
       if (equals == -1) {
         continue;
       }
       String name = nameValue.substring(0, equals);
       String value = nameValue.substring(equals+1);
       if (name.equalsIgnoreCase("domain")) {
         String uriDomain = uri.getHost();
         if (uriDomain.equals(value)) {
           this.domain = value;
         } else {
           if (!value.startsWith(".")) {
             value = "." + value;
           }
           uriDomain = 
             uriDomain.substring(uriDomain.indexOf('.'));
           if (!uriDomain.equals(value)) {
             throw new IllegalArgumentException(
               "Trying to set foreign cookie");
           }
           this.domain = value;
         }
       } else if (name.equalsIgnoreCase("path")) {
         this.path = value;
       } else if (name.equalsIgnoreCase("expires")) {
         try {
           this.expires = expiresFormat1.parse(value);
         } catch (ParseException e) {
           try {
             this.expires = expiresFormat2.parse(value);
           } catch (ParseException e2) {
             throw new IllegalArgumentException(
               "Bad date format in header: " + value);
           }
         }
       }
     }
  }

클래스 내의 다른 메소드들은 단지 저장된 데이터를 반환하거나 만료 여부를 확인한다.

   public boolean hasExpired() {
     if (expires == null) {
       return false;
     }
     Date now = new Date();
     return now.after(expires);
   }

   public String toString() {
     StringBuilder result = new StringBuilder(name);
     result.append("=");
     result.append(value);
     return result.toString();
   }

쿠키가 만료된 경우에는 ‘match’가 표시되면 안 된다.

   public boolean matches(URI uri) {

     if (hasExpired()) {
       return false;
     }

     String path = uri.getPath();
     if (path == null) {
       path = "/";
     } 

     return path.startsWith(this.path);
   }

Cookie 스펙이 도메인과 경로 양쪽에 대해 매치를 수행할 것을 요구한다는 점에 유의해야 한다. 단순성을 위해 여기서는 경로 매치만을 확인한다.

아래는 전체 Cookie 클래스의 정의이다.

   import java.net.*;
   import java.text.*;
   import java.util.*;

   public class Cookie {

     String name;
     String value;
     URI uri;
     String domain;
     Date expires;
     String path;

     private static DateFormat expiresFormat1
         = new SimpleDateFormat("E, dd MMM yyyy k:m:s 'GMT'", Locale.US);

     private static DateFormat expiresFormat2
        = new SimpleDateFormat("E, dd-MMM-yyyy k:m:s 'GMT'", Local.US);
		

     /**
      * Construct a cookie from the URI and header fields
      *
      * @param uri URI for cookie
      * @param header Set of attributes in header
      */
     public Cookie(URI uri, String header) {
       String attributes[] = header.split(";");
       String nameValue = attributes[0].trim();
       this.uri = uri;
       this.name = 
         nameValue.substring(0, nameValue.indexOf('='));
       this.value = 
         nameValue.substring(nameValue.indexOf('=')+1);
       this.path = "/";
       this.domain = uri.getHost();

       for (int i=1; i < attributes.length; i++) {
         nameValue = attributes[i].trim();
         int equals = nameValue.indexOf('=');
         if (equals == -1) {
           continue;
         }
         String name = nameValue.substring(0, equals);
         String value = nameValue.substring(equals+1);
         if (name.equalsIgnoreCase("domain")) {
           String uriDomain = uri.getHost();
           if (uriDomain.equals(value)) {
             this.domain = value;
           } else {
             if (!value.startsWith(".")) {
               value = "." + value;
             }
             uriDomain = uriDomain.substring(
               uriDomain.indexOf('.'));
             if (!uriDomain.equals(value)) {
               throw new IllegalArgumentException(
                 "Trying to set foreign cookie");
             }
             this.domain = value;
           }
         } else if (name.equalsIgnoreCase("path")) {
           this.path = value;
         } else if (name.equalsIgnoreCase("expires")) {
           try {
             this.expires = expiresFormat1.parse(value);
           } catch (ParseException e) {
             try {
               this.expires = expiresFormat2.parse(value);
             } catch (ParseException e2) {
               throw new IllegalArgumentException(
                 "Bad date format in header: " + value);
             }
           }
         }
       }
     }

     public boolean hasExpired() {
       if (expires == null) {
         return false;
       }
       Date now = new Date();
       return now.after(expires);
     }

     public String getName() {
       return name;
     }

     public URI getURI() {
       return uri;
     }

     /**
      * Check if cookie isn't expired and if URI matches,
      * should cookie be included in response.
      *
      * @param uri URI to check against
      * @return true if match, false otherwise
      */
     public boolean matches(URI uri) {

       if (hasExpired()) {
         return false;
       }

      String path = uri.getPath();
       if (path == null) {
         path = "/";
       }

       return path.startsWith(this.path);
     }

     public String toString() {
       StringBuilder result = new StringBuilder(name);
       result.append("=");
       result.append(value);
       return result.toString();
     }
   }

이제 조각들이 모두 확보되었으므로 앞의 Fetch 예제를 실행할 수 있다.

   >> java Fetch http://java.sun.com

   Cookies: {Connection=[keep-alive], Host=[java.sun.com], 
    User-Agent=[Java/1.5.0_04], GET / HTTP/1.1=[null], 
    Content-type=[application/x-www-form-urlencoded], 
    Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2]}
   Cache: []
   Adding to cache: SUN_ID=192.168.0.1:235411125667328
   Cookies: {Connection=[keep-alive], Host=[java.sun.com], 
    User-Agent=[Java/1.5.0_04], GET / HTTP/1.1=[null], 
    Cookie=[SUN_ID=192.168.0.1:235411125667328], 
    Content-type=[application/x-www-form-urlencoded], 
    Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2]}
   Cache: [SUN_ID=192.168.0.1:235411125667328]

(위에 표시된 결과에서 긴 행은 수동으로 줄바꿈한 것임)

‘Cache’로 시작되는 행은 저장된 캐시를 나타낸다. 저장된 쿠키가 즉시 반환되지 않도록 put() 메소드 전에 get() 메소드가 어떻게 호출되는지에 대해 유의하도록 할 것.

쿠키와 URL 접속을 이용한 작업에 관해 자세히 알고 싶으면 자바 튜토리얼의 Custom Networking trail(영문)을 참조할 것. 이는 J2SE 1.4에 기반을 두고 있으므로 튜토리얼에는 아직 여기서 설명한 CookieHandler에 관한 정보가 실려 있지 않다. Java SE 6 ("Mustang")(영문) 릴리즈에서도 기본 CookieHandler 구현에 관한 내용을 찾아볼 수 있다.

"Java SE" 카테고리의 다른 글

Posted by 1010
01.JAVA/Java2008. 11. 12. 17:23
반응형

Java SE 6.0(코드명 Mustang)에는 Swing JTable의 내용을 훨씬 쉽게 정렬하고 필터링할 수 있게 해주는 몇 가지 기능이 추가된다. (이 기능들이 최종적으로 포함되려면 JCP의 승인을 거쳐야 한다.) 최근의 테이블 중심 사용자 인터페이스는 대부분 사용자가 테이블 헤더를 클릭하여 칼럼을 정렬할 수 있도록 되어 있는데, 이는 Mustang 이전에 Swing JTable 지원을 통해 가능하게 되었다. 이 기능을 필요로 하는 각 테이블에 일일이 수동으로 기능을 추가해 주어야만 하는 불편이 따랐지만 Mustang은 최소한의 노력으로 이 기능을 사용할 수 있도록 해준다. 필터링은 사용자 인터페이스에서 일반적으로 이용할 수 있는 또 다른 옵션으로서, 테이블 내에서 사용자가 제공하는 기준에 부합하는 행만을 디스플레이할 수 있게 해준다. Mustang을 이용하면 JTable 컨텐츠 필터링이 훨씬 용이해진다.

행 정렬하기

Mustang에서 행을 정렬하고 필터링하는 기준이 되는 것이 바로 추상 RowSorter 클래스로서, 이 RowSorter는 두 가지 매핑-JTable 내의 한 행을 기본 모델의 엘리먼트로, 그리고 다시 반대로-을 유지한다. 이는 하나의 행이 정렬과 필터링을 수행할 수 있게 해준다. 이 클래스는 TableModelListModel 모두에 적용될 만큼 포괄적이긴 하지만 TableRowSorter에만 JTable에 적용되는 Mustang 라이브러리가 제공된다.

가장 간단한 경우를 예로 들면, TableModelTableRowSorter 생성자에 패스한 다음 생성된 RowSorterJTablesetRowSorter() 메소드로 패스한다. 다음은 이런 방식을 보여주는 예제 프로그램 SortTable이다.
   import javax.swing.*;
   import javax.swing.table.*;
   import java.awt.*;

   public class SortTable {
     public static void main(String args[]) {
       Runnable runner = new Runnable() {
        public void run() {
           JFrame frame = new JFrame("Sorting JTable");
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           Object rows[][] = {
               {"AMZN", "Amazon", 41.28},
               {"EBAY", "eBay", 41.57},
               {"GOOG", "Google", 388.33},
               {"MSFT", "Microsoft", 26.56},
               {"NOK", "Nokia Corp", 17.13},
               {"ORCL", "Oracle Corp.", 12.52},
               {"SUNW", "Sun Microsystems", 3.86},
               {"TWX",  "Time Warner", 17.66},
               {"VOD",  "Vodafone Group", 26.02},
               {"YHOO", "Yahoo!", 37.69}
             };
           String columns[] = {"Symbol", "Name", "Price"};
           TableModel model =
               new DefaultTableModel(rows, columns) {
             public Class getColumnClass(int column) {
               Class returnValue;
               if ((column >= 0) && (column < getColumnCount())) {
                 returnValue = getValueAt(0, column).getClass();
               } else {
                 returnValue = Object.class;
               }
               return returnValue;
             }
           };

           JTable table = new JTable(model);
           RowSorter<TableModel> sorter =
             new TableRowSorter<TableModel>(model);
           table.setRowSorter(sorter);
           JScrollPane pane = new JScrollPane(table);
           frame.add(pane, BorderLayout.CENTER);
           frame.setSize(300, 150);
           frame.setVisible(true);
         }
       };
       EventQueue.invokeLater(runner);
     }
   } 
Sort Table 1

디스플레이된 테이블의 특정 칼럼을 클릭하고 칼럼의 내용이 재정리되는 것을 살펴본다.

Sort Table 2

커스텀 서브클래스를 생성하느니 차라리 DefaultTableModel을 이용하면 안 되느냐고 질문을 던질지도 모른다. 그 대답은, TableRowSorter가 칼럼 정렬 시 적용되는 일련의 규칙을 가진다는 것이다. 기본값으로, 테이블 내의 모든 칼럼은 Object 타입으로 간주된다. 따라서, toString()을 호출함으로써 정렬이 수행되는 것이다. DefaultTableModel의 기본값 getColumnClass() 비헤이비어를 오버라이드함으로써, RowSorterComparable을 구현하는 것으로 가정하고 해당 클래스의 규칙에 따라 정렬한다. 또한, setComparator(int column, Comparator comparator)를 호출하여 특정 칼럼을 위한 커스텀 Comparator를 설치할 수도 있다.

다음은 정렬과 관련이 있는 SortTable 프로그램 내의 세 가지 주요 라인이다.
           JTable table = new JTable(model);
           RowSorter<TableModel> sorter =
             new TableRowSorter<TableModel>(model);
           table.setRowSorter(sorter);
첫 번째 라인은 모델을 테이블에 연결시키고, 두 번째 라인은 모델에 특정 RowSorter를 생성한다. 세 번째 라인은 RowSorterJTable에 연결시킨다. 이로써 사용자는 칼럼 헤더를 클릭하여 해당 칼럼을 정렬할 수 있다. 같은 칼럼을 두 번 클릭하면 정렬 순서가 반대로 된다.

정렬 순서가 바뀔 때 각자의 액션을 추가하고 싶으면 RowSorterRowSorterListener를 첨부하면 된다. 인터페이스는 다음과 같은 하나의 메소드를 가진다.
   void sorterChanged(RowSorterEvent e)
이 메소드는 상태 바에서 텍스트를 업데이트하거나 몇 가지 추가 태스크를 수행할 수 있게 해준다. 이 액션에 대한 RowSorterEventRowSorter가 뷰 안팎의 행을 필터링한 경우, 정렬 전에 얼마나 많은 행이 존재했었는지 알아낼 수 있게 해준다.

테이블 행 필터링하기

RowFilterTableRowSorter에 연결시켜 테이블의 내용을 필터링하는 데 사용할 수 있다. 예를 들어, RowFilter를 이용하여 이름이 A 자로 시작하거나 주가가 $50를 넘는 행만 테이블에 디스플레이되도록 하는 경우가 그것이다. 추상 RowFilter 클래스의 경우 다음과 같이 필터링에 사용되는 하나의 메소드를 가진다.
   boolean include(RowFilter.Entry<? extends M,? extends I> entry)
RowSorter에 연결된 모델 내의 각 엔트리에 대해, 메소드는 지정된 엔트리가 모델의 현재 뷰에 표시되어야 할지 여부를 알려준다. 대개의 경우 여러분은 각자의 RowFilter 구현을 생성할 필요는 없으나, 대신 RowFilter는 필터 생성을 위한 여섯 개의 정적 메소드를 제공한다.
  • andFilter(Iterable<? extends RowFilter<? super M,? super I>> filters)
  • dateFilter(RowFilter.ComparisonType type, Date date, int... indices)
  • notFilter(RowFilter<M,I> filter)
  • numberFilter(RowFilter.ComparisonType type, Number number, int... indices)
  • orFilter(Iterable<? extends RowFilter<? super M,? super I>> filters)
  • regexFilter(String regex, int... indices)
인덱스의 인자(dateFilter, numberFilter, regexFilter)를 가지는 RowFilter 팩토리 메소드의 경우에는 모델에서 지정된 인덱스에 일치하는 일련의 칼럼만을 확인하고, 지정된 인덱스가 없으면 모든 칼럼에 대해 일치 여부를 확인한다.

dateFilter는 날짜의 일치 여부를 확인할 수 있게 해주고, numberFilter는 일치하는 수를 확인한다. notFilter는 다른 필터를 반전시키는 데 사용된다. 즉, 제공 필터에 포함되지 않는 엔트리를 포함한다는 말인데, 이 필터는 가령 2005년 12월 25일까지 완료되지 않은 엔트리를 찾는다든지 하는 일에 사용할 수 있다. andFilterorFilter는 다른 필터들을 논리적으로 결합하는 데 사용되고, regexFilter는 정규 표현식을 사용하여 필터링을 수행한다. 다음은 regexFilter를 이용하여 테이블의 내용을 필터링하는 프로그램 FilterTable이다.
   import javax.swing.*;
   import javax.swing.table.*;
   import java.awt.*;
   import java.awt.event.*;
   import java.util.regex.*;

   public class FilterTable {
     public static void main(String args[]) {
       Runnable runner = new Runnable() {
         public void run() {
           JFrame frame = new JFrame("Sorting JTable");
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           Object rows[][] = {
             {"AMZN", "Amazon", 41.28},
             {"EBAY", "eBay", 41.57},
             {"GOOG", "Google", 388.33},
             {"MSFT", "Microsoft", 26.56},
             {"NOK", "Nokia Corp", 17.13},
             {"ORCL", "Oracle Corp.", 12.52},
             {"SUNW", "Sun Microsystems", 3.86},
             {"TWX",  "Time Warner", 17.66},
             {"VOD",  "Vodafone Group", 26.02},
             {"YHOO", "Yahoo!", 37.69}
           };
           Object columns[] = {"Symbol", "Name", "Price"};
           TableModel model =
              new DefaultTableModel(rows, columns) {
             public Class getColumnClass(int column) {
               Class returnValue;
               if ((column >= 0) && (column < getColumnCount())) {
                 returnValue = getValueAt(0, column).getClass();
               } else {
                 returnValue = Object.class;
               }
               return returnValue;
             }
           };
           JTable table = new JTable(model);
           final TableRowSorter<TableModel> sorter =
                   new TableRowSorter<TableModel>(model);
           table.setRowSorter(sorter);
           JScrollPane pane = new JScrollPane(table);
           frame.add(pane, BorderLayout.CENTER);
           JPanel panel = new JPanel(new BorderLayout());
           JLabel label = new JLabel("Filter");
           panel.add(label, BorderLayout.WEST);
           final JTextField filterText =
               new JTextField("SUN");
           panel.add(filterText, BorderLayout.CENTER);
           frame.add(panel, BorderLayout.NORTH);
           JButton button = new JButton("Filter");
           button.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent e) {
               String text = filterText.getText();
               if (text.length() == 0) {
                 sorter.setRowFilter(null);
               } else {
                 try {
                   sorter.setRowFilter(
                       RowFilter.regexFilter(text));
                 } catch (PatternSyntaxException pse) {
                   System.err.println("Bad regex pattern");
                 }
               }
             }
           });
           frame.add(button, BorderLayout.SOUTH);
           frame.setSize(300, 250);
           frame.setVisible(true);
         }
       };
       EventQueue.invokeLater(runner);
     }
   }
디스플레이는 어딘가에 SUN이라는 문자가 포함된 모든 문자열에 대해 필터를 설정하는데, 이는 문자열 "SUN"’에 의해 명시된다. 일치 여부를 정확하게 검사하려면 문자열의 시작과 끝 각각에 '^'와 '$'의 문자를 이용한다.
Filter Table 1

사용자가 아래쪽의 "Filter" 버튼을 누르면 필터는 자체적으로 Matcher.find()를 사용하여 포함 여부를 검사한다.

Filter Table 2

테이블에 표시된 일련의 행을 변경하려면 필터 텍스트를 변경하고, 테이블 내의 모든 행을 보고 싶으면 필터 텍스트를 삭제한다.

마지막으로 빼놓을 수 없는 것은, 정렬이나 필터링 시 선택은 뷰의 관점에서 이루어진다는 점이다. 따라서, 기본 모델에 매핑할 필요가 있다면 convertRowIndexToModel() 메소드를 호출해야 한다. 마찬가지로, 모델에서 뷰로 전환할 경우에는 convertRowIndexToView()를 사용해야 한다.

RowSorter, TableRowSorter, RowFilter 등에 관한 자세한 내용은 각 클래스에 관한 javadoc을 참조하기 바란다.

RowSorter
TableRowSorter
RowFilter

"Java SE" 카테고리의 다른 글

Posted by 1010
01.JAVA/Java2008. 11. 12. 17:22
반응형

2004년 3월 25일자 테크팁 예외 처리의 Best Practices에서 예외 처리를 위한 몇 가지 선진 기법을 설명한 바 있다. 이번 테크팁에서는 예외를 처리하는 또 다른 방법에 관해 배우게 될 것인데, J2SE 5.0에 추가된 UncaughtExceptionHandler가 바로 그것이다.

이름에서 알 수 있듯이 UncaughtExceptionHandler는 캐치되지 않은 예외를 처리하는 방법인데, 좀더 구체적으로 얘기하면 캐치되지 않은 런타림 예외를 처리하는 것이다. 자바 컴파일러는 모든 비(非) 런타임 예외를 처리할 것을 요구하며, 그렇지 않을 경우 프로그램은 컴파일되지 않는다. 여기서 '처리한다'는 것은 예외가 선언하는 메소드의 throws 절에서 선언되거나 try-catch 블록의 catch 절에서 캐치되는 것을 의미한다.

그럼 예시를 위해 다음 두 가지 예외를 살펴보기로 하자: FileNotFoundExceptionArithmeticException. String이나 File 인자로 FileReader 생성자를 호출할 때, 제공된 장소가 유효한 정상 파일을 가리키지 않을 경우 FileNotFoundException이 throw된다. 컴파일러는 이 생성자들 중 하나를 호출할 때 throw된 예외를 처리할 것을 요구한다.
   FileReader input;
   String filename = ...;
   try {
     input = new FileReader(filename);
   } catch (FileNotFoundException e) {
     processMissingFile(filename, e);
   }
이와 대조적으로, ArithmeticException은 일종의 런타임 예외라 할 수 있는데, 자바 프로그래밍 언어 스펙은(컴파일러도 마찬가지로) 그 런타임 예외를 처리할 것을 요구하지 않는다. 따라서 10에서 0까지의 수를 100으로 나누는 다음 루프의 경우 루프를 통과하는 최종 패스에 ArithmeticException을 throw한다:
   for (int i=10; i >= 0; i--) {
     int div = 100 / i;
   }

   Exception in thread "main" java.lang.ArithmeticException: / 
   by zero
        at Test.main(Test.java:4)
기본 Uncaught Exception Handler의 역할은 스택 트레이스를 프린트하는 것인데, 보통 이 기본값 동작으로 충분하지만 꼭 그렇지 않은 경우도 있다. 스택 트레이스를 시스템 콘솔에 덤프하는 대신 팝업 창에 트레이스를 표시한다고 생각해보자. 이럴 때는 자체의 기본 Uncaught Exception Handler를 설치하면 이 작업을 수행할 수 있다.

Uncaught Exception Handler 설치에는 최소 세 가지 방법이 사용되고 있다. 첫째는 ThreadsetUncaughtExceptionHandler() 메소드를 호출하는 것인데, 이 경우 특정 스레드의 동작을 커스터마이즈할 수 있게 된다. 둘째로, 자체 ThreadGroup을 정의하고 그룹 내에 생성된 스레드의 uncaughtException() 메소드를 오버라이드하여 해당 스레드의 동작을 변경할 수 있다. 셋째로, Thread의 정적 setDefaultUncaughtExceptionHandler() 메소드를 호출하여 모든 스레드의 기본값 동작을 설정할 수 있다.

ThreadsetUncaughtExceptionHandler()setDefaultUncaughtExceptionHandler() 메소드 모두 UncaughtExceptionHandler 인터페이스 인자의 구현을 수용한다. 이 인터페이스는 Thread 클래스의 내부 인터페이스이므로 정식 명칭은 Thread.UncaughtExceptionHandler이며, 하나의 메소드를 가진다.
   void uncaughtException(Thread t, Throwable e)
uncaughtException 메소드의 구현을 인터페이스의 커스텀 구현의 일부로서 또는 ThreadGroup의 오버라이드된 메소드로서 제공하여 커스터마이즈된 동작을 얻을 수 있다. 예시를 위해, 런타임 예외와 마주칠 때마다 텍스트 영역의 말미에 첨부되는 스택 트레이스가 포함된 창을 표시하는 UncaughtExceptionHandler의 구현을 살펴보기로 하자. 예외 사이에 창을 닫을 수 있으며, 창은 다음 예외가 발생할 때 다른 창 앞에 다시 표시된다
   import java.awt.*;
   import java.io.*;
   import javax.swing.*;

   public class StackWindow extends JFrame
       implements Thread.UncaughtExceptionHandler {

     private JTextArea textArea;

     public StackWindow(
      String title, final int width, final int height) {
       super(title);
       setSize(width, height);
       textArea = new JTextArea();
       JScrollPane pane = new JScrollPane(textArea);
       textArea.setEditable(false);
       getContentPane().add(pane);
     }

     public void uncaughtException(Thread t, Throwable e) {
       addStackInfo(e);
     }

     public void addStackInfo(final Throwable t) {
       EventQueue.invokeLater(new Runnable() {
         public void run() {
           // Bring window to foreground
           setVisible(true);
           toFront();
           // Convert stack dump to string
           StringWriter sw = new StringWriter();
           PrintWriter out = new PrintWriter(sw);
           t.printStackTrace(out);
           // Add string to end of text area
           textArea.append(sw.toString());
        }
     });
   }
  }
핸들러를 테스트하기 위해서는 핸들러를 설치한 다음 런타임 예외를 throw하는 프로그램이 필요한데, 다음의 프로그램 DumpTest가 이 작업을 수행한다. 단순성을 감안하여, DumpTest는 2개의 예외만을 생성한다. 사용자 여러분은 더 난해한 코드를 마음대로 프로그램에 추가하여 더 많은 예외가 throw되도록 한다. 이 때, 프로그램은 예외 사이에서 일시 중지됨으로써 사용자가 예외 사이에 예외 덤프 스택 창을 닫을 수 있음을 보여준다.
   import java.io.*;

   public class DumpTest {
    public static void main(final String args[]) 
     throws Exception {
       Thread.UncaughtExceptionHandler handler =
         new StackWindow("Show Exception Stack", 400, 200);
       Thread.setDefaultUncaughtExceptionHandler(handler);
       new Thread() {
         public void run() {
           System.out.println(1 / 0);
         }
       }.start();
       BufferedReader br =
         new BufferedReader(new InputStreamReader(System.in));
       System.out.print("Press Enter for next exception");
       br.readLine();
       new Thread() {
         public void run() {
           System.out.println(args[0]);
         }
       }.start();
       System.out.print("Press Enter to end");
       br.readLine();
       System.exit(0);
     } 
   }
StackWindowDumpTest를 컴파일한다. DumpTest 실행 시 콘솔에 다음과 같은 내용이 표시되어야 한다.
   > java DumpTest
   Press Enter for next exception
아울러, 텍스트 영역의 예외를 위한 스택 트레이스가 포함된 창이 표시된다.

UncaughtExceptionWindow Window

Enter를 누르면 콘솔에 다음과 같은 내용이 표시되어야 한다.
   Press Enter to end
또한, 창 내의 텍스트 영역에 첨부된 또 다른 스택 트레이스가 표시되어야 한다.

UncaughtExceptionWindow Window

캐치되지 않은 예외를 처리하는 작업은 이것 말고도 더 여러 가지가 있다. Modal Dialogs(여러가지 양식의 대화상자)의 경우에는 자체 이벤트 스레드를 요구하며, 따라서 자체 Uncaught Handler가 필요하다. 시스템 속성 sun.awt.exception.handler는 모든 경우를 커버할 수는 있지만 문서화 수준이 아직 미흡한 상태이다. 한편, 속성을 정식 API에 포함시키기 위해 RFE(Request for Enhancement)가 이미 제출된 상태이다.

예외 처리의 Best Practices 외에도, 2002년 5월의 StackTraceElements에 관한 팁에서도 유용한 참고 정보를 얻을 수 있다. 또한, 자바 튜토리얼에 포함된 레슨 Handling Errors Using Exceptions도 함께 참조할 것.

"Java SE" 카테고리의 다른 글

Posted by 1010
01.JAVA/Java2008. 11. 12. 17:21
반응형

정규 expression 또는 regex 지원은 버전 1.4 이후 자바 플랫폼의 일부가 되어 왔다. java.util.regex 패키지에서 발견되는 regex 클래스는 펄 언어가 제공하는 것과 유사한 패턴 매칭을 지원하지만 자바 언어 구문 및 클래스를 사용한다. 패키지 전체는 Pattern, MatcherPatternSyntaxException의 3가지 클래스로 제한된다. 버전 1.5에서는 MatchResult 인터페이스가 소개되었다.

두 클래스 PatternMatcher를 함께 사용한다. Pattern 클래스를 사용하여 정규 표현식을 정의한 다음, Matcher 클래스를 사용하여 입력 소스에 대해 패턴을 검사한다. 표현식에서 패턴에 구문 오류가 있으면 예외가 발생한다.

두 클래스 모두 구성자를 가지지 않는다. 대신, 정규 표현식을 컴파일하여 패턴을 얻은 다음 반환된 Pattern에게 일부 입력 소스를 기반으로 해당 Matcher를 요청한다.

Pattern pattern = Pattern.compile( <regular expression> );
Matcher matcher = pattern.matcher( <input source> );

Matcher를 얻었으면 일반적으로 입력 소스를 처리하여 포함된 모든 매칭을 찾는다. find() 메소드를 사용하여 입력 소스에서 패턴의 매칭을 찾는다. find()에 대한 각 호출은 마지막 호출 위치에서 계속되거나 첫 번째 호출 위치 0에서 계속된다. 그런 다음 매칭되는 항목이 group() 메소드에 의해 반환된다.

while (matcher.find()) {
   System.out.printf"Found: \"%s\" from %d to %d.%n",
       matcher.group(), matcher.start(), matcher.end());
}

다음 코드는 기본적인 정규 표현식 프로그램을 보여 주며 사용자가 정규 표현식과 비교 대상 문자열을 입력하도록 메시지를 표시한다.

import java.util.regex.*;

public class Regex {

   public static void main(String args[]) {
       Console console = System.console();

       // Get regular expression
       String regex = console.readLine("%nEnter expression: ");
       Pattern pattern = Pattern.compile(regex);

       // Get source
       String source = console.readLine("Enter input source: ");
       Matcher matcher = pattern.matcher(source);

       // Show matches
       while (matcher.find()) {
           System.out.printf("Found: \"%s\" from %d to %d.%n",
               matcher.group(), matcher.start(), matcher.end());
       }
   }
}

그러면 정규 표현식의 모양은 정확하게 어떠한가? Pattern 클래스는 보다 세부적인 사항을 제공하지만 기본적으로 정규 표현식은 다른 문자 시퀀스와 일치시킬 문자 시퀀스이다. 예를 들어, "Hello, World" 문자열에서 두 개의 L자("ll") 문자열 리터럴 패턴을 찾을 수 있다. 앞의 프로그램은 시작 위치 2와 끝 위치 4에서 "ll" 패턴을 찾을 것이다. 끝 위치는 일치된 문자열 패턴의 끝 이후에 다음 문자의 위치이다.

"ll" 같은 패턴 문자열은 입력 소스에서 문자적으로 위치하는 지점만을 보고하므로 그리 흥미롭지 않다. 정규 표현식 패턴은 특수 메타 문자를 포함할 수 있다. 메타 문자는 정규 표현식에서 강력한 매칭 기능을 제공한다. 정규 표현식에서는 "([{\^-$|]})?*+."의 15문자를 메타 문자로 사용할 수 있다.

일부 메타 문자는 문자 그룹을 나타낸다. 예를 들어, 대괄호([ 및 ])를 사용하면 대괄호 안의 문자 중 하나가 텍스트에서 발견되는 경우 매칭이 성공하는 일련의 문자를 지정할 수 있다. 예를 들어, "co[cl]a" 패턴은 coca 및 cola라는 단어와 매칭된다. []는 단일 문자를 매칭하는 데만 사용되므로 cocla는 매칭되지 않는다. 몇 가지 매칭을 해 보고 문제가 없으면 곧 수량자에 대해 자세히 살펴보자.

개별 문자의 매칭 이외에 대괄호 문자([ 및 ])를 사용하여 [j-z]로 지정된 j-z의 문자처럼 일정 범위의 문자를 매칭할 수 있다. 이러한 문자 범위는 "foo[j-z]"처럼 문자열 리터럴과 결합할 수도 있다. 여기서 fool을 찾으면 매칭이 성공하고 food를 찾으면 매칭이 실패한다. ljz 사이의 범위 안에 있지만 d는 그렇지 않기 때문이다. ^ 문자를 사용하여 문자열 리터럴 또는 문자 범위의 제외를 나타낼 수도 있다. "foo[^j-z]" 패턴은 foo로 시작하고 j에서 z 사이의 문자로 끝나지 않는 단어를 찾는다. 따라서 이번에는 food라는 문자열이 매칭에 성공한다. [a-zA-Z]처럼 여러 범위를 결합하여 a에서 z 사이의 소문자와 대문자를 나타낼 수도 있다.

정규 표현식을 처음 학습할 때는 문자열 리터럴이 유용하지만 정규 표현식에서 대부분의 사람들이 사용하는 보다 일반적인 요소는 미리 정의된 문자 클래스이다. 여기서 메타 문자 .\가 사용된다. 마침표(.)는 임의 문자를 나타내는 데 사용된다. 따라서 정규 표현식 ".oney"는 money 및 honey와 매칭되며 oney로 끝나는 5자의 어느 단어와도 매칭된다. 반면에 \는 다른 문자와 함께 사용되어 전체 문자 집합을 나타낸다. 예를 들어, 숫자 집합을 나타내기 위해 [0-9]를 사용할 수 있지만 \d를 사용할 수도 있다. 숫자가 아닌 문자 집합을 나타내기 위해 [^0-9]를 사용할 수도 있다. 또는 \D의 미리 정의된 문자 클래스 문자열을 사용할 수 있다. 이러한 모든 문자 클래스 문자열은 모두 기억하기가 어려우므로 패턴 클래스에 대한 자바 플랫폼 문서에 정의되어 있다. 다음은 미리 정의된 특수 문자 클래스의 하위 집합이다.

* \s -- whitespace
* \S -- non-whitespace
* \w -- word character [a-zA-Z0-9]
* \W -- non-word character
* \p{Punct} -- punctuation
* \p{Lower} -- lowercase [a-z]
* \p{Upper} -- uppercase [A-Z]

미리 정의된 문자열과 관련하여 지적해야 할 사항은 즉각 눈에 띄지 않는다. 위의 Regex 프로그램에 이러한 문자열 중 하나를 사용하려면 표시된 대로 입력한다. \s는 공백과 매칭된다. 하지만 자바 소스 파일에서 정규 표현식을 하드 코딩하려면 \ 문자가 특별하게 취급된다는 것을 기억해야 한다. 소스에서 이 문자열을 다음과 같이 이스케이프해야 한다.

String regexString = "\\s";

여기서 \\는 문자열에서 하나의 백슬래시를 나타낸다. 다른 문자열 리터럴을 나타내기 위한 기타 특수 문자열은 다음과 같다.

* \t -- tab
* \n -- newline
* \r -- carriage return
* \xhh -- hex character 0xhh
* \uhhhh -- hex character 0xhhhh

수량자는 정규 표현식을 더욱 흥미롭게 만드는데 문자 클래스 같은 기타 표현식과 결합될 때는 특히 그렇다. 예를 들어, a-z에서 3자의 문자열을 매칭하기 위해 "[a-z][a-z][a-z]" 패턴을 사용할 수도 있지만 그럴 필요가 없다. 문자열을 반복하는 대신 패턴 다음에 수량자를 추가하면 된다. 이 예제의 경우, "[a-z][a-z][a-z]"":[a-z]{3}"으로 나타낼 수 있다. 특정 수량에 대해 숫자가 {} 괄호 안에 들어간다. ?, * 또는 + 문자를 사용하여 0번 또는 한 번, 0번 이상, 한 번 이상을 각각 나타낼 수도 있다.

[a-z]? 패턴은 a-z의 문자와 0번 또는 한 번 매칭된다. [a-z]* 패턴은 a-z의 문자와 0번 이상 매칭된다. [a-z]+ 패턴은 a-z의 문자와 한 번 이상 매칭된다.

수량자는 주의해서 사용한다. 0번 매칭을 허용하는 수량자에는 특별한 주의를 기울여야 한다.

괄호 기호({})를 수량자로 사용할 때는 범위를 지정해야 한다. {3}은 정확히 3번을 의미하지만 {3,}은 적어도 3번을 의미한다. 수량자 {3, 5}3번에서 5번까지의 패턴과 매칭된다.

정규 표현식에는 여기서 살펴본 것보다 훨씬 많은 내용이 있다. 특정 상황에 맞는 정규 표현식을 사용하는 것이 중요하다. 앞의 Regex 프로그램을 사용하여 몇 가지 표현식을 시험해 보고 기대했던 결과가 나오는지 확인해 본다. 여러 가지 수량자를 사용하여 각 차이가 어떻게 나오는지 이해할 수 있도록 한다. 일반적으로 수량자는 가능한 매칭에 대해 최대 수의 문자를 포함하려고 한다.

정규 표현식에 대한 자세한 내용을 살펴보려면 자바 온라인 자습서의 정규 표현식 편을 참고한다.

또한 패턴 클래스에 대한 내용은 javadoc을 참고한다.


"Java SE" 카테고리의 다른 글

Posted by 1010
01.JAVA/Java2008. 11. 12. 17:20
반응형

이러한 팁은 Java SE 6을 사용하여 개발되었습니다. Java SE 6은 Java SE Downloads 페이지에서 다운로드할 수 있습니다.

이번 호 테크팁의 저자는 JZ Ventures사의 사장이자 주요 컨설턴트인 John Zukowski입니다.
이전에 다루었던 CookieHandler를 이용한 쿠키 관리 팁 에서는 J2SE 5.0이 네트워크 연결을 통해 쿠키 관리를 지원한다고 설명했습니다. 5.0 릴리스에서는 이러한 간략한 설명을 다루기 위한 프레임워크를 제공했지만 모든 작업을 수행하는 일은 개발자의 몫으로 남았습니다. 정의된 API를 따르기만 하면 되지만 실제로 프로그램에서 쿠키를 제대로 관리하려면 더 많은 작업이 수반됩니다.

J2SE 5.0 API를 다시 간략하게 살펴 보면 모호한 CookieHandler 클래스를 사용할 수 있게 되지만 실제 구현도, 스토리지 메커니즘도, 스토리지 정책도, 저장할 대상도 아무 것도 존재하지 않습니다. Java SE 6으로 이동하면서 CookieManager 클래스는 이러한 CookieHandler의 구현을 제공합니다. CookieStore는 스토리지 메커니즘이고, CookiePolicy는 쿠키를 수락하거나 거부하는 정책을 제공합니다. 그리고 HttpCookie는 저장할 개체입니다.

J2SE 5.0에서 수행하기 어려웠던 작업들이 Java SE 6에서는 기존 클래스를 활용한 간단한 작업이 되었습니다.

다음은 쿠키 작업을 위해 작동하는 J2SE 5.0 프로그램입니다.

   import java.io.*;
   import java.net.*;
   import java.util.*;

   public class Fetch {
     public static void main(String args[]) throws Exception {
       if (args.length == 0) {
         System.err.println("URL missing");
         System.exit(-1);
       }
       String urlString = args[0];
       CookieHandler.setDefault(new ListCookieHandler());
       URL url = new URL(urlString);
       URLConnection connection = url.openConnection();
       Object obj = connection.getContent();
       url = new URL(urlString);
       connection = url.openConnection();
       obj = connection.getContent();
     }
   }

setDefault 메소드는 중간에 CookieHandler를 호출합니다. ListCookieHandler 클래스는 기본 CookieHandler의 팁 구현이었습니다.

동일한 프로그램의 Java SE 6 버전은 거의 동일하며 다음 행만 다릅니다.

   CookieHandler.setDefault(new CookieManager());

추가 코드는 제공하지 않아도 됩니다. 간단하게 다른 API 사이를 이동할 수 있습니다. 다른 차이점은 있지만 페치(Fetch) 프로그램의 한 행을 변경하면 두 번째 네트워크 연결이 첫 번재 연결에서 반환된 쿠키를 사용합니다.

차이점은 다음과 같습니다. Java SE 6에는 CookiePolicy가 있습니다. 이것은 모든 쿠키를 수락하거나, 쿠키를 수락하지 않거나, 원래 호스트의 쿠키만 수락하는 기능인 CookieManager를 제공합니다. 다른 정책으로 CookieManager를 설정하려면 CookiePolicy 인터페이스의 상수 ACCEPT_ALL, ACCEPT_NONE 또는 ACCEPT_ORIGINAL_SERVER 중 하나를 사용합니다. 아무 것도 설정하지 않을 경우 마지막 옵션은 기본값이 됩니다. 쿠키 관리자를 구성하려면 아래에 표시된 대로 적절한 상수로 setCookiePolicy 메소드를 호출하십시오.

   CookieManager manager = new CookieManager();
   manager.setCookiePolicy(CookiePolicy.ACCEPT_NONE);
   CookieHandler.setDefault(manager);

그리고 CookieStoreCookiePolicy 인수 모두를 수락하는 CookieManager에 대한 두 번째 구성자를 호출할 수 있습니다.

   CookieManager(CookieStore store, CookiePolicy cookiePolicy)

널 저장소에 전달되면 시스템이 사전 정의된 메모리 내장 버전을 사용합니다. 쿠키의 장기 스토리지를 제공하려면 고유한 인터페이스 구현을 정의할 수도 있습니다.

수정된 페치 프로그램 버전을 소개하기 전에 API 차이점을 하나 더 설명하겠습니다. 바로 쿠키 jar, err..., 관리자 등에서 쿠키 목록을 가져오는 방법입니다. CookieManager 클래스에는 CookieStore를 가져오는 getCookieStore 메소드가 있습니다. getCookies 메소드로 저장소에 쿠키 목록을 요청하면 목록 전체를 반복할 수 있습니다.

다음은 Java SE 6 버전의 쿠키 처리 API를 활용하는 이전 프로그램의 수정된 버전입니다. 기본 프로그램은 크게 변경되지 않았지만 지원되는 모든 사용자 정의 클래스는 이제 더 이상 필요하지 않습니다.

import java.io.*;
import java.net.*;
import java.util.*;

public class Fetch {
  public static void main(String args[]) throws Exception {
    Console console = System.console();
    if (args.length == 0) {
      System.err.println("URL missing");
      System.exit(-1);
    }
    String urlString = args[0];
    CookieManager manager = new CookieManager();
    manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
    CookieHandler.setDefault(manager);
    URL url = new URL(urlString);
    URLConnection connection = url.openConnection();
    Object obj = connection.getContent();
    url = new URL(urlString);
    connection = url.openConnection();
    obj = connection.getContent();
    CookieStore cookieJar = manager.getCookieStore();
    List<HttpCookie> cookies = cookieJar.getCookies();
    for (HttpCookie cookie: cookies) {
      console.printf("Cookie: %s%n", cookie);
    }
  }
}

특정 URL을 방문할 때 시스템에 쿠키가 남는지 확인하려면 프로그램을 컴파일하고 실행하십시오. ACCEPT_ALL을 사용할 수 없으면 http://www.sun.com/을 방문해도 쿠키가 표시되지 않지만 모두 사용 가능하게 설정하면 세 개가 표시됩니다. 여러분이 실행하면 다른 결과가 생성될 것입니다.

> java Fetch http://www.sun.com
Cookie: JROUTE=9999
Cookie: JSESSIONID=999999995d3f13ffffffffc68433979b7f5b0
Cookie: Starload=star-fep7

그렇습니다. J2SE 5.0 쿠키 처리 메커니즘에서 Java SE 6으로의 이동은 매우 쉽습니다. 기본 기능에 만족하면 추가로 인터페이스를 구현하지 않아도 됩니다.

Posted by 1010
01.JAVA/Java2008. 11. 12. 17:17
반응형
저자 John Zukowski

자바 플랫폼에서의 문자열 정렬은 간단한 작업으로 생각할 수 있으나 국제 시장을 대상으로 한 프로그램을 개발할 경우에는 고려해야 할 사항이 많습니다. 영어만을 기준으로 한다면 tomorrow라는 단어가 today 다음에 정렬되므로 프로그램이 제대로 기능하는 것으로 보이며 아무 문제가 없을지도 모릅니다. 그러나 정렬 기능으로 기본적인 String 클래스의 compare() 메서드만 사용했을 경우 스페인어 사용자가 mañana라는 단어를 정렬하려 한다면 ñ 문자가 z 문자가 다음에 오게 되므로 n 문자와 o 문자 사이의 스페인어 문자 정렬 순서가 틀리게 됩니다. 바로 이러한 문제를 해결하기 위해 java.text 패키지의 Collator 클래스가 사용되는 것입니다.

다음과 같은 단어 목록을 예로 들어 보겠습니다.

  • first
  • mañana
  • man
  • many
  • maxi
  • next

기본 정렬 방법인 String의 클래스의 compare() 메서드를 사용할 경우 위의 단어 목록은 다음과 같이 정렬될 것입니다.

  • first
  • man
  • many
  • maxi
  • mañana
  • next

여기서 mañana는 maxi와 next 사이에 옵니다. 그러나 스페인어 알파벳에서 ñ 문자('에녜'로 발음)는 n 다음에 오므로 mañana는 many와 maxi 사이에 와야 합니다. ñ 문자를 처리하는 정렬 루틴을 자체적으로 만들 수도 있지만, 이번에는 또 독일어 사용자가 독일어 발음 부호를 사용하려 하거나 façade 같은 디자인 패턴 목록을 정렬하려 할 수도 있습니다. 이 경우 façade라는 단어를 factory 앞에 오게 정렬하시겠습니까? 아니면 뒤에 오게 정렬하시겠습니까? 실제로 세디유가 붙은 ç 문자는 c 문자와 동일하게 처리되거나 다르게 처리됩니다.

이러한 문제들을 해결하기 위해 Collator 클래스를 사용할 수 있습니다. Collator 클래스는 언어별 정렬 문제를 고려하므로 ASCII/Unicode 문자 값만을 기준으로 단어를 정렬하지 않습니다. Collator 클래스의 기능과 장점을 제대로 활용하려면 먼저 strength라고 하는 특별한 속성에 대해 잘 알고 있어야 합니다. Collator의 strength 설정은 정렬 순서에 사용되는 비교 정도가 얼마나 강하고 약한지를 결정합니다. 이 속성의 값으로 PRIMARY, SECONDARY, TERTIARY, IDENTICAL이라는 4가지 값을 사용할 수 있습니다. 언어에 대해 이러한 값이 일반적으로 어떻게 작용하는지 알아 보겠습니다. 제일 나중에 언급한 IDENTICAL은 말 그대로 정확하게 같아야만 문자가 동일한 것으로 간주됩니다. TERTIARY는 대소문자를 구분하지 않습니다. SECONDARY는 n에 대해 ñ과 같은 발음 부호의 차이를 무시합니다. PRIMARY는 기본적인 문자 비교 방식은 IDENTICAL과 동일하지만 제어 문자 및 악센트 부호를 처리할 때 몇 가지 차이점이 있습니다. 이러한 차이점과 분석 모드 규칙에 대한 자세한 내용은 Collator javadoc을 참조하십시오.

Collator를 사용하기 위해서는 먼저 한 가지 작업을 수행해야 합니다. 기본 로케일에 대해 getInstance()를 호출하여 사용하거나, 제공된 로케일에 대해 특정 LocalegetInstance() 메서드에 전달하여 사용할 수 있습니다. 예를 들어 스페인어의 경우, 다음과 같이 Locale("es")을 새로 사용하여 스페인어 Locale을 만든 다음 getInstance()에 전달해야 합니다.

 Collator esCollator =
   Collator.getInstance(new Locale("es"));

로케일에 기본 Collator 강도(스페인어에 SECONDARY 값 적용)로도 충분하면 다음과 같이 Comparator와 같은 CollatorCollectionssort() 루틴에 전달하여 정렬된 List를 얻을 수 있습니다.

 Collections.sort(list, esCollator);

이렇게 하면 위의 목록이 스페인어 알파벳의 올바른 순서에 따라 다음과 같이 정렬됩니다.

  • first
  • man
  • many
  • mañana
  • maxi
  • next

Collator에 US 로케일을 사용한다면 영어 알파벳에 ñ이라는 문자가 없기 때문에 mañana가 man과 many 사이에 올 것입니다.

다음은 이러한 차이점을 보여 주는 간단한 예입니다.

import java.awt.*;
import java.text.*;
import java.util.*;
import java.util.List; // Explicit import required
import javax.swing.*;

public class Sort {
 public static void main(String args[]) {
   Runnable runner = new Runnable() {
     public void run() {
       String words[] = {"first", "mañana", "man",
                         "many", "maxi", "next"};
       List list = Arrays.asList(words);
       JFrame frame = new JFrame("Sorting");
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       Box box = Box.createVerticalBox();
       frame.setContentPane(box);
       JLabel label = new JLabel("Word List:");
       box.add(label);
       JTextArea textArea = new JTextArea( list.toString());
       box.add(textArea);
       Collections.sort(list);
       label = new JLabel("Sorted Word List:");
       box.add(label);
       textArea = new JTextArea(list.toString ());
       box.add(textArea);
       Collator esCollator = Collator.getInstance(new Locale("es"));
       Collections.sort(list, esCollator);
       label = new JLabel("Collated Word List:");
       box.add(label);
       textArea = new JTextArea(list.toString());
       box.add(textArea);
       frame.setSize(400, 200);
       frame.setVisible(true);
     }
   };
   EventQueue.invokeLater (runner);
 }
}


sorting

마지막으로 정렬 순서에 대해 알아 둘 내용이 있습니다. getInstance() 호출을 통해 반환된 Collator는 지원되는 언어에 대한 RuleBasedCollator의 인스턴스입니다. RuleBasedCollator를 사용하면 정렬 순서를 원하는 대로 정의할 수 있습니다. 이러한 규칙 구문은 클래스에 대한 javadoc에 자세히 설명되어 있습니다. 여기서는 4자 알파벳을 사용하고 있으며 문자 순서가 ACEF가 아닌 CAFE가 되도록 만드는 규칙을 간단히 예로 들어 보겠습니다.

 String rule =
   "< c, C < a, A < f, F < e, E";
 RuleBasedCollator collator = new RuleBasedCollator(rule);

이 규칙은 대소문자를 표시하여 명시적인 순서를 cafe로 정의합니다. ace, cafe, ef, face라는 단어 목록이 있을 경우 새 규칙을 사용하여 정렬하면 cafe, ace, face, ef 순서가 됩니다.

import java.text.*;
import java.util.*;

public class Rule {
 public static void main(String args[]) throws ParseException {
   String words[] = {"ace", "cafe", "ef", "face"};
   String rule ="< c, C < a, A < f, F < e, E";
   RuleBasedCollator collator = new RuleBasedCollator(rule);
   List list = Arrays.asList(words);
   Collections.sort(list, collator);
   System.out.println(list);
 }
}

컴파일 후 실행하면 새 규칙을 사용하여 정렬된 단어를 볼 수 있습니다.

> javac Rule.java
> java Rule
[cafe, ace, face, ef]

javadoc에서 규칙 구문에 대한 내용을 자세히 읽은 후 더 많은 문자와 다양한 발음 부호를 사용하여 연습해 보십시오.

이제 전 세계를 대상으로 하는 글로벌 프로그램을 개발할 경우 다양한 언어를 지원하는 프로그램을 만들 수 있을 것입니다. 이전 팁에서 설명했듯이 문자열을 리소스 번들에 반드시 포함시켜야 합니다.

이전 팁

*********

사용자 삽입 이미지

GlassFish에 연결하여 참여
GlassFish에 참여하여 iPhone 경품의 주인공이 되어 보십시오. 본 행사는 2008년 3월 23일까지 진행됩니다. 지금 바로 참여하십시오.

Foote on Blu-ray Disc Java 이 비디오 인터뷰에서는 썬의 BDJ(Blu-ray Disc Java) 설계자인 Bill Foote가 강력한 기술에 대해 설명하고 BDJ 코드 및 애플리케이션의 몇 가지 예를 보여 줍니다. 코드 다운로드하기

이 글의 영문 원본은 http://blogs.sun.com/corejavatechtips/e ··· _strings
에서 보실 수 있습니다.

"Java SE" 카테고리의 다른 글


Posted by 1010
01.JAVA/Java2008. 11. 12. 17:13
반응형

기고인 : JCO 기술젼략팀장 김홍회(자바스터디 네트워크 대표 운영자)

Database 시장은 오라클, DB2, MS-SQL, MySQL등 많은 경쟁업체들의 각축장이 되어 왔다. BEA를 인수한 오라클은 점차 그 범위를 확장해 가고 있으며 Sun은 MySQL을 인수하며 시장에 합류하였다. 이렇듯이 Dabase는 Database가 시장에 갖는 의미만큼 각 업체에서 사활을 건 싸움을 하고 있다. 그리고 이러한 경쟁 시장에 JavaDB가 도전장을 내밀게 되었다. JavaDB는 제목처럼 경량화 DB를 모토로 만들어 졌으며 이 글은 소개 및 설치하는 방법과 실행 예제 등 기본적인 정보만 다루도록 하겠다.

1. JavaDB의 등장과 기원

여기서 필자는 JavaDB의 등장과 함께 기원이라는 단어를 사용했다. 그럼 JavaDB는 부모가 있다는 것인가? 그렇다. JavaDB의 기원은 1996년으로 거슬러 올라간다. IBM이 Cloudscape라는 프로젝트를 시작 하였으며 1999년에 Informix, 2001년에는 IBM에서 관리 하였으며 2004년에 지금의 Apache에 기부 되었다. Apache는 Apache Derby라는 프로젝트로 오픈 소스 프로젝트를 진행하고 있으며 Apache Derby는 Apache DB subproject라는 이름 또한 가지고 있다. 기존 Database가 무겁고 비싼 것에 비해 Derby는 경량화와 무료 라이센스 그리고 무엇보다 매력적인 오픈 소스를 표방하며 만들어 졌다. 이 프로젝트를 Sun에서 JavaDB라는 이름으로 JavaSE6에 포함시키며 공급하기 시작했다.

2. JavaDB의 특징

JavaDB의 특징은 Apache Derby의 특징과 같다. 이는 기존 Dababase와 성격이 매우 다른데 특징은 다음과 같다.

1) base engine과 JDBC driver 모두 합쳐 2메가바이트
2) 자바와 JDBC, SQL을 기초로 만들어짐
3) client/server 모드를 Derby Network Client JDBC driver and Derby Network Server. 를 통해 지원 가능
4) 설치 및 디플로이, 사용이 편함

또한 JavaDB는 다음과 같은 환경에 적합하다고 소개되어 있다.

1) 자바 애플리케이션 개발 및 테스트 : 사용하기 쉬우며 사용자의 컴퓨터나 메인프레임에서도 잘 돌아감.
아파치 라이센스하에 무료임.
2) 임베디드 애플리케이션
3) 멀티 플랫폼 환경 : 100% 자바이므로 Java DB에서 다른 오픈 스탠더드 데이터베이스로 마이그레이트 가능함.
4) Web 2.0 기반의 브라우져 based 환경
5) PDA와 같이 J2ME CDC에서 돌아가는 애플리케이션

먼저 base engine과 JDBC driver를 모두 합쳐서 2메가바이트라는 획기적이고도 믿을 수 없는 용량을 자랑한다.
또한 이전에 설명했듯이 Pure Java로 만들어 졌으며 설치법 또한 간단하다.

3. JavaDB 설치

JavaDB는 SE6를 설치하면 자동으로 설치되나 수동으로 설치하는 방법도 있다.

(1) homepage(http://developers.sun.com/javadb/downloads/index.jsp)에 접속하여 다운로드 하기
(2) 설치하기

① 윈도우의 경우

     javadb_<version>.ms를 더블 클릭하거나 msiexec /i javadb_<version>.msi 명령 실행

② 솔라리스의 경우
    1) 다운로드 하기
       javadb-<version>-solaris-<arch>-pkg.sh
    2) 권한 확인하기
       
chmod +x javadb-<version>-solaris-<arch>-pkg.sh

    3) 압축풀기
       
./javadb-<version>-solaris-<arch>-pkg.sh

    이 명령을 실행하고 나면 javadb-<version> 디렉토리 밑에 여러 개의 다음의 SVR4 package 디렉토리들이 생성된다

SUNWjavadb-common
SUNWjavadb-client
SUNWjavadb-core
SUNWjavadb-demo
SUNWjavadb-docs
SUNWjavadb-javadoc
SUNWjavadb-service

      4) su – root등을 사용하여 수퍼 권한자로 변경하기
      5) 기존 JavaDB 삭제하기
         기존에 JavaDB가 설치되어 있다면(디폴트 설치 경로는 /opt/SUNWjavadb 이다) 새 버전을 설치하기 전에 제거해야 한다. 현재 돌아가고 있는 패키지를 보는 방법은 다음과 같다.
    
pkginfo | grep SUNQjavadb-

          기존 패키지를 제거하기          
        
pkgrm SUNWjavadb-client SUNWjavadb-core SUNWjavadb-demo SUNWjavadb-docs SUNWjavadb-javadoc SUNWjavadb-service SUNWjavadb-common

      6) 설치하기
        
cd javadb-<version>
pkgadd
-d . SUNWjavadb-common SUNWjavadb-client SUNWjavadb-core SUNWjavadb-demo SUNWjavadb-docs SUNWjavadb-javadoc SUNWjavadb-service

      7) 새 JavaDB 패키지 설치하기
         
cd javadb-<version>
          pkgadd
-d . SUNWjavadb-common SUNWjavadb-client SUNWjavadb-core SUNWjavadb-demo SUNWjavadb-docs SUNWjavadb-javadoc SUNWjavadb-service



③ 리눅스의 경우
   1) 다운로드 하기
      javadb-<version>-linux-rpm.bin
   2) 권한 확인하기
        
chmod +x javadb-<version>-linux-rpm.bin

       3) 압축풀기
          
/javadb-<version>-linux-rpm.bin

    이 명령을 실행하고 나면 javadb-<version> 디렉토리 밑에 여러 개의 RPM 패키지
Sun-javadb-*.i386.rpm이 생긴다.

       4) 수퍼 권한자로 변경하기
       5) 기존 JavaDB 삭제하기
          만약 기존에 JavaDB 설치가 되어 있으면(디폴트 설치 경로는 /opt/sun/javadb 이다)
          이를 새 버전을 설치하기 전에 삭제해야 한다.
          현재 돌아가고 있는 JavaDB 패키지의 리스트를 보는 방법은 다음과 같다.
         
rpm qa | grep sun-javadb-

          기존 패키지를 제거하기       
         
rpm -ev sun-javadb-common sun-javadb-client sun-javadb-core sun-javadb-demo sun-javadb-docs sun-javadb-javadoc


        6) 새 JavaDB 패키지 설치하기

cd javadb-<version>
rpm
-ivh sun-javadb-*.rpm

       
위와 같이 JavaDB를 설치하면 demo, frameworks, javadoc, docs 그리고 lib라는 서브 디렉토리가
생긴다.
이들 서브 디렉토리가 어떤 정보를 가지고 있는지 살펴보자.

1) demo : 2개의 데모 프로그램을 가지고 있으며 database 폴더는 임베디드 애플리케이션을 어떻게 만드는 지에 대한 데모이며 programs 폴더는 클라이언트-서버 환경에서 JavaDB를 사용하는 데모이다. 이 데모는 밑에서 실행해 보도록 하겠다.
2) frameworks : 환경 변수, 데이터베이스 생성 및 작업의 셋팅을 위한 유틸리티를 가지고 있다.
3) javadoc : 예상 했겠지만 API 관련 문서가 있으며 jdbc3와 jdbc4 폴더로 나뉘어져 있다.
4) docs : JavaDB의 셋업 및 어드민, 레퍼런스 가이드가 있다.
5) lib : JAR 파일과 같은 패키지 된 JavaDB 라이브러리가 있다.

4. JavaDB 실행하기

설치를 마쳤으면 이제 JavaDB를 가동시켜 보자. 가동하기 전 현재 환경 셋업이 잘 되었는지 테스트 해야 한다. 테스트 하는 명령어는 다음과 같다.

java org.apache.derby.tools.sysinfo -cp embedded SimpleApp.class


명령어를 실행하면 다음과 같은 결과 화면이 나온다.
 

이 테스트는 먼저 클래스 경로를 찾고 라이브러리와 클래스를 찾는다.
이 테스트가 성공적으로 끝나면 화면과 같은 메시지가 나온다.

그럼 이제 Derby 프로그램을 실행시켜 보자.
우선 실행할 프로그램은 SimpleApp라는 자바 프로그램이다. 이 프로그램은 설치 시 예제로 들어가 있으며 기본적인 커넥션 얻는 법부터 SQL 문을 수행하는 예제이다. 소스는 다음과 같다.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class SimpleApp
{
   
/* the default framework is embedded*/
   
public String framework = "embedded";
   
public String driver = "org.apache.derby.jdbc.EmbeddedDriver";
   
public String protocol = "jdbc:derby:";

   
public static void main(String[] args)
   
{
       
new SimpleApp().go(args);
   
}

   
void go(String[] args)
   
{
       
/* parse the arguments to determine which framework is desired*/
        parseArguments
(args);

       
System.out.println("SimpleApp starting in " + framework + " mode.");

       
try
       
{
           
/*
               The driver is installed by loading its class.
               In an embedded environment, this will start up Derby, since it is not already running.
             */

           
Class.forName(driver).newInstance();
           
System.out.println("Loaded the appropriate driver.");

           
Connection conn = null;
           
Properties props = new Properties();
            props
.put("user", "user1");
            props
.put("password", "user1");

           
/*
               The connection specifies create=true to cause
               the database to be created. To remove the database,
               remove the directory derbyDB and its contents.
               The directory derbyDB will be created under
               the directory that the system property
               derby.system.home points to, or the current
               directory if derby.system.home is not set.
             */

            conn
= DriverManager.getConnection(protocol +
                   
"derbyDB;create=true", props);

           
System.out.println("Connected to and created database derbyDB");

            conn
.setAutoCommit(false);

           
/*
               Creating a statement lets us issue commands against
               the connection.
             */

           
Statement s = conn.createStatement();

           
/*
               We create a table, add a few rows, and update one.
             */

            s
.execute("create table derbyDB(num int, addr varchar(40))");
           
System.out.println("Created table derbyDB");
            s
.execute("insert into derbyDB values (1956,'Webster St.')");
           
System.out.println("Inserted 1956 Webster");
            s
.execute("insert into derbyDB values (1910,'Union St.')");
           
System.out.println("Inserted 1910 Union");
            s
.execute(
               
"update derbyDB set num=180, addr='Grand Ave.' where num=1956");
           
System.out.println("Updated 1956 Webster to 180 Grand");

            s
.execute(
               
"update derbyDB set num=300, addr='Lakeshore Ave.' where num=180");
           
System.out.println("Updated 180 Grand to 300 Lakeshore");

           
/*
               We select the rows and verify the results.
             */

           
ResultSet rs = s.executeQuery(
                   
"SELECT num, addr FROM derbyDB ORDER BY num");

           
if (!rs.next())
           
{
               
throw new Exception("Wrong number of rows");
           
}

           
if (rs.getInt(1) != 300)
           
{
               
throw new Exception("Wrong row returned");
           
}

           
if (!rs.next())
           
{
               
throw new Exception("Wrong number of rows");
           
}

           
if (rs.getInt(1) != 1910)
           
{
               
throw new Exception("Wrong row returned");
           
}

           
if (rs.next())
           
{
               
throw new Exception("Wrong number of rows");
           
}

           
System.out.println("Verified the rows");

            s
.execute("drop table derbyDB");
           
System.out.println("Dropped table derbyDB");

           
/*
               We release the result and statement resources.
             */

            rs
.close();
            s
.close();
           
System.out.println("Closed result set and statement");

           
/*
               We end the transaction and the connection.
             */

            conn
.commit();
            conn
.close();
           
System.out.println("Committed transaction and closed connection");

           
/*
               In embedded mode, an application should shut down Derby.
               If the application fails to shut down Derby explicitly,
               the Derby does not perform a checkpoint when the JVM shuts down, which means
               that the next connection will be slower.
               Explicitly shutting down Derby with the URL is preferred.
               This style of shutdown will always throw an "exception".
             */

           
boolean gotSQLExc = false;

           
if (framework.equals("embedded"))
           
{
               
try
               
{
                   
DriverManager.getConnection("jdbc:derby:;shutdown=true");
               
}
               
catch (SQLException se)
               
{
                    gotSQLExc
= true;
               
}

               
if (!gotSQLExc)
               
{
                   
System.out.println("Database did not shut down normally");
               
}
               
else
               
{
                   
System.out.println("Database shut down normally");
               
}
           
}
       
}
       
catch (Throwable e)
       
{
           
System.out.println("exception thrown:");

           
if (e instanceof SQLException)
           
{
                printSQLError
((SQLException) e);
           
}
           
else
           
{
                e
.printStackTrace();
           
}
       
}

       
System.out.println("SimpleApp finished");
   
}

   
static void printSQLError(SQLException e)
   
{
       
while (e != null)
       
{
           
System.out.println(e.toString());
            e
= e.getNextException();
       
}
   
}

   
private void parseArguments(String[] args)
   
{
       
int length = args.length;

       
for (int index = 0; index < length; index++)
       
{
           
if (args[index].equalsIgnoreCase("jccjdbcclient"))
           
{
                framework
= "jccjdbc";
                driver
= "com.ibm.db2.jcc.DB2Driver";
                protocol
= "jdbc:derby:net://localhost:1527/";
           
}
           
if (args[index].equalsIgnoreCase("derbyclient"))
           
{
                framework
= "derbyclient";
                driver
= "org.apache.derby.jdbc.ClientDriver";
                protocol
= "jdbc:derby://localhost:1527/";
           
}
       
}
   
}
}

 
이 소스를 실행하면 다른 DB에 접속하는 법과 다른 점은 없다.
 

지금까지 JavaDB의 기본적인 설명을 다루었다. JavaDB를 사용해보면서 느낀 점은 가볍다는
것이었다. 향후 임베디드 시장에서의 활약을 기대해 보지만 이를 뚫기 위해 넘어야 할 난관이
많으며 이 중 오라클에서 Oracle Berkeley DB라는 오픈소스 기반 Lightweight 
데이터베이스와의 경쟁이 그 하나이다. 오라클은 Derby와 Oracle Berkeley DB의 성능을 비교한
문서를 공개하며 성능 이슈를 재기하고 있다. 임베디드 시장에서의 두 데이터베이스간의 활약이
기대하며 기고를 마친다.

참조 문헌 :
JavaDB 설치: http://developers.sun.com/javadb/downlo ··· ons.html
아파치 Derby 소개: http://db.apache.org/derby/docs/dev/getstart/
오라클 버클리 DB 소개: http://www.oracle.com/technology/produc ··· dex.html

"Java SE" 카테고리의 다른 글

Posted by 1010
01.JAVA/Java2008. 11. 12. 17:10
반응형

많은 사람들이 알고 있는 것처럼, JDBC는 자바 프로그램으로부터 관련된 데이터베이스에 이식가능한 액세스를 할 수 있는 메커니즘이다. 관련된 데이터베이스에 액세스하기 위해 사용자의 J2EE 애플리케이션의 JDBC를 사용할 수 있다. 이번 테크팁은 JDBC를 사용하는 간단한 애플리케이션을 보여주고 이식성과 유연성을 위한 몇 가지 유용한 JDBC 실습법을 소개한다.

JDBC의 소개

JDBC를 이용해서 데이터에 액세스하는 절차는 간단하다.

  1. 드라이버를 로드한다. 대부분의 경우 클래스이름으로 되어있다.

  2. 데이터베이스에 Connection 접속한다. 이름으로 DataSource 를 위한 JNDI를 호출하고 DataSource 로부터 Connection을 얻어서 접속할 수 있다. 이 절차는 동일한 서블릿 메소드인 getConnection 에서 실제적으로 볼 수 있을 것이다.

  3. Connection로부터 Statement 객체를 받는다. 각각의 Statement는 단일 SQL 커맨드를 나타낸다. StatementStatement의 출처가 되는 Connection에 묶여 있기 때문에 다른 Connection을 위해 재사용될 수가 없다.

  4. updateQuery(데이터를 업데이트하지만 결과는 리턴하지 않음)나 executeQuery(선정된 데이터의 ResultSet를 리턴함) 와 같은 Statement 메소드를 이용해 비즈니스 기능을 수행해 보자.

  5. ResultSet를 받았다면 다른 비즈니스 기능을 수행하기 위해 쿼리의 결과를 반복해서 실행해 보자.

이 팁의 샘플 코드에서는 jdbcservlet라고 불리는 서블릿을 사용하고 있다. 이 서블릿은 데이터베이스에 접속하여 임의의 SQL 구를 실행하도록 한다. 그리고 리턴되는 결과를 테이블의 형태로 보여주고, SAVEDQUERIES라고 불리는 테이블 안에 지명된 쿼리들을 저장할 수 있게 한다.

데이터베이스 생성하기

설명을 계속하기 전에 이 애플리케이션에 번들된 데이터 로딩 스크립트가 연결하고자 하는 데이터베이스 내의 테이블을 드롭하고 생성한다는 것을 기억해야 한다. 필요한 데이터를 포함하고 있는 데이터베이스에 연결하고 있지 않다는 것을 확실히 해야 한다.

안전한 데이터베이스에 연결하고 있다는 것을 확실히 확인할 수 있는 가장 좋은 방법은 작업이 끝났을 때 삭제해 버릴 수 있는 것을 하나 생성해 놓는 것이다. 이 팁은 썬으로부터 배포된 표준 J2EE 1.4에 탑재된 Java technology relational database management system (RDBMS)인 PointBase 를 사용한다. 이는 통합된 PointBase 드라이버에 부수되어 배포되기 때문에 가장 사용하기 쉬운 방법이다. 원한다면 고유의 데이터베이스를 생성하기 위해 제공자가 지정한 툴을 사용할 수도 있다. (이 경우, 배포 시에 몇 가지 사항만 변경하면 된다.) 데이터베이스를 생성하기 위해서는 "샘플 코드 실행하기"의 "팁 2: 데이터베이스 생성하기" 부분을 참고하기 바란다.

쿼리 실행하기

샘플 애플리케이션에 의해 디스플레이되는 메인 페이지에서 SQL 쿼리를 동반하는 텍스트 박스를 볼 수 있다.

이 쿼리를 실행하려면 Execute SQL 버튼을 클릭한다.

쿼리 결과의 일부분만을 편집한 것이다.

결과를 나타내는 폼은 3가지 영역을 갖는다.

  • 왼쪽 윗부분, 쿼리 박스
  • 오른쪽 윗부분, 저장된 쿼리의 리스트
  • 이하부분, 쿼리를 실행했을 때 나타나는 결과를 나타내는 테이블

데이터베이스의 데이터 출처는 퍼블릭 도메인 소스이다. 이는 이세상에 존재하는 나라들과 그곳에 사는 사람들에 관한 기초적인 통계를 보여준다.

Name 박스에 이름을 타이핑하고 Save Query 버튼을 클릭하여 흥미있는 쿼리를 저장할 수 있다. 이 쿼리는 오른쪽 Saved 쿼리 박스에 나타날 것이다. 링크를 클릭하여 저장된 쿼리를 실행해보자.

샘플 코드

이하의 샘플은 보기에는 복잡하지만 사실은 매우 간단하다. 이 코드의 핵심을 간추려보았다.

1. 드라이버 로드하기

드라이버를 로드하는 코드는 서블릿을 위한 init 메소드 내에 있다.

    public void init(ServletConfig config)
       throws ServletException {
       _config = config;

       // Load driver. If this fails, the rest won't work.
       try {
          String driver =
                   _config.getInitParameter("driver");
          Class.forName(driver).newInstance();
       } catch (Exception e) {
          throw new ServletException(e);
       }
    }

드라이버 클래스 이름은 서블릿 초기화 파라미터에서 왔다는 것을 기억하자. 이 파라미터는 웹 애플리케이션 배포 디스크립터인 web.xml에 설정되어 있다.

   <servlet>
     <description>Sample servlet</description>
     <display-name>Apr2004Servlet</display-name>
     <servlet-name>Apr2004Servlet</servlet-name>
     <servlet-class>
       com.elucify.tips.apr2004.Apr2004Servlet
     </servlet-class>
     <init-param>
       <description>
         This is the name of the JDBC driver
         used to connect to the database.
       </description>
       <param-name>driver</param-name>
       <param-value>
         com.pointbase.jdbc.jdbcUniversalDriver
       </param-value>
     </init-param>
     ...

드라이버 클래스의 이름을 배포 정보에 삽입하는 것은 좋은 습관이다. 드라이버 클래스를 변경해야 한다면(가령 다른 데이터베이스를 사용하고 있기 때문에), 코드를 변경하고 그것을 다시 컴파일하는 것 대신에 이를 배포 툴에서 해결할 수 있다.

데이터베이스 이름, 사용자, 패스워드의 경우 모두 동일하다.

2. 데이터베이스에 접속한다.

다음 메소드는 데이터베이스에 대한 Connection을 얻기 위해 사용된다.

    protected Connection getConnection() throws Exception {
       String dbname = _config.getInitParameter("dbname");
       String user = _config.getInitParameter("user");
       String pass = _config.getInitParameter("pass");

       InitialContext ic = new InitialContext();
       DataSource ds = (DataSource)ic.lookup(dbname);
       Connection conn = ds.getConnection(user, pass);

       return conn;
    }

Init 파라미터를 정의하고 지정하기

이와 같은 init 파라미터를 세팅하는 배포 디스크립터는 다음과 같다.

     <init-param>
       <description>
         This is the JDBC name of the database.
       </description>
       <param-name>dbname</param-name>
       <param-value>jdbc/PointBase</param-value>
     </init-param>

    <init-param>
      <description>
        The name of the database user.
      </description>
      <param-name>user</param-name>
      <param-value>PBPUBLIC</param-value>
    </init-param>

    <init-param>
      <description>
        The password for the user named above.
      </description>
      <param-name>pass</param-name>
      <param-value>PBPUBLIC</param-value>
    </init-param>

또 다시, 이러한 정보를 배포 디스크립터에 삽입하면 컴파일링을 다시 하지 않고서도 정보를 변경할 수 있게 해준다.

일반적으로 제작과정에서는 배포 디스크립터 파일에 패스워드를 저장하지 않는다. 인증을 잘 관리하기 위해서는 조직의 보안 책임자와 상담하는 것이 대부분이다. 위의 "jdbc/PointBase" 스트링값은 데이터베이스의 이름이다. 이 JDBC리소스는 Sun One 애플리케이션 서버 내에 미리 형성되어서 존재한다. 만약 다른 애플리케이션 서버를 사용한다면 데이터베이스의 이름을 찾기 위해 서버 다큐먼테이션을 보면 된다.(서버 다큐먼트를 직접 생성해야 할 수도 있다.)

3. 데이터베이스를 로드한다.

dataload 메소드는 WAR 아카이브 내의 파일(data/data.sql)로부터 sql 문을 읽어 들인다. 그리고 파일이 처리될 때까지 항목들을 하나씩 차례대로 실행한다. 이 메소드 코드의 대부분은 단순한 스트링 처리이다. 이러한 스티링 처리의 결과는 sqlcmd 라고 불리는 스트링 변수이다. sqlcmd StringBuffer 로 구축되었다. 이 메소드는 Connection 을 생성하고 Connection 으로부터 Statement를 받아서 sqlcmd 쿼리 스트링을 구축한다. 그리고나서 완전한 커맨드를 갖으면 sqlcmd.executeUpdate 에 그 스트링 값을 넘겨주게 된다.

   StringBuffer sbcmd = new StringBuffer();
   String line = "";
   Connection conn = null;

   try {
      // Get connection and statement
      conn = getConnection();
      Statement stmt = conn.createStatement();

      while ((line = in.readLine()) != null) {
         linenumber++;

         // ... line splitting, cleaning, joining, etc.
         // ... result is in sbcmd

          String sqlcmd = new String(sbcmd);
         
          // ... more housekeeping

          stmt.executeUpdate(sqlcmd);

   } catch (Exception e) {
      // ... blah blah
   } finally {
      if (conn != null) {
         try {
            conn.close();
         } catch (SQLException exc) {
            // Not much we can do about it here except...
            System.err.println
              ("Failed closing connection in dataload");
         }
      }
   }

dataload 메소드의 코드는 파일로부터 읽어 들인 SQL 구를 구축하고 Statement.executeUpdate 가 실행될 수 있도록 이를 넘겨준다. 이 메소드는 executeQuery 대신에 executeUpdate 를 사용하는데, 이유는 executeUpdate가 결과를 리턴하지 않고 데이터 로드 스크립트는 SELECT 구를 포함할 수 없기 때문이다.

메소드 dataload의 코드(method dataload code)내의 try/finally블록을 주의 깊게 살펴보자. 이 코드 블록은 중요한 연습방법을 따르고 있는데, 그것은 사용자가 커넥션에 관한 작업을 마쳤을 때 언제나 커넥션들이 닫혀져 있어야 한다는 것이다. 이렇게 하지 않았을 때 심한 리소스 누출이 생길 수 있다. 이런 경우, 서버의 커넥션 풀 안의 모든 커넥션은 닫혀있지 않은 커넥션에 의해 계속된다. 때문에 항상 try/finally블록에 Connection객체의 사용을 enclose하고 필요할 시 커넥션을 닫아야 한다.

서버-사이드 커넥션 관리에 있어 또 다른 주의 사항은, 만약 서버가 커넥션을 갖지 않는다는 사실을 파악하지 못했다면 커넥션 풀을 구현하려는 시도를 하지 말아야 한다는 것이다. 서버가 이미 커넥션을 갖고 있는 상태라면 커넥션 풀을 구현하려는 것은 시간 낭비일 수 있기 때문이다. 또한 서버 커넥션 풀과 애플리케이션 레벨의 풀 간에 경합은 애플리케이션의 퍼포먼스를 떨어뜨릴 수 있다. 말하자면 커넥션 풀링은 애플리케이션 프로그래머가 아닌 서버 프로그래머의 일이라는 것이다.

웹 애플리케이션에서 대부분의 경우처럼 서버가 커넥션 풀을 갖고 있다면 HTML 호출을 리턴하기 전에 커넥션을 항상 해제해야 한다. 만약 서버가 이미 공유되는 커넥션을 효율적으로 관리하고 있다면 이 공유 커넥션에 시간을 투자할 이유는 없다. 또한 서블릿이 불필요하게 데이터베이스 커넥션에 매달려있다면 애플리케이션의 속도를 늦출 수 있다.

4. SQL 문 실행하기

브라우저로부터 받은 SQL문은 데이터를 리턴하는 SELECT 문이거나 데이터를 리턴하지 않는 다른 문장일 수 있다. evalprint 메소드는 이후의 SQL이 SELECT 문이라면 Statement.executeQuery를 사용하고 그렇지 않으면 executeUpdate를 사용한다. 입력 서식에서 받은 사용자의 SQL을 실행시키는 코드는 다음과 같다.

   try {
      // Get connection and statement
      conn = getConnection();
      Statement stmt = conn.createStatement();
      ResultSet rs;

      // Execute posted sqlcmd
      if (sqlcmd.trim().toUpperCase().indexOf("SELECT ") == 0) {
         rs = stmt.executeQuery(sqlcmd);
         pw.println("<div class=\"results\">");
         pw.println("<h2>Query Results</h2>");
         printResultSet(pw, rs);
         pw.println("</div>");
      } else {
         stmt.executeUpdate(sqlcmd);
      }

5. 출력 결과

printResultSet 메소드는 HTML 테이블 형식으로 ResultSet객체를 출력한다. ResultSet객체를 위한 데이터 액세스 인터페이스는 SQL 결과를 다루기 쉽게 만든다.

   protected void printResultSet(PrintWriter pw, 
           ResultSet rs)
      throws SQLException {
      ResultSetMetaData rsmd = rs.getMetaData();
      int cols = rsmd.getColumnCount();
      int nrows = 0;

      pw.println("<TABLE class=\"tbl\">");
      pw.println("<TR class=\"hdrtr\">");
      for (int n = 1; n <= cols; n++) {
         pw.print
           ("<TD class=\"hdrcol hdrcol" + n + "\">");
         pw.print(rsmd.getColumnLabel(n));
         pw.println("</TD>");
      }
      pw.println("</TR>");

      while (rs.next()) {
         ++nrows;
         pw.println
           ("<TR class=\"datatr datatr" + nrows + "\">");
         for (int i = 1; i <= cols; i++) {
            pw.print("<TD class=\"datacol datacol" + 
                     i + "\">");
            pw.print(rs.getObject(i).toString());
            pw.println("</TD>");
         }
         pw.println("</TR>");
      }
      pw.println("</TABLE>");

      pw.println("<div class=\"rowcount\">");
      pw.println(nrows + " rows returned.");
      pw.println("</div>");
   }

JDBC에 관한 더 많은 정보는 자바 튜토리얼의 "JDBC Basics" 과 Fisher, Ellis, Bruce 의 "JDBC API Tutorial and Reference, Third Edition" 를 참고하기 바란다.

샘플코드 실행하기

주의: 2번째 팁의 샘플 코드를 실행하기 위해서는 J2EE서버를 시작하기 전에 PointBase 데이터베이스 서버를 먼저 시작해야 한다.

이 팁을 위한 샘플 아카이브를 다운로드 받자. 애플리케이션의 컨텍스트 루트는 ttapr2004이다. 다운로드된 ear 파일은 샘플을 위한 완성된 코드를 포함한다. deploytool 프로그램이나 어드민 콘솔을 이용해서 J2EE 1.4 Application Server에 애플리케이션 아카이브(ttapr2004.ear) 를 배포할 수 있다. 혹은 다음과 같은 asadmin 커맨드로 이를 배포할 수도 있다.

   asadmin deploy install_dir/ttapr2004.ear

install_dir를 war 파일을 인스톨한 디렉토리로 대체하자.

http://localhost:8000/ttapr2004에서 애플리케이션에 액세스할 수 있다.

Application Server이외의 J2EE 1.4에 호환되는 구현을 원한다면 플랫폼에 애플리케이션을 배포할 때 J2EE 제품의 배포툴을 이용하면 된다.

애플리케이션의 실행을 위한 설명은 index.jsp welcome 파일을 참고하기 바란다.

팁 1: JAR의 다운로드와 압축출기

팁 1의 샘플 코드는 apr2004-tip1.jar라고 불리는 JAR 파일 내의 애플리케이션 아카이브에 있다. apr2004-tip1.jar파일을 다운로드 받는 가장 쉬운 방법은 위에서 언급한 애플리케이션 EAR 파일을 배포하고 메인 페이지를 방문하여 Web 페이지의 첫번째 부분에 있는 다운로드 링크를 클릭하는 것이다.

또 다른 방법은 ttapr2004.ear 에서apr2004.war 를 처음 추출해낼 때 JAR 유틸리티를 이용하는 것이다. 그리고나서 apr2004.war 에서 apr2004-tip1.jar를 추출해낸다.

jar파일을 확보했다면 다음을 이용해서 내용물들을 모두 추출하자.

   $ jar xvf apr2004.jar

결과는 "apr2004"라고 불리는 디렉토리이고 코드와 컴파일된 클래스 지원 데이터 파일등과 함께 소스 파일을 포함하고 있다.

팁 2: 데이터베이스 생성하기

프로그램을 처음으로 실행할 때 데이터를 데이터베이스안에 로드해야 한다. 데이터베이스 로드 스크립트는 애플리케이션 아카이브 내에 있다. 데이터를 로드하기 위해 페이지에서 적절한 링크를 클릭하자. 데이터베이스가 6000줄이 넘기 때문에 시간이 좀 걸릴 수 있다.

데이터가 로드되었다면 텍스트 입력란에 SQL문을 입력하고 Execute SQL 버튼을 이용해서 그것을 실행한다.

이 글 뿐만 아니라 썬에서 제공하는 다른 샘플코드로부터 샘플 테이터를 볼 수 있다.

리스트에 저장된 쿼리를 클릭하면 이 쿼리를 위한 SQL문과 쿼리를 실행한 결과를 보게 된다.

가령, CountryBorders 를 클릭하면 다음과 같은 결과를 보게 된다.

"Java EE" 카테고리의 다른 글

Posted by 1010
01.JAVA/Java2008. 11. 12. 17:08
반응형

트랜잭션은 반드시 원자적으로 수행되어야하는 작업들의 모음이다. 다시 말해, 트랜잭션 전체가 성공적이기 위해서는 각각의 작업이 반드시 성공적 이어야 한다는 뜻이며, 어느 한 작업이라도 성공적이지 못하면 전체 트랜잭션이 실패하게 된다. 실패했을 경우에는, 앞서 성공적으로 수행된 작업들은 반드시 원상태로 되돌아가, 작업을 시작하기 이전의 상태와 일치해야한다.

예를 들어, A 은행계좌(계좌번호12345-1)에서 B 은행계좌(계좌번호 12345-2)로 $50를 송금하길 원하는 사람이 있다고 하자. 이 트랜잭션의 절차는 다음과 같이 "pseudo code(역자 주: 프로그램이 실행되기 전 기계 코드로 번역될 필요가 있는 것)"로 나타낼 수 있다.

   BOUNDARY: START TRANSACTION A
   SUBTRACT 50 DOLLARS FROM SAVINGS ACCOUNT 12345-1
   ADD 50 DOLLARS TO THE CHECKING ACCOUNT 12345-2
   BOUNDARY: END TRANSACTION A

트랜잭션을 구동하기 위해서는 다음의 코드가 필요하다.

   PREPARE (RUN) TRANSACTION A
   IF TRANSACTION A SUCCEEDED
       COMMIT TRANSACTION A
   ELSE
       ROLLBACK TRANSACTION A

A은행계좌에 $50을 송금하기 충분한 자금이 있다고 가정하고, 트랜잭션의 첫번째 단계가 성공했다고 치자. 컴퓨터가 50 달러를 B계좌에 전송하려고 시도했으나 B 계좌가 사용정지 중이어서 두번째 단계에서 실패했다면, 이 두번째 단계가 실패했기 때문에 전체 트랜잭션은 실패한 것이 된다. 결과적으로 첫번째 단계의 작업은 초기화 되어야 한다. 즉, 50달러는 A계좌로 다시 돌아가야하는 것이다. 이는 매우 중요한 사항인데, 그렇지 않으면 컴퓨터가 전송을 시도할 때마다 A계좌에서는 돈이 빠져나가는 셈이기 때문이다!

전체 트랜잭션이 성공한 경우에는 모두 실행되고 그 결과가 지속된다.

전 과정이 완성되기 위해서는 두 과정이 실행된다. 첫번째로, 트랜잭션이 오류 없이 구동 되었는지를 확인하는 검사가 실행된다. 오류가 없다면 두번째로 넘어가며, 에러가 있다면 트랜잭션은 초기화된다. 이런 일반적인 트랜잭션 방법은 두 과정 실행 프로토콜(two-phase commit protocol)이라고 불린다.

J2EE 환경에서의 트랜잭션

트랜잭션에는 일반적으로 다음의 세가지가 관계되어 있다. 1. 애플리케이션: 트랜잭션 요청 착수, 2. data store(데이터베이스 등):트랜잭션 구동, 3. API(드라이버 등):애플리케이션과 데이터 창고 간의 통신. J2EE 플랫폼에서는 J2EE- compliant 애플리케이션 서버에 의해 API(또는 드라이버)가 제공된다. 이 애플리케이션 프로그램은 애플리케이션 서버를 호출하여 트랙잭션을 수행한다.

JTA(Java Transaction API)는 J2EE 플랫폼에 포함되어 있다. 이API는 분포된 트랙잭션을 수행할 수 있도록 한다. 즉, 애플리케이션은 이 API를 사용하여 한번에 네트워크 상에 있는 여러 개의 data store에서 트랙잭션을 수행할 수 있게 된다. 그러나 이를 효율적으로 수행하기 위해서는 애플리케이션 서버에서 기능하는 또다른 컴포넌트인 J2EE 트랜잭션 매니저가 도움이 될 것이다. 트랜잭션 매니저는 애플리케이션 서버에서 생성되는 많은 수의 트랜잭션을 효율적으로 스케쥴링하여 실행하도록 돕는다.

많은 수의 데이터베이스 벤더들은 각 회사 고유의 트랜잭션 매니저를 제공하고 있다. 그러나 특정 DBMS의 트랜잭션 매니저는 다른 벤더들의 데이터베이스에서 작동하지 않을 수 있다. 이런 여러 종류의 데이터베이스에서 작업하고 싶다면(ex. 여러 벤더사의 각종 데이터베이스를 업데이트), JTA 트랜잭션과 이에 수반되는 J2EE 트랜잭션 매니저를 사용할 것을 권장한다. JTA 설명서에는, "JTA 트랜잭션은 J2EE 트랜잭션 매니저로 관리됩니다"라고 나와있다. J2EE 트랜잭션 매니저에는 한가지 한계가 있는데, J2EE 트랜잭션은 수평적이라는 것이다. J2EE에서는 중첩된 트랜잭션이 지원되지 않는다. 즉, 먼저 시작한 트랜잭션이 끝나기 전에는 J2EE 트랜잭션 매니저가 다음 트랜잭션을 시작할 수 없다.

J2EE를 사용하는 애플리케이션 서버는 JTS(Java Transaction Service)를 이용하여 트랜잭션 매니저를 구현한다. JTA는 낮은 레벨의 JTS 절차에 호출할 API를 제공한다. JTA와 JTS를 헷갈리지 않도록 주의하기 바란다.

JTA 습득하기

트랜잭션을 수행하기 위해 JTA와 사용할 수 있는 인터페이스는 세가지가 있으며, 각 인터페이스는 트랜잭션을 핸들링하는 각각의 고유 방법이 있다. 다음은 그 인터페이스들이다.

  • javax.transaction.UserTransaction : 트랜잭션 매니저를 우회하는 트랜잭션 영역을 지정할 수 있다.
  • javax.transaction.TransactionManager : J2EE 트랜잭션 매니저가 각종 트랜잭션 작업과 함께 트랜잭션의 영역도 결정할 수 있도록 한다.
  • javax.transaction.xa.XAResource : 이 인터페이스는 트랜잭션 수행을 위해 써드파티 XA-compliant 트랜잭션 매니저를 이용하는 X/Open CAE Specification (Distributed Transaction Processing: The XA Specification) 표준과 매핑된다.

대부분의 J2EE 프로그래머들이 첫번째 인터페이스만을 사용하기 때문에 이 인터페이스에 특히 초점을 맞추어 설명하도록 하자.

EJB 트랜잭션: 컨테이너 & 빈 관리 트랜잭션

J2EE 환경에서 트랜잭션을 수행하는 가장 논리적인 장소는 EJB(Enterprise JavaBeans) 기술 컴포넌트(엔터프라이즈 빈이라고도 불림) 내부이다. 엔터프라이즈 빈을 이용하여 트랜잭션을 수행하는 데에는 두가지 방법이 있는데, 첫번째로 EJB 컨테이너로 트랜잭션 영역을 관리하는 것이다. 컨테이너 관리 트랜잭션(container-managed transactions)이라고 불리며, 이 방법으로 프로그래머에게 부담을 좀 줄여줄 수 있다. 두번째 방법을 이용하여 엔터프라이즈 빈 코드의 트랜잭션 영역을 명확히 지정해 줌으로써 프로그래머가 좀 더 자유로울 수 있다. 이는 빈 관리 트랜잭션(bean-managed transactions)이라고 불린다.

컨테이너 관리 트랜잭션은 세션 빈, 엔터티 빈, 메시지 드리븐 빈 중 어떤 엔터프라이즈 빈과도 함께 이용할 수 있다. 컨테이너 관리 트랜잭션에서는 EJB컨테이너가 트랜잭션 영역을 설정한다. 일반적으로 개별적인 트랜잭션으로 빈에 한 개 이상의 메소드를 선정하면서 작업이 완료된다. 컨테이너는 메소드 시간부분 바로 전부터 메소드가 끝나기 바로 전까지 영역을 설정한다. 그러나, 컨테이너 관리 트랜잭션에서는 각각의 메소드만이 하나의 트랜잭션이 될 수 있다(다중 트랜잭션은 허용되지 않는다.) 빈을 배치할 때 빈의 어떤 메소드가 트랜잭션과 관계될 것인지 지정해야한다. 트랜잭션 속성을 설정하여 지정할 수 있다.

트랜잭션 속성은 엔터프라이즈 빈 메소드가 다른 엔터프라이스 빈 메소드를 호출할 때 트랜잭션의 범위를 조절한다. JTA 설명서에서는 엔터프라이즈 빈 메소드가 EJB 배포 기술자의 6개의 트랜잭션 속성 중에서 선정할 수 있다고 명시하고 있다.

트랜잭션 속성은 트랜잭션이 수반될 때 EJB 컨테이너가 클라이언트 엔터프라이즈 빈에 의해 호출된 메소드를 어떻게 처리해야하는지를 보여준다.

   <ejb-jar>
     ...
    <enterprise-beans>
    ... 
     </enterprise-beans>
     <assembly-descriptor>
       <container-transaction>
         <method>
           <ejb-name>BankBean</ejb-name>
           <method-intf>Remote</method-intf>
           <method-name>transferMoney</method-name>
           <method-params>
             <method-param>java.lang.String</method-param>
             <method-param>java.lang.String</method-param>
             <method-param>java.lang.double</method-param>
           </method-params>
         </method>
         <trans-attribute>Required</trans-attribute>
       </container-transaction>
     </assembly-descriptor>
   </ejb-jar>

다음은 6개의 트랜잭션 속성에 대해 스펙에 적혀있는 내용이다.

  • Required - 클라이언트가 트랙잭션 하에 구동되고 있을 때 엔터프라이즈 빈의 메소드를 호출하면, 그 메소드는 클라이언트의 트랜잭션 내에서 실행된다. 만약 이 클라이언트가 트랜잭션에 관계 없다면, 컨테이너는 메소드를 구동하기 전에 새로운 트랙잭션을 시작한다. 대부분의 컨테이너 관리 트랜잭션이 Required를 사용한다.
  • RequiresNew - 클라이언트가 트랙잭션 하에 구동되고 있을 때 엔터프라이즈 빈의 메소드를 호출하면 컨테이너는 그 클라이언트의 트랜잭션을 잠시 보류하고 새로운 트랜잭션을 시작하며 메소드에 호출 권한을 위임한다. 메소드가 완료되면 클라이언트의 트랜잭션을 다시 시작한다. 클라이언트가 트랜잭션에 관계 없다면, 컨테이너는 메소드를 구동하기 전에 새로운 트랜잭션을 시작한다.
  • Mandatory - 클라이언트가 트랜잭션하에 구동될 때 엔터프라이즈 빈의 메소드를 호출하면 그 메소드는 그 클라이언트 트랜잭션 하에서 실행된다. 클라이언트가 트랜잭션과 관계 없다면 컨테이너는 TransactionRequiredException을 던지게 된다. 엔터프라이즈 빈의 메소드가 반드시 클라이언트의 트랜잭션을 이용해야할 때 Mandatory 속성을 이용하자.
  • NotSupported - 클라이언트가 트랜잭션하에 구동될 때 엔터프라이즈 빈의 메소드를 호출하면 컨테이너는 메소드를 활성화하기 전데 클라이언트의 트랜잭션을 일시 중지하며, 메소드가 완료되면 컨테이너는 클라이언트 트랜잭션을 재시작한다. 클라이언트가 트랜잭션과 관련이 없다면 컨테이너는 메소드를 구동하기 전에는 새로운 트랜잭션을 시작하지 않는다. 트랜잭션을 필요로하지 않는 메소드에 대해 code>NotSupported 속성을 사용하자. 트랜잭션이 전체를 포함하기 때문에 이 속성은 성능 향상을 가져다줄 것이다.
  • Supports - 클라이언트가 트랜잭션 하에서 구동될 때 엔터프아리즈 빈의 메소드를 호출하면 메소드는 그 클라이언트 트랜잭션 하에서 실행된다. 클라리언트가 트랜잭셕과 관계 없다면 컨테이너는 메소드를 시작하기 전에 새로운 트랜잭션을 시작하지 않는다. 메소드의 트랜잭션 비헤이비어가 변할 수 있기 때문에, Supports 속성을 사용할 때는 주의가 필요하다.
  • Never - 클라이언트가 트랜잭션 하에서 구동될 때 엔터프라이즈 빈의 메소드를 호출하면 컨테이너는 RemoteException를 던진다. 클라이언트가 트랜잭션과 관계 없다면 컨테이너는 메소드를 구동하기 전에 새로운 트랜잭션을 시작하지 않는다.

컨테이너 관리 트랜잭션을 처음상태로 돌리는 데에는 두가지 방법이 있다. 시스템 예외상황이 던져지면 컨테이너는 자동적으로 트랜잭션을 원상태로 돌리게 된다. 또한 EJBContext 인터페이스의 setRollbackOnly() 메소드를 호출하여 원상태로 만들 수도 있다. 이 메소드는 컨테이너에게 트랜잭션을 초기화하도록 지시한다. 엔터프라이즈 빈이 애플리케이션 예외상황을 던지면, 자동적으로 초기화 되지는 않지만 setRollbackOnly()를 호출함으로써 초기화에 착수할 수는 있다. 컨테이너 관리 트랜잭션을 사용할 때에는 JTA 메소드들을 호출할 수 없다는 것을 명심하기 바란다. 세 메소드가 빈 관리 트랜잭션을 이용하기 위해 예약되어 있기 때문이다. 이 세 메소드는 다음과 같다.

  • 트랜잭션적 의미와 충돌되는 리소스 지정 기능; java.sql.Connectioncommit(), setAutoCommit(), rollback() 메소드 등
  • javax.ejb.EJBContextgetUserTransaction() 메소드
  • javax.transaction.UserTransaction의 모든 메소드

빈 관리 트랙잭션에서 세션 빈 또는 메세지 드리븐 빈에서의 코드는 트랜잭션 영역을 명확하게 지정한다. 엔터티 빈은 빈 관리 트랜잭션을 가질 수 없으며, 반드시 컨테이너 관리 트랜잭션을 이용해야한다. 세션 빈 또는 메시지 드리븐 빈을 위해 빈 관리 트랜잭션을 코딩할 때는 일반적으로 JDBC 또는 JTA 트랜잭션을 사용할 수 있다. JDBC 트랜잭션은 J2EE 트랜잭션 매니저가 아닌 데이터베이스 관리 시스템의 트랜잭션 매니저에 의해 관리된다. JDBC 트랜잭션을 수행하기 위해서는 java.sql.Connection 인터페이스의 commit() 메소드와 rollback() 메소드를 이용한다. 트랜잭션의 시작에는 가장 최근의 commit(), rollback(), connect() 문을 따르는 첫번째 SQL 명령문으로 시작된다. JTA 트랜잭션을 위해서는 javax.transaction.UserTransaction 인터페이스의 begin(), commit(), rollback() 메소드를 호출할 수 있다. begin() 메소드와 commit() 메소드는 트랜잭션 영역을 지정한다. 트랜잭션 작업이 실패했을 경우, 일반적으로 예외상황 핸들러가 rollback() 메소드를 호출하여 EJBException을 던진다. 다음의 코드에서는 javax.transaction.UserTransaction 인터페이스를 이용하여 빈 관리 트랜잭션을 수행하는 법을 보여준다.

      UserTransaction ut = context.getUserTransaction();

      try {
         ut.begin();
         // Do whatever transaction functionality is necessary
         ut.commit();
      } catch (Exception ex) {
          try {
             ut.rollback();
          } catch (SystemException syex) {
              throw new EJBException
                 ("Rollback failed: " + syex.getMessage());
          }
          throw new EJBException 
             ("Transaction failed: " + ex.getMessage());
       }   

JDBC 빈 관리 트랜잭션을 수행하는 코드도 이와 비슷하다. 그러나 그 코드는 데이터베이스 자동 연결 기능이 되지 않음을 주의해야한다. 이 방법으로 데이터베이스는 수반되는 모든 작업을 하나의 트랜잭션으로 취급한다.( commit() 메소드가 호출될 때까지)

   try {            
        Connection con = makeDatabaseConnection();
        con.setAutoCommit(false);           
        //  Do whatever database transaction functionality
        //  is necessary           
        con.commit();          
    } catch (Exception ex) {
        try {
            con.rollback();
        } catch (SQLException sqx) {
            throw new EJBException("Rollback failed: " +
                sqx.getMessage());
        }
    } finally {
        releaseDatabaseConnection();
    }

JTA 스펙에 나와있는 몇가지 조항을 소개한다.

빈 관리 트랜잭션을 이용하는 비상태 유지 세션 빈(stateless session bean)에서는 비즈니스 메소드가 반드시 실행되거나 트랜잭션을 초기화한 후 리턴되야한다 그러나 상태 유지 세션 빈(stateful session bean)에서는 이러한 제한이 없다. JTA 트랜잭션을 이용하는 상태 유지 세션 빈에서는 빈 인스턴스와 트랜잭션 사이의 연관성이 다중 클라이언트 호출을 망라하여 유지된다. 심지어는 클라이언트에 의해 호출된 각각의 비즈니스 메소드가 데이터베이스 연결을 통제할 때는 인스턴스가 트랜잭션을 완료할 때까지 관계가 유지된다. JDBC 트랜잭션을 이용하는 상태 유지 세션 빈에서는 다중 호출 시 JDBC 연결이 빈 인스턴스와 트랜잭션 사이의 관계를 유지한다. 연결이 끊기면, 관계는 유지되지 않는다.

JTA 빈 관리 트랜잭션을 사용할 때 한가지 메소드 제한이 있다. EJBContext 인터페이스의 getRollbackOnly() 메소드와 setRollbackOnly()메소드를 호출하면 안된다.(이 메소드들은 컨테이너 관리 트랜잭션에만 사용되어야한다.) 빈 관리 트랜잭션을 위해서는 UserTransaction 인터페이스의 getStatus() 메소드와 rollback() 메소드를 사용하기 바라며 또한, 트랜잭션적 의미와 충돌되는 resource-specific 기능을 사용하지 말기 바란다.

JTA와JTS에 대한 좀 더 자세한 정보는 J2EE Transaction page를 참고하기 바란다.

Java Transaction API에 대한 예제 코드 구동하기

  1. Java 트랜잭션 API 팁을 위한 예제 압축파일을 다운로드 받으세요.
  2. 예제 압축파일을 다운로드할 디렉토리를 변경하고,예제 압축파일을 위한 JAR file의 압축을 푸세요.
          jar xvf  ttJan2005jta.jar
    
    jta라는 이름의 디렉토리와 소스 코드, 컴파일된 클래스들, 다른 지원 파일들이 나타납니다.
  3. 애플리케이션 서버를 시작합니다. J2EE 1.4 SDK는 Sun Java System Application Server Platform Edition 8을 포함합니다. 정확하게 작동하기 위해서는 Sun Java Application Server 8.1 4Q2004또는 그 이후 버전이 필요합니다.
  4. PointBase 데이터베이스 서버를 시작합니다.
  5. jta 디렉토리로 변경합니다. Ant 스크립트(build.xml)를 사용자의 J2EE 홈 디렉토리에 지정하여 편집합니다.
  6. 명령창에 명령어를 입력합니다.
          ant create-db
    
    데이터베이스가 생성되고 "account" 테이블로 채워집니다. 테이블을 삭제하려고 할 때 데이터베이스의 시간이 지연되면, 컴퓨터를 재부팅하고 PointBase를 다시 시작하기 바랍니다.
  7. 명령어를 입력합니다.
          ant build
    
    ejb라는 디렉토리가 생성되고 두개의 JAR 파일(bank-client.jar, bank-ejb.jar)로 채워집니다.
  8. Deploy bank-ejb.jar를 배치하세요. Sun Java System Application Server Platform Edition 8 Admin Console을 이용하거나(Application->EJB Modules), 또는 Autodeploy 디렉토리에 파일을 복사하여(이 옵션 없이 서버를 인스톨 했을 때) 실행할 수 있습니다.
  9. ejb 디렉토리를 변경하고 다음의 명령어를 입력하면,
          appclient -client bank-client.jar
    

다음과 같은 결과가 나타납니다.

   --OUTPUT FROM APP CLIENT BEGIN--
   Using Bean Transaction Management (Database Transaction 
   Manager)...
   
   Balance of 12345-01 is: 100.0
   Balance of 12345-02 is: 0.0
   
   Now transferring 23.43 from 12345-01 to 12345-02
   
   Balance of 12345-01 is: 76.57
   Balance of 12345-02 is: 23.43
   
   Now transferring 23.43 from 12345-01 to fictional account 
   number 12345-10
   Balance should be the same as before...
   
   Balance of 12345-01 is: 76.57
   Balance of 12345-02 is: 23.43
   
   
   Now Using JTA Container Transaction Management...
   
   
   Now transferring 23.43 from 12345-01 to fictional account 
   number 12345-10
   Exception was caught.
   Balance should again be the same as before...
   
   Balance of 12345-01 is: 76.57
   Balance of 12345-02 is: 23.43
   
   --OUTPUT FROM APP CLIENT END-- 

"Java EE" 카테고리의 다른 글

Posted by 1010
01.JAVA/Java2008. 11. 12. 17:07
반응형

저자 Greg Murray

AJAX는 'Asynchronous JavaScript and XML'의 머리글자를 딴 것으로, 웹 애플리케이션이 웹 페이지에 대한 사용자 인터랙션을 효율적으로 처리할 수 있도록 하는 수단을 제공한다(사용자 인터랙션이 이루어질 때마다 페이지를 리프레시(새로 고침)하거나 전체 페이지를 리로드하는 번거로움을 덜어줌). 이는 또한 브라우저를 이용한 리치 비헤이비어(rich behavior)를 가능케 해준다(데스크톱 애플리케이션 또는 플러그인 기반 애플리케이션의 경우와 유사). AJAX 인터랙션은 백그라운드에서 비동기적으로 처리되고, 그 동안 사용자는 페이지에 대한 작업을 계속할 수 있다. AJAX 인터랙션은 웹 페이지 내의 JavaScript에 의해 시작되는데, AJAX 인터랙션이 완료되면 JavaScript는 페이지의 HTML 소스를 업데이트한다. 변경 작업은 페이지 리프레시 없이 즉시 이루어진다. 이 AJAX 인터랙션은 서버측 논리를 이용한 폼 엔트리 검증(사용자가 입력하는 동안), 서버의 상세 데이터 검색, 페이지 상의 데이터에 대한 동적 업데이트, 그리고 페이지에서 폼을 부분적으로 제출하는 등의 작업에 이용될 수 있다.

여기서 특히 흥미를 끄는 부분은 AJAX 애플리케이션이 별도의 플러그인을 요구하지 않으며 플랫폼/브라우저 중립적 특성을 지니고 있다는 점이다. 첨언하자면, 구형 브라우저에서는 AJAX가 충분히 지원되지 않으며, 브라우저간의 차이를 유발하는 클라이언트측 스크립트를 작성할 때는 주의를 기울여야 한다. 따라서 브라우저의 차이를 추상화(abstract)하는 JavaScript 라이브러리를 사용하거나 경우에 따라서는 대체 인터랙션 기법을 이용하여 구형 브라우저를 지원하는 것도 좋은 방법이 될 수 있다. 자세한 내용은 자바 개발자를 위한 AJAX FAQ(영문)를 참조할 것.

자바 기술은 어떤 작업에 적합한가?

자바 기술과 AJAX는 서로 궁합이 잘 맞는다. 자바 기술은 AJAX 인터랙션을 위한 서버측 프로세싱 기능을 제공하는데, 이는 서블릿, JSP(JavaServer Pages) 기술, JSF(JavaServer Faces) 기술, 웹 서비스 등을 통해 제공될 수 있다. AJAX 요청 처리를 위한 프로그래밍 모델은 종래의 웹 애플리케이션에서 사용하던 것과 동일한 API를 사용한다. JSF 기술은 클라이언트측 JavaScript와 그에 대응하는 서버측 AJAX 프로세싱 코드를 작성하는 재사용 가능 컴포넌트를 생성하는 데 사용될 수 있다. 이제 AJAX와 서블릿의 활용 예제를 살펴보기로 하자.

자동 완성(autocomplete) 예제

사용자가 종업원에 관한 정보를 검색할 수 있는 웹 페이지를 상상해보자. 이 페이지에는 사용자가 종업원의 이름을 입력할 수 있는 필드가 포함되어 있다. 이 예제에서 엔트리 필드는 자동 완성(autocomplete) 기능을 가지고 있는데, 다시 말해 사용자가 종업원 이름의 일부를 입력하면 웹 애플리케이션은 입력한 문자로 이름이나 성이 시작되는 모든 종업원을 열거하여 이름을 자동으로 완성하게 된다. 자동 완성 기능은 사용자가 종업원의 정식 이름을 일일이 기억하거나 다른 페이지에서 이름을 찾아보아야 하는 번거로움을 덜어준다.

autocomplete example

검색 필드의 자동 완성 기능은 AJAX를 이용해서 구현될 수 있으며, 이를 위해서는 클라이언트와 서버 상에 코드를 제공해야 한다.

클라이언트 상에서

먼저, 사용자가 브라우저에 의해 로드되는 페이지의 URL을 지정한다. 한편, 이 예제에서는 JSF 컴포넌트, 서블릿, 또는 JSP 페이지에 의해 생성되는 HTML 페이지가 사용되었다고 가정하자. 페이지에는 JavaScript 함수 doCompletion()의 이름으로 된 onkeyup 속성을 가지는 폼 텍스트 필드가 포함되고, 이 함수는 폼 텍스트 필드에서 키를 누를 때마다 호출된다.

    <input type="text"
          size="20"
          autocomplete="off"
          id="complete-field"
                      name="id"
          onkeyup="doCompletion();">

사용자가 폼 텍스트 필드에 문자 "M"을 입력한다고 가정해보자. 그에 대한 응답으로 doCompletion() 함수가 호출되고, doCompletion() 함수는 다시 XMLHttpRequest 오브젝트를 초기화한다.

   function initRequest(url) {
       if (window.XMLHttpRequest) {
           return new XMLHttpRequest();
       } else if (window.ActiveXObject) {
           isIE = true;
           return new ActiveXObject("Microsoft.XMLHTTP");
       }
   }

   function doCompletion() {
       if (completeField.value == "") {
           clearTable();
       } else {
           var url = "autocomplete?action=complete&id=" + 
                   escape(completeField.value);
           var req = initRequest(url);
           req.onreadystatechange = function() {
               if (req.readyState == 4) {
                   if (req.status == 200) {
                       parseMessages(req.responseXML);
                   } else if (req.status == 204){
                       clearTable();
                   }
               }
           };
           req.open("GET", url, true);
           req.send(null);
       }
   }

XMLHttpRequest 오브젝트는 현재 표준 JavaScript에 포함되지는 않지만(표준화를 위한 노력이 진행중임), 사실상의 표준이자 AJAX의 핵심이라 할 수 있다. 이 오브젝트는 HTTP를 통해 서버측 컴포넌트(이 경우에는 서블릿)와 상호 작용하는 부분을 담당한다.

XMLHttpRequest 오브젝트 생성 시 URL, HTTP 메소드(GET 또는 POST), 그리고 상호작용의 비동기 여부 등 세 가지 매개변수가 지정된다. XMLHttpRequest 예제에서 매개변수는 다음과 같다.

  • URL autocomplete 및 전체 필드(complete-field)의 텍스트(M 문자):
         var url = "autocomplete?action=complete&id=" + 
                 escape(completeField.value);
    
  • GET(HTTP 인터랙션이 GET 메소드를 사용함을 의미) 및 true(인터랙션이 비동기적임을 의미):
         req.open("GET", url, true);
    

비동기 호출을 이용할 때는 callback 함수를 설정해야 하는데, XMLHttpRequestreadyState 속성이 변경될 경우 이 callback 함수는 HTTP 인터랙션 과정의 특정 포인트에서 비동기적으로 호출된다. 예제에서 callback 함수는 processRequest()이며, 함수에 대해 XMLHttpRequest.onreadystatechange 속성으로 설정된다. readState가 "4"’일 경우 parseMessages 함수에 대한 호출에 주목할 것. "4"의 XMLHttpRequest.readyState는 HTTP 인터랙션이 성공적으로 완수되었음을 나타낸다.

XMLHttpRequest.send()가 호출되면 HTTP 인터랙션이 시작되고, 인터랙션이 비동기적이면 브라우저는 계속해서 페이지의 이벤트를 처리한다.

서버 상에서

XMLHttpRequest는 URL 자동 완성에 대해 HTTP GET을 요청하고, autocomplete라 불리는 서블릿으로의 매핑이 수행된다. 그리고, AutoComplete 서블릿의 doGet() 메소드가 호출된다. 다음은 doGet() 메소드의 형태이다.

   public void doGet(HttpServletRequest request, 
           HttpServletResponse response) 
        throws IOException, ServletException { 
       ... 
       String targetId = request.getParameter("id"); 
       Iterator it = employees.keySet().iterator(); 
       while (it.hasNext()) { 
           EmployeeBean e = (EmployeeBean)employees.get(
                   (String)it.next()); 
           if ((e.getFirstName().toLowerCase().startsWith(targetId) || 
              e.getLastName().toLowerCase().startsWith(targetId)) 
              && !targetId.equals("")) { 
              sb.append("<employee>"); 
              sb.append("<id>" + e.getId() + "</id>"); 
              sb.append("<firstName>" + e.getFirstName() + 
                      "</firstName>"); 
              sb.append("<lastName>" + e.getLastName() + 
                      "</lastName>"); 
              sb.append("</employee>"); 
              namesAdded = true; 
           } 
       } 
       if (namesAdded) { 
           response.setContentType("text/xml"); 
           response.setHeader("Cache-Control", "no-cache"); 
           response.getWriter().write("<employees>" + 
                   sb.toString() + "</employees>"); 
       } else { 
           response.setStatus(HttpServletResponse.SC_NO_CONTENT); 
       } 
    }

이 서블릿을 보면 알 수 있듯이, AJAX 처리를 위해 서버측 코드 작성 방법을 배우는 데 필요한 새로운 내용은 전혀 나와있지 않다. XML 문서를 교환하고자 할 경우에 대비해서 응답 컨텐트 유형을 text/xml로 설정해야 하는데, AJAX의 경우에는 평문(plain text) 또는 심지어 클라이언트 상의 callback 함수에 의해 평가되거나 실행될 수 있는 JavaScript의 단편도 교환이 가능하다. 일부 브라우저는 결과를 캐시할 수 있으므로 Cache-Control HTTP 헤더를 no-cache로 설정할 필요가 있을 수 있다는 점에도 역시 유의할 것. 이 예제에서 서블릿은 이름이나 성이 문자 M으로 시작되는 모든 종업원을 포함하는 XML 문서를 생성한다. 다음은 호출을 한 XMLHttpRequest 오브젝트로 반환되는 XML 문서의 예제이다.

   <employees>
      <employee>
        <id>3</id>
        <firstName>George</firstName>
        <lastName>Murphy</lastName>
      </employee>
      <employee>
        <id>2</id>
        <firstName>Greg</firstName>
        <lastName>Murphy</lastName>
      </employee>
      <employee>
        <id>11</id><firstName>Cindy</firstName>
        <lastName>Murphy</lastName>
        </employee>
      <employee>
        <id>4</id>
        <firstName>George</firstName>
        <lastName>Murray</lastName>
      </employee>
      <employee>
        <id>1</id>
        <firstName>Greg</firstName>
        <lastName>Murray</lastName>
     </employee>
   </employees>

다시 클라이언트로

처음 호출을 한 XMLHttpRequest 오브젝트가 응답을 받을 경우, parseMessages() 함수가 호출된다(자세한 내용은 이 예제의 앞 부분에 있는 XMLHttpRequest의 초기화를 참조). 다음은 parseMessages() 함수의 모습이다.

   function parseMessages(responseXML) {
       clearTable();
           var employees = responseXML.getElementsByTagName(
                   "employees")[0];
       if (employees.childNodes.length > 0) {
           completeTable.setAttribute("bordercolor", "black");
           completeTable.setAttribute("border", "1");
       } else {
           clearTable();
       }
    
       for (loop = 0; loop < employees.childNodes.length; loop++) {
           var employee = employees.childNodes[loop];
           var firstName = employee.getElementsByTagName(
                   "firstName")[0];
           var lastName = employee.getElementsByTagName(
                   "lastName")[0];
           var employeeId = employee.getElementsByTagName(
                   "id")[0];
           appendEmployee(
                   firstName.childNodes[0].nodeValue,
                   lastName.childNodes[0].nodeValue, 
                   employeeId.childNodes[0].nodeValue);
       }
   }

parseMessages() 함수는 AutoComplete 서블릿이 반환한 XML 문서의 오브젝트 표현을 매개변수로 수신하는데, 이 함수는 XML 문서를 프로그램적으로 traverse한 다음 결과를 이용하여 HTML 페이지의 컨텐츠를 업데이트한다. 이 작업은 XML 문서 내의 이름에 대한 HTML 소스를 ID가 "menu-popup"’인 <div> 엘리먼트로 inject함으로써 수행된다.

   <div style="position: absolute; 
      top:170px;left:140px" id="menu-popup">

사용자가 문자를 더 많이 입력할수록 목록 길이는 줄어들게 되고, 이어서 사용자는 여러 이름 중 하나를 클릭할 수 있다.

이제 여러분은 AJAX가 단순히 페이지의 백그라운드에서 HTTP를 통해 정보를 교환하고 결과를 토대로 해당 페이지를 동적으로 업데이트한다는 것을 알게 되었을 것이다. AJAX와 자바 기술에 관한 자세한 내용은 테크니컬 아티클 Asynchronous JavaScript Technology and XML (AJAX) With Java 2 Platform, Enterprise Edition(영문)을 참조하기 바란다. 아울러 AJAX BluePrints 페이지(영문)와 Greg Murray의 블로그에 실려 있는 AJAX FAQ for the Java Developer(영문)의 내용도 함께 참조할 것.

예제 코드 실행하기

본 팁에는 본문에서 다루어진 기법을 예시하는 예제 패키지가 첨부되어 있는데, Servlet 2.4 이상의 API를 지원하는 웹 컨테이너라면 모두 예제 패키지 설치가 가능하다. 예제를 설치하고 실행하려면 다음 단계를 따르도록 한다.

  1. 먼저 GlassFish Project 페이지(영문)에서 GlassFish를 다운로드해야 하는데, GlassFish는 Servlet 2.5와 JSTL(JSP Standard Tag Library)을 곧바로 지원한다. 만약 J2EE 1.4 또는 Servlet 2.4 컨테이너를 사용하고 있다면 JSTL JAR 파일을 web/WEB-INF/lib 디렉터리에 포함시켜야 할 수도 있다.
  2. 다음의 환경 변수를 설정한다.
    • GLASSFISH_HOME. This should point to where you installed GlassFish (for example C:\Sun\AppServer) GLASSFISH_HOME. GlassFish 설치 장소를 가리켜야 한다(가령 C:\Sun\AppServer).
    • ANT_HOME. ant 설치 장소를 가리켜야 한다. ant는 다운로드한 GlassFish 번들에 포함되어 있다. (Windows의 경우에는 lib\ant 서브디렉터리 내에 위치함.)
    • JAVA_HOME. 시스템에서의 JDK 5.0 위치를 가리켜야 한다.

    아울러, ant 위치를 PATH 환경 변수에 추가한다.

  3. 예제 파일을 다운로드하여 압축을 해제한다. 이제 새로 추출된 디렉터리가 <install_dir>\ajax-autocomplete로 표시되어야 하는데, 예를 들어 Windows 컴퓨터의 C:\에 압축을 풀었다면 새로 생성된 디렉터리는 C:\ajax-autocomplete가 되어야 한다

  4. ajax-autocomplete 디렉터리로 이동해서 build.properties 파일에 build.properties.sample을 복사한다.

  5. build.properties 파일을 열고 Servlet 2.4 이상의 API를 포함하는 JAR 파일에 servlet.jar 속성을 설정한다. GlassFish의 경우 JAR 파일은 <gf_install_dir>/glassfish/lib/javaee.jar인데, 여기서 <gf_install_dir>은 GlassFish가 설치된 곳이다. javaee.autodeploy를 웹 컨테이너가 애플리케이션을 자동 설치할 디렉터리로 설정한다. GlassFish의 경우 이 디렉터리는 <gf_install_dir>/glassfish/domains/domain1/autodeploy이다.

  6. 6. 다음 명령어를 입력하여 GlassFish를 시작한다.
    <GF_install_dir>\bin\asadmin start-domain domain1
    
    이 때, <GFinstall_dir>은 Glassfish가 설치된 디렉터리이다.

  7. ant 툴을 이용하여 애플리케이션을 구축하고 설치한다. Glassfish는 /glassfish/bin/asant 디렉터리에 ant의 사본을 가지고 있고, 또한 Apache Ant Project 페이지(영문)에서 ant를 다운로드할 수도 있다.

    애플리케이션을 구축하려면 다음 명령어를 입력한다.
          ant
    
    애플리케이션을 설치하려면 다음 명령어를 입력한다.
          ant deploy
    
  8. 브라우저를 다음의 URL로 연다: http://localhost:8080/ajax-autocomplete/.

    NetBeans 4.1 이상을 사용하고 있다면 예제가 포함되어 있을 것이고, Help -> BluePrints Solutions Catalog를 선택하여 툴에서 이를 실행할 수 있다. 여기서 AJAX -> Autocomplete 예제를 선택하면 된다. 이제 NetBeans 내에서 예제를 실행할 수 있으며 원할 경우 수정도 가능하다.

    예제를 실행하면 다음과 같은 모습이 된다.
    example autocomplete

    목록의 이름을 클릭하면 종업원에 관한 정보가 표시된다.
    example autocomplete - Employee Info

필자 소개

서블릿 스펙 분야를 주도하고 있는 Greg Murray는 Java BluePrints 팀의 전 멤버로, 웹 티어 권고(recommendations) 부문을 담당한 바 있으며, 현재 그는 BluePrints 팀의 도움을 받아 썬의 AJAX 프로젝트를 이끌고 있습니다. 또한 Greg은 국제화, 웹 서비스, J2SE 독립형 클라이언트, AJAX 기반 웹 클라이언트 등의 분야에서 다양한 경력을 쌓기도 했습니다.

"Java EE" 카테고리의 다른 글

Posted by 1010
01.JAVA/Java2008. 11. 12. 16:19
반응형

향상된 루프문

Java SE 2005/07/04 10:24 Posted by Sun

J2SE 5.0의 새로운 언어 기능으로 소개된 향상된 루프문(enhenced for loop)은 Iterator를 생성하거나 카운터 변수의 시작과 끝 상태를 계산할 필요 없이 콜렉션을 반복할 수 있게 해준다. 향상된 루프문은 J2SE 5.0의 새로운 기능들 중 사용자의 코드에 즉시 적용시킬 수 있는 가장 쉬운 기능이다. 이번 테크팁에서는 향상된 루프문으로 콜렉션의 엘리먼트에 순차적으로 액세스하는 이전 방법을 대체하는 법에 대해서 배워보자.

향상된 루프문은 어떻게 생겼는가? RecentTips이라고 불리는 TechTip 오브젝트들의 콜렉션이 있다고 치자. 이 콜렉션에 다음과 같이 향상된 루프문을 사용할 수 있다.

   for (TechTip tip: RecentTips)

"for each TechTip in RecentTips(RecentTips안에 각각의 TechTip)"이라고 읽는다. 여기서 콜렉션 내의 TechTip의 현재 인스턴스를 가리키기 위해 tip 변수가 사용되었다. "for each" 단어 때문에, 향상된 생성문은 for-each 생성문으로도 불린다.

콜렉션을 반복하기 위해 사용한 기존 방법과 향상된 루프문을 비교한다면, for each loop이 더 간단하고 사용자의 코드를 보다 읽기 쉽게 만들어준다는 것을 쉽게 알 수 있다.

또한 향상된 루프문은 제너릭 작업을 간단히 할 수 있게 디자인되었다. 이번 테그팁에서 제너릭에 향상된 루프문을 사용한 두가지 예를 보여주겠지만, 이번 테크팁에서 다루고자 하는 부분은 아니다. 대신, for each loop 를 사용하여 코드에 줄 수 있는 좀 더 기본적인 변화에 대해서 보여주고자 한다.

먼저, Array 의 엘리먼트들을 반복하기 위해 루프문을 어떻게 사용하고자 하는 지 생각해보자. 간단히 하기 위해, 0부터 5까지 int의 제곱을 나타내는 6개의 int로 이루어진 배열을 로딩한다.

   for (int i=0; i< squares.length; i++)

이 라인은 루프구문의 전통적인 사용법을 보여준다. 한 개 이상 카운터의 초기값을 지정하고, 완료 상태를 설정하고 어떻게 카운터가 증가하는지 보여준다.

Here is a short program, OldForArray, that uses the for loop.

   public class OldForArray {

     public static void main(String[] args){
       int[] squares = {0,1,4,9,16,25};
       for (int i=0; i< squares.length; i++){
         System.out.printf("%d squared is %d.\n",i, squares[i]);
       }
     }
   }

OldForArray 프로그램을 컴파일하고 구동하면 다음이 나타난다.

   0 squared is 0.
   1 squared is 1.
   2 squared is 4.
   3 squared is 9.
   4 squared is 16.
   5 squared is 25.

향상된 루프문을 사용하도록 테스크 프로그램을 변경하려면, 관련 변수와 변수들이 나타나는 콜렉션을 지정한다. 다음은 향상된 루프문이다.

   for (int i : squares)
이 라인은 "iterate on elements from the collection named squares. (squere라는 이름의 콜렉션의 엘리먼트 반복) "로 읽을 수 있다.리먼트는 int i로 나타날 것이다.

루핑 전에 배열에 있어야할 엘리먼트의 수를 결정할 필요는 없다. 또한 현재 상태에서 어떻게 증가할지도 지정할 필요가 없다. "내부적" 배열에 대한 향상된 루프문은 이전에 보여준 루프문과 동일하다.

테스트 프로그램인 NewForArray에서는 OldForArray에서와 같은 결과가 나타난다.

    public class NewForArray {

     public static void main(String[] args) {
       int j = 0;
       int[] squares = {0, 1, 4, 9, 16, 25};
       for (int i : squares) {
         System.out.printf("%d squared is %d.\n", j++, i);
       }
     }
   }

배열은 배열이 선언될 때 지정되는 싱글 타입 엘리먼트들의 색인화된 콜렉션이다. ArrayList와 같은 좀 더 일반적인 콜렉션에서는 엘리먼트가 Object로 저장된다.다음과 같이 콜렉션을 반복하는 C 스타일 루프문을 사용할 수 있다.

   for (int i = 0; i < list.size(); i++)

그 후 llist.get(i)를 사용하여 현재 엘리먼트를 레퍼런스할 수 있다. 예를 들어, 다음의 프로그램 OldForArrayList에서는 ArrayList을 채워서 ArrayList에서 읽기 위해 오토박싱을 사용한다.

   import java.util.ArrayList;
   import java.util.List;

   public class OldForArrayList {
     private static List squares = new ArrayList();

     private static void fillList() {
       for (int i = 0; i < 6; i++) {
         squares.add(i * i);
       }
     }

     private static void outputList() {
       for (int i = 0; i < squares.size(); i++) {
         System.out.printf("%d squared is %d.\n",
           i, squares.get(i));
       }
     }

     public static void main(String args[]) {
       fillList();
       outputList();
     }
   }

그러나 ArrayList가 콜렉션 프레임의 일부이기 때문에, 다음의 패턴에서 Iterator를 사용하여 이를 반복하는 것이 좀 더 일반적이다.

   while( iterator.hasNext()) {
     doSomethingWith (iterator.next());
   }

다음의 프로그램 IteratorForArrayList에 나타난 것처럼 이를 루프문에 번들할 수 있다.

   import java.util.ArrayList;
   import java.util.List;
   import java.util.Iterator;

   public class IteratorForArrayList {

     private static List squares = new ArrayList();

      private static void fillList() {
       for (int i = 0; i < 6; i++) {
         squares.add(i * i);
       }
     }

     private static void outputList() {
       Iterator iterator = squares.iterator();
       int j=0;
       for (; iterator.hasNext();) {
         System.out.printf("%d squared is %d.\n",
                            j++, iterator.next());
       }
     }

     public static void main(String args[]) {
       fillList();
       outputList();
     }
   }

루프문에 첫번째 혹은 세번째 매개변수가 없다는 것이 좀 이상해보일지 모른다. 초기 상태가 없고, List에서의 포지션 증가가 루프문의 본문에서 iterator.next()를 호출하여 수행된다.

향상된 루프문은 불필요한 반복문을 명확하게한다. ArrayList에 대한 Iterator 오브젝트를 생성하여 루프문에 반목문을 사용하는 대신, 다음을 이용한다.

  for ( Integer square : squares)

이는 콜렉션의 이름이 squares이고, 현재 참조된 아이템이 Integer타입이며, 변수 square로 참조되고 있음을 가리키고 있다.

ArrayList의 컨텐츠가 Integer 타입임을 알 수 있는 방법이 없으므로 이 코드는 컴파일되지 않을 것이다. 이를 수정하기 위해서, J2SE 5.0에 소개된 또다른 기능인, 제너릭을 사용해야한다. Integer 타입의 엘리먼트만을 저장할 수 있는 것으로 squares의 정의와 선언문을 정의해주어야한다. 다음과 같이 하면 된다.

   private static List<Integer> squares
                               = new ArrayList<Integer>();

다음의 프로그램, NewArrayList은 향상된 루프문과 제너릭을 함께 사용하는 법을 보여준다.

   import java.util.List;
   import java.util.ArrayList;

   public class NewArrayList {
     private static List<Integer> squares
                               = new ArrayList<Integer>();

      private static void fillList() {
       for (int i = 0; i < 6; i++) {
         squares.add(i * i);
       }
     }

     private static void outputList() {
       int j=0;
       for (Integer square : squares) {
         System.out.printf("%d squared is %d.\n",
                         j++, square);
       }
     }

     public static void main(String args[]) {
       fillList();
       outputList();
     }
   }

NewArrayList 예제는 극단적으로 간단한 것이지만, 루프 일반문과 향상된 루프문 사이의 구문적 차이점을 보여주고 있다. 다음은 루프문들간의 구문적 차이를 보여주는 또다른 예제이다. 이 예제는 2004년 JavaOne 컨퍼런스에서 Joshua Bloch and Neil Gafter의 담화를 발췌한 것이다. 이 예제에서, 메소드는 콜렉션의 각 엘리먼트에 사용된다. 처음 시작할 때, 이 예제에서는 다음과 같이 Iterator를 사용한다.

   void cancelAll (Collection c) {
     for (Iterator i = c.iterator(); i.hasNext(); ) {
       TimerTask tt = (TimerTask) i.next();
       tt.cancel();
     }
   }

다음으로, 향상된 루프문이 도입되어 Iterator의 사용을 삭제한다.

   void cancelAll( Collection c ) {
     for (Object o : c)
       ( (TimerTask) o). cancel();
   }

콜렉션의 엘리먼트를 Object 타입으로 취급해서 TimerTask 타입으로 캐스팅된다는 문제가 남아있다. 이 문제는 다음과 같이 제너릭을 도입하면 해결된다.

   void cancelAll( Collection c ) {
     for (TimerTask task : c)
       task.cancel();
   } 

향상된 루프문이 모든 곳에 사용될 수는 없다는 것을 알아두길 바란다. 다음과 같은 상황에서는 사용할 수 없다.

  • 콜렉션을 순회하면서 엘리먼트를 삭제할 때
  • 배열이나 리스트에서 현재 슬롯을 수정할 때
  • 다중 콜렉션이나 배열을 반복할 때

그러나, 위의 경우들을 제외하고는 향상된 루프문의 사용하여 코드를 좀 더 간단히 하기 바란다.

새로운 것들이 언제나 그렇듯이, 향상된 루프문은 조금 낯설고 읽기 어렵게 느껴질 수도 있다. 이전에는 오랫동안 루프문에 C 스타일을 사용했을 것이다. 그러나, 카운터 변수나 Iterator를 갖지 않는 것이 더 읽기 쉽다. 또한 초기 값과 루프 종료 상태를 설정하는데 있어 사용자의 콜렉션이 어디에서 시작하고 끝나는지 걱정할 필요가 없다.

향상된 루프문에 대한 좀 더 자세한 정보는 The For-Each Loop를 참고하기 바란다.

"Java SE" 카테고리의 다른 글

Posted by 1010
01.JAVA/Java2008. 11. 11. 10:13
반응형
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTML;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.HttpURLConnection;
import java.util.Enumeration;
import javax.swing.text.BadLocationException;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML.Tag;
import javax.swing.text.html.parser.ParserDelegator;
public class HTMLParsing
{
 //파서는 콜백 형식으로 되어 있다. 각 태그가 들어 올때 적절한 메소드가 호출됨
 private class CallbackHandler extends HTMLEditorKit.ParserCallback
 {
  @Override
  public void flush() throws BadLocationException
  {
   System.out.println("flush");
  }
  @Override
  public void handleComment(char[] data, int pos)
  {
   System.out.println("Cmt " + new String(data));
  }
  @Override
  public void handleEndOfLineString(String eol)
  {
   System.out.println("EOL ");
  }
  @Override
  public void handleEndTag(Tag t, int pos)
  {
   System.out.println("End </" + t + ">");
  }
  @Override
  public void handleError(String errorMsg, int pos)
  {
//   System.out.println("ERROR\t" + new String(errorMsg));
  }
  @Override
  public void handleSimpleTag(Tag t, MutableAttributeSet a, int pos)
  {
   System.out.print("Sim <" + t.toString() + ">\n");
   for (Enumeration e = a.getAttributeNames(); e.hasMoreElements();)
   {
    Object attributeName = e.nextElement();
    System.out.print("\t" + attributeName + "=");
    System.out.println(a.getAttribute(attributeName));
   }
  }
  @Override
  public void handleStartTag(Tag t, MutableAttributeSet a, int pos)
  {
   System.out.println("Str <" + t + ">");
   for (Enumeration e = a.getAttributeNames(); e.hasMoreElements();)
   {
    Object attributeName = e.nextElement();
    System.out.print("\t" + attributeName + "=");
    System.out.println(a.getAttribute(attributeName));
   }
  }
  public void handleText(char[] data, int pos)
  {
   System.out.println("\t\t" + new String(data));
  }
 }
 public void parse(String str)
 {
  try
  {
   //입력받은 URL에 연결하여 InputStream을 통해 읽은 후 파싱 한다.
   URL url = new URL(str);
   HttpURLConnection con = (HttpURLConnection) url.openConnection();
   InputStreamReader reader =
     new InputStreamReader(con.getInputStream(), "euc-kr");
   new ParserDelegator().parse(reader, new CallbackHandler(), true);
   con.disconnect();
  } catch (Exception e)
  {
   e.printStackTrace();
  }
 }
 public static void main(String[] args)
 {
  HTMLParsing parser = new HTMLParsing();
  parser.parse("http://ecos.bok.or.kr/jsp/use/100keystat/100KeyStatCtl.jsp");
 }
}
Posted by 1010
01.JAVA/Java2008. 11. 10. 11:28
반응형
이곳은 50001.COM 주인장의 강좌와 주옥같은 JAVA고수님들의 강좌를 모아 놓은 곳입니다.
질문은 Q&A 게시판에 주세요.

들어가는 글 :: "시작하는 JAVA프로그래머를 위해" (특히 비 전공자분들께)
 
 
김상욱의 awt 멀티채팅강좌 ::
방개설, 귓말/쪽지, 방장기능, 캐릭터 및 글자색 기능, 이미지넣기, 관리자모드, 그림 및 음악 보내기 등 기술분석적 강의 (진행중)
김상욱의 db 이용한 awt 그래프 출력강좌 ::
db와 socket을 이용 3-Tier, 스크롤가능 그래프출력 강좌 (1차완료)
김상욱의 LIVECONNECTION :: 애플릿과 자바스크립트와의 통신강좌 (완료)
김상욱의 자바툴 강좌 :: Editplus, UltraEditor, Kawa, JCreator 등의 다운로드와 설정 (완료)
김상욱의 웹스타트(webstart) 강좌 (기본 완료, 응용 진행중)
김상욱의 Vector, Hashtable 클래스 성능 실험 외 (완료)
진은영 (50001.com javaside 시삽) 강사님의 자바 기초강좌 (진행중)
자바Side(50001.com) 온라인 자바 스터디 1기 채팅 소스 분석 스터디 정리(완료)
Java Basic처음 입문하신 분들은 이리로
J2SE(Core/Desktop)Java2 Standard Edition.
애플릿/애플리케이션 등 일반적인 자바
프로그램을 만들 수 있는 기본 패키지
J2EE(Enterprise/Server)Java2 Enterprise Edition
엔터프라이즈급 프로그램을 만들 때
사용하는 패키지.
웹프로그래밍 JSP :: servlet :: taglibrary/customtag
웹서비스
웹서비스
JAXP/JAXR/JAX-RPC

SOAP
Component
Enterprise JavaBeans(EJB)
Java Message Service(JMS)
기타

application server
Java Data Objects(JDO)
JavaMail
Transaction(JTA/JTS)
J2EE 기타

J2ME(Mobile/Wireless)Java2 Micro Edition.
휴대폰 등에 들어있는 소형 시스템에서
사용할 프로그램을 만들 수 있는 패키지.

모바일(J2ME)

(강사님별 / 기기별 강좌)

XML XML
IDE IDE
Other Java Technologies 준비중...
ETC 매뉴얼 :: 디자인패턴 :: 객체지향 UML ::
자바스크립트 :: XP(Extreame Programming) :: 기타

자바기본 (영문튜토리얼)

 
박용우님의 자바강좌 :: 자바 전반에 대한 문법 및 도움말 (강추!)
윤경구의 자바튜토리얼 :: '지나'시리즈로 유명한 저자의 기초~고급
최종명의 몽땅강좌 :: 기초부터 고수까지
최희창님의 자바클래스 소개
Java 전문 용어 이해하기 :: Sun사 문서 (오광신 님 번역)
원돈희님의 SCJP에 맞춘 자바강좌 :: 시험 유형에 맞춰 헷갈리기 쉬운 부분을 알기쉽게 강의
Sun의 자바기초강좌 SL275(한글문서) :: 김동학님 제공
자바 초보자를 위한 강좌 :: javanuri
corejava [1권] [2권] :: 번역판
Think In Java 2nd Ed (MS WORD버전)
자바기초에서 애플릿(바둑,채팅)까지 :: JSTORM
자바기초(당연히 알아야함에도 불구하고 그냥 지나치기 쉬운) :: JSTORM
JVM의기본 원리 및 클래스로더의 기초 :: JSTORM
제네럴 프로그래밍 애플릿에서 웹 서비스까지 [첨부파일] :: 박용우
GarbageCollection :: 오광신
JVM의 가비지 컬렉션 (영문) :: IBM
가비지 컬렉션과 퍼포먼스 (영문) :: IBM
이것은 무엇의 객체인가 (영문) :: IBM
추상클래스 :: 자바스터디
정적 유형 (Static type) (영문) :: IBM
final 사용 가이드라인 (영문) :: IBM
자바 속성 [1] [2] [3] [4] :: IBM
클래스와 클래스 로딩 (영문) :: IBM
Java Web Start 1.0 개발자 가이드 (번역) :: JSTORM
자바 네트워크 구동 프로토콜(JNLP)과 참조 구현, 자바 웹 스타트 :: 자바스터디
JAVA WEBSTART문서 [소스] :: 오광신
EMPOWER YOUR APPLICATIONS WITH JAVA™ WEB START - Sun사 문서 (오광신 님 번역)
자바프린팅모델 [1] [2] :: JSTORM
JDK 1_4의 프린팅 (printing), Part 1_새로운 Java Print Service API :: IBM
JDK 1_4의 프린팅 (printing), Part 2_프린트 관련 이벤트를 듣고 그래픽을 직접 프린트 :: IBM
표명(assertion) 기능 이용하기 :: IBM
J2SE 1_5_Tiger의 미래와 언어 차원의 변화 :: IBM
숫자와 currency 포맷 (영문) :: IBM
자바 어플리케이션에서 환경에 접근하기 :: 자바스터디
쓰레드 풀과 작업 큐(queue) (영문) :: IBM
쓰레드 보안 (영문) :: IBM
김세곤님의 클래스패스와 환경 변수, 그것이 알고 싶다. :: 패키지 및 클래스패스설정 총정리
classpath에 등록안된 클래스의 dynamic reload :: javapattern.info
Multiprocess JVM Implemetation_1 :: javapattern.info
Multiprocess JVM Implemetation_2 :: javapattern.info
native method 정의 및 구현 :: javapattern.info
StringBuffer class Optimization :: javapattern.info
Using java debugger :: javapattern.info
Java 2 레퍼런스 클래스 사용 가이드라인 (영문) :: IBM

애플릿 (영문튜토리얼)

 
Dubuilder로 Signed Applet 만들기 [소스] / [MakeRayCab.bat ] :: 오광신
Explore에서 Signed Applet만들기 :: 오광신
넷스케이프 브라우저에서의 사인 애플릿 작성 :: 핸디소프트 윤동빈
네트워크 가위바위보게임(+채팅) [소스] :: 박용우

그래픽(awt,JFC/swing,SWT) (영문튜토리얼)

 
AWT와 스윙 [1] [2] :: JSTROM
스윙(SWING)의 안쪽 탐험 :: JSTORM
Swinging audio_사용자 인터페이스 향상을 위한 소리 신호 구현하기 :: IBM
지능형 데이터로 Swing을 간단히!_(iData 기법) :: IBM
SWT: native 크로스플랫폼 GUI 애플리케이션 만들기 (영문) :: IBM
Create native, cross-platform GUI applications(GCJ, 리눅스, SWT) :: IBM
Equipping SWT 애플리케이션에 content assistants 추가하기 (영문) :: IBM
Fullscreen Exclusive Mode 와 draw directly to video RAM(영문) :: IBM
Java Web Start로 SWT 애플리케이션 전개하기 (영문) :: IBM
GUI의 접근성 높이기 (영문) :: IBM

자료구조(Collection) (영문튜토리얼)

 
콜렉션 개요와 Collection 클래스, MAP, Iterator, Comparator, 콜렉션 알고리즘:: 자바스터디

국제화(한글화) (영문튜토리얼)

 

네트웍(IO/NET)
 
파일과 네트웍 [01] [02] :: JSTORM
자바 I/O 성능 향상기법 :: JSTORM
네트웍 코드를 쉽게 테스트 하자 [소스] :: JSTORM
비 블록 소켓으로 가는 길 (영문) :: IBM
Merlin으로 자바 플랫폼에 nonblocking 입출력 가능_새롭게 추가된 기능들 :: IBM
JDK1.4의 New I/O에 대하여 [1] [2] :: 한빛미디어
스트림 완전히 바꾸기, Part 1 (영문) :: IBM
스트림 완전히 바꾸기, Part 2 내부 Java IO 최적화 (영문) :: IBM
자바 네트워킹 강화 (영문) :: IBM
Java NIO (Ron Hitchens 지음) (영문) :: IBM
Merlin의 new IO 버퍼의 모든 것 (영문) :: IBM
NIO Channel :: javapattern.info
NIO Reactor Pattern의 사용 :: javapattern.info
PushbackReader의 사용방법과 예제 :: javapattern.info
Multicast IP address를 이용한 채팅 :: javapattern.info
Extracting zip or jar file :: javapattern.info
Servlet과 Applet간의 HTTP 통신_1 :: javapattern.info
Servlet과 Applet간의 HTTP 통신_2 :: javapattern.info
Servlet과 Applet간의 HTTP 통신_3 :: javapattern.info
Servlet과 Applet간의 HTTP 통신_4 :: javapattern.info
SocketPool Implementation Source code Example_1 :: javapattern.info
SocketPool Implementation Source code Example_2 :: javapattern.info
DatagramSocket의 정의 및 샘플 :: javapattern.info
HttpURLConnection 사용예와 개념 :: javapattern.info
jNetServer Socket Framework :: javapattern.info
Lightweight Web Server Implementation :: javapattern.info

분산객체(RMI) (영문튜토리얼)

 
Java Distributed Computing Technology :: 자바스터디
자바 RMI 사용하기
차승욱님의 RMI강좌 :: 자바스터디
문영진님의 RMI강좌 :: 자바스터디
자바에서의 원격객체통신(RMI와 CORBA) :: 윤경구
RMI의 기초 :: JSTORM 박준용님
기업에서의 RMI-IIOP_IIOP상에 RMI 실행시키기 :: IBM

IDL(CORBA) (영문튜토리얼)

 
JBuilder를 이용한 코바(Corba)프로그래밍 :: Javastudy
코바와 자바 연동 (PDF) :: Javastudy
JAVA와 CORBA연동 (PDF) :: Javastudy
JBuilder에서 코바 프로그래밍 (MS_WORD) :: Javastudy
코바 이것만을 알고 개발하자!!(PDF) :: Javastudy
VisiBroker 설치 방법 (코바사랑) :: Javastudy
비지브로커의 이모저모.. (PDF) :: Javastudy
IDL에 대해서.. (PDF) 코바사랑 제공 :: Javastudy
JAVA에서 IDL 매핑 (PDF) 코바사랑 제공:: Javastudy
콜백 서비스에 대해.. (MS-WORD) 코바사랑 제공 :: Javastudy
CORBA & Next Generation :: Javastudy

보안(Security) (Security in 1.2 영문튜토리얼)

 
Globus Grid Security Infrastructure와 자바 (영문) :: IBM
JAAS와 JSSE를 이용한 자바 보안 (영문) :: IBM
대칭암호화알고리즘 소개 및 DES, Blowfish샘플코드 :: javapattern.info
Java Security Model Evaluation :: javapattern.info
MD5를 이용한 스트링 변환 :: javapattern.info

JDBC(데이터베이스)
 
데이타베이스와 자바(JDBC소개) :: 자바스터디
JDBC 팁 (영문) :: IBM
JDBC 쿼리 로깅을 쉽게_고급 PreparedStatement를 사용하여 JCBC 코드에 로깅 추가 :: IBM
JDBC와 ORACLE :: 자바스터디
JDBC와 MSQL :: 자바스터디
Database접속 Pool관리 :: 자바스터디
JDBC API를 이용한 프로그래밍 강좌 :: http://www.aboutjsp.com
JDBC 기초 강좌 :: http://cs.sookmyung.ac.kr
JDBC 다국어 처리법 :: http://www.ejavaschool.com.ne.kr
JDBC 설정 :: 자바스터디
PostgreSQL JDBC 활용 :: http://www.junghyun.pe.kr
자바 초보자를 위한 DB강좌 :: javanuri
SQL2000 강의자료 :: 김하나님 자료
Object Pool 패턴을 이용 구현한 JDBC Connection Pool :: JSTORM
oracle8i JDBC(Oracle 8i 와 Java) :: Javastudy
Informix 데이터베이스연결 :: javapattern.info
MySQL JDBC Connection_1 :: javapattern.info
MySQL JDBC Connection_2 :: javapattern.info
MySQL JDBC Connection_3 :: javapattern.info
Java JDBC Performance Tip(1)-Select Speed up! :: javapattern.info
Java JDBC Performance Tip(2)-Insert, Delete Speed up!.htm :: javapattern.info
JDBC DataConversion(Using Metadata) :: javapattern.info

JAR (영문튜토리얼)

 
JAR 파일 (영문) :: IBM

Extention Mechanism (영문튜토리얼)

 

2D Graphics (영문튜토리얼)

 
2D 애니메이션과 이미지 기반 경로 (영문) - IBM
롤오버(rollover) 효과를 위한 Java2D 합성 (영문) - IBM

Sound (영문튜토리얼)

 

JavaBeans (영문튜토리얼)

 
자바 빈으로 테트리스 게임의 구성 요소들을 재사용 가능한 컴포넌트로 :: IBM
JavaBeans 컴포넌트와 JSP 기술의 결합 (영문) :: IBM

JNI (영문튜토리얼)

 
자바와 C/C++ 연동하기 :: 마이크로소프트웨어
Java Native Interface(JNI) :: 윤경구
자바 네이티브 인터페이스로 피어 클래스 사용하기 :: 자바스터디

Reflection (영문튜토리얼)

 
reflection (영문) :: IBM
리플렉션(reflection) 적용하기 (영문) :: IBM

Optional Packages(JMF/JMX/commAPI/3D/JAI/SpeechAPI/Help System etc)

 
자바멀티미디어 JMF [01] [02] [03] :: JSTORM
JavaHelp 소프트웨어로 헬프셋 만들기 :: 자바스터디
JAVAHELP로 애플리케이션에 도움말 추가하기 :: 자바스터디
블랙박스에서 엔터프라이즈 까지, JMX 1.1 style (영문) :: IBM
블랙 박스에서 엔터프라이즈 까지, JMX 1.1 스타일 (영문):: IBM
블랙박스에서 엔터프라이즈 까지, JMX 통합_JMX Agent를 네트워크 관리 시스템에 연결:: IBM
자바 애플리케이션에서 USB 장치에 접근하기 (영문) :: IBM

J2SE 기타

 
클래스 변형하기 (영문) :: IBM
보다 나은 HashMap 구현하기 (영문) :: IBM
변이(mutate)할 것인가 말것인가 (영문) :: IBM
무한정 progress bars (영문) :: IBM
다중 스레드 애플리케이션 프로그래밍을 쉽게 구현. Consumer 클래스 :: IBM
안전한 구조 기술 (영문) :: IBM
자바 애플리케이션에서의 회귀 태스크 스케줄링 (영문) :: IBM
자바 최적화 기술_자바 애플리케이션의 퍼포먼스 향상을 위한 실질 가이드 :: IBM
패턴 매칭 :: 자바스터디
정규식을 위한 추상 자바 API 구현하기_Perl5 regexp 라이브러리를 사용 :: IBM
새로운 regex 라이브러리를 이용한 문자 시퀀스 파싱하기 (영문) :: IBM
패키지 의존성 줄이기 (영문) :: IBM
해시(hash) 해부 (영문) :: IBM
캐릭터 세트(Character set) (영문) :: IBM
내 쓰레드는 어디에_서버 애플리케이션에서 쓰레드 유출 피하기 :: IBM
Preferences API를 사용하여 객체 저장하기 (영문) :: IBM
SpringLayout 매니저 (gridbagLayout으로 부족할 때)(영문) :: IBM
String 클래스의 오타(mistyping) 방지하기 (영문) :: IBM
Shutdown hook클래스 작성방법 및 샘플 :: javapattern.info
Comparator클래스의 객체비교를 통한 sorting :: javapattern.info
Deep Copy, Shallow Copy에 관한 Perfomance Test 및 고려사항 :: javapattern.info
Property Utility Examples_1 :: javapattern.info
Property Utility Examples_2 :: javapattern.info
Reflection을 이용한 Value Object비교 :: javapattern.info
박용우님의 '스노우크래프트'자바강좌 :: 자바스터디

JSP
 

1.JSP 란? MS의 ASP처럼 java로 구현된 서버 스크립트입니다.

2.프로그램? java.sun.com/products/servlet/index.html

3.매뉴얼? java.sun.com/products/jsp/tags/tags.html

4.자세한 정보 java.sun.com/products/jsp

5.JSP FAQ www.esperanto.org.nz/jsp/jspfaq.html

6.JSP Developer's Guide java.sun.com/products/jsp/docs.html

JSP강좌 [01] [02] [03] :: JSTORM
JSP기초JSP이론 [01] [02] [03] [04] [05] [06] [07] :: 자바스터디강좌 by 파란공책
http://www.jabook.org/jbjsp/jbjsp_20000_0_0.html :: jabook의 JSP강좌 링크
JSP기초(Java Server Programming 번역일부) :: JSTORM

INSTALL

Tomcat4 설치하기 Windows NT/2K/XP, 98/ME :: okjsp

Tomcat4 Apache1.3.22연동 (mod_jk이용) (mod_webapp이용) :: okjsp

Tomcat 가상호스트 설정하기 :: okjsp

Apache 가상호스트 설정하기 ::okjsp

win98+apache+tomcat (win98과 winMe Tomcat 3.2.1, apache 1.3.14) :: okjsp

윈98 + 아파치 + 톰켓 설치 :: kimho.pe.kr

Tomcat 4.0 설치 (Windows 2000) :: kimho.pe.kr

apache + Tomcat설치하기 :: 자바스터디

리눅스에서 Tomcat 4.0 + 아파치 설치 :: kimho.pe.kr

Apache와 Tomcat4.0.1의연동(윈도2000) :: 김성박

Tomcat-apache 연동 :: okjsp

linux + apache + Tomcat설치하기 :: 자바스터디

Tomcat 3.2의 루트디렉토리 (Tomcat의 기본디렉토리 변경) :: okjsp

Tomcat 4.1의 루트디렉토리 (+ Context 추가) :: okjsp

win2k server + IIS + tomcat 3.2.3 (이미지 캡쳐) :: okjsp

IIS + tomcat 3.2.3 Context추가 (conf/uriworkermap.properties 변경) :: okjsp

IIS에서 자카르타톰캣 돌리기 :: 최종명

oracle 9i + jdbc + tomcat 4.0.3 연동 :: 하이텔 김현규(pasome)

일반계정으로 JSP 돌리기 :: kimho.pe.kr

Tomcat 서비스 설치하기 (NT, Tomcat 3.2.2 ) :: okjsp

win2000+apache+tomcat :: 자바스터디

win2000+IIS5+Resin (Resin 1.2.1) :: okjsp

resin install :: 자바스터디

Win2000에서 resin설치하기 :: 자바스터디

IIS에서 RESIN설치하기 :: 중앙정보기술 정원희

Resin 루트디렉토리 (Resin 1.2.1 기본디렉토리를 변경) :: okjsp

Apache1.X or 2.X+Resin 2.1.6 installed on Linux or Unix :: javapattern.info

자바 서비스를 위한 리눅스 보안 (영문) :: IBM

응용

Eclipse 시작하기 :: okjsp

Form study #1 :: okjsp

Tomcat 4 Manager 사용하기 :: okjsp

jsp에서 log() 이용하기 :: okjsp

WAR (Web ARchive jsp로 만든 웹 어플리케이션을 쉽게 배포) :: okjsp

한글처리 (일반적인 한글처리) :: okjsp

한글처리 빈 (빈에서의 한글처리) :: okjsp

useBean :: okjsp

톰켓에서 useBean 사용하기 :: kimho.pe.kr

session bean :: okjsp

bean 활용[1] [2] :: okjsp

FileUpload :: okjsp

JspSmartUpload 설치 :: okjsp

JspSmartUpload F&Q :: okjsp

jsp 에러잡기 :: okjsp

include 집중분석 :: okjsp

수학 내용을 포함하는 동적 웹 사이트 구축하기(JSP 기술과 LateX) :: IBM

패킹(Packing) (영문) :: IBM

The expression language_JSP 애플리케이션용 MA 단순화하기 :: IBM

Echo 웹 프레임웍으로 작업하기 [1] [2] :: IBM

include를 이용한 동적 콘텐트 조작 (영문) :: IBM

JSP 코드로 이미지 관리하기_동적 서블릿 이미지 메이킹을 마음대로! :: IBM

JSP best practices 외부 사이트에서 콘텐트를 가져오는 JSTL 태그 :: IBM

JSTL primer 프리젠테이션 (영문) :: IBM

JSTL을 이용한 JSP 페이지 업데이트 (영문) :: IBM

JSTL 기초 핵심에 접근하기_커스텀 태그를 이용한 플로우 제어와 URL 관리 :: IBM

JSTL 기초, Part 4 SQL과 XML 콘텐트에 접근하기 (영문) :: IBM

JSP best practices 타임 스탬프의 힘_JSP 페이지에 타임 스탬프 만들기 :: IBM

JSP best practices JSP 태그용 커스텀 애트리뷰트 만들기 :: IBM

JSP include 메커니즘으로 “look and feel”을 더욱 좋게 (영문) :: IBM

Struts, Tiles, JavaServer Faces 통합하기 :: IBM

Struts와 Tiles, 컴포넌트 기반의 개발 도우미 (영문) :: IBM

JSP Model 1 vs JSP Model 2 Architecture overview :: javapattern.info

URL Rewriting을 이용한 session tracking_1 :: javapattern.info

URL Rewriting을 이용한 session tracking_2 :: javapattern.info

[ JSP 기본 강좌 ] (http://www.ihelpers.co.kr)

“안녕하세요. 00 님!!!” 과 JSP 동작원리에 대하여

JSP Comment

JSP Directive

Scripting Elements

iimplicit object
Implicit Object - Request
Implicit Object - Response,Out
Implicit Object - Session, Application

공지사항 만들기 (1) (2) (3) (4) (5)

게시판 만들기 (1) (2) (3) (4) (5)

메일 발송 (1) (2)


진민님의 JSP 간단 강좌 ( http://myhome.shinbiro.com/~jimmy/ )

1. JSP 강좌1(jsp 기본구성)

2. JSP 강좌2(get,post처리 및 내장 인스턴트사용)

3. JSP 강좌3(외부 클래스 사용하는 방법)

4. JSP 강좌4(JDBC를 사용하는 방법)

5. JSP 강좌5(Cookie를 사용하는 방법)

6. JSP 강좌6(session을 사용하는 방법)

7. JSP 강좌7(session사용시 주의점)

김호님의 게시판 만들기 강좌 (http://www.kimho.pe.kr/)

JSP 게시판(방명록) 만들기 (글 내용보기)

JSP 게시판(방명록) 만들기 (글 삭제하기)

JSP 게시판(방명록) 만들기 (글 수정하기)

JSP 게시판(방명록) 만들기 (글 올리기)

JSP 게시판(방명록) 만들기 (리스트 출력하기)

JSP 게시판(방명록) 만들기 (페이징 기법)

JSP 게시판(방명록) 만들기 (또 다른 페이징 기법 1회)

JSP 게시판(방명록) 만들기 (또 다른 페이징 기법 2회)

JSP 게시판(방명록) 만들기 (글 삭제하기)

JSP 게시판(방명록) 만들기 (글 수정하기)

답변형 게시판 만들기 1회 - 답변형 게시판 로직

답변형 게시판 만들기 2회 - 글 올리기

답변형 게시판 만들기 3회 - 글 리스트 보기

답변형 게시판 만들기 4회 - 글 내용 보기


servlet
 

http://www.jabook.org/jbjsp/jbjsp_10000_0_0.html :: jabook의 서블릿강좌 링크

자바 서블릿 프로그래밍 :: 박용우
자바 서블릿(Java ServletTM) 아키텍처 :: 박용우
Java Servlets 2.4를 이용한 필터링 (영문) :: IBM
Servlet API와 NIO 완벽한 결합 (영문) :: IBM
쿠키에 한글이 들어갈 경우 예제 서블릿 :: javapattern.info
Making the Http WebServer(Java로 web server를 구현하는 방법)_1 :: javapattern.info
Making the Http WebServer(Java로 web server를 구현하는 방법)_2 :: javapattern.info
Making the Http WebServer(Java로 web server를 구현하는 방법)_3 :: javapattern.info
Servlet2.3 API Filter interface Implementation :: javapattern.info
Servlet과 Applet간의 TCP_IP 통신_1 :: javapattern.info
Servlet과 Applet간의 TCP_IP 통신_2 :: javapattern.info
Servlet의 각종 Listener 사용방법 및 샘플 :: javapattern.info
Web Tier Java Techonology :: javapattern.info

INSTALL

 JSPINSTALL 참고

 

taglibrary/customtag
 

JSP Tag Library 기초강좌 :: okjsp

커스텀 태그로 JSP 페이지 제어하기_커스텀 태그 라이브러리 통신의 모든 것 :: IBM

Custom Tag Library (1) (2) (3) (4) (5) (6) :: http://www.ihelpers.co.kr

커스텀 태그에서의 에러 핸들링 (영문) :: IBM

JSP 커스텀 태그를 구현하는 다섯 단계 (영문) :: IBM

InvokeEJB Custom Tag Library implementation_1 :: javapattern.info

InvokeEJB Custom Tag Library implementation_2 :: javapattern.info

InvokeEJB Custom Tag Library implementation_3 :: javapattern.info

Struts 1.1 Tiles-framework에 대한 개요 및 사용방법 :: javapattern.info

taglib (영문) :: IBM

 

웹서비스
 

웹 티어 클러스터링, Part 1 JavaGroups로 웹 서비스와 애플리케이션 설계 :: IBM

 

JAXP/JAXR/JAX-RPC
 

 

SOAP
 

아파치 SOAP 유형 매핑, Part 1 아파치의 직렬화 API 검토하기 :: IBM

아파치 SOAP 유형 매핑, Part 2 정의된 직렬자와 비직렬자를 작성 :: IBM

 

Enterprise JavaBeans(EJB)
 
J2EE 환경 소개 :: 자바스터디
오라이온 서버 설치 및 J2EE 애플리케이션 배치 :: 자바스터디
J2EE 신기술의 해설 :: 자바스터디

[ EJB 기본문서 ]

Java Enterprise edition tutorial :: SUN

썬 사의 EJB 규약

Enterprise Java Beans란 무엇인가? [01] [02] [03] [04] [05] :: JSTORM

EJB 한글자료

EJB 실전프로그래밍 (Persistence PowerTier for EJB) :: 자바스터디

Java Enterprise [PDF] :: 김국현님

EJB 성능향상을 위한 Best Practice [1] [2] :: JSTORM

Writing Enterprise Application [01] [02] [03] [04] [05] [06] [07] :: JSTORM

EJB 디자인 패턴 ↓

[ EJB 응용 ]

EJB의 트랜잭션 :: JSTORM 박지훈님

J2EE 애플리케이션에서의 XML :: JSTORM 한제택님

자바 서버상에서 서블렛의 활용 :: 핸디소프트 윤동빈님

J2EE에서의 작업 스케쥴링 :: JSTORM 윤준호님

J2EE 신기술 해설 :: 한국오라클(주) 안병문님

Component Architecture(CORBA, EJB, COM) :: 김국현님

Grady Report - EJB, Design Pattern, XP 강좌 문서 :: 박현철(hpark@kebi.com)

이런 J2EE프로젝트는 위험하다 :: JSTORM

LDAP 소개 :: database.sarang.net 부산대학교 컴공과 박근오님 (MS WORD)

분산 관리 솔루션 (영문) :: IBM

상태보존형(stateful) 네트워크용 J2EE (영문) :: IBM

싱글사인온 솔루션 구현 (영문) :: IBM

싱글사인온 GSS-API와 Kerberos 티켓을 사용하여 SSO를 구현 :: IBM

EJB 예외 처리 실전 (영문) :: IBM

타당성검사(Validation) 헬퍼(helper) 클래스_데이터-포맷 타당성 검사에서 코드 중복 없애기 :: IBM

데이터 타당성검사(validation) (영문) :: IBM

동적 delegate_Java reflection을 이용하여 보다 일반적인 business delegate 구현하기 :: IBM

보다 나은 예외 처리 프레임웍 구현하기 (영문) :: IBM

엔터티 빈 보호_Session Facade 패턴으로 데이터를 안전하게 관리하기 :: IBM

Business Delegate 패턴_EJB 디자인에서의 추상 비지니스, 구현, 애플리케이션 로직 :: IBM

delegation의 한계_business delegate의 대안 :: IBM

JNDI의 산업용 최적화 (영문) :: IBM

JNDI 미로 통과하기 (영문) :: IBM

value 객체를 사용하여 RMI 트랜잭션 속도 높이기 (영문) :: IBM

EJB State와 SOAP 헤더 (영문) :: IBM

JavaSpaces로 적응력 있고 광범위한 솔루션 구현하기 (영문) :: IBM

J2EE 1.2에 다중 애플리케이션 전개하기 (영문) :: IBM

J2EE 내부 객체 사용 (영문) :: IBM

J2EE 영속적인 데이터 관리, Part 1 (영문) :: IBM

J2EE 영속적인 데이터 관리, Part 2 (영문) :: IBM

J2EE를 이용한 서비스 지향 아키텍쳐 프레임웍 설계 (영문) :: IBM

stateful 웹 애플리케이션의 구현과 관리 (영문) :: IBM

stateless 네트워크용 J2EE 기술 (영문) :: IBM


Java Message Service(JMS)
 

벤더로부터 독립된 JMS 솔루션 구현하기 :: IBM

메시지 큐잉이 기업 애플리케이션의 유연성과 확장성을 향상시키는 방법 :: IBM

JMS를 이용한 엔터프라이즈 메시징 (영문) :: IBM

 

application server
 

JEUS 기반의 J2EE - from TmaxSoft
   JEUS EJB Server의 관리와 이를 이용한 EJB 개발 (PDF)
   JEUS JTS의 구조와 이를 이용한 개발 (PDF)
    JDBC의 개념과 프로그래밍하는 방법 (PDF)
   XML 소개와 XML APPLICATION 개발 (PDF)
   JEUS JMS의 구조와 이를 이용한 개발 (PDF)
   JEUS JNDI의 구조와 이를 이용한 개발 (PDF)
   WebtoB Web Server의 소개 (PDF)

HP Netaction Application Server 기반의 J2EE - from Nicstech
   HP Netaction Application Server 설치 방법(WIN 환경) [MS-Word]
   HP Netaction Application Server 설치 방법(UNIX/LINUX 환경) [MS-Word]
   HP Netaction Application Server 에서 웹서버 세팅 방법 [MS-Word]
   HP Netaction Application Server 기반의 JSP, Servlet 개발 방법 [MS-Word]
   HP Netaction Application Server기반에서 EJB사용을 위한 Tutorial [PDF]
   RADPAK 개발툴 사용방법 [MS-Word]

Ea Server 기반의 J2EE - from Sybase
   EA Server 소개 (PDF)
   EJB-CORBA 개발 (PDF)
   분산어플리케이션 (PDF)
   EAServer & PowerJ Installation Guide (ZIP)

PowerJ 연재 강좌 (PDF)
   Simple Application | 웹 어플리케이션 | EJB 컴포넌트 작성 | 컴포넌트 사용하기
   완벽한 J2EE Application 구축방법 (PDF)


javapattern.info 강좌

IBM Webshpere 5.0 의 서버시작, 중지 및 EJB Deploy ANT Build

Web Application Framework개발방법(1)-Framework의 개요

Web Application Framework개발방법(2)-LifeCycle,Controller

Web Application Framework개발방법(3)-View page Composing

Web Application Framework최종 소스 및 인스톨

Weblogic 7에서 JMS Queue Browser 활용 1

Weblogic 7에서 JMS Queue Browser 활용 2

Weblogic EJB Deploy using ANT build

 

Java Data Objects(JDO)
 

Castor JDO 시작하기(영문) :: IBM

Castor를 이용한 데이터 바인딩 (영문) :: IBM

 

JavaMail
 

JavaMail 설치 :: 자바스터디

JavaMail 기본설치 :: okjsp

JavaMail 폼메일 :: okjsp

JavaMail 파일첨부메일 :: okjsp

JavaMail 메일링리스트 :: okjsp

Apache의 James 엔터프라이즈 이메일 서버 (영문) :: IBM

javapattern의 java WebMail 구현

[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16]

 

Transaction(JTA/JTS)
 

트랜잭션에 대한 소개_트랜잭션은 신뢰성 있는 애플리케이션을 위한 구성 요소 :: IBM

장막 뒤의 마법_J2EE 컨테이너가 트랜잭션 관리의 복잡성을 숨기는 방법 :: IBM

보안과 퍼포먼스 균형맞추기_트랜잭션 경계설정과 고립화 가이드라인 :: IBM

WS-AtomicTransaction과 JTA를 이용한 분산 트랜잭션 (영문) :: IBM

 

J2EE 기타
 

Authenticator클래스를 통한 서버인증 메일전송 :: javapattern.info

Distributed Transaction Introduce :: javapattern.info

JRMP, IIOP type의 RMI분산 객체(RMI over IIOP) :: javapattern.info

MarshalledObject and Deserialization :: javapattern.info

RMI Peering System Construct :: javapattern.info

RMI programming, The Lifecycle of server :: javapattern.info

WebLogic WLSPool Size변경 application :: javapattern.info

 

모바일(J2ME) :

J2ME와 mobile device :: 김종원

핸드폰 단말기용 자바 애플리케이션의 구현 :: 배준현

네덜란드의 무선 기술 (영문) :: IBM

모바일 장치 디텍션(detection) (영문) :: IBM

P2P 네트워크 모바일 디바이스를 JXTA와 Jabber 클라이언트로 전환하기 :: IBM

기존의 네트워크 경계를 넘어 확장되는 P2P 시스템 설계 :: IBM

JXTA 2 고성능 P2P 네트워크 (영문) :: IBM

무선 J2ME 보안 (영문) :: IBM

EPOC에서 자바 애플리케이션 만들기 (영문) :: IBM

J2ME 101, Part 3 Record Management System (영문) :: IBM

J2ME 101, Part 4 Generic Connection Framework (영문) :: IBM

J2ME 기록 관리 저장 (영문) :: IBM

J2ME 애플리케이션과 Kerberos, Part 3 (영문) :: IBM

J2ME를 무선 메시지교환으로 확장하기 (영문) :: IBM

J2MEMIDP 애플리케이션 보안 (영문) :: IBM

MIDlets 클래스_모든 J2ME 프로그램의 기반하에 구축하기 :: IBM

Secrets of the wireless elite Jason Loia (영문) :: IBM

Secrets of the wireless elite Nancy Lehrer(영문) :: IBM

J2ME를 이용한 모바일 결제(m-payments)-모바일 장치에서 결제까지 :: IBM

강사님별 강좌
 

배준현님 마소 강의


무선단말을 위한 자바플랫폼 : CLDC/MIDP
핸드폰에는 나만의 자바 애플리케이션을!
OSGi로 여는 임베디드 자바 세상

이경범님 마소 강의

알라딘 기반의 상용만화 애플리케이션 만들자

김종원님 프세 강의

MIDP를 사용한 휴대폰 프로그래밍
J2MEWTK를 사용한 MIDlet Httpconnection 프로그래밍
SK-Aladdin VM(virtual machine)을 이용한 멀티 플렛폼 채팅 프로그램 작성
&J2ME와 embedded device

유제정님 모바일 DB 강의

1. 모바일데이터베이스를 이용한 MIDP Sample 프로그램 구현

김준동님 모바일 강의

소형기기를 위한 프로그래밍 전략

정성권님 번역 자료

Introduction to Wireless Application Development

권기경님 번역 자료

Using XML in Wireless Applications
Connected Limited Device Configuration (CLDC) (CLDC API) (KJAVA API)

권기경님 자료

컴파일에서 사전 검증, 실행까지
이미지 사용 예제 분석
[번역] Connection Framework


기기별 강좌
 

Mobile Information Device Profile (MIDP) (MIDP-FCS API)
권기경님 자료

컴파일에서 사전 검증, 실행까지
웹서버에 midp 응용프로그램을 올려 놓고 실행하기

[번역]
MIDP Inter-Communication with CGI and Servlets
HTTP를 사용하는 MIDP Network Programming과 Connection Framework (정창수님번역)
MIDP GUI Programming Programming the Phone Interface (오용석님번역)
Quick Start Guide: JavaTM 2 Platform Micro Edition, Wireless Toolkit (오광신님 번역)
MIDP Database Programming using RMS: a Persistent Storage for MIDlets (번역)

PALM Pilot PDA (Palm OS) (PALM API)

권기경님 자료 :: 컴파일에서 사전 검증, 실행까지

WABA (WabaSoft) (WABA API)

권기경님 자료 :: 컴파일에서 사전 검증, 실행까지

n.TOP 마법사 (SK Telecom, XCE) (n.TOP 마법사 API) (XCE Tutorial)

박재범님 강의 :: 컴파일에서 실행까지
마소자료 :: MIDP 소개 | SKT-P 소개 | 게임작성 소개

EZ-JAVA 핸드폰 (LG Telecom) (EZ-JAVA 영문 API) (EZ-JAVA 한글 API)

권기경님 자료
  컴파일에서 사전 검증, 실행까지
  실제 폼에서 ez-java 응용프로그램 실행하기

박재범님 자료 :: 이미지 사용 예제 분석

-MODE 핸드폰 (Nttdocomo) (I-MODE API)

권기경님 자료
  컴파일에서 사전 검증, 실행까지
i모드 Java 확장 API 클래스 라이브러리가 아닌 i-jade를 사용하여 컴파일과 실행까지

wizardee님 자료 :: iAppli 개발환경 만들기

iDEN 핸드폰 (Motorola) (CLDC API) (MIDP API)

권기경님 자료 :: 컴파일에서 사전 검증, 실행까지

Personal Java 강좌

황제헌님 자료
  Personal Java Programming
  Personal Java 한글 encoding 문제 해결

CessHan for Palm-sized PC & PocketPC 설치 방법

KVM에 대한 기본 설명
어플리케이션 사이즈를 줄여주는 Obfuscator
SUN의 Monty 프로젝트 관련 자료
MIDP NG (New Generation) 버젼에 관한 자료 [UI, Games, and Sound] [Security and Networking]
Parsing XML in J2ME MIDP
Introducing Wireless JMS (PDF)

XML
 
XML의 기본개요 :: javapattern.info
XML 정리 (pdf파일)
XML korean spec :: http://user.chollian.net/~clevekim
자바와 XML :: JSTROM
Using XML in Oracle
XML 게시판 [소스] :: 김미영 님
XML 과 데이타베이스 :: 박용우
XSL, XSLT, XPATH [1] [2] [3] [4]:: 전윤경(ygchon@penta.co.kr)
DOM으로 프로그래밍하자 [1] [2] :: 전윤경(ygchon@penta.co.kr)
About DOM & DOM Programming with Java :: javapattern.info
DOM Level 3 Core의 핵심 기능 [1] [2] (영문) :: IBM
About SAX & SAX programming with Java :: javapattern.info
SAX 파서 설치하기 (영문) :: IBM
자바 프로그래밍으로 온라인 XML 데이터 검색하기_XML 파싱 :: IBM
자바 프로그래밍의 XML-RPC (영문) :: IBM
자바가 본 XML :: 자바스터디
Digester와 Lucene을 이용한 XML 파싱, 인덱싱, 검색 (영문) :: IBM
XML 로 홈페이지 만들기 :: 전윤경(ygchon@penta.co.kr)
IBM developerWorks XML 아티클 템플릿 (영문) :: IBM
자바 문서 모델 사용법_상이한 자바 XML 문서 모델들이 작동하는 방식 :: IBM
Schema Infoset Model로 스키마에 대한 복잡한 쿼리를 간단히! :: IBM
Working XML 경로 컴파일과 테스트 자동화_알고리즘과 JUnit 자세히 살펴보기 :: IBM
XML 데이터 바인딩, 성능 (영문) :: IBM
XML 데이터 바인딩, JiBX architecture (영문) :: IBM
XML 데이터 바인딩, JiBX 사용하기 (영문):: IBM
About JDOM & JDOM Programming with Java.htm :: javapattern.info
FOP를 이용한 PDF생성시 한글변환방법 :: javapattern.info
XML을 이용한 Database Query Manager 구현하기 :: javapattern.info
XMLBeans를 이용한 xml binding.htm :: javapattern.info

IDE

 
JBuilder 5 한글 매뉴얼 (pdf)
JBuilder 6 한글 매뉴얼
JBuilder 7 [인스톨] [환경설정](ppt)
JBuilder 에서 휠마우스 사용
제이빌더에서 라인넘버 표시
제이빌더에서 Ant 실행
제이빌더에서 자바코드 뷰티파이어
한국 인프라이즈 제공 J 빌더 특강 [ZIP로 내려받기] :: javastudy.co.kr
Eclipse Platform 시작하기 :: IBM
Eclipse 플러그인 개발하기_플러그인 구현, 디버그, 설치 :: IBM
Eclipse 플러그인 서비스 (영문) :: IBM
Eclipse Workbench 밖에서 Eclipse GUI 사용하기, 간단한 파일 탐색 애플리케이션 :: IBM
Eclipse Workbench 밖에서 Eclipse GUI 사용하기, 메뉴, 툴바 추가(영문) :: IBM
Eclipse와 HSQLDB 관계형 데이터베이스를 Eclipse에 임베딩하기, Part 1 (영문) :: IBM
Eclipse의 자바 개발 툴 확장하기 (영문) :: IBM
Graphical Editing Framework을 사용하여 Eclipse 기반 애플리케이션 만들기 (영문) :: IBM

매뉴얼
 
VisualAgeForJava 3.0 한글 매뉴얼 (pdf)
WSCP 매뉴얼 (doc) :: 윤성민

디자인패턴
 
디자인패턴 실전체험 [1] [2] [3] [4] :: 자바스터디
기본패턴 Overview :: javapattern.info
인터페이스! 다시 생각하기 :: 오광신
Good Java Style :: JSTORM
Command패턴의 기초 :: JSTORM
동적으로 자바 어플리케이션 확장하기 :: JSTORM
DesignPattern for Java [소스] :: JSTORM
리팩토링(Refactoring)_Eclipse의 자동화 리팩토링 기능 :: IBM
Double-checked locking과 Singleton 패턴_double-checked locking 이디엄 :: IBM
반 패턴으로 프로그래밍을 향상시키는 방법 :: IBM

EBJ 디자인패턴

Session Facade :: JSTORM

EJB Home Factory :: JSTORM

Business Interface :: JSTORM

Dual Persistent Entity Bean :: JSTORM

JDBC for Reading :: JSTORM

Business Delegate :: JSTORM

Data Transfer HashMap :: JSTORM

Data Transfer RowSet :: JSTORM

EJB Command Pattern :: JSTORM

Version Number :: JSTORM

"Dependent Value Object" 와 큰 단위의 BMP 엔티 :: JSTORM

EJB 전략, 팁 그리고 관례 :: JSTORM

Message Facade :: JSTORM

Value Object Factory :: JSTORM

Data Access Command Beans :: JSTORM

Blueprint(J2EE Petstore) client tier pattern overview :: javapattern.info

EJB design performance tips :: javapattern.info


객체지향 UML
 
박용우님의 객체지향형 프로그래밍 :: 자바스터디
심원도님의 UML강좌 :: 자바스터디
이준규님의 객체지향형 강좌 :: 자바스터디
Rational Rose에서 UML을 이용한 모델링 [1] [2] [3] [4] :: 자바스터디
http://www.jabook.org/jbjava2/jbjava2_10000_0_0.html :: jabook의 객체지향강좌링크

자바스크립트
 
자바스크립트 레퍼런스(win help용)
자바 초보자를 위한 JavaScript 강좌 :: javanuri
애플릿과의 통신(LIVE CONNECTION)을 위한 netscape.jar

XP(Extreame Programming)
 
Extreme Programming 돌아온 XP distilled, Part 1_XP의 진실
Extreme Programming을 밝힌다 돌아온 XP distilled, Part 2 (영문)
Extreme Programming을 밝힌다 돌아온 XP distilled, Part 3 (영문)
Extreme Programming을 밝힌다 진정한 XP 고객_소프트웨어 프로젝트를 운영하는 방법 배우기
Extreme Programming을 밝힌다 페어 프로그래밍(Pair programming) (영문)
Extreme Programming Just-in-time 디자인 (영문)
Extreme Programming Test-driven 프로그래밍_코드를 작성하기 전에 테스트 먼저 작성하기
Extreme Programming 작업에 맞는 (XP) 툴
Extreme Programming Just-in-time 디자인 (영문)

기타
 
ANT 매뉴얼 [] [] :: http://www.hanbitbook.co.kr
Apache ANT Guide :: 최지웅
자바 마이그레이션 :: 하동욱(handan@hitel.net)
JINI기술과 실제 :: 자바스터디
고급 객체 직렬화 :: JSTORM
COM과 자바의 연결 :: 핸디소프트 윤동빈
PDF와 자바 :: JSTORM 윤준호
JavaCC를 이용하여 당신만의 언어를 만들자 [소스]:: JSTORM 윤준호
JavaCC, 파스 트리, XQuery 문법, Part 1 (영문) :: IBM
JavaCC, 파스 트리, XQuery 문법, Part 2 (영문) :: IBM
인스턴트 로깅(Instant logging) log4j 활용하기 (영문) :: IBM
Log4j를 위한 여러가지 환경설정(xml property)_1 :: javapattern.info
Log4j를 위한 여러가지 환경설정(xml property)_2 :: javapattern.info
Log4j의 출력방향 전환하기 :: javapattern.info
Extract unicode from ASCII format text :: javapattern.info
MP3 File Footer ID3V2 Spec Navigator :: javapattern.info
객체 보유 (object prevalence) 소개 (영문) :: IBM
동적 이벤트 리스너 프록시 (영문) :: IBM
리눅스에 LSID 권한 구현하기 (영문) :: IBM
매력적인 Jython (영문) :: IBM
소프트웨어 개발의 미래 (영문) :: IBM
접근가능성을 위한 코딩 (영문) :: IBM
쉬운 코드 관리를 위한 디자인 (영문) :: IBM
영속적인 트레이스 시스템으로 디버깅을 쉽게! (영문) :: IBM
영역 지향 프로그래밍(Aspect -oriented programming)으로 모듈화 향상시키기(AspectJ) :: IBM
강결합의 약점을 없앤 AOP (영문) :: IBM
자바 native 컴파일의 무게 재기_자바 소스에서 native 코드를 생성할 때의 장단점 :: IBM
자바 프로그래밍에서의 Assertion과 temporal logic (영문) :: IBM
버그 패턴에 Temporal logic 사용하기 (영문) :: IBM
콘텐트를 배치하는 새로운 방법 (영문) :: IBM
플랫폼 의존 gotchas: platform-dependent bug patterns (영문) :: IBM
AspectJ와 mock 객체를 이용한 유연한 테스팅 :: IBM
Concurrency made simple util.concurrent package :: IBM
Concurrent 컬렉션 클래스 (영문) :: IBM
ContentHandler의 애트리뷰트 (영문) :: IBM
ContentHandler의 엘리먼트와 텍스트 (영문) :: IBM
'스팩(specification)'이라는 줄타기를 하다_잘 정의된 스팩의 중요성 :: IBM
깊이 우선 Visitor와 broken dispatches_Visitor 패턴 변종으로 코드 간결성 향상 :: IBM
대화식 검사 기능을 제공하는 Repls_소프트웨어를 효과적으로 진단하는 기법 :: IBM
Run-on Initializer 버그 패턴_인자를 가진 생성자를 피함 :: IBM
e-business on demand 개발자의 로드맵 (영문) :: IBM
Eye on performance 객체 레퍼런싱 (영문) :: IBM
Eye on performance 마이크로 퍼포먼스 벤치마킹 (영문) :: IBM
Eye on performance 스트레스의 하중 (영문) :: IBM
Eye on performance 예외에 대한 예외 (영문) :: IBM
Eye on performance 향상된 개발 프로세스 (영문) :: IBM
Javassist를 이용한 클래스 변형 (영문) :: IBM
JML 시작하기_JML 주석으로 자바 프로그램 향상시키기 :: IBM
peer-to-peer 컴퓨팅의 실제 IP 멀티캐스트 기반의 검색 :: IBM
1vs순차N구조의 name-value pair DataSet 정의 :: javapattern.info
코딩지침 :: javapattern.info
Proxy하에서의 Client IP얻기.htm :: javapattern.info

※ 자료는 서로 공유되어야 합니다. ^_^ 각 강의자료의 저작권은 저작권자에게 있습니다.



출처 : http://50001.com/language/javaside/java-lecture.html
Posted by 1010
01.JAVA/Java2008. 11. 5. 15:13
반응형
Posted by 1010
01.JAVA/Java2008. 11. 5. 14:52
반응형
썬의 홈페이지에 실린 인터뷰 기사를 보다가...

Java의 오랜 미신 중에 하나...
"String 더하기 보다 StringBuffer append가 빠르다!?"

예를 들어... 아래의 코드는:

public static String concat1(String s1, String s2, String s3,
        String s4, String s5, String s6) {
    String result = "";
    result += s1;
    result += s2;
    result += s3;
    result += s4;
    result += s5;
    result += s6;
    return result;
}

이렇게 짜는게 좋다고... 가르치고 배운다. 나도 그렇게 배웠다:

public static String concat2(String s1, String s2,
        String s3, String s4, String s5, String s6) {
    StringBuffer result = new StringBuffer();
    result.append(s1);
    result.append(s2);
    result.append(s3);
    result.append(s4);
    result.append(s5);
    result.append(s6);
    return result.toString();
}

결론을 먼저 얘기하면, 새빨간 거짓말이다. 적어도 지금은 그렇다. 1.5 버전 이후의 썬의 자바 컴파일러를 사용한다면 확실히 그렇다.

StringBuffer를 사용해서 효과를 볼려면 이 정도는 해 줘야 한다:

public static String concat3(String s1, String s2, String s3,
        String s4, String s5, String s6) {
    return new StringBuffer(
        s1.length() + s2.length() + s3.length() + s4.length() +
        s5.length() + s6.length()).append(s1).append(s2).
        append(s3).append(s4).append(s5).append(s6).toString();
}

버퍼를 최초에 한번만 할당하면 append할때마다 버퍼 재할당을 하지 않으므로 확실히 빨라진다.
부작용은 코드가 극단적으로 읽기 힘들어 진다는 점. -.-;

옛날 얘기는 이쯤하고, 요즘 얘기를 해보자.

Java5에서 StringBuilder라는 새로운 클래스가 소개되었는데... 한마디로 요약하면 쓰레드에 안전하지 않은 StringBuffer다. 그런데 String은 immutable이라서 동기화 문제가 거의 없으므로, 예전에 StringBuffer쓰던 자리에 StringBuilder를 쓰면 된다.

똑같은 기능을 하는 함수를 가장 간단하게 구현하면 이렇다:

public static String concat4(String s1, String s2, String s3,
    String s4, String s5, String s6) {
    return s1 + s2 + s3 + s4 + s5 + s6;
}

1.5버전 이후의 썬의 자바 컴파일러는 concat4()처럼 짜면 StringBuilder append를 사용한 코드를 생성한다.

(위의 concat3()에서 사용한 방법까지 적용하면) 가장 효율적으로 구현하면 이렇게 된다:

public static String concat5(String s1, String s2, String s3,
        String s4, String s5, String s6) {
    return new StringBuilder(
        s1.length() + s2.length() + s3.length() + s4.length() +
        s5.length() + s6.length()).append(s1).append(s2).
        append(s3).append(s4).append(s5).append(s6).toString();
}

그러나, 여기서 고려해야할 점 두 가지:
1. 지금은 가장 효율적인 concat5()가 Java7이나 그 이후에도 가장 효율적이라는 보장이 없다.
2. concat4()가 concat5()보다 훨씬 읽기 좋다.

public static String concat6(String s1, String s2, String s3,
        String s4, String s5, String s6) {
    return new StringBuilder(BUFFER_SIZE).append(s1).append(s2).
        append(s3).append(s4).append(s5).append(s6).toString();
}


결론은:
1. 특별한 이유가 없다면 성능도 좋고 읽기도 좋은 concat4()가 최선의 선택이다.
2. 그러나 추가적인 계산없이, 버퍼 크기를 미리 알 수 있다면 concat6()도 나쁘지 않다.
3. 역시... 짜는 넘 맘이다.


출처 : http://iolothebard.tistory.com/291
Posted by 1010
01.JAVA/Java2008. 10. 27. 19:48
반응형

이 문서는 기술지원 또는 개발 시 java.lang.OutOfMemoryError 를 만났을 때 원인 파악 및 해결방안 입니다.

java.lang.OutOfMemoryError 에는 크게 2가지 패턴이 있다고 볼 수 있습니다.(전적으로 개인적인 생각이지만..^^)

Java heap 메모리가 정말로 Full 되서 나는 종류가 있고 그렇지 않은데도 나는 종류가 있습니다.

그 둘 중에 어는 것 인지부터 가려내는 것이 가장 먼저 선행되어야 합니다.

Java 가상머신에는 메모리 구조가 여러단계로 나뉘어 져 있으므로 어느 영역에 의해 java.lang.OutOfMemoryError 가 나는지 알기 위해 JAVA OPTION으로 싸이트가 안정화 되기 전까진 verbosegc 또는 -XX:+PrintGCDetails  옵션을 추가해 놓는 것이 java.lang.OutOfMemoryError 났을 때를 대비해 좋은 습관이라 할 수 있습니다.

-verbosegc 또는  -XX:+PrintGCDetails  옵션으로 로그에 남는 heap 메모리 정보를 본 후 java.lang.OutOfMemoryError 가 날 때 heap이 꽉 차서 나는 것인지 아닌지 부터 판단합니다.

1.     Heap Memory Full 차지 않았을 때 1)     Perm 영역이 full 되는 경우

Permanent generation is full…

increase MaxPermSize (current capacity is set to: 134217728 bytes)

[Full GC[Unloading class sun.reflect.GeneratedSerializationConstructorAccessor31282]

 810207K->802132K(1013632K), 8.3480617 secs]

<GC: 2 4  2465625.831280 10348 0 31 113802808 105534632 286326784 0 0 35782656 715849728 715848840 715849728 134217720 134023296 134217728 8.348677 8.348677 >

Passwd Check =============

<2005. 5. 19. 오전 9 32 23 KST> <Error> <HTTP> <BEA-101017> <[ServletContext(id=2536415,name=/,context-path=)] Root cause of ServletException.

java.lang.OutOfMemoryError

위와 같은 case 인 경우네는 Java 가상머신중에 Perm 영역이 full 차는 경우 입니다. 

Perm 영역에는 class object 및 관련된 meta data가 로드되는 곳인데 싸이트가 매우 많은 수의 class를 사용하는 경우 늘려줘야 하는 case도 있습니다.

얼마가 적정한 사이즈란 정답이 없는 것 같고 max가 계속 늘어나지 않고 일정한 사이즈를 유지 하면 됩니다.

             위 에러가 났을때는 -XX:MaxPermSize=256m  옵션으로 사이즈를 적당하게 늘려주는게 방

             법이며 늘려주었는데도 불구하고 Full 차는 시간만 늘어날 뿐 계속 사이즈가 늘어난다면 이 영역은 일반 비즈니스 프로그램으로 핸들링 할 수 없는 영역이므로 WAS 제품의 버그 및 jdk 버그로 보는 것이 일반적입니다.

       

2)     MAXDSIZ 사이즈 관련

  - Exception in thread “CompileThread0″ java.lang.OutOfMemoryError: requested 32756 bytes for ChunkPool::allocate

Possible causes:

         - not enough swap space left, or

         - kernel parameter MAXDSIZ is very small.

-          java.lang.OutOfMemoryError: unable to create new native thread

 

위 두 에러가 나는 이유는 Data 사이즈가 Full 차서 더 이상 메모리 할당을 할 수 없다는 java.lang.OutOfMemoryError 입니다.

Jdk도 내부적으로 c 라이브러리를 쓰고 jni를 통해서 c프로그램을 호출할 수 도 있는 환경에서 Data 영역이상으로 메모리 사용 시 위 에러를 만날 수 있습니다.

Heap 영역에는 java heap C heap이 있는데 C heap Data 메모리 영역에 영향을 미치는 것으로 보이며 보통 C의 전역 변수들이 잡히는 영역입니다.

위 현상을 만났을 때는 hp os MAXDSIZ가 너무 작게 잡혀있지 않은지 확인 후 적당한 크기로 늘려 줘야 합니다.

Glance 에서 shift+m 을 누른 후 jvm pid를 누르면 java가 사용하는 Data 사이즈를 모니터링 할 수 있습니다.

모니터링을 통해 적정한 사이즈로 MAXDSIZ를 늘려주어야 하며 만일 늘려 준게 에러 발생의 시간만 지연 시킬 뿐 계속 사용량이 늘어난다면 이는 사용하는 c라이브러리 쪽에 메모리 릭 버그가 있는 것이므로 c라이브러리를 체크 하셔야 합니다.

java.lang.OutOfMemoryError: unable to create new native thread

이 경우는 프로그램에서 Thread pool 프로그램 실수로 필요이상으로 쓰레드가 생성되는 경우도 과도하게 메모리를 사용할 수 있으므로 jvm 쓰레드 덤프를 통해 과도한 쓰레드가 생성되지 않았는지도 확인해 보셔야 합니다.

2.     Heap Full 찾을 때

이 경우는 java가 사용하는 heap 영역이 Full 되서 java.lang.OutOfMemoryError 가 나는 경우 인데 두 가지 패턴이 있습니다.

순간적으로 대량의 데이터를 메모리에 올리는 프로그램이 실행되어 문제를 야기 할수 있으며 다른 한 가지는 조금씩 메모리 릭이 발생하여 점차적으로 메모리가 쌓여 가는 경우 입니다.

두 가지 중에  어느 것인지 구별하는 것이 중요하며 이를 위해서도 마찬가지로 -verbosegc 또는  -XX:+PrintGCDetails  로그를 통해 순간적으로 메모리가 차는 것인지 조금씩 메모리가 차는 것인지를 확인하셔야 합니다.

1) 특정 프로그램의 특정시점의 과도한 메모리 사용에 의한 경우

                특정 프로그램이 과도하게 heap 메모리 이상 메모리를 사용하면서

java.lang.OutOfMemoryError가 발생하는 경우는 이 에러가 발생하는 시점의 쓰레드 덤프를 통해 어느 프로그램인지 쉽게 찾을 수 있습니다.

쓰레드 덤프에 메모리를 쓸만한 프로그램은 어느 정도의 자바프로그램 경험이 있으면 찾을 수 있습니다.

Ex)

“ExecuteThread: ‘36′ for queue: ‘default’” daemon prio=10 tid=0×0048e7b0 nid=48 lwp_id=4139729 runnable [0x23f32000..0x23f30500]

          at java.net.SocketInputStream.socketRead(Native Method)

          at java.net.SocketInputStream.read(Unknown Source)

          at oracle.net.ns.Packet.receive(Unknown Source)

          at oracle.net.ns.NetInputStream.getNextPacket(Unknown Source)

          at oracle.net.ns.NetInputStream.read(Unknown Source)

          at oracle.net.ns.NetInputStream.read(Unknown Source)

          at oracle.net.ns.NetInputStream.read(Unknown Source)

          at oracle.jdbc.ttc7.MAREngine.unmarshalUB1(MAREngine.java:718)

          at oracle.jdbc.ttc7.MAREngine.unmarshalSB1(MAREngine.java:690)

          at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:373)

          at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1405)

          at oracle.jdbc.ttc7.TTC7Protocol.fetch(TTC7Protocol.java:889)

          - locked <0×35e8e3b0> (a oracle.jdbc.ttc7.TTC7Protocol)

          at oracle.jdbc.driver.OracleResultSetImpl.next(OracleResultSetImpl.java:242)

          - locked <0×36f66c98> (a oracle.jdbc.driver.OracleResultSetImpl)

          at weblogic.jdbc.pool.ResultSet.next(ResultSet.java:180)

          at Dcard.AAA.ejb.monitor.member.wbbb.WACBean.getInfoList(WACBean.java:5789)

java.lang.OutOfMemoryError 가 날 상황에 쓰레드 덤프를 두 세번 떠서 같은 쓰레드 번호로 위 같은 로직이 오래 결려있다면 이는 프로그램에서 while(rs.next()) 를 오랜 기간 돌면서 메모리에 DB로부터 읽어서 올리고 있다는 것을 의미 합니다 대량 데이터 조회가 일어나는 경우인 것 입니다.

이런 식으로 특정 프로그램의 특정 시점에 과도한 메모리 사용으로 인한 java.lang.OutOfMemoryError 에러는 쓰레드 덤프를 통해 찾을 수 있습니다.

물론 2번에서 설명 할 heap dump를 통해서도 찾을 수 있습니다.

2) 메모리 릭에 의해 조금씩 메모리가 쌓인 경우

JVM위 에서 실행중인 프로그램중에 어떤 것이 GC 대상에서 제외되는 영역에 data를 조금씩 쌓고 있다는 얘기입니다.

GC 대상에서 제외되는 영역은 다음과 같은 곳이 있습니다.

- Http Session에 넣는 데이터..(세션 타임아웃 또는 invilidate 씨 까지 제외됨)

- Static 변수

- 서블릿 또는 jsp의 멤버변수 ( WAS 기동 후 최초 호출 시 인스턴스 화 되어 WAS가 내려 갈 때 까지 사라지지 않음 )

- EJB의 멤버변수( pool안에서 객체가 존재하는 한 GC대상에서 제외)

          위 같은 영역에 프로그램에서 data add 하는 구조를 메모리 릭 이라고 할 수 있습니다.

           IBM 또는 SUN JDK 인 경우에는 heapdump를 통해서 분석하여 어느 데이터가 메모리를 많이 잡고 있는지를 알 수 있습니다.

           Heapdump 사용법 및 분석 법은 다음을 참조 하시면 됩니다.

 http://www.alphaworks.ibm.com/aw.nsf/FAQs/heaproots

http://www-1.ibm.com/support/docview.wss?uid=swg21190476

http://www-1.ibm.com/support/docview.wss?rs=180&context=SSEQTP&q1=heapdump+solaris&uid=swg21190608&loc=en_US&cs=utf-8&lang=en

http://www.skywayradio.com/tech/WAS51/IBMHeapDump/

출처 : http://www.javaservice.net/~java/bbs/read.cgi?m=etc&b=jdk&c=r_p&n=1117521098&p=1&s=t#1117521098

var viewer_image_url = “http://blogimgs.naver.com/blog20/blog/layout_photo/viewer/”; var photo = new PhotoLayer(parent.parent.parent); photo.Initialized(); window.onunload = function() { photo.oPhotoFrame.doFrameMainClose(); }.bind(this);

Posted by 1010
01.JAVA/Java2008. 10. 27. 19:46
반응형

java.lang.OutOfMemoryError: PermGen space

요즘 들어 부쩍 java.lang.OutOfMemoryErorr로 인해 이클립스가 뻗어버리는 일이 많이 발생했었다.
하지만 Heap Monitor를 보면 200M 조차 사용하지 않는다.
이런 경우, 대부분은 PermGen 영역이 모자란 것이 원인일 수 있다.

{workspace}/.metadata/.log를 확인해보면 PermGen space라고 기록되어 있을 것이다.

Eclipse를 사용할 때는 JVM에 -Xmx 옵션은 대부분은 넣어서 사용하리라 생각한다.
하지만 Java는 메모리 영역을 사실상 두 부분으로 구분하여 사용한다.
일반 Java Heap space와 클래스와 같이 Permenant Generation 대상 데이터를 두기 위한 PermGen space이다.

대부분의 자바 애플리케이션에서는 기본 PermGen Size로 충분하겠지만
이클립스의 경우 클래스가 꽤 많아지면서 모자란 경우가 있는듯 하다.
javanese의 경우 Callisto를 깔아놓고 JDT, CDT를 왔다갔다 하면서 사용하다보니
Heap은 별로 쓰지도 않는데 PermGen space가 종종 모자라는 경우가 있다.
아마 Web관련 Tool을 많이 사용하는 분도 같은 현상이 나타날 수 있을 것이다.

PermGen space는 -XX:MaxPermSize 옵션으로 설정할 수 있다.

eclipse -vm /usr/lib/jvm/java-1.5.0-sun/bin/java -vmargs -XX:MaxPermSize=128m -Xms128m -Xmx512m

OutOfMemory 에러가 발생한다면 -Xmx만 늘려주지말고 PermSize도 확인해보라.

Posted by 1010
01.JAVA/Java2008. 10. 27. 14:39
반응형

StackOverflowException 예외는 메서드 호출이 너무 많이 중첩되어 실행 스택이 오버플로하는 경우에 throw됩니다.

무한 루프 또는 무한 재귀가 없는지 확인하십시오.

메서드 호출이 너무 많은 경우 이는 대부분 너무 깊거나 종료 조건이 없는 재귀를 의미합니다.

예외 처리 코드에는 스택이 필요할 수 있으므로 스택 오버플로 예외는 catch할 수 없습니다. 대신, 일반적인 응용 프로그램에서 스택 오버플로가 발생하면 CLR(공용 언어 런타임)에서 프로세스를 종료합니다.

CLR를 호스팅하는 응용 프로그램에서는 기본 동작을 변경하여 CLR에서 예외가 발생한 응응 프로그램 도메인을 언로드하고 프로세스를 계속하도록 지정할 수 있습니다. 자세한 내용은 ICLRPolicyManager공용 언어 런타임 호스팅을 참조하십시오.

Posted by 1010
01.JAVA/Java2008. 10. 27. 14:19
반응형
복구할 수 없는 StackOverFlow
 

문제 설명
JVM 종료 또는 코어 덤프 직전에 응용 프로그램이 "an irrecoverable stack overflow has occurred. Unexpected Signal 11" 오류 메시지를 표시합니다.  또는 응용 프로그램이 일반 "StackOverFlow Error" 메시지를 표시합니다. 


Unexpected Signal : 11 occurred at PC=0xfb9c22ec
Function name=write (compiled Java code)
Library=(N/A)
Current Java thread:
Dynamic libraries:

0x10000     /opt/bea/jdk131/jre/bin/../bin/sparc/native_threads/java
0xff350000     /usr/lib/lwp/libthread.so.1
0xff380000     /usr/lib/libdl.so.1
0xff200000     /usr/lib/libc.so.1
0xff330000     /usr/platform/SUNW,Ultra-Enterprise/lib/libc_psr.so.1
0xfee00000     /opt/bea/jdk131/jre/lib/sparc/client/libjvm.so
0xff2f0000     /usr/lib/libCrun.so.1
0xff1e0000     /usr/lib/libsocket.so.1
0xfed00000     /usr/lib/libnsl.so.1
0xff1b0000     /usr/lib/libm.so.1
0xff320000     /usr/lib/libw.so.1
0xff190000     /usr/lib/libmp.so.2
0xfede0000     /usr/lib/librt.so.1
0xfedc0000     /usr/lib/libaio.so.1
0xfecc0000     /opt/bea/jdk131/jre/lib/sparc/native_threads/libhpi.so
0xfec80000     /opt/bea/jdk131/jre/lib/sparc/libverify.so
0xfec40000     /opt/bea/jdk131/jre/lib/sparc/libjava.so
0xfec10000     /opt/bea/jdk131/jre/lib/sparc/libzip.so
0xfd810000     /opt/bea/jdk131/jre/lib/sparc/libnet.so
0xaafc0000     /usr/lib/nss_files.so.1
0x6c0c0000     /opt/bea/wlserver6.1/lib/solaris/libmuxer.so
0x6c0a0000     /usr/ucblib/libucb.so.1
0x6bfb0000     /usr/lib/libresolv.so.2
0x6bec0000     /usr/lib/libelf.so.1
0x6bf90000     /opt/bea/jdk131/jre/lib/sparc/libioser12.so
0x6bdc0000     /opt/bea/wlserver6.1/lib/solaris/libjsafe.so

Local Time = Fri Nov  21 16:32:28 2003
Elapsed Time = 6143

# HotSpot Virtual Machine Error : 11
# Error ID : 4F530E43505002BD 01
#
# Please report this error at
# http://java.sun.com/cgi-bin/bugreport.cgi
# Java VM: Java HotSpot(TM) Client VM (1.3.1_07-b02 mixed mode)
#

문제 해결다음 항목을 모두 수행해야 하는 것은 아닙니다.  어떤 경우에는 다음 중 일부만 수행하여도 해결할 수 있습니다.

항목 바로가기:

문제 발생 원인
StackOverFlow 메시지는 대개 JVM 코어 덤프 직전에 나타납니다.  대개 이 메시지는 사용자의 응용 프로그램 코드에 오류가 있음을 나타냅니다. 이 오류 메시지는 사용자/응용 프로그램 코드에서의 재귀적 호출이나 개체의 다차원 배열로 인해 StackOverFlow가 발생할 수 있는 시나리오 중 하나입니다. (java.sun.com에 이 문제에 대한 버그 보고서가 있습니다.)  문제 해결을 위해서는 까다롭겠지만 JVM의 구현 세부 사항을 알아야 합니다.

페이지 맨 위

응용 프로그램 코드 진단

  1. 이러한 문제을 유발하는 것이 응용 프로그램 코드인지 WebLogic인지 확인할 수 있도록 스택 트레이스 기능을 사용할 수 있는지 확인합니다.. 

  2. 응용 프로그램 코드가 의심스러운 경우 java.lang.StackOverflowError 예외가 발생하면 스택 트레이스를 표시하도록 응용 프로그램 코드를 변경할 수 있습니다.

이 방법을 사용하면 이러한 유형의 프로그래밍 오류를 신속하게 탐지할 수 있습니다(다음 프로그램 참조).

Catch ( StackOverflowError e ) {

        System.err.println("Exception: " + e );
        // Here is the important thing to do
        // when catching StackOverflowError's:
        e.printStackTrace();
        // do some cleanup and destroy the thread or unravel if possible.
}

  1. 최근에 변경한 응용 프로그램 코드에서 차이점이 있는지 살펴보고 재귀적으로 호출될 수 있는 항목이 있는지 확인합니다. 

  2. 의심스러운 코드에 디버그 문을 추가합니다.

페이지 맨 위

코어 파일에서 정보 수집
코어 파일은 대개 StackOverFlow가 발생할 때 생성됩니다.  코어 파일에서 주의할 점은 동일한 응용 프로그램 코드 함수가 반복적으로 호출되지만 실제 문제의 함수를 표시하지 않을 수도 있다는 점입니다.  코어 파일이 생성되지 않았다면 파일 권한 문제나 코어 파일 자체의 실제 제한 때문일 수 있습니다.  코어 덤프 파일의 크기는 다음 요소의 영향을 받을 수 있습니다.

  • ulimit -a를 검사하여 코어 파일이 생성될 수 있는 환경인지 확인하십시오.

  • ulimit -c (코어 파일의 크기 제한입니다.  이 부분을 ulimit -c unlimited로 수정하십시오.)

  • 커널 제한(ulimit -c에 대해 엄격한 제한).

  • 사용 가능한 사용자 디스크 공간(디스크 할당량이 있습니까?)

생성된 코어 파일이 있으면 코어 파일에 대해 dbx 또는 gdb를 실행합니다.  다음은 dbx 및 gdb용 명령과 gdb에 의해 생성된 출력 예제입니다. (참고:  DEBUG_PROG는 Java 환경에서 실행할 디버거나 프로파일러를 지정할 수 있는 환경 변수입니다.)
 
 a. dbx:


 $ java -version  (need to use right version of jdk)
$ ls /opt/bin/dbx (need to know dbx location) or "which dbx"
$ export DEBUG_PROG=/opt/bin/dbx (or wherever "dbx" is located)

 For JDK 1.3.X do the following:
       $ <path to java command>/java corefile
 For JDK 1.4.X do the following:
       $ dbx  <path to java command>/java corefile
  
Now you will be in the debugger.  Execute the following commands:
(dbx) where    ("shows a summary of the stack")
(dbx) threads    ("shows the state of the existing threads")
(dbx) quit


b. gdb:

 $ java -version  (need to use right version of jdk)
$ ls /usr/local/bin/gdb (need to know gdb location) or "which gdb"
$ export DEBUG_PROG=/usr/local/bin/gdb  (or wherever "gdb" is located)

 For JDK 1.3.X do the following:
       $ <path to java command>/java corefile
 For JDK 1.4.X do the following:
       $ gdb  <path to java command>/java corefile


Now you will be in the debugger.  Execute the following commands:
(gdb) where        ("shows a summary of the stack")
(gdb) thr    ("switch among threads or show the current thread")
(gdb) info thr        ("inquire about existing threads")
(gdb) thread apply 1 bt    ("apply a command to a list of threads, specifically the backtrace to thread #1")
(gdb) quit


where 명령을 사용하면 실행된 마지막 스레드의 스택 트레이스가 생성되고, thr 명령을 사용하면 현재 스레드가 표시되고, info thr 명령을 사용하면 모든 스레드의 상태가 표시되고, thread apply 1 bt 명령을 사용하면 코어 파일에 포함된 스레드 1의 스택 트레이스를 다른 방식으로 가져올 수 있습니다.  마지막 명령 thread apply # bt에서 #을 실제 스레드 번호로 바꾸어 개별 스레드의 스택 트레이스를 가져오거나 3을 "all"로 바꾸어 모든 스레드의 스택 트레이스를 가져올 수 있습니다.

다음 예제는 gdb 디버거를 이용하여 코어 파일(위의 명령 포함)을 분석한 것입니다.  이 예제 코어는 응용 프로그램의 사용자 native 코드 오류로 인해 야기된 것입니다.  (굵게 서식이 지정된 항목을 참조하십시오.)  이 스택 트레이스에서 signal handler가 호출되기 전 마지막 줄을 살펴보십시오.  원시 라이브러리 libhello.so에 포함된 displayHelloWorld 함수를 볼 수 있습니다.


    $ export DEBUG_PROG=/usr/local/bin/gdb
    $ java core

    GNU gdb 5.0
    Copyright 2000 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "sparc-sun-solaris2.8"...
    (no debugging symbols found)...
    Core was generated by `/wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/bin/../bin/sparc/native_threads'.
    Program terminated with signal 9, Killed.
    Reading symbols from /usr/lib/libthread.so.1...(no debugging symbols found)...
    Loaded symbols for /usr/lib/libthread.so.1
    Reading symbols from /usr/lib/libdl.so.1...(no debugging symbols found)...done.
    Loaded symbols for /usr/lib/libdl.so.1
    Reading symbols from /usr/lib/libc.so.1...(no debugging symbols found)...done.
    Loaded symbols for /usr/lib/libc.so.1
    Reading symbols from /usr/platform/SUNW,UltraAX-i2/lib/libc_psr.so.1...
    (no debugging symbols found)...done.
    Loaded symbols for /usr/platform/SUNW,UltraAX-i2/lib/libc_psr.so.1
    Reading symbols from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so...(no debugging symbols found)...done.
    Loaded symbols for /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    Reading symbols from /usr/lib/libCrun.so.1...(no debugging symbols found)...
    Loaded symbols for /usr/lib/libCrun.so.1
    Reading symbols from /usr/lib/libsocket.so.1...(no debugging symbols found)...
    Loaded symbols for /usr/lib/libsocket.so.1
    Reading symbols from /usr/lib/libnsl.so.1...(no debugging symbols found)...
    Loaded symbols for /usr/lib/libnsl.so.1
    Reading symbols from /usr/lib/libm.so.1...(no debugging symbols found)...done.
    Loaded symbols for /usr/lib/libm.so.1
    Reading symbols from /usr/lib/libw.so.1...
     warning: Lowest section in /usr/lib/libw.so.1 is .hash at 00000074
    (no debugging symbols found)...done.
    Loaded symbols for /usr/lib/libw.so.1
    Reading symbols from /usr/lib/libmp.so.2...(no debugging symbols found)...
    Loaded symbols for /usr/lib/libmp.so.2
    Reading symbols from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/native_threads/libhpi.so...(no debugging symbols found)...done.
    Loaded symbols for /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/native_threads/libhpi.so
    Reading symbols from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/libverify.so...(no debugging symbols found)...done.
    Loaded symbols for /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/libverify.so
    Reading symbols from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/libjava.so...(no debugging symbols found)...done.
Loaded symbols for /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/libjava.so
    Reading symbols from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/libzip.so...(no debugging symbols found)...done.
    Loaded symbols for /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/libzip.so
    Reading symbols from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/libnet.so...(no debugging symbols found)...done.
    Loaded symbols for /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/libnet.so
    Reading symbols from /wwsl/sharedInstalls/solaris/wls70sp2/server/lib/solaris/libfilelock.so...(no debugging symbols found)...done.
    Loaded symbols for /wwsl/sharedInstalls/solaris/wls70sp2/server/lib/solaris/libfilelock.so
    Reading symbols from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/libioser12.so...(no debugging symbols found)...done.
    Loaded symbols for /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/libioser12.so
    Reading symbols from /usr/lib/nss_nis.so.1...(no debugging symbols found)...
    Loaded symbols for /usr/lib/nss_nis.so.1
    Reading symbols from /wwsl/sharedInstalls/solaris/wls70sp2/server/lib/solaris/libstackdump.so...(no debugging symbols found)...done.
    Loaded symbols for /wwsl/sharedInstalls/solaris/wls70sp2/server/lib/solaris/libstackdump.so
    Reading symbols from /usr/lib/libmd5.so.1...(no debugging symbols found)...
    Loaded symbols for /usr/lib/libmd5.so.1
    Reading symbols from /wwsl/sharedInstalls/solaris/wls70sp2/server/lib/solaris/libmuxer.so...(no debugging symbols found)...done.
    Loaded symbols for /wwsl/sharedInstalls/solaris/wls70sp2/server/lib/solaris/libmuxer.so
    Reading symbols from /usr/ucblib/libucb.so.1...(no debugging symbols found)...
    Loaded symbols for /usr/ucblib/libucb.so.1
    Reading symbols from /usr/lib/libresolv.so.2...(no debugging symbols found)...
    Loaded symbols for /usr/lib/libresolv.so.2
    Reading symbols from /usr/lib/libelf.so.1...(no debugging symbols found)...
    Loaded symbols for /usr/lib/libelf.so.1
    Reading symbols from /home/usera/wls70/solaris/projectWork/lib/libhello.so...
    (no debugging symbols found)...done.
    Loaded symbols for /home/usera/wls70/solaris/projectWork/lib/libhello.so

(gdb) where

    #0  0xff369764 in __sigprocmask () from /usr/lib/libthread.so.1
    #1  0xff35e978 in _resetsig () from /usr/lib/libthread.so.1
    #2  0xff35e118 in _sigon () from /usr/lib/libthread.so.1
    #3  0xff361158 in _thrp_kill () from /usr/lib/libthread.so.1
    #4  0xff24b908 in raise () from /usr/lib/libc.so.1
    #5  0xff2358f4 in abort () from /usr/lib/libc.so.1
    #6  0xfe3c6904 in __1cCosFabort6Fl_v_ ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #7  0xfe3c59f8 in __1cCosbBhandle_unexpected_exception6FpnGThread_ipCpv_v_()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #8  0xfe20a8bc in JVM_handle_solaris_signal ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #9  0xff36b82c in __sighndlr () from /usr/lib/libthread.so.1
    #10 <signal handler called>
    #11 0xe9f90420 in Java_HelloWorld_displayHelloWorld ()
       from /home/usera/wls70/solaris/projectWork/lib/libhello.so

    #12 0x90aec in ?? ()
    #13 0x8dc54 in ?? ()
    #14 0x8dc54 in ?? ()
    #15 0x8dc54 in ?? ()
    #16 0x8ddbc in ?? ()
    #17 0x8dde0 in ?? ()
    #18 0x8dc54 in ?? ()
    #19 0x8dc54 in ?? ()
    #20 0x8dde0 in ?? ()
    #21 0x8dc78 in ?? ()
    #22 0x8dc54 in ?? ()
    #23 0x8ddbc in ?? ()
    #24 0x8dc54 in ?? ()
    #25 0xfe5324f0 in __1cMStubRoutinesG_code1_ ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #26 0xfe0cbe9c in
__1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #27 0xfe1f6dc4 in __1cJJavaCallsMcall_virtual6FpnJJavaValue_nLKlassHandle_nMsymbolHandle_4pnRJavaCallArguments_pnGThread__v_()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #28 0xfe1fcd94 in __1cJJavaCallsMcall_virtual6FpnJJavaValue_nGHandle_nLKlassHandle_nMsymbolHandle_5pnGThread__v_()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #29 0xfe21b708 in __1cMthread_entry6FpnKJavaThread_pnGThread__v_ ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #30 0xfe216208 in __1cKJavaThreadDrun6M_v_ ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #31 0xfe213ed0 in _start ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so

    (gdb) thr

    [Current thread is 1 (LWP    14        )]

    (gdb) info thr
      16 LWP    13          0xff29d194 in _poll () from /usr/lib/libc.so.1
      15 LWP    12          0xff29f008 in _lwp_sema_wait () from /usr/lib/libc.so.1
      14 LWP    11          0xff29f008 in _lwp_sema_wait () from /usr/lib/libc.so.1
      13 LWP    10          0xff29bc2c in _so_accept () from /usr/lib/libc.so.1
      12 LWP    9          0xff29bc2c in _so_accept () from /usr/lib/libc.so.1
      11 LWP    8          0xff29d194 in _poll () from /usr/lib/libc.so.1
      10 LWP    7          0xff29d194 in _poll () from /usr/lib/libc.so.1
      9 LWP    6          0xff29f008 in _lwp_sema_wait () from /usr/lib/libc.so.1
      8 LWP    5          0xff29f008 in _lwp_sema_wait () from /usr/lib/libc.so.1
      7 LWP    4          0xff29f008 in _lwp_sema_wait () from /usr/lib/libc.so.1
      6 LWP    3          0xff29d194 in _poll () from /usr/lib/libc.so.1
      5 LWP    2          0xff29e958 in _signotifywait () from /usr/lib/libc.so.1
      4 LWP    1          0xff29d194 in _poll () from /usr/lib/libc.so.1
      3 LWP    16          0xff29c4fc in door_restart () from /usr/lib/libc.so.1
      2 LWP    15          0xff369774 in private___lwp_cond_wait ()
       from /usr/lib/libthread.so.1
    * 1 LWP    14          0xff369764 in __sigprocmask ()
       from /usr/lib/libthread.so.1
    (gdb) thread apply 1 bt

Thread 1 (LWP    14       ):
    #0  0xff369764 in __sigprocmask () from /usr/lib/libthread.so.1
    #1  0xff35e978 in _resetsig () from /usr/lib/libthread.so.1
    #2  0xff35e118 in _sigon () from /usr/lib/libthread.so.1
    #3  0xff361158 in _thrp_kill () from /usr/lib/libthread.so.1
    #4  0xff24b908 in raise () from /usr/lib/libc.so.1
    #5  0xff2358f4 in abort () from /usr/lib/libc.so.1
    #6  0xfe3c6904 in __1cCosFabort6Fl_v_ ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #7  0xfe3c59f8 in __1cCosbBhandle_unexpected_exception6FpnGThread_ipCpv_v_()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #8  0xfe20a8bc in JVM_handle_solaris_signal ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #9  0xff36b82c in __sighndlr () from /usr/lib/libthread.so.1
    #10 <signal handler called>
    #11 0xe9f90420 in Java_HelloWorld_displayHelloWorld ()
       from /home/usera/wls70/solaris/projectWork/lib/libhello.so    #12 0x90aec in ?? ()
    #13 0x8dc54 in ?? ()
    #14 0x8dc54 in ?? ()
    #15 0x8dc54 in ?? ()
    #16 0x8ddbc in ?? ()
    #17 0x8dde0 in ?? ()
    #18 0x8dc54 in ?? ()
    #19 0x8dc54 in ?? ()
    #20 0x8dde0 in ?? ()
    #21 0x8dc78 in ?? ()
    #22 0x8dc54 in ?? ()
    #23 0x8ddbc in ?? ()
    #24 0x8dc54 in ?? ()
    #25 0xfe5324f0 in __1cMStubRoutinesG_code1_ ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #26 0xfe0cbe9c in __1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #27 0xfe1f6dc4 in __1cJJavaCallsMcall_virtual6FpnJJavaValue_nLKlassHandle_nMsymbolHandle_4pnRJavaCallArguments_pnGThread__v_()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #28 0xfe1fcd94 in __1cJJavaCallsMcall_virtual6FpnJJavaValue_nGHandle_nLKlassHandle_nMsymbolHandle_5pnGThread__v_()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #29 0xfe21b708 in __1cMthread_entry6FpnKJavaThread_pnGThread__v_()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #30 0xfe216208 in __1cKJavaThreadDrun6M_v_ ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so
    #31 0xfe213ed0 in _start ()
       from /wwsl/sharedInstalls/solaris/wls70sp2/jdk131_06/jre/lib/sparc/server/libjvm.so

    (gdb) quit


페이지 맨 위

스레드 덤프 수집JVM이 실행될 때 JVM의 스레드 덤프를 대개 5-10초 간격으로 주기적으로 수집할 수 있습니다.  이 정보를 사용하여 재귀적 코드를 찾아 수정할 수 있습니다.  스레드 덤프를 수집하려면 Java 프로세스 ID(PID)에서 다음 과정을 수행해야 합니다.

Unix 유형의 플랫폼:

  1. 크래시가 발생하기 직전에 kill -3을 수행합니다.
  2. kill -3 <jvm-pid>는 java 스레드를 덤프합니다.

Windows 플랫폼:

  1. JVM PID에서 kill -3을 수행합니다. 

  2. JVM이 실행되는 창에서 <Ctrl> <Break> 키를 눌러도 됩니다.

JRockit JVM의 경우:

  1. JRockit JVM의 경우 모든 플랫폼에서 위의 사항을 적용합니다.

이 작업은 루트 java 프로세스에서 수행해야 합니다. 

  1. 프로세스의 트리 구조(부모-자식 ASCII 다이어그램)를 얻으려면 --forest 옵션을 사용합니다. 

예를 들어, 사용자 "usera"가 시작한 프로세스를 찾으려면   ps -lU usera --forest를 실행합니다.

Linux에서 JRockit을 사용하여 스레드 덤프를 얻는 특정 예제는 다음을 참조하십시오. http://e-docs.bea.com/wls/docs70/cluster/trouble.html#602852

페이지 맨 위

JVM을 중지하여 스레드 덤프 가져오기
다음 플래그를 설정하여 코어가 발생하기 직전에 서버의 스레드 덤프를 생성할 수 있습니다.

Sun JVM
이 옵션은 SUN JVM에서 -XX:+ShowMessageBoxOnError입니다. (이 옵션은 SUN 웹 사이트에 공식적으로 설명되어 있지 않습니다.)  JVM 크래시가 발생하면 프로그램은 다음과 같은 메시지를 표시합니다. Do you want to debug the problem?  이 때 JVM의 스레드 덤프를 가져올 수 있습니다. 

JRockit JVM
jRockit에서 이에 해당하는 옵션은 8.1 SP2 버전에 포함된 버전부터 사용할 수 있도록 지원될 예정입니다.  JRockit의 옵션은   -Djrockit.waitonerror입니다.

페이지 맨 위

재귀적 JSP 오류 페이지 및 태그
어떤 경우에는 다음과 같은 JSP의 재귀적 호출 문제로 인해 발생하기도 합니다.

JSP 오류 페이지:

  1. jsp_error 페이지에서 <%@ page errorPage="jsp_error"%> 태그가 있는지 확인하십시오. 이 태그로 인해 무한정 재귀가 발생할 수 있습니다. 

  2. 이 태그를 제거하고 발생 가능성이 있는 모든 예외의 스택 트레이스를 출력하십시오.

이러한 방법으로 오류 페이지에서 발생하는 문제를 찾을 수 있습니다. 

  1. 이 문제가 해결된 다음 이 페이지로 보내진 원래의 오류를 확인할 수 있습니다.


JSP 태그:

  1. 이 태그를 검사하여 잘못된 jsp/servlet login/auth/error 보고 코드가 있는지 판별합니다. 

  2. 이 코드에 문제가 있는 경우 해당 코드를 수정하면 재귀 및 크래시 문제를 해결할 수 있습니다.


WebLogic JSP Form Validation 태그:

  1. WebLogic JSP Form Validation 태그를 사용하는 경우 StackOverFlow 예외를 유발하는 무한 루프가 발생할 수 있으므로 <wl:form> 태그에 동일한 페이지를 action 속성을 설정하지 않아야 합니다. 

페이지 맨 위

스택 크기 조정
또 다른 해결 방법은 JVM에 -Xss 인수를 사용하여 스레드 스택의 크기를 늘리는 것입니다.  그러나 이 방법은 재귀적 호출인 경우에는 도움이 되지 않으며 문제 해결을 지연시킬 뿐입니다.  각 Java 스레드는 두 개의 스택, 즉 Java 코드용 스택과 C 코드용 스택을 가지고 있습니다. 이 옵션은 스레드에서 C 코드가 사용할 수 있는 최대 스택 크기를 지정된 값으로 설정합니다.  -Xss 플래그의 자세한 사용 방법은 다음 페이지의 Non-Standard Options 항목을 참조하십시오. http://java.sun.com/j2se/1.3/docs/tooldocs/solaris/java.html

페이지 맨 위

알려진 Sun 관련 문제점
java.util 패키지에서 getProperty를 호출할 때 StackOverFlow 문제가 발생할 수 있습니다.  java.util.Properties.getProperty(Properties.java:475)에서 java.lang.StackOverflowError를 일으키는 재귀적 호출이 발견되었습니다.  이 문제는 모든 플랫폼의 버전 1.3.1 또는 1.4.1 JDK에서 발생합니다.  이것은 Properties()의 클래스 생성자를 사용하는 JDK의 문제입니다.  Sun, #4906193에 다음과 같은 버그 리포트가 기록되어 있습니다. 

코드에서 다음 명령을 사용하지 마십시오.

Properties p = new Properties(System.getProperties());

대신 다음 명령을 사용하십시오.

Properties p = new Properties();
p = System.getProperties();

이렇게 하면 재귀적 호출 스택 트레이스를 방지할 수 있습니다. 


이 문제는 일부 웹 응용 프로그램(응용 프로그램의 로그인 부분)에서 일정 기간 동안 발생했으며 트레이스가 쉽지 않았습니다.  다음은 잘못된 코드에 대한 주석이 포함된 예제 코드입니다.  다음의 간단한 프로그램에서 문제의 행에서 리마크를 제거하고 아래 두 행을 리마크로 막으면(로직은 동일) 재귀적 스택 트레이스가 나타납니다.

import java.util.Properties;

public class stacktest {

public static void main(String args[]) {

    int max = 500000;  // or some other large number depending on the stack size

    for ( int i = 0; i < max; i++ ) {
      //Properties p = new Properties(System.getProperties());
      // un-comment the line above and comment the following two lines
      // out to see the recursive stacktrace
      // containing "java.util.Properties.getProperty(Properties.java:475)"
      Properties p = new Properties();
      p = System.getProperties();

      p.put("blah", "blah");
      System.setProperties(p);
    }
    System.out.println("Went through "+max+" iterations, now get a property");
    String s = System.getProperty("some property other than blah");
  }

}

페이지 맨 위 

추가 도움말이 필요하십니까?

패턴대로 작업했지만 추가 도움말이 필요한 경우 다음과 같이 할 수 있습니다.

  1. http://support.bea.com/의 AskBEA에서 "StackOverFlow error"로 문제를 조회하여 게시된 다른 해결 방법을 찾아봅니다.
  2. http://newsgroups.bea.com/ 사이트에서 BEA 뉴스그룹에 보다 자세한 내용을 질문합니다.

이렇게 해도 문제를 해결할 수 없는 경우 유효한 유지보수 계약이 되어 있다면 http://support.bea.com/에 로그인하여 Support Case를 신청할 수 있습니다.


고객 의견

이 지원 진단 패턴 "복구할 수 없는 StackOverFlow"가 도움이 되셨습니까? 여러분에게 꼭 필요한 정보나 지원 진단 패턴에 새로 추가하길 바라는 항목이 있으면 저희에게 알려주시기 바랍니다.


책임의 한계에 대한 고지:

BEA Systems, Inc.는 사용자와 BEA 간의 유지 보수 및 지원 계약 내용에 따라 이 웹 사이트에 기술 팁과 패치를 제공합니다. BEA에서 허가한 소프트웨어와 함께 이 정보 및 코드를 사용할 수 있지만 BEA는 기술 팁 및 패치와 관련하여 어떠한 명시적이거나 암시적인 보증도 하지 않습니다.

이 문서에 참조된 상표는 해당 소유자의 자산입니다. 자세한 상표 정보에 대해서는 제품 설명서를 참조하십시오.

Posted by 1010
01.JAVA/Java2008. 10. 10. 16:58
반응형

JAVA/Advance 2008/09/23 16:08

1 . 다운로드주소 http://james.apache.org/download.cgi
     다운로드파일 : http://apache.mirror.cdnetworks.com/james/server/binaries/james-binary-2.3.1.zip


2. james-binary-2.3.1.zip  파일을 압축 풀고 Path에 추가
  Path = %Path%;C:\kjy\james-2.3.1\bin;

3. C:\kjy\james-2.3.1\bin\run.bat 실행

사용자 삽입 이미지


4. 텔넷 접속 : 새로운 콘솔 창 띄워서 실행
   telnet localhost 4555
사용자 삽입 이미지

5. 로그인
   아이디/패스워드 : root/root

6. 사용자 추가
   adduser [사용자 이름] [패스워드]
    예) adduser test 1234

7. 사용자 추가 확인
    listusers
사용자 삽입 이미지

8. 아웃룩 설정 추가

     새로운 계정을 만들고,
사용자 삽입 이미지

     메일주소는 [사용자이름]@localhost,
사용자 삽입 이미지

     POP3는 localhost ,
     SMTP도 localhost
사용자 삽입 이미지

9. 메일 송수신 확인
사용자 삽입 이미지

추가 : C:\kjy\james-2.3.1\apps\james\SAR-INF\config.xml 설정파일 수정으로 localhost 가 아니 IP로 송수신 가능 함
Posted by 1010
01.JAVA/Java2008. 10. 10. 16:56
반응형

[펌] JavaMail

JAVA/Basic 2008/09/23 14:56

JavaMail 1.4
http://java.sun.com/products/javamail/index.jsp
http://java.sun.com/products/javamail/downloads/index.html

압축풀어서 mail.jar 파일을 %JAVA_HOME%\lib 아래 복사


JavaBeans Activation Framework (JAF)
http://java.sun.com/products/javabeans/jaf/index.jsp
http://java.sun.com/products/javabeans/jaf/downloads/index.html

압축풀어서 activation.jar 파일을 %JAVA_HOME%\lib 아래 복사


classpath 에 mail.jar 와 activation.jar 파일 추가



import java.util.*;
import java.io.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;


public class MailTest {

        public static void main(String[] args)
        throws Exception
        {
                String host =  "SMTP서버";
                String senderemail = "보내는 사람 메일 주소";
                String email = "받는 사람 메일 주소";
                String subject = "제목";
                String mailtext = "<html><body><h1>내용</h1></body></html>";
                String[] attached = {"D:/projects/encyclopedia/java/mail/석양.jpg", "D:/projects/encyclopedia/java/mail/겨울.jpg"};

                sendEmail(host, senderemail, email, subject, mailtext, attached);
        }


        /**
         * send Email.
         *
         * @param       host    메일서버주소
         * @param       from    보내는 사람
         * @param       to              받는사람 - ","로 구분된 메일 주소
         * @param       subject 제목
         * @param       mailtext        내용
         * @param       attached        첨부파일
         * @result      boolean
         * @exception   javax.mail.internet.AddressException
         *                              javax.mail.MessagingException
         */
        public static void sendEmail(String host, String senderemail, String email,
         String subject,String mailtext, String[] attached)
        throws javax.mail.internet.AddressException, javax.mail.MessagingException,
        java.io.UnsupportedEncodingException
        {
                Properties props = new Properties();


                props.put("mail.smtp.host", host);


                Session session = Session.getDefaultInstance(props, null);
                Multipart mp = new MimeMultipart();


                // create a message
                MimeMessage msg = new MimeMessage(session);
                msg.setFrom(new InternetAddress(senderemail));


                // 받는사람
                InternetAddress[] toAddress = InternetAddress.parse(email);
                msg.setRecipients(Message.RecipientType.TO, toAddress);


                // 제목
                msg.setSubject(subject, "euc-kr");


                // 내용
                MimeBodyPart mbp1 = new MimeBodyPart();

                mbp1.setContent(mailtext, "text/html; charset=euc-kr");

                mp.addBodyPart(mbp1);


                System.out.println("host="+host);
                System.out.println("sender="+senderemail);
                System.out.println("receive="+email);
                System.out.println("mbp1="+mbp1);


                // 파일첨부
                if (attached != null) {
                        for (int i = 0; i < attached.length; i++) {

                                MimeBodyPart mbp2 = new MimeBodyPart();

                                FileDataSource fds = new FileDataSource(attached[i]);
                                mbp2.setDataHandler(new DataHandler(fds));

                                mbp2.setFileName(iso8859(fds.getName()));

                                mp.addBodyPart(mbp2);
                        }
                }


                // 메시지 add
                msg.setContent(mp);


                // header 에 날짜 삽입
                msg.setSentDate(new Date());


                // send the message
                Transport.send(msg);
        }


        public static String iso8859(String strStr)
        throws java.io.UnsupportedEncodingException
        {
                if (strStr == null)
                {
                        return  null;
                }
                else
                {
                        return new String(strStr.getBytes("KSC5601"), "8859_1");
                }
        }
}

Posted by 1010
01.JAVA/Java2008. 9. 17. 15:24
반응형
자바의 CLASSPATH 설정하는 방법
JDK를 설치하면 java파일을 컴파일 할 수 있겠죠. 다만 JDK설치 폴더내 bin폴더 안에 있는 javac.exe라는 자바 컴파일용 파일이 있는 위치에서만 됩니다. 이것을 어느곳에서든지 컴파일이 가능하도록 설정해보도록 합니다.

먼저 내컴퓨터 등록정보 - 고급 - 환경변수를 클릭합니다. 그럼 다음과 같은 창이 하나 뜹니다.
여기서 시스템 변수를 변경합니다.

먼저 JAVA_HOME을 설정합니다. 새로만들기를 클릭해서 변수이름에 JAVA_HOME이라고 입력하고 변수 값에는 JDK가 설치된 경로를 입력합니다.
주의할 점은 C:\jdk1.5.0_06까지만 입력하고 뒤에 \;이나 ;을 붙이지 않도록 합니다.

그다음 Path를 설정합니다. 변경을 눌러서 추가를 합니다.
앞에 이미 지정되어 있는 Path뒤에 연결하여 입력합니다. 구분은 ;(세미콜론)으로 합니다.
;%JAVA_HOME%\bin;을 입력합니다.

CLASSPATH를 설정합니다. 시스템 변수에 CLASSPATH가 이미 있으면 추가를 하고 없다면 새로 만드시면 됩니다.
변수값에는 .;를 입력합니다.

확인 버튼을 눌러서 설정을 완료합니다.


시스템 변수가 제대로 지정이 되었는지 확인합니다.
윈도우시작 - 실행 - cmd를 입력하여 커맨드창을 엽니다.
확인은 echo %변수이름% 으로 합니다.

입력한대로 변수값이 제대로 나오는지 확인합니다.
Path부분의 밑줄은 환경변수에서 %JAVA_HOME%\bin;이라고 입력한 부분입니다.
만약 JAVA_HOME에서 JDK의 경로를 C:\jdk1.5.0_06를 C:\jdk1.5.0_06\; 이나 C:\jdk1.5.0_06; 이라고 입력했으면 저 밑줄친 부분은 C:\jdk1.5.0_06\;bin; 이나 C:\jdk1.5.0_06;bin; 이라고 나타날껍니다.
컴파일도 당연히 안되겠지요.
다음에 JDK를 다른곳에 재설치하게 되면 JAVA_HOME의 JDK의 설치경로만 바꿔주시면 간단해집니다.

제대로 실행이 되는지 확인해봅니다. javac를 입력합니다.
위와 같은 화면이 나오면 설정 완료~

- 확인 할때 java를 입력하지 않고 왜 javac를 입력하는이유?
JDK가 설치될때 java.exe는 경로등이 자동으로 등록이 됩니다. 설치직 후에 커맨드창을 열어서 java라고 입력하면 잘 실행됩니다. 그게 잘 되잖아~ 가 아닙니다. -_-;;
javac는 자동으로 등록되지 않기 때문에 환경변수를 설정하고 javac로 확인합니다.
Posted by 1010
01.JAVA/Java2008. 8. 28. 10:58
반응형
How do I resolve a java.lang.UnsupportedClassVersionError?
Abstract: How do I resolve a java.lang.UnsupportedClassVersionError?

Issue:

When I attempt to run my Servlet, I receive the following exceptions:

javax.servlet.ServletException: Error allocating a servlet instance
org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:185)
com.sun.enterprise.web.connector.grizzly.ProcessorTask.process(ProcessorTask.java:653)
com.sun.enterprise.web.connector.grizzly.ProcessorTask.process(ProcessorTask.java:534)
com.sun.enterprise.web.connector.grizzly.ProcessorTask.doTask(ProcessorTask.java:403)
com.sun.enterprise.web.connector.grizzly.WorkerThread.run(WorkerThread.java:55)

root cause java.lang.UnsupportedClassVersionError: untitled1/Servlet1 (Unsupported major.minor version 49.0)
java.lang.ClassLoader.defineClass0(Native Method)
java.lang.ClassLoader.defineClass(ClassLoader.java:537)
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:123)
org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1774)
org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:905)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1370)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1234)
org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:185)
com.sun.enterprise.web.connector.grizzly.ProcessorTask.process(ProcessorTask.java:653)
com.sun.enterprise.web.connector.grizzly.ProcessorTask.process(ProcessorTask.java:534)
com.sun.enterprise.web.connector.grizzly.ProcessorTask.doTask(ProcessorTask.java:403)
com.sun.enterprise.web.connector.grizzly.WorkerThread.run(WorkerThread.java:55)

How do I resolve this issue?

Solution:

This exception can occur when the source is built targeting a JDK that is not supported by the JDK attempting to run it. In the above example, if the servlet was built targeting only JDK 1.5, but the web server runs JDK 1.4, the above exception will occur.

Check, Project Properties | Build | Java | Target VM, and verify that the Target VM indicates a JDK compatibility that is appropriate for the JDK that is running it. It is recommended to set this field to 'All Java SDKs' for the most compatibility. The only reason you would want to specify a particular version is if your code uses language features that only appear in a particular verison of the JDK, and you want to ensure that users use only a compatible JDK.

Also check, Project Properties | Build | Java | Language Features, and verify that the Language Features are applicable with JDK that is running it.

--------------------------------------------------------------------------------------------------

java.lang
Class UnsupportedClassVersionError

java.lang.Object
  extended byjava.lang.Throwable
      extended byjava.lang.Error
          extended byjava.lang.LinkageError
              extended byjava.lang.ClassFormatError
                  extended byjava.lang.UnsupportedClassVersionError
All Implemented Interfaces:
Serializable

public class UnsupportedClassVersionError
extends ClassFormatError

Thrown when the Java Virtual Machine attempts to read a class file and determines that the major and minor version numbers in the file are not supported.

Since:
1.2
See Also:
Serialized Form

Constructor Summary
UnsupportedClassVersionError()
          Constructs a UnsupportedClassVersionError with no detail message.
UnsupportedClassVersionError(String s)
          Constructs a UnsupportedClassVersionError with the specified detail message.
 
Methods inherited from class java.lang.Throwable
fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, initCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toString
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Constructor Detail

UnsupportedClassVersionError

public UnsupportedClassVersionError()
Constructs a UnsupportedClassVersionError with no detail message.

UnsupportedClassVersionError

public UnsupportedClassVersionError(String s)
Constructs a UnsupportedClassVersionError with the specified detail message.
Parameters:
s - the detail message.

JavaTM 2 Platform
Std. Ed. v1.4.2

Submit a bug or feature
For further API reference and developer documentation, see Java 2 SDK SE Developer Documentation. That documentation contains more detailed, developer-targeted descriptions, with conceptual overviews, definitions of terms, workarounds, and working code examples.

Copyright 2003 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. Also see the documentation redistribution policy.
-------------------------------------------------------------------------

java.lang.UnsupportedClassVersionError

By Alvin J. Alexander, devdaily.com

You know what will really screw with your mind? When there is a 1.4.2 version of a java.exe file in the C:\Windows\System32 directory of your Windows XP system, and you're trying to compile and run a Java 1.5 program from the command line. I kept getting this error message and couldn't figure it out, even though I knew what it meant(!):

C:\Al\JavaProjects\AutomatedGUITester\deploy>java -jar xylocator.jar

Exception in thread "main" java.lang.UnsupportedClassVersionError: com/devdaily/
xylocator/XYLocator (Unsupported major.minor version 49.0)
        at java.lang.ClassLoader.defineClass0(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:537)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:12
3)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:251)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:55)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:194)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:187)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:289)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:274)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)

I knew that this error message was telling me that I was trying to run a Java program/class with a JVM version that was older than what I compiled it with, but I thought I had everything set up right, including my JAVA_HOME and PATH environment variables. (FWIW, after a little research it looks like the "Unsupported major.minor version 49.0" message refers to Java 1.5.0.)

Now, before you think I'm too crazy I compile my program with this batch file:

REM compile.bat
set JAVA_HOME=C:\jdk1.5.0_06
set PATH=C:\Windows;C:\Windows\System32;C:\jdk1.5.0_06\bin
set CLASSPATH=

javac com/devdaily/xylocator/XYLocator.java

Then I would create my jar file with this batch script:

REM createjar.bat
set JAVA_HOME=C:\jdk1.5.0_06
set PATH=C:\Windows;C:\Windows\System32;C:\jdk1.5.0_06\bin
set CLASSPATH=

jar cfm xylocator.jar Manifest.txt com/devdaily/xylocator/*.class

And finally, I would try to run it like this:

REM runjar.bat (BAD VERSION, NEED TO FIX PATH)

set JAVA_HOME=C:\jdk1.5.0_06
set PATH=C:\Windows;C:\Windows\System32;C:\jdk1.5.0_06\bin
set CLASSPATH=
set QTJAVA=

java -jar xylocator.jar

Now, once I realized that the #%$! java.exe file was in the C:\Windows\System32 directory the problem was easy to fix. I just had to put the Java 1.5 directory in the PATH before the System32 directory, like this:

REM runjar.bat
set JAVA_HOME=C:\jdk1.5.0_06
REM This works because the JDK is in the PATH before the System32
REM directory.
set PATH=C:\jdk1.5.0_06\bin;C:\Windows;C:\Windows\System32
set CLASSPATH=
set QTJAVA=

java -jar xylocator.jar

Now it works like a champ. FWIW, this Java program lets me determine the x/y coordinates of any point I choose on the screen. I basically take a snapshot of the screen, then display that snapshot as an overlay to the entire desktop, then use mouse click information to get the x/y coordinates. Some of this had to be done using Java 1.5.x, or native code, which I don't want to get into because I want this to work on the Mac as well as Windows.

------------------------------------------------------------------------
Posted by 1010
01.JAVA/Java2008. 8. 25. 14:22
반응형
Posted by 1010
01.JAVA/Java2008. 8. 20. 15:11
반응형

만약 내가 특정 알고리즘으로 파일을 인코딩하고, 디코딩하며 보안을 철저히 하고 싶을때..

또는 통신 알고리즘상에서 스푸핑을 방지하고 싶을때..


또는 DB 설정파일을 보안화하고 싶을때..


그냥 자바를 보면 답이 나온다.



 import java.util.Iterator;
import java.security.Security;
import java.security.Provider;

public class PrintProviders {
    public static void main(String[] args) {
        Provider[] providers = Security.getProviders();
        for (int i = 0; i < providers.length; i++) {
            String name = providers[i].getName();
            String info = providers[i].getInfo();
            double version = providers[i].getVersion();
            System.out.println("-------------------------------------");
            System.out.println("name: " + name);
            System.out.println("info: " + info);
            System.out.println("version: " + version);

            for (Iterator iter = providers[i].keySet().iterator(); iter
                    .hasNext();) {
                String key = (String) iter.next();
                System.out.println("\t" + key + "\t"
                        + providers[i].getProperty(key));
            }

            System.out.println("-------------------------------------");

        }
    }
}



자바에서는 Security 알고리즘이 무상하게 제공되고 있다.


위의 소스의 결과를 볼까?


 -------------------------------------
name: SUN
info: SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; JavaLoginConfig Configuration)
version: 1.6
 Alg.Alias.Signature.SHA1/DSA SHA1withDSA
 Alg.Alias.Signature.1.2.840.10040.4.3 SHA1withDSA
 Alg.Alias.Signature.DSS SHA1withDSA
 SecureRandom.SHA1PRNG ImplementedIn Software
 KeyStore.JKS sun.security.provider.JavaKeyStore$JKS
 Alg.Alias.MessageDigest.SHA-1 SHA
 MessageDigest.SHA sun.security.provider.SHA
 KeyStore.CaseExactJKS sun.security.provider.JavaKeyStore$CaseExactJKS
 CertStore.com.sun.security.IndexedCollection ImplementedIn Software
 Alg.Alias.Signature.DSA SHA1withDSA
 KeyFactory.DSA ImplementedIn Software
 KeyStore.JKS ImplementedIn Software
 AlgorithmParameters.DSA ImplementedIn Software
 Signature.NONEwithDSA sun.security.provider.DSA$RawDSA
 Alg.Alias.CertificateFactory.X509 X.509
 CertStore.com.sun.security.IndexedCollection sun.security.provider.certpath.IndexedCollectionCertStore
 Provider.id className sun.security.provider.Sun
 Alg.Alias.Signature.SHA-1/DSA SHA1withDSA
 CertificateFactory.X.509 ImplementedIn Software
 Signature.SHA1withDSA KeySize 1024
 KeyFactory.DSA sun.security.provider.DSAKeyFactory
 CertPathValidator.PKIX ImplementedIn Software
 Configuration.JavaLoginConfig sun.security.provider.ConfigSpiFile
 Alg.Alias.Signature.OID.1.2.840.10040.4.3 SHA1withDSA
 Alg.Alias.KeyFactory.1.2.840.10040.4.1 DSA
 MessageDigest.MD5 ImplementedIn Software
 Alg.Alias.Signature.RawDSA NONEwithDSA
 Provider.id name SUN
 Alg.Alias.AlgorithmParameters.1.2.840.10040.4.1 DSA
 CertPathBuilder.PKIX ValidationAlgorithm RFC3280
 Policy.JavaPolicy sun.security.provider.PolicySpiFile
 Alg.Alias.AlgorithmParameters.1.3.14.3.2.12 DSA
 Alg.Alias.Signature.SHA/DSA SHA1withDSA
 Alg.Alias.KeyPairGenerator.1.3.14.3.2.12 DSA
 MessageDigest.SHA-384 sun.security.provider.SHA5$SHA384
 Signature.SHA1withDSA ImplementedIn Software
 AlgorithmParameterGenerator.DSA sun.security.provider.DSAParameterGenerator
 Signature.NONEwithDSA SupportedKeyClasses java.security.interfaces.DSAPublicKey|java.security.interfaces.DSAPrivateKey
 MessageDigest.SHA-512 sun.security.provider.SHA5$SHA512
 CertPathBuilder.PKIX sun.security.provider.certpath.SunCertPathBuilder
 Alg.Alias.Signature.1.3.14.3.2.27 SHA1withDSA
 CertPathBuilder.PKIX ImplementedIn Software
 Provider.id version 1.6
 AlgorithmParameters.DSA sun.security.provider.DSAParameters
 Signature.SHA1withDSA SupportedKeyClasses java.security.interfaces.DSAPublicKey|java.security.interfaces.DSAPrivateKey
 CertStore.Collection sun.security.provider.certpath.CollectionCertStore
 AlgorithmParameterGenerator.DSA ImplementedIn Software
 KeyPairGenerator.DSA KeySize 1024
 CertStore.LDAP sun.security.provider.certpath.LDAPCertStore
 CertificateFactory.X.509 sun.security.provider.X509Factory
 CertStore.LDAP LDAPSchema RFC2587
 CertStore.LDAP ImplementedIn Software
 KeyPairGenerator.DSA ImplementedIn Software
 CertPathValidator.PKIX ValidationAlgorithm RFC3280
 CertStore.Collection ImplementedIn Software
 Alg.Alias.Signature.1.3.14.3.2.13 SHA1withDSA
 CertPathValidator.PKIX sun.security.provider.certpath.PKIXCertPathValidator
 Alg.Alias.MessageDigest.SHA1 SHA
 AlgorithmParameterGenerator.DSA KeySize 1024
 SecureRandom.SHA1PRNG sun.security.provider.SecureRandom
 Signature.SHA1withDSA sun.security.provider.DSA$SHA1withDSA
 Alg.Alias.KeyFactory.1.3.14.3.2.12 DSA
 KeyPairGenerator.DSA sun.security.provider.DSAKeyPairGenerator
 MessageDigest.SHA ImplementedIn Software
 Provider.id info SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; JavaLoginConfig Configuration)
 Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1 DSA
 Alg.Alias.Signature.SHAwithDSA SHA1withDSA
 MessageDigest.MD5 sun.security.provider.MD5
 Alg.Alias.Signature.DSAWithSHA1 SHA1withDSA
 MessageDigest.SHA-256 sun.security.provider.SHA2
 Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1 DSA
 MessageDigest.MD2 sun.security.provider.MD2
-------------------------------------
-------------------------------------
name: SunRsaSign
info: Sun RSA signature provider
version: 1.5
 Alg.Alias.Signature.OID.1.2.840.113549.1.1.4 MD5withRSA
 Alg.Alias.Signature.OID.1.2.840.113549.1.1.2 MD2withRSA
 Alg.Alias.KeyFactory.1.2.840.113549.1.1 RSA
 Signature.SHA512withRSA SupportedKeyClasses java.security.interfaces.RSAPublicKey|java.security.interfaces.RSAPrivateKey
 Provider.id version 1.5
 Signature.MD5withRSA SupportedKeyClasses java.security.interfaces.RSAPublicKey|java.security.interfaces.RSAPrivateKey
 Alg.Alias.Signature.1.2.840.113549.1.1.13 SHA512withRSA
 KeyPairGenerator.RSA sun.security.rsa.RSAKeyPairGenerator
 Alg.Alias.Signature.1.2.840.113549.1.1.12 SHA384withRSA
 Alg.Alias.Signature.1.2.840.113549.1.1.11 SHA256withRSA
 KeyFactory.RSA sun.security.rsa.RSAKeyFactory
 Alg.Alias.Signature.1.3.14.3.2.29 SHA1withRSA
 Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1 RSA
 Signature.MD2withRSA sun.security.rsa.RSASignature$MD2withRSA
 Signature.SHA384withRSA sun.security.rsa.RSASignature$SHA384withRSA
 Signature.MD5withRSA sun.security.rsa.RSASignature$MD5withRSA
 Provider.id info Sun RSA signature provider
 Signature.SHA1withRSA SupportedKeyClasses java.security.interfaces.RSAPublicKey|java.security.interfaces.RSAPrivateKey
 Signature.SHA1withRSA sun.security.rsa.RSASignature$SHA1withRSA
 Alg.Alias.Signature.1.2.840.113549.1.1.5 SHA1withRSA
 Signature.SHA256withRSA sun.security.rsa.RSASignature$SHA256withRSA
 Alg.Alias.Signature.1.2.840.113549.1.1.4 MD5withRSA
 Provider.id className sun.security.rsa.SunRsaSign
 Alg.Alias.Signature.OID.1.2.840.113549.1.1.13 SHA512withRSA
 Alg.Alias.Signature.OID.1.2.840.113549.1.1.12 SHA384withRSA
 Alg.Alias.Signature.1.2.840.113549.1.1.2 MD2withRSA
 Alg.Alias.Signature.OID.1.2.840.113549.1.1.11 SHA256withRSA
 Signature.MD2withRSA SupportedKeyClasses java.security.interfaces.RSAPublicKey|java.security.interfaces.RSAPrivateKey
 Provider.id name SunRsaSign
 Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1 RSA
 Signature.SHA384withRSA SupportedKeyClasses java.security.interfaces.RSAPublicKey|java.security.interfaces.RSAPrivateKey
 Signature.SHA512withRSA sun.security.rsa.RSASignature$SHA512withRSA
 Signature.SHA256withRSA SupportedKeyClasses java.security.interfaces.RSAPublicKey|java.security.interfaces.RSAPrivateKey
 Alg.Alias.Signature.OID.1.2.840.113549.1.1.5 SHA1withRSA
 Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1 RSA
-------------------------------------
-------------------------------------
name: SunJSSE
info: Sun JSSE provider(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1)
version: 1.6
 Alg.Alias.Signature.OID.1.2.840.113549.1.1.4 MD5withRSA
 Alg.Alias.KeyFactory.1.2.840.113549.1.1 RSA
 Alg.Alias.Signature.OID.1.2.840.113549.1.1.2 MD2withRSA
 SSLContext.Default com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl
 Provider.id version 1.6
 TrustManagerFactory.SunX509 com.sun.net.ssl.internal.ssl.TrustManagerFactoryImpl$SimpleFactory
 KeyManagerFactory.NewSunX509 com.sun.net.ssl.internal.ssl.KeyManagerFactoryImpl$X509
 KeyPairGenerator.RSA sun.security.rsa.RSAKeyPairGenerator
 KeyStore.PKCS12 com.sun.net.ssl.internal.pkcs12.PKCS12KeyStore
 SSLContext.SSLv3 com.sun.net.ssl.internal.ssl.SSLContextImpl
 KeyFactory.RSA sun.security.rsa.RSAKeyFactory
 Alg.Alias.Signature.1.3.14.3.2.29 SHA1withRSA
 Alg.Alias.TrustManagerFactory.X509 PKIX
 Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1 RSA
 Signature.MD5andSHA1withRSA com.sun.net.ssl.internal.ssl.RSASignature
 Signature.MD2withRSA sun.security.rsa.RSASignature$MD2withRSA
 Signature.MD5withRSA sun.security.rsa.RSASignature$MD5withRSA
 Provider.id info Sun JSSE provider(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1)
 Signature.SHA1withRSA sun.security.rsa.RSASignature$SHA1withRSA
 Alg.Alias.Signature.1.2.840.113549.1.1.5 SHA1withRSA
 Alg.Alias.Signature.1.2.840.113549.1.1.4 MD5withRSA
 Provider.id className com.sun.net.ssl.internal.ssl.Provider
 Alg.Alias.Signature.OID.1.3.14.3.2.29 SHA1withRSA
 Alg.Alias.Signature.1.2.840.113549.1.1.2 MD2withRSA
 Provider.id name SunJSSE
 SSLContext.SSL com.sun.net.ssl.internal.ssl.SSLContextImpl
 SSLContext.TLS com.sun.net.ssl.internal.ssl.SSLContextImpl
 TrustManagerFactory.PKIX com.sun.net.ssl.internal.ssl.TrustManagerFactoryImpl$PKIXFactory
 SSLContext.TLSv1 com.sun.net.ssl.internal.ssl.SSLContextImpl
 Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1 RSA
 KeyManagerFactory.SunX509 com.sun.net.ssl.internal.ssl.KeyManagerFactoryImpl$SunX509
 Alg.Alias.TrustManagerFactory.SunPKIX PKIX
 Alg.Alias.TrustManagerFactory.X.509 PKIX
 Alg.Alias.Signature.OID.1.2.840.113549.1.1.5 SHA1withRSA
 Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1 RSA
-------------------------------------
-------------------------------------
name: SunJCE
info: SunJCE Provider (implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, Diffie-Hellman, HMAC)
version: 1.6
 Cipher.Blowfish SupportedKeyFormats RAW
 AlgorithmParameters.DESede com.sun.crypto.provider.DESedeParameters
 AlgorithmParameters.DES com.sun.crypto.provider.DESParameters
 Cipher.DES SupportedPaddings NOPADDING|PKCS5PADDING|ISO10126PADDING
 AlgorithmParameters.Blowfish com.sun.crypto.provider.BlowfishParameters
 Cipher.DESedeWrap SupportedKeyFormats RAW
 Alg.Alias.KeyAgreement.1.2.840.113549.1.3.1 DiffieHellman
 AlgorithmParameterGenerator.DiffieHellman com.sun.crypto.provider.DHParameterGenerator
 Cipher.RSA SupportedPaddings NOPADDING|PKCS1PADDING|OAEPWITHMD5ANDMGF1PADDING|OAEPWITHSHA1ANDMGF1PADDING|OAEPWITHSHA-1ANDMGF1PADDING|OAEPWITHSHA-256ANDMGF1PADDING|OAEPWITHSHA-384ANDMGF1PADDING|OAEPWITHSHA-512ANDMGF1PADDING
 Alg.Alias.Cipher.TripleDES DESede
 Cipher.ARCFOUR SupportedModes ECB
 Mac.SslMacSHA1 SupportedKeyFormats RAW
 KeyGenerator.DES com.sun.crypto.provider.DESKeyGenerator
 Provider.id version 1.6
 KeyGenerator.DESede com.sun.crypto.provider.DESedeKeyGenerator
 Alg.Alias.SecretKeyFactory.PBE PBEWithMD5AndDES
 Alg.Alias.KeyFactory.1.2.840.113549.1.3.1 DiffieHellman
 Mac.HmacSHA1 com.sun.crypto.provider.HmacSHA1
 Cipher.PBEWithMD5AndDES com.sun.crypto.provider.PBEWithMD5AndDESCipher
 Cipher.AES SupportedModes ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128
 Cipher.AESWrap SupportedModes ECB
 SecretKeyFactory.DESede com.sun.crypto.provider.DESedeKeyFactory
 KeyGenerator.SunTlsKeyMaterial com.sun.crypto.provider.TlsKeyMaterialGenerator
 AlgorithmParameters.OAEP com.sun.crypto.provider.OAEPParameters
 Cipher.AES SupportedKeyFormats RAW
 AlgorithmParameters.RC2 com.sun.crypto.provider.RC2Parameters
 AlgorithmParameters.PBE com.sun.crypto.provider.PBEParameters
 Alg.Alias.KeyPairGenerator.DH DiffieHellman
 Alg.Alias.KeyAgreement.OID.1.2.840.113549.1.3.1 DiffieHellman
 Cipher.AES com.sun.crypto.provider.AESCipher
 KeyGenerator.RC2 com.sun.crypto.provider.KeyGeneratorCore$RC2KeyGenerator
 Mac.HmacSHA512 com.sun.crypto.provider.HmacCore$HmacSHA512
 Provider.id info SunJCE Provider (implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, Diffie-Hellman, HMAC)
 Cipher.AES SupportedPaddings NOPADDING|PKCS5PADDING|ISO10126PADDING
 Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.12.1.6 PBEWithSHA1AndRC2_40
 Cipher.Blowfish SupportedPaddings NOPADDING|PKCS5PADDING|ISO10126PADDING
 Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.12.1.3 PBEWithSHA1AndDESede
 KeyStore.JCEKS com.sun.crypto.provider.JceKeyStore
 Cipher.Blowfish SupportedModes ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64
 Alg.Alias.SecretKeyFactory.1.2.840.113549.1.5.12 PBKDF2WithHmacSHA1
 Mac.HmacSHA384 SupportedKeyFormats RAW
 Cipher.DESedeWrap com.sun.crypto.provider.DESedeWrapCipher
 Cipher.ARCFOUR SupportedPaddings NOPADDING
 Alg.Alias.KeyPairGenerator.1.2.840.113549.1.3.1 DiffieHellman
 Cipher.PBEWithMD5AndTripleDES com.sun.crypto.provider.PBEWithMD5AndTripleDESCipher
 Alg.Alias.Cipher.1.2.840.113549.1.12.1.6 PBEWithSHA1AndRC2_40
 Alg.Alias.Cipher.1.2.840.113549.1.12.1.3 PBEWithSHA1AndDESede
 Mac.HmacSHA256 SupportedKeyFormats RAW
 Alg.Alias.AlgorithmParameterGenerator.1.2.840.113549.1.3.1 DiffieHellman
 Cipher.PBEWithSHA1AndDESede com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndDESede
 SecretKeyFactory.PBEWithMD5AndDES com.sun.crypto.provider.PBEKeyFactory$PBEWithMD5AndDES
 KeyPairGenerator.DiffieHellman com.sun.crypto.provider.DHKeyPairGenerator
 Cipher.RC2 SupportedModes ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64
 Alg.Alias.AlgorithmParameters.Rijndael AES
 KeyAgreement.DiffieHellman SupportedKeyClasses javax.crypto.interfaces.DHPublicKey|javax.crypto.interfaces.DHPrivateKey
 Mac.HmacMD5 SupportedKeyFormats RAW
 KeyGenerator.SunTlsRsaPremasterSecret com.sun.crypto.provider.TlsRsaPremasterSecretGenerator
 Cipher.AESWrap SupportedKeyFormats RAW
 SecretKeyFactory.DES com.sun.crypto.provider.DESKeyFactory
 Cipher.AESWrap SupportedPaddings NOPADDING
 Provider.id name SunJCE
 KeyGenerator.HmacSHA512 com.sun.crypto.provider.KeyGeneratorCore$HmacSHA512KG
 Mac.HmacSHA256 com.sun.crypto.provider.HmacCore$HmacSHA256
 Cipher.ARCFOUR SupportedKeyFormats RAW
 Cipher.DES SupportedModes ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64
 Cipher.RSA SupportedKeyClasses java.security.interfaces.RSAPublicKey|java.security.interfaces.RSAPrivateKey
 SecretKeyFactory.PBEWithMD5AndTripleDES com.sun.crypto.provider.PBEKeyFactory$PBEWithMD5AndTripleDES
 Cipher.PBEWithSHA1AndRC2_40 com.sun.crypto.provider.PKCS12PBECipherCore$PBEWithSHA1AndRC2_40
 AlgorithmParameters.DiffieHellman com.sun.crypto.provider.DHParameters
 Mac.HmacMD5 com.sun.crypto.provider.HmacMD5
 Cipher.RSA com.sun.crypto.provider.RSACipher
 Mac.SslMacMD5 com.sun.crypto.provider.SslMacCore$SslMacMD5
 Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.5.3 PBEWithMD5AndDES
 Cipher.DESede SupportedPaddings NOPADDING|PKCS5PADDING|ISO10126PADDING
 Alg.Alias.AlgorithmParameterGenerator.OID.1.2.840.113549.1.3.1 DiffieHellman
 Cipher.DESede com.sun.crypto.provider.DESedeCipher
 Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.3.1 DiffieHellman
 Alg.Alias.AlgorithmParameters.1.2.840.113549.1.5.3 PBEWithMD5AndDES
 Mac.HmacSHA512 SupportedKeyFormats RAW
 Mac.HmacPBESHA1 SupportedKeyFormats RAW
 Alg.Alias.AlgorithmParameterGenerator.DH DiffieHellman
 Cipher.DESedeWrap SupportedPaddings NOPADDING
 Alg.Alias.SecretKeyFactory.OID.1.2.840.113549.1.5.12 PBKDF2WithHmacSHA1
 Alg.Alias.AlgorithmParameters.1.2.840.113549.1.3.1 DiffieHellman
 Mac.HmacPBESHA1 com.sun.crypto.provider.HmacPKCS12PBESHA1
 Cipher.DES SupportedKeyFormats RAW
 AlgorithmParameters.PBEWithMD5AndTripleDES com.sun.crypto.provider.PBEParameters
 Cipher.DESedeWrap SupportedModes CBC
 Alg.Alias.KeyFactory.OID.1.2.840.113549.1.3.1 DiffieHellman
 Alg.Alias.Cipher.OID.1.2.840.113549.1.5.3 PBEWithMD5AndDES
 AlgorithmParameters.AES com.sun.crypto.provider.AESParameters
 Alg.Alias.AlgorithmParameters.TripleDES DESede
 Alg.Alias.SecretKeyFactory.TripleDES DESede
 KeyGenerator.HmacSHA256 com.sun.crypto.provider.KeyGeneratorCore$HmacSHA256KG
 Alg.Alias.KeyGenerator.TripleDES DESede
 Alg.Alias.AlgorithmParameters.DH DiffieHellman
 KeyGenerator.AES com.sun.crypto.provider.AESKeyGenerator
 Cipher.RC2 SupportedPaddings NOPADDING|PKCS5PADDING|ISO10126PADDING
 Alg.Alias.Cipher.RC4 ARCFOUR
 Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.3.1 DiffieHellman
 Mac.HmacSHA384 com.sun.crypto.provider.HmacCore$HmacSHA384
 SecretKeyFactory.PBKDF2WithHmacSHA1 com.sun.crypto.provider.PBKDF2HmacSHA1Factory
 Provider.id className com.sun.crypto.provider.SunJCE
 Cipher.DES com.sun.crypto.provider.DESCipher
 Cipher.Blowfish com.sun.crypto.provider.BlowfishCipher
 KeyGenerator.SunTlsMasterSecret com.sun.crypto.provider.TlsMasterSecretGenerator
 KeyGenerator.HmacSHA1 com.sun.crypto.provider.HmacSHA1KeyGenerator
 Alg.Alias.SecretKeyFactory.1.2.840.113549.1.5.3 PBEWithMD5AndDES
 KeyGenerator.SunTlsPrf com.sun.crypto.provider.TlsPrfGenerator
 SecretKeyFactory.PBEWithSHA1AndDESede com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndDESede
 KeyGenerator.ARCFOUR com.sun.crypto.provider.KeyGeneratorCore$ARCFOURKeyGenerator
 Alg.Alias.KeyAgreement.DH DiffieHellman
 Alg.Alias.KeyGenerator.Rijndael AES
 AlgorithmParameters.PBEWithSHA1AndDESede com.sun.crypto.provider.PBEParameters
 Alg.Alias.KeyGenerator.RC4 ARCFOUR
 Alg.Alias.Cipher.OID.1.2.840.113549.1.12.1.6 PBEWithSHA1AndRC2_40
 Alg.Alias.Cipher.OID.1.2.840.113549.1.12.1.3 PBEWithSHA1AndDESede
 Mac.SslMacMD5 SupportedKeyFormats RAW
 Mac.HmacSHA1 SupportedKeyFormats RAW
 Cipher.DESede SupportedKeyFormats RAW
 Cipher.RC2 com.sun.crypto.provider.RC2Cipher
 SecretKeyFactory.PBEWithSHA1AndRC2_40 com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC2_40
 KeyGenerator.HmacMD5 com.sun.crypto.provider.HmacMD5KeyGenerator
 AlgorithmParameters.PBEWithSHA1AndRC2_40 com.sun.crypto.provider.PBEParameters
 KeyGenerator.HmacSHA384 com.sun.crypto.provider.KeyGeneratorCore$HmacSHA384KG
 Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6 PBEWithSHA1AndRC2_40
 KeyFactory.DiffieHellman com.sun.crypto.provider.DHKeyFactory
 Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.3 PBEWithSHA1AndDESede
 AlgorithmParameters.PBEWithMD5AndDES com.sun.crypto.provider.PBEParameters
 Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.6 PBEWithSHA1AndRC2_40
 Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.3 PBEWithSHA1AndDESede
 Cipher.AESWrap com.sun.crypto.provider.AESWrapCipher
 Alg.Alias.SecretKeyFactory.OID.1.2.840.113549.1.5.3 PBEWithMD5AndDES
 Alg.Alias.Cipher.Rijndael AES
 Cipher.RSA SupportedModes ECB
 Cipher.DESede SupportedModes ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64
 Alg.Alias.SecretKeyFactory.OID.1.2.840.113549.1.12.1.6 PBEWithSHA1AndRC2_40
 Alg.Alias.SecretKeyFactory.OID.1.2.840.113549.1.12.1.3 PBEWithSHA1AndDESede
 Cipher.ARCFOUR com.sun.crypto.provider.ARCFOURCipher
 Alg.Alias.Cipher.1.2.840.113549.1.5.3 PBEWithMD5AndDES
 Mac.SslMacSHA1 com.sun.crypto.provider.SslMacCore$SslMacSHA1
 KeyAgreement.DiffieHellman com.sun.crypto.provider.DHKeyAgreement
 Cipher.RC2 SupportedKeyFormats RAW
 Alg.Alias.KeyFactory.DH DiffieHellman
 KeyGenerator.Blowfish com.sun.crypto.provider.BlowfishKeyGenerator
-------------------------------------
-------------------------------------
name: SunJGSS
info: Sun (Kerberos v5, SPNEGO)
version: 1.0
 GssApiMechanism.1.3.6.1.5.5.2 sun.security.jgss.spnego.SpNegoMechFactory
 Provider.id info Sun (Kerberos v5, SPNEGO)
 Provider.id className sun.security.jgss.SunProvider
 Provider.id version 1.0
 GssApiMechanism.1.2.840.113554.1.2.2 sun.security.jgss.krb5.Krb5MechFactory
 Provider.id name SunJGSS
-------------------------------------
-------------------------------------
name: SunSASL
info: Sun SASL provider(implements client mechanisms for: DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5; server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5)
version: 1.5
 Provider.id className com.sun.security.sasl.Provider
 SaslClientFactory.CRAM-MD5 com.sun.security.sasl.ClientFactoryImpl
 Provider.id version 1.5
 SaslClientFactory.EXTERNAL com.sun.security.sasl.ClientFactoryImpl
 SaslClientFactory.DIGEST-MD5 com.sun.security.sasl.digest.FactoryImpl
 SaslClientFactory.PLAIN com.sun.security.sasl.ClientFactoryImpl
 Provider.id name SunSASL
 SaslClientFactory.GSSAPI com.sun.security.sasl.gsskerb.FactoryImpl
 SaslServerFactory.DIGEST-MD5 com.sun.security.sasl.digest.FactoryImpl
 SaslServerFactory.CRAM-MD5 com.sun.security.sasl.ServerFactoryImpl
 SaslServerFactory.GSSAPI com.sun.security.sasl.gsskerb.FactoryImpl
 Provider.id info Sun SASL provider(implements client mechanisms for: DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5; server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5)
-------------------------------------
-------------------------------------
name: XMLDSig
info: XMLDSig (DOM XMLSignatureFactory; DOM KeyInfoFactory)
version: 1.0
 Alg.Alias.TransformService.XPATH http://www.w3.org/TR/1999/REC-xpath-19991116
 TransformService.http://www.w3.org/TR/1999/REC-xslt-19991116 MechanismType DOM
 Provider.id version 1.0
 Alg.Alias.TransformService.INCLUSIVE http://www.w3.org/TR/2001/REC-xml-c14n-20010315
 TransformService.http://www.w3.org/2000/09/xmldsig#base64 MechanismType DOM
 Alg.Alias.TransformService.EXCLUSIVE http://www.w3.org/2001/10/xml-exc-c14n#
 KeyInfoFactory.DOM org.jcp.xml.dsig.internal.dom.DOMKeyInfoFactory
 TransformService.http://www.w3.org/2001/10/xml-exc-c14n#WithComments org.jcp.xml.dsig.internal.dom.DOMExcC14NMethod
 Alg.Alias.TransformService.INCLUSIVE_WITH_COMMENTS http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments
 TransformService.http://www.w3.org/2002/06/xmldsig-filter2 MechanismType DOM
 TransformService.http://www.w3.org/TR/1999/REC-xpath-19991116 MechanismType DOM
 TransformService.http://www.w3.org/2001/10/xml-exc-c14n# org.jcp.xml.dsig.internal.dom.DOMExcC14NMethod
 XMLSignatureFactory.DOM org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory
 Alg.Alias.TransformService.XPATH2 http://www.w3.org/2002/06/xmldsig-filter2
 TransformService.http://www.w3.org/2001/10/xml-exc-c14n# MechanismType DOM
 TransformService.http://www.w3.org/2001/10/xml-exc-c14n#WithComments MechanismType DOM
 TransformService.http://www.w3.org/TR/1999/REC-xslt-19991116 org.jcp.xml.dsig.internal.dom.DOMXSLTTransform
 TransformService.http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments org.jcp.xml.dsig.internal.dom.DOMCanonicalXMLC14NMethod
 Alg.Alias.TransformService.BASE64 http://www.w3.org/2000/09/xmldsig#base64
 Alg.Alias.TransformService.ENVELOPED http://www.w3.org/2000/09/xmldsig#enveloped-signature
 Provider.id info XMLDSig (DOM XMLSignatureFactory; DOM KeyInfoFactory)
 TransformService.http://www.w3.org/TR/2001/REC-xml-c14n-20010315 org.jcp.xml.dsig.internal.dom.DOMCanonicalXMLC14NMethod
 Provider.id className org.jcp.xml.dsig.internal.dom.XMLDSigRI
 Alg.Alias.TransformService.EXCLUSIVE_WITH_COMMENTS http://www.w3.org/2001/10/xml-exc-c14n#WithComments
 TransformService.http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments MechanismType DOM
 TransformService.http://www.w3.org/2002/06/xmldsig-filter2 org.jcp.xml.dsig.internal.dom.DOMXPathFilter2Transform
 TransformService.http://www.w3.org/2000/09/xmldsig#enveloped-signature org.jcp.xml.dsig.internal.dom.DOMEnvelopedTransform
 Provider.id name XMLDSig
 TransformService.http://www.w3.org/2000/09/xmldsig#base64 org.jcp.xml.dsig.internal.dom.DOMBase64Transform
 TransformService.http://www.w3.org/TR/1999/REC-xpath-19991116 org.jcp.xml.dsig.internal.dom.DOMXPathTransform
 TransformService.http://www.w3.org/TR/2001/REC-xml-c14n-20010315 MechanismType DOM
 Alg.Alias.TransformService.XSLT http://www.w3.org/TR/1999/REC-xslt-19991116
 TransformService.http://www.w3.org/2000/09/xmldsig#enveloped-signature MechanismType DOM
-------------------------------------
-------------------------------------
name: SunPCSC
info: Sun PC/SC provider
version: 1.6
 Provider.id info Sun PC/SC provider
 Provider.id className sun.security.smartcardio.SunPCSC
 Provider.id version 1.6
 Provider.id name SunPCSC
 TerminalFactory.PC/SC sun.security.smartcardio.SunPCSC$Factory
-------------------------------------
-------------------------------------
name: SunMSCAPI
info: Sun's Microsoft Crypto API provider
version: 1.6
 SecureRandom.Windows-PRNG sun.security.mscapi.PRNG
 Provider.id version 1.6
 Cipher.RSA/ECB/PKCS1Padding sun.security.mscapi.RSACipher
 Signature.MD5withRSA SupportedKeyClasses sun.security.mscapi.Key
 KeyPairGenerator.RSA sun.security.mscapi.RSAKeyPairGenerator
 KeyStore.Windows-ROOT sun.security.mscapi.KeyStore$ROOT
 Signature.NONEwithRSA SupportedKeyClasses sun.security.mscapi.Key
 Cipher.RSA SupportedKeyClasses sun.security.mscapi.Key
 Signature.MD2withRSA sun.security.mscapi.RSASignature$MD2
 Signature.MD5withRSA sun.security.mscapi.RSASignature$MD5
 Cipher.RSA SupportedModes ECB
 Provider.id info Sun's Microsoft Crypto API provider
 Signature.SHA1withRSA SupportedKeyClasses sun.security.mscapi.Key
 Signature.SHA1withRSA sun.security.mscapi.RSASignature$SHA1
 Provider.id className sun.security.mscapi.SunMSCAPI
 KeyPairGenerator.RSA KeySize 1024
 Signature.MD2withRSA SupportedKeyClasses sun.security.mscapi.Key
 Provider.id name SunMSCAPI
 Cipher.RSA SupportedPaddings PKCS1PADDING
 Cipher.RSA sun.security.mscapi.RSACipher
 KeyStore.Windows-MY sun.security.mscapi.KeyStore$MY
-------------------------------------




이렇게 많ㅇ이 사용될 수 있는 알고리즘 구현방식이 있다.



아래 URL의 샘플 코드를 봐보자.

http://java.sun.com/developer/technicalArticles/Security/AES/AES_v1.html



    import java.security.*;
   import javax.crypto.*;
   import javax.crypto.spec.*;
   import java.io.*;

   /**
   * This program generates a AES key, retrieves its raw bytes, and
   * then reinstantiates a AES key from the key bytes.
   * The reinstantiated key is used to initialize a AES cipher for
   * encryption and decryption.
   */

   public class AES {

     /**
     * Turns array of bytes into string
     *
     * @param buf Array of bytes to convert to hex string
     * @return Generated hex string
     */
     public static String asHex (byte buf[]) {
      StringBuffer strbuf = new StringBuffer(buf.length * 2);
      int i;

      for (i = 0; i < buf.length; i++) {
       if (((int) buf[i] & 0xff) < 0x10)
    strbuf.append("0");

       strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
      }

      return strbuf.toString();
     }

     public static void main(String[] args) throws Exception {

       String message="This is just an example";

       // Get the KeyGenerator

       KeyGenerator kgen = KeyGenerator.getInstance("AES");
       kgen.init(128); // 192 and 256 bits may not be available


       // Generate the secret key specs.
       SecretKey skey = kgen.generateKey();
       byte[] raw = skey.getEncoded();

       SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");


       // Instantiate the cipher

       Cipher cipher = Cipher.getInstance("AES");

       cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

       byte[] encrypted =
         cipher.doFinal((args.length == 0 ?
          "This is just an example" : args[0]).getBytes());
       System.out.println("encrypted string: " + asHex(encrypted));

       cipher.init(Cipher.DECRYPT_MODE, skeySpec);
       byte[] original =
         cipher.doFinal(encrypted);
       String originalString = new String(original);
       System.out.println("Original string: " +
         originalString + " " + asHex(original));
     }
   }

Posted by 1010
01.JAVA/Java2008. 8. 20. 11:46
반응형
서버에 소스를 이전시켰다.

Window 2000 서버 ==> IBM AIX 서버(유닉스)

코드 폴더 통째로 바꿨다!! 그런데..!!!

잘 돌아가던 소스가 실행이 안되는 거다!!!

다음과 같은 에러가...!!!@@

org.apache.jasper.JasperException: Unable to compile class for JSP
Generated servlet error:
/home/lsms/WEB-INF/work/org/apache/jsp/main_jsp.java:1033: handlePageException(java.lang.Exception) in javax.servlet.jsp.PageContext cannot be applied to (java.lang.Throwable)
(source unavailable)
1 error

at org.apache.jasper.compiler.DefaultErrorHandler.javacError(DefaultErrorHandler.java:84)
at org.apache.jasper.compiler.ErrorDispatcher.javacError(ErrorDispatcher.java:332)
at org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:412)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:472)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:451)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:439)
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:511)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:295)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:300)
at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:374)
at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:743)
at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:675)
at org.apache.jk.common.SocketConnection.runIt(ChannelSocket.java:866)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
at java.lang.Thread.run(Thread.java:568)


이런 에러가 뜨면서..뜨아..

아무리 찾아봐도 안되는거다. 그 좋다는 지식검색마저도...

결국 해결봤다.

어떻게??~~ ==> 소스 폴더 안에 WEB-INF 라는 놈도 같이 다 카피가 됐었는데. 그놈은 서버마다 다른거 같다.

따라서 WEB-INF 라는 폴더를 통째로 삭제시켜주자!!!!

그럼 이런 에러 없이 전혀 문제없이 잘 돌아간다. 6시간 뺑이친 결과물이다. ㅡㅡ;


출처 : http://sweetjini.egloos.com/2477988
Posted by 1010
01.JAVA/Java2008. 8. 20. 11:32
반응형
-->(세부출처 : http://www.dbtool.co.kr/)

Java Error Message 정리 자료입니다.


1. ERROR Exception in thread "main" java.lang.NoClassDefFoundError: 파일명
발생되는 경우 클래스 파일을 찾을 수 없는 경우
조 언 실행하려는 클래스 파일 이름이 제대로 되어 있는지 확인한다.
또한, CLASSPATH 설정이 제대로 되어 있는지 확인하며 (도스모드에서 set명령어)
만약, 되어있지 않다면 설정한다. (CLASSPATH = jdk1.3/jre/lib/rt.jar; 2-1강좌 참조)
 
2. ERROR cannot resolve symbol
symbol : class in(에러가 난 부분)
location : class StackTest(찾으려는 위치)  
발생되는 경우 이해할 수 없는 클래스나 메소드, 변수명이 올경우
조 언 보통 이 에러는 철자가 틀렸을 경우에 많이 발생한다. 클래스, 메소드, 변수의 철자를 세심히 확인해 본다.
특히, 철자를 확인할때 대소문자 구분을 확실히 체크한다.(자바는 대소문자를 구별한다.) 그리고 클래스에서 발생할 경우 import를 해주었는지 확인해 봅니다.
 
3. ERROR non-static variable 변수이름(or method 메소드이름) cannot br referenced from a static context
발생되는 경우 static 메소드 안에서 static 으로 선언되지 않은 메소드나 변수를 참조(사용)했을 경우.
특히, 메소드의 경우는 인스턴스를 사용하지 않고 static메소드 내에서 바로 선언한 경우.
조 언 static 선언자의 사용여부를 살펴보고 static 메소드 안에 static으로 선언되어지지 않은 메소드나 변수가 있느지 확인해본다.
만약 그런것이 있으면 메소드를 새로 만들어 그쪽에서 선언한다. 단, 인스턴스를 생성해서 불러줘야 한다는 것을 잊지 말아야한다.
 
4. ERROR valiable 변수명 might not have been initialized
발생되는 경우 지역변수인 변수명의 변수가 초기화가 되어있지 않았을 경우
조 언 지역변수(메소드 내에서 선언한 변수)를 초기화 하지 않은채 선언했을 경우 발생한다.
멤버 필드가 아닌 경우는 반드시 변수 선언시 초기화를 해주어야 한다.
(멤버 필드는 자바 프로그램 자체에서 자동으로 default값으로 초기화 해준다.)
 
5. ERROR class 클래스명 is public, should be declared in a file named 클래스명.java
발생되는 경우 클래스명이 public으로 선언되었는데 파일명과 다를 경우
조 언 public으로 선언된 클래스가 있다면 반드시 그 클래스명과 파일명이 같아야 한다.
클래스명과 파일명의 대소문자 및 철자가 같은지 비교해 본다.
또한, public으로 선언된 클래스가 하나 이상 있는지 찾아본다.(반드시 하나만 있어야한다.)
 
6. ERROR push(java.lang.object)[메소드(인자로 받을 수 있는 형)] in java.util.Stack(메소드의 클래스) cannot be applied to (int)[잘못 들어간 형]
발생되는 경우 메소드에서 인자를 받을 때 받을 수 있는 형이 아닌 자료형 또는 클래스형을 사용할 경우
조 언 사용하는 메소드의 API를 참고하여 어떤 형을 인자로 받을 수 있는지 찾아본다.
API를 보지 못할 경우는 각 자료형으로 인자를 직접 바꾸어 본다.
 
7. ERROR java.lang.NoSuchMethodError: main
Exception in thread "main"
발생되는 경우 클래스 파일 안에서 main() 메소드를 찾을 수 없는 경우
조 언 자바 애플릿이 아닌 이상 자바 애플리케이션은 반드시 main() 메소드를 사용해야 합니다.
main() 메소드를 빼먹지 않았는지 확인해 보십시요. 또한 public static void main(String[] args) 형식으로 씌어졌는지도 확인해 보십시요.
(main 클래스는 반드시 위와 같은 형식으로 만들어져야 합니다.)
 
8. ERROR unreported exception java.io.IOException(Exception명); must be caught or declared to be thrown
발생되는 경우 예외가 발생하는데 예외처리를 해주지 않았을 경우
조 언 예외를 발생하는 메소드 같은 경우는 반드시 예외처리를 해주어야 합니다.
예외를 발생하거나 예외처리를 해야하는 메소드는 API를 확인해 보시면 알 수 있습니다.
그렇지 않다면 컴파일 후 지금처럼 에러가 난 예외를 예외처리해 주시면 됩니다.
또한, 예외를 처리할 때는 메소드 차원에서 throws 예외명을 이용해서 처리할 수 있고
try{} catch{} 구문을 이용해서 직접 처리해 주셔도 됩니다.(예외 강좌를 참고하세요.)
특히, 예외도 클래스이므로 반드시 예외가 들어간 패키지를 import 해주어야 합니다.
 
9. ERROR Note : Calculator.java(파일명) uses or overrides a deprecated API.
Note : Recompile with -deprecation for details.  
발생되는 경우 JDK 버전이 높아졌거나 보안등의 기타이유로 사용이 deprecated된 메소드를 사용한 경우
조 언 이건 예외라기 보다는 경고 입니다.(실행하면 됩니다.^^)
JDK가 버전이 높아지거나 보안등의 이유에 따라 예전에 만들어졌지만 필요가 없어지거나 대체된 메소드가 생겨났습니다.
그런 메소드를 deprecated 되었다고 하는데 이것은 API상에 나왔있습니다.
또한, 컴파일할때 -deprecation 옵션주면 어떤 메소드가 deprecate됐는지 알수있읍니다.
사용이 중지 됐다고 보기 보다는 사용을 가능하면 하지 않게끔 해주는 거죠.
대치되었거나 버전 업된 메소드를 사용하시면 됩니다.

 
10. ERROR MouseEvent(클래스명) should be declared abstract; it does not define mouseDragged(java.awt.event.MouseEvent)[메소드명(메소드가 포함된 클래스)] in MouseEvent(클래스명)  
발생되는 경우 implements한 Interface의 모든 메소드를 구현하지 않아서 발생됨  
조 언 Interface는 모든 메소드가 선언만 되고 구현되지 않은 추상(abstract) 메소드입니다.
만약 Interface를 implements하려면 implements한 클래스가 Interface에서 선언한 모든 메소드를 구현해 주어야 합니다.
하나라도 빠질 경우 implements한 클래스도 추상 클래스로 보고 에러가 발생합니다.
에러에 구현해 주어야할 메소드명이 나오므로 그곳에 쓰여있는 메소드를 구현해 주면 됩니다.
만약, 그 메소드를 구현해 주었는데 에러가 나면 철자 및 대소문자를 다시 확인해 보십시요.
 
11. ERROR incompatible types
found : /null(입력한 자료형)
required : int(요구하는 자료형)
발생되는 경우 입력을 했을때 맞지 않는 자료형이나 클래스형을 입력할 경우
조 언 incompatible 은 '성미가 맞지 않는','모순된' 이라는 뜻을 가진 단어 입니다.
단어뜻 처럼 입력 경우 required 에 나타난 자료형 및 클래스형을 요구하는데
found 에서 나타난 자료형 및 클래스형을 써주어서 입력을 하지 못하게 되어서 발생하는 에러입니다.
found 에 나타난 자료형을 required 에 나타난 자료형으로 변경해 주시면 됩니다.

 
12. ERROR package java.servlet(패키지명) does not exist
발생되는 경우 import한 패키지가 존재하지 않을 경우
조 언 import한 패키지가 존재하지 않을 경우에 발생하는 에러입니다.
철자와 대소문자를 먼저 확인하고 CLASSPATH 설정을 확인해 보시기 바랍니다.
또한 그 곳에 패키지가 jar파일로 있는지도 확인해 보셔야 합니다.
(API에 나와있는 패키지는 rt.jar에 다 있습니다.
단 javax가 붙거나 다름으로 시작되는 확장 패키지는 설치해 주어야합니다.(javax.swing 제외))  
 
13. ERROR java.lang.NullPointerException
Exception in thread "main"(메소드) java.lang.NullPointerException
at java.awt.Container.addImpl(Container.java:341)... [에러가 일어난 부분]
발생되는 경우 참조하거나 사용한 클래스 또는 자료형이 초기화 되지 않은 경우
조 언 보통 이것은 awt나 배열 부분에서 자주 발생하는데 초기화를 해주지 않아서 많이 발생합니다.
자바의 변수들은 기본적으로(자동으로 초기화 되는 멤버필드등을 제외하고) 초기화를 요구합니다.
에러에 체크된 부분을 검토해 보시고 초기화를 해주십시요.  
 
14. ERROR ';'(빠진 부분) expected
발생되는 경우 문법상으로 써야할 것을 쓰지 않은 경우 발생합니다.
조 언 주로 ';'을 안써주시거나 아님 '()'(괄호)를 열기만 하고 닫지 않은 실수를 할 경우 발생합니다.
대부분 이 에러가 발생한 경우는 에러에 나온것을 소스에 추가해 주시면 됩니다.
 
15. ERROR unexpected type
required : value(요구하는 타입)
found : class(소스상 써준 타입)

발생되는 경우 써주어야 할 타입이 아닌 잘못된 타입을 써주었을 경우
조 언 unexpected type 에러를 해석하면 '기대하지 않은 타입'이란 뜻을 가지고 있습니다.
즉, 원하는 타입(required)이 아닌데 잘못된 타입(found)을 써준 경우 발생합니다.
에러 체크된 부분의 타입을 required 에서 나타난 타입으로 변경해 주시면 됩니다.

 
16. ERROR java.lang.ArrayIndexOutOfBoundsException
at Test.main(Test.java:10)[클래스.메소드(파일명:에러난 위치)]
Exception in thread "main"(예외가 던져진 메소드)

발생되는 경우 배열의 범위를 넘어선 값을 넣었을 경우
조 언 위의 에러는 특이하게 컴파일은 이상없이 되지만 실행을 하면 발생하는 에러입니다.
배열의 범위를 넘어설 경우에 발생하므로 에러난 위치의 배열의 참조 범위를 확인해보시고
선언해둔 배열의 범위에 맞게 조정해 주시면 됩니다.  
 
17. ERROR illegal start of expression
발생되는 경우 선언자(modifier)를 잘못 집어 넣은 경우
조 언 에러의 단어뜻을 확인해 보면 '표현의 시작이 부적격 합니다.'하고 해석할 수 있습니다.
보통 선언자가 맞지 않거나 쓰일데가 아닌데 선언자를 줄 경우에 많이 발생합니다.
특히 메소드안에서 static 선언자를 쓴 경우에는 직격으로 볼수 있죠.
에러가 난 부분의 선언자를 제거하거나 맞는 것인지 다시 확인해 보십시요.  
 
18. ERROR java.io.InputStream(클래스) is abstract; cannot be instantiated
발생되는 경우 abstract로 선언된 클래스를 직접 new 명령어를 이용하여 인스턴스화 할 경우
조 언 abstract로 선언된 클래스를 직접 new 명령어를 이용하여 인스턴스화 할 경우에 발생하는 에러입니다.
왜냐하면, 추상 클래스는 직접 new 명령어를 이용하여 인스턴스화 할수 없기 때문입니다.(객체를 못만든다구요.)
이 경우에는 인스턴스를 다른 방법으로 생성하시면 됩니다.
예를 들어 인스턴스를 반환하는 메소드를 이용한다거나 상속을 통해서 상속받은 클래스의 인스턴스를 만들어
직접 인스턴스를 만드는 효과를 낼수도 있구요. 원하시는 방법으로 바꾸어 보시길...  
 
19. ERROR local variable name(변수명) is accessed from within inner class; needs to be declared final
발생되는 경우 Local Class의 변수를 final로 선언하지 않은 경우
조 언 Local Class의 변수는 참조변수의 참조값 변동을 방지하기 위하여 final 선언자를 붙여주어야 합니다.
변수에 final 선언자를 붙이면 변수는 값을 변동할 수 없는 상수 처럼 쓰이며
만약 이 값을 참조할 경우 자바는 이 값을 넘기는게 아니라 이 값의 복사본을 참조 값으로 넘기게 됩니다.
그러므로 Local Class에서 참조값 변동없이 변수를 참조할 수 있게 되는 것입니다.
Local Class를 정의해준 곳을 살펴보고 final 선언자를 확실하게 확인하시기 바랍니다.  
 
20. ERROR inner classes cannot have static declarations
발생되는 경우 내부 클래스 안에서 static 선언자를 쓴 경우
조 언 내부 클래스 안에서는 static 선언자를 쓸수 없습니다.
내부 클래스 안에서 사용된 static 선언자를 제거해 주십시요.  
 
21. ERROR referenceto List is ambiguous,both class java.util.List(클래스) in java.util(패키지)
and class java.awt.List(클래스) in java.awt(패키지) match  
발생되는 경우 클래스 사용시 다른 패키지내에 동일이름의 클래스들이 있어서 참조가 모호할 경우
조 언 예시를 보면 아시겠지만 import 한 패키지중에 같은 이름을 사용하는 클래스를 클래스 이름만으로
생성함으로서 참조가 모호해질 경우 발생하는 에러입니다.
이와 같은 경우는 import를 하나 제거 하거나 아님 java.util.List 이런식으로
직접 그 클래스의 패키지를 같이 써줌으로서 모호성을 제거할수 있습니다.

 
22. ERROR m()(메소드명) in B(클래스명) cannot override m()(메소드명) in A(클래스명);
attempting to use incompatiable return type  
발생되는 경우 클래스를 상속받고서 메소드를 오버라이드 하고자할때 잘못한 경우
조 언 클래스를 상속받고서 메소드를 오버라이드 할 경우에는 지켜야 하는 규칙이 있습니다.
1. 메소드의 이름이 같아야 합니다.
2. 메소드의 파라미터 개수, 데이터형이 같아야 합니다.
3. 메소드의 리턴형이 같아야 합니다.
4. 상위 메소드와 동일하거나 더 구체적인 Exception을 발생시켜야 합니다.
5. 상위 메소드와 동일하거나 접근범위가 더 넣은 접근 제한자를 사용해야 합니다.

님의 메소드 오버라이드시 위 규칙을 잘 지켰는가를 다시 한번 확인해 보세요.

 
23. ERROR getPathBetweenRows(int,int)(메소드) has protected access in javax.swing.jTree(클래스)
발생되는 경우 protected로 선언된 메소드를 상속 없이 직접 불러쓸 경우
조 언 protected로 선언되어 있는 메소드는 상속하거나 같은 package에 있을 때만 쓸 수 있습니다.
상속해서 다시 public 메소드로 값을 받던지 아니면
public 메소드 중에서 비슷한 기능을 하는 메소드가 있는지 찾아서 바꾸어주어야 합니다.  
 
24. ERROR invalid method declaration; return type required
발생되는 경우 리턴 타입을 쓰지 않아 메소드의 선언이 잘못된 경우
조 언 리턴 타입을 쓰지 않아 메소드의 선언이 잘못된 경우에 발생하는 에러이므로
에러가 발생한 메소드를 확인해보고 리턴 타입을 맞게 적어주어야 합니다.  
 
25. ERROR Error occurred during initialization of VM
java.lang.ExceptionInInitializerError
발생되는 경우 static으로 선언된 변수중 초기화가 안되어 있는 것이 있는 경우
조 언 static으로 선언된 변수중에 초기화가 안된게 있는 경우에 발생하는 에러이므로
에러가 발생한 변수를 확인해보고 알맞은 초기화를 시켜주거나 변수의 위치를
자동 초기화가 가능한 메소드 밖의 클래스 변수로서 사용하게 합니다.  
 
26. ERROR Error opening registry key 'Software\JavaSoft\Java Runtime Environment'
Error: could not find java.dll
Error: could not find Java 2 Runtime Environment
발생되는 경우 중복설치 등으로 인해 레지스트리 키값이 잘못되어 있는 경우
조 언 중복설치 등으로 인해 레지스트리 키값이 잘못되어 있는 경우에 발생하는 에러이므로
레지스트리 편집기를 열어서 HKEY_LOCAL_MACHINE -> SOFTWARE -> JavaSoft에
보시면 3개의 키가 있을 겁니다. 그중에서 첫번째 키인 Java 런타임 환경 을 마우스
오른쪽 버튼으로 클릭하여 Java Runtime Environment로 이름을 바꿔주시면 됩니다.

 
27. ERROR Error Registry Key 'Sofrware\JavaSofrware\Java Runtime Environment\CurrentVerison'
has value '1.1',but '1.3' is requried.
Error: could not find java.dll
Error: could not find java 2 Runtime Enviroment.  
발생되는 경우 중복설치 등으로 인해 레지스트리 키값의 자바 버전이 잘못되어 있는 경우
조 언 중복설치 등으로 인해 레지스트리 키값의 자바 버전이 잘못되어 있는 경우에 발생하는 에러이므로
레지스트리 편집기를 열어서 HKEY_LOCAL_MACHINE -> SOFTWARE -> JavaSoft -> Java Runtime Environment의 Current version의 값을 1.3으로 되어있는지 확인해 주시면 됩니다.

 
28. ERROR java.lang.ClassNotFoundException: org.gjt.mm.mysql.Driver(드라이버명)  
발생되는 경우 JDBC로 데이터 베이스에 연결하는 중 드라이버를 찾지 못할 경우
조 언 JDBC를 연결하는 중에 드라이버를 찾지 못할 경우에 발생하는 에러이므로
각 데이터 베이스에 맞는 드라이버가 제대로 다운로드 되었는지 확인해 보시고
드라이버의 위치가 클래스 패스에 잡혀 있는지 확인해주시면 됩니다.  
 
29. ERROR Method printIn(java.lang.String)(메소드명) not found in class java.io.PrintStream(클래스명)  
발생되는 경우 자신이 사용한 클래스의 메소드가 맞지 않는(=없는)경우
조 언 자신이 사용한 클래스의 메소드가 맞지 않는(=없는) 경우에 발생하는 에러이므로
API를 통해서 사용하고자 하는 클래스와 메소드를 다시 한번 확인해 봅니다.
보통 이경우 메소드의 철자나 대소문자를 잘못 쓴 경우가 많으니 그점을 유심히 살표봅니다.
마지막으로 철자와 대소문자도 맞는다면 메소드의 인자의 객체형을 맞게 주었는지 확인해보면 됩니다.

Posted by 1010
01.JAVA/Java2008. 8. 19. 16:52
반응형

규칙1: properties 파일은 Text 파일이며, 다음과 같은 형태의 이름들을 가질 수 있습니다.

MyResource_ko_KR_IBMeucKR.properties
MyResource_ko_KR.properties
MyResource_ko.properties
MyResource_en_US.properties
MyResource_en.properties
MyResource.properties


baseclass "_" language1 "_" country1 "_" variant1
baseclass "_" language1 "_" country1
baseclass "_" language1
baseclass

즉, 자동으로 JVM의 Locale 정보를 찾아서 위 순서대로 프로퍼티 파일을 순차적으로 찾아
나갑니다.

Locale 옵션을 주지 않으면, Locale.getDefault()를 사용하게 됩니다.
System.out.println(Locale.getDefault()) 해 보시면 확인이 가능하며, 이 값은
"file.encoding" 이라는 System Property 값에 의해 영향을 받으며, 이것은 다시
환경변수 "LANG" 값에 영향을 받습니다.

이 기능을 이용하여, Locale 값이 무엇이냐에 따라 서로 다른 문자열을 프로그램내에서
제공할 수 있게 되는 것이지요...
즉, 아래와 같은 서로 다른 이름의 resource 파일을 두게 되면, 영어와 한글 문자열을
Locale 값에 따라 서로 다르게 제공할 수 있는 것이지요.

MyResource_ko.properties
MyResource_en.properties
MyResource.properties <--- 이도저도 아닐 때 사용되는 defualt



규칙2: 위의 해당 properties 파일은 classpath 에 잡혀 있는 곳에 있어야 하며,
만약, package 로 구분된 sub directory 에 두었다면, 반드시 full path 를 주어야
합니다.


ResourceBundle resource =
    ResourceBundle.getBundle("org.jsn.somewhere.MyResource")

그리고, MyResource_??_??.properties 파일들(!)은 org/jsn/somewhere/ 하부 디렉토리에
놓여 있어야 합니다.

해당 properties 파일들은 jar 파일내에 함께 묶어 두어도 됩니다.


규칙3: properties 파일들은 다음과 같은 포멧으로 구성되어 있습니다.
----------------------------------------------------------------------
# 1. key = value_string 으로 기술된다.
# 2. Comment 는 '#'으로 시작되면 되나, 문자열 중간에 있는 '#'기호는 Comment로
#    인식하지 않는다.
# 3. '=' 대신 ' '(공백)을 사용해도 된다.
#    (즉 첫번째 나오는 공백이 key와 vlaue string를 나누는 구실도 한다.
# 4. 3번의 이유로 인하여 key에는 중간에 공백이 허용되지 않는다.
# 5. 반면, value string에는 공백이 허용된다.
# 6. value string를 사용할 때 한글이 지원된다. 그러나 key는 한글지원이 안된다.
# 7. 두 줄 이상을 사용하려면 라인의 끝에 '\' 문자를 사용하면 된다.
#    '\'문자 자체가 필요할 땐 '\' 대신 '\\'을 사용하라.
# 8. 7번의 이유로 인하여 Windows 환경에서 디렉토리 구분은 '\'가 아니라 '\\' 이다.
key = value
name = 이원영
.....
----------------------------------------------------------------------




규칙4: 한글은 8859_1 캐릭터 셋으로만 읽혀 집니다. 따라서, JVM의 인코딩이 8859_1 이
아니라면, 다음처럼 변환하여야 합니다. file.encoding 이 "KSC5601" 이라면,


ResourceBundle resource = ResourceBundle.getBundle("resource.MyResource");
System.out.println(Locale.getDefault());
System.out.println(resource.getString("name"));
System.out.println(new String(resource.getString("name").getBytes("8859_1"),"KSC5601"));

내부적으로 ClassLoader.getResourceAsStream(filename); 의 형태로 읽혀 들이기
때문입니다.

보다 자세한 사항은 해당 클래스의 API 문서와 JDK 소스를 직접 읽어 보시길 바랍니다.
가장 빨리/정확히/깊이있게 공부하는 지름길입니다.


------------------------------------------------------- 
  본 문서는 자유롭게 배포/복사 할 수 있으나 반드시
  이 문서의 저자에 대한 언급을 삭제하시면 안됩니다
================================================
  자바서비스넷 이원영
  E-mail: javaservice@hanmail.net
  PCS:011-898-7904
================================================


출처 : http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=javatip&c=r_p&n=993541416&p=13&s=t

Posted by 1010
01.JAVA/Java2008. 8. 19. 16:50
반응형

File이 어떤 포맷인지 알아보자


public String getFileType (File file) {
        InputStream inputStream = null;
        byte[] buf = new byte[132];
        try {
            inputStream = new FileInputStream(file);
            inputStream.read(buf, 0, 132);
        } catch (IOException ioexception) {
            return "UNKNOWN";
        } finally {
            if (inputStream != null) try { inputStream.close(); } catch (Exception exception) {}
        }
       
        int b0 = buf[0] & 255;
        int b1 = buf[1] & 255;
        int b2 = buf[2] & 255;
        int b3 = buf[3] & 255;
       
        if (buf[128] == 68 && buf[129] == 73 && buf[130] == 67 && buf[131] == 77
            && ((b0 == 73 && b1 == 73) || (b0 == 77 && b1 == 77)))
            return "TIFF_AND_DICOM";
       
        if (b0 == 73 && b1 == 73 && b2 == 42 && b3 == 0)
            return "TIFF";
       
        if (b0 == 77 && b1 == 77 && b2 == 0 && b3 == 42)
            return "TIFF";
       
        if (b0 == 255 && b1 == 216 && b2 == 255)
            return "JPEG";
       
        if (b0 == 71 && b1 == 73 && b2 == 70 && b3 == 56)
            return "GIF";
       
        if (buf[128] == 68 && buf[129] == 73 && buf[130] == 67 && buf[131] == 77)
            return "DICOM";
       
        if (b0 == 8 && b1 == 0 && b3 == 0)
            return "DICOM";
       
        if (b0 == 83 && b1 == 73 && b2 == 77 && b3 == 80)
            return "FITS";
       
        if (b0 == 80 && (b1 == 50 || b1 == 53) && (b2 == 10 || b2 == 13 || b2 == 32 || b2 == 9))
            return "PGM";
       
        if ( b0 == 66 && b1 == 77)
            return "BMP";
       
        if (b0 == 73 && b1 == 111)
            return "ROI";
       
        if (b0 >= 32 && b0 <= 126 && b1 >= 32 && b1 <= 126 && b2 >= 32 && b2 <= 126
                     && b3 >= 32 && b3 <= 126 && buf[8] >= 32 && buf[8] <= 126)
            return "TEXT";
       
        if (b0 == 137 && b1 == 80 && b2 == 78 && b3 == 71)
            return "PNG";
       
        return "UNKNOWN";
}


Posted by 1010