Design Quality

What does it mean to be well designed? A system that is well designed is easy to understand,
easy to change, and easy to reuse. It presents no particular development difficulties,
is simple, terse, and economical.

잘 디자인(설계)된 프로그램은 위와 같은 특징들이 있음


Design Smells.

You know when a programmer is working with a poor design by the state of his eyes
and nose while he’s looking at the code. If his or her facial expression reminds you of the
detectives who have just opened a body bag containing a 12 day old corpse, then the
design is probably pretty ripe. The smells of a poor design have many different components.

1. Rigidity: The system is hard to change because every time you change one thing,
you have to change something else in a never ending succession of changes.

- 강직, 경직됨 : 시스템을 바꾸기 어려운 경우, 매번 바꾸었기 때문(스파게티 코드), 지속적인 변경이 필연적인 상황

2. Fragility: A change to one part of the system causes it to break in many other,
completely unrelated, parts.

- 단편, 깨지기 쉬움 : 하나의 변화 전체 시스템에 치명적 영향을 줌, Strongly Coupled~

3. Immobility: It is hard to disentangle the system into components that can be
reused in other systems.

- 부동성 : 시스템을 콤포넌트(다른 시스템에서 사용될 수 있는) 조합으로 분리해 내기 힘든 상황

4. Viscosity: The development environment is held together with scotch tape and
toothpaste. It takes forever to go around the edit, compile, test loop.

- 점착성 : 개발 환경에 지나친 의존성을 가지는 상황

5. Needless Complexity: There are lots of very clever code structures that aren’t
acutally necessary right now, but could be very useful one day.

- 불필요한 복잡성 : 당장 필요하지도 코드 구조가 존재하는 상황, 그러나 언젠가는 유용할 지도 모르는 코드임

6. Needless Repetition: The code looks like it was written by two programmers
named Cut and Paste.

- 불필요한 반복 : Ctrl C, V로 생산된 코드가 혼재하는 상황

7. Opacity: Elucidation of the originator’s intent presents certain difficulties
related to convolution of expression.

- 투명성 : 작성자의 의도에 대한 설명이 난해한 표현으로 어려움을 내포하고 있음
The primary mechanisms behind the Open-Closed principle are abstraction and polymorphism.
In statically typed languages like C++, one of the key mechanisms that supports
abstraction and polymorphism is inheritance. It is by using inheritance that we can
create derived classes that conform to the abstract polymorphic interfaces defined by pure
virtual functions in abstract base classes.

 inheritance를 이용하여 객체지향의 특성(polymorphism, abstraction)을 활용한다.

What are the design rules that govern this particular use of inheritance? What are the
characteristics of the best inheritance hierarchies? What are the traps that will cause us to
create hierarchies that do not conform to the Open-Closed principle? These are the questions
that this article will address.

상속의 사용에 있어 설계의 원칙이 있는가?
상속을 이용한 디자인의 특성은 무엇인가?

FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE
CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES
WITHOUT KNOWING IT.

Reference 형을를 쓰는 기능은 상속되는 클래스는 실제 Object의 구조를 알 필요없이,
상위 레벨의 클래스의 Object로 사용될 수 있어야 한다.

The above is a paraphrase of the Liskov Substitution Principle (LSP). Barbara Liskov first
wrote it as follows nearly 8 years ago1:

위의 문장은 LSP 정의의 의역이고 바바라 리스코프는 처음에 다음과 같이 섰다.(8년전)

What is wanted here is something like the following substitution property: If
for each object o1 of type S there is an object o2 of type T such that for all
programs P defined in terms of T, the behavior of P is unchanged when o1 is
substituted for o2 then S is a subtype of T.

복잡하다.. -_-;


The Open-Closed principle is at the heart of many of the claims made for OOD. It is when
this principle is in effect that applications are more maintainable, reusable and robust. The
Liskov Substitution Principle (A.K.A Design by Contract) is an important feature of all
programs that conform to the Open-Closed principle. It is only when derived types are
completely substitutable for their base types that functions which use those base types can
be reused with impunity, and the derived types can be changed with impunity.

상위 class의 객체를 상속구조상의 하위 class의 객체로 대체할수 있어야 된다..
OCP 를 더욱 견고히 하기위한 원칙..



오늘 밴쿠버에서 태어난 학원 선생님이 명언을 남기셨다.

밴쿠버에는 2가지 계절이 있고,
2가지 계절이란,
There are August and Not August~ !!

밴쿠버에서 봄여름가을 까지 생활해본 사람으써 저말에 적극 동의한다..

캐나다는 7~8월을 제외하면 '우기'에 가까울 정도로 비가 오거나 흐린날이 많다..

물론 한국의 여름처럼 게릴라성 폭우 같은 비가 아닌,
부슬부슬, 안개비 같은것들을 자주 만날 수 있다..

맞아도 그만인 비만 오는 덕에, 비가 와도 거리에서 우산을 쓴 사람의 비율이 절반을 넘지 않는다..
비 많이 온다고 우산 꼭꼭 몇개씩 챙겨오는 사람들을 자주 보는데,
사실 와보면 알겠지만 아이러니하게 비는 자주오는데 우산이 필요없는 곳 임을 알게된다..

참고로 사진을 올린다.. 전체날씨중 70%는 저런 날씨라 보면된다..
[버나비 지역 주택가]

[다운타운]

[벤쿠버 남부 주택가]

우산 보다는 노*페이스 방한, 방수 자켓은 필수 아이템..
검정색 방수 자켓하나 있으면 봄여름가을겨울 지내는데 부족한게 없다.. 아주 유용하다..

이억만리 먼나라 답게 한국과는 또 다른 차이가,
6월경에는 새벽 4:30분이 되면 여명이 밝아오고 저녁 9시나 되어야 어두워 진다..

이것이 의미하는게 무엇일까..
해가 떠있는 낮의 길이가 무척 길기 때문에 생활패턴에도 조금 차이가 있다..

아침을 조금 늦게 먹는다거나 아침겸 점심으로 브런치 문화가 발달해 있고,
저녁도 7시 이후에나, 조금 늦게 먹는거 같다..
긴 오후시간을 이용해 여가시간을 즐기는 사람도 많다..
회사-집-회사-집 패턴이 아니라 회사-여가-집의 패턴이 가능한 것..
물론 10월 정도되면 해도 7시에나 뜨고 저녁 7시만 지나도 어두워진다..
한국과 대충 비슷해지는 시기가 아닌가 싶다..

여름기온은 최대 30도 정도이고,
날씨가 건조하기 때문에 햇살은 따갑지만, 전혀 땀이 나지 않는다..

동양인은 이런 강한 햇살에 취약한 피부를 가졌기에,
남미나 유럽쪽 사람들에 비해 훨씬 피부가 잘 타기 때문에, 선크림, 모자는 필수이며,
선글라스나 자외선 차단 코딩된 안경이 필수다..
없으면 눈이 굉장히 피곤하다..

봄과 가을은 10~20도 수준으로 집안에서는 반팔과 반바지만 입고도 생활이 가능한 수준이나,
10도 이하로 떨어지는 새벽에는 많이 춥기때문에 편하게 입을 옷은 반팔, 긴팔 일단 다 챙기는 것이 좋다..

겨울은 생활하지 않아서 잘 모르겠으나,
벤쿠버는 역시 눈보다는 비가 많이 온다 그런다..
한국보다 겨울은 따듯하고 여름은 시원한 이상적인 날씨다..

그리고 신기한게, 밴쿠버에는 여름에도 모기가 없다.. (한번도 물려 본적이 없음)
모기 물린데 바르는 약따위 필요없으니 참고하시라..

벤쿠버 날씨는 이것만 알고 가면 일단 OK..
 

 
 Crawler에 의해 추출된 웹페이지를 적절히 Indexing 하기 위해서는 해당 문서에 본문영역을 추출(Filtering)하는 것은 검색의 정확도에 있어 매우 중요한 부분이다.
 
 관련된 연구논문에 따르면 본문과 상관없는 네비게이션, 광고, 페이지 템플릿 등 본문의 내용과 관련없는 부분이 전체 Html 구성 Text에서 40% 이상을 차지한다 그런다. 물론 광고, 네비게이션, 템플릿등은 모든 페이지에서 공통적으로 등장한다면 단순하게 TFIDF과 같은 단순한 확률분포기반 Indexing 만으로도 어느정도 검색과 무관한 데이터로 가려낼 수 있기는 하지만, 이외의 여러가지 다양한 용도로 사용될 수 있고 검색의 방법론 등을 고려해 보았 을때 매우 중요한 기능 임에는 틀림없다.

 일단 아래의 신문기사의 DOM Tree를 보자.

다소 길기는 하지만 본문 영역만 자세히 보자.

 본문을 추출하기 위한 가장 간단한 아이디어는 Dom Tree 를 이용하여 Link(a tag)가 설정되어 있지 않는 Text Node를 추출하는 방식이 있으나 이렇게 했을때 불필요한 텍스트를 포함하고 있을 가능성이 매우 크기때문에 2차적인 보정이 필요하다. 
 
아래는 본문영역 추출을 위해 사용될 수 있는 간단한 방법이다. 
(몇몇 논문 참조 및 개인연구를 통해 알아낸 가장 적합한 방법이라 생각한다)


1. Unlink Text Node를 추출하여 Dom의 Node Depth가 같은 Node의 군집을 추출한다.
 (실제 구현시에는 인접노드 추출후 재병합하는 방법을 사용하였는데, 이것은 이후에 설명을 하겠다) 

2. Unlink Text의 밀도를 추출하여 대량의 Text가 밀집된 영역군을 추출하고 1번에서 추출된 후보군집과의 비교를 통해 최종 추출 노드들의 공통 parent node들을 추출하고 parent의 child내의 Text Node의 조합이 본문이 된다. 여기서 추출된 parent node는 1개 이상이 된다. 덧글과 같은 비링크 데이터가 존재할 수 있기 때문이다. 그래서 다수의 후보 node 군이 추출된다.

3. 기사의 내용이 지나치게 짧다거나 기사보다 내용이 긴 덧글 등은 본문 추출의 최대의 적이다.
  - 사실상 짧은 내용의 기사일 경우 정확한 추출은 불가능하다. (여러 페이지 분석을 통한 템플릿 추출 이후 가능)
  - 덧글 등은 Table 태그의 구조적 Pattern 양상을 보이므로, DOM 의 구조분석을 통해서 덧글 여부를 판별 할 수 있다.

4. 가장 이상적인 방법은 언론사 사이트의 메인페이지에서 동일 level(군집)의 Link를 추출하여, 동일한 페이지 구조 템플릿을 사용하는 페이지들을 분석하여, 본문에 해당되는 DOM Tree의 Path를 추출하는 방법이다.


 한가지 불행한 사실은 본문과 그렇지 않은 부분의 경계가 모호한 페이지도 많다는 것이다. 연구를 하다가 부딛히는 문제들중 본문의 기준을 무엇으로 볼것인가 라는 의문을 던져주는 사이트도 적지 않았다.
 
 결국에는 패턴을 통한 기계의 자동화와 인간의 인지에 의한 영역 지정, 기계와 인간의 하이브리드된 방법이 답니다. 다시말해 추출의 대상이 되는 사이트의 XPath 형태의 본문을 포함하는 영역의 DOM 경로 추출 후 추출 값이 정확하지 않을 경우 추가 되거나 제거되어야 할 영역의 규칙을 사람에 의해 수동으로 설정이 가능하도록 하는 방법이 지금으로써는 답이다.

 물론 불과 몇년전에 불가능으로 보였던 것들에 대한 구현들에 관한 내용이 최근에 계속해서 논문으로 나오고 있는 것을 보면, 수년내에 자동 본문 추출도 완전에 가까운 형태가 되지 않을까 생각된다. 아니면 사람이 좀 고생하는 거고..

김영곤 <gonni21c@gmail.com>
 
 Html Parser는 검색엔진 개발에 있어 가장 기본적이면서도 문자열의 논리적 구성을  담당하는 역할을 하는 중요한 모듈이므로, 속도, 안정성, 정확성등 여러가지 섬세하게 고려해야 될 부분이 많다.
 학생시절 부터 관심이 있어서 Html Parser를 어떻게 만들면 잘 만들수 있을까 참 많은 고민을 한 것 같다.
많은 세월이 흘렀음에도 아직도 해답을 찾지는 못했고, 대략적인 실패한 경험들을 토대로 개발시 고려사항들을 정리해 보고자 한다. (참고로 Version 6 정도의 Html Parser가 현재 개발중이다.)


1. HTML파서와 XML파서의 제작은 차원이 틀리다.
 
 XML 문서와 같은 경우 Well-Formed check를 통해 Tag의 열고닫음, XML의 문법적인 유효성을 강하게 체크하지만,
HTML은 그렇지 못하다. 대표적으로 <BR> 과 같은 Tag는 </BR>과 같이 닫기Tag가 명시적으로 사용되고 있지는 않으므로,
HTML Dom Tree 생성시 계층구조 구성을 위한 별도의 처리가 필요하다.
 
 즉, HTML은 모호성(Ambiguous)을 아직까지는 문법적으로 허용하며, 문법의 정확성을 보장할수 없는 변칙적인 언어이다.
대부분의 HTML DOM 파서는 1Pas 시 Well-Formed 조건에 맞게 XML 파서로 파싱이 가능한 형태의 문서를 생성하고, 
2Pass시 Dom Tree를 생성하는 구조로 되어있다. 



2. 속도와 공간사용량 타협이 필요하다.

 대부분의 Parser가 아마도 최단 시간내에 Parsing을 완료하는 것을 목표로 할 것이다. 물론 정확하게 파싱해 내는 것은 말 할 것도 없다. 하지만 파서의 속도가 아무리 빠르다 할지라도 Web 상의 정보, 소스를 Network을 통해 가져오는 Html Parser의 특성상 극단적으로 속도를 빠르게 하는 것이 무의미한 작업일 수도 있다.

 하지만 속도가 극단적으로 중요한 상황이라면 네트웍에서 데이터를 가져오는 동안 소스의 부분을 여러부분으로 나누어 독립적인 쓰레드의 병렬 파싱을 하도록 한는것도 가능하지만, 가장 간단하면서도 빠른 방법은 일단 데이터를 웹에서 다운받아 StringBuffer나 Char의 배열에 미리 저장해 두고 parsing하는 것이 속도 측면에서는 더 효율적이 이었다.

 파싱을 위한 초기작업으로 HTML 문서에서 의미의 단위별로 텍스트의 조합, 즉 Token을 추출하는 Lexing 작업이 선행된다. 파서자체, 객체지향 프로그램 언어적 시각으로 보았을때 파싱의 대상이 되는 Source라는 커다란 객체를 문법으로 정의된 의미의 객체단위로 분리하는 작업이라 할 수 있다. 보통의 경우 Token의 Text와 Token Object가 최소한 1:1의 관계를 이루게 된다. 모든 Parser가 그러하듯 Lexing의 가장 작은 단위동작은 char, 즉 문자 하나를 소스로 부터 가져와 비교하고 그 문자 하나하나가 모여서 하나의 문자열 Token을 이루게 된다. Char단위의 문자열 연산이 상당히 많으며, String 연산 또한 많다. Token의 Size는 예측할 수 없으므로 결국 Token값의 최종결과는 정적으로 할당된 배열에 저장하게 되는데, 토큰 생성시 마다 정적배열의 생성은 극단적으로 H/W power가 약한 시스템에서는 무리가 될 수 있으며, 배열의 전체공간이 Pull인 경우 배열공간을 갱신하는(ex, StringBuffer) 자료구조를 쓸 경우 속도적인 측면에서 손해를 보게 된다.

언제나 그렇듯, 속도와 공간의 타협점을 찾아야 한다.



3. 사용언어의 추출 : UTF-8, EUC-KR

 다양한 언어가 공존하고, Charset이 다양하게 존재하는 웹의 구조적 특성상, 웹에서 어떤 데이터를 취득했을때, 그 데이터가 어떠한 Charset을 사용했는지 알아내는 것이 HTML 문서 파싱의 선행 작업이라 할 수 있다. 어떠한 Charset을 사용하는지는 아래와 같은 단서를 이용해서 알 수 있다.

a. Http Protocol Header의 Charset attribute 값에서 추출
b. Html Header 내의  <meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
c. <Html lang="ko"> Tag의 lang 속성

a의 경우 서버 자체적으로 제공해 주는 기능이라 최초 Lexing전 charset의 정보를 취득할 수 있으며, b, c의 경우 일단 데이터를 저장하고 pre-reading을 통해 해당정보를 추출해야 한다.(Parsing 속도 측면에서 좋은 방법은 아니며, 초기 ASCII 모드형태로 데이터를 읽으면서 해당정보가 추출된 이후 charset 형태의 맞추어 문자 읽기를 동적으로 변환하는 방법으로 가능하다)

저러한 정보를 얻을 수 없는 최악의 상황은 byte연산을 통해 현재 어떠한 type의 문자를 포함하고 있는지 별도의 연산과정이 더 필요하다.



4. 무한 루프의 가능성

 앞서 언급한 바와 같이 html 언어는 모호성을 허용하며, 변칙적인 문법의 사용이나, 정확하지 않은 문법을 사용한 문서들도 상당히 많음을 항상 염두해 두어야 한다. 아마도 모든 파서가 데이터로 부터 커서나 포인터를 증가시켜 문자를 읽어들이면서 파싱이 진행되는 형태를 취하고 있을 것으로 생각된다. 
 
 커서의 진행방향이 consume만 하는, 값이 증가만 하는 단방향성만을 가진 다면 큰 문제는 없으나, 경우에 따라서는 커서의 backward가 필요한 경우가 종종 발생한다. 생각해 볼수 있는 가장 심각한 시나리오는 커서가 진행을 못해 파싱 과정에서 파서 자체의 프로세스가 무한루프에 빠지는 경우이다.

 커서가 지속적으로 진행하는 단방향성을 가지는 것이 최고의 시나리오이나 그렇지 못한 문법구조를 가졌다면 무한루프의 가능성을 항상 염두해 두어야 되겠다. (불행히도 수많은 Case에 대한 Test 필요)



5. 주석처리상의 문제

 위에서도 언급한 바와 같이 HTML parser의 문자처가 단방향성을 가진다면 더할 나위 없이 좋겠지만, <script>, <style> <!-- 주석 -->등 과 같은 요소로 인해 사실상 커서의 backward나 미리 읽기버퍼를 현재 문자이후에 등장하는 문자열을 검사해야 하는 경우가 발생한다. 

 <script>나 <style> 태그의 경우 Value값의 경우 HTML과는 다른 별개의 언어의 문법을 사용하므로 HTML Parsing 모듈이 해당 언어를 파싱할 수 있는 모듈에게 제어권을 넘기거나 혹은 </script> 나 </style>이라는 문자열이 나타날때 까지 모든 문자열을 무시해야 한다. 주석의 경우에도 마찬가지 인다.
문자 단위로 커서를 이동하면서 미리읽기를 통해 이후에 뒤따르는 문자열을 분석하는 작업이 필요하다. 속도 측면에서 상당한 마이너스가 아닐까 생각된다.



6. DOM Object의 경량화

 앞서 언급한 바와 같이 Token 과 Token의 Object는 1:1 관계를 이룬다. 일반적으로 Java Application이 실행시 부하량(시간지연)에 가장 많이 영향을 주는 요소는 객체의 생성 시간이다. 객체의 생성량이 크지 않는 경우라면 시스템 성능에 미치는 영향이 미미하겠지만 대형 포털 사이트 메인페이지를 파싱하면 보통 2000개 이상의 Token이 생성된다. Token Object 객체도 똑같이 2000개 이상 생성된다는 소리이며, Tree 생성시 구조에 따라서 생성 객체수는 2배이상 증가 될 수 있다. 

 일반적인 프로그램에 비해 객체의 생성량이 많고, 페이지의 특성에 따라 생성되는 수를 예측할 수 없기 때문에, 일반적으로 Class 생성시 DOM을 구성하는 단위 객체는 최대한 경량화 되어야한다. C의 구조체처럼 데이터만을 포함될 수 있는 형태가 적절하며 연산이 들어간 method의 사용은 최소화 하는 것이 바람직해 보인다.

 전체 디자인적으로는 Parsing 을 하는 행위모듈과 파싱후 생성되는 객체, 데이터 모듈을 Class 단위로 철저히 분리해야 한다. 또한 Parsing의 행위모듈의 경우에도 최대한 static 하거나 single object에서 실행되도록 하여, 객체의 생성 자체를 최소화 하는 것이 바람직한 방향으로 보인다. 

 객체의 생성이 과도하다면 Object의 메모리 영역을 clone copy를 통해 새로운 객체를 생성하는 Prototype Design Pattern을
고려해 볼 수 있으나, Prototype 패턴은 사용 class의 구조적 특성에 따라 효율이 오히려 떨어지는 경우도 있다. 객체 생성시 생성자의 구현이 복잡하다면 고려해 볼 수 있으나, 생성자의 내용이 없는 DOM의 Token 혹은 Node Object 생성시에는 시간적 효율은 거의 없거나 증가하는 양상을 보였다.



7. 문법 확장성의 고려
 새로운 문법에 대한 확장성에 대한 고려도 물론 필요하다. 전체 설계시 영향을 주는 부분이고, 지나친 환장성은 속도, 공간적 효율을 저해한다. 이 부분은 현재 개발중인  YGHtmlParser Release시 별도 언급을 하겠다.


- 김영곤(gonni21c@gmail.com) 

 Java를 이용한 웹개발시 Servlet 과 같은 Dynamic Page의 구현시에는 Servlet Container를 지원하는 Web Server를 사용하는 수 밖에는 없습니다. Servlet 을 지원하는 Java 다수의 경량 서버가 있습니다만, PDA 같은 임베디드급 머신에 포팅하여 동작 시키기에는 상당한 부담임에는 틀림없습니다.


 그래서 임베디드나 PDA 같은 H/W 리소스가 제한적인 장비에서 동작시키기 위한 경량 웹서버를 취미 생활(?)로 만들어 보았습니다. 이름하여 YG HttpServer 이며 아래 원칙하에 제작되었습니다.


- HTTP Fullspec이 아닌 단순 페이지뷰나 파일전송 정도의 기본적 기능만 지원하고 필요한 기능은 사용자가 확장할 수 있을 것

- 장치에 Capability에 맞춰 Setting이 쉬울 것

- Servlet 과 유사한 동적인 페이지를 지원 할 것


즉, WebServer의 평가항목 Performance, Scalability, Security, Avaliability, Compliance to standards, Flexibility, Platform requirements, Manageability 중  굵은 글씨로 표시된 항목에만 중점을 두었습니다.


 일단 위와 같은 특성들을 지원하기 위하여 웹서버를 최대한 단순화하여, 필요한 역할을 하는 부분들을 나누고 사용자의 요구에 따라 사용자가 직접 필요한 부분은 tuning 할 수 있도록, 


 Server를 구성하는 부분항목에 대해서는 OpenAPI를 제공 기능의 추가, 삭제, 부하량을 고려한 퍼포먼스 튜닝등을 용이하게 하였습니다.

 

 서버의 대략적인 서버 Core 모듈의 구조는 아래와 같습니다.

  

1. MicroWebServer에서 ServerSocket의 생성 관리 및 Client Socket Binding을 담당하여,


2. ServiceMapper에서는 생성된 Client Socket의 Header를 parsing 하여 요구 Resource를 추출, Resource를 처리할 수 있는 Service Object에 넘겨주는 역할을 합니다.


3. AbstractService를 extends 하여 사용자가 원하는 형태의 서비스를 구현도 가능하며, 현재 Web Server에서는 기본적으로 Html이나 일반적은 파일을 전송하는 StaticResourceService와 Servlet과 같은 동적인 웹페이지를 사용자가 구현할 수 있도록 경량화한 GdpService를 지원합니다.


4. Gdp 요청에 대해서는 사용자가 직접 작성한 Gdplet Object에 전달되어 개별적인 동적 처리가 이루어 지는 구조입니다.

4-1. 예제로 쓰인 Hello gdp 와 파일전송은 이후에 살펴보겠습니다.


5. IServiceScheduler는 다수의 요청의 처리를 위한 스케쥴러 Interface이며, 사용자는 Device의 Capa에 맞추어 적절한 형태의 스케쥴러를 직접 작성할 수도 있습니다.

5-1. 기본적으로 내장된 DefaultServiceScheduler는 ThreadPool의 형태로 구현되었고, Client의 요구를 순차적으로 저장했다가 처리하는 저장 순서에 따라 처리하는 Unbounded queue 가 사용되었으며, Pool 공간은 10입니다.(동시에 10건 이내의 요청만 처리 가능합니다.)

 

눈치 채신분도 많겠지만,

위의 웹서버는 Java의 NIO가 아닌 Standard IO로 구동되는 구조입니다. Standard IO는 다수의 동시처리를 위해 쓰레드를 사용할 수 밖에 없습니다. 


Performance가 떨어지는 Standard IO + ThreadPool 기반으로 제작한 이유는 NIO는 OS에 종속성이 있으며, JVM에 제약이 있는 임베디드 장비에서는 정상적인 동작이 어려울 수 도 있고, 애초에 의도가 대량 접속처리가 아니라 최대한 가벼운 환경에서 동작되는것을 목표로 하였기 때문입니다.

NIO 버전은 현재 ME 버전이 아닌 SE 버전에서 적용될 예정입니다.


아래는 위에서 설명한 Server의 Core 모듈입니다. (상업적 이용은 불가입니다. 모든 소스 오픈예정)




앞서 설명한 바와 같이 기본 Service 만을 탑재하여 아래와 같이 Cosole에서 실행 시킬 수도 있습니다.

주석으로 처리된 부분은 GpeService를 추가시키는 부분으로 사용자가 작성한 Gdplet 서비스의 탑재도 가능합니다.


Gdp는 Gonni Dynamic Page의 약자로 서블릿과 같이 사용자가 동적인 웹페이지를 구성할 수 있도록 제공하는 API를 제공합니다. 사용자는 Gdplet 이라는 class의 service(XRequest req, XResponse res) method만 구현하면 됩니다.


아래는 Hello GDP 예제입니다.


Http 프로토콜은 기본적으로 Header와 Body의 구조로,  Header에는 기본적으로 사용자가 Client에게 전송하는 data의 mime type의 지정이 필요하며,  Body부분에 실제 전송을 위한 data를 write 해주면 됩니다. (API상으로는 Character와 Binary 두가지 형태의 write를 모두 지원합니다. )

 

아래는 위의 Gdp 예제의 실행결과 입니다.


새로고침 버튼을 눌렀을 경우 페이지가 동적으로 현재시간에 맞추어 갱신되는 것을 확인 할 수 있습니다.


아래는 해당 모듈을 이용하여 만들어본 GUI 모듈입니다. 실행시 TrayIcon에 서버 실행이 활성된 Icon이 생성되고 사용자가 웹서버의 Root 폴더 지정 및 현재 서버의 상태를 확인 할 수 있습니다.(귀찮아서 할 수 있는게 많은데 여기까지 밖에 못했네요)



트레이 아이콘, Server 의 상징인 'G' 모양이 아이콘이 생성되었음을 확인 할 수 있습니다. ^^



서버 설정화면, Http File Server 운용을 위한 root dir 설정 및 서버의 로그, 순간 접속량 등을 확인 할 수 있습니다. 


아래의 파일은 UI 및 일부 Gdp를 포함하는 샐행파일이 포함된 Jar 파일입니다. (실행은 콘솔에서 java -jar  cKserver.jar 이며, 반드시 동일 폴더에 org.ygsoft.webserver.core_20100102.jar 파일이 같이 있어야만 동작합니다.)



Gdplet 테스트를 위해 UI 및 Demo gdp 가 포함된 Eclipse Project도 첨부합니다. 관심있으신 분들은 아주 적절하게 필요한 서비스를 확장하여 사용할 수 있으리라 확신합니다. (Gdplet 개발시 공유해 주시면 감사 ^^)



해당 프로젝트 내에서 Client에서 WebServer로 파일을 전송하는 gdp 예제도 포함되어 있습니다.  



아래의 웹페이지에 파일 전송시 서버 실행을 하였던 jar 파일이 포함된 폴더내에 download 폴더가 생성 파일이 저장되는 구조입니다. 원격지에서 집 Server에 파일 전송이 가능하죠. 본 예제를 참고, gdp를 확장하여 다양한 형태의 데이터 송수신 서비스를 구현 할 수 있을 거라 생각됩니다.


다음 버전에는 아래의 기능들을 추가해 볼까합니다.

- Session을 추가하여 간단한 사용자 인증 구현 (Open API 제공)

- Reflection을 활용하여 Service를 추가하는 기능

- GUI 개선

- GDP 예제 : 웹기반 파일 탐색기, CCTV, 원격제어 



어디까지나 취미생활 인지라 다음이 언제가 될 지는 모르겠네요..ㅋㅋ 

김영곤 (mailto:gonni21c@gmail.com)


+ Recent posts