아.. 이 게임 무지 땡기네.. :: Bio Shock

바이오 쇼크

각종 게임 매거진에서 극찬을 하고 있는 바이오쇼크.
FPS게임을 마지막으로 즐기고 수년은 흘렀는데.. 요즘 Bio Shock 가 무지 땡긴다.  어두운 분위기 하며 탄탄한 스토리까지..
딱 내 스타일이긴 하지만 내 PC로 이 게임 플레이가 가능 할까 생각 해보면 완전 암울 모드..
아.. 업그레이드(라고 쓰고 새 PC 구매라고 읽는다.) 해야 하나..


DVDprime 잔상_현영님이 자막입힌 오프닝 동영상

Who's your daddy?에서 대디란 일단 표면적으로는 표지의 저 육중한 잠수복을 입은 생명체로
생각되지만 게임을 해보면 알 수 있는 이중적 의미가 있을겁니다. 루리웹에 올라온 정보에 의하면

Gatherer (Little Sisters) :
개발초기에는 유전적으로 변형된 달팽이처럼 생긴 바다생물로 묘사되었으나,
현재는 유전적으로 변형된 아이의 모습을 하고 있다.
Little Sister (아래 LS)들은 아담부족을 해결하기 위해 테네바움(Tenebaum) 박사에
의해 만들어진 존재들로서, 시체 - LS들은 'angel'이라고 부름 - 에서 비활성 아담을
체취하여 섭취한 후 그것을 사용가능한 형태로 재처리할 수 있는 능력을 갖고 있다.
게임의 개발팀은 LS의 존재를 통해, 아담이라는 필수적인 물질을 얻기 위해 어린 소녀
를 죽일 것인가라는 윤리적 결정을 플레이어에게 강요한다.
물론 LS들을 죽이는 것조차도 LS와 공생관계에 있는 Protectors(Big Daddy)로 인해 쉬
운 일은 아니다. 게임 수석 디자이너 Ken Levine에 따르면, 플레이어가 LS에게 직접적
으로 물리적인 위해를 가할 수는 없지만 아담을 체취하는데 그들을 사용할 수 있고 이
것은 곧 LS가 죽는다는 것을 뜻한다고 말했다. 그는 또한 이 장면이 오디오를 통해서
만 표현될 것이며 검은 화면으로 처리 될 것이라고 밝혔다.

(페이블 베드신 생각하면 될 듯)

Protectors (Big Daddies, Mr. Bubbles, Mr. B) :
LS들을 보호하기 위해 만들어진, 말못하고 육중한 괴물같은 존재.
잠수복처럼 생긴 육중한 아머를 착용하고 대형드릴같은 고성능 무기로 무장하고 있어
대부분의 스플라이서들은 가까이 접근하지 못한다.
수석 디자이너인 Paul Hellquist는, 플레이어가 자극하지 않는 한 Big Daddy가 먼저
공격을 하지는 않지만 "한 번 붙어보면 왜 아무도 Big Daddy와 붙으려하지 않는지 알
게 될 것이다" 라고 한다.
BD는 평상시 느린 움직임과 큰 덩치에도 불구하고 때로는 플레이어보다 훨씬 더 빨리
움직이는 민첩성을 가지고 있다.



바이오쇼크 뮤직 비디오

2007/08/31 16:16 2007/08/31 16:16
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

BigDecimal의 필요성

부동 소수점 숫자 사용은 재미있는 작업이 될 수 있다. 일반적으로 양을 다룰 때 정수가 아니라면 double 형식을 사용하려고 한다. 정수인 경우 일반적으로 int 형식이면 충분하다. 값의 크기에 따라 float나 long도 효과적일 수 있다. 그러나 화폐를 다룰 경우, 이 형식들은 최악의 선택이 되는데, 정확한 값을 제공하지 않을 때도 있기 때문이다. 단지 이진수 형식에 저장 가능한 값만 제공한다. 다음은 합계를 계산하거나 할인을 반영하거나 부가가치세를 추가할 때 double을 사용하면 겪게 되는 문제를 보여주는 간단한 예제이다.

Calc 프로그램은 금액 $100.05로 시작한 다음 사용자에게 10% 할인을 적용하고 다시 5% 부가가치세를 추가한다. 부가가치세율은 다를 수 있지만, 이 예제에서는 5%를 사용한다. 그 결과를 보자면, 이 클래스는 NumberFormat 클래스를 사용하여 결과의 형식을 지정하는데, 이 결과는 통화로 표시되어야 한다.

import java.text.NumberFormat;

public class Calc {

  public static void main(String args[]) {
    double amount = 100.05;
    double discount = amount * 0.10;
    double total = amount - discount;
    double tax = total * 0.05;
    double taxedTotal = tax + total;
    NumberFormat money = NumberFormat.getCurrencyInstance();
    System.out.println("Subtotal : "+ money.format(amount));
    System.out.println("Discount : " + money.format(discount));
    System.out.println("Total : " + money.format(total));
    System.out.println("Tax : " + money.format(tax));
    System.out.println("Tax+Total: " + money.format(taxedTotal));
  }
}

모든 내부 계산에 double 형식을 사용하면 결과는 다음과 같다.

Subtotal : $100.05
Discount : $10.00

Total : $90.04
Tax : $4.50
Tax+Total: $94.55

가운데의 Total이 기대하는 값일 수 있으나, 맨 끝의 Tax+Total 값에서 끝난다. 할인은 $10.01이 되어야 $90.04의 금액을 얻는다. 해당 부가가치세를 추가하고 나면 최종 합계가 1센트 늘어나 있다. 세무 당국은 이 점을 이해하지 못할 것이다. 반올림 오류가 문제이다. 이 반올림 오류를 바탕으로 계산한 것이다. 다음은 형식이 지정되지 않은 값이다.

Subtotal : 100.05
Discount : 10.005

Total : 90.045
Tax : 4.50225
Tax+Total: 94.54725

형식이 지정되지 않은 값을 살펴보자면, 맨 처음 떠오르는 질문은 왜 90.045가 90.05 대신 90.04가 되었는가이다. (즉, 왜 10.005가 10.00으로 반올림되는가?) 이는 소위 RoundingMode에 의해 제어되는데, 이는 Java SE 1.6에 도입된 계수법으로서 이전 릴리스에서는 그러한 제어가 없었다. 통화를 위해 도입된 NumberFormat은 기본 반올림 모드가 HALF_EVEN이다. 즉, 남은 값이 등거리(equidistant)이면 짝수 쪽으로 라운딩된다. 이 계수법에 대한 Java 플랫폼 설명서에 따르면, 통계상 이 방법은 여러 차례의 계산을 거친 후 누적 오류를 최소화한다.

RoundingMode
계수법에서 사용 가능한 또 하나의 모드는 다음과 같다.

  • CEILING 항상 양수 무한대로 라운딩한다.
  • DOWN 항상 0으로 라운딩한다.
  • FLOOR 항상 음수로 라운딩한다.
  • UP 항상 0으로부터 벗어나서 라운딩한다.
  • HALF_DOWN 항상 가장 가까운 인접 수로 라운딩한다. 단, 두 인접 수 모두 등거리라면 버림한다.
  • HALF_UP 항상 가장 가까운 인접 수로 라운딩한다. 단, 두 인접 수가 모두 등거리라면 올림한다.
  • UNNECESSARY 라운딩할 필요 없이 정확한 결과를 선언한다.

이 문제의 해결 방법을 알아보기에 앞서, 약간 다른 결과를 살펴 보도록 한다. 70센트로 시작하고 할인이 없는 경우이다.

Total : $0.70
Tax : $0.03

Tax+Total: $0.74

70센트 거래의 경우, 단순히 라운딩 문제가 아니다. 형식 지정 없이 값을 보자면 다음과 같다.

Total : 0.7
Tax : 0.034999999999999996

Tax+Total: 0.735

부가가치세인 0.035는 double로 저장할 수 없다. 즉, 이진 형식에서 double로 표현할 수 없다.

BigDecimal
클래스는 float 및 double을 사용하는 부동 소수점 연산에서 생기는 문제 몇 가지에서 도움이 된다. BigDecimal 클래스는 사실상 무제한적인 정밀도로 부동 소수점 숫자를 저장한다. 이 데이터를 다루기 위해 add(value), subtract(value), multiply(value) 또는 divide(value, scale, roundingMode) 메소드를 호출한다.

BigDecimal
값을 출력하려면 setScale(scale, roundingMode)로 단위 및 라운딩 모드를 설정하거나 toString() 또는 toPlainString() 메소드를 사용한다. toString() 메소드는 과학적 표기를 사용할 수 있지만, toPlainString()은 그렇지 않다.

BigDecimal
을 사용하도록 프로그램을 변환하기 전에 그 생성 방법을 확인하는 것이 중요하다. 이 클래스에는 16개의 구성자가 있다. BigDecimal의 값을 double과 같은 primitive 객체에 저장할 필요는 없으므로 String으로부터 BigDecimal 객체를 만드는 것이 가장 좋다. 이 오류를 보여 주기 위해 간단한 예제를 소개한다.

  double dd = .35;
  BigDecimal d = new BigDecimal(dd);

  System.out.println(".35 = " + d);

예상했던 출력이 아닐 것이다.

  .35 = 0.34999999999999997779553950749686919152736663818359375

그보다는 여기서 보여주는 것처럼 string "35"를 직접 사용하여 BigDecimal을 만들어야 한다.

  BigDecimal d = new BigDecimal(".35");

그 결과 다음과 같은 출력을 얻는다.

 .35 = 0.35

값을 생성한 후 숫자의 단위와 라운딩 모드를 setScale()을 사용하여 명시적으로 설정할 수 있다. Java 플랫폼의 다른 Number 하위 클래스와 마찬가지로, BigDecimal은 변경할 수 없다. 따라서 setScale()을 호출할 경우 반환 값을 "저장"해야 한다.

  d = d.setScale(2, RoundingMode.HALF_UP);

BigDecimal
을 사용하여 수정된 프로그램은 다음과 같다. 계산마다 또 다른 BigDecimal을 사용하고 그 단위를 설정해야 달러 및 센트에 대한 수학 연산이 수행된다. 분할 페니를 사용하려는 경우 단위에서 3개의 소수 자리로 갈 수도 있지만, 꼭 그럴 필요는 없다.

import java.math.BigDecimal;
import java.math.RoundingMode;


public class Calc2 {
  public static void main(String args[]) {
    BigDecimal amount = new BigDecimal("100.05");
    BigDecimal discountPercent = new BigDecimal("0.10");
    BigDecimal discount = amount.multiply(discountPercent);
    discount = discount.setScale(2, RoundingMode.HALF_UP);
    BigDecimal total = amount.subtract(discount);
    total = total.setScale(2, RoundingMode.HALF_UP);
    BigDecimal taxPercent = new BigDecimal("0.05");
    BigDecimal tax = total.multiply(taxPercent);
    tax = tax.setScale(2, RoundingMode.HALF_UP);
    BigDecimal taxedTotal = total.add(tax);
    taxedTotal = taxedTotal.setScale(2, RoundingMode.HALF_UP);
    System.out.println("Subtotal : " + amount);
    System.out.println("Discount : " + discount);
    System.out.println("Total : " + total);
    System.out.println("Tax : " + tax);
    System.out.println("Tax+Total: " + taxedTotal);
  }
}

여기서는 NumberFormat이 사용되지 않았다. 하지만 통화 기호를 보여주고 싶다면 다시 추가할 수 있다.

이제 프로그램을 실행하면 훨씬 나은 계산이 수행된다.

Subtotal : 100.05
Discount : 10.01

Total : 90.04
Tax : 4.50
Tax+Total: 94.54

BigDecimal
은 이 예제에서 보여준 것보다 더 다양한 기능을 제공한다. 정수를 사용하는데 무한대의 정밀도가 필요한 경우를 위한 BigInteger 클래스도 있다. 두 클래스에 대한 Java 플랫폼 설명서에서는 단위, MathContext 클래스, 정렬 및 동등(equality)에 대한 정보를 비롯하여 이 클래스와 관련된 자세한 내용을 확인할 수 있다.

저자 JZ Ventures사의 사장 겸 대표 컨설턴트 John Zukowski

2007/08/30 16:00 2007/08/30 16:00
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

용인 스피드웨이 다녀왔습니다.

예~ 어제는 무지막지하게 찌는 날이었습니다.
지난주에 직장 동료 중 하나가 스피드웨이 입장권이 생겼다고 가 볼 것을 적극적으로 권유해
다녀오게 되었습니다. 용인 에버랜드 쪽으로 가보는 것도 햇수로 2년은 넘은듯합니다.

사진찍는 사람들도, 행사 진행원들도, 레이서도 힘든 하루였을 겁니다.

이번 행사장에서의 수확이라면 레이싱 모델이 아닌 아마추어 보드팀의 퍼포먼스를 볼 수 있었다는 것입니다.
아마추어팀이라고 자신을 소개 했는데 활동명이나 연락처를 못 받아온 게 내심 아쉽네요.











곡 : Soda Love by SHK

minolta @7, 100-300apo, fuji pro 160s
2007/08/27 12:29 2007/08/27 12:29
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 2007/08/29 22:51
    포토 에세이 찍는 법... Tracked from 요지경 세상, 즐거운 하루.

꺅~ 꺅~ Hero



HERO~ HERO~ HERO~ 빨랑 나와랏!!

국내에서는 10월 달에 개봉될 예정이라니.. 무지 기대됩니다.. ^^


영화 히어로 포스터

http://www.hero-movie.net
2007/08/27 03:29 2007/08/27 03:29
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

자바 애플리케이션에서 동적으로 PDF 파일 생성하기

2007/08/26 22:06

서비 JAVA ,

애플리케이션에서 PDF 문서를 동적으로 만들어야 한다면 iText 라이브러리가 필요하다. 오픈 소스 iText 라이브러리로 PDF 생성이 간단해 진다. 이 글에서는 iText를 소개하고 이를 사용하여 자바 애플리케이션에서 PDF 문서를 생성하는 방법을 설명한다. iText를 잘 이해할 수 있도록 샘플 애플리케이션도 구현한다.

많은 애플리케이션들이 PDF 문서의 동적 생성을 요구하고 있다. 이 같은 애플리케이션은 이메일 전달용 고객 일람표를 생성하는 은행부터, 책의 특정 챕터를 구매하여 이를 PDF 포맷으로 받는 리더기 까지 다양하다. 그 리스트는 끝이 없다. 이 글에서 iText 자바 라이브러리를 사용하여 PDF 문서를 만들 것이다. 여러분의 이해를 돕기 위해 샘플 애플리케이션도 제공한다.
 
iText 공식 사이트 : http://www.lowagie.com/iText/download.html


iText와 친해지기

iText는 Lowagie.com(참고자료)에서 무료로 사용할 수 있는 자바 라이브러리이다. iText 라이브러리는 강력하고, HTML, RTF, XML 문서의 생성 뿐만 아니라 PDF 생성을 지원한다. 문서에 사용될 다양한 폰트를 선택할 수 있다. 또한 iText 구조에서는 같은 코드를 사용하여 앞서 언급한 유형의 문서를 만들 수 있다.

iText 라이브러리에는 다양한 폰트로 PDF 텍스트를 만들고, PDF 문서에 테이블을 생성하고, 워터마크를 페이지에 추가하는 클래스가 포함되어 있다. iText로 사용할 수 있는 더 많은 기능들이 있다. 하지만 그 모든 것을 이 글에서 다 설명하기는 불가능하다. PDF 생성에 필요한 기본적인 것만을 설명하겠다.

샘플 애플리케이션 개발에 Eclipse를 사용할 것이다. 오픈 소스 IDE인 Eclipse는 무료로 사용할 수 있고 매우 강력하다. 지금 Eclipse를 다운로드 하라. (참고자료)

iText API

com.lowagie.text.Document는 PDF 문서 생성을 위한 주 클래스이다. 인스턴스로 만들어질 첫 번째 클래스이다. 문서가 생성되면 라이터는 여기에 작성해야 한다. com.lowagie.text.pdf.PdfWriter는 PDF 라이터이다. 다음은 일반적으로 사용되는 클래스들이다.

  • com.lowagie.text.Paragraph -- 들여쓰기 단락을 나타내는 클래스이다.
  • com.lowagie.text.Chapter -- PDF 문서의 챕터이다. 타이틀로 Paragraph를 사용하고, 챕터 번호로 int를 사용한다.
  • com.lowagie.text.Font -- 폰트, 크기, 스타일, 컬러 같은 모든 폰트 스팩들이 포함되어 있다. 다양한 폰트들은 이 클래스에 정적 상수로서 선언된다.
  • com.lowagie.text.List -- 많은 ListItems를 포함하고 있는 리스트이다.
  • com.lowagie.text.Table -- 매트릭스에서 정렬된 셀들을 포함하고 있는 테이블이다.

Eclipse에서 iText 다운로드 및 설정하기

순수 자바 라이브러리인 아아텍스트는 JAR 파일의 형태로 되어 있다. (참고자료.) 라이브러리를 다운로드 하면(C:\temp) Eclipse 환경에서 iText 라이브러리를 설정한다.

  1. Eclipse에서 iText라는 이름의 새로운 자바 프로젝트를 만든다.
  2. Package Explorer 뷰에서 iText 프로젝트를 오른쪽 클릭하고 Properties를 선택한다.
  3. Java Build Path를 클릭한다. Libraries 탭에서, Add External JARs를 클릭한다.
  4. C:\temp 디렉토리를 검색하여 itext-1.3.jar를 선택한다.
  5. OK를 클릭한다.

iText가 설정되면 Eclipse는 동적인 PDF 문서를 생성하는 자바 애플리케이션을 구현할 준비를 갖춘 것이다.






샘플 애플리케이션

직접 샘플을 만드는 것 만큼 확실한 설명 방법은 없다. 필요한 툴(Eclipse IDE)과 라이브러리(iText 라이브러리)가 준비되었으니 샘플 프로그램을 디자인 및 개발해 보자.

평이한 텍스트, 특별 폰트로 색상을 입힌 텍스트, 테이블, 리스트, 챕터, 섹션 같은 기본적인 엘리먼트를 포함하고 있는 PDF 문서를 만들어 보자. 이 애플리케이션의 목적은 여러분이 iText 라이브러리를 사용하는 방법을 보다 잘 이해할 수 있도록 돕는 것이다. PDF 문서 생성과 관련되어 많은 일을 수행하는 많은 클래스들이 있다. 이 모든 클래스들을 다 다루기는 불가능하다. iText의 javadoc은 이러한 클래스들의 사용법을 잘 이해할 수 있는 좋은 자료이다. 코딩부터 시작해 보자.

첫 번째 단계는 문서를 만드는 것이다. 이 문서는 PDF 문서의 모든 엘리먼트용 컨테이너이다.


Listing 1. 문서 객체의 인스턴스화

				
Document document = new Document(PageSize.A4, 50, 50, 50, 50);

첫 번째 인자는 페이지 크기이다. 다음 인자들은 각각 왼쪽, 오른쪽, 상단, 하단 여백들이다. 이러한 유형의 문서는 아직 정의되지 않았다. 여러분이 만드는 라이터의 유형에 의존한다. 이 샘플에서 우리는 com.lowagie.text.pdf.PdfWriter를 선택했다. 기타 라이터로는 HtmlWriter, RtfWriter, XmlWriter 등이 있다. 이름만으로도 충분히 그 용도를 알 수 있다.


Listing 2. PdfWriter 객체의 생성

				
PdfWriter writer = PdfWriter.getInstance(document, \
new FileOutputStream("C:\\ITextTest.pdf"));
document.open();

첫 번째 인자는 문서 객체에 대한 참조이고, 두 번째 인자는 아웃풋이 작성될 파일의 고유 이름이다. 작성을 위해 문서를 연다.

이제, 문서의 첫 번째 페이지에 몇 가지 텍스트를 추가할 것이다. com.lowagie.text.Paragraph을 사용하여 어떤 텍스트라도 추가된다. 텍스트로 기본 단락을 만들고 폰트, 컬러, 크기 등 기본적인 설정을 할 수 있다. 각자의 고유 폰트를 사용해도 된다. 두 가지 옵션 모두를 살펴보자.


Listing 3. 단락 객체의 생성

				
document.add(new Paragraph("First page of the document."));
document.add(new Paragraph("Some more text on the \
first page with different color and font type.", 
FontFactory.getFont(FontFactory.COURIER, 14, Font.BOLD, new Color(255, 150, 200))));

아래 그림은 위 코드의 아웃풋이다. 위 코드 말미에 document.close();을 추가하여 문서를 마감한다.


그림 1. 아웃풋
Sample output of above code

평이한 텍스트를 PDF 문서에 추가하는 방법을 배웠다. 복잡한 요소들도 문서에 추가해야 한다. 새로운 챕터를 만든다. 이 챕터는 특별 섹션으로서 새로운 페이지로 시작하고 기본적으로 디스플레이 된 숫자가 있다.


Listing 4. 챕터 객체의 생성

				
Paragraph title1 = new Paragraph("Chapter 1", 
           FontFactory.getFont(FontFactory.HELVETICA, \
           18, Font.BOLDITALIC, new Color(0, 0, 255)));
Chapter chapter1 = new Chapter(title1, 1);
chapter1.setNumberDepth(0);

위 코드에서 chapter1 이라는 새로운 챕터 객체를 만들었다. 제목은 "This is Chapter 1."이다. 숫자 한계를 0으로 설정하면 페이지에 챕터 번호가 디스플레이 되지 않는다.

섹션은 챕터의 하위 요소이다. 다음 코드에서, "This is Section 1 in Chapter 1." 이라는 제목의 섹션을 만들었다. 이 섹션에 텍스트를 추가하기 위해 또 다른 단락 객체인 someSectionText를 만들고 이를 섹션 객체에 추가한다.


Listing 5. 섹션 객체의 생성

				
Paragraph title11 = new Paragraph("This is Section 1 in Chapter 1", 
           FontFactory.getFont(FontFactory.HELVETICA, 16, \
           Font.BOLD, new Color(255, 0, 0)));
Section section1 = chapter1.addSection(title11);
Paragraph someSectionText = new Paragraph("This \
text comes as part of section 1 of chapter 1.");
section1.add(someSectionText);
someSectionText = new Paragraph("Following is a 3 X 2 table.");
section1.add(someSectionText);

테이블을 추가하기 전에 문서가 어떤 모습인지를 보자. 다음 두 줄을 추가하여 문서를 종료하고 프로그램을 컴파일 및 실행하여 PDF 문서를 만든다. document.add(chapter1);document.close();.


그림 2. 아웃풋
Sample output of chapter

이제 테이블 객체를 만들어 보자. 테이블에는 열과 칼럼의 매트릭스가 포함된다. 한 열의 셀은 한 개 이상의 칼럼으로 확장될 수 있다. 마찬가지로, 한 칼럼에 있는 셀은 한 개 이상의 열로 확장될 수 있다. 따라서, 3 x 2 테이블은 정확히 6 개의 셀만 가질 필요가 없다.


Listing 6. 테이블 객체의 생성

				
Table t = new Table(3,2);
t.setBorderColor(new Color(220, 255, 100));
t.setPadding(5);
t.setSpacing(5);
t.setBorderWidth(1);
Cell c1 = new Cell("header1");
c1.setHeader(true);
t.addCell(c1);
c1 = new Cell("Header2");
t.addCell(c1);
c1 = new Cell("Header3");
t.addCell(c1);
t.endHeaders();
t.addCell("1.1");
t.addCell("1.2");
t.addCell("1.3");
section1.add(t);

위 코드에서, t라는 테이블 객체를 만들었다. 세 개의 칼럼과 두 개의 열을 갖고 있다. 테이블의 보더 색상을 설정했다. 패딩(padding)은 셀의 텍스트와 셀의 경계간 공간을 만드는데 사용된다. 스페이싱(spacing)은 인접하는 셀의 경계들간 공간이다. 그런 다음, 세 개의 셀 객체를 만든다. 각각 다른 텍스트를 갖고 있다. 이들을 계속해서 테이블에 추가한다. 첫 번째 칼럼에서 시작하여 같은 열의 다음 칼럼으로 이동한다. 열이 완성되면 다음 셀이 다음 열의 첫 번째 칼럼에 추가된다. 셀은 t.addCell("1.1"); 같은 셀의 텍스트를 제공하여 테이블에 추가될 수 있다. 마지막으로 테이블 객체가 섹션 객체에 추가된다.

마지막으로 PDF 문서에 리스트를 추가해 보자. 리스트에는 많은 ListItem들이 추가된다. 리스트에는 번호가 붙을 수도 있고 붙지 않을 수도 있다. 첫 번째 인자를 TRUE로 전달하면 번호가 붙은 리스트를 만들어야 한다.


Listing 7. 리스트 객체의 생성

				
List l = new List(true, false, 10);
l.add(new ListItem("First item of list"));
l.add(new ListItem("Second item of list"));
section1.add(l);

지금까지 chapter1 객체에 모든 것을 추가했다. chapter1에 추가될 더 이상의 객체가 없기 때문에, chapter1을 주 document에 추가해야 한다. 샘플 애플리케이션을 통해 한 개의 문서를 완성했다.


Listing 8. 주 document에 챕터 추가하기

				
document.add(chapter1);
document.close();






샘플 애플리케이션 실행하기

  1. 샘플 애플리케이션, j-itextsample.jar(Download)을 다운로드 한다.
  2. 디렉토리에 j-itextsample.jar의 압축을 푼다. C:\temp에 추출하면, 소스와 클래스 파일은 C:\temp\com\itext\test에 배치된다.
  3. 명령어 프롬프트를 열고 디렉토리를 C:\temp로 변경한다.
  4. 명령어 프롬프트에 시스템의 classpath를 설정한다. 시스템의 classpath에 C:\temp\itext-1.3.jar를 포함시킨다. Windows®에서는, set classpath=C:\temp\itext-1.3.jar;%classpath%명령어를 실행한다.
  5. java com.itext.test.ITextTest 명령어로 애플리케이션을 실행한다.

이 프로그램은 C:\에 ITextTest.pdf 문서를 생성할 것이다. 아래 그림은 이 PDF 문서의 두 번째 페이지 모습이다.


그림 3. PDF 문서 모습
Screenshot of PDF document

결론

지금까지 PDF 생성을 위한 기본 요소들을 살펴 보았다. iText의 장점은 같은 엘리먼트의 신택스가 다른 유형의 라이터에도 사용될 수 있다는 점이다. 또한, 이 라이터의 결과는 콘솔( XML과 HTML 라이터), 서블릿의 아웃풋 스트림 (PDF 문서의 웹 요청에 대한 응답), 또는 다른 유형의 OutputStream 으로 리다이렉션 된다. 또한 iText는 응답은 갖지만 PDF, RTF, HTML, XML 등 다양한 응답 유형을 보이는 상황에서 편리하게 사용할 수 있다. iText에서는 워터마크를 만들 수 있고 문서를 암호화 할 수 있으며 아웃풋도 정확하다.

다운로드 :

2007/08/26 22:06 2007/08/26 22:06
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

RFID 관련 국제 표준

RFID 관련 국제표준은 태그, 리더 등 기기에 대한 표준과 RF 태그에 저장되는 코드 표준으로 크게 구분할 수 있습니다. 기기 표준은 자사 제품과 타사 제품 간 호환성을 확보케 하여 중복 투자로 인한 비용을 절감하고 기술 개발 촉진 및 시장 확대가 가능합니다. 코드의 경우 다른 코드는 응용 분야가 제한적인 경우가 많으나 EPCglobal이 보급하고 있는 EPC 코드는 유통, 물류를 중심으로 한 전 산업에 적용 가능하며, 이미 바코드와 함께 산업계에서 널리 활용되고 있는 EAN.UCC 식별 코드도 EPC 코드에서 수용 가능합니다.


사업내용

ISO/IEC JTC1/SC31/WG4
RFID의 국제표준화는 ISO와 IEC가 공동으로 구성한 JTC1 산하 SC31의 워킹그룹 4(WG4)가 중심이 되어 추진
ISO : International Organization for Standardization, 국제표준화기구
IEC : International Electrotechnical Commission, 국제전기기술위원회
JTC1 : Joint Technical Committee 1, 공동기술위원회 1
SC31 : Sub-Committee 31, 산하 위원회 31

응용 산업별 국제표준화
컨테이너, 포장, 차량 등 유통물류의 공급망에 관련되어 있는 ISO의 TC104(컨테이너), TC122(포장), TC204(교통정보) 등 ISO의 응용분야 기술위원회에서 응용 산업별 국제표준화 추진
TC : Technical Committee, 기술위원회
각 TC들은 JTC1/SC31과 긴밀한 상호협력관계 유지
ISO는 유통물류 분야의 사실상 표준화를 주도하고 있는 EPCglobal 등과도 협력관계를 갖고 Air Interface 등 RFID 핵심 표준화 분야에서 유기적인 협력관계 지속


민간국제표준 담당기구

EPCglobal
www.epcglobalinc.org
EPCglobal은 상품코드의 국제표준 개발/관리 기구인 EAN과 UCC가 통합되어 탄생한 GS1이 2003년 11월에 설립한 자회사로서 EPC 코드와 EPCglobal 네트워크의 전 세계 보급 총괄
AIM Global
1972년 설립된 자동인식기술 장비업체들의 협력기구로서 43개국 900여 업체 참여
RFID 바코드 등 자동인식기술 관련 업계표준 제정, 국제표준화 활동참여 및 자문
조직별 주요사업

조직 사업내용
표준 자문그룹 SC31, SC17(카드 및 생체인식 표준),
SC37(바이오매트릭스 표준화) 등 국제 표준제정 활동 참여
의료산업 실무그룹 FDA 바코드 표시 규정 관련 연구 및 자문
RFID 개인정보 보호 실무그룹 RFID관련 개인정보보호 제반 문제 규명 및 해결방안 연구
전략적 협력 자문그룹 GS1, EPCglobal 활동에 직ㆍ간접적 참여
심벌기술위원회 바코드 관련 기술적 제반 문제 연구

지역지원센터(Support Center)와 지부(Chapter)를 통한 회원사 지원 활동 추진
원문 출처 : http://www.rfidepc.or.kr/sub.asp?s_m=3&s=3_03
2007/08/26 09:13 2007/08/26 09:13
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

인간은 무었때문에 네트워크를 만들며 산다고 생각해?

미치코는 방을 나가려고 했다.
"저, 선배님."
"뭔데?"
"일부러 제 넋두리를 들어주시려고 오신거예요?"
"그래"
"고맙습니다. 항상 신경 써 주셔서. 죽음을 앞둔 사람들의 마음을 구원해 주고 싶다고 큰소리 떵떵 치며 호스피스를 지원 했으면서, 저도 참...."
미치코는 고개를 저었다.
"키타지마 선생, 인간은 무었때문에 네트워크를 만들며 산다고 생각해?"
갑작스런 질문에 사나에는 당황했다.
"그건 그 편이 정보를 효율적으로 전할 수 있으며......"
미치코는 코웃음 쳤다.
"키타지마 선생도 역시 인터넷이니 하는것에 물들었구나. 정보따위는 어차피 9할이 쓰레기고 나머지도 독이 든 거야.
인간과 인간의 네트워크라는것은 말이야, 정보망 같은게 아니라 트램펄린( Trampoline ) 네트야."
"......"
"무슨 일이 있어도 혼자 감당해야 한다고 생각하면 안돼. 무너질 테니까.
그럴 때는 주위 사람들에게 조금씩 충격을 분담시켜서 네트 전체가 흡수하게 만들면 되는거야. 알겠어?"
2007/08/25 12:01 2007/08/25 12:01
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

화이트 스페이스 :: 태터툴즈 1.1, 텍스트큐브 1.5 스킨

에이라이님의 '자폐증 증세호전' 버전이 마음에 들어 유심히 살펴보다 몇 가지 문제가 있어 수정을 하였습니다.

사용자 삽입 이미지

2008.04.01 추가
  나미나미님의 의견으로 방명록 기능을 쓸 수 있는 방법을
  http://www.yunsobi.com/link/guestbook.txt 에 기술해 둡니다.

2007.09.03 추가수정
  스킨갤러리의 jane님의 충고를 받아들여 스킨 제목을 '자폐증 증세호전'에서
  '화이트스페이스'로 수정 하여 배포합니다.

2007.08.27 추가수정
  텍스트큐브 1.5.1로 업데이트 시 포스트 하단의 최근글,최근 댓글이 사라지는 문제를 해결 했습니다.
  style.css에 blockquote 태그의 스타일을 먹이고  wysiwyg.css 에도 적용 하였습니다.
  본문 폭을 700px로 약간 줄였습니다.
  화면 맨 아래쪽에 rss feed 표시를 추가하였습니다.

제가 수정한 부분은
  열고 닫는 HTML 태그가 맞지 않아 정리 하였습니다.
  HTML 들여쓰기를 정리하였습니다.
  검색결과가 나타나도록 했습니다.
  폰트 크기/색상을 정리하였습니다.
  텍스트큐브 1.5 에디터에 적용 되는 wysiwyg.css를 작성 하였습니다.
  본문의 가록 폭은 750px에 맞춰졌습니다.

적용된 스킨의 확인은 여기서 하실 수 있습니다.
스킨이 마음에 들어서 수정을 하긴 했는데.. 어디에 적용하면 좋을지 고민 입니다. ^^

다운로드 :
2007/08/24 16:12 2007/08/24 16:12
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 스킨이 맘에 들어 사용을 했는데, 문제가 발생해서요. 혹시 본문 글 제목 글자 크기 수정할려면 어떻게 해야하나요 ?
    <div class="entry"><br/>
    <h1><a href="[##_article_rep_link_##]">[##_article_rep_title_##]</a></h1>

    요부분말이예요 css 수정을 어떻게 해야하나요 ?

국내 무료 계정 서비스

웹을 누비다 발견한 무료 호스팅 서비스. 호스팅랜드 :



서비스 내용을 보자면
    서버 : Linux + PHP + Mysql 4.1
    HDD : 200Mbyte
    MySQL : 20Mbyte
    일트래픽 : 500Mbyte
    초기설치프로그램 : 쇼핑몰+제로보드
    도메인 : 아이디.ft.co.kr 제공
    메일 : 3개
    기타 : Telnet, SSH, FTP 제공

2007년 08월 25일까지 무료 호스팅 신청을 받고 있다. 무료계정신청을 계속 받고 있다.
현재 40개 정도의 계정이 남아있으며, 신청 후 취소하는 사람들도 있는 걸로 봐서는
기간 내에만 신청한다면 무료 계정을 받을 수 있을 듯.

특징이라면, 계정을 분양받고 사이트를 개설하면 호스팅랜드의 작은 배너를 달것을 요구하고
있다는 것이다. 이미지 배너이거나 배너가 크거나 하지 않고, 호스팅랜드를 광고하는 텍스트
배너이며 테두리나 색상은 자신의 사이트에 맞게 꾸밀 수 있기 때문에 단점으로 보이진 않는다.

무료계정은 언제나 이런저런 제약과 언제 운영자의 마음이 바뀌어 분양받은 계정이
사라질지 모르는 부담을 안고 있는 것 역시 사실이다.
하지만, 이런 불안요소가 있더라도 이런 서비스를 필요로하는 사람들은 있는 법.
이런 계정이라도 쓰는 사람의 손에 달린 거 아닐까?
필요한 사람이 있다면 한번 신청하러 달려가 보자.
2007/08/24 10:54 2007/08/24 10:54
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

EPCglobal ALE 표준 스펙에 대한 인증 절차

EPCglobal ALE 표준 스펙에 대한 인증 절차는  다음과 같다.
 
1. EPCglobal 회원가입 (회원에게만 인증 자격이 주어짐.)
2. ALE 인증 신청서 제출 (한국유통물류진흥원http://www.gs1kr.org/ 제공)
3. 진흥원 및 EPCglobal에서 신청서 검토
4. 신청서에 문제가 없을 경우, 인증 비용을 위한 invoice 발송
5. 인증 비용 입금 후, 테스트를 대행하고 있는 미국 Met Lab 과 협의 하여 테스트 일정 확정


EPCglobal 인증절차



국내에서는 'RFID 산업 활성화 지원센터'( http://www.rfidepc.or.kr ) 에서 인증을 대행 한다고 하며,
인증 요구사항(http://www.epcglobalinc.org/standards/ale) 역시 EPCglobal 회원에 한해 열람이 가능.
2007/08/23 15:27 2007/08/23 15:27
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

테터툴즈에서 텍스트큐브로 이전한 후..

엊저녘 갑자기 삘 받아 테터툴즈에서 텍스트큐브로 업그레이드를 단행 했다.
원래 계획은 텍스트큐브 마이너 업데이트버전이 출시되면 그때 느긋이 진행하려고 했는데..
하루일과가 지루했던지, 정말 아무 생각 없이, 그냥 삘이 통해 버려서...

우선 기존 태터툴즈의 스킨과 플러그인이 제대로 동작하는지가 제일 걱정인 부분이었는데,
계정에 테스트용으로 설치를 해 보니 사용 중이던 스킨, 플러그인이 별 문제없이 동작하는듯하여
퇴근 후 자정을 전후해 업그레이드를 진행 했다.


업그레이드 후 꼼꼼히 살펴보니 다른 부분들은 사용하는 데 큰 저항감이 없었는데
결정적으로 테터에 등록한 이미지처리 부분이 크게 바뀐듯했다.

  • 이미지 워터마크 기능이 삭제된 것과
  • 모든 이미지크기가 리사이즈되어 나온다는 것.

처음엔 적잖이 놀랐지만 관련 소스 어딘가를 고치면 쉽게 해결될 줄 알았다.
근데, 이게 어디에서 세팅이 들어가 그런지를 전혀 찾을 수가 없는 것이다!! 컥..
하릴없이 시간을 허비할 수도 없어서 잘 업그레이드를 한 걸로 일단 만족하고 잠자리에 들었다.

오늘, 관련 문제를 해결하기 위해 검색을 해 보니 내 마음을 불편케 한 두 가지 문제점에 대한
내용을 확인할 수 있었다.

하나는 바로 수정가능.
나머지 하나는 당분간 사용 불가능.

포스트의 이미지들이 리사이즈 되어 나오는 문제는 텍스트큐브의 본문 중의 이미지 사이즈에
영향을 주는 인자가 스킨의 index.xml 파일에 있다는 것.
워터마크 기능은 플러그인으로 빼기 위해 텍스트큐브 1.5에서는 빠졌다는 것.

다른 사람들은 잘 안 썼을지 모르지만 나 같은 경우 내가 직접 작성한 이미지, 사진, 도표 등에는
워터마크를 사용해 왔기 때문에 아직 구현이 안되었다는 게 상당히 아쉽다.
- 워터마크 기능이 사라진 줄 알았으면 업그레이드도 플러그인 등장 이후로 미뤘텐데...-

어쨌든 플러그인 구현을 위한 새로운 티켓까지 발행 했으니 당분간만 불편을 감수하면 되겠지?
이른 시일 내에 워터마크 플러그인이 등록되었으면 좋겠다.

2007/08/23 13:18 2007/08/23 13:18
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 2007/08/25 14:24

JavaMail :: 인증을 요하는 메일 SMTP에 접속하는 방법

2007/08/22 16:33

서비 JAVA , , ,

얼마전 인증을 해야하는 SMTP에 연결해야 했는데 그 방법 때문에 매우 고민했었습니다.
Mail API에서 Authenticator는 제공을 하면서 ID와 PW를 설정하는 부분이 없어서
참 난감했었습니다. 영어 실력이 짧아서 관련 Document를 읽어보다가 못찾고
다만 API에 있는 Session 클래스의
getInstance(Properties prop, Authenticator auth) 메소드가 마음에 걸려
혹시나 하는 마음으로 만들어 봤었는데 잘 되더군요.
sendmail 과 qmail 및 윈도기반 smtp server 몇 곳을 테스트 해봤는데 잘 되었습니다.

클래스 전체 소스는 다음과 같습니다.

/*
* MyAuthenticator.java
* 2002.05.27.
* Hyunho Kim(falllove@ducc.or.kr)
*
* Copyrightⓒ 2002 FancyArts Corps. All rights reserved.
*/

/**
* SMTP Authenticator
*/
public final class MyAuthenticator extends javax.mail.Authenticator {

    private String id;
    private String pw;

    public MyAuthenticator(String id, String pw) {
        this.id = id;
        this.pw = pw;
    }

    protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
        return new javax.mail.PasswordAuthentication(id, pw);
    }

}

사용하실 때는 session을 얻기 전에 프로퍼티에 mail.smtp.auth 항목을 추가하시고
MyAuthenticator의 인스턴스를 하나 만드셔서 인자로 넘기시면 됩니다.

Properties prop = new Properties();
prop.put("mail.smtp.host", "smtp_host_name");
prop.put("mail.smtp.auth", "true");

MyAuthenticator auth = new MyAuthenticator("smpt_id", "smtp_pw");

// 새로운 메일 세션
Session mailSession = Session.getInstance(props, auth);
// or Session mailSession = Session.getDefaultInstance(props, auth);

정말 간단하죠^^;; 정말 암 것도 없는데 전에 이것을 하기 위해서 그 많은 글을 뒤적일
때는 못찾겠더라구요. 전 만들긴 했었지만 실제 서비스는 sendmail에서
localhost relay를 허용해서 사용하고 인증없이 발송하고 있습니다.
2007/08/22 16:33 2007/08/22 16:33
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

조디악 :: ZODIAK Killer

치열함 뒤에 갖는 휴식은 천국과 같다고 했던가?
지금 내게 딱 맞는 표현이 아닐까 한다.
지난 2주간 '피를 말리는'이라는 표현까지는 아니더라도 굉장히 신경을 써왔던 일을
마무리하면서 오늘과 내일은 일에서 손을 놓고 온전히 나만의 시간을 즐길 수 있게 되었다.

오늘은 더위도 피할 겸 요 며칠간 보고 싶었던 조디악을 보러 갔다.

영화 조디악 포스터
영화 조디악 포스터


조디악, 조디악 킬러라고 하면 범죄학을 전공하거나 그런 쪽의 이야기를 좋아하는 사람에겐 너무도 유명한 미국의 미결 연쇄살인 사건이다.
마치 우리나라의 화성 연쇄 살인처럼.

영화는 희대의 살인마를 다루는 여화답지 않게, 무겁거나 침울한 분위기를 유지하지도 않는다.
어쩌면, 이 영화의 주인공은 조디악 킬러가 아닌 조디악 킬러에 집착하는 카투니스트와 사건 전담 형사 인지도 모르겠다.

영화 속에서 그려지는 일반적인 형사의 이미지 '터프함 이라든지 과격함 같은 것' 를 이 영화에선 찾아볼 수 없다.
처음 형사역을 맡은 배우가 등장하고 그 목소리를 들었을 때 일반 남성보다 더 가는 목소리로 그의 성격을 단박에 파악할 수 있을 정도였으니..
- 실은, 형사의 목소리와 어투가 너무 독특해 이질적이었지만 영화가 진행되면서 바로 익숙해져 버렸다.. -

또 한가지, 70년대부터 80년대 말까지 근 20년이라는 시간의 흐름을 영화 배경 안에 잘 살려 내고 있다.
특정시대의 특정 장소가 나타내는 특징을 잘 그려내고 있어 이를 보는 즐거움도 빼놓을 수 없는 관전 포인트가 아닌가 한다.

영화에는 영어 히어링에 잼병이인 나도 피식 하고 웃을 수 있는 블랙 유머들이 요소요소에 배치되어있다.
한 장면에선 '밥은 먹고다니냐?'란 번역이 나오는데-물론 배우의 스크립트는 그렇지 않았지만-
딱 맞는 장면에 적절한 번역으로 묘하게 '살인의 추억'이 오버랩 되어 순간 객석에서 일어나는 약간의 동요는 영화관에서 영화를 보는 즐거움 중의 하나가 아닐까?


데이빗 핀처 감독의 두 전작을 보단 폭력성이 줄긴 했지만 여전히 매력적인 영화.
단, 느린 전개와 인간의 심리를 파악하면서 봐야 하는 영화를 꺼리는 사람에게는
긴 상영시간과 맞물려 무지 지루한 영화가 될지도 모르겠다.

제작노트 ..

2007/08/18 22:04 2007/08/18 22:04
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

동해 - 양떼 목장 - 대구 달성 습지의 여름 일몰

지난 주말 대학 동기중 하나와 간단히 여행을 다녀 왔습니다.
주말에 비온다 비온다 그러더니 운이 좋은지 저희가 이동하는 시간동안 하늘은 너무나 깨끗한 모습을 보여 주었습니다.
이동 경로는 서울 새벽 2시에 출발해서 새벽에 경포대를 들른 후 -> 대관령 양떼 목장을 둘러보고 -> 동해의 해안로를 타고
포항까지 내려와서 대구로 진입 해 달성 습지를 찾아갔습니다.
간만에 하던일을 잠시 미루고 서울 도심을 벗어난데다 날씨도 쾌청이라 기분이 좋더군요.
동해안 끼고 이동 할 땐 수영복 없는게 조금 후회될 정도 였으니까요..



동해 어느 작은 해변이 바라다보이는 도로가에도 사람의 손길이..
저 돌을 하나하나 쌓아올린 사람들의 소원이 이루어지길 바랍니다.




어느 조그마한 해안의 조용한 소경 입니다.





경포대를 거쳐, 지난 겨울에 이어, 또 한번 양떼목장에 들렀습니다. 그 때는 무척이나 추웠는데..
이번에는 날이 너무 좋았습니다. 멋진 날씨에 너른 초원의 순한 양을 보니 제 마음도 순해지더군요..




여행의 마지막. 대구의 달성습지입니다.
일몰이 정말 장관이었는데 사진으로는 그 감흥이 덜하네요..




조심스런 마음으로 아름다운 자연의 순간을 담는것. 멋진 일 입니다.


나머지 필름들도 얼른 현상 맡겨야 겠어요.

2007/08/15 23:25 2007/08/15 23:25
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

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

2007/08/15 17:49

서비 JAVA ,


자바 메시징 서비스 (JMS) 사양은 자바 기반의 지점간 (point-to-point, P2P) 메시징과 publish/subscribe (P/S) 메시징에 대한 표준을 열거한다. Sun은 현재 12개의 라이선스 받은 JMS 구현자 목록을 가지고 있고 16개의 라이선스 받지 않은 구현자를 가지고 있다. 구조적으로 JMS는 JDBC API와 유사한데, 둘 다 적은 수의 클래스를, 그러나 많은 인터페이스 집합을 정의하기 때문이다. 이 인터페이스들은 구현되어져야 하고, 여기에 상응하는 구현들도 동일하게 행동할 것이다.

대부분의 데이터베이스의 경우 행동의 유사성은 JDBC 인터페이스 구현으로 끝난다. SQL 준수 수준과 독자적인 절차적 SQL 확장 (Oracle의 PL/SQL과 Sybase의 Transact-SQL등)의 차이로 인해 데이터베이스 서비스에 접근해서 이를 사용하기 위해 작성된 코드에 상당한 차이가 있을 수 있다.

JMS에서는 그렇지 않다. 최소의 노력과 이 글에서 내가 제시한 절차들을 따름으로서 여러분은 여러분의 JMS 클라이언트 코드가 여러분이 사용하고 있는 벤더 구현을 알지 못하게 만들 수 있다. 여러분이 JMS 메시지 처리에 대한 기본적인 이해를 가지고 있다고 가정하지만, 기본 개념과 용어를 간단하게 살펴보면서 시작해보자.

JMS 아키텍처

메시지를 보내고 받는 기본은 연결인데,이는 JVM 외부에 자원을 할당하는 책임을 가지고 있다. JMS 벤더는 보통 P2P 트랜잭션을 위해 적어도 하나의 QueueConnection 을, P/S 트랜잭션을 위해 TopicConnection 을 구현할 것이다. 이들 접속은 Session 을 제공하는데, 이것은 메시지의 전송과 수신을 관리하는 생성자이다.

P2P 트랜잭션 관리를 위한 기본 생성자는 QueueSenderQueueReceiver이고, P/S 트랜잭션 관리를 위한 생성자는 TopicSubscriber과 TopicPublisher이다. Topic 객체와 Queue 객체는 각 메시지의 수신지와 출처를 나타내는 특정 정보를 캡슐화한다. 이 계층이 그림 1에 나와 있다.


그림 1. JMS 클래스 계층
JMS class hierarchy diagram

request/response 지원 클래스 등의 다른 생성자와 애플리케이션 서버에 고유한 기능들은 JMS 표준 (참고 자료 )에 나와있다.

다른 유형의 연결 설정

연결은 JMS 서버와의 상호작용을 위한 진입점이기 때문에, 각 연결 인터페이스를 구현하려면 자체적인 JMS 서버의 인스턴스에 어떻게 연결하는지를 알아야 한다. 기반이 되는 연결 프로토콜의 상세사항은 각 벤더마다 다른 경우가 많기 때문에, 유효한 연결 설정에 필요한 정보도 각 벤더마다 다르다.

대부분의 벤더는 연결이 동적으로 설정될 수 있도록 한다. 즉 연결 클래스의 생성자를 공개적으로 정의하여, 프로그래머들이 필요한 연결 정보를 정의할 수 있도록 하고 있다. 대부분의 벤더는 호출에 대응해 연결을 반환하는 factory 클래스를 제공한다.

연결 factory의 경우 factory 클래스는 독자적인 연결 정보를 가지고 미리 로딩되어있는 연결을 반환할 수 있다. 벤더가 정의한 factory 클래스는 프로그래머가 접속 매개변수를 설정할 수 있도록 하는 메소드들을 보여 줄 것이며, 이 접속 매개변수들에는 factory가 반환하는 접속의 특성이 들어 있다.

벤더 API가 다른 부분

이 모두를 좀 더 구체화하기 위해 몇몇 QueueConnectionQueueConnectionFactory 구현 제품의 생성자, 접속 factory 및 설정 메소드들을 살펴보자. (일부 경우에는 오버로드된 생성자가 많이 있음에 유의한다.; 나는 각 경우에 대해 한 개씩만 보여주겠다.)

  • java.lang.String socketFactory: 소켓 factory의 클래스 명
  • java.lang.String hostname: JMS 서버의 호스트 명
  • int port: JMS 서버의 포트
  • long keepalive: 활동 주기

다음 코드는 swiftMQ QueueConnectionFactory 객체를 생성하는 방법이다. :


IIT SwiftMQ 2.1.3 QueueConnectionFactory 생성자 매개변수

 
QueueConnectionFactory qcf = (QueueConnectionFactory) new 
com.swiftmq.jms.ConnectionFactoryImpl
  ("com.swiftmq.net.PlainSocketFactory", "myhost",4001,60000);

  • java.lang.String brokerURL: URL (in the form [protocol://]hostname[:port])
  • java.lang.String connectID: 접속을 구별하기 위한 ID 문자열
  • java.lang.String username: 기본 사용자명
  • java.lang.String password: 기본 패스워드

다음은 Progress SonicMQ QueueConnectionFactory 객체를 생성하는 샘플 코드이다:


Progress SonicMQ 3.5 QueueConnection 생성자 매개변수


progress.message.jclient.QueueConnection queueConnection = new
progress.message.jclient.QueueConnection("tcp://myhost:2506", 
    "ServiceRequest", "username", "password");

우리가 살펴볼 마지막 예제는 IBM MQSeries 구현이다. MQSeries는 연결 생성자를 이용하지 않는다. 대신 여러분은 동적으로 연결을 생성하기 위해 연결 factory를 구축해야 하는데, 이는 연결을 제공하기 위한 메소드를 제공한다. 매개변수가 없는 생성자를 만들기 위한 코드는 다음과 같다.:


MQSeries (MA88)


MQQueueConnectionFactory = new
MQQueueConnectionFactory();

연결 factory의 생성자는 매개변수가 없기 때문에, factory는 factory가 제공할 연결의 특성들을 제어하기 위해 호출될 수 있는 돌연변이 메소드를 가지고 있어야 한다.:

  • setTransportType(int x): 다음 옵션 중 하나에 전송 유형을 설정한다. :
    • JMSC.MQJMS_TP_BINDINGS_MQ: MQSeries 서버가 클라이언트와 동일한 호스트에 있을 때 사용된다.
    • JMSC.MQJMS_TP_CLIENT_MQ_TCPIP: MQSeries 서버가 클라이언트와 다른 호스트에 있을 때 사용된다.
  • setQueueManager(String x): 큐 관리자의 이름을 설정한다.
  • setHostName(String hostname): 클라이언트만 해당됨, 호스트의 이름을 설정한다.
  • setPort(int port): 클라이언트 연결을 위한 포트를 설정한다.
  • setChannel(String x): 클라이언트에만 해당됨, 사용할 채널을 설정한다.

다음은 MQSeries QueueConnectionFactory를 생성하고 특정 큐 관리자로 접속하게 하는 샘플 코드이다. :


com.ibm.mq.jms.MQQueueConnectionFactory factory = new 
com.ibm.mq.jms.MQQueueConnectionFactory();
factory.setQueueManager("QMGR");
com.ibm.mq.jms.MQQueueConnection connection = 
  factory.createQueueConnection();

벤더에 독립적인 코드 생성에서의 JNDI의 역할

간략하게 살펴보았듯이, 각 벤더는 자체적인 별개의 연결 매개변수를 채택하고 있다. 그렇다면 이들 모두를 여러분 코드에 어떻게 투명하게 지원할 것인가? 표준 솔루션은 네이밍 서비스를 사용하여 사전 설정된 ConnectionFactory를 유지하는 것이다. 실행 시에 여러분의 코드는 ConnectionFactory를 검색하고 여기에서 반환되는 연결을 여러분의 JMS 서버에 투명하게 연결시킬 수 있을 것이다. 간단히 여러분의 네이밍 서비스에서 정확하게 구성된 연결 factory들만을 관리하면 되기 때문에 코드를 유지보수하고 재구축할 필요가 없어진다.

Java Naming and Directory Interface (JNDI)는 네이밍 서비스와 인터페이스하는 가장 일반적인 방법이다. JNDI는 구현되어야 하는 인터페이스 세트를 간단히 정의한다는 점에서 JMS와 유사하다. JNDI를 구현하는 모든 네이밍 서비스는 하나의 표준 API하에 접근된다.

JNDI는 벤더에 독립적인 코드를 작성하려는 우리 노력의 중심이다. 벤더에 독립적인 방식으로 네이밍 서비스에 접근할 수 있는 방법을 제공하기 때문이다. JNDI는 우리가 위 섹션에서 설명한 독자적 구현 제품에 관해 걱정하지 않고 네이밍 서비스에서 올바른 객체를 검색하기 위한 코드 작성에만 신경을 쓰도록 해준다.






JMS 서버로의 접속

연결 factory를 생성하고 이를 미리 구성하여 여러분의 네이밍 서비스에 결합시킴으로써, 여러분의 메시징 서비스에서 특정 벤더에 국한된 연결 매개변수를 감출 수 있다. 여러분의 코드가 관련되어 있는 한 여러분은 일반적인 javax.jms.Connection 객체를 사용하고 있다. 벤더 구현은 인터페이스 뒤에 숨겨진다.

JMS 사양은 관리자에 의해 생성되고 JMS 클라이언트가 사용할 구성 정보를 가지고 있는 객체를 JMS 관리 객체로 지칭하고 있다. 관리 객체는 JNDI에 의존적이지 않지만, JNDI 이름공간에서 결합되고 검색될 수 있음을 암시한다.

Listing 1과 Listing 2는 JMS 서버 (이 경우에는 SwiftMQ)에 접속하기 위한 두 가지 다른 방식을 보여준다. 벤더에 의존하는 코드를 이용하는 방식과 벤더에 독립적인 코드를 이용하는 방식이 그것이다.


Listing 1. 벤더에 의존적인 접속 방법


1.QueueConnectionFactory queueConnectionFactory = 
(QueueConnectionFactory) new 
com.swiftmq.jms.ConnectionFactoryImpl
  ("com.swiftmq.net.PlainSocketFactory", "localhost",4001,60000);
2.QueueConnection queueConnection = 
queueConnectionFactory.createQueueConnection();


Listing 2. 벤더에 중립적인 접속 방법

1.Properties p = new Properties();
2.p.put(Context.INITIAL_CONTEXT_FACTORY,
    "com.swiftmq.jndi.InitialContextFactoryImpl");
3.p.put(Context.PROVIDER_URL,"smqp://localhost:4001");
4.ctx = new InitialContext(p);
5.qcf = (QueueConnectionFactory)ctx.lookup("MyQCF");
6.oQueueConnection queueConnection = 
queueConnectionFactory.createQueueConnection();

코드를 나누는 방법

여러분들은 우선 벤더에 독립적인 코드가 몇 행을 더 가지고 있다는 점을 알아차릴 것이다. 이는 우리가 네이밍 서비스에 접속해야 하기 때문이다. 그러나 전체 프로그램에서 한번만 네이밍 서비스에 접속하면 된다는 사실을 염두에 두어야 한다. 따라서 추가적인 몇 행은 그 가치가 있다. (필요할 때마다 원격 context를 인스턴트화 하는 대신 네이밍 서비스를 재사용하도록 한다.)

네이밍 서비스와의 상호작용과 준비는 벤더에 중립적인 메시징 코드를 작성하는데 중요하다. 벤더에 의존적인 코드 예제에서 우리는 연결을 제공할 factory를 작성하기 위해 SwiftMQ 구현의 QueueConnectionFactory 생성자를 사용하였다. Listing 1의 1행에서와 같이, 이 구현을 위해 우리는 벤더에 독자적인 클래스를 포함시켜야 할 뿐 아니라 QueueConnectionFactory 생성자에게 특정 벤더에 국한된 매개변수도 보내야 한다.

벤더에 중립적인 예제에서, 특정 벤더에 국한된 코드는 없지만 우리는 초기 context factory와 네이밍 서비스를 제공하는 URL 뿐 아니라 QueueConnectionFactory의 바인딩 명도 알아야 한다. 바인딩 명의 경우 네이밍 서비스를 적절하게 유지하면 어떤 벤더가 제공하는 객체라도 여러분의 JNDI 트리에 바인딩시킬 수 있을 것이다. 따라서 벤더가 바뀌더라도 바인딩 명을 바꿀 필요가 없다. JNDI context의 경우 특성 파일에 매개변수 문자열 (Listing 2의 2행과 3행)을 저장하는 것이 일반적이다. 이렇게 하면 JMS 벤더가 바뀔 경우 간단히 특성 파일을 바꾸기만 하면 된다.

이 기법은 여러분에게 네이밍 서비스와 관련하여 유연성과 이식성을 제공한다는 점도 흥미로운 일이다. 많은 JMS 벤더 (Fiorano, SwiftMQ등)들이 자체적인 JNDI 서비스를 제공하지만, 여러분은 네이밍 서비스를 JMS 서비스에서 분리하고 싶어할 수도 있다. (예를 들어, 여러분은 여러분의 연결 factory를 중앙의 LDAP 서버에 저장하려 할 수 있다.)

다음은 각기 다른 JNDI 연결들을 가져올 특성 파일 엔트리의 예이다.:

  • java.naming.provider.url=smqp://myhost:4001
  • java.naming.factory.initial=com.swiftmq.jndi.InitialContextFactoryImpl

IBM WebSphere JNDI 서비스

  • java.naming.provider.url=iiop://myhost:9001
  • java.naming.factory.initial= com.ibm.websphere.naming.WsnInitialContextFactory

iPlanet 디렉토리 서버 (LDAP)

  • java.naming.provider.url=ldap://myhost:389
  • java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory

BEA WebLogic JNDI 서비스

  • java.naming.provider.url=t3://myhost:7001
  • java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory

File System JNDI 서비스

  • java.naming.provider.url=file:/tmp/stuff
  • java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory

여러분의 소스 코드는 벤더 클래스를 직접 참조하지 않을 수 있지만 벤더 클래스는 이름으로 JVM에 동적으로 로딩된다는 점에 주의하라. 따라서 실행 시에 여러분 프로그램의 클래스경로에 이들이 있어야 한다. JNDI와 JMS 클래스에서도 마찬가지이다.

특성 파일 설정하기

따라서 여기에서 우리는 JNDI 서비스에 연결하는 방법과 코드를 재컴파일하지 않고 상이한 JNDI와 JMS 구현으로부터 연결하는 방법을 알아야 한다. 특성 파일이 어떻게 설정되는지와 JNDI 연결에서 특성 파일이 수행하는 역할을 살펴보면서 지금까지 설명한 정보들을 종합해 보자.

JNDI 연결을 위한 기본 클래스는 javax.naming.InitialContext이다. InitialDirContext와 같이 디렉토리 작업에 국한된 InitialContext 의 하위 클래스도 있지만, 일반 클래스가 그 작업을 수행할 것이다. InitialContext 가 구축되면 환경 (시스템 특성이나 애플릿 매개변수)으로부터 JNDI 매개변수를 가져오거나 특정한 jndi.properites 파일을 찾는다.

이 작업은 J2SE 1.3.1 javadoc에 다음과 같이 설명되어 있다.:

JNDI는 다음 두 소스의 값을 차례로 합하여 각 특성의 값을 결정한다.

  1. 생성자의 환경 변수에서 처음 나타나는 특성과 (적합한 특성에 대한) 애플릿 매개변수와 시스템 특성

  2. 애플리케이션 자원 파일 (jndi.properties)

추가적인 특성들

지금까지 우리는 접속 제공자의 URL와 InitialContext factory 명(name)이라는 두개의 매개변수만 살펴보았다. 실제로는 훨씬 더 많은 특성 변수들이 제공될 수 있다. 우리가 살펴본 두 가지를 제외하고 가장 일반적인 것은 보안 처리된 JNDI store에 접근시 여러분의 신원을 확인해주는 사용자 명과 패스워드이다. 이 매개변수들은 다음과 같다.:

  • java.naming.security.principal (사용자명)
  • java.naming.security.credentials (패스워드)

파일 로딩하기

나는 여러분 애플리케이션의 모든 런타임 구성 매개변수를 하나의 애플리케이션 특성 파일에 두고 거기에 JNDI 매개변수를 포함시킬 것을 권한다. 모든 매개변수를 한 곳에 두면 불확실성이 없어진다. 그러면 여러분은 애플리케이션 특성 파일을 로드하기 위한 몇 가지 옵션을 가진다. 여기서는 두 가지 예를 들겠다. 파일은 자원 번들로 로딩될 수도 있고, 또는 명령행 매개변수로 특성 파일의 이름과 위치를 전달할 수도 있다.각 방식은 각기 다른 장점을 가지고 있다.

파일 위치를 명령행 매개변수로 전달하는 것이 여러분 코드를 구성하는 가장 쉬운 방법이다. 매개변수는 간단히 애플리케이션의 시동을 수정하여 변경시킬 수 있다.

자원 번들로 파일을 로딩하면 두 가지 이점이 있다.:

  • JVM의 위치에 따라 다른 자원 번들이 로딩될 수 있다. 예를 들어, application_en_US.properties 파일은 뉴욕의 JNDI 서비스를 가리키고, application_fr.properties 파일은 파리의 JNDI 서비스를 가리킨다.
  • 자원 번들에서 특성을 로딩하는 것은 아키텍처와 플랫폼에 독립적인 방법이다. 자원 번들은 클래스 경로로부터 로딩되기 때문에
    코드는 JVM의 명령행 매개변수를 읽을 수 있는지와 무관하다. 또한 EJB 컴포넌트와 같은 일부 컴포넌트들이 파일 입출력을 직접 이용하지 않기 때문에 자원 번들은 특성 파일의 내용을 로딩하는 더욱 편리한 방법을 제공한다.

상충되는 환경 설정에서 오는 혼란을 피하기 위해 나는 항상 내 특성 파일에서 읽은 JNDI 값으로 특성 인스턴스를 설정한다.

특성 파일 초기화 및 JNDI 검색

이 섹션에 나와 있는 코드는 특성 파일 초기화의 두 유형 (명령행 매개변수 및 자원 번들) 뿐 아니라 일반적인 JNDI 검색도 보여준다. 우선 Listing 3에 나와 있는 application_fr.properties라는 구성 파일 샘플을 살펴보자.:


Listing 3. PropertiesManagement.properties


java.naming.provider.url=smqp://localhost:4001
java.naming.factory.initial=com.swiftmq.jndi.InitialContextFactoryImpl
java.naming.security.principal=admin
java.naming.security.credentials=secret
com.nickman.neutraljms.QueueConnectionFactory=myQueueConnectionFactory
com.nickman.neutraljms.TopicConnectionFactory=myQueueConnectionFactory
com.nickman.neutraljms.Queue=testqueue@router1
com.nickman.neutraljms.Topic=testtopic

특성 파일 정의

이제 특성 파일을 읽기 위한 코드를 살펴보자. 앞에서 설명했듯이, 여러분은 JNDI 접속 매개변수를 결정하기 위한 두 가지 옵션을 가지고 있다. Listing 4는 JNDI 특성을 검색하기 위한 샘플 코드이다.:


Listing 4. JNDI 특성 조회하기


package com.nickman.jndi;
import javax.naming.*;   // For JNDI Interfaces
import java.util.*;
import java.io.*;
import javax.jms.*;
public class PropertiesManagement {
   Properties jndiProperties = null;
   Context ctx = null;
   public static void main(String[] args) {
     PropertiesManagement pm = new PropertiesManagement(args);
.
.
   public PropertiesManagement(String[] args) {
     jndiProperties = new Properties();
     if(args.length>0) {
       try {
         loadFromFile(args[0]);
.
.
     } else {
       try {
         loadFromResourceBundle();
.
.
   private void loadFromFile(String fileName) throws Exception {
     FileInputStream fis = null;
     try { 
       fis = new FileInputStream(fileName);
       jndiProperties.load(fis);
     } finally {
       try { fis.close(); } catch (Exception erx){}
     }
   }
   private void loadFromResourceBundle() throws Exception {
     String key = null;
     String value = null;
     ResourceBundle rb = 
       ResourceBundle.getBundle("PropertiesManagement");
     Enumeration enum = rb.getKeys();
     while(enum.hasMoreElements()) {
       key = enum.nextElement().toString();
       value = rb.getString(key);
       jndiProperties.put(key, value);
     }
   }

이 글에서의 작업시 참조하기 위해 전체 소스 코드 파일을 다운로드 받을 수 있다.

코드를 나누는 방법

Listing 4는 특성 파일을 두 가지 다른 방식으로 로딩하기 위한 코드를 보여준다. 명령행 매개변수가 전달되면 코드는 이것이 완전한 조건을 갖춘 특성 파일명이라고 가정하며, loadFromFile(String fileName) 메소드를 사용해 특성이 로딩된다.

클래스는 다음과 같이 호출된다. :


java com.nickman.jndi.PropertiesManagement 
c:\config\PropertiesManagement.properties

명령행 매개변수가 전달되지 않으면 코드는 loadFromResourceBundle() 메소드를 호출할 것이다. 이 메소드는 CLASSPATH에서 특성 파일을 찾는다. 따라서 클래스 경로에 이 파일의 디렉토리를 두어야 한다. 양 방식 모두에서 특성은 jndiProperties라는 특성 변수로 로딩된다.

I JNDI 서비스에 연결하기

Listing 5는 JNDI 서비스로의 연결을 보여준다. :


Listing 5. JNDI 연결


   public void connectToJNDI() throws javax.naming.NamingException {
     
     // jndiProperties was loaded from PropertiesManagement.properties
     ctx = new InitialContext(jndiProperties); 

     System.out.println("Connected to " + 
       ctx.getEnvironment().get(Context.PROVIDER_URL));
   }

위의 연결 코드는 아주 직접적이다. jndiProperties 변수는 InitialContext 생성자로 전달되고, 결과로 나오는 Context는 JNDI 서비스에 대한 일종의 "핸들"이다. javax.naming.Context 인터페이스가 사용 가능한 모든 환경 특성 변수들을 모두 표현하는 상수들의 셋트를 담고있다는 데 주의하는 것이 좋다.

구축된 Context로 우리는 Listing 6에서와 같이 JMS 객체 검색을 진행할 수 있다.:


Listing 6. JNDI 검색


   public QueueConnectionFactory lookupQueueConnectionFactory() 
        throws javax.naming.NamingException {
     return 
     (QueueConnectionFactory)ctx.lookup(jndiProperties.get
         ("com.nickman.neutraljms.QueueConnectionFactory").toString());
   }
   public Queue lookupQueue() throws javax.naming.NamingException {
     return 
     (Queue)ctx.lookup(jndiProperties.get
         ("com.nickman.neutraljms.Queue").toString());
   }

검색은 간단히 Context의 lookup(String name) 메소드를 호출하고, 우리가 원하는 객체가 바인딩될 이름으로 전달되는 과정이라고 볼 수 있다. 반환되는 객체는 올바른 클래스로 보내져야 하는데, 이 경우에는 표준 javax.jms 인터페이스중 하나가 될 것이다.

Destination 인터페이스

javax.jms.Destination 은 메시지가 전달될 특정 목적지를 캡슐화하는 인터페이스이다. QueueTopic 인터페이스는 모두 Destination 인터페이스를 확장한다. Destination 은 JMS가 관리하는 객체이기 때문에, Queues와 Topics도 마찬가지이다.

여러분은 JMS API가 Topic과 Queue 세션 클래스에 두개의 메소드를 가지고 있음을 알게 될 것이다.:

  • Topic TopicSession.createTopic(java.lang.String topicName)
  • Queue QueueSession.createQueue(java.lang.String topicName)

따라서 다음과 같은 질문을 던질 수 있다.: 하나의 문자열을 사용해 간단히 이를 참조할 수 있는데 왜 JNDI에 queue나 topic을 저장하는 수고를 해야 합니까? 그 이유는 아주 미묘하다.: 이를 이해하기 위해 javacdoc에서 다음을 인용하겠다.:

Destination 객체는 제공자(provider) 고유의 주소를 캡슐화한다. JMS API는 표준 주소 구문을 정의하지 않는다. 표준 주소 구문을 염두에 두더라도, 기존의 메시지 지향 미들웨어 (MOM) 제품들간의 주소 의미론간에 차이가 너무 커서 하나의 구문으로는 해결할 수 없다는 결론이 내려졌다.

Destination 은 관리되는 객체이기 때문에 자신의 주소 외에 제공자 고유의 구성 정보를 포함하고 있을 수 있다.

간단히 말해, 이것은 우리가 특정 JMS 제공자에 관한 상세사항을 JNDI에서 이름 공간을 검색하기 위해 사용되는 간단한 이름 뒤에 숨길 수 있다는 것이다. 나는 또한 JMS 클라이언트와 실제 JMS 목적지간에 중간층을 두면 아키텍쳐상에 추가적인 유연성이 주어진다는 것을 알았다. 클라이언트 코드는 myQueue라고 불리는 JNDI내의 이름공간을 참조할 수 있지만 관리자는 모든 벤더의 큐 수신지가 될 수 있는 객체를 그 이름공간에 할당할 수 있다. 이 개념이 그림 2에 나와 있다.


그림 2. 수신지 유연성
Destination Diagram





골치 아픈 topics

JMS의 publish-and-subscribe 프레임워크는 벤더에 중립적이 되려는 우리의 작업을 왜곡시키는 몇 가지 기능을 정의한다. 많은 JMS 서버가 계층적 이름 공간이라는 개념을 지원하는데, 이는 P/S 메시지가 하나의 계층으로 분류될 수 있게 한다. 토픽 구독 클라이언트가 JMS 서버에 접속하면 계층의 특정 부분에 해당하는 메시지를 요청할 수 있다. 그림 3에 설명된 계층을 예로 살펴보자.:


그림 3. 샘플 계층
Sample Hierarchy

이를 좀 더 잘 이해하기 위해 예제 시나리오를 사용해보자. 가령 구독자 클라이언트가 서비스 내에 있는 모든 미국 주가 정보를 구독하고 싶어한다고 가정해보자. 정적인 구독의 경우 클라이언트는 미국 주가를 구독하기 위해 사전 구성된 topic을 나타내는 JMS 관리 객체를 간단히 검색하기만 하면 된다. JMS 벤더들마다 계층적인 구독을 표현하기 위해 다른 구문을 사용하기 때문이 이것이 이상적인 방법이 될 것이다. 그리고 이를 JNDI가 검색하는 객체 뒤로 숨김으로써 클라이언트는 기반이 되는 JMS 구현을 알지 못할 것이다.

그러나 수백개의 다른 구독 "cell"을 제공하며 50개의 다른 단계를 포함하고 있는 한 계층을 생각해보자. 또한 그 계층이 동적이며 관리자가 이를 지속적으로 늘린다고 생각해보자. 그런 경우 JMS 관리자가 가능한 모든 구독을 표시하는데 필요한 JMS 관리 객체를 모두 생성하는 것은 불가능할 것이다. 더구나 계층 선택은 클라이언트 애플리케이션을 지원하도록 유연하고 동적이어야 한다.

이런 상황에서는 topic 명이 실행 시에 정의되도록 하는 것이 더 적합할 것이다. 문제는 계층을 표현하기 위해 사용되는 구문이 벤더마다 틀리다는 점이다. 다음 코드들은 세 개의 다른 벤더가 사용하는 구독 구문들이다.


MQSeries JMS


Topic topicEqUs = topicSession.createTopic("topic://Prices/Equity/US");
Topic topicEqAll = topicSession.createTopic("topic://Prices/Equity/*");


SonicMQ 3.5

Topic topicEqUs = topicSession.createTopic("Prices.Equity.US");
Topic topicEqAll = topicSession.createTopic("Prices.Equity.*");


SwiftMQ 2.1.3

Topic topicEqUs = topicSession.createTopic("Prices.Equity.US");
Topic topicEqAll = topicSession.createTopic("Prices.Equity.%");

MQSeries JMS 구현은 다른 두개의 구현과 다른 topic 구분자를 채택했다는 점에 주의한다. (거의 모든 다른 벤더들은 마침표를 사용하는데 MQSeries는 사선 표시를 사용한다.)

위에서 설명한 문자들과 별도로, topic 명에 나타날 수 있는 벤더마다 고유한 문자열들이 있다. 예를 들어, SonicMQ는 상위 계층을 구분하기 위해 파운드 기호를 사용하고, MQSeries는 보통 API용으로 남겨둔 옵션을 표현하기 위해 topic명에 접미사를 붙인다. 거의 모든 JMS 벤더들이 다른 와일드카드를 채택하고 있기 때문에 실행 시에 토픽 명을 일률적으로 정의하는 것이 어렵다. 다행히도 이 문제에 대한 해결방법이 있다. 모든 특수 문자를 하나의 참조 소스에 저장하고 이 소스에서 문자들을 로드하여 실행 시에 사용하는 것이다.

참조 소스는 여러분의 애플리케이션 특성 파일이 될 수도 있고 JNDI 서비스가 될 수도 있다. 이를 보여주기 위해 Listing 7과 같이 우리의 PropertiesManagement.properties 파일에 topic 문자를 추가할 것이다:


Listing 7. topic 문자가 추가된 PropertiesManagement.properties


#Topic Delimiter For  Sonic and Swift
com.nickman.neutraljms.TopicDelemiter=.
#Topic Delimiter for MQSeries
#com.nickman.neutraljms.TopicDelemiter=/
#Topic Wild Card For Sonic and MQSeries
com.nickman.neutraljms.TopicWildCard=*
#Topic Wild Card For Swift
#com.nickman.neutraljms.TopicWildCard=%
#Topic Prefix For MQSeries
#com.nickman.neutraljms.TopicPrefix=topic://
#Topic Prefix For All Others
com.nickman.neutraljms.TopicPrefix=

이들 엔트리가 추가되어 우리의 topic 구독 코드가 다음과 같이 되면 이 코드는 벤더에 독립적으로 될 것이다:


Listing 8. Topic 구독 코드


String delim = 
jndiProperties.get("com.nickman.neutraljms.TopicDelemiter").toString();
String wildcard = 
jndiProperties.get("com.nickman.neutraljms.TopicWildCard").toString();
Strung prefix = 
jndiProperties.get("com.nickman.neutraljms.TopicPrefix").toString();
Topic topicEqUs = topicSession.createTopic("Prices" + delim + 
"Equity" + delim + "US");
Topic topicEqAll = topicSession.createTopic("Prices" + delim + 
"Equity" + delim + wildcard);

일단 여러분이 Listing 7에 나타난 외부 설정을 끝내고 나면 여러분은 여타의 벤더 고유 옵션을 처리하도록 이를 확장할 수 있다. 예를 들어, JMS 사양은 한 세션이 구현할 수 있는 두 개의 배달 (delivery) 모드를 정의하지만, Sonic MQ는 세 개의 배달모드를 추가적으로 더 지원한다. 배달 모드를 외부에서 정의함에 따라 여러분은 Sonic MQ의 독자적 확장자를 구현하는 한편 여러분 코드의 벤더 중립성을 유지할 수 있다.


원문 출처 : http://www.ibm.com/developerworks/kr/library/j-jmsvendor/

2007/08/15 17:49 2007/08/15 17:49
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다