| 이름 기반의 유연한 객체구조를 이용하여 순차적인 데이터를 개발자가 생성하지 않고 setValue만을 호출하여 데이터처리가 가능하도록 만든 구조로 놀새가 많이 사용할 것 같아 올립니다. ( 2004/01/29 ) 144 | |||||
| Written by ienvyou - 최지웅 | |||||
| 1 of 1 | |||||
|
BLOG ARTICLE ARTICLE | 26 ARTICLE FOUND
- 2012/01/20 1:순차N구조의 name-value pair DataSet 정의
- 2009/05/29 SOA가 정착될 것인가.
- 2008/07/23 Native Method 정의 및 구현
- 2008/07/03 여전히 많은 글들이 떠돌아 다니다.
- 2008/04/09 Introduction to Complex Event Processing (CEP)
- 2008/03/26 MD5방식을 이용한 암호화 및 복원화
- 2008/03/26 Datagram Socket 정의 및 샘플
- 2008/03/26 MySQL 관련 (1)
- 2008/03/25 Shutdown Hook 작성 방법 및 샘플 (2)
- 2008/03/25 Java Security Model
놀새~의 경우 2006년 말 모 통신사 SOA BMT 및 초기 프로젝트를 수행하면서 나타났었던 XML처리에 대한 문제를 고민하고 있었습니다. 그 즈음 프로젝트 SI인 L사의 혁신팀이 데이터파워 등의 XML 가속기에 대한 사업(총판 정도?)을 하려했었고 프로젝트 팀에서는 성능 향상을 위하여 시연회 때 참석을 했었던 기억이 있습니다.
결론부터 이야기하자면 도입하지 않는다였습니다. 그 때 해당 회사가 IBM에 인수되었었는데 초기 제품인데다가 차세대 프로젝트에서 검증되지 않은 플랫폼을 도입한다는 것 자체가 모험이었습니다. "권한은 있는데 책임은 지지 않으려 하는" 심리가 확연히 드러났다라고 볼 수도 있겠습니다.
또 한가지 요인은 이미 그 때 Azul이라는 H/W형 자바가 이미 나와있었음에도 불구하고 국내에서는 거의 검토도 하지 않았습니다. 자바라는 엔터프라이즈 솔루션에 대한 가속기가 있다는 것을 거부하는 마당에 이제 도입 초기의 SOA에 XML 가속기는 어불성설이었던 셈이지요.
어찌되었건 SOA 프로젝트는 대외에 성공적으로 끝이 났다고 이야기합니다. 가만히 생각해보면 국내에 도대체 실패한 프로젝트가 있긴 하는지 궁금할 다름입니다 소위 "광팔기(고스톱에서)"케이스로 CxO레벨에서 무언가 업적을 남겨야 하므로 프로젝트 내부를 까보면 개판임에도 불구하고 어떻게든 오픈은 시켜놓는 케이스로 진행되고 있다는 겁니다. 이러한 것을 경험하신 분들도 있을 것이고 들으신 분들도 있으실 겁니다.
개념을 IT화시키는 데 걸리는 평균 시간
바코드 시스템은 1932년에 고객의 자동 구매를 위한 프로젝트로 시작이 됐습니다. 하지만 실제 최초 설치된 것은 1960년대였고 활성되기 시작한 것이 1980년대부터였습니다.
ERP(Enterprise Resource Planning)은 1960년초에 IMC(Inventory Management Control)이라는 재고 관리를 위한 시스템 개념으로부터 시작되어 1970년대 MRP(Manufacturing Resource Planning), CIM(Computer Integrated Manufacturing)으로 발전하면서 1990년대에 ERP 붐을 일으켰습니다.
CRM(Customer Relationship Management)는 전단지와 같은 카탈로그 마케팅(catalog marketing)으로 1950년대에 처음 시작이 되었고 SCM(Supply Chain Management)는 MRP II(1970년대)와 같이 시작해서 1990년대에 와서야 비로소 정착하게 됩니다.
BPM(Business Process Management)의 경우는 1970년대 제록스의 OA(Office Automation) 개념으로 시작되었으니 지금 딱 30년째이고 어느 정도 성숙 단계로 접어드는 시기입니다.
위의 경우를 살펴보았을 때 우리가 현재 사용하고 있는 IT개념들이 정착되는데 걸리는 시간이 평균 30년입니다.
EAI(Enterprise Application Integration) 등장
EAI는 1990년대 메이저 ERP 사용 기업들이 시스템을 업그레이드 하면서 레거시 시스템과의 연계 요구로 처음 생겨나게 되었습니다. 이 때 TIBCO, Vitria, WebMethod, iWay 등의 전통 EAI 업체가 생겨나게 되었습니다. 이 업체들의 특징은 기본 코어 엔진은 낮은 가격에 실제 레거시와 붙는 어댑터의 개발 생산성, 성능에 집중하므로서 고가의 어댑터를 통한 제품을 공급하기 시작하였습니다.
시작 시점은 1990년대라고 했습니다. 그러면 대부분의 EAI프로젝트는 성공을 했을까요? 보고서(Trotta, Gian(2003-12-15). "Dancing Around EAI 'Bear Traps'". http://www.ebizq.net/topics/int_sbp/features/3463.html. Retrieved on 2006-06-27)에 의하면 전세계의 70%의 EAI 프로젝트는 실패했다고 보고됩니다. 문제는 다음과 같았습니다.
- 지속적인 기업환경 변화에 시스템이 따라주지 못함
- 대상 시스템에 대한 전문가 부재
- 각 사용자 부서와 협업, 의사 소통이 제대로 이루어지지 않아 인터페이스 도출 어려움
- 기술, 문화, 정치적인 이유로 부서의 시스템을 다른 사업부에 보여주기 원치 않음
- 많은 부서 참여로 인한 요구 사항 중첩 및 해결책 모호로 인하여 최종 시스템 구조가 명확하지 않음
EAI 프로젝트의 가장 큰 폐해 요소로 기업들은 해당 패키지 애플리케이션 벤더 및 EAI 벤더에게 lock-in 되었다고 보고되었습니다.
Vendor Lock-in은 고객이 벤더, 제품, 서비스에 의존한 나머지 lock-in 비용이 발생하여 시장에 빠르게 진입하지 못하는 현상을 일컫습니다. 놀새~의 글을 읽는 분들이 겪는 가장 대표적인 케이스의 생활 벤더 lock-in은 DSLR 카메라입니다. 타사의 죽여주는 렌즈를 구입하고 싶을 때 렌즈만을 구입하는 것이 아니라 카메라 바디를 바꾸어야 하는 switch-cost가 발생을 하게 되는 경우입니다.
국내의 EAI 프로젝트를 보더라도 실제 공공, 제조는 거의 제로에 가깝다고 말할 수 있고 그나마 통신, 금융이 복잡한 시스템들로 인하여 도입을 한 경우가 상당수 있습니다. 문제는 도입됨과 동시에 빼도 박지도 못하는 상황이 발생할 수 있다는 것입니다.
그렇다면 SOA는?
1996년 가트너 보고서에는 이런 말이 실립니다.
"잘 정의된 인터페이스를 가진 재사용이 가능한 일련의 컴포넌트들로 구축되는 기술 구조 방식을 SOA(Service Oriented Architecture)라 한다"목적은 공유와 재사용이라 했습니다. 벤더들은 앞다투어 이 개념을 제품화시키기 위해 노력했고 여기에 EAI, WAS 벤더들이 마구잡이로 달려들기 시작을 했습니다. 하지만 현재의 결과는 어떨지 상상해보세요.
문제는 대부분의 벤더들이 SOA 제품을 기존의 EAI 제품에 웹서비스 기능 강화를 통하여 이루어보고자 했지만 앞서 도안구 기자께서 쓰신 글에도 MS, IBM, Oracle 등의 벤더 웹서비스도 잘 호환이 안되는 경우가 상당수 발생합니다. 결국 벤더 통합을 이루어낼 수 있는 재사용 컴포넌트 만들기란 쉽지 않다는 결론을 내릴 수도 있습니다.
신문기사를 보면 KTF가 SOA 프로젝트의 막바지에 다다랐습니다. 성능 개선작업이 진행되고 있다고 합니다. 하지만 전문가가 그리 많지 않은 상황에서 개발자들이 성능(performance)을 낼 수 있는 코드를 작성했다고 보기 또한 어렵습니다.
기사 내용 인터뷰 중 하나를 살펴보겠습니다. 한국 오라클의 인터뷰에서 "SOA는 이기종 시스템 환경에서 프로세스 혁신과 맞물려 진행할 때 큰 효과를 볼 수 있다"라고 이야기하고 있습니다. 이 기종은 맞는 이야기입니다. 하지만 PI 프로젝트와 맞물렸을 때 큰 효과는 그저 궁금할 다름입니다.
프로세스 개선(EA관점)도 중요하겠지만 가트너가 하고자 했던 SOA는 궁극적 목표는 재사용을 통한 서비스 조립으로 기업의 민첩성 향상, 즉 그만큼 다른 경쟁사보다 시장에 빨리 진입하겠다는 의도입니다. SOA 프로젝트가 효과를 보려면 전사적인 SOA 조직을 통한 서비스 컴포넌트 축적을 통하여 향후 프로젝트의 서비스가 기존의 작성된 서비스를 참조할 때 최고의 효과를 볼 수 있습니다. 즉 단기간에 효과를 볼 수 없다는 게 SOA의 가장 큰 단점일 수도 있습니다. 당연히 비용 곡선은 다음과 같이 구성되겠지요.

해법은?
나름 기업에게 제시할 수 있는 해법을 놀새~ 머리 속에 생각하고 있고 그것을 고객에게 이야기하고 있습니다. 고객은 "그렇게 하면 될 수 있겠구나"라고 맞장구는 치면서 정작 앞서 이야기한 "책임지고 싶지 않다"라는 말도 안되는 이유로 슬슬 피하네요.
혁신을 실행하지 않는다면 도태될 수 밖에 없을 것입니다.
더 쓰고 싶은데 노무현 전 대통령 및 영결식 보러 가야겠습니다.
2001년 6월에 작성된 글입니다.
※ Java Native Interface
JNI는 native method를 이용해서 C/C++의 code를 Java에서 이용할수 있는 방법이다.
native 메소드를 정의해서, 사용하는 방법에 대해 소개를 하겠습니다.
1. Example Java Source
C/C++의 code를 자바에서 불러 사용하려면, native method를 정의해야 하는데, 아래 코드와 같이 method body를 갖지않는 method를 native keyword를 통해 정의한다.
이것은 method의 body가 C/C++ code의 dll(Unix에서는 so) 파일로 되어 있다는 의미이다.
그래서 runtime에는 이 dll 파일을 메모리에 loading을 해야만 method를 실행할수가 있는데,
dll 파일을 loading하는 library는 System class의 loadLibrary() 메소드이다.
classpath경로에서 파라미터의 파일을 메모리에 loading을 하죠.
public class Hello {
public static native void print();
static {
System.loadLibrary("hello");
}
public static void main(String args[]) {
Hello.print();
}
}
compile
prompt>javac Hello.java
compile된 class를 실행하면 당연히 에러가 발생되겠죠. 다음과 같이.
prompt>java Hello
Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello in java.libr
ary.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1312)
at java.lang.Runtime.loadLibrary0(Runtime.java:749)
at java.lang.System.loadLibrary(System.java:820)
at Hello.(Hello.java:6)
2. C/C++의 Header file 생성
native method를 C/C++로 구현 하기 위해서는 Java method 선언을 C/C++의 method선언으로 mapping시켜주어야 겠죠. 이것은 javah 라는 명령어를 이용합니다.
그래서, 다음과 같은 명령어로 C/C++의 Header 파일을 생성합니다.
prompt>javah -jni -classpath . -o Hello.h Hello
//생성된 header file : Hello.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class Hello */
#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Hello
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Hello_print
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
3. C code 생성을 위한 C/C++ compiler install
생성된 header file에 정의된 JNIEXPORT void JNICALL Java_Hello_print(JNIEnv *, jclass); 메소드를 구현하기 위해 Borland C++ Compiler5.5 를 다운 받아 설치합니다.
http://www.borland.com/downloads/
설치방법은 인스톨 파일을 실행하면, 설치 디렉토리에 readme file이 있는데, bcc32.cfg, ilink32.cfg 파일을 readme 파일의 내용과 같이 만들어 bin dir에 저장하면 끝납니다.
4. C source code
Hello.h 파일에 선언된 메소드를 다음과 같이 구현한다.
#include "Hello.h"
JNIEXPORT void JNICALL Java_Hello_print
(JNIEnv *, jclass)
{
printf("Hello World");
}
5. compile and dll file 생성
다음과 같은 명령어로 compile해서 hello.dll 파일을 생성한다.
prompt>bcc32 -c -Id:\java\jdk1.3\include -Id:\java\jdk1.3\include\win32 hello.cpp
prompt>bcc32 -tWD hello.obj
6. 실행
hello.dll 파일이 현재 디렉토리에 만들어 졌기 때문에, System.loadLibrary()로 메모리에 loading할수 있고, print() 라는 native method가 실행될수 있겠죠.
prompt>java Hello
Hello World

다행히 예전 javapattern.info 사이트(아마 국내 최초 struts+tiles로 만든 사이트가 아니었나 생각합니다)에 썼던 글들을 김상욱님께서 캡쳐해 놓으셔서 그럭저럭 이 곳에 다시 옮겨는 놓았습니다.
이제 앞으로 open source관련 일을 하게 되어서 다시 글을 쓰게 될 것 같습니다. 사이트도 번외로 새롭게 구성이 될 것 같구요. 그 작업을 하는 동안에 이 사이트가 incubate 장소가 될 것 같습니다.

이벤트 프로세싱은 이미 십년전부터 있던 컴퓨터 시스템의 중심에 위치하고 있습니다. 모든 industry에 해당하는 일반적인 문제는 고객의 시스템에서 들어오는 사용하는 전체 이벤트 데이터 중 필요한 것들만 추출하는 방법이었겠네요. 이에 부응하기 위하여 DW, Data Mining 등이 BI(Business Intelligence)와 함께 중요한 경영 의사 결정 요소로 자리 잡아 온 것이 사실입니다.
제가 지금 다니고 있는 회사의 이벤트 프로세싱 엔진의 경우 메모리 내에서 pentium 4 dual processor기준으로 초당 50만건 이상을 거뜬하고 처리하고 있습니다. 사실 메모리 작업을 통해 SQL속성을 가진 query languaue를 통해서 가능한데 만약 처리의 결과가 실제 database와 연결되어 있다면 저러한 성능은 나오지 않을 겁니다.
즉 이벤트 프로세싱은 데이터를 필터링하여 내가 원하는 결과값을 보기 위한 것이기 때문에 이벤트 데이터의 속성이 중요한 것이지 결과가 저장되는 data source영역이 아님을 알고 있어야 합니다.
그림 ? 이벤트 프로세싱

그림에서 보는 것처럼 이벤트 소스는 다양한 형태로 입력될 수 있으며 그게 EAI, MOM 또는 SOA를 통하여 얻는 방법, RFID등의 다양한 이벤트를 통해 얻는 방법 등이 있을 수 있습니다.
위의 정의를 CEP(Complex Event Processing)라고 이야기합니다. CEP의 기본적인 목적은 시스템간에 실시간으로 수집되는 가치있는 정보를 분석하는 데 있습니다.
Introduction to Esper
WebLogic Event Server가 존재하지만 여기서는 Esper라는 오픈소스 CEP엔진을 간략하게 보도록 합니다. Esper는 자바로 쓰여졌으며 .NET을 원한다면 NEsper를 사용하면 .NET과 C#을 통한 CEP가 가능합니다. 다운로드는 esper.codehaus.org에서 할 수 있으며 예제와 문서가 잘 정리되어 있습니다.
특징은 WebLogic Event Server와 마찬가지로 SQL과 흡사한 data query language를 사용하기 때문에 손쉽게 이벤트 프로세싱을 배우실 수 있을 것 같아요.
예 : Esper Query ? 마지막 10분간의 총 고객의 숫자와 고객의 아이디를 찾으시오.
select customerId, count(*)
from PayInqAck(isFound = false).win:time(10 minutes)
group by customer
having count(*) >= 3
예: WebLogic Event Server Query ? GLV라는 심볼을 가진 주식 중 마지막 5개의 이벤트 중 lastPrice의 트렌드(method name)가 2를 넘는 데이터의 정보를 추출하라.
select symbol, lastPrice, trend(lastPrice), clientTimestamp, timestamp from (select * from StockTick where symbol='GLV') retain 5 events having trend(lastPrice) > 2
그러면 저걸 어디에다 쓸 수 있을까요? 하루에 신용카드사로 들어오는 이벤트는 상상을 초월합니다. 그런데 한 여성이 신용카드를 분실했다고 가정을 해보죠. 이 여성은 카드를 이용해서 대부분 화장품, 패밀리 레스토랑에서 카드를 사용했습니다. 그런데 어느 날 카드를 잃어버리게 됩니다. 어떤 남자가 카드를 주워서 바로 유흥주점으로 놀러가 카드를 계산합니다. 이 때 이벤트 서버가 들어오는 이벤트 데이터의 패턴과 기존의 데이터를 비교하여 문제가 발생했다는 걸 실시간으로 알린다거나 할 수 있습니다. 간단하게 예를 든 것이지만 정말 다양한 곳에서 이런 event processing을 사용할 수 있습니다.
간략하게 이벤트 프로세싱을 살펴보았지만 내부의 programming model, flow 등을 보면 쉽지가 않는 영역입니다. 하지만 이런 분야도 있다는 것을 아는 게 중요해서 이렇게 글로 남깁니다.

위에서 이야기한 MD5는 또 어디서 봤을까요? 어? 못봤어요? 리눅스에 조금만 관심이 있다던지 시스템을 조금 안다고 한다면 보통의 unix운영체제에서 MD어쩌구 저쩌구 라고 보셨을텐데..
아구~ 만약 못보았다면 공부좀 열심히 하셔야 겠습니다.
그럼 아파치에서 사용자 인증을 위한 htpasswd는 보셨나요? 디렉토리에 user리스트등을 걸어서 해당 사용자에 대한 접근을 시도하도록 하는 거 말이죠~ 어라? 이것도 구경못해봤다구요?
홍.... 그럼 진짜 쌍코피터지게 공부하셔야 겠군요. 하기사 이런것 몰라도 먹구 사는데 지장은 없습니다만 그래도 안다면 어디가서 아는 척은 할수도 있겠지요.
자 그럼 대체 MD5가 무엇인지를 알고서 넘어가야 왜 쓰는지를 알수 있겠지요? 알아봅시다.
▶ MD2, MD4, MD5란 무엇인가?
MD2, MD4, MD5는 Rivest가 개발한 메시지 요약 알고리즘이며, 128비트의 메시지 요약을 생성해냅니다. MD2는 8비트 컴퓨터용으로 최적화되었고, Md4와 Md5는 32비트 컴퓨터용으로 되어있다는 특징을 가지고 있습니다. 얘네들 같은 경우는 대표적인 해쉬함수측에 포함되어져 있는데, 해쉬함수란놈은 자바에서처럼 스트링을 일정한 길이의 해쉬코드로 출력을 내보내게 되는데 얘들은 두가지 성질을 만족해야 하는 특징을 가지고 있습니다.
첫째로 만들어진 해쉬코드를 보고 해당 해쉬코드를 만들었던 스트링을 찾아내지 못해야 하며, 두번째는 주어진 스트링에 대하여 같은 해쉬코드를 생성하는 또 다른 스트링을 찾아내지 못해야
한다는 것입니다.
보통의 해쉬함수들은 SNEFRU, MD2, MD4, MD5, SHA등등이 있는데 MD4가 1992년에 아주 똑똑한 사람에 의하여 해독이 되어 버려서 MD5로 비트길이를 발전시키기에 이르렀다네요..SHA같은 경우도 MD4에서 파생된 160비트 해쉬코드를 만드는 놈인데 보면 대략 MD5와 비슷한 형태를 가지고 있습니다.
MD5같은 경우 사실 SHA보다 32비트가 작은 128비트를 가지고 있지만 빠르고, 쉬우며, 간결하다는데 특징을 둘수 있겠네요. 알려진 결과로는 SHA보다 MD5의 수행성능이 약 25%정도 빠르다는 특징을 가지고 있습니다.
SHA같은 경우는 SMTP서버나 기타등등의 데몬등에서 사용자에 대한 내용등을 옵션으로 선택하여 사용할수도 있게하고 있죠.
▶ 자바에서의 MD5의 사용
어떤 방식의 해쉬결과가 나오는지 알고 싶다면 옆에 있는 컴퓨터중에 linux같은게 있으면 열어보세요. 콘솔로 /etc/passwd파일을 열어서 해당 사용자들에 대한 패스워드가 어떻게 입력이 되어져 있는지 보세요. cbWWy0LuJU90FgQ9GE/JcA== 등등의 문자로 장식을 하고 있는 게 보일겁니다.
자 이제 그러한 해쉬함수를 이용한 결과값을 자바측에서 얻어낼 것인데, 기본적인 MD5알고리즘을 이용하여 자바코드를 짜게 된다면 약 400라인정도의 byte연산을 통하여 결과값을 얻어낼 수
있습니다. 하지만 알고리즘 이해하고 그걸 짜실랍니까?
보통의 인터넷을 뒤진다고 했을때 지금 여러분은 빨리 찾고 빨리 적용하고 싶어서이기 때문에 API를 이용하여 만들어내는 방법을 더 선호하겠죠~ 연구자 기질이 있다면 그 원리를 알고 싶어할지는 몰라도 말이죠~
시작해보죠~
자바에서 java.security패키지에 보면 여러가지 보안에 관련된 클래스를 사용할 수 있도록 구성되어 있습니다. 거기에 MessageDigest클래스가 해당 알고리즘을 이용하여 digest를 할 수 있도록 구성해줍니다.
보통의 Util을 만든다하면 개발되는 프레임웍의 util package에 위치할 것이기 때문에 공통으로
사용할 수 있도록 클래스를 구성합니다
▶ SecurityUtil.java
public class SecurityUtil {
/**
* byte[] ret = HashUtil.digest("MD5", "abcd".getBytes());
* 처럼 호출
*/
public static byte[] digest(String alg, byte[] input) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(alg);
return md.digest(input);
}
public static String getCryptoMD5String(String inputValue) throws Exception {
if( inputValue == null ) throw new Exception("Can't conver to Message Digest 5 String value!!");
byte[] ret = digest("MD5", inputValue.getBytes());
String result = Base64Util.encode(ret);
return result;
}
}
위의 클래스에 해당 스트링값을 던지게 되면 실제 digest된 결과 문자열을 되돌려 줄수 있도록 처리하였는데 이것이 끝이냐~ 아닙니다. 실제 던져진 해쉬함수에 의한 결과를 System.out으로 찍게 되면 찌그러진 코드형태로 나오게 되는데 이것을 우리 눈으로 비교하여 String문자비교를 통하여 추후 사용할 수 있도록 하려면 Base64 인코딩을 시도해야 합니다.
그 유틸리티 클래스는 아래와 같습니다.
▶ Base64Util.java
import sun.misc.*;
import java.io.*;
/**
*
* Filename : Base64Util.java
* Class : Base64Util
* Function : Base64 Encoding/Decoding을 수행하는 클래스
* Comment :
* History : 2000-08-16 2:48오후
*
* @version 1.0
* @author carouser
*/
public class Base64Util {
public Base64Util() {}
/**
* Base64Encoding을 수행한다. binany in ascii out
*
* @param encodeBytes encoding할 byte array
* @return encoding 된 String
*/
public static String encode(byte[] encodeBytes) {
BASE64Encoder base64Encoder = new BASE64Encoder();
ByteArrayInputStream bin = new ByteArrayInputStream(encodeBytes);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buf = null;
try{
base64Encoder.encodeBuffer(bin, bout);
} catch(Exception e) {
System.out.println("Exception");
e.printStackTrace();
}
buf = bout.toByteArray();
return new String(buf).trim();
}
/**
* Base64Decoding 수행한다. binany out ascii in
*
* @param strDecode decoding할 String
* @return decoding 된 byte array
*/
public static byte[] decode(String strDecode) {
BASE64Decoder base64Decoder = new BASE64Decoder();
ByteArrayInputStream bin = new ByteArrayInputStream(strDecode.getBytes());
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buf = null;
try {
base64Decoder.decodeBuffer(bin, bout);
} catch(Exception e) {
System.out.println("Exception");
e.printStackTrace();
}
buf = bout.toByteArray();
return buf;
}
}
String passwd = SecurityUtil.getCryptoMD5String("Carouser");

UDP(User Datagram Protocol)는 인터넷에 있어 datagram을 전송하는 전송층 프로토콜인 것은
사실이지만 TCP 처럼 그 사양이 엄격하게 정의된 것은 아닙니다.
UDP 는 비연결기반형인데, 이러한 비연결성(connectionless) 은 IP 프로토콜의 특징이기도 합니다. 또한 UDP 의 데이터 패킷인 데이터그램 패킷은 그 헤더에 소스 포트(로컬 포트)와 목적지 포트(원거리 포트) 그리고 데이터그램 패킷 길이, 체크섬 정도만 갖습니다. 그런데 자바의 데이크그램 패킷은 IP 어드레스정보도 포함하고 있어 데이터그램 패킷에 대한 IP 패킷에 더 가깝습니다.
<표 1> UDP Datagram 형식
-------------------------------
Source Port(로컬포트)
Destination Port(원거리포트)
Length Checksum
Data
▶ TCP 프로그래밍과 데이터 프로그래밍의 차이
<표 2>
| TCP 프로그래밍 | Datagram 프로그래밍
소켓의 종류 접속 요청용 | ServerSocket 통신용 : Socket | 구분없이 DatagramSocket만
사용 전달 데이터 유형 | 미가공 데이터 | Datagram Packet
▶ 소켓의 종류
TCP 프로그래밍에서는 클라이언트로부터의 접속요청을 듣는 서버 소켓(ServerSocket 개체)과
클라이언트와 상호 통신을 담당하는 클라이언트 소켓(Socket 개체)이 구분되어 있었습니다.
그러나 데이터그램 프로그래밍에서는 서버소켓이 따로 없고 클라이언트 소켓에 해당하는DatagramSocket 개체만이 있습니다. 이는 당연한 것이 UDP 프로그래밍은 비연결형이므로 접속을 당당할 서버소켓이 필요없는 것입니다. 그러니까 데이터그램 프로그래밍에서는 클라이언트의 접속을 허용하고 어쩌고 할 것 없이 데이터그램 소켓 하나로 무조건 데이터그램 패킷을 읽고 씁니다. 물론 보안관리자가 없을 때 그렇습니다.
보안관리자가 설치되어 있으면 보안 검사 정도는 합니다.
▶ 전달 데이터 유형
TCP 프로그래밍(혹은 소켓 프로그래밍)에서는 전달하는 데이터가 우리가 프로그래밍에서 일상적으로 다루는 유형과 다를 바 없었습니다. 즉, 입출력스트림이 다룰 수 있는 데이터라면 TCP 프로그래밍에서도 전송할 수 있었습니다. 이 말이 TCP에서 전달 데이터 유형이 그렇다는 것이 아니라 TCP 애플리케이션에서 그렇다는 것입니다. 우리가 TCP 애플리케이션에서 다른 것은 신경쓰지 않고 출력스트림으로 일반 데이터를 보내면, 그 아래층인 TCP 및 IP 층을 통과하면서 패킷화됩니다. 그러니까 TCP 프로그래밍은 철저하게 애플리케이션층만 담당합니다.
그러나 데이터그램 프로그래밍에서는 미가공 데이터를 그대로 보내지 않고, 먼저 데이터그램 패킷으로 변환한 뒤 이를 입출력스트림을 통해 전송합니다. 그런데 자바의 데이터그램 패킷은 순수한 데이터그램 패킷이 아닌 IP 패킷 특성도 포함한 그런 것입니다. 그러니까 자바 데이터그램
프로그래밍은 애플리케이션층만 담당하는 것이 아니라 그 아래층인 전송층, 심지어는
네트웍층까지도 직접 건드립니다.
▶DatagramSocket 클래스 정의
DatagramSocket 클래스- DatagramPacket 객체를 전송하고 수신하는데 사용할 수 있는 데이터그램 소켓 클래스 입니다.
* 생성자
DatagramSocket() throws SocketException
- 포트 번호가 임으로 정해진 상태의 DatagramSocket 객체를 생성
DatagramSocket(int port) throws SocketException
- 매개변수로 들어온 port에서 대기하는 DatagramSocket 객체를 생성
DatagramSocket(int port, InetAddress Iaddr) throws SocketException
- 매개변수로 들어온 port에서 대기하는 DatagramSocket 객체를 생성하여 해당 IP 어드레스에 바인딩 합니다.이 생성자는 다중 IP 어드레스를 갖는 호스트에서 사용합니다.
▶ DatagramPacket 클래스 정의
DatagramPacket은 UDP 통신에서 데이터의 패킷을 만들어 DatagramSocket을 이용해서 송,수신할 수 있는 기능을 제공합니다.
public DatagramPacket(byte buffer[ ], int length)
- 데이터를 받기 위해 DatagramPacket 객체를 만드는 생성자
- buffer[ ]: 데이터가 위치해 있는 바이트 배열
- length: 버퍼의 길이
public DatagramPacket(byte buffer[ ], int length, InetAddress ia, int port)
- 다른 호스트로 전송할 DatagramPacket 생성하는 생성자
- buffer[ ]: 전송할 데이터의 바이트 배열
- length: 버퍼의 길이
- InetAddress ia: 패킷의 목적지 호스트 주소
- Port: 목적지 포트 번호
▶ Datagram Server작성예
import java.net.*;
public class DaytimeServer {
public static final int DEFAULT_PORT = 13;
public static void main (String[] args) throws IOException {
if (args.length > 1)
throw new IllegalArgumentException ("Syntax: DaytimeServer []");
// 사용자 입력 포트의 DatagramSocket 생성 입력값이 없을 경우 Default Port 13
DatagramSocket socket = new DatagramSocket
(args.length == 0 ? DEFAULT_PORT : Integer.parseInt (args[0]));
DatagramPacket packet = new DatagramPacket (new byte[1], 1); // DatagramPacket 생성
while (true) {
socket.receive (packet); // 소켓으로부터 패킷을 받음
System.out.println
("Received from: " + packet.getAddress () + ":" + packet.getPort ());
byte[] outBuffer = new java.util.Date ().toString ()
.getBytes ("latin1"); // 패킷 정보를 표시
packet.setData (outBuffer);
packet.setLength (outBuffer.length);
socket.send (packet);
}
}
}
데이터임 서버는 명령행 인자로 설정된 포트에서 대기하면서, 들어오는 모든 패킷에 대해 현재 시간을 담아 클라이언트에 응답합니다. 패킷 수신과 응답에는 하나의 스레드만 사용하였습니다.
Main()메소드에서는 우선 인자로 설정된 포트 번호가 제대로 된 것인지 검증하고, 그렇지 않은경우 디폴드 포트 번호인 13을 사용합니다.그리고 DatagramSocket타입의 Socket을 생성하고 이 포트에서 대기시킨 후 UDP 패킷을 받을 때 사용할 DatagramPacket 타입의 Packet을 생성합니다.
이 프로그램의 핵심인 루프 부분에서는 receive()를 호출하여 패킷이 오기를 기다리며, 패킷이 오면 이 패킷을 보낸 호스트 정보를 출력한 후에 현재의 날짜와 시간 정보가 담긴 바이트 배열인 outBuffer를 새로 만듭니다. packet 객체의 setData()와 setLength()를 사용하여 receive()로 받은 패킷에 시간정보를 넣습니다.
마지막으로 send()메소드를 호출하여 원래의 호스트로 packet을 돌려 보냅니다.
== 참고 ==
packet에는 원래 호스트 주소와 포트번호가 이미 들어 있기 때문에, packet정보는 그냥 놔두어도 됩니다
▶ Datagram Client 작성예
import java.net.*;
public class DaytimeClient {
public static void main (String[] args) throws IOException {
if ((args.length != 1))
throw new IllegalArgumentException
("Syntax: DaytimeClient [:]");
int idx = args[0].indexOf (":");
int port = (idx > -1) ? Integer.parseInt (args[0].substring (idx + 1))
: DaytimeServer.DEFAULT_PORT;
String hostName = (idx > -1) ? args[0].substring (0, idx) : args[0];
InetAddress host = InetAddress.getByName (hostName);
DatagramSocket socket = new DatagramSocket ();
socket.setSoTimeout (5000);
DatagramPacket packet = new DatagramPacket (new byte[256], 1, host, port);
socket.send (packet);
packet.setLength (packet.getData ().length);
socket.receive (packet);
socket.close ();
byte[] data = packet.getData ();
int length = packet.getLength ();
System.out.println (new String (data, 0, length, "latin1"));
}
}}
DaytimeClient 는 DaytimeServer를 테스트 하기 위한 것입니다. 매개변수로 설정된 컴퓨터 포트에 패킷을 보내고, 응답을 기다리고, 받은 응답 정보의 내용을 출력하는 것이 전부입니다.
Main()메소드 에서는 호스트 주소인 host와 포트 번호를 검사하여, 역시 포트번호가 주어지지 않으면 디폴트 포트 번호를 사용합니다.
패킷을 보낼 준비를 하기 위해 5초의 수신 타임아웃이 설정된 DatagramSocket타입의 소켓을 생성하고 테이터 길이가 1이고 리모트 서버의 주소가 담긴 256바이트의 버퍼를 넣어 DatagramPacket 타입의 패킷을 생성합니다.
Send()를 통해 보내지는 패킷은 단 한 바이트를 보내지만 응답을 받기에는 충분합니다.
패킷을 보내고 나면 즉시 이 패킷의 페이로드를 256으로 재설정하여 응답을 기다리기 때문에 받아들일 수 있는 응답 정보의 길이는 최대 256 이 됩니다.
만약 수신시간 5초를 넘기면 InterruptedIOException예외와 함께 프로그램 실행이 바로 멈춥니다.
간단하게 Datagram에 대하여 알아보았으며, 다음 아티클은 멀티캐스트에 대하여 알아보도롭 합니다.

4. MySql은 어떻게 실행시키나요?
---------------------------------------
시작은 mysql설치 디렉토리 아래bin에(C:\mysql\bin) 가서 mysqld.exe 를 실행.
dos창이 잠시 보였다가 없어짐.
( 놀라지마세요. CTRL-ALT-DEL을눌러보면
mysqld-opt.exe(win95/98)나 mysqld-nt.exe(winnt/2000)가 실행중 )
확인법:
prompt> cd c:\mysql\bin
prompt> mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2 to server version: 3.23.21-beta
Type 'help' for help.
mysql>
c:\mysql\bin\mysql.exe는 mysql용 client program
이러한 메세지가 뜨면 정상적으로 MySql서버가 동작중임.
그리고 간단한 명령어 몇개를 입력해보죠.
mysql> show databases; --> 기본적으로 만들어져있는 database 이름 출력
+----------+
| Database |
+----------+
| mysql |
| test |
+----------+
2 rows in set (0.00 sec)
mysql> select user(); --> 로긴한 사용자 정보 출력
+----------------+
| user() |
+----------------+
| ODBC@localhost |
+----------------+
1 row in set (0.08 sec)
mysql>
위와같이 나오면 정상적인 설치임.
끝내려면 exit이라하면 됨.
mysql> exit;
---------------------------------------
5. Winnt/Win2000에서 서비스로 동작 시킬 수 있나요?
---------------------------------------
winnt/win2000에서는 mysql을 서비스로 등록가능.
방법 1 (command line ): mysql설치 디렉토리 아래bin에 가면 mysqld.exe있음.
prompt> mysqld -install ( service로 등록 )
prompt> net start mysql ( mysql 서비스 시작 )
prompt> net stop mysql ( mysql 서비스 중지 )
prompt> mysqld -remove ( service에서 등록 해제 )
방법 2 (GUI) : c:\mysql\bin\win,ysqladmin.exe를 실행시킴.
그러면 userid와 암호를 묻는 화면이 뜰때 userid는 root, 암호는 sunedu21을 입력.
입력한 root는 기본적으로 제공되는 관리자용 id이고 암호는 없음. sunedu21을 입력하면
그걸로 자동 설정됨.
---------------------------------------
6. mysql.exe의 간단한 사용법을...
---------------------------------------
mysql.exe를 이용해서 다른 시스템의 database로 접속가능하고 다른 사용자로도 접속이
가능합니다.
mysql.exe옵션들
prompt> mysql [-h hostname] [-u userID] [-p암호] [database]
예:
prompt> mysql -h 203.239.XXX.XXX -u root -p sl300
-h 203.239.XXX.XXX : 203.239.XXX.XXX으로 접속, 생략하면 기본값 127.0.0.1 이 사용됨.
-u root : root사용자로 접속 -u옵션을 안주면 anonymous로 접속
-p : 암호를 입력한후 접속. 암호를 묻는 프롬프트가 뜸.
암호가 있는 사용자로 접속시에는 반드시 사용.
만약 암호를 같이 입력하려면 암호를 -p옵션과 붙여 입력.(-ptiger)
database : 사용할 database이름. 만약 생략하면 접속후 use명령으로
database를 지정해야됨. 기본제공 database name은 mysql,test 2개.ㄴ
---------------------------------------
7. MySql관련 GUI tool은 없나요?
---------------------------------------
MySql용 GUI tool은 대부분이 UNIX/LINUX용입니다.
다행히 3.23.21버전부터는 winmysqladmin.exe 라는 GUI tool이 포함되어 있읍니다.
( C:\mysql\bin\winmysqladmin.exe )
이 툴은 MySql서버를 start,stop시킬 수 있고, NT/2000에서는 service에 등록,해제도 가능합니다.
그리고 현재 접속하고있는 process의 갯수와 MySql관련 환경변수 정보와 설정정보까지
파악이 가능합니다.
이 툴은 win95/98/nt/2000에서 모두 동작합니다.
이명령어를 처음 실행하면 접속시 사용할 사용자id와 암호를 넣으라하는데 주로 root를 입력하고
암호는 아무거나 입력하면됩니다.
단 이때 입력한 암호는 자동으로 root의 암호로 인식이 됩니다. 반드시 기억해야겠죠?
그러면 시스템트레이에 신호등 아이콘이 생깁니다. 이걸 누르면 showme 와
winnt,win9X메뉴가 보이죠. winnt,win9X 메뉴를 선택하면 server start,stop tool의 shutdown이 보입니다.
현재 mysql server가 실행중이면 파란색불이 실행하지 않으면 빨간색 불이 들어옵니다.
만약 빨간색불(mysql서버가 중지중)일때 실행 시키려면 트레이에 있는 신호등 아이콘을 누르고
WinNT나Win9X를 선택, start the service 를 선택하면 신호등에 파라생 불이 들어옴.
즉 mysql서버가 시작했다는 말.
그외 관리용 명령어인 mysqladmin이 있음.
수동으로 실행시에는 mysqld.exe를 실행하면 되지만 수동으로 stop시키려면 mysqladmin을 실행.
물론 옵션과함께...
아래는 mysqladmin용 명령어임. 기능은 설명을 참조.
create databasename Create a new database
drop databasename Delete a database and all its tables
extended-status Gives an extended status message from the server
flush-hosts Flush all cached hosts
flush-logs Flush all logs
flush-status Clear status variables
flush-tables Flush all tables
flush-threads Flush the thread cache
flush-privileges Reload grant tables (same as reload)
kill id,id,... Kill mysql threads
password new-password Change old password to new-password
ping Check if mysqld is alive
processlist Show list of active threads in server
reload Reload grant tables
refresh Flush all tables and close and open logfiles
shutdown Take server down
status Gives a short status message from the server
variables Prints variables available
version Get version info from server
위 명령어중 특히 신경쓸것은 password관련.
설치후 반드시 root(MySQL DB)의 암호를설정할것.
안하면 불행한일(DB삭제)이 발생할 지도...
# mysqladmin -u root password 새암호
필요한 TABLE을 만드는 순서:
1. Database만들기
2. MySQL용 사용자 만들기
3. Table만들기
- javabrain용 DB 만들기(2가지 방법)
1.UNIX shell상에서 만들기
# mysqladmin -u root -p create javabrain
2.DB에 login후 만들기
mySQL에서제공하는 명령어중 mysqladmin은 관리용
mysql은 client용 명령어.
# mysql -u root -p mysql
mysql> create database javabrain;
** mysql 명령어 요약
mysql [-h DB서버IP] [-u DB용사용자ID] [-p[암호]] [Database] [< sql-script파일 ]
-p 만 부여하면 암호는 물어봄. 암호까지 주려면 -p암호(-p와 암호를 붙여씀)
- 새사용자등록
먼저 MySQL에 root로 login
# mysql -u root -p mysql
mysql> grant SELECT,insert,update,delete,create,drop
> on javabrain.*
> to scott@'localhost'
> identified by 'tiger';
mysql> grant SELECT,insert,update,delete,create,drop
> on javabrain.*
> to scott@'%'
> identified by 'tiger';
mysql> flush privileges;
또는
mysql> grant all privileges
> on javabrain.* to scott@'%'
> identified by 'tiger';
mysql> grant all privileges
> on javabrain.* to scott@localhost
> identified by 'tiger';
mysql> flush privileges;
scott 사용자를 등록할때 여러가지(3가지) 방법이 있는데 그중 하나를 씀
등록시 반드시 to scott@'localhost'와 to scott@'%'를 둘다 해줘야함
localhost와 %는 접속을 허용하는 hostname인데 localhost를 빼면 다른 시스템에서
network으로만 접근할 수 밖에 없음.
그리고 %란 모든호스트를 의미하기때문에 %를 지정해야지만 다른 시스템에서
network으로 MySQL로 접근가능( mysql -h hostIP또는hostname -u 사용자ID -p )
user생성후 반드시 DB를 reload 해야만 만든 사용자가 접속가능(아래명령어)
# mysqladmin -u root -p reload
또는
mysql> flush privileges;
접속해서 확인하기
# mysql -u scott -p javabrain --> ㅤDB서버에서login
다른시스템에서
# mysql -h DB서버의IP주소 -u scott -p javabrain
필요한 테이블 만들기(customer,shares,stock)
-주의사항: mysql은 table name에서의 대소문자를 구분함
(이것은 MySQL이 설치된 OS를 따름. 즉 M$계열에서는 구분안함)
필요한 sql문을 파일(maketable.sql-확장자는 무관)로 만든후 shell상에서 아래
명령어 실행
# mysql -u scott -p javabrain < maketable.sql
확인
# mysql -u scott -p javabrain
mysql> show tables;
mysql> select * from customer;
mysql> select * from shares;
mysql> select * from stock;
- JDBC Driver 사용하기
MySQL용 JDBC Driver는 2가지가 있지만 여기서는 mm driver를 사용.
http://www.worldserver.com/mm.mysql/ 에 가서 최신 버전을 download할것
(mm.mysql-2.0.4-bin.jar)
가져온것을 적당한 곳에서 해제.
사용법:
Class.forName("org.gjt.mm.mysql.Driver");
String url="jdbc:mysql://127.0.0.1:3306/javabrain";
Connection conn = DriverManager.getConnection(url,"scott","tiger");
관련 명령어들.
# mysql -u root -p mysql
password:
mysql> select user(); --> 현재 어떤 user권한으로 접속하고 있는지.
mysql> show database; -->데이터베이스 종류보기
mysql> show tables from mysql; --> mysql상의 테이블 정보보기
mysql> show columns from customer; --> customer 테이블 구조보기
mysql> show index from customer; --> customer테이블의 인덱스보기
mysql> use mysql; --> 사용할 database를 변경
(기본적으로 MySQL에는 두개의 database-mysql,test-가 있음.
mysql은 DBMS관리용 정보, test는 연습용
그래서 mysql이란 database는 사용시 주의할것)
#########################################
#########################################
##
## 추 가 사 항
##
#########################################
#########################################
javabrain.sql 이라는 파일을 수행 시키면 SL-300을위한 DB를 위한 모든 내용이 자동 설정됨.
사용예)
mysql 서버를 가동시킨후 ( mysqld.exe )
prompt> mysql -u root -p < javabrain.sql
이러면 아래 사항이 자동 생성됨
database이름 : javabrain
root암호 : javabrain
사용자 id : scott
암호 : tiger
생성된table들 : customer, shares, stock
가끔씩 user부분이 적용이 안되는 경우에는 DB를 restart시키면 된다.
prompt> mysqladmin -u root -p shutdown --> DB shutdown
prompt> mysqld
만약 암호를 바꾸고 싶으면 sql script내부에 .... identified by 다음부분이 암호이니
알아서 바꾸면 됨. 단 반드시 암호는 single quotation으로 묶어줄것.
예) 암호를 apple 로 하자면 .... identified by 'apple'
import java.sql.*;
public class MySQLJdbcTest {
public static void main(String[] args) throws Exception{
try{
Class.forName("org.gjt.mm.mysql.Driver").newInstance();
System.out.println("DriverLoading succeed..");
String url="jdbc:mysql://127.0.0.1:3306/javabrain";
// 만약 위의 url로 접속시 한글에 문제가 발생하면 아래 url을 써서 사용하도록 한다.
// String url="jdbc:mysql://127.0.0.1:3306/javabrain?useUnicode=true&characterEncoding=euc-kr";
Connection conn = DriverManager.getConnection(url,"scott","tiger");
System.out.println("Connection succeed");
Statement stmt = conn.createStatement();
System.out.println("정보추출");
ResultSet rs = stmt.executeQuery("show databases");
while( rs.next() ) {
System.out.println(rs.getString(1));
}
System.out.println("MySQL 환경 점검 종료");
rs.close();
stmt.close();
conn.close();
}catch(Exception e){
System.out.println(e);
}
}
}
2003년 3월 작성.

이번 아티클에서는 shutdown hook에 대한 글을 써보고자 한다. 우선 개요부터 말하자면 당신이 열나게 애플리케이션을 만들었다고 가정을 해보자. 사용자가 도스창에서 애플리케이션을 실행시키고 동작시키고 있는데, 이 사용자가 갑자기 이게 아니다 싶어서 애플리케이션을 죽이려고 한다. 근데 분명 내가 메뉴에 종료라는 항목을 하나 추가해주었거늘.. Ctrl+C를 눌러버리고야 말았다.
문제는 무었인고? 나는 해당사용자의 내용에 대한 backward기능을 주고 싶어서 그 사람이 하고 있는 행동에 대한 rollback가능한 로그를 쌓고 사용자가 애플리케이션을 종료시키면 그때 필요없는 데이터들을 모두 없애버리리라 마음을 먹고 있던 차였다.
그런데...
위의 같은 상황이 발생을 한다면 당신은 어떻게 할것인가?
서블릿 컨테이너나 Applet의 경우도 실제 라이프사이클에 의하여 동작하여 해당 클래스가 메모리에서 unload되어지는 시점에 destroy메소드들을 호출하도록 하고 있는데, 위의 ctrl+c라는 행위는 아예 daemon thread까지 "너 죽어랏~!" 하면서 보내버리는 케이스니 말이다.
만약 저러한 애플리케이션을 스윙으로 만든다면 actionPerformed 이벤트를 걸어서 어떻게든
처리를 하겠는데 일반 text based application의 경우는 더더욱이 문제가 아닐듯 싶다.
▶ 자바에서의 shutdown event의 두가지
자바에서 virtual machine이 shutdown을 인식하는 방법으로는 두가지가 있는데
1. 첫번째로는 애플리케이션이 System.exit()메소드를 통하여 정상적으로 종료하는 경우가 있고,
2. 두번째로는 사용자가 직접 Ctrl+C를 키보드에 입력함으로서 현재 실행중인 애플리케이션을
closing하지 않고 virtual machine을 비정상적으로 강제종료시키는 경우이다.
간단하게 shutdown hook을 작성할 수 있는 방법은 다음과 같다.
1. java.lang.Thread를 상속받는 클래스를 하나 작성한다.
2. Thread의 run메소드를 구현할 때 당신이 shutdown시에 처리해야 할 일들에 대하여 기술한다.
3. 해당 shutdown hook클래스를 생성한다.
4. Runtime클래스의 addShutdownHook()메소드를 이용하여 등록한다.
Runtime.getRuntime().addShutdownHook(shutdownHook);
▶ ShutdownHook Sample정의
여기서 우선 애플리케이션을 만들 경우를 가정하자.
보통의 서블릿 컨테이너는 사용자에 대한 세션을 자신의 로컬파일로 저장하여 관리하고 있다.
레진같은 엔진을 보더라도 session이라는 디렉토리에 file serialize를 통하여 저장하고 엔진이 종료되거나 세션의 시간이 만료되게 되면 그 저장된 temporary파일들을 삭제하는 루틴을 가지고 있다. 그런데 만약에 그러한 엔진들이 비정상적인 종료에 해당 파일들을 삭제하지 못하고 쌓아두게 된다면, 또한 접속이 많은 그러한 서버였다면 파일시스템의 사이즈가 비대하게 불어나게 될 것은 불을 보듯 뻔한 일 아닌가?
놀새~의 샘플코드 가정을 비슷하다.
애플리케이션이 시작되면 사용자의 고유식별파일을 하나 만들어서 기록하고 있다가 어떠한 방법으로라도 프로그램이 종료되게 되면 그 파일을 삭제하도록 할것이다.
자 그럼 위의 순서에 의하여 하나하나 작성을 해보도록 하자.
▶ ShutdownHookDemo.java
import java.io.*;
public class ShutdownHookDemo {
private String dir = ".";
private String filename = "session_tmp.txt";
/**
* 애플리케이션이 시작되면 shutdown을 생성한후 등록한다.
*/
public void start() {
System.out.println("Demo");
ShutdownHook shutdownHook = new ShutdownHook();
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
/**
* 1. 실행의 순서는 먼저 tempoary파일의 생성
* 2. Runtime클래스에 shutdown hook을 등록
* 3. 사용자의 입력을 기다림(무한루프)
*/
public static void main(String[] args) {
ShutdownHookDemo demo = new ShutdownHookDemo();
demo.setup();
demo.start();
try {
while(true){
System.in.read();
}
}
catch(Exception e) {
e.printStackTrace();
}
}
/**
* ShutdownHook클래스를 inner클래스로 사용함으로서 ShutdownHookDemo클래스의
* 멤버변수에 대한 참조를 가능하도록 만든다.
*/
private class ShutdownHook extends Thread {
public void run() {
shutdown();
}
}
/**
* Shutdown의 되는 시점에 생성되었던 temporary파일을 삭제한다.
*/
private void shutdown() {
System.out.println("start shutdown progress.. please wait");
// delete the temp file
File file = new File(dir, filename);
if (file.exists()) {
System.out.println("Deleting temporary file.");
file.delete();
}
}
/**
* 프로그램최초 수행시에 임시파일을 생성해낸다.
*/
private void setup(){
// create a temp file
File file = new File(dir, filename);
try {
System.out.println("Creating temporary file");
file.createNewFile();
}
catch (IOException e) {
System.out.println("Failed creating temporary file.");
}
}
}
위에서 별반 다르게 볼건 없다. 프로그램이 시작되면
while(true){
System.in.read();
}
처럼 무한루프를 돌며 사용자의 키보드 입력을 기다리게 되는데, ctrl+c가 입력되기 전에는 계속 입력만을 받게 된다.
실제 shutdown hook클래스는 아래와 같이 간단하게 만들수 있으며
private class ShutdownHook extends Thread {
public void run() {
shutdown();
}
}
단순히 클래스가
Runtime.getRuntime().addShutdownHook(shutdownHook);
에 의하여 등록만 되어 있으면 자동으로 처리되게 된다.
실제로 테스트를 해볼경우 프로그램을 수행시키는 시점에 session_tmp.txt파일이 디렉토리에 생기게 된다. 계속 테스트하다가 실제 ctrl+C를 키보드에 입력했을 경우 shutdown progress라는 메시지와 함께 해당 임시파일은 없어지게 될것이다.
간단하게 테스트 해볼 수 있으며 위의 프로그램을 조금만 응용해도 당신은 아주 훌륭한 애플리케이션을 만들수 있을 것이다.

JVM에 ClassLoader 객체는 사용되어지는 class file을 Memory로 Loading하는 작업을 한다.
Applet을 실행 시키는 JVM은 classpath(Browser내에 내장된 class Library)에서 Loading한 class와 외부로 부터 downloading한 class의 Naming Space를 다르게 관리를 한다.
외부로 부터 downloading된 class, 즉 Untrusted Code는 SecurityManager객체에 의해 활동이 제한이 되어 진다.
JDK1.0 Security Model은 Sandbox Model이라고 하는데, Untrusted Code에 대해서는 Naming Space를 다르게 관리 함으로써, SecurityManager객체에 의해 활동이 제한되는 Sandbox라는 Boundary 영역내에서만 활동하는 구조를 말한다.
▶ JDK1.1 Security Model - Sandbox Model + Signed Applet
JDK1.1 Security Model은 1.0의 Sandbox Model에 Signed 개념이 추가가 되었다.
Untrusted Code가 Sign만 되면, Sandbox boundary를 벗어나 local의 classpath에서 loading된 class처럼 활동할 수 있다. SecurityManager 객체의 제한은 않받는다는 것이지요.
지금 현재의 Browser는 JDK1.1의 Security Model을 사용하고 있다.
▶ JDK1.2 Security Model - Sandbox Model + Protection Domain
JDK1.2 Security Model은 JDK1.1 Security Model(Sandbox + Signed)에 Protection Domain개념을 추가시킨 구조이다.
1.1 version에서 Signed code는 1.2 version에서 Domain으로 관리가 되고, 각 Domain별로 Sandbox boundary를 다르게 설정할 수가 있어, Sandbox boundary가 Domain별로 가변적이라는 특성을 갖게 된다.
Domain은 Signer와 Codebase에 의해 결정이 되고, client의 policy file에 각 Domain이 활동 가능한 Sandbox boundary를 설정하게끔 되어있다.
JDK1.2 version에서는 jdk1.2\jre\lib\security\ directory에 java.security file은 master security properties file을 제공하는데, 이것은 Security에 관련된 Configuration file이다. 이 file내에 Domain의 활동 영역을 설정하는 policy file을 지정할 수 있는 부분이 있다.
# The default is to have a single system-wide policy file,
# and a policy file in the user's home directory.
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
# User Policy File
policy.url.3=file:/D:/javaLab/signedApplet1.2/MyPrint.jp
java.home : jre directory
java.policy file : System policy file
.java.policy file : user default policy file(c:\windows\ 생성)
MyPrint.js file : user define policy file
java.policy file은 JDK1.2 version, JRE1.2 version을 Installation하면 ~jre/lib/security/ 자동 생성되고, .java.policy file은 c:\windows directory에 필요하다면 생성 할 수가 있다.
policy file은 editor tool로 작성가능하지만, JDK에서 제공하는 policytool로 edit하는 것이 편리하다. 일단 System policy file인 java.policy file의 내용은 아래와 같다.
// Standard extensions get all permissions by default
grant codeBase "file:${java.home}/lib/ext/-" {
permission java.security.AllPermission;
};
// default permissions granted to all domains
// 모든 domain에 대해 System properties를 read 할 수 있는 permission을 설정하고 있다.
grant {
// Allows any thread to stop itself using the java.lang.Thread.stop()
// method that takes no argument.
// Note that this permission is granted by default only to remain
// backwards compatible.
// It is strongly recommended that you either remove this permission
// from this policy file or further restrict it to code sources
// that you specify, because Thread.stop() is potentially unsafe.
// See "http://java.sun.com/notes" for more information.
permission java.lang.RuntimePermission "stopThread";
// allows anyone to listen on un-privileged ports
permission java.net.SocketPermission "localhost:1024-", "listen";
// "standard" properies that can be read by anyone
permission java.util.PropertyPermission "java.version", "read";
permission java.util.PropertyPermission "java.vendor", "read";
permission java.util.PropertyPermission "java.vendor.url", "read";
permission java.util.PropertyPermission "java.class.version", "read";
permission java.util.PropertyPermission "os.name", "read";
permission java.util.PropertyPermission "os.version", "read";
permission java.util.PropertyPermission "os.arch", "read";
permission java.util.PropertyPermission "file.separator", "read";
permission java.util.PropertyPermission "path.separator", "read";
permission java.util.PropertyPermission "line.separator", "read";
permission java.util.PropertyPermission "java.specification.version", "read";
permission java.util.PropertyPermission "java.specification.vendor", "read";
permission java.util.PropertyPermission "java.specification.name", "read";
permission java.util.PropertyPermission "java.vm.specification.version", "read";
permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
permission java.util.PropertyPermission "java.vm.specification.name", "read";
permission java.util.PropertyPermission "java.vm.version", "read";
permission java.util.PropertyPermission "java.vm.vendor", "read";
permission java.util.PropertyPermission "java.vm.name", "read";
};
위의 내용은 보면, jre\lib\ext\ directory에서 loading된 class는 AllPermission을 갖는다. 즉 SecurityManager의 제한이 없다는 것을 의미한다. 그리고, 두번째 항목은 모든 Domain에 대해 System.getProperty("java.version") method를 통해 System Property를 read할 수 있는 Permission을 설정한 사항이다.
policytool을 이용해 위와 같은 내용으로 Domain별 Sandbox boundary를 설정한 file을 생성할 수가 있고, 그 file을 JVM이 loading될때 policy file로 인식하게 하기 위해 java.security file에 설정할 수가 있다.





