Visual Studio 에서 subversion 사용하기 개발


주로 java 프로그램을 하다 간만에 MS 제품군을 하게 되었는데  Java eclipse 플러그인으로 주로 사용해 왔던 Subversion 을 MS 제품군에서 플러그인 형태로 추가해서 사용하게 되었다.

가장 많이 쓰이는 프로그램은 AnkhSVN 이다.  http://ankhsvn.open.collab.net/

회원가입을 하고 다운로드 받을수 있다. 

AnkhSvn-2.5.12478.zip


설치한 플러그인을 사용하기 위해서는 비주얼스튜디오에서 Tool > Options > Source Control 를 선택하고 화면에서 Current source control plug-in 클릭하면 설치한 플러그인 리스트  AnkhSVN 을 선택한다.


서버 셋팅이 끝났다면 이제 Visual Studio 에서 연결을 하자.

project를 선택하고 우측마우스를 눌러 메뉴에서 Add Solution to Subversion 을 선택한다.

그러면 연결 화면이 뜨게 되는다.

서버의 trunk에 소스를 올려보자.



메일서버를 관리한다. - PostFix.admin 기본테마


시스템 운영자들은 유닉스(Unix)를 사랑하는데, 
그 툴들이 보통 맡은 일 하나는 제대로 처리해내기 때문이다. 
포스트픽스 메일 서버의 일상적인 관리를 돕는 웹 UI를 제공하는 포스트픽스 어드민(Postfix Admin) 역시 추천할 만 하다..

포스트픽스 어드민은 메일 서버 운영자가 마음놓고 일상적인 이용자 추가와 변경 업무를 
부하 IT 직원들에게 맡기기에 충분할 정도로 간단한 인터페이스를 제공한다. 
부하 직원은 큰 어려움이나 혼란 없이 사용자와 그 별칭들을 추가, 업데이트, 삭제할 수 있다. 
또한 포스트픽스 어드민은 휴가시 자동 응답 메시지를 작성하고, 서버 로그를 보고, 
심지어 새로운 도메인 추가까지 할 수 있게 해준다.


리눅스와 유닉스 백업 오픈소스 - Rsnapshot 기본테마


리눅스와 *BSD 시스템(바쿨라(Bacula), 아만다(Amanda), 아르케이아(Arkeia)) 등에는 백업을 위한 다양한 기능이 있다.
그중 하나는 Rsync 파일 미러링 유틸리티에 기반한 Rsnapshot 이다.

R스냅샷은 유닉스 하드링크(hard links)를 이용하여 
오직 네트워크 대역폭과 차등 백업의 디스크 공간만을 소비하면서도 
효과적으로 각각 스냅샷의 전체 백업을 유지한다. 
그 백업들은 테입이 아닌 백업 서버의 하드드라이브상 일반 파일 시스템에 저장되기 때문에, 
미디어 교체가 필요없다. - 대신 디스크의 프리 사이즈를 확인해야 한다 -

R스냅샷은 펄(Perl), R싱크, 하드링크 등의 흔한 유닉스 툴을 사용하기 때문에 
대부분의 유닉스류 운영체제에서 실행되고 
심지어 맥(Mac) OS X, 솔라리스(Solaris) 아이릭스(Irix) 등에서도 사용할수 있다.

ISP Control Panel - 시스템 호스팅 업체가 되어보자. 기본테마


구형 버추얼 호스팅 컨트롤 패널(Virtual Hosting Control Panel) 프로젝트에 기반한 
ISP 컨트롤 패널(ISP Control Panel)은 호스팅 서비스를 실행하기위해 만들어졌으며, 

ISP 서비스 운영자, 서비스 리셀러(service resellers), 최종 고객들을 위한 
분리된 제어 패널을 갖추고 있다. 

ISP 컨트롤 패널은 특정 서버 소프트웨어 앱 세트와 작동하도록 설계되었지만, 
웹 호스팅 회사를 운영할만한 거의 턴키식 시스템을 제공한다.

ISP 컨트롤 패널은 
호스팅 회사로부터 기대하는 발신자 정책 프레임워크(Sender Policy Framework) 기록, 
대역폭 사용 추적, 그레이리스팅(graylisting) 기능을 갖춘 스팸 필터링을 포함한 모든 서비스를 제공해준다. 

ISP 컨트롤 패널은 데비안(Debian)과 레드햇 리눅스(Red Hat Linux) 그리고 프리BSD(FreeBSD)를 확실하게 지원하며, 
자료를 보면 모든 리눅스나 *BSD등에서 실행 가능하다고 한다.


유넷부틴 - USB 리눅스를 가지고 다니자... 기본테마


소형 USB 드라이브에 리눅스를 설치하려고 했을 때, 
인터넷 검색의 설명을 참고하여 따라해보았고, 
무수한 실패를 경험했다. 

유넷부틴(UNetbootin) 프로젝트는 USB 드라이브에 
라이브 리눅스(Live Linux) 설치를 쉽게 셋업시켜준다. 

유넷부틴 드라이브를 사용하여 리눅스로 부팅하거나 
윈도우 PC상의 듀얼 부팅 옵션으로 리눅스를 설치할 수 있다. 
이는 리눅스를 들고 다닐 수 있는 손쉬운 방법이다.

나도 시간내서 함 해봐야지... 



윈도우 7 홈 프리미엄 원격데스크탑 RDP 설치 기본테마

1. 방화벽에 3389포드 개방

  ㄴ Control Panel > System and Security > Windows Firewall > Advanced settings > Inbound Rules > New Rule 까지 이동

  ㄴ Rule Type : Port > Protocol and Ports (TCP: 3389) > Action (Allow the connection) > Profile (전체체크) > Name (RDP PORT) > 완료


2. 컴퓨터 > 원격 > 원격지원

  ㄴ 이 컴퓨터에 대한 원격지원 연결 허용 체크


3. 첨부파일을 다운로드

4. install.cmd 실행

5. 터미널 접근 계정 설정

  ㄴ 비밀번호가 설정되어 있지 않으면 터미널 접근이 안되므로 접근 계정의 비밀번호를 설정함.

6. 재부팅


W7-SP1-RTM-RDP-v4.zip



Error Code 및 String을 ENUM을 사용해 보자... Java - 자바

다음과 같이 enum 을 정하면 됨...

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public enum Errors {

    NETWORK_ERROR("ERR_1001", "network error."),

    FILE_ERROR("ERR_2001", "file io error."),

    DB_ERROR("ERR_3001", "database error."),

    CLIENT_ERROR("ERR_4001", "client error.");

 

    private String code;

    private String desc;

 

    Errors(String code, String desc) {

        this.code = code;

        this.desc = desc;

    }

    public String getCode() {

        return this.code;

    }

    public String getDesc() {

        return this.desc;

    }

}

 

사용할때는 객체처럼 사용하는 것이 나을 듯...

catch (XXException e) {

    throw new MYNewException(Errors.DB_ERROR);

}

 

아래처럼 로그나 출력 가능...

System.out.println("[" + Errors.DB_ERROR.getCode() + "]" +  Errors.DB_ERROR.getDesc() );

 

Errors dbErr= Errors.DB_ERROR;

System.out.println(dbErr.getDesc() );

 


ZooKeeper 소개 개발

소개

일단 공식페이지로 가서 살펴보자.

아파치 주키퍼는 오픈소스이며 JVM위에서 동작하고 JAVA로 만들어져 있다. 신뢰할 수 있는 분산 코디네이터coodinator이며 설정 정보, 네이밍naming, 분산 동기화,그룹 관리를 제공한다고 공식 메인 페이지에 써있다. 그리고 일반적으로 알려져 있듯이 HBase에 통합되어져 있고 BookKeeper와 HedWig프로젝트와 관련이 있다.

주키퍼가 무엇인지 아직 감이 안온다면 이름과 다음 그림을 먼저 살펴보자. 주키퍼,동물원 사육사, 관리자다. 공식 페이지에도 이렇게 그림이 걸려 있다. 정말 동물원의 지배자 답게 늠름하지 않는가. 게다가 들고 있는 삽을 보자. 우리의 삽질을 대신 해줄것 같아 보인다. 보이고 있다. 보였다. 확실하다.

이 그림은 꽤 지나것이지만 나름 하둡 생태계에서 주키퍼의 위치를 잘 설명해 준다. 그래서 주키퍼는 어플리케이션들이 서로 잘 동작하도록 중재를 해주는 기능을 제공해준다. 그 기능이 분산 동기화, 그룹 관리, 설정 정보, 네이밍이고, 이 기능을 위한 각종 명령들operations이 제공되고, 이를 이용해 구현된 각 언어별 클라이언트 라이브러리들이 몇개씩 있을 수 있다. 그래서 구현되어 있는 기능과 성능은 구현 정도에 따라 차이가 날 수 있다.

성능

이 그림은 고수준의 주키퍼 내부의 서비스 구성을 설명한다. 주키퍼 앙상블(클러스터cluster)에는 쿼럼quorum 기반으로 선출된 리더와 그를 따르는 팔로워들이 있다. 주키퍼는 각각의 복제된 저장소를 자신이 가지고 있다. 읽기 요청은 자신의 저장소를 참조해 응답을 준다. 하지만 쓰기 요청은 리더에게 모든 요청이 전달되어 처리된다.

주키퍼는 메모리에 적재 되어 있기 때문에 대량 처리와 낮은 응답시간을 갖는다곤 하지만 분산 동기화라는 타이틀이 있기대문에 엄청나게 빠르진 않다. 아래 그림은 버전 3.2를 기준으로 측정된 내용이다. 측정 환경은 2Ghz 제온 CPU 두개, 15K RPM STAT 하드디스크 두개중 하나는 OS로 할당 하나는 로그전용으로 할당해서 사용되었다. 읽기 쓰기 요청은 각각 1K 씩 사용했으며, 30개의 클라이언트를 사용했다. 그리고 클라이언트들은 주키퍼 리더에게는 요청을 수행하지 않았다. 이 그림의 재미있는 점은 3대의 앙상블ensemble과 13대의 앙상블의 쓰기 성능 차이가 2배이상 난다는 점이다. 3대의 앙상블일 경우 쓰기는 초당 20K이상 읽기는 80K 이상이라고 그러져 있다. 그리고 앙상블의 크기가 늘어날 수록 쓰기 성능은 줄고, 읽기 성능은 늘어난다. 개인적으로 관심이 많은 Redis의 기본 명령들이 100K를 상회하는것 본다면 조금 느린 편이다. 하지만 분산 동기화와 고가용성의 관점에서 보면 당연하고 수용할만하다고 생각된다.

데이터 모델

/문자로 구분되어진 경로명은 일반적인 파일시스템과 유사하다. 하지만 ... 문자를 이용해 상대경로를 나태낼 수 없고 zookeeper라는 이름은 예약어 이기때문에 사용할 수 없다. 각각의 노드는 지노드znode라고 부른다. 주키퍼의 데이터 모델은 3가지 종류의 노드와 이벤트 감시자로 구성된다.

  • 일반 노드Nodes
  • 임시 노드Ephemeeral Nodes
  • 순차 노드Sequence Nodes
  • 이벤트 감시자Watches

일반 노드는 클라이언트가 명시적으로 생성, 삭제 해야 하고 자식 노드를 가질 수 있다. 임시 노드는 클라이언트의 세션이 끊어지면 삭제되고 자식 노드를 가질 수 없다. 순차 노드는 주키퍼가 알아서 순차적인 노드를 만들어준다. 순차 노드의 정보는 부모 노드가 가지고 있는데 이 말은 순차 노드 생성시 지정된 노드가 부모 노드가 된다는 이야기다. 이벤트 감시자는 각 노드들이 어떠한 이벤트가 발생 했을경우 이를 클라이언트에게 전달해 준다.

접근 제어 목록Access Control List

클라이언트는 접속시 다음 3가지 인증을 이용 할 수 있다.

  • Digest
  • Host
  • IP

이 인증을 기반으로 노드에 ACL을 설정 할 수 있다.

API

주키퍼의 디자인 목표중 하나는 간단한 프로그래밍 인터페이스를 제공하는 것이다. 그래서 다음과 같은 간단한 명령들operations을 제공하고 이를 이용해 더 높은 추상화를 제공하는 라이브러리를 이용 할 수 있다.

  • 노드를 특정 위치에 생성
  • 노드 삭제
  • 노드가 존재하는지 확인
  • 노드에 저장된 데이터를 읽기
  • 노드에 데이터 저장
  • 자식 노드 목록 조회
  • 데이터가 동기화되기 기다리기

REST 아키텍쳐에 대한 소개 개발

REST 아키텍쳐 소개


REST는 웹의창시자(HTTP) 중의 한 사람인 Roy Fielding2000년 논문에 의해서 소개되었다.

 현재의 웹 아키텍쳐가 웹의 본래 설계의 우수성을 많이 사용하지 못하고 있다고 판단했기 때문에, 웹의 장점을 최대한 활용할 수 있는 네트워크 기반의 아키텍쳐를 소개했는데 그것이 바로 Representational safe transfer (REST)이다.


REST의 정의


RESTHTTP URI + HTTP Method 라고 할 수 있다. URI로대상 Resource를 명시하고 Method로 해당 자원에대한 행위(Action)를 정의한다.


Resource

REST의 가장큰 특징중의 하나가 모든 자원을 표현한다는 것이다. ResourceHTTP URL에 의해서 표현되는데 javastudy 사이트의bcho 라는 사용자를 표현하면  http://www.javastudy.com/users/bcho 로 표현을한다. HTTP URI를 통해서 모든 Resource를 표현하는것이 가능하다.


Action

그렇다면 해당 자원에 대한 행동은 어떻게 표현 할 것인가?

이는 HTTP Method를 사용하여표현한다.

l   자바스터디 사이트의 bcho에 대한 회원 정보를 가지고 오고싶을때는
URI : http://www.javastudy.co.kr/users/bcho
Method : GET 

l   또는 해당 회원을 생성하고 싶을 때
URI : http://www.javastudy.co.kr/users/bcho
Method : POST
PayLoad
 <payload>
  <name>
조대협</name>
     :
 </payload>

l   해당 회원을 삭제하고 싶을 때
URI : http://www.javastudy.co.kr/users/bcho
Method : DELETE

l   해당 회원에 대한 정보를 변경하고 싶을 때
URI : http://www.javastudy.co.kr/users/bcho
Method : PUT
PayLoad
 <payload>
  <name>
조대협</name>
    :
 </payload>

HTTP 프로토콜에 정의된4개의 Method를 사용하여 자원(Resource)에 대한 CRUD를 정의한다.

 HTTP Method

의미

 

 POST

Create

 

 GET

Select

 

 PUT

Create or Update

 

 DELETE

Delete

 



REST의 문제점

그런데 사용할 수 있는 메서드가 4가지밖에 없다는 문제가 있다. 예를 들어 가입자 인증 처리라던가, 로그집계 처리와 같은 MethodHTTP Method로 표현하기가모호해진다.

기존의 프로그래밍 스타일이 Function이나 Method를 중심으로 한 행위 중심적인 접근이었기 때문에, REST가지향하고 있는 자원 기반의 접근에 맞지 않는 것이다. 오히려DBMS와 같이 CRUD를 가지고 있는 자원에 대해서는 적절하게적용된다. 이런 이유가 REST를 단순히 프로토콜이라고 부르지않고 아키텍쳐라고 정의한 이유다.

그렇다면 이 문제를 어떻게 해결해야 할 것인가?

사실 CRUD만으로 모든 행위를표현할 수 는 없다. Control성이나 함수성의 의미를 갖는 것들을 표현해야 하는데, 이런 경우는 HTTP/PUT이나 POST메서드를 사용하거나 또는 함수에 대한 의미를 재해석하는 접근이 필요한데. Send Mail을예를 들어보면 “메일을 보낸다” 라는 행위를 “누구한테 보내는 메일을 생성한다” 라는 의미로 바꾸면 다음과 같은 표현이 가능하다.

  HTTP/POST  http://www.xxx./sendmail/to/{emailaddress}

 그래도 문맥상으로 의미 변환이 불가능한 경우가 생긴다.

이런 경우는 HTTP/PUTURI를 사용하여 control의 의미를 부여한다. 사용자 ID bcho에 대한 등급 변경을 하는 경우는 다음과 같이표현할 수 있다.

예를 들어 http://www.xxx/users/bcho/upgrade

사실상 REST 기반의 아키텍쳐를설계하려면 가장 어려운 것이 이 URI를 어떻게 정의하는 것이다. REST의장점 중 하나는 이 URIHTTP Method만으로도쉽게 의미를 파악할 수 있다는 것이기 때문에, URI 정의에 많은 노력을 기울이는 것이 좋다


장단점


REST의 장점


기존의 웹 인프라를 그대로 이용할 수 있다.

가장 큰 장점중의 하나일거다. 기존HTTP를 그대로 사용하기 때문에, Remote Call을할때도 방화벽을 새로 뚫어야 하느니 등의 요건이 없고, L4등의 부하 분산 장비들도 그대로 사용이 가능하다.

무엇보다. 웹캐쉬 서버를 그대로사용할 수 있다. 모든 ResourceURIUnique하게 표현되기 때문에, 웹 캐쉬 상에 보관될 수 있고, 특히나 SELECT성의 Operation은 캐쉬에 의해서 바로 리턴될 수 있으므로, 성능과 리소스 활용 측면에서 장점을 가지고 있다.


쉽다.

웹서비스와 비교해보면 웹서비스는 스펙이 정말 많다. WS*-I, WS Reliable Messaging, WS Transaction 등등 스펙 덩어리다. 그러나 REST는 별도의 SPEC이없다. 보통 Defactor 표준이라고 하는데, HTTP URIMethod만 잘 지켜서 사용하면 그게 REST.


REST의 문제점


표준이 없다. 즉 관리가 어렵다.

REST가 요즘들어 부각되는 이유 자체가 WebService의 복잡성과 그 표준의 난이도 때문에 Non Enterprise 진영 (Google,Yahoo,Amazone) 을중심으로 집중적으로 소개되었다. 데이터에 대한 의미 자체가 어떤 비즈니스 요건 처럼 Mission Critical 한 요건이 아니었기 때문에 서로 데이터를 전송할 수 있는 정도의 상호 이해 수준의표준만이 필요했지 Enterprise 수준의 표준도 필요하지 않았고,벤더들 처럼 이를 주도하는 회사도 없었다.

 단순하여 많이 사용되고 암묵적으로 생겨난 표준과 유사한 Defactor 표준있을 뿐이다. 그런데 문제는 정확한 표준이 없다보니, 개발에있어서 이를 관리하기가 어려워진다는 것이다. 표준을 따르면 몇가지 스펙에 맞춰서 개발 프로세스나 패턴을만들 수 가 있는데, 이는 표준이 없으니, REST 기반으로시스템을 설계하자면 사용할 REST에 대한 자체 표준을 정해야 하고,어떤 경우에는 REST에 대한 잘못된 이해로 인하여 잘못된 REST 아키텍쳐에 이건 REST다 라는 딱지를 붙이는 경우가 많다. 실제로 WEB 2.0의 대표 주자 격인 Flickr.com REST의 특성을 살리지 못하면서 RPC 스타일로 디자인한 APIHTTP+ XML을 사용했다는 이유로 Hybrid REST라는 이름을 붙여서 REST 아키텍쳐에 대한 혼란을 초래했다.

. FlickrHybrid Rest는 어떤 Operation을 처리할 때,

 http://URL/operation?name=operationname 과 같은 형태로 메서드를 Query String으로 넘기는 형태를 사용했다. 언뜻 봐서는 RESTful한 디자인 같지만, 모든 ResourceURI는 같고 operationQuery String으로 나눈 것에 불과 하기 때문에, 모든 Resource Unique URI를 부여하는 REST의 원래 설계 원칙과 벗어난다.

 그런데, 국내에는 이런 형태의 디자인을 REST로 이해하고 있는 사람들이 많은 것 같아서 걱정이고 몇몇 포탈에서도 이런 형태의 서비스를 제공하는 것으로 알고 있다.

 

REST적인 접근과 설계가 필요하다.

위에서도 잠깐 설명했지만, RESTWebService와 같은 프로토콜이 아니다. REST는아키텍쳐이다 Resource를 기반으로 하는 아키텍쳐이기 때문에 시스템 설계도 Rest 에 맞는 설계가 필요하다.


Alternative Key의 사용

예를 들어 Resource를 표현할때이러한 ResourceDB의 하나의 Row가되는 경우가 많은데, DB의 경우는 Primary Key가복합 Key 형태로 존재하는 경우가 많다. (여러 개의 컬럼이묶여서 하나의 PK가 되는 경우) DB에서는 유효한 설계일지몰라도, HTTP URI/ 에 따라서 계층 구조를 가지기때문에, 이에 대한 표현이 매우 부자연스러워진다.

예를 들어 DBPK가 “세대주의 주민번호”+”사는 지역”+”본인 이름일 때” DB에서는 이렇게 표현하는 것이 하나 이상할 것이없으나, REST에서 이를 userinfo/{세대주 주민번호}/{사는 지역}/{본인 이름} 식으로표현하게 되면 다소 이상한 의미가 부여될 수 있다.

이외에도 resource에 대한UniqueKey를 부여하는 것에 여러가지 애로점이 있는데, 이를 해결하는 대안으로는 Alternative Key (AK)를사용하는 방법이 있다. 의미를 가지지 않은 Unique ValueKey로 잡아서 DB TableAK라는 필드로 잡아서 사용 하는 방법인데. 이미 Google REST도 이러한 AK를사용하는 아키텍쳐를 채택하고 있다.

그러나 DBAK 필드를 추가하는 것은 전체적인 DB설계에 대한 변경을 의미하고이는 즉 REST를 위해서 전체 시스템의 아키텍쳐에 변화를 준다는 점에서 REST 사용시 아키텍쳐적인 접근의 필요성을 의미한다.

사실 그외에도 REST적인 설계를하기 위해서는 Resource간의 관계를 href(링크)로 표현하는 기법,Versioning방법,Naming Rule, ESB를 이용한 Cross cuttingconcern의 처리와 Routing 등 여러가지 고려 사항이 있으나, 아키텍쳐 설계 방법과 고급 REST에 대해서는 다음 기고 (고도화된 REST 아키텍쳐)에대해서 논의 하기로 하겠다.


REST에 대한 잘못된 인식


REST = HTTP + XML 프로토콜 이다?

대부분의 사람들의 REST에 대한이해는 RESTHTTP를 써서 XML을 보내면 REST라고 생각하고 있다. 절대 아니다. REST는 웹의 특성을 활용하여 자원을 리소스로표현하는 아키텍쳐이다.(프로토콜이 아니다) 물론 HTTP는 사용해야 한다. 그러나 XML은필수가 아니다. JSON이나 YAML과 같은 다른 표현 언어를사용해도 무방하다. 리소스에 대한 표현과 웹의 특성을 얼마나 잘 활용했는가가 REST 아키텍쳐를 제대로 이해하는가에 대한 판단 기준이 될 것이다.


RESTWebService보다 쉽다.?

사실 그렇지도 않다. 맨 바닥에서개발한다면야 REST가 더 쉽다. 자체 표준을 만들어서 Simple XML로 메시지를 정의해서 단순히 HTTP로만 보내면 되니까.. 그런데 이건 서비스 제공자 입장이다. 서비스를 사용하는 입장에서는HTTP Client로 요청을 보내서 리턴받은 XML이나JSON 데이터를 일일이 파싱해서 처리해야 한다.

 그런데 WebService는 이미 정해진 표준 덕분에 POJOJAX-WS등으로 코딩만 하면 자동으로 웹서비스가 생성되고WSDL에 의해서 정해진 서비스 Contract에 의해서Client Stub을 자동으로 생성할 수 있으므로, 프로토콜Spec을 몰라도 마치 Java Library를 호출해서사용하는 것처럼 쉽게 사용할 수 있다.

개발자 입장에서는 REST보다는WebService개발이 더 쉬워 보인다. 가장 쓰기 좋은것은 복잡도가 낮고 잘 정리된 WS-I 기반의 WebService를사용하는 것이 가장 간단하고 생산성 면에서 좋다.


REST의 전망

국내에서는 아직 REST에 대한수요가 그다지 많지는 않다. 복잡도가 높은 시스템 설계를 기피하는 현상때문인지.. 아니면 아직 개방형 시스템에 대한 수요가 많지 않아서인지…

그러나 이미 해외의 유수 사이트들은 REST기반의 아키텍쳐를 통해서 서비스 하고 있으며 대표적인 Open API 업체중의 하나인 Amazon역시 기존에 WebService로 개발되어 있었던 Open API들을 REST 기반으로 Migration할 계획이다. RESTDefactor표준이기는 하지만 웹세상에서는 이미 무시하기 어려운 표준으로 자리잡아 가고 있다.

또한 이렇게 오픈 진영에서 탄생한 RESTJ2EE Spec중의 하나인 JAX-RS(JSR311)로 추가되어 다음 JEE6 버전에 포함될 예정이다. (오픈 소스로는 SunJersey라는 프레임웍과 Apache CXF에 포함도어 있다. 그리고Spec화 된다해도 어디까지나 구현 방법에 대한 Spec이지REST가 가지고 있는 그 자유도는 매우 높다. ) REST에대한 표준화의 일환으로 WebServiceWSDL과 유사한WADL이라는 Spec이 나오기는 했지만 REST 서비스의 URI정도를 표현하는 뿐이지, 실제 Operation안에 들어가는 MessageScheme등을 표현하고 있지 않고 있기 때문에 여전히REST에 대한 Service Contract 표준은 없다고보는 것이 맞을 것이고 이것이 앞으로 장점이 될지 단점이 될지는 판단하기 어렵다.


결론


REST는 그단순성과 웹의 특성을 최대한 활용한다는 장점 때문에 해외에서는 이미 급격하게 전파되고 있으며 오픈 진영에서 개발된 기술로는 드물게 표준기술(JSR-311)로 채택되는 사례까지 만들었다.

그러나 그 높은 자유도로 개발이나 관리가 어려워 아직까지 널리 사용되지 못하고서비스 시스템 위주로 사용되고 있으며, 국내에서는 REST에대한 이해 부재와 Open API 라이브러리 부족으로 아직까지는 잘 사용되고 있지 않다.

 해외에서는 이미 여러 서비스 업체들이 REST 기반의 서비스를주류로 하고 있으므로 국내 개발자들도 REST에 대한 공부를 해야 하지 않나 싶다.

 


visualSVN에서 백업 및 복구하기 CVS


VisualSVN Server 에서 직접 UI로 하는 방법은 없고 svnadmin 을 사용한다,

백업하기
  1. Start command prompt interpreter.
  2. Perform the following command:
    PATH-TO-SVN\svnadmin dump PATH-TO-REPO > PATH-TO-DUMP
    where
    • PATH-TO-SVN - path to your old Subversion installation;
    • PATH-TO-REPO - path to the repository folder;
    • PATH-TO-DUMP - full path to the dump file.

    For example:

    c:\Program Files\Subversion\bin\svnadmin dump c:\repositories\Contoso > c:\repo.dump

    Depending on the repository size, this operation can take considerable time. You can watch the status output of the operation in your terminal window.

    Warning
    ImportantRepository dump should be created using the svnadmin utility from the corresponding Subversion installation used to create this repository.

복구하기
  1. Create new empty repository. To do that:
    1. Open VisualSVN Server Manager by selecting Start | All Programs | VisualSVN and clicking VisualSVN Server Manager;
    2. Right-click the Repositories node and select Create New Repository;
    3. Specify the name for the new repository;
    4. Do not select the Create default structure (trunk, branches, tags) check box as repository should be empty; * 중요함 *
    5. Click OK.
  2. Load a repository dump stream from the created dump file performing the following command:
    "%VISUALSVN_SERVER%\bin\svnadmin" load PATH-TO-NEW-REPO < PATH-TO-DUMP
    where
    • PATH-TO-NEW-REPO - path to the created repository folder;
    • PATH-TO-DUMP - full path to the dump file.
    Note
    Notes
    • To be sure that the correct Subversion version (the one provided with VisualSVN Server) is used to load the dump, use the %VISUALSVN_SERVER% environment variable to locate the svnadmin executable file. Alternatively, to locate the correct version of svnadmin executable, you can use the Start a new instance of command interpreter command on the VisualSVN Server Manager toolbar to launch the terminal window.
    • The Subversion repository dump format describes versioned repository changes only. It will not carry any information about uncommitted transactions, user locks on file system paths, repository or server configuration customizations (including hook scripts), and so on.

    After performing this command, all the data from the existing repository will be moved to the new one and the new repository will be available for use with VisualSVN Server.




JEUS 6.0 fix#8 설정 및 JNDI / JMX 샘플 테스트 개발

JEUS 6.0 fix#8 설정

 

1.    JEUS 설치 매뉴얼 참조

2.    Example url test

3.    Webamin 설정 포트, 파일 등 매뉴얼참조

A.    JEUSMain.xml

B.     Accounts.xml

4.    Webamin - Jdbc 설정

5.    Ojbdc?.jar 파일을 lib/datasource에 복사하고 JEUS 서비스 재부팅

A.    Jeusadmin 에서 jeusexit 하고

B.     Jeus 다시 실행

6.    Jeusadmin john-PC

A.    User : administrator

B.     Password : cjsvkfqordl (천팔백이)

7.    Sample monitor 실행하려는데 빌드오류 발생

A.    라이브러리 찾아서 맞추어야 함

                        i.        \TmaxSoft\JEUS6.0\lib\client\clientcontainer.jar

                       ii.        \TmaxSoft\JEUS6.0\lib\client\jclient.jar

                      iii.        \TmaxSoft\JEUS6.0\lib\client\jclient_jaxb.jar

                      iv.        jeus.jar

                       v.        jmxremote.jar

                      vi.        jmxtools.jar

                     vii.        javax.management.j2ee.jar

                    viii.        jeusjaxb.jar

                      ix.        javax.jms.jar

                       x.        jaxrpc-api.jar

                      xi.        jaxrpc-impl.jar

                     xii.        jaxrpc-spi.jar

                    xiii.        jeusapi.jar

                    xiv.        jeusutil.jar

                     xv.        javaee.jar

B.     javax.management.j2ee.statistics를 사용하려면 JEE JDK (GlassFish) 설치하고 module에 있는 javax.management.j2ee.jar 를복사해서 넣어야 함

8.    JEUS Client Library를 프로젝트라이브러리 추가하고 실행해야 함(CLASSPATH)

9.    JNDI 연동하고 MBean으로 바꿔서 사용하는게 가장 좋음.


WAS별 RMI통신 개발


1. BEA WebLogic (8.x)

    1) INITIAL_CONTEXT_FACTORY : weblogic.jndi.WLInitialContextFactory

    2) PROVIDER_URL : t3:/127.0.0.1:7001

    3) 필요한 jar : weblogic.jar (?)


2. IBM WebSphere

    1) INITIAL_CONTEXT_FACTORY : com.ibm.websphere.naming.WsnInitialContextFactory

    2) PROVIDER_URL : iiop://127.0.0.1:2809

    3) 필요한 jar : ibmorb.jar (+ a)

 

3. Tmax JEUS (4.x)

    1) INITIAL_CONTEXT_FACTORY : jeus.jndi.JEUSContextFactory

    2) URL_PKG_PREFIXES : jeus.jndi.jns.url

    3) PROVIDER_URL : 127.0.0.1:9736

    4) SECURITY_PRINCIPAL : jeus 사용자ID

    5) SECURITY_CREDENTIALS : jeus 패스워드

    6) 필요한 jar : jeus.jar  jmxri.jar


4. Tmax JEUS (5.x)

    6) 필요한 jar : 

jaxb-api.jar jaxb-impl.jar jaxb-libs.jar

jeus.jar jeusjaxb.jar jeusmbean.jar

jeusutil.jar jmxremote.jar jmxri.jar


5. JBoss (3.x)

    1) INITIAL_CONTEXT_FACTORY : org.jnp.interfaces.NamingContextFactory

    2) PROVIDER_URL : 127.0.0.1:1099

    3) 필요한 jar : jboss-j2ee.jar  jnp-client.jar  jbossall-client.jar  jboss-j2ee.jar



IT 경력 관리 개발

새해가 시작됐다. 2012년은 IT 업계 종사자들에게 있어서 정신 없는 한 해였고, 2013년도 그에 못지 않을 것으로 보인다. 그러나 더 많은 회사들이 성장하기 시작하고 직원을 확충함에 따라 IT 인력 시장이 서서히 힘을 받고 있기 때문에, 이를 준비하던 이들은 계획을 행동에 옮길 준비를 하고 있다.

현재 IT 직장이나 임무에 만족하고 있다 할지라도, 인력 감축이나 아웃소싱, 혹은 구조조정으로 인해 올해 새로운 일자리를 찾아야 될 가능성도 있다.

최근 통계에 따르면, 한 직장에서 일하는 기간은 지난 10년간 꾸준히 감소하여 현재 평균 4.4년에도 미치지 못하고 있다. 평생 직장의 시대는 말 그대로 끝났다. 그렇다면 IT업계를 관통하고 있는 혼란과 해직으로부터 자신을 보호하려면 어떻게 해야 할까? 무엇이든 준비가 되어있어야 한다. 진보를 멈춰선 안된다. 기술의 발전에 따라 함께 진화하던가 뒤쳐지던가, 선택은 자신의 몫이다. 여기 준비한 2013년 경력 관련 조언들을 참고하면 도움이 될 것이다.

1 자신의 업계를 더 잘 이해하기 위해 힘써라
“당신이 어떻게 어디에 들어맞는지 세부적으로 파악하고, 어디에서 어떻게 도움이 될 수 있는지를 알아야 한다. 그럴 수 있다면 당신의 가치를 모두가 인정해줄 것이다”라고 커리어 퀘스트(Career Quest)의 회장이자 고급 커리어 전략 전문가인 로스 맥퍼슨은 강조했다.

세계 최고의 프로그래머라고 하더라도, 회사가 진정 원하는 인재는 사업적 측면까지도 이해할 수 있는 사람이다. 그러므로 행사에 참석하고, 구글 뉴스 알리미(Google News Alerts)에 업계 키워드를 설정해두거나 링크드인(LinkedIn), 야후(Yahoo) 그룹에 가입하여 참여하라. 업계에서 무슨 일이 일어나고 있는지를 알게 되면, 경쟁상대들을 앞서는데 큰 도움이 된다.

“인생의 많은 실패는 성공이 얼마나 가까운지 모르고 포기할 때 생긴다” – 토마스 에디슨

2 커리어 지도를 그려라
오늘날의 많은 회사들은 규모에 상관없이 IT 인력을 위한 경력 진로를 제대로 제시하 못한다. 그렇기 때문에 스스로 커리어 진로를 만들어 내야 한다. 스스로의 계획이 강점과 약점을 결정하고 명확한 커리어 목표를 파악하는데 도움을 줄 수 있다.

맥퍼슨은 “그 어떤 이도 자신의 커리어를 책임져 주지 않는다. 회사도, 상사도 아닌 오직 자신만의 책임이다. 훌륭한 커리어를 설계하고, 그대로 실현시켜라”라고 말했다.

개인 커리어 지도는 아래 사항들을 포함해야 한다:

- 지금까지 거친 작업과 역할을 나열한 직원 프로필(세부적이어야 한다)
- 회사 내외에서의 위치를 포함하는 아이디어나 목표
- 자신의 기술력에 대한 분석과 기술 격차를 줄이기 위한 계획
- 같이 일하고 필요할 때 조언을 구할 수 있는 전문가 인맥

스스로의 커리어 지도를 작성하는 것은 구직 활동에도 도움을 줄 것이다.

“당신의 운명을 통제하라. 그렇지 않으면 다른 이가 당신을 통제할 것이다.” – 스티브 잡스

3 이력서를 업데이트하라
이력서에 최근의 변경사항까지 모두 기재하여 언제나 바로 쓸 수 있게 준비해두면, 마음에 평안을 주는데 도움이 될 수 있다. 가끔씩 확인하고 업데이트해두는 것은 중대한 시점에서 이력서를 완전히 새로 뜯어 고치는 것보다 훨씬 수월한 일이다.

“이력서는 마케팅 문서다. 당신의 전문성을 팔아야 하고, 자격을 갖춘 경쟁자들 사이에서 두각을 드러내야 한다”라고 맥퍼슨은 이야기했다.

관심 있는 직위를 염두에 두고 이력서를 작성하고 그 위치에 적절하게 쓰일 수 있는 기술을 강조하라. 구직 게시판을 살펴보고 채용담당관들이 어떤 키워드를 사용하고 있는지를 파악하여 그 키워드를 이력서에 끼워 넣어라. 영예로운 일, 수상내역, 모든 자선활동 등을 이력서에 포함하라. 세미나나 수강 내역 등 역시 종종 여기에서 간과하기 쉬운 부분이다.

이런 이력서 작성 방식을 두고 씨름하고 싶지 않다면? 수많은 커리어 서비스 회사들이 있다. 이력서를 다듬거나, 소셜 존재감을 구축할 때, 혹은 커리어를 완전히 변화시키는 경우에 모두 도움을 줄 수 있다.

“당신이 사랑하는 직업을 택하면, 평생 일을 안해도 된다.” – 공자

4 브랜드를 위해 개인 웹사이트를 구축하라
IT업계에서 일한다면, 웹은 생활의 일부다. 웹사이트는 이전에 일했던 작업과 제품 정보들을 많이 보여주고 싶은 사람들에게 가장 알맞은 접근방식이다. 맥퍼슨의 충고다. “당신의 웹사이트를 데이터 저장소로 만들지 말고, 역동적이고 당신의 가치를 팔 수 있는 장소로 만들라.”

그렇다. 고려할 사항이 많다. 호스팅, 도메인 이름, 콘텐츠 제작, 프로그래밍, 관리, 그리고 비용까지. 그러나 커리어가 당신에게 얼마나 중요한가를 묻지 않을 수 없다. 여기에서도 더 많이 투자할수록 더 많은 것을 얻을 수 있다. 당신의 SEO 랭킹을 올리는 것 또한 추천한다.

이미 웹사이트를 운영하고 있다면, 업데이트가 필요한 시점일지 모른다. 먼저 연락처 정보를 쉽게 찾을 수 있도록 하라. 또한 이력서와 자기소개서에 URL을 포함할 수도 있다. 현재 IT 실업률은 3.6%로, 기술 시장에서의 경쟁은 치열하다. 개인 브랜드를 구축하는 것은 이 난국을 돌파하는 좋은 수단이 될 수 있다.

“스스로를 커리어의 설계자가 아닌 조각가로 생각하라. 커리어에 수많은 망치질, 끌질, 긁어내기와 연마가 들어가야 한다는 점을 명심하라.” –B.C.포브스

5 소셜 프로필을 만들거나 정제하라
소셜 네트워킹 프로필은 기술 분야 채용에서 핵심사항이 되었다. 이로 인해 구직의 성패가 갈리기도 했다. 소셜 네트워킹에 가입을 주저해왔다 하더라도, 이제 더 이상 피하긴 힘들다. 트위터(Twitter), 페이스북(Facebook), 링크드인, 구글플러스(Google+)는 검색 트래픽, 웹 존재감, IT 채용에 점점 관련도가 높아져감으로써 피할 수 없는 필요악이 되었다.

채용담당자들과 회사들은 구직자들의 소셜 네트워크로부터 정보를 캐내어 채용 적입자를 찾는데 점점 더 능숙해져 가고 있다. 맥퍼스은 “훌륭한 온라인 존재감/브랜드를 구축하고, 유지하고, 키워나가면, 기회가 스스로 찾아올 것이다”라고 조언했다. 프로필을 업데이트 해두고, 전문가처럼 보이도록 꾸며놓으면 다음 직장이 저절로 굴러들어올지 모른다.

자신을 구글이나 빙(Bing)으로 검색하여 어떤 결과물이 뜨는지 확인해보라. 거기에 부정적 내용이 뜬다면? 검색을 통해 회사에 관련된 최대한의 정보를 찾는 것과 마찬가지로, 인사부 직원들 역시 면접 전에 동일한 검색을 통해 당신에 대한 정보를 찾을 것이다. 예전에 남겼던 바보 같은 댓글, 계류중인 소송, 좋지 못한 사진 등, 어떠한 검색 결과가 나오더라도, 어떻게 제대로 설명하여 이 문제를 극복할지 먼저 준비해야 한다.

 “하루에 8시간씩 성실하게 일한다면, 결국에는 상사로 진급해 하루에 12시간씩 일하게 될 것이다.” – 로버트 프로스트

6 사회적 인맥을 구축하라
이런 속담 들어봤을 것이다, “당신이 무엇을 아는지보다, 누구를 아는지가 중요하다.” 링크드인과 페이스북상의 브랜치아웃(BranchOut)같은 전문가 네트워킹 사이트들이 등장하면서, 전문가 인맥을 키울 수 있는 수많은 방법들이 쏟아져 나왔다.

맥퍼슨은 “인맥만들기는 여전히 기회를 잡는 최고의 방법이며, 얼굴을 맞댄 직접적인 교류 또한 놓쳐선 안된다”라고 말했다.

예를 들어 링크드인을 이용해 목표 회사를 팔로우할 수 있다. 당신과 이전에 함께 일했거나 존경하는 사람들과 연결을 시도하라. 링크드인에서 찾을 수 있는 업계 리더들도 아주 많다. 그들을 팔로우하며 그들과 연결을 유지하라. 그룹에 가입하거나 일종의 대화 등에 끼어들어라. 상당히 많은 일 같아 보이고, 사실이 그렇기도 하지만, 그렇게 하는 것이 당신이 찾던 “풋 인 더 도어(문틈에 발 끼우기)” 전략으로 작용할 수 있다.

“많은 이들에게, 직업은 수입처 그 이상이다. 당신이 누구인지를 알려주는 중요한 단서다. 그러므로 커리어 전환은 당신의 인생에서 맞이할 수 있는 가장 불안한 경험의 일종이다.” 폴 클리세로

7 후속조치 실력을 향상시켜라
“제대로 된 후속조치는 핵심이다. 제때에 이뤄져야 하고 항상 프로다워야 한다”라고 맥퍼슨은 강조했다. IT같은 경쟁적인 구직 시장에서 자신의 운명을 운에 맡기고 싶진 않을 것이다. 후속조치를 향상시켜 인사부 사람들의 생각 속에 당신의 이름을 계속적으로 각인시켜야 한다. 면접 후 감사 인사장을 보내고, 명함을 교환하라.

몇몇 전문가들은 면접 후에 다시 사측에 연락하기까지 이삼 주 정도는 기다릴 것을 추천한다. 다른 누군가 그 자리를 차지했을 수도 있지만, 새로운 자리가 항상 나오기 때문이다. 후속조치와 연락 유지를 통해서, 당신이 지원하지 않았던 역할에 기회가 주어질 수도 있다.

“좋은 관리자는 자신의 커리어보다 자신을 위해 일하는 이들의 커리어를 걱정하는 사람이다.” – H. S. M. 번스

8 자기 소개서를 개인화하라
자기 소개서는 당신의 메시지를 개인화하기 위한 것이다. 소통 능력뿐 아니라 지식을 고용주와 채용담당자들에게 보여줄 수 있는 장이다. 개인적 경험과 지식이 어떻게 회사에 가치를 더해줄 수 있을지에 대해 설명하는데 자기 소개서를 사용하라. 자기소개서가 설득력이 있다면 누군가 그것을 읽을 가능성이 크다.

자기 소개서에 오자가 생기지 않도록 확인하라. 확신이 없다면 친구나 동료에게 읽고 확인해달라고 부탁하라. 구인 공지에 담당자 연락처가 올라와있다면, 그에게 자기 소개서를 보내라. 자기 소개서에 관련한 맥퍼슨의 충고는 간단하다. “간략하고 요점만 포함시켜라. 긴 문단을 피하고 자신의 자질과 관심사를 명료하게 기술하라.”

“당신이 가장 잘하는 것을 찾아내고, 그 일을 할 때 돈을 줄 사람을 찾아라.” – 캐서린 화이트혼

9 지평을 넓혀라
“성장하고 있지 않다면, 당신은 죽어가는 것이다. 성장하고 확대하며 당신 스스로를 가치 있는 사람으로 만들라”라고 맥퍼슨은 말했다. 안전지대를 벗어나서 새로운 무언가를 배워라. 당신에게 주어진 옵션들 중에서도 돈이 들지 않는 것들도 많다. 도서관에 가던지, 현지 수업, 대학 강좌 혹은 강연, 세미나 등 여러 가지가 있다. 무엇보다도 배우고 성장하는 것을 멈추면 안된다.

“당신의 일을 발견하고 거기에 전념하는 것이 당신이 일이다.” – 부다



Drools 소개: Rule을 바라보는 새로운 관점 Java - 자바

Drools 소개: Rule을 바라보는 새로운 관점

작성자: Jaroslaw Kijanowski

오랜 기간 함께 일해 온 기고가 중 한 명이 폴란드에서 활동하는 JBoss QA 엔지니어인 Jaroslaw를 소개하면서, 그가 매우 흥미로운 자료를 작성하고 있다고 전해왔습니다. Jaroslaw의 첫 번째 기고문인 이 문서는 복잡한 Rule  Engine의 비밀을 파헤치고 있습니다. 여러분은 DroolsJBoss Rules또는 JBoss Drools으로 불리는 이 Rule Engine이 어떤 일을 하며, 그것을 여러분의 프로젝트에 어떻게 적용할 수 있을지에 대해 알고 싶어할 것입니다. (이 기고문은 논리적이면서도 흥미로운 내용을 포함하고 있기 때문에, 어려운 단어 퍼즐이나 난해한 수학 문제를 좋아하는 사람이라면 재미있게 읽을 수 있을 것입니다.).

여기서는 그의 기고문 전문을 트랙백과 함께 모두 제공하며, 원문은 Jaroslaw의 사이트에서 확인할 수 있습니다. 본아티클은 독어와 폴란드어로도 제공됩니다.

이 글의 목적:

개발자, 아키텍트 또는 비즈니스 분석가라면 최소한 본 기고문의 제 1장은 알아둘 필요가 있습니다. 여기에는 특정 어플리케이션의 가독성을 높이고 이들의 관리 및 유지 보수를 쉽게 만들어주는 Rule Engine에 대해 소개하고 있습니다. Rule Engine은 특정 이벤트나 메모리 내 일부 객체의 상태에 따라 의사 결정을 수행하는 어플리케이션에 적용됩니다.

개요:

 이 기고문은 Rule Engine에 대한 소개, Eclipse IDE를 설치하는 법, 그리고 Drools Workbench 플러그인을 통한 Eclipse 구성 방법 등에 대하여 다룹니다.

  1. 규칙 엔진
  2. Drools
  3. Drools 규칙 엔진의 이점
  4. BRMS
  5. 생성 규칙  이벤트
  6. 시작하기
  7. 결과
  8. 요약

Rule Engine

Rule Engine은 소프트웨어의 일부분이며, 최소한의 지식(Knowledge)만으로도, 결론을 추론(inferencing)해낼 수 있는 도구입니다. 지식 및 추론은 규칙(rule)로 저장되며, 이를 생성 규칙(production rule)이라 합니다. 다시 말해, 생성 규칙은 주어진 조건들이 true일때 실행되는 Action으로 구성됩니다. 이외에도 의사 결정을 수행하는 동안 사용하고자 하는 모든 객체를 저장하는 작업 메모리(working memory)도 있습니다. Action의 수행을 통해 기존 객체가 추가, 삭제 또는 변경될 수 있기 때문에, 메모리의 상태는 계속해서 변화하며, 이 과정에서 둘 이상의 규칙들이 서로 충돌하는 현상이 발생할 수 있습니다. 보통 1개 이상의 규칙들이 동시에 true가 될때 이러한 현상이 발생합니다. Agenda는 이러한 충돌 상황을 해결해줍니다. Agenda는 현채 선택되어 있는 Action의 실행 순서를 조정합니다. 특정 Action이 실행된 이후 메모리의 상태가 변경되면, 이전에는 true값을 가졌던 Rule들이 이제는 더이상 유효하지 않은 상태로 바뀌며, 그 결과 관련된 Action들이 취소되니다. Agenda는 Rule엔진에서 매우 중요한 부분입니다. 위의 전체 과정을 간단하게 요약하면 다음과 같은 그림으로 나타낼 수 있습니다.



Rule Engine은 다음과 같은 용도에 가장 적합합니다.

  • 제품 수량이나 가격에 따른 할인 금액 계산
  • 운전자의 연령 및 자동차의 가격에 따른 보험 정책 결정
  • 문제점 분석
  • 장애 발생 의심 상황 탐지
  • 매우 복잡한 문제 해결

Drools

Drools는 오픈 소스 Rule Engine중 하나이며, Apache 라이센스 하에서 배포된 Java 라이브러리입니다. 바이너리뿐 아니라 소스 코드까지 다운로드 받을 수 있으며, 해당 라이브러리를 사용하여 자유롭게 어플리케이션을 작성할 수 있습니다.

Rule Engine의 핵심은 추론 엔진(inference engine)입니다. 추론 엔진의 역할은 Fact와 Rule을 패턴 매칭을 사용하여 분석한 뒤, condition이 true인 것으로 판명되는 Rule의 Action들을 수행하도록 합니다. 이러한 패턴 매칭 작업은 객체 지향 개념을 사용하여 확장된 RETE 알고리즘에 의해 수행됩니다

앞서 말한 바와 같이, Rule Engine내에서 지식(Knowlede)은 Production Rule의 형태로 표시됩니다. 데이터에 Rule Engine에 데이터를 제공하기 위한 방법으로는 ‘일차 술어 논리’(First Order Logic)가 사용됩니다. 일차 술어 논리 표현식을 사용하면 ‘2 + 3 == 5’ 또는 ‘customer.age > 17’ 같은 표현식의 true/false 여부를 평가할 수 있습니다.

생성 규칙은 Condition과 Action 두가지 주요 부분으로 나뉩니다.

when

            Customer (age > 17)

then

            System.out.println("Customer is full age");

위의 규칙들을 만족하는 모든 객체들은 true값을 반환할 것이며, 해당 객체들은 성년 고객으로 분류될 것입니다. SQL 쿼리를 사용하는 경우 위 Rule을 다음과 같이 나타낼 수 있을 것입니다.

SELECT * from Customers c WHERE c.age > 17

Rule이 true인지 판단하고 그에 따른 Action을 수행 하는데에는 두가지 방식이 있습니다. 먼저 Fact 위주의 연산을 수행하는 Forward Chaining방식은 Fact위주의 연산을 수행하여 결론을 추론냅니다. 이것은 Condition 파트의  조건들을 사용하여 작업 메모리에서 true로 판명된 Fact들을 분류하고, 실행될 Action들의 목록을 분류하는 방법입니다. Condition을 만족시키는 Fact가 더이상 남아있지 않은 경우 패턴 매칭 프로세스가 종료됩니다.

반면에, Backward Chaining은 목적(Goal) 중심의 접근 방식입니다. 특정 목적에 해당하는 Action들을 수행하는 Rule에 대해서만 true/false 여부를 판단하고, 평가한 Rule들중 true인것이 존재하는 경우 해당 Action을 수행합니다.

Drools Rule Engine의 장점

  • 어플리케이션에서 작업 흐름을 제어하는 조건들을 별도 분리 가능
    • Rule은 별도의 파일에 저장
    • 서로 다른 사용자 그룹에 의한 Rule 변경이 가능
    • Rule 변경으로 인해 전체 어플리케이션을 다시 빌드할 필요가 없음
    • 모든 Rule들이 단일 저장소(repository)에 저장되므로 어플리케이션 작업 흐름을 손쉽게 제어 또는 관리 가능
  • 복잡한 if-then 구문을 쉽고 읽기 편한 Rule로 대체 가능
    • Rule 문법을 쉽게 배울수 있음
    • Eclipse IDE 플러그인을 통해 손쉽게 Rule을 작성하고 RETE 트리를 확인 가능
  • 복잡한 알고리즘을 사용해서도 풀수 없는 문제들을, Rule Engine을 사용하여 해결하는 것이 가능하며코드에 비해서 읽고 이해하기가 쉬움
  • 문제 해결에 사용된 전체 추론 과정을 살펴볼 수 있어어떤 과정을 통해 최종 결과가 도출되었는지를 쉽게 이해할 수 있음

 특정 문제의 해결 방식이 지나치게 복잡하거나, 알고리즘 내에 if-then, switch 구문이 많이 포함되어 있는 경우, Rule Engine의 사용을 고려할 필요가 있습니다. 어플리케이션의 로직이 자주 변경되거나, 실제 개발자가 아닌 일반 사용자들이 어플리케이션 내부 로직을 변경해야 하는 경우에도 마찬가지입니다.

 

BRMS

Drools는 Rule Engine에 추가하여, BRMS(Business Rules Management System) 라고 불리는 Rule 관리 어플리케이션도 제공합니다. 이 어플리케이션을 사용해서 Rule을 생성/수정/삭제 하거나 특정 저장소에 저장하거나 다양한 버전의 Rule로 분리하여 관리할 수 있습니다. 또한 각각의 사용자별로 Rule 관리에 필요한 다양한 역할을 할당할 수 있으며, 로그인 메커니즘과 LDAP 통합을 통한 손쉬운 보안 환경 구축 기능도 제공합니다. 예를 들어, 비즈니스 분석가는 Rule 저장소에 접근하여 각각의 Rule을 수정하는 것이 가능하지만, 어플리케이션 개발자는 Rule 저장소에서 특정 Rule을 읽기만 가능하고 수정은 불가능하도록 역할을 할당할 수 있습니다. BRMS는 Rule 집합 저장을 위한 단일 저장소로 사용될 수 있습니다.

Pruduction Rule vs. events

Production Rule은 주로 Condition(when)과 Action(then) 두 부분으로 구성되어 있습니다. (예: 운전 면허증 소지 기간이 5년 미만인 고객에게는 보험료 할증 규칙을 적용하라.). 기타 다른 유형의 Rule에는 이벤트(event)가 있습니다. 이것은 event condition action 형태의 문법을 갖습니다. 이 경우 Rule Engine은 등록된 이벤트와 일치하는 사건이 발생한 경우 해당 룰의 조건이 true인지 여부를 판단합니다. 마지막 상품이 판매되어 제품 재고가 모두 소진되었다거나, 신호등의 고장 같은 사건이 이런 이벤트에 해당합니다. Production Rule에서는 Rule Engine이 모든 action을 수행하는 시기를 개발자가 결정하지만, event를 사용하는 경우에는 해당 이벤트가 발생할 경우  관련된 action들이 실행됩니다.

Rule Engine 사용예제

먼저 Eclipse IDE를 설치합니다. Eclipse를 선택한 이유는 Eclipse 자체만으로도 Drools를 사용한 어플리케이션을 개발하기에 충분하며, Eclipse에서 사용할 수 있는 Drools Rule Engine 플러그인들이 추가적으로 제공되기 때문입니다.

Eclipse IDE, Java EE 개발자를 위한 Eclipse IDE(eclipse-jee-europa-winter-linux-gtk.tar.gz)

다운로드가 끝나면 압축을 풀어서 Eclipse를 시작하십시오. 메뉴에서 Help -> Software Updates -> Find and install… -> Search for new features to install -> New Remote Site…를 클릭하십시오.



“Drools IDE Update Site” 아래 있는 Drools 
다운로드 페이지에 URL이 나타납니다. 이 URL은 플러그인에 대한 링크입니다. Drools 4.0.7 Eclipse Workbench for Europa 3.3의 경우에는http://downloads.jboss.com/drools/updatesite3.3/입니다.

OK와 Finish를 차례로 선택하면 Eclipse에 검색 결과가 나타납니다.



Next를 클릭해서 라이센스를 수락하고 Finish를 선택하면 플러그인 다운로드가 시작됩니다. 다운로드가 끝나면 Eclipse에 또 다른 창이 나타나는데, 여기에서 “Install all”을 클릭합니다. 재시작에 대해 물으면 “Yes”를 클릭하십시오. 플러그인이 성공적으로 설치되었는지를 확인하려면, 툴바에 Drools 아이콘이 새로 추가되었는지를 보면 됩니다.



이제 첫 번째 Drools 애플리케이션을 만들어보겠습니다. 툴바의 Drools 아이콘을 클릭한 뒤 “New Rule Project”를 선택합니다.


 
 프로젝트 이름을 입력하고 Finish를 클릭하십시오. Drools 플러그인이 표준 레이아웃을 생성하고 시작에 필요한 모든 라이브러리를 제공합니다. 이 애플리케이션을 실행하려면 com.sample.DroolsTest를 클릭한 다음, “Shift + Alt + X”와 “J”를 차례로 누르십시오. 콘솔에 다음과 같이 표시됩니다.

Hello World

Goodbye cruel world

내부적으로 어떤 작업들이 수행되었습니까?

이 예제는 Drools와 함께 배포되는 문서에 포함되어 있는 예제입니다. Rule Engine이 초기화되고, DroolsTest.java에서 해당 Rule을 어떻게 읽어서 실행하는지에 대해서는 자세히 설명하지 않겠습니다. 여기서 우리가 주로 살펴볼 부분은 Rule 파일인 Sample.drl 파일입니다.

이 파일은 두 가지 Rule을 포함하고 있습니다. 최초 프로그램 실행시, 작업 메모리는 message 필드가 “Hello World”, status 필드가 0으로 설정된 Message 클래스 객체가 1개 존재하고 있습니다. 이 상태에서 fireAllRules() 메소드가 호출되어 Rule의 조건을 만족하는 모든 Action들이 실행됩니다. 중요한 것은 객체가 작업 메모리에 추가될 때, 각 Rule의 condition 부분의 true/false 여부가 평가된다는 것입니다. 작업 메모리에 있는 1개의 객체는 Message 객체이고, 해당 객체의 status 필드는 0이기 때문에 “Hello World”라는 규칙의 condition은 true 값을 갖습니다. 따라서, 해당 Rule의 action 부분이 실행됩니다. 그 결과, Message 객체의 상태 및 메시지 필드가 수정됩니다. update() 명령어는 Rule Engine에게 작업 메모리 내의 객체들이 변경되었으므로, Rule들을 다시 평가하도록 지시합니다.  이번에는 두 번째 Rule의 조건이 true값을 갖게 되며, 해당 Rule의 action이 실행될 것입니다.

요약

규칙 엔진의 세계와 엄선된 Drools 애플리케이션에 대한 간단한 소개를 통해 주요 특성과 몇 가지 가능한 사용 영역에 대해 알아 보았습니다. Drools 소프트웨어에 대한 자세한 내용은 Drools 설명서를 참조하십시오.

All images and content copyright © 2008 Jaroslaw Kianowski. All rights reserved. Used with permission.

본 내용은 Jaroslaw Kijanowski가 2008년 7월 10일 목요일 오후 5시 25분에 게시했으며, JBoss의 technical아래에 정리되어 있습니다. RSS 2.0피드를 통해 이에 대한 모든 댓글을 확인해 보실 수 있습니다. 여러분의 사이트에서 댓글이나 트랙백을 남길 수 있습니다.



오른쪽 마우스 해제하기 URL 개발


javascript:function r(d){d.oncontextmenu=null;d.onselectstart=null;d.ondragstart=null;d.onkeydown=null;d.onmousedown=null; d.body.oncontextmenu=null;d.body.onselectstart=null;d.body.ondragstart=null;d.body.onkeydown=null; d.body.onmousedown=null;};function unify(w){r(w.document);if(w.frames.length>0){for(var i=0;i<w.frames.length;i++){try{unify(w.frames[i].window);}catch(e){}};};}; unify(self);



JCF 3.0 사이트 개발


사이트 주소


mantis 사이트 네....



Eclipse - redmine - myln 연동 개발

왜 Mylyn 은 RedMine 이랑 친하지 않아서 안찾아 지는건지 ㅡㅡ;;
설정해서 install software 여기 들어간다.

1. Myln 설치
http://download.eclipse.org/mylyn/releases/indigo

여기중 task ~ , task repositories ~ 머 이런애들 두개 설치.
나머지는 필요하다면 설치..
2.  Mylyn Connector (Redmine) 설치
Redmine과 연동하기 위해 Mylyn Connector (Redmine)을 찾아야 된다.
http://redmin-mylyncon.sourceforge.net
요놈 사이트에 가면 redmin 과 mylyn을 연동하는 프로젝트가 진행중인것을 알수있다.
여기저기 돌아다니다보면 이클립스에 connector 를 올리려면

http://redmin-mylyncon.sourceforge.net/update-site/N/
이놈으로 하면 된다고 한다...

완성~!~!~! 

///
사용방법
window - show view 에서 task List 와 Task Repositories 를 끄집어 낸다.
레드마인 주소를 입력 아이디 비밀번호 설정하면
뉴 쿼리를 통해 원하는 데이터를 읽어올수 있다~!

Dynamic MBean 예제 개발

흔히 사용하는 SomethingMBean과는 달리

동적으로 MBean을 생성하는 방식이 Dynamic MBean이다.

Dynamic MBean은 애플리케이션 설정을 포함한 속성 파일을 사용하고,

이 내용를 관리를 위해 노출하고자 할 때 사용할 수 있다.

Dynamic MBean을 사용함으로써 원격에서 속성 파일의 정보를 확인하고,

애플리케이션이 실행 중에 속성 파일이 변경되더라도 이를 반영할 수 있다.

가장 큰 차이점은 동적으로 없던 속성을 추가하거나 있던 속성을 제거할 수 있다는 것이다.

다음은 Dynamic MBean을 사용하는 예제이다.

다음은 Dynamic MBean의 구현체이다.


package propertymanager;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.Iterator;

import java.util.Properties;

import java.util.SortedSet;

import java.util.TreeSet;

import javax.management.Attribute;

import javax.management.AttributeList;

import javax.management.AttributeNotFoundException;

import javax.management.DynamicMBean;

import javax.management.InvalidAttributeValueException;

import javax.management.MBeanAttributeInfo;

import javax.management.MBeanException;

import javax.management.MBeanInfo;

import javax.management.MBeanOperationInfo;

import javax.management.ReflectionException;

public class PropertyManager implements DynamicMBean {

 private final String propertyFileName;

 private final Properties properties;

 public PropertyManager(String propertyFileName) throws IOException {

  this.propertyFileName = propertyFileName;

  properties = new Properties();

  load();

 }

 public synchronized String getAttribute(String name)

   throws AttributeNotFoundException {

  String value = properties.getProperty(name);

  if (value != null)

   return value;

  else

   throw new AttributeNotFoundException("No such property: " + name);

 }

 public synchronized void setAttribute(Attribute attribute)

   throws InvalidAttributeValueException, MBeanException,

   AttributeNotFoundException {

  String name = attribute.getName();

  if (properties.getProperty(name) == null)

   throw new AttributeNotFoundException(name);

  Object value = attribute.getValue();

  if (!(value instanceof String)) {

   throw new InvalidAttributeValueException(

     "Attribute value not a string: " + value);

  }

  properties.setProperty(name, (String) value);

  try {

   save();

  } catch (IOException e) {

   throw new MBeanException(e);

  }

 }

 public synchronized AttributeList getAttributes(String[] names) {

  AttributeList list = new AttributeList();

  for (String name : names) {

   String value = properties.getProperty(name);

   if (value != null)

    list.add(new Attribute(name, value));

  }

  return list;

 }

 public synchronized AttributeList setAttributes(AttributeList list) {

  Attribute[] attrs = (Attribute[]) list.toArray(new Attribute[0]);

  AttributeList retlist = new AttributeList();

  for (Attribute attr : attrs) {

   String name = attr.getName();

   Object value = attr.getValue();

   if (properties.getProperty(name) != null && value instanceof String) {

    properties.setProperty(name, (String) value);

    retlist.add(new Attribute(name, value));

   }

  }

  try {

   save();

  } catch (IOException e) {

   return new AttributeList();

  }

  return retlist;

 }

 public Object invoke(String name, Object[] args, String[] sig)

   throws MBeanException, ReflectionException {

  if (name.equals("reload") && (args == null || args.length == 0)

    && (sig == null || sig.length == 0)) {

   try {

    load();

    return null;

   } catch (IOException e) {

    throw new MBeanException(e);

   }

  }

  throw new ReflectionException(new NoSuchMethodException(name));

 }

 public synchronized MBeanInfo getMBeanInfo() {

  SortedSet<String> names = new TreeSet<String>();

  for (Object name : properties.keySet())

   names.add((String) name);

  MBeanAttributeInfo[] attrs = new MBeanAttributeInfo[names.size()];

  Iterator<String> it = names.iterator();

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

   String name = it.next();

   attrs[i] = new MBeanAttributeInfo(name, "java.lang.String",

     "Property " + name, true, // isReadable

     true, // isWritable

     false); // isIs

  }

  MBeanOperationInfo[] opers = { new MBeanOperationInfo("reload",

    "Reload properties from file", null, // no parameters

    "void", MBeanOperationInfo.ACTION) };

  return new MBeanInfo(this.getClass().getName(),

    "Property Manager MBean", attrs, null, // constructors

    opers, null); // notifications

 }

 private void load() throws IOException {

  InputStream input = new FileInputStream(propertyFileName);

  properties.load(input);

  input.close();

 }

 private void save() throws IOException {

  String newPropertyFileName = propertyFileName + "$$new";

  File file = new File(newPropertyFileName);

  OutputStream output = new FileOutputStream(file);

  String comment = "Written by " + this.getClass().getName();

  properties.store(output, comment);

  output.close();

  if (!file.renameTo(new File(propertyFileName))) {

   throw new IOException("Rename " + newPropertyFileName + " to "

     + propertyFileName + " failed");

  }

 }

}

다음은 Dynamic MBean 테스트 클래스이다.

package propertymanager;

import java.io.IOException;

import java.lang.management.ManagementFactory;

import javax.management.InstanceAlreadyExistsException;

import javax.management.MBeanRegistrationException;

import javax.management.MBeanServer;

import javax.management.MalformedObjectNameException;

import javax.management.NotCompliantMBeanException;

import javax.management.ObjectName;

public class PropertyManagerTest {

 

 public static void main(String[] args) {

  MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

  ObjectName name;

  try {

   name = new ObjectName("propertymanager:type=PropertyManager");

   PropertyManager mbean = new PropertyManager("test.properties");

   mbs.registerMBean(mbean, name);

   

   System.out.println("Waiting forever...");

   Thread.sleep(Long.MAX_VALUE);

  } catch (MalformedObjectNameException e) {

   // TODO Auto-generated catch block

   e.printStackTrace();

  } catch (NullPointerException e) {

   // TODO Auto-generated catch block

   e.printStackTrace();

  } catch (IOException e) {

   // TODO Auto-generated catch block

   e.printStackTrace();

  } catch (InstanceAlreadyExistsException e) {

   // TODO Auto-generated catch block

   e.printStackTrace();

  } catch (MBeanRegistrationException e) {

   // TODO Auto-generated catch block

   e.printStackTrace();

  } catch (NotCompliantMBeanException e) {

   // TODO Auto-generated catch block

   e.printStackTrace();

  } catch (InterruptedException e) {

   // TODO Auto-generated catch block

   e.printStackTrace();

  }

 }

 

}

JConsole로 연결하여 MBeans 탭을 활용하면 간단히 테스트할 수 있다.

Reference:

http://weblogs.java.net/blog/emcmanus/archive/2006/11/a_real_example.html


java 실행 옵션에 대하여 개발

java - the Java application launcher

SYNOPSIS

    java [ options ] class [ argument ... ]    java [ options ] -jar file.jar [ argument ... ]    javaw [ options ] class [ argument ... ]    javaw [ options ] -jar file.jar [ argument ... ]
options
Command-line options.
class
Name of the class to be invoked.
file.jar
Name of the jar file to be invoked. Used only with -jar.
argument
Argument passed to the main function.

DESCRIPTION

The java tool launches a Java application. It does this by starting a Java runtime environment, loading a specified class, and invoking that class's main method.

The method must be declared public and static, it must not return any value, and it must accept a String array as a para meter. The method declaration must look like the following:

    public static void main(String args[])
By default, the first non-option argument is the name of the class to be invoked. A fully-qualified class name should be used. If the -jar option is specified, the first non-option argume nt is the name of aJAR archive containing class and resource f iles for the application, with the startup class indicated by the Main-Class manifest header.

The Java runtime searches for the startup class, and other classes used, in three sets of locations: the bootstrap class path, the installed extensions, and the user class path.

Non-option arguments after the class name or JAR file name are passed to the main function.

The javaw command is identical to java, except that with javaw there is no associated console window. Use javaw when you don't want a command prompt window to appear. The javaw launcher will, however, display a dialog box with error information if a launch fails for some reason.

OPTIONS

The launcher has a set of standard options that are supported on the current runtime environment and will be supported in future releases. In addition, the default Java HotSpot VMs provide a set of non-standard options that are subject to change in future releases.

Standard Options

-client
Select the Java HotSpot Client VM.

For more information, see Server-Class Machine Detection

-server
Select the Java HotSpot Server VM.

For more information, see Server-Class Machine Detection

-agentlib:libname[=options]
Load native agent library libname, e.g.

-agentlib:hprof

-agentlib:jdwp=help

-agentlib:hprof=help

For more information, see JVMTI Agent Command Line Options.

-agentpath:pathname[=options]
Load a native agent library by full pathname. For more information, see JVMTI Agent Command Line Options.

-classpath classpath
-cp classpath
Specify a list of directories, JAR archives, and ZIP archives to search for class files. Class path entries are separated by semicolons (;). Specifying -classpath or -cp overrides any setting of theCLASSPATH environment variable.

If -classpath and -cp are not used and CLASSPATH is not set, the user class path consists of the current directory (.).

For more information on class paths, see Setting the Class Path.

-Dproperty=value
Set a system property value. If value is a string that contains spaces, you must enclose the string in double quotes:
        java -Dfoo="some string" SomeClass        
-enableassertions[:<package name>"..." | :<class name> ]
-ea[:<package name>"..." | :<class name> ]
Enable assertions. Assertions are disabled by default.

With no arguments, enableassertions or -ea enables assertions. With one argument ending in "...", the switch enables assertions in the specified package and any subpackages. If the argument is simply "...", the switch enables assertions in the unnamed package in the current working directory. With one argument not ending in "...", the switch enables assertions in the specified class.

If a single command line contains multiple instances of these switches, they are processed in order before loading any classes. So, for example, to run a program with assertions enabled only in package com.wombat.fruitbat (and any subpackages), the following command could be used:

java -ea:com.wombat.fruitbat... <Main Class>

The -enableassertions and -ea switches apply to all s loaders and to system classes (which do not have a class loader). There is one exception to this rule: in their no-argument form, the switches do not apply to system. This makes it easy to turn on asserts in all classes except for system classes. A separate switch is provided to enable asserts in all system classes; see -enablesystemassertions below.

-disableassertions[:<package name>"..." | :<class ; ]
-da[:<package name>"..." | :<class name> ]
Disable assertions. This is the default.

With no arguments, disableassertions or -da disables assertions. With one argument ending in "...", the switch disables assertions in the specified package and any subpackages. If the argument is simply "...", the switch disables assertions in the unnamed package in the rent working directory. With one argument not ending in "...", the switch disables assertions in the specified class.

To run a program with assertions enabled in package com.wombat.fruitbat but disabled in class com.wombat.fruitbat.Brickbat, the following command could be used:

java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat lt;Main Class>

The -disableassertions and -da switches apply to all ss loaders and to system classes (which do not have a class loader). There is one exception to this rule: in their no-argument form, the switches do not apply to system. This makes it easy to turn on asserts in all classes except for system classes. A separate switch is provided to enable asserts in all system classes; see -disablesystemassertions below.

-enablesystemassertions
-esa
Enable asserts in all system classes (sets the default assertion status for system classes to true).

-disablesystemassertions
-dsa
Disables asserts in all system classes.

-jar
Execute a program encapsulated in a JAR file. The first argument is the name of a JAR file instead of a startup class name. In order for this option to work, the manifest of the JAR file must contain a line of the form Main-Class: classname. Here, classname identifies the class having the public static void main(String[] args) method that serves as your application's starting point. See the Jar tool reference page and the Jar trail of the Java Tutorial for information about working with Jar files and Jar-file manifests.

When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored.

-javaagent:jarpath[=options]
Load a Java programming language agent, see java.lang.instrument.

-verbose
-verbose:class
Display information about each class loaded.

-verbose:gc
Report on each garbage collection event.

-verbose:jni
Report information about use of native methods and other Java Native Interface activity.

-version
Display version information and exit.

-showversion
Display version information and continue.

-?
-help
Display usage information and exit.

-X
Display information about non-standard options and exit.

Non-Standard Options

-Xint
Operate in interpreted-only mode. Compilation to native code is disabled, and all bytecodes are executed by the interpreter. The performance benefits offered by the Java HotSpot Client VM's adaptive compiler will not be present in this mode.

-Xbatch
Disable background compilation. Normally the VM will compile the method as a background task, running the method in interpreter mode until the background compilation is finished. The -Xbatch flag disables background compilation so that compilation of all methods proceeds as a foreground task until completed.

-Xdebug
Start with support for JVMDI enabled. JVMDI has been deprecated and is not used for debugging in J2SE 5.0, so this option isn't needed for debugging in J2SE 5.0.

-Xbootclasspath:bootclasspath
Specify a semicolon-separated list of directories, JAR archives, and ZIP archives to search for boot class files. These are used in place of the boot class files included in the Java 2 SDK. Note: Applications that use this option for the purpose of overriding a class in rt.jar should not be deployed as doing so would contravene the Java 2 Runtime Environment binary code license.

-Xbootclasspath/a:path
Specify a semicolon-separated path of directires, JAR archives, and ZIP archives to append to the default bootstrap class path.

-Xbootclasspath/p:path
Specify a semicolon-separated path of directires, JAR archives, and ZIP archives to prepend in front of the default bootstrap class path. Note: Applications that use this option for the purpose of overriding a class in rt.jar should not be deployed as doing so would contravene the Java 2 Runtime Environment binary code license.

-Xcheck:jni
Perform additional checks for Java Native Interface (JNI) functions. Specifically, the Java Virtual Machine validates the parameters passed to the JNI function as well as the runtime environment data before processing the JNI request. Any invalid data encountered indicates a problem in the native code, and the Java Virtual Machine will terminate with a fatal error in such cases. Expect a performance degradation when this option is used.

-Xfuture
Perform strict class-file format checks. For purposes of backwards compatibility, the default format checks performed by the Java 2 SDK's virtual machine are no stricter than the checks performed by 1.1.x versions of the JDK software. The -Xfuture flag turns on stricter class-file format checks that enforce closer conformance to the class-file format specification. Developers are encouraged to use this flag when developing new code because the stricter checks will become the default in future releases of the Java application launcher.

-Xnoclassgc
Disable class garbage collection.

-Xincgc
Enable the incremental garbage collector. The incremental garbage collector, which is off by default, will reduce the occasional long garbage-collection pauses during program execution. The incremental garbage collector will at times execute concurrently with the program and during such times will reduce the processor capacity available to the program.

-Xloggc:file
Report on each garbage collection event, as with -verbose:gc, but log this data to file. In addition to the information -verbose:gc gives, each reported event will be preceeded by the time (in seconds) since the first garbage-collection event.

Always use a local file system for storage of this file to avoid stalling the JVM due to network latency. The file may be truncated in the case of a full file system and logging will continue on the truncated file. This option overrides -verbose:gc if both are given on the command line.

-Xmsn
Specify the initial size, in bytes, of the memory allocation pool. This value must be a multiple of 1024 greater than 1MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is 2MB. Examples:
       -Xms6291456       -Xms6144k       -Xms6m       

-Xmxn
Specify the maximum size, in bytes, of the memory allocation pool. This value must a multiple of 1024 greater than 2MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is 64MB. Examples:
       -Xmx83886080       -Xmx81920k       -Xmx80m       

-Xprof
Profiles the running program, and sends profiling data to standard output. This option is provided as a utility that is useful in program development and is not intended to be be used in production systems.

-Xrunhprof[:help][:<suboption>=<value>,...]
Enables cpu, heap, or monitor profiling. This option is typically followed by a list of comma-separated "<suboption>=<value>" pairs . Run the command java -Xrunhprof:help to obtain a list of suboptions and their default values.

-Xrs
Reduces usage of operating-system signals by the Java virtual machine (JVM). This option is available beginning with J2SE 1.3.1.

In J2SE 1.3.0, the Shutdown Hooks facility was added to allow orderly shutdown of a Java application. The intent was to allow user cleanup code (such as closing database connections) to run at shutdown, even if the JVM terminates abruptly.

The JVM watches for console control events to implement shutdown hooks for abnormal JVM termination. Specifically, the JVM registers a console control handler which begins shutdown-hook processing and returns TRUE for CTRL_C_EVENT, CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT.

The JVM uses a similar mechanism to implement the pre-1.2 feature of dumping thread stacks for debugging purposes. Sun's JVM uses CTRL_BREAK_EVENT to perform thread dumps.

If the JVM is run as a service (for example, the servlet engine for a web server), it can receive CTRL_LOGOFF_EVENT but should not initiate shutdown since the operating system will not actually terminate the process. To avoid possible interference such as this, the -Xrs command-line option has been added beginning with J2SE 1.3.1. When the -Xrs option is used on Sun's JVM, the JVM does not install a console control handler, implying that it does not watch for or process CTRL_C_EVENT, CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, or CTRL_SHUTDOWN_EVENT.

There are two consequences of specifying -Xrs:

  • Ctrl-Break thread dumps are not available.
  • User code is responsible for causing shutdown hooks to run, for example by calling System.exit() when the JVM is to be terminated.

-Xssn
Set thread stack size.

SEE ALSO


Copyright © 2004, 2010 Oracle and/or its affiliates. All rights reserved.

Sun 

자바 툴을 사용해 보자 Java - 자바

자바툴을 사용하자

자바를 처음 시작할 때 반드시 배우는 명령어가 있다. javac, java, javaw (이건 옵션... -_-;;;) 이다.
자바 컴파일러와 인터프리터... javac는 자바 소스코드를 바이트코드로 컴파일해주는 툴이고, java는 컴파일된 자바 바이트코드를 실행하는 툴이다. 모두 알다시피 java 툴은 인터프리터이다.

그런데 JDK 또는 JRE가 설치된 위치에 bin 디렉토리를 보면 javac, java, javaw 들 외에도 상당히 많은 바이너리들이 존재한다. 보통은 JVM에서 그냥 쓰는 녀석들이려니 하고 넘어가지만 만물은 모두 존재이유가 있는 법... -_-;; 이들은 자바 어플리케이션 개발 및 운영시에 상당히 유용하게 사용할 수 있는 각종 툴들이다.

물론 메모리 덤프를 통해 힙 영역에 있는 각종 객체들을 볼 수 있는 툴도 존재한다. 올레~~ /-_-/
이들 중 유용하다고 생각되는 몇개만 뽑아서 정리해보도록 하자. 


1. jps
http://java.sun.com/javase/6/docs/technotes/tools/share/jps.html

jps는 unix 명령어인 ps와 같이 실행중인 자바 프로세스를 보여주는 툴이다. 일반적으로 ps 명령어와 grep 명령어의 조합으로 실행중인 자바 프로세스를 찾을 수도 있지만, jps를 사용하면 좀 더 편하다. (사실.. 말이 편하다는거지 ps 와 grep 으로 찾는게 더 편하다는 사람이 있다면 그것도 좋다.)

옵션없이 실행하면 프로세스 아이디와 클래스명만 보이므로 정보가 매우 부족하다. 
보통 -v 옵션(JVM 파라미터 보임)만 줘도 상당히 좋은 결과를 보여주며, 취향에 따라 -m (메인 메소드의 args 보임)과 -l (전체 패키지명 보임)옵션을 곁들이면 좋다.

예) jps -v -m -l


2. jmap
http://java.sun.com/javase/6/docs/technotes/tools/share/jmap.html

jmap은 현재 수행중인 자바 어플리케이션의 메모리맵을 보여주는 툴이다. 이 툴을 사용하여 heap 메모리를 덤프떠서 볼 수 있다. 일반적으로 OOME는 heap 영역에서 나는 것이 대부분이므로 이 툴을 사용하는 경우도 아마 heap 메모리 영역을 덤프를 뜨기 위한 것이 대부분일 것이다. 

jmap을 사용하여 heap 메모리 덤프를 뜨는 방법은 다음과 같다.

jmap -dump:<dump-options> pid
또는 
jmap -histo[:live] pid
-dump 옵션을 사용할 때는 보통 -dump:format=b,file=heap.hprof 정도의 옵션만으로 충분하다.

JDK 버전에 따라 제공되는 옵션이 다르므로 jmap -help 명령을 실행한 후에 사용법을 읽어보고, 두개 중 지원되는 옵션을 선택하여 실행하면 된다. 

pid는 ps 명령어를 사용하거나 위에서 본 jps를 사용하여 알아내도록 하자.
 
만약 톰캣과 같이 WAS에서 동작하는 서버 어플리케이션에 jmap을 사용하여 heap 덤프 생성하고자 한다면 -Xmx 옵션값에 주의해야 한다.
만약 -Xmx가 1024m 으로 잡혀있는 WAS에서 OOME 발생 후 jmap으로 heap 덤프를 만들게 되면??
1G가 넘는 덤프파일과 만나게 된다.. -_-;;;;;

보너스~~ heap 덤프를 생성하는 또 다른 방법)
jmap은 runtime에 직접 툴을 실행하여 덤프를 생성해야 한다. 하지만 서비스를 운영하고 있는 경우 OOME가 언제 발생할 줄 알겠는가... OOME가 발생하기까지 눈뜨고 기다렸다가 jmap을 실행하여 덤프를 생성하는건 너무 터무니없다. 이럴 땐 -XX:+HeapDumpOnOutOfMemoryError VM 옵션을 이용하자. 이 옵션을 사용하면 OOME가 발생했을 때 자동으로 java_pid<pid>.hprof 파일명으로 heap 덤프를 생성한다. 또한 -XX:OnOutOfMemoryError=<Command> 옵션을 추가하여 OOME 발생 후 특정 명령어를 수행하도록 할 수도 있다. 주의할 점은 OnOutOfMemoryError 옵션은 JDK 버전 1.4.2 update 12 이후 버전과 6 에서만 동작한다는 점이다. 왜 그런지는 모르겠지만 JDK 5 에서는 해당 옵션을 지원하지 않는다.

이와 같은 VM 추가 옵션에 대해서는 다음의 링크를 참조하면 된다.
http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
http://wiki.ex-em.com/index.php/JVM_Options

주의할 점은 -XX 옵션은 Hotspot 옵션으로 각 VM마다 제공할수도 안할수도 있다.


3. jhat
http://java.sun.com/javase/6/docs/technotes/tools/share/jhat.html

jmap으로 heap 메모리 덤프를 생성했으면 이제 메모리를 분석해야 한다. 메모리 덤프 파일은 눈으로 보기 힘드므로 (그래도 굳이 눈으로 보고 싶으면 말리진 않겠다...) 이를 분석하여 쉽게 보여주는 툴이 필요하다.

대표적으로 IBM에서 만든 HeapAnalyzer 가 있지만 라이센스 문제도 있고, 직접 사용해본 결과 덤프 파일의 크기가 매우 큰 경우 HeapAnalyzer에서 OOME가 발생하는 아주 짜증나는 상황에 직면하게 된다. -_-;;;;;;; (물론 jhat도 마찬가지다.)

jhat은 jmap으로 생성된 바이너리 heap 덤프 파일을 분석하여 보여주는 툴이다. jhat을 실행하는 방법은 매우 간단하며 heap 덤프 파일 경로를 주어 jhat을 실행시키면 7000 포트로 분석 결과를 볼 수 있도록 자체 웹서버가 구동된다. 7000 포트가 이미 사용중이면 -port 옵션을 사용하여 포트를 변경할 수 있다.

IBM의 HeapAnalyzer 와 같은 예쁜 GUI를 제공하는 것은 아니지만, 나름 쓸만한 정보를 보여준다.

<jhat 실행 후...>

<각 인스턴스(객체) 별 갯수를 볼 수 있다.. 메모리 누수의 범인은 뉴규~??>


여기서는 Memory 상태를 추적할 수 있는 공짜 Tool 을 하나 소개하겠다.
Sun JDK, HP JDK 에 포함되어있는 것으로 jstat 라는 것이다.
현재 JVM 의 Heap Memory 상태를 실시간으로 추적하는 매우 효율적인 Tool 이다.

다음은 jstat 에 사용할 수 있는 파라미터들이다.

[ngwas1:/NGI/agreeDomain]jstat
invalid argument count
Usage: jstat -help|-options
       jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

Definitions:
  <option>      An option reported by the -options option
  <vmid>        Virtual Machine Identifier. A vmid takes the following form:
                     <lvmid>[@<hostname>[:<port>]]
                Where <lvmid> is the local vm identifier for the target
                Java virtual machine, typically a process id; <hostname> is
                the name of the host running the target Java virtual machine;
                and <port> is the port number for the rmiregistry on the
                target host. See the jvmstat documentation for a more complete
                description of the Virtual Machine Identifier.
  <lines>       Number of samples between header lines.
  <interval>    Sampling interval. The following forms are allowed:
                    <n>["ms"|"s"]
                Where <n> is an integer and the suffix specifies the units as 
                milliseconds("ms") or seconds("s"). The default units are "ms".
  <count>       Number of samples to take before terminating.
  -J<flag>      Pass <flag> directly to the runtime system.


위에 있는 <option> 을 보겠다.

[ngwas1:/NGI/wily601]jstat -options
-class
-compiler
-gc
-gccapacity
-gccause
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-printcompilation


위와같이 여러개의 옵션이 있는데 여기서 우리는 GC 관련 옵션을 선택하여 Heap Memory Area 를 추적해보겠다.

[ngwas1:/NGI/wily601]jstat -gc -h20 6637 3000
위의 명령을 해석해보면...

-gc : GC 되는 것을 보겠다는 의미
-h20 : 아래 데이터를 보면 알겠지만 숫자에 대한 헤더가 있는데 그 헤더를 20 라인마다 찍겠다는 의미이다.
6637 : Process PID 이다. 이건 항상 변하겠죠?
3000 : 시간이다. ms 단위라서 3000 이면 3초마다 한번씩 데이터를 추출하겠다는 얘기다.

위와같이 명령을 실행하면 아래와 같은 내용이 추출되며 각 줄마다 3초에 한번씩 추출된다.
그럼 아래의 데이터를 보는 법을 알려주겠다.
첫번째 파마리터 부터 설명을 붙여주겠다.

SOC : Servivor 0 Area Capacity
S1C : Servivor 1 Area Capacity
SOU : Servior 0 Area Used
S1U : Servivor 1 Area Used
EC : Eden Capacity
EU : Eden Used
OC : Old Capacity (Tenured Capacity)
OU : Old Used (Tenured Used)
PC : Permanent Capacity
PU : Permanent Used
YGC : Young GC Count
YGCT : Young GC Count Time (Young GC 시간이다. 누적시간이므로 아래서 위의 시간을 빼면 Young GC Time 을 알수있다)
FGC : Full GC Count
FGCT : Full GC Count Time
GCT : GC Time (YGCT + FGCT)

어려운가 ?

http://blog.naver.com/salsu0/30000025219  <== 요기를 읽고나서 보면 안어렵다.

그럼 아래 데이터를 한번 분석해 봅시다.

S0 Area 는 34 메가 정도가 할당되었다.
S1 Area 역시 동일하게 할당되었다.
Eden Area 는 72 메가 정도가 할당되었고
Old Area (Tenured Area) 는 700 메가 정도가 할당되었다.
Permanent Area 는 130 메가 정도 할당되었다.

Young GC 가 마지막줄을 봤을때 40 번 실행되었고,
Full GC 는 실행된적이 없다.

Young GC 가 40 번 실행되는 동안 걸린 시간은 7초 정도이며
맨 밑에 세번째 줄과 다음 줄을 비교해봤을때 Young GC 가 일어난 시간은 0.17 초 정도이다.
알다시피 GC 할때는 전혀 일을 하지 않는다.
물론 Default GC Option 일 경우이다. (다음번에는 GC Option 의 종류를 설명하겠다.)

그럼 다들 한번 테스트를 해보기를 바란다.

잼있죠 ?

  S0C        S1C     S0U      S1U      EC           EU            OC           OU            PC         PU        YGC    YGCT FGC    FGCT     GCT   
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 72110.9   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 73802.8   699072.0   86240.1   131072.0 69871.3     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 76141.1   699072.0   86240.1   131072.0 69871.4     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 102379.9  699072.0   86240.1   131072.0 69871.7     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 159719.5  699072.0   86240.1   131072.0 69875.0     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 207689.5  699072.0   86240.1   131072.0 69946.6     39    7.006   0      0.000    7.006
34944.0 34944.0  0.0   17142.6 279616.0 259934.1  699072.0   86240.1   131072.0 69948.0     39    7.006   0      0.000    7.006
34944.0 34944.0 17625.0  0.0   279616.0 50821.6   699072.0   86240.1   131072.0 69950.3     40    7.176   0      0.000    7.176
34944.0 34944.0 17625.0  0.0   279616.0 83850.1   699072.0   86240.1   131072.0 69950.9     40    7.176   0      0.000    7.176





JMX 사용 관련 정보 URL 개발


JMX를 사용해 관리되는 인스턴스 생성하기
http://chanwook.tistory.com/568
간단한 사용법

JMX를 이용한 daemon 모니터링
http://blog.kangwoo.kr/76
설정, 클라이언트, 서버 개발 코드 포함

4장. JMX 어플리케이션 개발
http://technet.tmax.co.kr/kr/edocs/jeus/60/jmx/chapter_JMX_applications.html
TMAX 의 제우스에 jmx 추가 설정하는 방법

Chapter 20. JMX 지원 - Spring
http://openframework.or.kr/framework_reference/spring/ver1.2.2/html/ch20.html
Spring내 JMX지원



NOSQL 제품 특징 비교 개발


FeaturesMongoDBRiakHyperTableHBase
Logical Data ModelRich Document with
support
for Nested Document
Rich DocumentColumn FamilyColumn Family
Support for CAPCAAPCACA
Dynamic Addition
/Removal of Node
SupportedSupportedSupportedSupported
Multi DC supportSupportedNot SupportedSupportedSupported
InterfaceVariety of APIs
(Java, Python, Perl, C#)
JSON over HTTPREST, Thrift, JavaC++,Thrift
Persistence ModelDiskDiskMemory + Desk
(Tunable)
Memory + Desk
(Tunable)
Comparative
Performance
Better
(C++)
Best
(Erlang)
Better
(C++)
Good
(Java)
Commercial
Support
10gen.comBasho TechnologiesHypertable IncCloudera

사례

해외사례

  • Google Bigtable
    • 모든 URL 기반의 문서 정보 수집 (Key/Value 기반의 Bigtable에 저장)
    • 수집한 정보를 Map/Reduce로 색인 (색인 데이터도 Bigtable에 저장)
    • Document에서 사용하는 정보가 계속 추가될 수 있다. (URL, title, 본문, meta tag 등)
  • Amazon’s Dynamo
  • Digg.com Cassandra
    • 내 친구가 추천한 정보를 보여주기 위해서 NoSQL이 필요해짐
  • Twitter Cassandra
    • 모든 사용자의 글을 하나의 DB에 저장할 수 없다면 내가 팔로우하는 timeline은 어떻게 보여줄 수 있을까?

NHN 인증 플랫폼

  • 요구사항
    • backend DB 점검 시에도 read가 가능한 시스템
    • 로그인 사용자 세션 정보를 저장 및 조회
  • 구현
    • MySQL 클러스터링으로 세션 정보 저장 – MySQL을 메모리 DB로 사용
    • in-house 메모리 DB로 사용자 정보 저장 – Oracle 로그 기반으로 메모리 리플리케이션

Daum view 추천 플랫폼 (예정)

  • 사용자의 추천을 모두 수집한다.
  • 소셜 네트워크를 저장한다.
  • 추천 정보를 추천 히스토리와 소셜 네트워크 기반으로 Map/Reduce 분석
  • 신뢰도 높은 추천 기반으로 문서 랭킹 부여

Daum Cafe

  • ‘최근 방문 카페’ 기능에 Cassandra 적용

Reference

This entry was posted in Software & Developer and tagged . Bookmark thepermalinkPost a comment or leave a trackback: Trackback URL.

NoSQL 정의와 사례 정리 개발

NoSQL 정의

No SQL? Not Only SQL?

NoSQL은 관계형 데이터베이스의 한계를 극복하기 위한 데이터 저장소의 새로운 형태로 수평적 확장성을 특징으로 한다.
관계형이 아니기 때문에 join이 없고 고정된 스키마를 갖지 않는다.

대표적인 NoSQL 제품은 Google의 BigTable, Amazon의 Dynamo이 있고, 이외에 비롯해 다양한 오픈소스 제품이 소개되어 있다.

Why NoSQL?

데이터 규모의 확대

  • 저장할 데이터가 많아지면서 읽고/쓰기에 있어서 RDB가 제약 요소가 되었다.
  • RDB의 수평적 확장성 한계로 새로운 해결책이 필요했다.

웹 서비스의 구조 변화

  • 저장할 데이터의 형태가 계속 변화한다.
  • 사용자의 데이터 요구가 일관적이지 않고 다양하다.

NoSQL 선택

BigTable, Dynamo, Cassandra, CouchDB, MongoDB, Hbase, Riak, Voldemort 등 20개 이상의 NoSQL 제품이 있고,
자신의 목적에 맞는 NoSQL 제품을 선택하기 위해서는 각각의 특징을 정확히 파악해야 한다.

CAP 이론

CAP이란?

  • Consistency: 각각의 사용자가 항상 동일한 데이터를 조회한다.
  • Availability: 모든 사용자가 항상 읽고 쓸 수 있다.
  • Partition tolerance: 물리적 네트워크 분산 환경에서 시스템이 잘 동작한다.

Availability와 Partition tolerance가 추상적 정의만으로 이해가 힘들 수 있어서 설명을 추가합니다. (용어 때문에 오히려 이해가 어려울 수 있는데 둘 다 파티션에 대한 특성으로 접근해야 합니다.) Availability and Partition Tolerance 글과 댓글을 참고하면 A, P에 대한 정의 및 기능이 좀 더 이해가 쉬울 수 있습니다.

  • 장애 때문에 특정 노드들이 기약 없이 대기해야 한다면 Availability가 희생된다.
  • 특정 요청이 장애로 기약 없이 대기해야 한다면 Partition tolerance이 희생된다.

CAP 이론과 NoSQL

데이터 저장소는 CAP 중에서 2가지만 선택할 수 있다. 예를 들어 RDB는 CA에 특화되어 있기 때문에 분산 환경에 적용이 어렵다.
NoSQL 제품은 CAP 중에서 C 또는 A를 일부 포기함으로써 분산 확장이 가능하다. 일반적으로 NoSQL 시스템은 관계형을 포기하거나 트랜잭션 구조를 느슨하게 함으로써 수평 확장이 가능하도록 한다.

CAP과 데이터 모델에 따른 구분 (각각의 구분은 설정에 따라 변경될 수 있다.)

RDB 대안

RDB 대안에 NoSQL만 있는 것은 아니다.

RDB CLUSTER

  • Oracle RAC, MySQL cluster
  • 분산 확장과 안정성을 강화한 RDB 솔루션
  • 단점)
    • 확장 비용이 비싸고 적용 및 관리에 고급 기술이 필요하다.
    • 읽기 성능만 향상된다.
  • 장점)
    • 최소한의 개발 비용으로 도입이 가능하다.
    • 비용 예측이 가능하다.
    • 상용화된 지원이 가능하다.

MEMORY CACHE

  • memcached, Coherence, Santa
  • RDB 앞단에 메모리 캐시를 두고 읽기 또는 읽기/쓰기를 캐싱한다.
  • 단점)
    • 메모리 비용이 비싸다.
    • 메모리 크기에 제약이 있다.
    • RDB를 저장소로 사용하지만 장애시 일부 데이터가 손실될 수 있다.
  • 장점)
    • 가격대비 효율성이 disk보다 훨씬 높다.
    • 읽기/쓰기 성능을 크게 향상시킬 수 있다.
    • 읽기/쓰기 수평 확장이 가능하다.

NOSQL

  • 디스크 기반의 수평 확장이 뛰어난 데이터 저장소
  • 단점)
    • Persistence Layer를 새로 개발해야 한다.
    • 사용화된 지원이 어려울 수 있다.
  • 장점)
    • 읽기/쓰기 성능 및 확장성이 뛰어나다.
    • 일반 저가 장비를 사용할 수 있다.

NOSQL 교체 비용, 가치, 특징 비교

API, DATA MODEL

  • Interfaces- REST (HBase, CouchDB, Riak, etc.), MapReduce (HBase, CouchDB, MongoDB, Hypertable, etc.), Get/Put (Voldemort, Scalaris, etc.), Thrift (HBase, Hypertable, Cassandra, etc.), Language Specific APIs (MongoDB).
  • Logical Data Models-Key-Value oriented (Voldemort, Dynomite etc.), Column Familiy oriented (BigTable, HBase, Hypertable etc.), Document oriented (Couch DB, MongoDB etc.), Graph oriented (Neo4j, Infogrid etc.)
  • Data Distribution Model- Consistency and Availability(HBase, Hypertable, MongoDB etc), Availability and Partitionality (Cassandra etc.).
  • DataPersistence-Memory Based (e.g. Redis, Scalaris, Terrastore), Disk Based (e.g., MongoDB, Riak etc.), Combination of both Memory and Disk(e.g., HBase, Hypertable, Cassandra).



noSQL란 무엇인가? 개발


noSQL기술이 BigData처리와 함께 갑자기 화두가 되고 있다. 5년전 memory cache기반의 noSQL기술을 접했을 때에는 '이걸로 과연 어디에 적용할 수 있을까?' 하며 부정적이었는데, 어느새 이런 기술이 이전의 많은 기술을 뒤엎기라도 할 기세다. 아무튼 noSQL에 대한 나의 부정적인 감정(?)에 대한 토로는 나중으로 미루고 이번에는 noSQL의 기본 개념에 대해 정리해보자.

구글의 BigTable paper에 보면 구글의 BigTable이 대체 무엇인지에 대해 간단하고 명료하게 기술하고 있다.

A Bigtable is a sparse, distributed, persistent multidimensional sorted map.

이 간단한 문장에 noSQL기반 기술의 거의 모든 기본이 들어있다고 보면 된다. 자 이제 하나 하나 파들어가볼까?

Map이다

이게 정말 핵심중의 핵심이다. 이것만 이해해도 상당히 많은 기본개념을 이해한거라 나는 생각한다. 바쁘면 이제 이 글의 나머지를 안 읽어도 된다(^^). 거의 모든 noSQL은 Map이다. 즉, 유일한 키와 그것에 관련된 하나의 값을 가진 자료형이 noSQL이 데이타를 저장하는 기본적인 방식이다. JSON방식으로 예를 들면 다음과 같은 형태로 noSQL은 자료를 저장한다.
{
 "zzzzz" : "woot",
 "xyz" : "hello",
 "aaaab" : "world",
 "1" : "x",
 "aaaaa" : "y"
}
영구적이다 (Persistence)
noSQL은 기본적으로 데이타베이스의 역할을 수행한다. 당연히 데이타는 어느 정도 이상은 영구적이어야한다. 다만 메모리기반의 noSQL의 경우 이 영구적인 특성이 조금 떨어진다고 볼수도 있겠다.

분산기반이다 (Distribute)

noSQL이 나온 배경중의 하나는 기존의 RDB가 데이터 확장에 따른 확장성에 제약이 심했기 때문이다. 따라서 대부분의 noSQL은 데이터 저장 및 복제에 대해 설계 초기부터 분산시스템을 기반에 두게 되었다. 구글의 BigTable의 경우 Google File System(GFS)을 기반으로 하고, HBase를 비롯한 많은 noSQL은 하둡(Hadoop)의 분산 파일 시스템(HDFS)을 사용한다.
데이타 복제와 분산처리를 어떻게 하는지 자체에 대한 것은 사실 noSQL 기본 개념과는 큰 상관이 없는 주제이므로, 그리고 나도 사실 그쪽에는 내공이 딸리므로 넘어가자.

정렬기능이 있다 (Sorted)

모든 noSQL이 이 기능을 가지고 있다는 게 아니라 HBase, BigTable같은 일부가 가지고 있는 기능이다. 키와 값이 알파벳순으로 정렬이 되는 기능을 가진다. 실로 어마어마한 데이타를 처리하기 위한 용도로 만들어진게 noSQL이다보니 이런 정렬기능은, 혹은 이런 정렬기능의 성능은 너무나도 중요한 요소이다.

다차원적이다 (Multidimentional)

noSQL의 개념이 기존 데이타베이스에 익숙한 사람들에게 전달되기 위해 많은 noSQL기술들이 기존의 개념을 많이 차용한다. 테이블이나 칼럼 혹은 Row같은 RDB의 개념이 그대로 noSQL에서도 쓰이는 경우가 있고 이로 인해 noSQL의 이해를 어렵게 하는 경우가 있다. 새술은 새푸대에 담았으면 싶다. 그래서 다차원적인 Map을 지원하는게 noSQL의 특징이라고 강조하고 싶다. 다차원적이라는 말이 어렵다면 Map의 Map을 지원한다라고 할까? 즉,
{
 "1" : {
 "A" : "x",
 "B" : "z" },
 "aaaaa" : {
  "A" : "y",
  "B" : "w"
},
 "aaaab" : {
  "A" : "world",
  "B" : "ocean"
},
 "xyz" : {
 "A" : "hello",
  "B" : "there"
},
 "zzzzz" : {
 "A" : "woot",
 "B" : "1337"
}
}
위의 코드와 같이 Map의 Map의 형태로 데이터를 저장하는 것이 가능하다. 이 특성을 이용해서 "1"이나 "aaaa"를 row에 대한 키로 정의하고 "A"나 "B"를 column의 키로 정의하는 것이 가능하고 전체를 하나의 테이블로 정의할수도 있겠다.

엉성하다 (Sparse)
noSQL의 데이타 모델의 특징은 엉성하다는데 있기도 하다. 기존 RDB가 명확한 데이타 스키마 기반으로 데이타를 처리하고 그 스키마를 변경하는데 많은 비용이 들었다면, noSQL의 경우는 그보다 훨씬 더 데이타 모델에 대해 유연성을 제공한다.
{  // ...
 "zzzzz" :
{ "A" :
{
"catch_phrase" : "woot",
}
  }
}
위의 예처럼, "zzzz" Row의 "A"칼럼은 이제까지 없었던 "catch_phrase"라는 키를 가지고 있다. 이처럼 noSQL은 데이타 모델에 대해 훨씬 더 유연한 특성을 가지고 있다.

그럼 어떤 종류의 noSQL이 있을까?
맵+엉성+다차원= memcache: 일단 가장 단순한 형태로 memcache를 들수 있다. 쉽게 말해 메모리상에 맵형태로 데이터를 처리하는 방식인데, 이 메모리가 해싱기법에 의해 다중 서버에 의해 관리되는 방식이다. 클라이언트는 자신만의 해싱키를 이용해서 자기가 원하는 서버에 데이터를 저장하고 처리할 수 있다. 하지만 Persistence를 지원하거나 확장성이 높은 형태를 지원하지는 않는다. 또한 메모리만을 사용하므로 가격이 저렴한 편도 아니다. 하지만 가장 단순하게 noSQL을 적용해서 처리할 수 있는 기술이고 특히 캐시용도로 많이 사용한다.

맵+엉성+다차원+분산= 오라클 coherence, IBM ObjectGrid: memcache에다가 그리드 기반의 기술을 접목한 것으로 메모리만 충분히 많다면 가장 빠른 처리시스템을 보유할 수 있고 데이타 복제나 분산기반 확장등에 아주 많은 잇점을 가져올 수 있다. 별도의 솔루션을 이용하면 일반 Disk기반의 영속성등을 처리할 수도 있다.

맵+엉성+다차원+분산+영속성+정렬=HBase, BigTable, Cassandra: 이것은 앞서 설명했던 기본적인 noSQL의 기능을 대부분 가지고 있는 기술들이다. 더 설명할 게 없다. MongoDB같은 문서기반의 noSQL도 설명할 수도 있겠는데, 일단 본 포스트는 기본 개념에 충실하자고 쓴 글이므로 여기서 마무리 한다.


이정도면 기본이겠지
noSQL기술이 얼마나 앞으로 사람들을 더 열광시킬지 잘 모르겠다. 분명 재미있는 기술이고 부분적으로나마 상당히 효과를 볼만한 곳이 많은 기술이다. 아무튼 기본적인 noSQL의 개념은 여기까지...

Eclipse + Drools 설치 및 확인하기 개발

[Drools 5.1 다운로드 + Eclipse 설정]

  1. http://www.jboss.org/drools/downloads.html 접속
  2. Drools Binaries 다운로드
    → Drools 5.1 Runtime 이므로 임의 위치에 압축을 해제한다.
  3. Drools Eclipse 3.5 Workbench 다운로드
    → Drools 5.1 Eclipse Plug-In 이므로 Eclipse 설치한 곳에 압축을 해제한다.
  4. Drools Runtime 설정
    → Eclipse 실행
    → 메뉴 “Windows – Preferences – Drools – Installed Drools Runtime”
    → Add 클릭
    → Create a new Drools 5 Runtime… 클릭
    → Drools 5.1 Runtime 경로 지정  (ex, D:\BOX-PROGRAMMiNG\drools-5.1.1-bin) (2번에 해당)
    → Installed Drools Runtimes 선택 후 OK 클릭
  5. Drools Project 생성 테스트
    → ”File – New – Project”
    → “Drools – Drools Project”
    → Project Name 지정 – Next 클릭
    → New Drools Project – 전부 체크 – Next 클릭
    → Generate code compatible with – Drools 5.1.x 선택 – Finish 클릭
    → Project Name\src\main\java\com\sample\DroolsTest.java 선택
    → 메뉴 “Run – Run”
    → Console 창에 아래와 같이 나오면 설정 완료


    Hello World
    Goodbye cruel world


스프링 배치(Spring Batch) 관련 국내 자료 Java - 자바

정상혁

이미 35개 이상의 Accenture 고객사에 Spring batch가 적용되고 있다

스프링배치 연재(1) 배치처리의 특징

스프링배치 연재(2) 대용량 처리 배치 프로그램을 만들 때 유의할 점

스프링배치 연재(3) 스프링배치 프로젝트와 주요 기능들

스프링배치 연재(4) 스프링배치의 구조와 구성요소들

스프링배치 연재(5) ItemReader와 ItemWriter

스프링배치 연재(6) 플랫파일 읽기와 쓰기

스프링배치 연재(7) XML파일 읽기와 쓰기

스프링배치 연재(8) JDBC를 이용한 Cursor 기반의 DB 조회

스프링배치 연재(9) JobRepository

스프링배치 연재(10) JobLauncher와 Job, Step

스프링배치 연재(11) 재시작과 재시도

스프링배치 연재(12) 이벤트 처리, 유효성 검사, 변환, 기존 클래스 활용

스프링배치 연재(13) 스프링배치의 형제들

스프링배치 연재(14) 드라이빙 쿼리와 iBatis의 활용

스프링배치 연재(15) 하이버네이트 활용과 여러파일 읽기

스프링배치 연재(16) DB to XML 파일 만들기 예제

배치 어플리케이션 실행 스크립트와 빌드

 

박찬욱님

엘레강스한 배치 추상화 프레임웍 - 스프링 배치

[Beta 1.0]Spring Batch 프레임웍 레퍼런스 한글 편역 버전.

[Beta 2.0] Spring Batch 프레임웍 레퍼런스 한글 편역 버전.

[Beta 3.0] Spring Batch 프레임웍 레퍼런스 한글 편역 버전.

 

제 1부. 스프링 배치 기본 아키텍처와 잡(Job) 직접 실행해보기

제 2부. FlatFileItemReader와 그 친구들(파트1) 

제 2부. FlatFileItemReader와 그 친구들(파트2) (소스 및 PPT)

제 3부. FlatFileItemWriter와 아이템 변환하기 (소스 및 PPT)

제 4부. StAX 기반 아이템 처리 (소스 및 PPT)

제 5부. 데이터베이스에 아이템 쓰고, 읽고~ (소스 및 PPT)

제 6부. 배치 반복 처리하기

 

Spring Batch 쓰임새 분석 - 단순한 배치 반복하기

Spring Batch 쓰임새 분석 - 자동적인 재시작

Batch Processing Strategies at Spring Batch 

스프링 배치's 액터(Actor)

 

Spring Batch 1.0에서 2.0으로 진화하기- 1. ItemReader/ItemWriter(1)

Spring Batch 1.0에서 2.0으로 진화하기- 1. ItemReader/ItemWriter(2)

Spring Batch 1.0에서 2.0으로 진화하기- 3. JobExecutionLisneter & 4. ItemProcessor

Spring Batch 1.0에서 2.0으로 진화하기- 5. Configuration

 

백기선님

The Domain Language of Batch - Spring Batch Chapter 2

ItemReader - Spring Batch Chapter 3

경구사님

Spring batch 개발환경 설정

 

김승권님

차세대배치시스템구축성공전략

 - [Spring batch]차세대 배치시스템 구축 성공전략 - JCO컨퍼런스

박재성님

Spring Batch 시작하기

 

KSUG포럼

SpringBatch에 대한 경험담을 듣고 싶습니다.

Spring Batch ItemReader 구현체에 대한 궁금증 


Java Object Serialization에 대해 모르고 있던 5가지 사항 Java - 자바

출처 : http://www.ibm.com/developerworks/kr/library/j-5things1/index.html

직렬화된 데이터가 안전하다고 생각한다면 다시 한번 생각하라.
Ted Neward, Principal, Neward & Associates

요약: 
Java Object Serialization은 모든 사람이 당연하게 생각하는 Java 프로그래밍의 기본 기술입니다. 
하지만 Java 플랫폼의 많은 특성과 마찬가지로 Serialization도 자세히 알수록 더욱 유용하게 사용할 수 있습니다. 
기사에서 Ted Neward는 Java Object Serialization API를 다시 한번 봐야 하는 5가지 이유와 함께 
직렬화된 데이터의 리팩토링, 암호화 및 유효성 검증을 위한 트릭(및 코드)을 설명합니다.

Java 프로그래밍에 대해 알고 있다고 생각하는가? 하지만 실제로는 대부분의 개발자가 작업을 수행하기에 충분할 정도만 알고 있을 뿐 Java 플랫폼에 대해서는 자세히 알고 있지 않다. 이 시리즈에서 Ted Neward는 Java 플랫폼의 핵심 기능에 대한 자세한 설명을 통해 까다로운 프로그래밍 과제를 해결하는 데 도움이 되는 알려져 있지 않은 사실을 밝힌다.
1년여 전 애플리케이션의 사용자별 설정 관리를 담당한 개발자는 설정 내용을 Hashtable에 저장한 후 지속성을 위해 Hashtable을 디스크에 직렬화했다. 사용자가 해당 설정을 변경하면 Hashtable은 단순히 디스크에 다시 기록되었다.
이는 일반적인 개방형 설정 시스템이었지만 팀에서 Hashtable을 Java Collections 라이브러리의 HashMap으로 이주하기로 결정할 경우 문제가 발생한다.
Hashtable과 HashMap은 디스크 양식이 서로 다르기 때문에 호환되지 않는다. @@@영구적인 각 사용자 설정에 대해 데이터 변환 유틸리티를 실행하지 않으면(임시 태스크) Hashtable은 라이프사이클의 나머지 기간 동안 애플리케이션의 저장소 형식인 것처럼 보인다.@@@
팀은 한계를 절감하게 된다. 하지만 이는 Java Serialization와 관련된 중요한(그러면서도 약간 모호한) 무엇인가를 모르기 때문이다. 그것은 바로 Java Serialization이 시간이 지나면서 유형의 확장이 가능하도록 빌드되었다는 것이다. 필자가 자동 직렬화 대체를 수행하는 방법을 보여주자 HashMap으로의 변환이 계획대로 진행되었다.
@@@이 기사는 Java 플랫폼의 유용한 기능을 밝히기 위한 시리즈의 첫 번째 기사로서 Java 프로그래밍 과제를 해결하는 데 유용한 정보를 제공한다.@@@
Java Object Serialization은 JDK 1.1부터 제공되었기 때문에 시작하기에 매우 좋은 API이다. 이 기사에서 설명하는 Serialization에 대한 5가지 사항을 알고 나면 표준 Java API라고 하더라도 다시 한번 볼 필요가 있다는 생각이 들 것이다.

Java Serialization 101
JDK 1.1의 획기적인 기능 세트의 일부로 도입된 Java Object Serialization은 Java 오브젝트 그래프를 저장 또는 전송을 위해 바이트 배열로 변환하고 나중에 다시 바이트 배열을 Java 오브젝트 그래프로 변환할 수 있는 메커니즘을 제공한다.
기본적으로 직렬화라는 개념은 오브젝트 그래프를 "고정"하고 디스크 또는 네트워크로 이동한 다음 그래프를 사용 가능한 Java 오브젝트로 "되돌리는" 것이다. 이 모든 작업은 ObjectInputStream/ObjectOutputStream 클래스, 신뢰성 높은 메타데이터 및 클래스에 Serializable 표시자 인터페이스를 태그로 지정하여 이 프로세스를 "선택"한 프로그래머의 의지로 인해 마술처럼 발생한다.
Listing 1에서는 Serializable을 구현한 Person 클래스를 보여 준다.

Listing 1. Serializable Person
---------------------------------------------------------------------
public class Person implements java.io.Serializable {
    public Person(String fn, String ln, int a) {
        this.firstName = fn; this.lastName = ln; this.age = a;
    }

    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }
    public int getAge() { return age; }
    public Person getSpouse() { return spouse; }

    public void setFirstName(String value) { firstName = value; }
    public void setLastName(String value) { lastName = value; }
    public void setAge(int value) { age = value; }
    public void setSpouse(Person value) { spouse = value; }

    public String toString() {
        return "[Person: firstName=" + firstName + 
            " lastName=" + lastName +
            " age=" + age +
            " spouse=" + spouse.getFirstName() +
            "]";
    }    

    private String firstName;
    private String lastName;
    private int age;
    private Person spouse;
}
---------------------------------------------------------------------

Person을 직렬화한 후에는 JUnit 4 유닛 테스트에서 본 것처럼 매우 쉽게 오브젝트 그래프를 디스크에 쓰고 다시 읽어올 수 있다.


Listing 2. Person의 직렬화 해제하기
---------------------------------------------------------------------
public class SerTest
{
    @Test public void serializeToDisk() {
        try {
            com.tedneward.Person ted = new com.tedneward.Person("Ted", "Neward", 39);
            com.tedneward.Person charl = new com.tedneward.Person("Charlotte", "Neward", 38);

            ted.setSpouse(charl); charl.setSpouse(ted);

            FileOutputStream fos = new FileOutputStream("tempdata.ser");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(ted);
            oos.close();
        } catch (Exception ex) {
            fail("Exception thrown during test: " + ex.toString());
        }
        
        try {
            FileInputStream fis = new FileInputStream("tempdata.ser");
            ObjectInputStream ois = new ObjectInputStream(fis);
            com.tedneward.Person ted = (com.tedneward.Person) ois.readObject();
            ois.close();
            
            assertEquals(ted.getFirstName(), "Ted");
            assertEquals(ted.getSpouse().getFirstName(), "Charlotte");

            // Clean up the file
            new File("tempdata.ser").delete();
        } catch (Exception ex) {
            fail("Exception thrown during test: " + ex.toString());
        }
    }
}
---------------------------------------------------------------------

지금까지 살펴본 작업이 바로 Serialization 101이며, 새롭거나 흥미로운 내용은 아니지만 시작하기에 좋은 주제이다. 
이 기사에서는 Person을 사용하여 아마도 Java Object Serialization에 대해 지금까지 모르고 있었을 5가지 사항을 살펴본다.

1. Serialization은 리팩토링을 지원한다.

Serialization은 어느 정도의 클래스 변형을 허용한다. 즉, 리팩토링 후라도 ObjectInputStream은 클래스를 잘 읽는다.
중요한 점은 Java Object Serialization 스펙이 다음 사항을 자동으로 관리할 수 있다는 것이다.
클래스에 새 필드 추가하기
정적 필드를 비정적 필드로 변경하기
투명 필드를 불투명 필드로 변경하기
역으로(비정적에서 정적 또는 불투명에서 투명으로) 변경하거나 필드를 삭제하려면 필요한 이전 버전과의 호환성 정도에 따라 추가 작업이 필요하다.
직렬화된 클래스 리팩토링하기
이제 Serialization에서 리팩토링이 지원되는 것을 알았으므로 Person 클래스에 새 필드를 추가할 경우 어떤 일이 발생하는지 살펴보자.
Listing 3에서 PersonV2는 원본 Person 클래스에 성별에 대한 필드를 추가한다.

Listing 3. 직렬화된 Person에 새 필드 추가하기
---------------------------------------------------------------------
enum Gender {
    MALE, FEMALE
}

public class Person implements java.io.Serializable {
    public Person(String fn, String ln, int a, Gender g) {
        this.firstName = fn; this.lastName = ln; this.age = a; this.gender = g;
    }
  
    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }
    public Gender getGender() { return gender; }
    public int getAge() { return age; }
    public Person getSpouse() { return spouse; }

    public void setFirstName(String value) { firstName = value; }
    public void setLastName(String value) { lastName = value; }
    public void setGender(Gender value) { gender = value; }
    public void setAge(int value) { age = value; }
    public void setSpouse(Person value) { spouse = value; }

    public String toString() {
        return "[Person: firstName=" + firstName + 
            " lastName=" + lastName +
            " gender=" + gender +
            " age=" + age +
            " spouse=" + spouse.getFirstName() +
            "]";
    }    

    private String firstName;
    private String lastName;
    private int age;
    private Person spouse;
    private Gender gender;
}
---------------------------------------------------------------------

Serialization은 지정된 소스 파일의 모든 정보(메소드 이름, 필드 이름, 필드 유형, 액세스 한정자 등)를 기반으로 하는 계산된 해시를 사용하며 이 해시 값을 직렬화된 스트림의 해시 값과 비교한다.
Java 런타임에서 이 두 유형이 동일하다는 것을 확신할 수 있도록 두 번째 및 이후 버전의 Person에는 첫 번째와 동일한 직렬화 버전 해시(private static final serialVersionUID 필드로 저장됨)가 있어야 한다. 따라서 이제 필요한 것은 원본(또는 V1) 버전의 Person 클래스에 대해 JDK serialver 명령을 실행하여 계산된 serialVersionUID 필드이다.
Person의 serialVersionUID가 있으면 이제 원본 오브젝트의 직렬화된 데이터를 사용하여 PersonV2 오브젝트를 작성할 수 있다. (새 필드가 있을 경우 이러한 필드는 기본적으로 필드의 기본값에 상관 없이 대부분 "널"이다.) 또한 그 역의 경우도 가능하다. 즉, 추가 작업 없이 PersonV2 오브젝트를 사용하여 원본 Person 오브젝트를 직렬화 해제할 수 있다.

2. Serialization은 안전하지 않다.

Serialization 2진 형식이 완전히 문서화되어 있고 역으로 변환할 수 있다는 사실이 Java 개발자에게는 유쾌한 일이 아닐 것이다. 실제로 직렬화된 2진 스트림의 컨텐츠를 콘솔에서 보면 클래스의 형태와 내용을 충분히 파악할 수 있다.
여기에는 보안과 관련하여 약간 걱정되는 부분이 있다. 예를 들어, RMI를 통해 원격 메소드를 호출할 경우 네트워크를 통해 전송되는 오브젝트의 private 필드는 소켓 스트림에서 거의 일반 텍스트로 표시된다. 이는 가장 단순한 보안 사항마저도 명백하게 위반하는 것이다.
다행스럽게도 Serialization에는 직렬화 이전과 직렬화 해제 이후에 직렬화 프로세스를 "선택"해서 필드 데이터에 대한 보안 설정(또는 감추기)을 수행할 수 있는 기능이 있다. Serializable 오브젝트의 writeObject 메소드를 사용하여 이를 수행할 수 있다.
직렬화된 데이터 감추기
Person 클래스의 age 필드에 중요한 데이터가 있다고 가정하자. 신사와 숙녀라면 자신의 나이를 밝히지 않는다. 직렬화 전에 비트를 왼쪽으로 한 번 회전시켜서 이 데이터를 감춘 후 직렬화 해제 이전에 반대 방향으로 회전시켜서 복구할 수 있다. (이는 간단한 예제에 불과하며 더욱 안전한 알고리즘 개발은 독자에게 맡긴다.)
직렬화 프로세스를 "선택"하기 위해 Person에 writeObject 메소드를 구현한다. 그리고 직렬화 해제 프로세스를 "선택"하기 위해 동일한 클래스에 readObject 메소드를 구현한다. 두 메소드 모두 세부 사항을 자세히 알아야 한다. 액세스 한정자, 매개변수 또는 이름이 Listing 4와 다르면 어떠한 경고도 없이 코드가 실패하며 Person의 나이가 다른 사람에게 표시되기 때문이다.

Listing 4. 직렬화된 데이터 감추기
---------------------------------------------------------------------
public class Person
    implements java.io.Serializable
{
    public Person(String fn, String ln, int a)
    {
        this.firstName = fn; this.lastName = ln; this.age = a;
    }

    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }
    public int getAge() { return age; }
    public Person getSpouse() { return spouse; }
    
    public void setFirstName(String value) { firstName = value; }
    public void setLastName(String value) { lastName = value; }
    public void setAge(int value) { age = value; }
    public void setSpouse(Person value) { spouse = value; }

    private void writeObject(java.io.ObjectOutputStream stream) throws java.io.IOException {
        // "Encrypt"/obscure the sensitive data
        age = age << 2;
        stream.defaultWriteObject();
    }

    private void readObject(java.io.ObjectInputStream stream) throws java.io.IOException, ClassNotFoundException {
        stream.defaultReadObject();
        // "Decrypt"/de-obscure the sensitive data
        age = age << 2;
    }
    
    public String toString() {
        return "[Person: firstName=" + firstName + 
            " lastName=" + lastName +
            " age=" + age +
            " spouse=" + (spouse!=null ? spouse.getFirstName() : "[null]") +
            "]";
    }      

    private String firstName;
    private String lastName;
    private int age;
    private Person spouse;
}
---------------------------------------------------------------------
감춘 데이터를 볼 필요가 있는 경우에는 언제라도 직렬화된 데이터 스트림/파일을 살펴볼 수 있다. 
그리고 형식이 완전히 문서화되어 있으므로 클래스를 사용할 수 없더라도 직렬화된 스트림의 컨텐츠를 읽을 수 있다.

3. 직렬화된 데이터를 서명 및 봉인할 수 있다.

앞의 팁에서는 직렬화된 데이터를 감추기만 했을 뿐이다. 데이터를 암호화하지도 않았고 데이터가 수정되지 않았음을 보장하지도 않았다. writeObject 및 readObject를 사용하여 암호화 및 서명 관리가 분명 가능하기는 하지만 더 좋은 방법이 있다.
전체 오브젝트를 암호화하고 서명할 필요가 있을 경우 가장 간단한 방법은 javax.crypto.SealedObject 및/또는 java.security.SignedObject 랩퍼에 전체 오브젝트를 포함시키는 것이다. 두 랩퍼 모두 직렬화가 가능하므로 SealedObject로 오브젝트를 랩핑하면 원본 오브젝트를 포장하고 있는 일종의 "선물 상자"가 작성된다. 암호화를 수행하려면 대칭 키가 필요하며 이 키는 개인적으로 관리해야 한다. 이와 마찬가지로 SignedObject를 사용하여 데이터를 확인할 수 있으며, 이 경우에도 대칭 키를 개인적으로 관리해야 한다.
이 두 오브젝트를 함께 사용하면 디지털 서명 확인 또는 암호화에 대한 세부 사항을 몰라도 직렬화된 데이터를 봉인하고 서명할 수 있다. 간단하지 않은가?

4. Serialization은 프록시를 스트림에 배치할 수 있다.

클래스에 클래스의 나머지 부분을 파생 또는 검색할 수 있는 데이터의 핵심 요소가 있는 경우도 있다. 그러한 경우에는 오브젝트 전체를 직렬화하지 않아도 된다. 해당 필드를 투명으로 표시할 수 있다. 하지만 클래스는 여전히 메소드가 해당 필드에 액세스할 때마다 필드가 초기화되었는지 확인하는 코드를 명시적으로 생성해야 한다.
주제가 직렬화이므로 스트림에 배치할 플라이웨이트(flyweight) 또는 프록시에 대해 알아보자. 원본 Person의 writeReplace 메소드를 제공하면 다양한 오브젝트를 적절하게 직렬화할 수 있다. 마찬가지로 readResolve 메소드도 직렬화 해제 동안에 사용된다. 이를 호출자에게 대체 오브젝트를 제공한다라고 한다.
프록시 패킹 및 언패킹하기
writeReplace 및 readResolve 메소드를 함께 사용하면 Person 클래스에서 PersonProxy를 모든 데이터(또는 일부 핵심 데이터)와 함께 패킹하여 스트림에 배치한 다음 나중에 직렬화 해제 동안 패킹을 해제할 수 있다.

Listing 5. 완성과 대체
---------------------------------------------------------------------
class PersonProxy implements java.io.Serializable {
    public PersonProxy(Person orig) {
        data = orig.getFirstName() + "," + orig.getLastName() + "," + orig.getAge();
        if (orig.getSpouse() != null) {
            Person spouse = orig.getSpouse();
            data = data + "," + spouse.getFirstName() + "," + spouse.getLastName() + ","  + spouse.getAge();
        }
    }

    public String data;
    private Object readResolve() throws java.io.ObjectStreamException {
        String[] pieces = data.split(",");
        Person result = new Person(pieces[0], pieces[1], Integer.parseInt(pieces[2]));
        if (pieces.length > 3) {
            result.setSpouse(new Person(pieces[3], pieces[4], Integer.parseInt
              (pieces[5])));
            result.getSpouse().setSpouse(result);
        }
        return result;
    }
}

public class Person implements java.io.Serializable {
    public Person(String fn, String ln, int a) {
        this.firstName = fn; this.lastName = ln; this.age = a;
    }

    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }
    public int getAge() { return age; }
    public Person getSpouse() { return spouse; }

    private Object writeReplace() throws java.io.ObjectStreamException {
        return new PersonProxy(this);
    }
    
    public void setFirstName(String value) { firstName = value; }
    public void setLastName(String value) { lastName = value; }
    public void setAge(int value) { age = value; }
    public void setSpouse(Person value) { spouse = value; }   

    public String toString() {
        return "[Person: firstName=" + firstName + 
            " lastName=" + lastName +
            " age=" + age +
            " spouse=" + spouse.getFirstName() +
            "]";
    }    
    
    private String firstName;
    private String lastName;
    private int age;
    private Person spouse;
}
---------------------------------------------------------------------
PersonProxy는 Person의 모든 데이터를 추적해야 한다. 
이는 private 필드에 액세스하기 위해 프록시가 Person의 내부 클래스여야 한다는 것을 의미하기도 한다.
또한 프록시가 다른 오브젝트 참조(예: Person의 배우자)를 추적하고 수동으로 직렬화해야 하는 경우도 있다.
이 방법은 읽기/쓰기를 함께 사용하지 않아도 되는 몇 가지 방법 중 하나이다. 
예를 들어, 다른 유형으로 리팩토링된 버전의 클래스는 직렬화된 오브젝트를 새 유형으로 자동으로 전환하는 readResolve 메소드를 제공할 수 있다. 
마찬가지로 writeReplace 메소드를 사용하여 기존 클래스를 가져와서 새 버전으로 직렬화할 수도 있다.

5. 믿지만 검증한다.
직렬화된 데이터는 스트림에 원래 기록되었던 데이터와 항상 같다고 가정하는 것이 좋다.
하지만 전 미국 대통령의 말대로 "믿지만 검증"하는 것이 더 안전한 정책이다.
직렬화된 오브젝트의 경우 이 말은 직렬화 이후 필드의 값이 유효한지 "확인"하기 위해 필드를 유효성 검증한다는 의미이다. 
ObjectInputValidation 인터페이스를 구현하고 validateObject() 메소드를 오버라이드하여 이를 수행할 수 있다. 
이 메소드를 호출할 때 오류가 발생하면 InvalidObjectException이 발생한다.

결론
Java Object Serialization은 대부분의 Java 개발자가 인식하고 있는 것보다 훨씬 유연하며 까다로운 상황을 해결할 수 있는 충분한 기회를 제공한다.
다행스럽게도 이와 같은 코딩 기술은 JVM 어디에서나 발견할 수 있다. 중요한 것은 이러한 코딩 기술을 알고 있어야 하고 어려운 문제가 발생했을 때 활용해야 한다는 것이다.




java system command call Java - 자바


1. exec call
 public void Mon() {
   try {
      String[] comm = {"/bin/sh", "-c", "ps -ex | grep XXX > pslist.txt" };
      Process ps = Runtime.getRuntime().exec(comm );
.....

2. memory use

public class sample {
String lm_sPs;

public sample() {
lm_sPs = "ps -ex";
};

public void Mon() {
try {
Process ps = Runtime.getRuntime().exec(lm_sPs);
byte[] msg = new byte[1024];
String str;
int len;
while ((len = ps.getInputStream().read(msg)) > 0) {
str = new String(msg).substring(10);
System.out.println(str);
}
System.out.println("수행결과: " + ps.exitValue());
} catch (Exception e) {
e.printStackTrace();
}
return;
}

public static void main(String[] arg) {
sample mon = new sample();
mon.Mon();
}
}


동일 컨테이너상 서로다른 webapp 선언으로 인한 문제해결 개발


동일 작업대상을 협업으로 개발할때 log4j설정중 로그파일 위치는 각 개발자간 서로다른 경로상에 위치하게 된다.

웹 base개발인 경우 본인은 이 문제를 해결하기 위해
web.xml의 context-param 을 통해서 각 개발자간 상이한 환경에서도 동적으로 webroot경로를
얻기 위해 다음과 같이 정의하여 사용한다.
web.xml
    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>webapp.root</param-value>
    </context-param>

log4j.xml
    <appender name="DAILY" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="datePattern" value="'.'yyyy-MM-dd" />
        <param name="file" value="${webapp.root}/WEB-INF/logs/epms.log" />
        <param name="append" value="true" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%t> [%d{yyyy-MM-dd HH:mm:ss}] [%c{1}] [%L] [%p] %m %n"/>
        </layout>
    </appender>

 단일 컨테이너(WAS)상에 위의 형태를 사용하는 web app가 한개인 경우는 아무런 문제 없이 작동한다. 
하지만 두 개 이상의 web app가 구동되면 여지없이 기동시에 에러를 발생시킨다.

이유인즉 context-param에 선언되는 webAppRootKey name의 경우
system property의 key로 설정된다는것이다.
즉, System.getProperty("webapp.root") 이렇게 사용될 수 있다는것이다.
그러므로 서로다른 webapp내에 context-param이라 할지라도
system property로 활용되기에 중복된 key값을 사용할 수 없으므로 나타나는 에러인것이다.
어쩔수 없이 context-param의 value는 유니크한 값으로 선언할 수 밖에 없을것 같다.
다음과 같이 말이다. ㅡㅡ

webapp1
    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>first.webapp.root</param-value>
    </context-param>

    <appender name="DAILY" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="datePattern" value="'.'yyyy-MM-dd" />
        <param name="file" value="${first.webapp.root}/WEB-INF/logs/epms.log" />
        <param name="append" value="true" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%t> [%d{yyyy-MM-dd HH:mm:ss}] [%c{1}] [%L] [%p] %m %n"/>
        </layout>
    </appender>

webapp2
    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>second.webapp.root</param-value>
    </context-param>

    <appender name="DAILY" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="datePattern" value="'.'yyyy-MM-dd" />
        <param name="file" value="${second.webapp.root}/WEB-INF/logs/epms.log" />
        <param name="append" value="true" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%t> [%d{yyyy-MM-dd HH:mm:ss}] [%c{1}] [%L] [%p] %m %n"/>
        </layout>
    </appender>

톰캣에 SSL 등록하기 개발



Tomcat은 자바의 "keystore" 를 이용하여 인증서를 설정하므로 Tomcat으로
SSL 웹서버를 운영하려는 서버에 JDK(Java Development Kit) 1.4 버전 이상의
프로그램이 먼저 설치되어 잇어야 합니다.

테스트 환경은 다음과 같다.
tomcat 5.5
jdk 1.5
windows7

SSL 사설인증서(보안서버인증서) 발급과 JKS 등록방업은 
을 참조한다.

<Connector SSLEnabled="true" clientAuth="want"
 keystoreFile="c:/cert/sslserver.jks" keystorePass="1q2w3e4r"
 maxThreads="150" port="8443" protocol="HTTP/1.1" scheme="https"
 secure="true" sslProtocol="TLS" />

jks를 첨부한다



1 2 3 4