논문을 완성한 지금 오래전 부터 꿈뀌오던 세벌식으로 바꾸기 프로젝트를 시작했다. 이 글도 삼천빡을 하는 심정으로 힘들게 쓰고 있다. 이제 삼일차. 차라리 이제는 완전히 두벌식을 잊고 싶다. 평생 키보드를 두드려야 하는 운명, 입사하기 전 지금이 마지막 기회다. 미련해 보이더라도 노력하면 된다는 걸 스스로 증명해 보자!

세벌식 쓰시는 분들 정말 좋은가요?

리눅스로 재부팅을 하던 중 컴퓨터가 멈췄다. 컴퓨터를 아예 껐다가 다시 켜니 CPU의 온도가 너무 높다고 투덜대면서 부팅이 안되는 것이 아닌가! 바이오스에 들어가 확인해보니 CPU의 온도는 놀랍게도 92도였다. 요즘들어 컴퓨터가 버벅댄다는 느낌을 많이 받았는데, 100도에 육박하는 온도에 CPU는 계속 무리를 하고 있었나보다.

부팅조차 안되는 상황에서 응급조취를 하기위해 케이스를 열었다. 오래전 이 컴퓨터를 샀을 때 잘만쿨러로 바꾸면서 CPU 팬의 속도를 최저로 해놓은 것이 생각났기 때문이다. 그 당시에는 그다지 성능에 민감한 작업을 하지 않았기 때문에 조용한 것이 최고라는 생각에서 그렇게 설정했다. CPU 팬의 속도를 최고로 설정하자 2500RPM으로 동작하며 온도가 68도로 안정이 되었다.

3기가 CPU에 메모리 2기가를 장착한 컴퓨터 치고는 너무 느리다는 생각이 든다. 분명 나의 무관심이 한 몫 했으리라. 내가 부품을 고르고 내 돈으로 부품을 사서 내 손으로 조립한 컴퓨터라면 이 지경에 이르기까지 방치했을까?  오히려  훌륭한 하드웨어의 존재가 세심한 관리 없이 컴퓨터를 대충대충 사용하게 만들었다. 2년에 이르는 지금까지 남이 설치해준 윈도우를 그대로 사용하고 있으니 그 속이 적잖이 꼬여있을 것이다. 그 사이 수없이 깔고 지웠던 프로그램들이 각자의 자취를 무수히 남겼을테니.

석사과정이 얼마남지 않은 지금 윈도우를 다시 설치한다는 것은 좋은 생각은 아닌 것 같다. 신해철의 '절망에 관하여'의 한 소절 처럼 ... 그냥 가보는거야. 그냥 가보는거야.

또 다시 지름신의 강림인가! 웹서핑을 하다가 우연히 해피해킹 키보드가 국내 정식 출시되었다는 소식을 듣게 되었다. 기존의 30만원을 넘던 가격이 20만 9천원으로 착해졌다는 점이 나를 솔깃하게 만든다. 어차피 평생 키보드를 두들기고 살아야할 운명, '가장 손에 많이 닿는 키보드를 가장 좋은 것으로 하는 것은 사치가 아니다'라고 지름신의 정언명령(?)이 나에게 지름을 강요하고 있다. 회사에 들어가면 나를 위한 투자의 일안으로 구입하게 될 것 같지만 그 때까지 참을 수 있을까? 옆방 선애누나의 HHK를 가끔 두들겨보며 아쉬움을 달래볼까? 내가 생각하는 이 키보드의 장점은 특정 운영체제에 의존적이지 않고, 공간을 적게 차지 한다는 것. 선애누나가 극찬하는 키감 역시 기대된다.

오전에 석사논문의 Abstract를 쓰고 교수님께 제출한 후 마음이 홀가분해져서 반나절만 낭비(?)해서 평소 해보고 싶었던 일을 하기로 했다. 쓸데없는 호기심에 이끌려 3시간을 삽질끝에 원하던 바를 이루었다. 바로 그림에 보이는 것과 같은 화려한 UI를 내 눈으로 직접 확인해볼 수 있었던 것!

윈도우 Vista의 Aero Glass가 화려한 UI를 제공한다고 하나 CPU 3기가에, 메모리 2기가를 자랑하는 나의 컴퓨터도 그래픽카드의 성능이 딸리는 관계로 화려한 UI를 보여주지 못했다. 반면 Ubuntu Edge Eft를 사용한 Beryl은 비교적 가벼왔다. Aero Glass 기능을 제외한 비스타는 평범한 화면에서도 버벅댔으니.

설치는 매우 간단하다. Ubuntu Edgy Eft + Xgl + Beryl 조합으로 다음문서를 참조하면 쉽게 따라할 수 있다. 요즘은 문서화가 워낙 잘 되어 있어서 리눅스의 세팅이 많이 편해졌다. 재력가(?) 전폭적인 지원으로 날이갈 수록 데스탑 리눅스로 발전해가고 있는 우분투 리눅스로 인해 많은 사람들이 리눅스를 접하게 되기를 기대해본다.

Beryl을 사용한 리눅스의 화려함을 맛보고 싶으시면 다음 동영상을 감상해보세요.
http://www.youtube.com/watch?v=i0ZtcxHUSDQ
요즘 하는 일은 하드웨어 디버깅. 학부 2학년때 논리회로 수업을 지지리도 싫어했었는데 먼 훗날 Verilog HDL 코드를 작성하게 될 줄이야 꿈앤들 알았겠는가. VICODE에서 하드웨어와 소프트웨어를 연결하기 위해서 필요한 인터페이스는 3가지 파트로 이루어져있는데 제대로 동작안하면 대체 어떤 부분에 문제가 있는지 파악할 수 없다는 사실이 나를 슬프게 한다. 그래도 죽으라는 법은 없는지 어제 밤 겨우 Verilog HDL코드에 문제가 있다는 것을 알아낼 수 있었다.


그리하여 오늘의 미션은 Verilog HDL 코드에서 오류를 찾아내는 것! 코드를 고치고, 컴파일 하고, FPGA에 프로그램하고, 임베디드 리눅스에 연결한 터미널로 소프트웨어를 실행하고, FPGA 보드위에 LED의 불빛을 애처로운 눈빛으로 바라보기를 수십번 반복해야만 했다. (하드웨어의 반응을 확인하는 뾰족한 수가 없다.) 종국에는 속에 천불이라는 요즘 잘 나가는 술집이름이 생각났다.

소프트웨어를 디버깅 할 때 마다 언제나 컴퓨터는 정직하여 나를 배신하지 않았다. 모든 버그는 나의 잘못이였다. 그러나 나는 하드웨어를 불신하기 시작했다. '하드웨어는 소프트웨어와 달라', '회로에 이상이 있을꺼야', 'Verilog 컴파일러에 문제가 있을지도?'

내가 이렇게 생각하게 된 이유는 논리적으로 따져보았을 때 전혀 말도 안되는 상황이 자꾸 연출되었기 때문이다. 이를테면 같은 코드인데 순서를 바꿨을 때 동작이 다르다. 속에 천불을 내고 있다가 우연히 발견한 것은 연결하지 않은 시그널이 있을 때 이상한 동작을 보인다는 점. 자세히 알아보니 연결되지 않은 회로가 있는 경우에 오동작할 가능성이 있었다. 선무당이 사람 잡는다고 하드웨어는 문외한이라 소프트웨어의 변수처럼 선언하고 안써도 그만이라고 생각했던 것이다.

상처난 회로를 정성스럽게 어루만지며 오늘도 나는 간다.
내가 파이어폭스를 쓰기 시작한 이유는 단순했다. 컴퓨터를 전공하는 사람으로서 시대의 조류(?)를 무시할 수 없었고, (각종 리눅스 배포판이 발표될때 마다 설치하게 만드는) 호기심 덕분에 사용하기 시작했는데, 그러한 심리적인 이유 이외에도 표준을 지키고, 기능확장이 가능하고, 테마를 적용할 수 있고, 탭브라우징이 가능하다는점 등의 기능적인 장점도 상당했다.

사실 그동안은 Add-on에 대해 별로 관심이 없었는데, 최근에 필요한 기능을 찾아보다가 우연히 All-in-One Gestures를 발견하게 되었다. 'All-in-One Gestures 때문에 파이어폭스를 쓴다' 라고 하는 어떤 블로그의 글을 읽고 호기심이 발동했던 것. 사용해본 소감은 억수로 유용하다! (이미 많은 파이어폭스 유저가 이것을 사용하고 있다.)


All-in-One Gestures의 설정화면이다. 오른쪽 동작컬럼에 보이는 것 처럼 마우스 오른쪽 버튼을 누르고 마우스를 움직이면 왼쪽 기능컬럼에 적혀있는 일들이 수행된다. 나는 탭 닫기만 '아래'로 수정해서 총 4가지 동작을 활용하고 있다. 다른 기능까지 활용하려면 좀 더 익숙해져야겠다.

- 새 탭을 열기
아래 - 현재 탭을 닫기
위, 왼쪽 (혹은 오른쪽) - 이전 탭(혹은 다음 탭)
왼쪽 (혹은 오른쪽) - 탐색 기록 뒤로 (혹은 앞으로)

한동안 웹질에 빠져있다가 문득 '내가 뭔 쓸데없는 짓을 하고 있지?' 라는 생각이 들면 간단히 마우스 오른버튼을 살포시 누른체 밑으로 한번 긁어주자.

문서를 읽을 때면 (정신을 산만하게 하는) 컴퓨터는 딱 꺼놓고 집중하고 싶지만, 모르는 영어단어를 만날 때 마다 영어사전을 펼치기는 너무나 번거롭다. 그래서 네이버 영어사전을 즐겨사용하는데 이를 모니터에 열어두면 Flash 영상이 정신없이 번쩍이며 집중을 방해한다. 그리하여 찾게 된 파이어폭스 Add-on은 바로 Flashblock. 기능은 매우 간단하다. Flash 부분을 위 처럼 안보이게 해주고 마우스를 가져가서 클릭하면 보이게 할 수 있다. 역시 여타 다른 Add-on 처럼 특정 사이트를 예외처리할 수 있다.  

워낙 깔끔떠는 성격이라서 그런지 몰라도 나는 간결한(?) 형태를 좋아하는 편이다. 컴퓨터에 운영체제를 두개 깔아쓰기 보다는 깔끔하게 하나를 사용하는것을 좋아하고 웹브라우저도 하나만 사용하기를 희망한다. 여러가지 측면에서 웹표준을 지키고 가벼우며 탭브라우징 기능을 제공하는 파이어폭스가 마음에 들었으나 몇몇 몰지각한(?) 국내 사이트들이 웹표준을 지키지 않거나 ActiveX를 사용하는 관계로 익스플로어를 사용할 수 밖에 없을 경우가 빈번하다. 그리하여 어쩔 수 없이 두개를 번갈아 가며 사용하다가 한동안 익스플로어만 사용했는데 영 마뜩치가 않았다.


이런 와중에 우연히 IE View라는 Add-on을 발견하게 되어 설치해보았는데 이는 파이어폭스에서 익스플로러를 따로 실행해주는 기능을 제공하고 있으나 탭브라우징의 극대화 측면에서는 영 마뜩치 않은 방법! 그리하여 찾게 된 것이 바로 IE Tab이라는 Add-on인데 이는 위의 화면처럼 파이어폭스의 탭안에 익스플로러를 로딩해준다. 그림처럼 도구모음에 버튼을 추가해서 사용할 수도 있고 마우스 오른쪽 버튼을 눌렀을 때 나오는 메뉴를 이용해 파이어폭스와 익스플로러를 오갈 수 있다.


익스플로러를 이용해야 원활히 보이는 사이트를 방문할 때 마다 매번 도구모음의 아이콘을 클릭할 수는 없다. 그래서 등록된 사이트에 접근할 때 마다 자동으로 탭안에 익스플로러를 로딩하도록 세팅이 가능하다. IE Tab을 설치하면 도구 > IE Tab 설정 이라는 메뉴를 볼 수 있는데 이를 클릭하면 위와 같은 설정화면에서 특정 사이트를 등록할 수 있다. 이제 단 하나의 파이어폭스 윈도우만으로 웹브라우징을 할 수 있게 되었으나 익스플로러의 새버전이 나오면 무엇을 선택하게 될까?

이클립스 워크벤치에서 perspective라고 하는 것은 툴바와 메뉴에 위치하게될 action들의 사용여부와 view의 초기 레이아웃을 정의하는 역할을 담당한다. 아래의 그림의 우측상단에 VICODE라고 선택되어 있는 부분이 바로 perspective를 의미한다.


이클립스에 기본적으로 제공되는 perspective가 몇가지 있다. Java를 선택하면 자바 어플리케이션을 개발하는데 필요한 action이 메뉴와 툴바에 나타날 것이고, Debug를 선택하면 디버깅을 위한 view들이 화면에 배치되는 것을 확인할 수 있다.

따라서 특정 목적(VICODE의 경우 임베디드 시스템 개발)을 가지는 개발환경을 이클립스에서 구현한다면, 이에 해당하는 action들만을 메뉴나 툴바에 나타내고 특정 정보를 화면에 보여주기 위한 view를 원하는 레이아웃에 따라 배치하고 싶을 것이다.

VICODE perspective를 선택했을 때를 살펴보면, Project 메뉴 아래에 필자가 여기저기서 주워와서 갔다 붙인 조악한 툴바 아이콘을 볼 수 있고 화면의 하단에는 따로 만들어서 추가한 Log, Result view가 존재하는 것을 알 수 있다. 이와 같이 perspective는 플러그인이 제공하는 특정 개발 환경을 정의하는 역할을 한다.

개념의 대한 설명은 여기서 마치고 구현방법을 소개하자면,
다음과 같이 org.eclipse.ui.perspectives 확장점을 이용한다.  

  <!-- VICODE Perspective -->
  <extension
        point="org.eclipse.ui.perspectives">
     <perspective
           class="edu.kaist.vicode.perspective.PerspectiveFactory"
           fixed="true"
           icon="icons/jdg2eProd.gif"
           id="edu.kaist.vicode.perspective"
           name="VICODE"/>
  </extension>

PerspectiveFactory.java의 내용은 다음과 같다.

package edu.kaist.vicode.perspective;import org.eclipse.ui.IFolderLayout;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;
public class PerspectiveFactory implements IPerspectiveFactory {
public static final String ID_VICODE_ACTIONS = "edu.kaist.vicode.actionset";
public static final String ID_VICODE_PROJECT_WIZARD =
  "edu.kaist.vicode.projectwizard";
public static final String ID_VICODE_MODULE_WIZARD =
  "edu.kaist.vicode.modulewizard";
public static final String ID_VICODE_LOG_VIEW = "edu.kaist.vicode.logview";
public static final String ID_VICODE_RESULT_VIEW = "edu.kaist.vicode.resultview";

public void createInitialLayout(IPageLayout layout) {
// Navigator
layout.addView(IPageLayout.ID_RES_NAV, IPageLayout.LEFT, 0.20f,
  IPageLayout.ID_EDITOR_AREA);
// Bottom : Another folder area, to stack additional views
IFolderLayout bottom = layout.createFolder("bottom",
  IPageLayout.BOTTOM, 0.8f, IPageLayout.ID_EDITOR_AREA);
bottom.addView(ID_VICODE_LOG_VIEW);
bottom.addView(ID_VICODE_RESULT_VIEW);
bottom.addView(IPageLayout.ID_PROBLEM_VIEW);

// Add Outline View
layout.addView(IPageLayout.ID_OUTLINE, IPageLayout.RIGHT, 0.80f,
IPageLayout.ID_EDITOR_AREA);
   
// Add new wizard shortcut
layout.addNewWizardShortcut(ID_VICODE_PROJECT_WIZARD);
layout.addNewWizardShortcut(ID_VICODE_MODULE_WIZARD);

// Add our actions
layout.addActionSet(ID_VICODE_ACTIONS);
}
}

위의 VICODE perspective가 선택된 화면과 소스코드를 비교해보면 이해하기가 수월 할 것이다. createInitialLayout() 메서드에서 넘어온 IPageLayout 인스턴스를 이용하여 레이아웃을 지정할 수 있다. 차례로 왼쪽의 Navigator를 추가하고 하단에 3개의 view를 추가한다. 그리고 우측의 Outline view를 정의한 후 추후에 다루게 될 마법사를 추가한다. 마지막으로 action에서 다루었던 action set을 추가한다. action set의 visible 속성이 false로 지정되었다면 이렇게 perspective에서 추가해주어야만 화면에 나타나게된다. 모든 것의 참조는 plugin.xml에서 정의한 ID로 이루어진다.

물론 이미 존재하는 perspective에 자신의 view나 action을 추가할 수 있는데 (JDT를 확장하는 경우) 이럴 때는 org.eclipse.ui.perspectiveExtensions 확장점을 이용해야 한다.

다른 사람의 블로그를 구경하다가 깜짝 놀랐다. 구글 노트북?  차분히 글을 읽어보니 구글랩에서 새롭게 개발한 웹페이지 스크랩을 위한 서비스의 이름이였다. 구글의 직원들에게는 자신이 맡고 있는 일 이외에 새로운 아이디어로 하고 싶은 일을 도전해볼 수 있는 시간이 주어진다고 하는데, 이렇게 시도되는 여러가지 서비스가 우리를 즐겁게 하고 있다.


웹서핑을 하다보면 두고두고 다시 읽고 싶은 좋은 글들을 만날 때가 많은데 막상 이를 어떻게 보관해야할지 막막하다. 지금까지는 네이버 블로그에 저장해두었는데 이제는 해당내용을 긁고 오른버튼 눌러서 나오는 Note this 버튼을 누르는 것으로 간단히 보관할 수 있게 되었다.

익스플로어나 불여우에 플러그인 형태로 설치되며 사용법은 매우 간단하다. 처음 플러그인을 설치하면 스크랩 방법과 열람하는 방법을 간단히 설명해준다. 구글 UI의 매력은 무엇보다도 단순함과 실용성에 있다는 것을 다시 한번 느끼끼게 해주었다. 웹서핑 중 만나는 간간히 보관하고 싶은 문서가 있는 분들은 도전해보시길.

http://www.google.com/notebook/

Plug-in Development Environment(이하 PDE)는 그 자신이 플러그인이면서 플러그인을 개발하는 환경을 제공한다. 우리가 일반적으로 다운받는 Eclipse SDK에 기본적으로 포함되어 있다. 이는 플러그인 개발의 편의를 도모하기 위해 플러그인의 정보를 담고 있는 plugin.xml을 효과적으로 편집할 수 있는 플러그인 설명서 편집기와 개발 중인 플러그인를 실행하고 디버깅할 수 있는 환경을 제공한다.


위의 그림은 여러 페이지로 구성되어 있는 플러그인 설명서 편집기이며 plugin.xml 파일을 쉽게 편집할 수 있도록 도와주는 역할을 한다. 이클립스 3.0에서 개발을 시작하였고 현재는 3.2 버전을 사용하고 있는데 플러그인의 구조가 적잖이 변경되었다. 이전에는 대부분의 정보가 plugin.xml에 저장되었던 것에 반하여 3.2 버전에서는 일부정보가 MANIFEST.MF 파일에 저장된다. 따라서 3.2 버전에서의 plugin.xml은 확장점과 확장에 관한 내용만 담고 있다.

각각의 페이지에 대해서 간략히 설명하자면,

Overview - 플러그인의 ID, 이름, 버전, 제작자등의 정보
Dependencies - 플러그인이 의존하고 있는 다른 플러그인의 집합
Runtime - 런타임에 client에게 export할 package의 집합
Extenstion - 확장정의
Extension Points - 확장점정의
Build - 빌드할때 포함해야할 파일등 플러그인 빌드 관련 설정
MANIFEST.MF - MANIFEST.MF 파일 텍스트 편집기
plugin.xml - plugin.xml 파일 텍스트 편집기
build.properties - build.properties 파일 텍스트 편집기  

정리하자면,

Overview, Dependencies, Runtime 페이지를 수정하면 MANIFEST.MF 파일이, Extenstion, Extenstion Points 페이지를 수정하면 plugin.xml 파일이, Build 페이지를 수정하면 build.properties 파일이 수정된다. 텍스트 편집기에서 파일을 직접 수정한 내용도 각 페이지의 폼에 바로 적용되어 상호보완적으로 편집할 수 있다.

플러그인의 실행을 이해하기 위해서는 host 워크벤치와 runtime 워크벤치의 개념을 이해해야한다. 먼저 host 워크벤치는 현재 PDE를 이용해 플러그인을 개발하고 있는 워크벤치를 의미한다. host 워크벤치에서 개발 중인 플러그인의 Run을 구성해 실행시키면 쉽게 말해서 이클립스가 하나 더 뜬다! 이 것이 바로 runtime 워크벤치다.


위의 그림에서는 PDE에서 vicode 플러그인의 Run을 구성하고 있다. 여기서 Plug-ins 탭으로 들어가보면 host 워크벤치와 runtime 워크벤치의 개념을 이해할 수 있다. 여기서 선택된 것은 runtime 워크벤치를 실행할 때 포함하는 플러그인을 의미한다. 다시 말하면 runtime 워크벤치는 host 워크벤치에 포함된 플러그인에 더하여 현재 개발 중인 플러그인을 추가한 워크벤치를 의미한다. (물론 개발하는 플러그인과 의존관계가 없는 플러그인은 제외하고 수행해도 무방하다)  

개념을 잡는 것에 도움을 드리기 위해 씌여지고 있는 글이기 때문에 실제 PDE를 사용하는 예제를 수행해보고 싶으신 분은 이클립스 메뉴의 Help > Help Contents를 클릭하시고 나오는 메뉴얼에서 Platform Plug-in Developer Guide > Simple plug-in example을 참조하시기 바랍니다.
플러그인이란 무엇인가? 이클립스에 어떤 기능을 제공하기 위한 것들의 집합이다. 기능을 제공하기 위해서 필요한 것에는 무엇이 있는가? 예를 들어 선택된 파일을 리눅스 콘솔에서 실행하는 기능을 제공한다고 가정하자. 이 때 필요한 것은 이클립스의 어떤 부분(확장점)을 통해 이 기능을 제공할 것인지에 대한 정보(파일을 선택하고 오른쪽 버튼을 눌렀을 때 나오는 팝업메뉴에서? 혹은 파일을 선택하고 툴바의 버튼을 눌러서?)와 이 기능의 이름이 화면에 어떻게 표시 될 것인지, 툴바에 버튼이 추가 된다면 icon 파일은 무엇을 사용할 것인지 등의 정보가 필요할 것 이다. 가장 중요한 것은 메뉴선택이나 툴바버튼이 눌렸을 때 수행되는 일이 무엇인지를 정의하는 것이다.

정리하자면, 이클립스에 기능을 제공하기 위한 플러그인이 가져야 할 정보는 텍스트 데이터와 자바 코드로 나누어 볼 수 있다. 우리는 이 사실로 부터 플러그인의 구조를 유추할 수 있다. 하나의 플러그인 프로젝트는 텍스트 데이터를 담고 있는 plugin.xml 파일과 자바소스코드들로 구성되어 있다. 다음의 다이어그램을 보고 좀 더 상세히 살펴보자.


왼쪽은 이클립스 워크벤치에 해당하는, 즉 이클립스 플랫폼에 기본적으로 포함되어 동작하는 플러그인이며 오른쪽은 우리가 개발하고 있는 플러그인 이라고 하자. 왼쪽의 플러그인은 다른 플러그인이 자신의 기능을 확장할 것을 고려하여 확장점(extenstion-point)를 plugin.xml에 정의하고 있다. 오른쪽의 플러그인은 이 확장점(popupMenus)을 이용하여 확장(extension)하고 있다. 쉽게 이야기 하면 왼쪽의 플러그인은 다른 플러그를 꽂을 수 있는 콘센트를 제공하고, 오른쪽 플러그인은 그 콘센트에 꽂을 수 있는 플러그가 되는 것이다!

확장을 할 때 필요한 정적인 정보는 오른쪽 플러그인의 plugin.xml 파일의 extenstion태그 아래 기술 될 것이며 팝업메뉴가 클릭되었을 때의 동작은 MyObjectAction 클래스에 정의한다. 확장점을 열어주는 입장(Workbench plug-in)에서는 확장하는 방법을 제공해주어야 한다. 즉 확장하는 플러그인(MyAction plug-in)에서 아무렇게나 MyObjectAction 클래스를 정의한다면 제대로 확장이 이루어질 수 없다. 확장점을  열어주는 플러그인에서는 IOjbectActionDelegate 인터페이스를 제공함으로써 확장하는 클래스가 이를 구현하여 자신에게 필요한 코드를 정의하도록 유도한다.

확장점을 열어준 플러그인은 자신을 확장한 플러그인에 대해서 처리해야할 책임을 갖는다. 현재 자신이 제작하고 있는 플러그인에서도 확장점을 얼마든지 정의할 수 있고 이를 다른 사람 혹은 자신이 제작하는 또 다른 플러그인에서 확장이 가능하다. 필자의 경우에는 다른 플러그인이 VICODE를 확장할 가능성을 염두해 두지 않았기 때문에 이클립스 워크벤치가 제공하는 기본 확장점을 이용하고 따로 확장점을 정의해본 경험이 없다.

     <extension
        point="org.eclipse.ui.popupMenus">
     <objectContribution
           adaptable="false"
           id="edu.kaist.vicode.consoleContribution"
           nameFilter="*.console"
           objectClass="org.eclipse.core.resources.IFile">
        <action
              class="edu.kaist.vicode.actions.RunConsoleProgramAction"
              enablesFor="1"
              icon="icons/exec_obj.gif"
              id="edu.kaist.vicode.actions.esterelSimulation"
              label="Run Console Program"/>
     </objectContribution>

위의 예제는 실제 VICODE에서 확장자가 *.console인 파일을 선택하고 오른쪽 버튼을 눌렀을 때 나타나는 팝업메뉴에서 리눅스 console 프로그램을 수행하는 기능을 제공하기 위한 것이다. 자세한 내용은 나중에 팝업메뉴 확장하기에 대한 글에서 다루도록 하고 여기서는 확장점과 확장의 관점에서 살펴본다.

이 플러그인은 org.eclipse.ui.popupMenus 라는 확장점에 확장하고 있다. 이 확장점이 필요로 하는 정보가 obejctContribution 태그 아래로 정의되어 있는 것을 볼 수 있다. 정적인 정보는 이렇게 plugin.xml에 정의되고 behavior에 해당하는 내용은 확장점이 기대하는 behavior를 정의한 IOjbectActionDelegate 인터페이스를 구현한 RunConsoleProgramAction 클래스에 정의된다.

이클립스 플랫폼이 구동될 때 플러그인의 정적인 정보를 담고 있는 plugin.xml 파일을 읽어 확장점과 확장의 관계를 고려하여 화면의 UI를 구성한다. 그리고 효율성을 위해 자바 클래스는 그 것이 필요한 시점, 즉 action이라면 메뉴가 클릭되었을 때 객체가 생성되어 수행된다.

이클립스(Eclipse)는 많은 사람들에게 흔히 꽤나 훌륭한 자바개발환경으로 널리 알려져있다. 그러나 이클립스를 자바개발환경으로만 생각한다면 이클립스의 잠재력을 무시하는 일! 다음 이클립스 Help에 있는 이클립스의 정의를 읽어보자.

Eclipse is a platform that has been designed from the ground up for building integrated web and application development tooling. By design, the platform does not provide a great deal of end user functionality by itself. The value of the platform is what it encourages: rapid development of integrated features based on a plug-in model.

여기서 중요한 것은 이클립스 그 자체로 사용자에게 기능을 제공하는 것이 아니며 기능적인 요소는 플러그인으로 제공된다는 사실! 애초에 이클립스는 plug-in model을 기반으로 하는 개방성을 목표로 개발되었다. 다음 다이어그램을 참조하면 이 사실은 더욱 명확해진다.


이클립스 플랫폼 자체는 자바 개발환경(JDT)와 플러그인 개발환경(PDE)를 포함하지 않는다. 다시 말하면 자바 개발환경 조차도 이클립스 플랫폼에 확장되는 플러그인 중에 하나 일 뿐이다. 다만 우리가 일반적으로 이클립스를 다운받을 때 Eclipse SDK의 형태로 가져오기 때문에 이클립스가 마치 자바개발환경인 것 처럼 보일 뿐이다. eclipse가 설치된 디렉토리 밑에 plugins 디렉토리를 열어보면 org.eclipse.jdt.* 형태의 이름을 가지는 파일과 디렉토리를 통해 JDT가 플러그인임을 확인할 수 있다. 필자가 개발하고 있는 VICODE는 오른쪽의 New Tool 중에 하나에 해당할 것 이다.

이미 매우 다양한 플러그인들이 개발되어 있다. 여기를 방문하면 다운받아 사용해볼 수 있다. 이클립스에서 데이타베이스 스키마 디자인을 하거나 UML 다이어그램을 그리는 작업등이 이클립스 플랫폼에 플러그인을 추가함으로써 가능해진다.  

Platform Runtime은 이클립스 플랫폼의 핵심으로 앞서 이야기한 plug-in model을 책임지는 역할을 한다. 이클립스가 시작될때 현재 플랫폼에 어떤 플러그인이 기여되어있는지를 확인하고 그 정보를 바탕으로 현재의 이클립스 플랫폼을 구성한다. 플러그인이 어떤 방법으로 이클립스 플랫폼에 확장(Extension)되는지는 "확장점과 확장"이라는 제목의 글에서 다룰 예정이다.

현재 저는 연구실 프로젝트 겸 석사학위를 위하여 Verification Integrated CODesign Environment(이하 VICODE)라고 하는 하드웨어/소프트웨어 동시설계 개발환경을 이클립스 플러그인 형태로 개발하고 있습니다. 블로그에서 제가 쓰고자 하는 글은 이클립스 플랫폼을 기반으로 하는 통합개발환경(IDE)를 구축하는 방법에 관한 것 입니다. 따라서 동시설계에 관련된 내용이나 이 툴이 제공하는 기능의 상세 대해서는 생략하겠습니다만, 간략히 하드웨어와 소프트웨어가 모두 존재하는 시스템을 설계하는 도구정도로 생각할 수 있습니다.

올해 초 swing으로 작성하던 어플리케이션을 갑자기 이클립스 기반으로 다시 개발해야 했을 때, 많이 난감했던 기억이 납니다. 이클립스 플러그인 개발에 대한 국내서적은 거의 없었고 번역서 조차도 찾기 어려웠습니다. 물론 몇몇 분들이 쓰신 이클립스 강좌가 있었지만 IDE를 개발하기에는 부족했습니다. 다행히 "자바 개발자를 위한 이클립스 바이블"이라는 책이 출판되었고 이 책을 차근차근 공부하면서 이클립스와 친해질 수 있었지만 책의 구성 탓인지 번역 탓인지 모르겠지만 잘 읽히지가 않아서 인내를 배워야 했습니다.

다른 일에 집중하다가 오랜만에 다시 제가 개발한 플러그인을 뜯어 보았을 때, 잊은 부분이 적지 않았고 제가 개발한 플러그인을 이어서 개발할 후임자를 위해서도 정리가 필요하다고 생각되었습니다. 또한 제가 정리한 글들이 이클립스 플러그인 개발을 처음으로 접하는 분들의 삽질을 조금이라도 줄여드릴 수 있다면 큰 보람이 될 것 입니다.

다른 사람을 가르치면서 배우는 것이 많다는 이야기가 있듯이 그동안 공부한 지식들을 정리 및 공개하여 많은 분들의 피드백을 받으며 제가 공부한 지식을 더욱 굳건히 하고자 하는 욕심도 있습니다. 틀린 부분이나 보충할 부분이 있으면 가감없이 덧글로 남겨주시면 큰 도움이 될 것 같습니다. 질문도 주저없이 덧글로 남겨주시면 제가 모르는 것은 공부해서라도 답변할 수 있도록 노력할 것 입니다.

블로그에서 제가 다룰 것으로 예상되는 부분은 다음과 같습니다. 개발을 진행하면서 틈틈히 쓰는 글이라 예정된 순서가 없고 중간에 필요하다고 생각되는 부분은 추가될 수도 있습니다. 제가 아는 바를 모두 정리한 후 적었던 글들을 체계적으로 정리할 생각입니다.


제가 쓰는 글들이 강좌라고 할 것 까지는 없지만, 인터넷의 강좌나 마소의 기사를 보면 반말(?)을 사용하는 경우가 많아서 저도 글쓰기의 편의를 위해서 반말로 글을 작성하고자 합니다. 플러그인 개발에 대한 글들은 제가 다음의 책들을 공부한 결과를 기반으로 하고 있기에 참조하시면 도움이 될 것 같습니다.

자바 개발자를 위한 이클립스 바이블
Official eclipse 3.0 FAQs
The Definitive Guide to SWT and JFace

Eclipse 플러그인 개발에서 action이라고 하는 것을 간단히 정의하자면 메뉴나 툴바의 아이콘을 클릭하였을 때 수행되는 어떤 일이라고 이야기 할 수 있다. IDE에서 소스를 편집하는 editor 혹은 무언가 정보를 보여주는 viewer를 제외하면 대부분의 기능이 바로 action의 형태로 기여된다고 할 수 있다.

action에 대해서 공부하기 이전에 알아야 할 것이 있는데 action set 이라고 하는 녀석이다. 이는 menu와 action으로 구성되어 있는 action을 정의하기 위한 논리적인 집합이라고 생각하면 되는데 일단 다음의 plugin.xml의 일부를 읽어보자.

<!-- Action Definition -->
  <extension
        point="org.eclipse.ui.actionSets">
        <actionSet
              id="edu.kaist.vicode.actionset"
              label="Co-Design Actions"
              visible="false">
           <menu
                 id="edu.kaist.vicode.interfacemenu"
                 label="Interface">
              <separator name="actionGroup"/>
           </menu>
            <menu
                 id="edu.kaist.vicode.verificationmenu"
                 label="Verification">
              <separator name="actionGroup"/>
           </menu> 
            <!--  Generate Interface for Simulation -->
           <action
                 class="edu.kaist.vicode.actions.SimulationInterfaceGenAction"
                 disabledIcon="icons/config-linker.gif"
                 enablesFor="1"
                 hoverIcon="icons/config-linker.gif"
                 icon="icons/config-linker.gif"
                 id="edu.kaist.vicode.actions.simulationinterfacegen"
                 label="Generate Interface for Simulation"
                 menubarPath="edu.kaist.vicode.interfacemenu/actionGroup"
                 style="push"
                 toolbarPath="edu.kaist.vicode.interfacemenu"
                 tooltip="Generate Interface for Simulation">
              <!-- Project에 대해서만 적용가능한 Action -->
              <selection class="org.eclipse.core.resources.IProject"/>
           </action>

action에 대한 기여는 action 기여를 위한 확장점(extenstion point)이 있어서 여기에 바로 기여(extenstion)하는 것이 아니라 그 것을 둘러싼 action set에 해당하는 확장점(org.eclipse.ui.actionSets)에 기여 함으로써 이루어진다.

menu는 action의 분류를 제공한다. 아래에 정의되어 있는 각 action들이 UI에 나타나려면 적어도 하나 이상의 menu를 지정해야한다. 위의 플러그인을 수행하면 "Interface"와 "Verification"이라는 최상위 메뉴가 (실제로 그 메뉴에 기여하는 action이 존재하는 경우) 메뉴바에 나타난다. menu의 정의는 메뉴바뿐만 아니라 툴바의 분류가 되기도 하며 어떻게 사용되는지는 action 태그의 menubarPathtoolbarPath에 달려있다.

메뉴는 하나 이상의 separator를 가진다. 쉽게 설명하자면 인터넷 익스플로러에 파일 메뉴를 클릭하면 4가지 그룹의 메뉴가 나타나는 것을 볼 수 있으며 이는 4개의 separator를 하나의 menu 태그에서 정의하는 것으로 구현될 수 있다. 그리고 각각의 action은 그들이 속해야 하는 menubarPath = "menu의 id/separator의 name" 형태로 자신이 UI의 어디에 나타나야 하는지를 지정할 수 있다. 툴바에 기여하는 경우에는 separator를 지정할 필요가 없다.

여기서 action set의 중요한 속성을 하나 살펴보자. Eclipse 플랫폼은 다수의 플러그인을 포함하여 동작하고 있다. 모든 플러그인이 제공하는 action과 menu가 UI에 모두 나타난다고 상상해보면 어떨까?

나중에 perspective에 대한 글에서 자세히 설명하겠지만, 이와 같은 문제를 해결하기 위해서 플러그인이 제공하는 환경과 기능을 관리할 수 있는 perspective라는 개념을 도입하였다. Eclipse 플랫폼에 기본적으로 포함되어 있는 perspective에는 Java, Debug, Resource등이 있다. Java라는 perspective를 선택하면 자바프로그램을 편집하는데 필요한 에디터와 뷰어 그리고 툴바의 아이콘등이 나타나는 것을 알 수 있다. Java와 Resource perspective를 변경하면서 툴바를 살펴보면 그 차이를 알 수 있을 것이다.

action set에서 visible 속성을 이용하여 action set에 포함되는 menu와 action들이 perspective와 상관없이 무조건 UI에 나타날 것인지 아닌지를 true, false로 지정할 수 있다. 다시 말하면 이 값이 true인 경우 항상 action set에 포함되는 것들이 UI에 표현되고, false인 경우에는 특정 perspective에 action set을 포함시켜 그 perspective로 전환되었을 때만 UI에 표현하게 한다. 자세한 내용은 perspective에 대한 글에서 다룰 생각이다.

지금까지는 action set의 구조와 메뉴(menubarPath)와 툴바(toolbarPath)에 각 action이 어떻게 추가될 수 있는지를 살펴보았다. 지금부터는 action 자체에 대해서 살펴보자. action에서 지정되는 클래스는 IWorkbenchWindowActionDelegate 인터페이스를 상속해야 한다.

public class SimulationInterfaceGenAction implements
IWorkbenchWindowActionDelegate {
private IStructuredSelection selection;

public void dispose() {
// TODO Auto-generated method stub
}
public void init(IWorkbenchWindow window) {
// TODO Auto-generated method stub
}
public void run(IAction action)
{
// TODO Auto-generated method stub
IProject project = (IProject) selection.getFirstElement();
...
...
...
}
public void selectionChanged(IAction action, ISelection selection) {
// TODO Auto-generated method stub
if (selection instanceof IStructuredSelection) {
  this.selection = (IStructuredSelection) selection;
}

}
}

action을 구현한 클래스는 위와 같은 구조를 가지게 된다. 툴바의 아이콘이나 메뉴를 클릭하면 해당 action의 run() 메서드가 호출되어 특정 작업이 수행된다. 여기서 추가로 알아야 할 것은 특정 action은 특정 selection과 관계를 맺을 수 있다는 것! 즉 action을 수행하는 대상이 무엇인지 알아야 한다. 예를 들어 JDT에서 메서드의 이름을 바꾸는 리펙토링 액션을 수행한다고 한다면 분명 선택한 메서드가 있을 것이다. 이러한 선택을 selection이라고 하며 selectionChanged() 메서드에서 이 selection을 얻어올 수 있다. 이렇게 얻어온 selection을 통해 특정 영역에 해당하는 action을 수행하게 된다.

action은 selection의 형태에 따라 enable/disable 될 수 있다. 이를테면 어떤 action은 프로젝트(IProject)만을 선택으로 받아들일 수 있고, 어떤 action은 디렉토리(IFolder)에 대해서만 작업을 수행할 수 있다.  이는 plugin.xml에서 selection 태그로 지정할 수 있다. 심지어 name 속성을 이용하면 특정 파일명에 대해서만 action을 제한할 수 있다.


여기를 방문하면 현재 자신의 컴퓨팅환경에서 Vista를 돌릴 수 있는 확인할 수 있다. 연구실에서 사용하고 있는 나의 시스템에 자부심을 가지고 있었는데 어이없게도 결과는 Minimum Pass! Vista의 GUI가 화려하기 때문인지 다른 부분은 충분하였지만 그래픽 카드에서 많은 부족함을 나타내었다. 살펴보면 CPU 파워도 그리 넉넉한 편은 아닌 것 같다.


어렸을 때 부터 항상 새로운 운영체제가 나타나면 꼭 설치를 해보아야 직성이 풀렸다. 덕분에 리눅스는 수십번도 더 깔았던 것 같다. 매우 다양한 배포판이 수시로 배포되었기 때문이다.

Window Vista RC1이 발표되었고, 여기를 방문하면 인증키를 얻을 수 있다. 현재 64비트 버젼으로 이미지 파일을 다운받고 있는데 그 용량이 3.59GB로 DVD를 이용해야한다. 과연 오늘 새로운 윈도우를 볼 수 있을것인가?

Preference는 IDE에서 흔히 볼 수 있는 환경설정을 의미한다. 우리가 어떤 특정 플러그인을 개발할 때, 그 플러그인에 특화된 환경설정이 필요한 경우가 있다. 예를 들어 설명하자면, 이전에 소개한 바 있지만 Esterel 언어는 소프트웨어 언어인 C로도 컴파일이 되고 하드웨어 언어인 Verilog로도 컴파일이 가능하다.

Preferences in Eclipse


Esterel 언어를 위한 개발환경에서 위와 같은 환경설정이 존재한다면 각 항목의 체크유무에 따라 소스코드의 컴파일시에 생성되는 아웃풋 파일의 종류를 결정할 수 있다. 이와 같은 작업을 위해서 알아야 할 확장점(Extension Point)에는 두가지가 있으며 이를 포함한 plugin.xml의 일부분의 내용은 다음과 같다.         

  <!-- vicode preference page -->
  <extension
        point="org.eclipse.ui.preferencePages">
     <page
           class="kr.ac.kaist.vicode.preference.VicodePreferencePage"
           id="kr.ac.kaist.vicode.preferencepage"
           name="VICODE"/>
  </extension>
  <!-- vicode preference initial data -->
  <extension
        point="org.eclipse.core.runtime.preferences">
     <initializer class="kr.ac.kaist.vicode.preference.Defaults"/>
  </extension>

첫번째 확장점인 org.eclipse.ui.preferencePages을 이용해 Preference page에 기여할 수 있으며, 두번째 확장점인 org.eclipse.core.runtime.preferences에서는 환경설정의 기본값을 지정할 수 있다.

우선 첫번째 확장점을 위한 클래스인 VicodePreferencePage를 살펴보자. 이 클래스는 PreferencePage를 상속하며 UI를 만드는 createContents() 메서드, Restore Defaults 버튼을 눌렀을 때 호출되는 performDefaults(), OK 버튼을 눌렀을 때 호출되는 performOk() 메서드등으로 구성되어 있다. 메서드 이름만으로 각 메서드의 역할을 알 수 있을 것이다.

다음 생성자(Constructor)와 performOk() 메서드를 통해서 환경설정을 어떻게 이용하는지 알아보자.

public VicodePreferencePage() {
super();
setPreferenceStore(Activator.getDefault().getPreferenceStore());
setDescription("Development environment settings for VICODE");
fCheckBoxes = new ArrayList<Button>();
}

public boolean performOk() {
IPreferenceStore store = getPreferenceStore();
for (int i = 0; i < fCheckBoxes.size(); i++) {
  Button button = (Button) fCheckBoxes.get(i);
  String key = (String) button.getData();
  store.setValue(key, button.getSelection());
}
return super.performOk();
}

생성자에서는 setPreferenceStore() 메서드를 호출하여 preference page에서 사용할 preference 저장소를 지정한다. performOk() 메서드에서는 preference 저장소를 얻어와 여기에 setValue() 메서드를 이용해 <key, value>의쌍으로 환경설정을 저장한다. 저장할 수 있는 값들은 boolean, double, float, int, String, long 등의 simple data type중에 하나이어야 한다. 위의 예제는 플러그인이 UI에 기여하는 경우(Activator 클래스가 AbstractUIPlugin를 상속하는 경우)에 해당하며 그렇지 않은 경우(Plugin 클래스를 상속하는 경우)에는 getPluginPreferences 메서드를 사용해야 한다.

정리하면 생성자에서 preference 저장소를 지정한 후, createContents() 메서드에서 preference page에 들어가는 UI를 작성한다. 그리고 각 버튼에 해당하는 코드를 작성한다. 이는 UI에 입력된 정보를 환경설정에 저장하거나 그 반대의 일이 될 것이다.

지금부터는 환경설정의 기본값(Default)를 지정하기 위한 클래스인 Defaults를 살펴보자. 여기서는 간단히 initializeDefaultPreferences() 메서드에서 setDefault() 메서드를 호출해서 각 key에 해당하는 기본값을 지정하기만 하면 된다.

public void initializeDefaultPreferences() {
// TODO Auto-generated method stub
// get preference store
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
store.setDefault("CDE_ESTEREL_C", true);
store.setDefault("CDE_ESTEREL_VERILOG", true);
store.setDefault("CDE_ESTEREL_BLIF", false);
}

지금까지 Eclipse plug-in 개발시에 preference를 활용하는 방법을 살펴보았다. 아래 첨부한 소스코드를 읽어보면 쉽게 이해할 수 있을 것이다. 예제코드에서 UI 부분은 JDT의 JavaBasePreferencePage 클래스의 것을 응용하였다.

Visitor 패턴은 AST(Abstract Syntax Tree)와 같은 자료구조를 순회하면서 필요한 작업을 정의하기에 용이하다. 이를 처음으로 접하게 된 것은 CEC(Comlumbia Esterel Compiler)의 소스코드를 분석할때였다. CEC는 Esterel 소스코드를 파싱하여 이를 XML 형태의 IR(Intermediate Representation)로 저장한다. CEC는 C++ 언어로 프로그램되어 있는데 XML 형태의 IR은 C++의 클래스 구조로 구성된 AST에 대응된다.

Esterel Source Code (Text) - AST (C++ Classes) - IR (XML)

배경은 이쯤에서 정리하고 본론으로 들어가보자. Esterel 언어는 하드웨어 언어인 Verilog로 컴파일되기도 하고 소프트웨어 언어인 C로 컴파일 되기도 하는 신기한(?)언어인데, Esterel 소스코드로 부터 C언어 코드가 나오기까지 IR을 XML 포맷으로 유지하며 여러단계의 독립적인 프로그램을 거치게 된다. 이때마다 XML 파일을 읽어 AST를 구축한 후 Visitor 패턴을 이용해 AST를 순회하며 필요한 작업을 수행한다. 물론 그러한 작업에 의해 AST가 수정되면 수정된 상태의 AST가 다시 XML형태로 저장된다.

Esterel Source Code - Parser - Expander - Dismantler - GRC synthesizer - C generator - C Source code

필자가 하고 있는 일은 동시설계 개발환경에서 Esterel 언어를 기반으로 임베디드 시스템을 정의하는 방법론을 제시하고 그 것으로 부터 임베디드 시스템 구현에 필요한 여러가지 인터페이스를 자동으로 생성하는 것이다. 임베디드 시스템을 XML 형태의 언어로 정의하도록 하고 이를 파싱하여 저장하는 나름의(?) AST를 자바 클래스로 구축하였다. 인터페이스 생성등 다양한 작업이 AST를 기반으로 이루어질 것 이며, 여기서는 AST에 저장되어 있는 정보를 다시 XML로 출력하는 프로그램을 예로 들어 Visitor 패턴을 설명하려고 한다.  

모든 AST의 클래스들은 다음과 같은 AbstractSpec 추상클래스를 상속한다. 여기에는 Visitor 패턴을 위한 메서드인 welcome 추상 메서드가 정의되어 있다.

package kr.ac.kaist.vicode.spec;
public abstract class AbstractSpec {
  public abstract void welcome(Visitor v);
}

그리고 당연히 모든 AST 노드에 해당하는 클래스들은 welcome 메서드를 정의해야 하는데 그 내용은 모두 다음과 같이 동일하다. 굳이 설명하자면 파라메터로 넘어온 visitor를 이용해서 자기 자신에 해당하는 visit 메서드를 호출하게 하는 것 이다.

public void welcome(Visitor v)
{
    v.visit(this);
}

다음으로 해야할 일은 Visitor 클래스를 생성하는 것이다. Visitor 패턴을 이용하는 클래스는 이 클래스를 상속받아서 visit 메서드를 구현하기만 하면 된다. 즉 파라메터로 입력받은 AST 노드에 해당하는 작업을 visit 메서드에 정의하면 된다.

package kr.ac.kaist.vicode.spec;

public abstract class Visitor {
  public abstract void visit(Spec n);
  public abstract void visit(Communication n);
  public abstract void visit(Api n);
  public abstract void visit(Rule n);
  public abstract void visit(DataFunc n);
  public abstract void visit(SignalFunc n);
  public abstract void visit(SignalDecl n);
  public abstract void visit(State n);
  public abstract void visit(Transition n);
  public abstract void visit(Set n);
}

Visitor 패턴을 사용하기 위한 준비작업은 모두 끝이 났다. 지금부터는 AST에 저장되어 있는 정보를 Visitor 패턴을 이용하여 AST를 순회하면서 XML형태로 출력하는 예제를 살펴본다. Spec2Xml 클래스는 Vistor 클래스를 상속하여 Visitor 패턴을 구현하고 있다. 각 visit 매서드에서 하는 일은 크게 두가지다. 하나는 해당 노드에 해당하는 작업을 수행하는 것이고, 나머지 하나는 자식 노드를 방문하게 하는 일인데 이과정을 위해서 단순히 각 AST 노드의 welcome 메서드를 호출하는 print 메서드를 정의하였다.

package kr.ac.kaist.vicode.spec.util;

import java.util.*;
import kr.ac.kaist.vicode.spec.*;

public class Spec2Xml extends Visitor {
  public void print(AbstractSpec n) {
       n.welcome(this);
  }

  public void visit(Spec n) {
       output("<spec>");
       print(n.getCommunication());
       print(n.getApi());
       print(n.getRule());
       output("</spec>");
  }

...

Vistor 패턴의 시작은 간단하다. AST의 최상위 노드에 대해서 print 메서드를 호출하면 자신의 자식노드에 대해서 visit 메서드를 호출하게 되고 이러한 일련의 과정을 통해 경우에 따라서 모든 노드를 방문하며 특정 작업을 수행할 수 있다. 위의 예제에서 Spec은 AST의 최상위 노드에 해당하며 이는 3가지 자식노드 (communication, api, rule)을 가지고 있으며 각각에 대해서 visit 메서드가 호출되도록 한다.  

지금까지 살펴본 것 처럼 Visitor 패턴은 AST와 유사한 자료구조를 빠짐없이 탐색하며 특정작업을 수행하기에 적합한 방법론을 제공한다. 특히 컴파일러나 인터프리터와 같이 AST를 사용하는 프로그램에서 잘 활용하면 유지보수가 용이하고 코드가 깔끔한 코드를 작성하는데 큰 도움이 될 것 같다.

UML Diagram using Draw2D


Draw2D는 GEF에 내장되어 있기도 하지만 standalone으로 사용될 수 있는 그래픽 라이브러리다. GEF에서 그림을 그릴 때 내부적으로 이 라이브러리를 사용한다. Display a UML Diagram using Draw2D 문서를 읽고 금방 그 사용법을 익힐 수 있을 정도로 잘 구성되어 있다. 여러 Figure를 조합해서 하나의 component를 구성하고 그 component 사이에 connection을 정의할 수 있도록 되어있다. 물론 그림 처럼 connection에 해당하는 외관을 변경한다던지 레이블을 추가하는 등의 작업이 가능하다. Eclipse 혹은 SWT 기반의 어플리케이션에서 유용하게 사용할 수 있을 것 같다.  
The Graphical Editing Framework (GEF) allows developers to create a rich graphical editor from an existing application model. GEF consists of 2 plug-ins. The org.eclipse.draw2d plug-in provides a layout and rendering toolkit for displaying graphics. The developer can then take advantage of the many common operations provided in GEF and/or extend them for the specific domain. GEF employs an MVC (model-view-controller) architecture which enables simple changes to be applied to the model from the view.

GEF는 이름 그대로, Graphical Editor의 구현을 도와주는 프레임워크라고 할 수 있다. 무에서 Graphical Editor를 구현한다고 상상해본다면 어떨까? 유사한 경험을 가지고 있지 않다면 대체 어디서 어떻게 시작해야할지 도무지 감을 잡을 수 없을 것이다.

항상 어떤 프레임워크나 플랫폼을 활용할 때는 딜레마를 느끼게 된다. 잘 짜여진 프레임워크를 활용하면 내가 한 일에 비해서 보기좋은(?) 아웃풋을 얻을 수 있다는 장점이 있는 반면에 얼마나 자유도를 가지고 시스템을 개발할 수 있는지에 대해서 의구심을 떨쳐버릴 수가 없고 충분히 활용하기까지 공부를 많이 해야한다는 단점이 있다.

분명한건 이런 프레임워크나 플랫폼은 나보다 똑똑한 여러명이 심사숙고해서 만들어 놓은 뼈대이며, 자유도를 고려한 디자인을 가지고 있다보니 본의 아니게(?) 복잡해질 수 밖에 없다. 따라서 이를 활용하기 위해서 적잖이 공부해야한다.

연구실에서 개발하는 Verification Integrated CODesign Environemnt (VICODE)에서 임베디드 시스템을 설계 할때 전체 시스템의 논리적인 디자인을 다이어그램 에디터에서 이루어지게 하려고 한다. 분명 xml 코드를 직접 쓰는 것보다는 훨씬 낫겠다는 기대와 함께 ...

구현을 돕기 위해 공부해야할 것에는 다음과 같은 것 들이 있다.

EMF (Eclipse Modeling Framework)
GEF (Graphical Editing Framework)
GMF (Graphical Modeling Framework)


이들은 모두 MVC (Model-View-Controller) Architecture를 기반으로 한다. EMF는 Eclipse에서 사용할 Model의 클래스 구조를 자동생성해주는 녀석 쯤으로 보이고 GEF는 특정 Model을 편집할 수 있는 그래픽 편집기를 생성하는 프레임워크라고 볼 수 있다. 여기서 EMF로 생성된 Model이 GEF의 Model의 조건을 만족하기 때문에 EMF+GEF 조합의 솔루션이 소개되었다. 그리고 이를 돕기 위해 GMF 프로젝트가 전개되고 있다.

나는 GEF만을 사용하여 다이어그램 에디터를 구현하고자 한다. 여전히 복잡하고 어려워보이지만 "복잡한 문제는 단순한 문제의 합" 이라고 믿고 그냥 가보는거다! GEF를 공부하고 그 틀대로 구현을 하게 되면 아래와 같이 보기 좋은 그래픽 에디터가 생성된다.

+ Recent posts