'분류 전체보기'에 해당되는 글 140건

  1. 2009.06.12 다시 쓰는 UTF
  2. 2009.06.12 예언?
  3. 2009.06.11 최근에 책을 읽다가..
  4. 2009.06.08 패키지의 설계 원칙
  5. 2009.06.08 GUI TEST
  6. 2009.06.08 양화 구축 2
  7. 2009.06.08 AOP
  8. 2009.06.01 Self-Signed Java Applets
  9. 2009.05.28 후...
  10. 2009.04.30 AL : Permission 1
IT 이야기/유니코드2009. 6. 12. 16:14

UTF 얘기는 이미 충분히 글을 적었음에도 다시 포스팅을 하는 이유는 사람들이 자주 헛갈리는 캐릭터셋(charset)과 인코딩(enecoding)의 차이를 이야기 하기 위해서이다. 

"A"라는 글자가 컴퓨터에 이진수로 표현되어 저장된다는 것은 누구나 알고 있을 것이다. 중요한건 2단계를 거치는 것이 중요하다. 첫번째는 "해석"이고 두번째가 "저장"이다. 

첫번째 "해석"이란 컴퓨터가 아닌 사람을 위해 존재한다. "A" 글자를 저장해야 한다고 할때 글자 "A"라는 의미를 어떻게 전달해야 할까가 문제의 시발점이다. 다른 사람에게 "A"가 어떻게 저장되지? 라고 묻는건 올바르지 않다. 좀더 정확하게 말하자면 "2009년 현재 미국에서 사용하고 있는 알파벳의 대문자 A"라고 전달해야 한다. 번거롭기 그지 없다. 게다가 그 다른 사람이 사는 문화권에서는 "에이" 라고 불리는 다른 문자가 있을지도 있을지도 모른다. 원래 말이라는건 오해하기 쉬운 법이다. 

그래서 좀더 쉬운 전달을 위해 모든 문자에 숫자를 할당했다.(숫자은 전세계 모든 사람의 공용어 역할을 한다.) 이제 다른 사람에게 (십진수로) 65(16진수로 표현하면 0x41)번 문자는 어떻게 저장하지? 라고 물으면 된다. 이렇게 해석단계에서 사용하는, 문자에 번호를 매겨놓은게 charset (캐릭터 셋)이다. 컴퓨터가 발명된 초기부터 이렇게 별도의 해석 단계가 있었던건 아니었다. 컴퓨터가 처음 발명된 초기에는 해석 == 저장이었기 때문에 65번 글자인 'A'는 65번으로 저장한다 였다. 초기에는 128개(2^7)에만 번호를 할당했고 저장하였는데 구미지역에서는 이정도면 충분하였다. 

다시 말해서 캐릭터 셋은 해당 캐릭터 셋이 표현가능한 문자의 일종의 단순한 매핑 테이블이다. 이를테면 한글 "가"라는 글자는 KSC5601에서 "0116" 번으로 할당되어 있다. 이제 "0116" 에 해당하는 글자(즉 한글 "가")를 어떻게 컴퓨터의 이진 코드화 시키는가가 인코딩이다. 앞서 해석 - 캐릭터셋에 매핑된 숫자를 읽기 -는 논리적이며 저장 - 인코딩 -은 물리적 과정이기 때문에 서로 같지 않고 당연히 "0116" 글자가 0116 라고 저장되리라는 것을 기대하거나 보장할 수 없다. 

왜냐하면 캐릭터 셋은 논리적 과정이라 얼마든지 새로운 캐릭터 셋을 만들어도 상관이 없지만(물론 이 경우 다양한 단체의 알력싸움에 의해 정해진다.) 인코딩은 물리적 단계이며 이경우 가장 중요한 것은 호환성이다. 예컨데 "A"라는 글자는 KSC5601에서 "3305"번에 할당되어 있는데 디코딩은 인코딩의 역함수이기 때문에 기존에 ASCII로 "0x40"으로 저장된 코드를 "A"라고 읽을 수 없다. 따라서 캐릭터 셋의 번호대로 인코딩이 되지는 않고 실제로는 캐릭터셋의 해쉬 함수 인코딩을 하게 된다. 

KSC5601의 해쉬 함수를 통해 (KSC5601은 일반적으로 캐릭터셋의 의미를 가지지만 때로는 인코딩을 의미하기도 한다. 그래서 이전의 책이나 글에서는 문맥을 통해 구별하는 수밖에 없으며 이는 많은 혼란의 요인이 되었다.) "0116"글자는 "0xAC00"로 인코딩(즉 computer에는 AC00로 저장이 된다.) "3305" 글자는 "0x40"으로 바뀌어서 저장이된다. 문제는 디코딩을 할때 "0xAC00"  코드를 읽어서 화면에 "가"라고 보여줄 수 있느냐이다. 왜냐하면 파일에는 해당 파일의 캐릭터 셋에 대한 정보를 저장하기 않기때문에 이 파일을 읽을때 "0xAC00" 가 정말 "가"인지를 확인할 수 없기 때문이다. 어쩌면 다른 캐릭터 셋의 인코딩으로 "0xAC00"는 다른 글자일지도 모르기 때문이다. (어쩌면 초기에 구미에서 컴퓨터를 발명하면서 파일에 캐릭터 셋을 저장하지 않는 것이 문제의 시발점인지 모른다. )

파일을 인코딩한 해쉬 함수의 역함수는 당연히 캐릭터 셋에 종속이 되기 때문에 해당 파일의 캐릭터 셋을 모르고서는 해당 파일이 제대로 읽을 수 없다. 앞문장의 "제대로" 라는 뜻은 "0xAC00" 라는 코드를 읽어도 해당 파일의 캐릭터 셋을 알지못하면 이를 "가"로 제대로 화면에 보여주지 못한다는 이야기 이다. 

만약 자신의 컴퓨터에서 혼자만 쓰는 파일이라면 상관이 없다. 각 컴퓨터에는 기본 캐릭터셋이 지정되어 있기 때문에 아무런 추가 작업을 하지 않는 이상 기본 캐릭터 셋으로 쓰고 기본 캐릭터 셋으로 읽으면 된다. 그러나 A 컴퓨터에서 작성한 파일을 B 컴퓨터로 전달하는 경우(이메일을 쓰거나 웹에 글을 올리거나 하는 경우도 마찬가지이다. )에 해당 파일이 어떤 캐릭터 셋인지 전달해 주지 않으면 상대편의 컴퓨터에서는 제대로 읽을수가 없다. 설사 말로 알려준다고 하더라도 상대편의 컴퓨터에 해당 캐릭터셋에 대한 정보가 없으면 역함수가 없고 디코딩도 당연히 할수 없다. 

그럼 이쯤에서 나올만한 생각이 있다. 지구의 모든 컴퓨터가 공용으로 사용할 수 있는 캐릭터 셋을 만들면 되지 않을까? 정답이다. 그래서 나온게 유니코드이다. 문제는 유니코드의 발상이 나오기 전에 이미 많은 캐릭터 셋이 많은 컴퓨터에서 사용이 되고 있다는 점과 모든 글자를 담기 위해서는 글자당 할당되는 번호가 길어지고 이는 당연히 저장 공간이 길어지는 2가지 문제가 추가적으로 야기된다. 

둘을 묶어 보면 기존에 호환성을 유지하면서도(여기서 호환성이란 보통 ASCII만을 의미한다.) 수많은 글자를 가능한 작은 저장공간에 인코딩을 할 수 있어야 한다는 얘기이다. 


ASCII
당시의 컴퓨터는 유닉스 기반의 컴퓨터로 7비트가 1바이트인 메모리를 사용하였고 따라서 자연스럽게 하나의 문자를 표현하는데 7비트를 사용하였다. null로 시작하는 32개의 제어문자,공백문자, 94개의 프린트문자, 지움문자로 128개의 비트조합을 배정하였다. 이에 따라 1963년 최초의 ASCII 표준이 제정되었는데 이때까지만 해도 많은 비트 조합이 94개의 프린트 문자 번호로 배정되지 않은 상태였으며 1968년에 오늘날과 같은 ASCII 코드가 만들어져 표준으로 지정되었다. 


ISO 8859
같은 라틴계열의 문자이긴 하지만 별도의 강세문자를 가지는 프랑스나 그리스의 문자는 구미의 알파벳과 조금 달랐고 이런 언어의 표현을 포함하는 캐릭터 셋을 만들려는 국제적인 노력은 ISO8859 시리즈에서 나타났다. ISO 8859-1은 서유럽 언어를 다루기에 충분했으며, ISO 8859-7은 기본적인 그리스 문자, 알파에서 오메가, 발음기호 등 현대의 그리스 문자와 영어를 모두 지원했다. ISO 8859에서는 하나의 문자를 표현하는데 8비트를 사용하며 ASCII 외의 각 나라마다 자신이 사용할 문자는 128 이후에 배치하였다. 즉 ISO 8859는 128개의 세계 공통 문자(주로 알파벳과 숫자, 제어코드)와 128개의 지역 문자(지역별로 다른 문자 할당)의 조합이다. 

ISO 2022
상식적으로 공통으로 사용하는 128개의 문자말고 추가적인 128개의 문자는 지역마다 다르게 정의되었기 때문에 제대로된 문서 교환이 이루어질리 없다. 파일에는 그 파일이 어떤 캐릭터 셋을 사용했는지에 대한 정보가 저장되어 있지 않기 때문에 wrirte할때는 불어 지역문자를 사용하면 러시아에서 read 할때는 제대로 읽혀지지 않는다. 초기에는 네트워크가 활발하지 않았고 대부분 컴퓨터에는 혼자 사용하는 것이라는 인식이 강했지만 이게 문제가 되는 대표적인 예는 이메일(Email)이다. 

프랑스 사람이 러시아 사람에게 프랑스어로 이메일을 작성했을때 러시아인 컴퓨터에서 프랑스어가 제대로 보이기 위해서 이메일은 이스케이프 시퀀스(escape sequence)로 글자별로 캐릭터 셋을 설정하도록 하였다. 즉 프랑스 이메일 클라이언트는 프랑스어 코드가 나올때마다 ISO 2022 문자 인코딩들은 이어서 나오는 문자들에 대한 문자세트를 지시하는 escape sequence를 포함하고 있다. 그럼 저장단계에서 escape를 보고 해당 캐릭터셋의 번호로 저장 하였다. 즉 아직까지는 해석과 저장의 명확한 분리를 하지 않았기 때문에 기본 ASCII가 아닌 문서를 교환하는 것은 이렇게 비효율적인 면이 존재한다. (escape 문자로 인해 data 길이가 늘어나고 여전히 read하는 곳에서 해당 charset을 인식하지 못한다면 읽을 수 없었다.)

ISO 2022 문자세트들은 여전히 많이 사용되고 있으나, 최근에는 최신 이메일 소프트웨어 등 에서 UTF-8과 같은 유니코드 문자 인코딩들을 사용하는 것으로 차츰 변환되고 있다.


KSC 5601

KSC 5601은 94x94의 각 위치(행열)에 한글 문자를 일정한 순서에 따라 배열해 놓은 charset이다. 앞서 말했듯이 한글은 표의문자와 표음 문자 2가지 성격을 모두 가지고 있는 독특한 특성때문에 여러가지 다양한 방법중에서 한글 코드의 KS 제정에서 완성형이 채택된 것은 내부적으로 한글의 출력이 모아쓰기 형태로 이루어지면서 동시에 한자를 섞어서 쓸 수 있어야 한다는 사회적 요구로 조합형을 수용 하기가 어려웠기 때문이다.(물론 정치적인 이유가 없던것은 아니다.)

또 다른 배경은 국가간의 정보교환을 위한 코드 표준화 과정에서 앞의 ISO 2022에서 제정한 코드 체계에 따라 세계 각국의 문자를 처리하는데 기인한다. 이는 1바이트 코드로 한 문자 표현이 불가능한 CJK(Chinese, Japanese, Korean) 문자를 2바이트 코드 영역의 첫 번째 영역에 넣을 수 있도록 영역을 확보해야 했기 때문이다.


KSC 5601은 완성형 한글 2,350자, 한자 4,888자, 기술/학술기호 등 특수문자 432자, 숫자 30자, 한글 낱자 94자, 로마문자 52자, 그리스 문자 48자, 괘선 조각 68자, 라틴 문자 27자, 일본 문자 169자, 러시아 문자 66자 등 총 8,224자와 기타 사용자 정의 영역으로 한글 96자, 한자 95자 정도를 사용하도록 배정하고 있다.(이후 KSX 등의 명칭이 변동된 역사는 이전글을 참조)

를 보면 94*94(8836) 의 매트릭스에 위 문자들이 지정되어 있다. 'A'가 03 * 33에 'a'가 03*65에 지정되어 있고 '가'는 16*01에 할당되어 있다. 위 PDF를 보면 캐릭터 셋과 인코딩의 차이에 대해 좀더 이해할 수 있다. KSC 5601 캐릭터 셋이란 "한국"이라는 지역에서 최소한 지원해야 하는 문자들에게 각각의 번호를 지정해놓은 것이고 인코딩이란 그 번호들을 컴퓨터 이진수로 어떻게 저장할 것인가에 대한 문제이다. 

일반적으로 KSC 5601을 지원하는 인코딩은(이를테면 euc-kr)은 1byte의 첫번째 비트가 0이면 이후 7bit를 ASCII문자에 대응시키고 첫번째 bit가 1이면 다음 바이트까지 묶어서 KSC 5601의 문자번호를 지정된 해쉬함수 계산을 통해 저장된 문자로 인식한다. 

네트워크가 발전하고 CJK에 컴퓨터가 많이 보급되면서 위와같이 지역적인 문사셋을 사용하는 것은 글자깨짐의 문제(파일의 메타정보에는 문자셋을 지정할 수 없다는 것을 기억하자. 대표적으로 HTML안에도 HTML의 문자셋을 HTML 문자 안에 지정해야 한다. 이러한 - 파일 해석을 위한 방법이 파일안에 있는 - 방법이 먹혀드는 이유는 HTML은 규약상 charetSet을 지정하는 부분까지 ASCII를 제외한 다른 문자가 나오지 않아야 한다는 가정때문이다.)때문에 UniCode가 나왔다. 


UNICODE

유니코드(Unicode)는, 컴퓨터에 저장하려는 모든 문서의 글자에 대해 캐릭터 셋을 제공하기 위한 국제 표준이다. 유니코드는 오늘날 실제 사용되는 모든 문자들과, 학자들만 사용하는 문자들, 또 수학기호, 언어학기호, 프로그래밍 언어 기호 등까지 포함하고 있다. 보통 유니코드는 말하거나 문서에 적을때 캐릭터 셋과 인코딩의 두가지 의미를 동시에 가지기 때문에 다소 헛갈리지만 

보통의 경우 
유니코드라고 말하면 캐릭터 셋을, 
USC-2, UCS-4는 캐릭터 셋 혹은 인코딩 2가지 의미를
UTF-8, UTF-16, UTF-32라고 말할때는 인코딩 방법을 의미한다. 

UCS-2는 2byte 숫자로 전세계에서 자주사용하는 문자를 지정해놓은 캐릭터 셋이고(여기에는 기본 ASCII 와 서유럽언어, CJK 언어 일본어 등이 할당되어 있다. 단 65536의 제약이 있기 때문에 모든 글자가 할당되어 있지는 않다.) 이 캐릭터 셋의 번호로 컴퓨터에 저장하면 UCS-2 인코딩을 사용한 경우가 된다. 

USC-4는 4byte의 숫자로 전세계의 모든 문자와 학자들만 사용하는 문자들, 수학기호, 언어학기호, 프로그래밍 언어등까지 포함하고 이후에 새로이 나타나게 될지도 모를 문자들를 위해 많은 여유공간이 있다. 실제로는 0번부터 256^4 까지 순차적으로 번호를 부여하는게 아니라 32bit를 영역별로 쪼개서 언어판(Plane)과 Group를 지정한다. ( Group 1byte + Plane 1byte + CodePoint 2byte를 사용한다. UCS-4가 인코딩의 의미로 사용될때에는 0x00000000 ~ 0x0010FFFF 범위만을 합법적인 코드값으로 갖는다. 00그룹 + (00 - 10 까지의 17개 Plane) + codepoint 2byte)


인터넷에서는 카더라 통신이 많아서 혼란의 소지가 많지만. 위 문서는 유니코드에 대해 가장 잘 설명한 그리고 정확한 문서이다. 

'IT 이야기 > 유니코드' 카테고리의 다른 글

Unicode와 Database  (0) 2009.03.01
Global Software - Unicode와 Programming  (0) 2009.02.26
Global Software - Unicode  (0) 2009.02.25
Global Software  (0) 2009.02.22
Posted by bleujin

이를테면 나는 내일 이시간에 내가 무엇을 하고 있을지 약 80%의 확률로 맞출수 있다고 하자. 아마도 컴퓨터 앞에서 자판을 투닥거리고 있을 것이다.

그럼 내가 1년후에 무엇을 하고 있을지 맞출수 있는 확률은 얼마정도일까? 간단한 확률의 문제이다. 다음날 무슨 일을 할지가 독립변수라면 1년후에 내가 무엇을 하고 있을지 맞출 확률도 80%확률이어야 한다. 하지만 다음날 무슨 일을 할지는 독립변수가 아니고 내일모래 무슨일을 할지는 내일 무슨일을 할지에 영향을 받는다. 즉 내일 예상과 다른 일이 일어날 확률이 20%이고 그중의 반은 다음 날들의 일에 영향을 미친다고 하자. 그럴경우 내가 1년후에 무슨일을 하고 있을지 맞출수 있는 확률은 고작 2%에 불과하다.(0.9^365) 그리고 이것도 내일 무슨 일을 하고 있을지 맞출수 있는 확률이 80%라는 아주 낙관적인 기대에서 출발한 것을 잊지 말자.

이런걸 흔히 불확실성의 연속이라고 하는데 그래서 프로젝트에서도 가능하면 3월 이상의 일은 예측이라기 보다 예언이라고 해두는게 좋다. 컨설팅의 비밀이라는 책에서 나오는 의미없는 차이 + 의미없는 차이 + 의미없는 차이.... 는 의미 있는 차이라고 하는 예와 비슷하다. 

'Framework > 아키텍쳐 일반' 카테고리의 다른 글

호출의 빈도  (0) 2009.07.08
한줄짜리 함수  (0) 2009.07.06
패키지의 설계 원칙  (0) 2009.06.08
양화 구축  (2) 2009.06.08
AOP  (0) 2009.06.08
Posted by bleujin
Framework/Another Lore2009. 6. 11. 20:19

AL 개발하면서... 코드가 막힐때면 책을 읽곤 하는데..
"드리밍 인 코드"에 소개된 오픈소스 "챈들러" 프로젝트의 백엔드 저장소와 AL이 상당히 비슷하다는 걸 알았다.

AL은 Node와 Node의 Link로 정보를 저장하는데.
챈들러는 <this> <has-relationship-with> <that> 형태로 저장하는 RDF(Resource Description Framework)를 사용하고 있었다. 챈들러라는 프로젝트는 2003년쯤에 우연히 관련자료를 찾다가 알게된 프로젝트인데 당시에는 개인정보관리 시스템 정도로  알려져 있었지만 오픈된 내용이 거의 없어서 곧 잊혀졌다. (고작해야 1시간 정도 살펴본것뿐이긴 하지만 이걸 기억하는건 당시 프렌즈라는 미국 드라마를 아주 좋아했기 때문이다. 물론 챈들러 프로젝트의 챈들러는 프렌즈의 챈들러가 아니다. )


RDF(이런 용어가 존재한다는 것도 처음 알았다)는 주로 학구적인 성격이 강하기 때문에 구현체가 많지 않지만.
Phthon 구현체인 ZODB는 아직 자세히 살펴보진 않았지만 AL의 현재의 모습과 아주 비슷하다 -ㅅ-..

혼자 하는 AL이니 머 수십명 이상이 하는 ZODB나 챈들러와는
세부적인 모습은 다르지만.. 목적지가 같다..이런...

본래 오픈소스에서 비슷한 걸 발견하면 기뻐해야 겠지만..
첫번째.. 거의 실패 혹은 잊혀진 프로젝트라는 것이고..
두번째.. 파이썬으로 되어 있어서 그들의 경험으로부터 배우기가 쉽지 않기 때문이다. 췟.




'Framework > Another Lore' 카테고리의 다른 글

레이어의 속도  (0) 2009.07.05
read & write  (0) 2009.06.25
AL : Permission  (1) 2009.04.30
AL : 현재의 난제들  (0) 2009.04.30
AL : Workspace  (0) 2009.04.28
Posted by bleujin

패키지의 설계 원칙은 클래스의 설계원칙과 기본적인면에서 큰 차이가 없다. 현재까지 잘 알려진 설계 원리들은 다음과 같다.


CRP (Common Reuse Principle) - 패키지의 클래스들은 전체적으로 재사용됨.

CCP (Common Closure Principle) - 패키지의 클래스들은 동일한 유형의 변경에 대해서 닫혀있어야 함. 만일 클래스가 변경되어야 한다면 패키지의 모든 클래스들은 마찬가지로 변경되어야 함.

SOC (Separation Of Concerns) - 여러 관심사를 혼합시키지 마라.

세개 모두 High Cohension에 관한 얘기이다. 하나의 패키지는 하나의 클래스와 마찬가지로 Single Responsibility를 가져야 한다.



ADP (Acyclic Dependencies Principle) - 패키지들 간의 의존성 구조는 비순환구조이어야 함. A패키지의 일부 클래스가 B패키지를 참조하고 B패키지의 일부 클래스가 C패키지를 참조하고 C패키지의 일부 클래스가 A 패키지를 참조하는 경우를 순환 패키지 구조라고 하는데

SDP (Stable Dependencies Principle) - 패키지는 최소한 그 자체로 안정적인 패키지들에만 의존해야 함. 를 통해 예방할 수 있다. concrete 클래스가 추상클래스 혹은 인터페이스에 의존하는 것처럼 패키지도 좀더 안정적이고 추상적인 패키지에 의존해야 한다. 예컨데 java의 패키지나 apache의 stable project, 일반적인 프레임워크는 상대적으로 더 안정적이다.


SAP (Stable Abstractions Principle) - 패키지가 점점 더 안정될수록 점점 더 추상화되어야 함. 즉 SDP에 의거해 더 추상화된 패키지에 의존해야 한다는 말로 설명할 수있다.



패키지를 만들때 흔히 하는 잘못들은 A Interface의 구현클래스를 모두 하나의 패키지에 넣어야 한다고 생각하는 것이다. 물론 그럴 경우도 있지만 꼭 그래야 할 필요는 없다.

두번째로 클래스의 이름이 모든 패키지에 대해 전역으로 유니크해야 한다고 생각해서 매우 긴 클래스 이름을 만드는 경우이다. 역시 이는 늑대를 피하다가 호랑이를 만나는 실수가 될 수 있다.  

'Framework > 아키텍쳐 일반' 카테고리의 다른 글

한줄짜리 함수  (0) 2009.07.06
예언?  (0) 2009.06.12
양화 구축  (2) 2009.06.08
AOP  (0) 2009.06.08
Self-Signed Java Applets  (0) 2009.06.01
Posted by bleujin
Framework/예외처리2009. 6. 8. 20:04

흔히 알려진 테스트 하기 어려운 모듈은 네트워크, 데이타 베이스, GUI 인데 특히 Swing으로 제작된 GUI 프로그래밍을 테스트 하는 것은 꽤 어렵다. 

사실 가장 좋은 방법은 그냥 View 모듈을 Model과 Controller에서 최대한 분리하는 방법이 최선이긴 하다. 그걸로 충분하지 않다면 아래와 같인 자동 로봇을 시도해 볼 수 있다.

아래 코드는 특정 시나리오대로 프로그램을 실행하면서 마지막에 해당 GUI 화면을 갭쳐한다.

package com.bleujin.thinlet.sample.robot;

import java.awt.AWTException;
import java.awt.FlowLayout;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

public class RobotTest {

  public static void main(String[] args) {

    ButtonFrame frame = new ButtonFrame() ;
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE;
    frame.setVisible(true;
    
    GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice screen = environment.getDefaultScreenDevice();

    try {
      Robot robot = new Robot(screen);
      run(robot);
    catch (AWTException ex) {
      ex.printStackTrace();
    }
  }

  private static void run(Robot robot) {
    robot.keyPress(' ');
    robot.keyRelease(' ');

    robot.delay(2000);
    robot.keyPress(KeyEvent.VK_TAB);
    robot.keyRelease(KeyEvent.VK_TAB);
    robot.keyPress(' ');
    robot.keyRelease(' ');

    robot.delay(2000);
    robot.mouseMove(20050);
    robot.mousePress(InputEvent.BUTTON1_MASK);
    robot.mouseRelease(InputEvent.BUTTON1_MASK);

    robot.delay(2000);
    BufferedImage image = robot.createScreenCapture(new Rectangle(00450350));

    ImageFrame frame = new ImageFrame(image);
    frame.setVisible(true);

  }
}

class ButtonFrame extends JFrame {
  private JButton plainJButton; 

  public ButtonFrame() {
    super("Testing Buttons");
    setSize(450350;
    setLayout(new FlowLayout())// set frame layout

    plainJButton = new JButton("Plain Button")
    add(plainJButton)

    ButtonHandler handler = new ButtonHandler();
    plainJButton.addActionListener(handler);
  

  private class ButtonHandler implements ActionListener {
    public void actionPerformed(ActionEvent event) {
      JOptionPane.showMessageDialog(ButtonFrame.this, String.format("You pressed: %s", event.getActionCommand()));
    
  
  
  
}

class ImageFrame extends JFrame {
  public ImageFrame(Image image) {
    setTitle("Capture");
    setSize(450350);
    JLabel label = new JLabel(new ImageIcon(image));
    add(label);
  }

}

'Framework > 예외처리' 카테고리의 다른 글

예외 수집기  (0) 2009.03.26
exception framework  (0) 2009.03.10
checked vs runtime  (0) 2009.03.07
checked exception의 문제  (0) 2009.02.09
예외 처리 격언  (2) 2009.02.09
Posted by bleujin


IT는 다른 학문에 비해 비교적 신입이기 때문에 다른 학문에서 나왔지만 IT에 적용되는 이런저런 법칙들이 있다. 잘 알려진 8:2이 법칙은 성능이나 오류의 문제를 설명하는데 사용되곤 한다.

그밖에도 양화구축 - 혹은 16세기 영국 재무장관 그레셤의 이름을 딴 그레셤의 법칙이라는 게 있다. 

16세기 영국의 주요 화폐는 금화와 은화였다. 처음에는 금화의 포함된 금과 은의 가치와 금화의 가치가 거의 차이가 없었다. 그러나 화폐의 유통이 활발해지면서 화폐를 만들 금과 은이 부족해지면서 점차 금과 은의 함량을 줄인 화폐를 발행하였다.

일반 사람들로서는 최악의 상황에서 언제든 동일한 가치로 교환할수 있는 이전의 금화 은화는 자신의 금고에 두고 이 후에 발행된 함량이 부족한 화폐(악화,惡貨, bad money)만을 사용하게 되는데 이는 화폐의 신뢰문제로 이어지게 되었다.

근세 화폐 경제 체제에서 악화(함량이 부족한 금화)가 양화(1:1비율의 금화)를 구축하는 현상이 심화되자, 사람들은 통용되는 금화와 은화를 믿지 않게 된다. 일일이 금과 은의 함량을 재면서 거래를 하다 보니 화폐의 의미가 크게 퇴색하고 말았다. 결국 근세 화폐 경제 체제가 붕괴 직전까지 가고 말았다.

대항해 시대의 영국은 당시 국제통화로서의 가치를 잃고 싶지 않았고 당시 영국의 재무관이었던 T. 그레셤은 엘리자베스 여왕에게 이런 상황을 개탄하는 편지를 올렸다. 악화를 개주(改鑄)하는 작업을 거치지 않고는 영국이 외환을 지배할 수 없다는 취지였다. 19세기 중반 H. 마크로드는 그레셤의 보고에 ‘그레셤의 법칙’이라는 이름을 붙였고, 이는 훗날 경제학사에 가장 유명한 법칙의 하나가 됐다. 오늘날에서는 나쁜 것이 좋은 것을 압도하는 현상 일반을 지칭하는 용어가 됐다.

최근의 신용중심으로 변한 금융시장에서 그레셤의 법칙은 그 의미를 찾기 힘들지만 IT에서는 종종 사용되곤 한다. 대표적으로 좋은 글이나 사이트가 자극적이고 저급한 글에 밀려 사라지게 되는 현상이나 좋은 아이디어나 프로그램이 상업주의에 밀려 없어질때 사용되곤 한다.(물론 단순히 변명으로 사용되기도 한다.)





Broken Window 혹은 깨진 유리창 이론은 사회학에서 유래한 용어이다. 깨진 유리창 이론(Broken Windows Theory)은 미국의 범죄학자인 제임스 윌슨과 조지 켈링이 1982년 3월에 공동 발표한 깨진 유리창(Broken Windows)이라는 글에 처음으로 소개된 사회 무질서에 관한 이론이다.

깨진 유리창 하나를 방치해 두면, 그 지점을 중심으로 범죄가 확산되기 시작한다는 이론으로, 사소한 무질서를 방치하면 큰 문제로 이어질 가능성이 높다는 의미를 담고 있다. 오랜 기간 수리하지 않고 방치된 창문 하나가 거주자들에게 버려진 느낌을 스며들게 한다. 담당자들이 그 건물에 별 관심이 없다는 느낌 말이다. 그래서 다른 창문이 하나 더 깨진다. 사람들은 이제 어지르기 시작한다. 낙서가 등장한다. 심각한 구조적 손상이 시작된다. 꽤 짧은 시간 안에 소유주가 그걸 고치려는 의지를 넘어설 정도로 건물이 손상되고, 결국 버려진 느낌은 현실이 되어 버린다.


이는 사람들이 쓰레기를 다른 쓰레기가 버려져 있는 곳에 버리는 것과 비슷한 이치이다. 길에 쓰레기가 하나도 없다면 처음으로 쓰레기를 버리고자 하는 사람은 망설여지지만 이미 쓰레기가 버려져 있다면 그다지 죄책감을 가지지 않는 다는 것에 기인한다.

깨진 유리창을 일소하듯이 경범죄 단속에 힘쓰는 것이 중범죄 예방에 효율적인 전략이냐에 대해서는 논란이 좀 있지만 Broken Window 이론은 리팩토링 논리의 바탕이 되는 이론이다. 

깨진 창문 - 즉 조악한 설계의 코드, 형편없는 경영상의 결정 등 프로젝트 기간 동안 팀이 동고동락해야 하는 것들 - 내리막길로 가는 첫걸음이다. 깨진 창문이 꽤 있는 프로젝트를 한다면, "나머지 코드가 전부 쓰레기니까 나도 그렇게 하지 뭐."라는 사고로 빠져들기 너무도 쉽다. … 같은 맥락에서, 코드가 청순할 정도로 아름다운(깨끗하고, 잘 설계되었으며 우아한) 프로젝트와 팀에 여러분이 속해 있다면, … 별도의 특별한 주의를 기울여서 엉망으로 만들지 않도록 노력할 확률이 높다. 비록 불길이 일어날지라도 (데드라인, 출하 날짜, 시사회 데모 등) 엉망진창으로 만드는 첫째 사람이 자신이 되는 것만은 피하려 한다. 그래서 지속적인 리팩토링이 필요하다는 논리이다.




물리학에서는 잘 알려진 엔트로피의 법칙이 있다. 엔트로피란 물질계의 열적 상태를 나타내는 물리량의 하나이다. 통계 열역학적 정의로 엔트로피는 열역학적 계의 통계적인 ‘무질서도’를 나타낸다.

열역학 제 1법칙은 에너지 보존에 관한 법칙이다. 즉 제 1법칙은 "에너지는 그 형태를 달리 할 수는 있으나, 없어지지는 않는다" 는 법칙이다

IT에서 주로 회자되는 원칙은 열역학 제 2법칙으로 우주의 진화 방향에 관한 법칙이다. 즉 제 2 법칙은 "자연계에 있어서 자발적인 진화 방향은 혼란도(또는 emtropy)가 증가하는 방향"이라는 법칙이다. 우주의 에너지는 일정하지만 변화는 계속되기 때문에 결국은 엔트로피가 더 이상 증가할 수 없는 극도의 혼란한 상황에 이르게 된다. 그렇게 되면 더 이상의 자연적인 변화는 불가능하다. 이것이 바로 열죽음이라고 부르는 우주의 종말이다.

이는 사람들이 bit의 조합은 코드는 영원히 순수하리라 기대하지만 실제 코드는 버그수정과 기능 추가등을 통해 부패한다. 따라서 코드의 부패를 막기 위해서는 임의적인 작업이 이루어져야 하며 이는 코드의 생존주기 내내 끝없는 리팩토링의 필요성의 근거이론으로 사용된다.



14세기 영국의 논리학자이며 프란체스코회 수사였던 오컴의 윌리엄에서 이름을 딴 오컴의 면도날이라는 원칙도 있다. 오컴은 보다 적은 수의 논리로 설명이 가능한 경우 많은 수의 논리를 세우지 말라. 라는 말을 자주했는데 이를 약간 변형하여 가장 단순한 것이 답이다. 라는 것으로 알려져 있다.

독일의 Bauhaus 운동의 아키텍트이자 리더인 Ludwig Mies van der Rohe(1886-1969)가 직접 오컴의 면도날 원칙을 참조했는지는 알수 없지만, 설계에 있어서의 최소주의 설계(minimalist design)라는 개념을 주장하였다.

그는 Less is More를 모토로 삼았는데 의미는 단순성(simplicity)과 명료성(clarity)이 좋은 설계를 만들게 된다라는 것으로 현대 설계의 아키텍처의 단순한 형태(style)와 관련된 용어이다.

SW 아키텍처에서는 견실한(consistent) 아키텍처는 동일한 것에 대해 수행하는 두가지 이상의 방법을 제공하지 않는다는 것을 의미하며, 이는 사용자로 하여금 어떤 것을 사용할지를 선택하도록 강요하는 시간 낭비를 유발시킬 수 있기 때문이다.
따라서, 견실한 SW 아키텍처는 배우기가 더 쉽고 빨라야 하며, 일단 처음에 배운 내용을 거의 알지 못한다고 하더라도 그 나머지에 대해서는 쉽게 예상할 수 있게 구성되어야 한다. 특별한 경우에 대해서 염두하고 처리할 필요가 없이 코드는 더 깔끔해지고 테스트 코드는 더 적어야 한다.



원칙까지는 아니지만 혹시 기타를 쳐본 사람들은 시나위의 기타리스트 신대철의 명언을 알것이다. "기타가 펜더면 뭐해? 손꾸락이 펜더여야지" (펜더(Fender)-Gibson 사와 더불어 세계 최고의 일렉기타 메이커)

이는 IT 세일즈의 주장과는 달리 좋은 툴을 든 바보도 그냥 바보다. 라는 말과 일맥상통한다. 이전에 적은대로 툴이든 방법론이든간에 기본적으로 어려운것을 쉽게 해주는 것은 무척이나 어렵다. (아주 가끔 일어나기는 한다.) 단지 복잡하거나 귀찮은 것을 단순하게 만들어 줄 수 있을 뿐이다.

이 주장이 조금 과격해지면 툴은 사람을 바보로 만든다 라는 주장에 쓰이기도 하는데 개인적으로는 그렇게까지는 생각하진 않고 좋은 툴이라도 바보를 똑똑하게 만들지는 못한다 정도로만 이해하는게 좋을 것 같다. 이는 소프트웨어 작업에서 가장 중요한 요소는 프로그래머들이 사용하는 도구나 기술이 아닌 프로그래머들 자신들의 자질(quality)임을 말해준다.


그 밖에도 IT에서 회자되는 타학문의 원칙들은 다음에.. ..






'Framework > 아키텍쳐 일반' 카테고리의 다른 글

예언?  (0) 2009.06.12
패키지의 설계 원칙  (0) 2009.06.08
AOP  (0) 2009.06.08
Self-Signed Java Applets  (0) 2009.06.01
여섯번째 계 - Encapsulation  (0) 2009.04.14
Posted by bleujin

AOP


AOP는 프레임워크나 아키텍쳐보다는 패러다임에 더 가깝기 때문에 굳이 AOP 전용 언어가 아니더라도 그 의미를 살리는데는 큰 무리가 없다.

이를테면 Javascript의 경우
AOP = {
 addBefore : function(obj, fname, before) {
  var oldFunc = obj[fname];
  obj[fname] = function() {
   before(arguments, obj);
   return oldFunc.apply(this,arguments);
  };
 },

 addAfter : function(obj, fname, after) {
  var oldFunc = obj[fname];
  obj[fname] = function() {
   result = oldFunc.apply(this, arguments);
   try{
    return result;
   } finally{
    after(result, arguments, obj);
   }
  };
 }
};

// example 1
   function setRed(o){
    o.style.color = "red";
   }

   function altBeforeAdvisor(args, targetObject){
    alert("before");
   }
   AOP.addBefore(this, "setRed", altBeforeAdvisor);

   // example 2
   function setBlue(o){
    o.style.color = "blue";
   }

   function altAfterAdvisor(result, args, targetObject){
    alert("after");
   }

   AOP.addAfter(this, "setBlue", altAfterAdvisor);

와 같이 비교적 쉽게 구현할 수 있다.

좀더 나은 예제는

에서 볼수 있다.


자바에서 AOP을 적용 하는 것은 생각보다 쉽지 않다. http://www.voelter.de/data/articles/aop/aop.html 와 같이 AspectJ언어를 사용하지 않는다면 말이다.

스프링처럼 AOP패러다임을 제공하는 프레임워크를 만들기 위해서는 약간의 테크니컬한 기술이 필요하다. 가장 쉽게는 데코레이터 패턴을 생각해 볼 수 있다. 이러 상황에서 상속은 좀 위험하기 때문에 현명한 선택이 아니다.

다소 복잡하지만 Proxy를 사용할 수도 있다.
먼저 Proxy객체는 InvacationHandler를 구현해야 한다.

package com.bleujin.thinlet.sample.invocation;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;


public class NumObjectHandler implements InvocationHandler{
  
  private Object target ;
  NumObjectHandler(Object target){
    this.target = target ;
  }

  public Object invoke(Object proxy, Method m, Object[] argsthrows Throwable {
    System.out.println(m.getName());
    return m.invoke(target, args);
  }
  
}

NumObjectHandler 클래스는 모든 메소드의 호출전에  System.out.println(m.getName());를 실행시켜 준다.


package com.bleujin.thinlet.sample.invocation;

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;

public class TestInvoke extends TestCase {

  
  public void testSum() throws Exception {
    
    TestInvoke iv = new TestInvoke() ;
    
//    NumObject n3 = new NumObject(3);
//    NumObject n5 = new NumObject(5);
    
    NumObject no3 = new NumObject(3);
    NumObject no5 = new NumObject(5);
    
    INum n3 = (INum)Proxy.newProxyInstance(new SimpleClassLoader(""), no3.getClass().getInterfaces()new NumObjectHandler(no3)) ;
    INum n5 = (INum)Proxy.newProxyInstance(new SimpleClassLoader(""), no5.getClass().getInterfaces()new NumObjectHandler(no5)) ;
    
    iv.add(n3);
    iv.add(n5);
    
    assertEquals(8, iv.sum()) ;
  }
  
  
  private int sum() {
    int result = ;
    for (Object obj : data) {
      result += ((INum)obj).getValue() ;
    }
    return result;
  }


  private List<Object> data = new ArrayList<Object>() 
  private void add(INum numObject) {
    data.add(numObject;
  }
}


'Framework > 아키텍쳐 일반' 카테고리의 다른 글

패키지의 설계 원칙  (0) 2009.06.08
양화 구축  (2) 2009.06.08
Self-Signed Java Applets  (0) 2009.06.01
여섯번째 계 - Encapsulation  (0) 2009.04.14
중복을 볼 수 있는 눈  (0) 2009.03.13
Posted by bleujin

Generate a new keystore "testkey.keystore" as follows:

keytool -genkey -keyalg RSA -sigalg MD5withRSA -keystore testkey.keystore -alias testkey -validity 1460

Using this command, the keytool will generate a new keypair and create a self signed certificate for its public key. To create the certificate, the keytool will prompt for the necessary bits of X.509 information.

To sign the applet, use code similar to this (this code snipped was copied out of an Ant script):

<exec executable="${env.JAVA_HOME}/bin/jarsigner.exe">

    <arg value="-keystore"/>
    <arg value="testkey.keystore"/>
    <arg value="-storepass"/>
    <arg value="changeit"/>
    <arg value="-signedjar"/>
    <arg value="output.jar"/>
    <arg value="input.jar"/>
    <arg value="testkey"/>
</exec>

In order to run an applet signed with this key, the generated certificate may have to be imported into the Java plugin. For this, the certificate must be exported and stored in a file (e.g. 'testkey.cer'). The command line used to do this is:

keytool -export -alias testkey -file testkey.cer -keystore  testkey.keystore

The default keystore password is 'changeit'


Sharing Java objects between class loader instances
http://tom.conjective.ch/tomtom/space/Sharing+Java+objects+between+class+loader+instances

'Framework > 아키텍쳐 일반' 카테고리의 다른 글

양화 구축  (2) 2009.06.08
AOP  (0) 2009.06.08
여섯번째 계 - Encapsulation  (0) 2009.04.14
중복을 볼 수 있는 눈  (0) 2009.03.13
Here is Dragon  (0) 2009.03.12
Posted by bleujin
카테고리 없음2009. 5. 28. 05:05

3년전쯤에 지인에게
사회는 변증법적으로 발전해나가기에 정치 문제에 있어서도 특정 당 지지보다는 순환 사이클이 바람직해 보인다는
말을 한적이 있다.


MB를 지지하진 않았지만 그가 대통령이 되었을때
영화나 만화에서처럼 뚜렷한 선악 구별이 어려운 현실 사회에서
그도 그 나름의 역할이 있고 미진하더라도 나름의 역할을 할 것이라고 생각했""다..


일찌기 현자 간디가 말한 7가지 사회악을 보니

첫째- 원칙 없는 정치 (Politics without principle)
둘째-노동 없는 부 (Wealth without work)
셋째- 양심 없는 쾌락 (Pleasure without conscience)
넷째- 인격 없는 교육 (Knowledge without character, 인격 없는 지식)
다섯째- 도덕 없는 경제 (Commerce without morality,도덕성 없는 상업)
여섯째- 희생 없는 종교 (Religion without sacrifice)
일곱째- 인간성 없는 과학 (Science without humanity)


새삼스레 간디의 혜안이 놀랍기만 하다.


가끔은 그들도
다른 사람이 이상한게 아니라 사실은 내가 이상한게 아닐까? 라는 고민을 해보길 간절히 바란다.


지난 몇달간의 일련의 사태를 보면서 고결한 신이 되길 바란적은 없으니
힘들지라도 그냥 존경할 수 있는 이전 대통령으로 존재해주길 바랬다.

다른 나라 처럼 우리나라에도 존경받는 대통령 한명쯤은 있어도 되지 않는가 싶었다.

그러나
그 시간들이 고 노무현 전 대통령께는 고통이었고 그 바램들이 나에게는 사치스런 욕심이었나 보다.



여러가지로 힘든 계절이다...




Posted by bleujin
Framework/Another Lore2009. 4. 30. 11:26

Permissions encompass the restrictions imposed by any access control restrictions that may be in effect upon the content of a repository, either implementation specific or JCR-defined

In repositories that support Access Control this will include the restrictions governed by privileges but may also include any additional policy-internal refinements with effects too fine-grained to be exposed through privilege discovery


Permissions are reported through
     boolean Session.hasPermission(String absPath, String actions)

which returns true if this Session has permission to perform all of the specified actions at the specified absPath and returns false otherwise. Similarly, void Session.checkPermission(String absPath, String actions) throws an AccessDeniedException if the this Session does not have permission to perform the specified actions and returns quietly if it does.


The actions parameter is a comma separated list of action strings, of which there are four, defined as follows:

  create: The permission to add a node at absPath.
  update: The permission to set (add or change) a property at absPath.
  delete: The permission to remove an item at absPath.
  read: The permission to retrieve (and read the value of, in the case of a property) an item at absPath.


The permission actions add_node, set_property and remove will only be relevant in a writable repository. In a read-only repository they will always return false. The information returned through these methods only reflects access controlrelated restrictions, not other kinds of restrictions such as node type constraints.

For example, even though hasPermission may indicate that a particular Session may add a property at /A/B/C, the node type of the node at /A/B may prevent the addition of a property called C.

SampleCode

package com.bleujin.lore.core.security;

import com.bleujin.lore.addon.security.Group;
import com.bleujin.lore.addon.security.IResource;
import com.bleujin.lore.addon.security.IUser;
import com.bleujin.lore.addon.security.Member;
import com.bleujin.lore.addon.security.UserAuthority;
import com.bleujin.lore.addon.security.UserAuthority.Range;
import com.bleujin.lore.addon.security.UserAuthority.Type;
import com.bleujin.lore.core.TestCaseParent;
import com.bleujin.lore.core.exception.ALRepositoryException;
import com.bleujin.lore.core.node.Node;

public class TestSecurity extends TestCaseParent {

  private Group adminGroup = new Group("admin");
  private Group normalGroup = new Group("normal");
  private Member bleujin = new Member("bleujin");

  private Node lvl1 = null;
  private Node lvl2 = null;

  private NodeResource lvl1Resource = null;
  private NodeResource lvl2Resource = null;
  private TransientSecurityFilter sf = null;
  private AuthoritySetting setting = AuthoritySetting.createDefault() ;

  public void setUp() throws Exception {
    super.setUp();

    lvl1 = createNode(objectType, "level1");
    lvl2 = createNode(lvl1, objectType, "level2");

    lvl1Resource = new NodeResource(lvl1);
    lvl2Resource = new NodeResource(lvl2);

    sf = new TransientSecurityFilter(setting);
  }

  private boolean isAllowed(IResource resource, IUser user, NodeAction actionthrows ALRepositoryException{
    return sf.isAllowed(resource, user, action;
  }
  
  public void testResourceInherit() throws Exception {
    setting.add(new UserAuthority(lvl1Resource, bleujin, setting.readAuthority(), Range.ONLY_THIS_RESOURCE, Type.GRANT));

    assertEquals(true, isAllowed(lvl1Resource, bleujin, NodeAction.create("read")));
    assertEquals(false, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));

    // test include Sub
    setting.add(new UserAuthority(lvl1Resource, bleujin, setting.readAuthority(), Range.INCLUDE_SUB_RESOURCE, Type.GRANT))// inherit..
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));

    UserAuthority lvl2Revoke = new UserAuthority(lvl2Resource, bleujin, setting.readAuthority(), Range.ONLY_THIS_RESOURCE, Type.REVOKE);
    setting.add(lvl2Revoke);
    assertEquals(false, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));

  }

  public void testEqual() throws Exception {
    setting.add(new UserAuthority(lvl2Resource, bleujin, setting.readAuthority(), Range.ONLY_THIS_RESOURCE, Type.GRANT));
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));

    setting.remove(new UserAuthority(lvl2Resource, bleujin, setting.readAuthority(), Range.ONLY_THIS_RESOURCE, Type.REVOKE));
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));
  }

  public void testAuthorityInherit() throws Exception {
    setting.add(new UserAuthority(lvl1Resource, bleujin, setting.managerAuthority(), Range.INCLUDE_SUB_RESOURCE, Type.GRANT));
    bleujin = new Member("bleujin");
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("write")));

    setting.add(new UserAuthority(lvl2Resource, bleujin, setting.readAuthority(), Range.INCLUDE_SUB_RESOURCE, Type.REVOKE));
    assertEquals(true, isAllowed(lvl1Resource, bleujin, NodeAction.create("read")));
    assertEquals(false, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));

    assertEquals(true, isAllowed(lvl1Resource, bleujin, NodeAction.create("write")));
  }

  public void testUserInherit() throws Exception {
    setting.add(new UserAuthority(lvl1Resource, adminGroup, setting.managerAuthority(), Range.INCLUDE_SUB_RESOURCE, Type.GRANT));
    assertEquals(true, isAllowed(lvl1Resource, adminGroup, NodeAction.create("read")));
    assertEquals(true, isAllowed(lvl1Resource, adminGroup, NodeAction.create("read")));
    assertEquals(false, isAllowed(lvl1Resource, bleujin, NodeAction.create("manager")));
    assertEquals(false, isAllowed(lvl1Resource, bleujin, NodeAction.create("read")));
    assertEquals(false, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));
    assertEquals(false, isAllowed(lvl2Resource, bleujin, NodeAction.create("write")));

    bleujin = new Member("bleujin");
    bleujin.partIn(adminGroup);

    assertEquals(true, isAllowed(lvl1Resource, bleujin, NodeAction.create("read")));
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));
    assertEquals(true, isAllowed(lvl1Resource, adminGroup, NodeAction.create("read")));
    assertEquals(true, isAllowed(lvl1Resource, adminGroup, NodeAction.create("read")));
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("write")));
  }

  public void testMultiGroup() throws Exception {
    // adminGroup <- bleujin
    // normalGroup <- bleujin
    setting.add(new UserAuthority(lvl1Resource, adminGroup, setting.managerAuthority(), Range.INCLUDE_SUB_RESOURCE, Type.GRANT));
    assertEquals(true, isAllowed(lvl1Resource, adminGroup, NodeAction.create("read")));
    assertEquals(false, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));

    bleujin.partIn(adminGroup);
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));

    setting.add(new UserAuthority(lvl2Resource, normalGroup, setting.managerAuthority(), Range.INCLUDE_SUB_RESOURCE, Type.REVOKE));
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("write")));

    bleujin.partIn(normalGroup);
    assertEquals(true, isAllowed(lvl1Resource, bleujin, NodeAction.create("write")));
    assertEquals(false, isAllowed(lvl2Resource, bleujin, NodeAction.create("write")));

    normalGroup = new Group("normal");
    bleujin.dropOut(normalGroup);
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("write")));
  }

  public void testGroup() throws Exception {
    // adminGroup <- normarGroup <- bleujin
    setting.add(new UserAuthority(lvl1Resource, adminGroup, setting.managerAuthority(), Range.INCLUDE_SUB_RESOURCE, Type.GRANT));
    setting.add(new UserAuthority(lvl2Resource, normalGroup, setting.managerAuthority(), Range.INCLUDE_SUB_RESOURCE, Type.REVOKE));
    assertEquals(true, isAllowed(lvl1Resource, adminGroup, NodeAction.create("read")));
    assertEquals(false, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));

    bleujin.partIn(adminGroup);
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));

    normalGroup.partIn(adminGroup);
    assertEquals(true, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));

    bleujin.partIn(normalGroup);
    assertEquals(true, isAllowed(lvl1Resource, bleujin, NodeAction.create("read")));
    assertEquals(false, isAllowed(lvl2Resource, bleujin, NodeAction.create("read")));
  }
}


'Framework > Another Lore' 카테고리의 다른 글

read & write  (0) 2009.06.25
최근에 책을 읽다가..  (0) 2009.06.11
AL : 현재의 난제들  (0) 2009.04.30
AL : Workspace  (0) 2009.04.28
AL : Property Type Conversion  (0) 2009.04.26
Posted by bleujin