SSISO Community

시소당

JET를 사용하여 Eclipse에서 더 나은 코드 만들기 (한글)

전문가의 베스트 프랙티스를 배워, 모델 중심 개발을 적극 활용하는 방법

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

수평출력으로 설정

이 페이지 출력

이 페이지를 이메일로 보내기

이 페이지를 이메일로 보내기


제안 및 의견
피드백

난이도 : 초급

Chris Aniszczyk, Software Engineer, IBM
Nathan Marz, Software Engineer, IBM

2007 년 1 월 16 일

베스트 프랙티스를 코딩 하는 템플릿을 만든다면 시간을 절약하고, 지루한 코딩을 줄일 수 있을 것입니다. Eclipse 프로젝트인, 코드 생성 프레임웍 JET를 소개합니다.

생성은 새로운 개념이 아니다. 오랫동안 존재했었고, 생산성을 늘리는 방식으로서 모델 중심 개발(MDD) 운동으로 인해 인기를 얻어왔다. Eclipse 프로젝트에는 특별한 코드 제너레이터인 JET라고 하는 기술 프로젝트가 있다. JET는 “코드” 그 이상을 만들 수도 있으며, 이 글에서는 생성물(artifact)이라고 하는 비 코드 요소에 대해 설명하겠다.

JET? EMF? JET2?
신 참 JET 사용자들이 반드시 알아두어야 할 부분은, 이 글에서 소개되는 JET 버전이, 일반적으로 JET2로 알려진 업데이트 JET 버전이라는 점이다. Eclipse Modeling Framework (EMF) 프로젝트에서 코드 생성에 사용했던 더 오래된 버전의 JET도 있다. JET2 는 업데이트 되었고, 새로운 Eclipse Modeling Framework Technology (EMFT) 프로젝트의 일부이다. JET 구 버전에 대해 알고 싶다면 참고자료 섹션을 참조하라.

시작하기

이 섹션에서는 JET 프로젝트의 기본적인 설치 방법과 JET 프로젝트 구조를 설명하고, 변형을 실행해 본다.

JET 프로젝트 만들기

JET를 본격적으로 시작하기 전에, 프로젝트를 만들어야 한다. 프로젝트를 만드는 표준 Eclipse 방식을 사용한다. JET의 경우, File > New > Other > EMFT JET Transformations > EMFT JET Transformation Project 명령어로 EMFT JET Transformation Project를 만든다. (그림 1)


그림 1. JET 프로젝트 위자드
JET project wizard

JET 프로젝트 구조

프로젝트 구조를 분석하여 JET 작동 방법을 알아보자. 이전 섹션에서는 JET 프로젝트를 만들었다. (그림 2) 이 JET 프로젝트에는 여섯 개의 파일들이 있다.


그림 2. JET 프로젝트 구조
JET project structure

Eclipse 프로젝트 파일(MANIFEST.MF, plugin.xml, build.properties)
Eclipse 프로젝트에서 작업할 때 생성되는 표준 파일들이다. 특히 plugin.xml에 있는 것들에 주목해야 하고, JET는 org.eclipse.jet.transform 확장을 자동으로 추가한다. 이 확장 포인트를 확장함으로써, JET에게 우리가 JET 변형을 제공하고 있다는 것을 알려주게 된다.
컨트롤 및 템플릿 파일(dump.jet, main.jet)
변형에 사용되는 템플릿과 컨트롤 파일들이다. 아래 개념 섹션에서 상세히 설명하겠다.
인풋 모델(sample.xml)
변형에 사용되는 샘플 인풋 파일도 있다. 이 인풋은 어떤 소스에서도 가져올 수 있고 한 프로젝트로 제한되지 않는다.
시작 템플릿 변경하기
기본적으로, JET는 시작 템플릿을 main.jet로 정의한다. 이 옵션은 startTemplate 애트리뷰트 밑에 plugin.xml (org.eclipse.jet.transform 확장)에서 설정할 수 있다. 이 확장 밑에 다른 설정 옵션들이 있으니 자유롭게 사용할 수 있다.

JET 변형 실행하기

프로젝트에 템플릿, 컨트롤 파일, 인풋 모델을 다 갖추었다면, 변형을 실행할 수 있다. JET는 친숙한 Eclipse의 시작 설정을 통해 변형을 호출하는 편리한 방식을 제공한다. (그림 3) JET 시작 설정에 액세스 하려면, Run > JET Transformation으로 가서, 알맞은 옵션을 채우고, Run을 누른다.


그림 3. JET 시작 설정
JET launch configuration

개념

JET는 생성물을 만들어 내는(output) 템플릿을 지정하는 언어이다. 몇몇 애플리케이션을 구현하는 템플릿의 컬렉션을 우리들 사이에서는 블루프린트(blueprint)라고 한다. 제트의 패러다임은 다음과 같다.

Parameters + Blueprint = Desired Artifacts

블루프린트(blueprint)는 JET로 만들어지고, 매개변수(parameter)는 블루프린트 사용자가 제공한다. 블루프린트는 세 개의 파일들로 구성된다.

1. 매개변수
블루프린트에 대한 매개변수는 XML 포맷으로 되어있다. XML은 계층적 관계와 각 노드에 대한 애트리뷰트가 있기 때문에 표현성이 풍부하다. 인풋 매개변수들을 인풋 모델(input model)이라고 한다. 블루프린트는 매개변수가 무엇을 기대하는지를 설명하는 스키마를 정의해야 한다. 예를 들어, 다음은 네트워크 스니퍼를 만드는 블루프린트에 대한 인풋 예제이다.

Listing 1. 네트워크 스니퍼 블루프린트용 인풋
                        
<app project="NetworkSniffer" >
<sniffer name="sampler" sample_probability=".7" >
<logFile name="packet_types" />
<packet type="TCP" subType="SYN" >
<logToFile name="packet_types" />
<findResponse type="TCP" subType="ACK" timeout="1" />
</packet>
<packet type="UDP" >
<logToFile name="packet_types" />
</packet>
</sniffer>
</app>

블루프린트는 이러한 인풋 매개변수들을 네트워크 스니퍼를 구현하는 코드로 변형한다. 블루프린트에 대한 매개변수들은 커스텀 프로그래밍 언어로 간주되고, 블루프린트는 “컴파일러”처럼 작동하고, 인풋을 고유의 생성물들로 변형한다.
2. 컨트롤 파일
이 파일들은 코드 생성 작동을 제어한다. 이 컨트롤 태그에서 가장 중요한 태그는 <ws:file>이다. 이것은 템플릿을 실행하고, 결과를 지정된 파일에 덤핑한다. 코드 생성 실행은 main.jet에서 시작하고, 이것이 이 프로그램의 주 기능이다.
3. 템플릿 파일
템플릿 파일은 텍스트를 생성하는 방법과 조건을 지정한다. 텍스트는 코드, 설정 파일, 또는 어떤 것이라도 될 수 있다.
XPath

XPath를 잘 모르겠다면, 참고자료 섹션을 참조하기 바란다.

XPath

JET 블루프린트에 대한 인풋은 XML 모델이기 때문에, XPath 언어는 노드와 애트리뷰트를 참조하는데 사용된다. 게다가, XPath는 식 내에서 변수를 사용하는 고유의 방식이 있고, JET에서도 이러한 식으로 사용된다. 핵심 포인트는 다음과 같다.

  1. 경로 식(path expression)은 파일시스템 경로와 비슷하다. 경로는 포워드 슬래시(/)로 구분된다.
  2. 이 단계는 왼쪽에서 오른쪽으로 계산되고, 모델의 트리에서 내려간다.
  3. 각 단계는 트리 노드를 이름에 따라 구분한다. (다른 가능성도 있다.)
  4. 옵션 필터 조건에는 단계의 끝에 대괄호 ([])가 쳐진다.
  5. 첫 슬래시 (/)는 식이 모델 트리의 루트(root)에서 시작한다는 것을 알려준다.
  6. 경로 식은 변수로도 시작할 수 있다. 그 이름 앞에는 달러 표시 ($)가 붙는다.

JET에서 XPath에 대해 기억해야 할 것:

  1. 변수들은 여러 JET 태그들에 의해 정의된다. var 애트리뷰트를 찾는다. c:setVariable 태그로도 정의될 수 있다.
  2. 경로 식을 필요로 하는 JET 태그에는 select 애트리뷰트가 있다.
  3. 모든 태그 애트리뷰트에는 동적인 XPath 식이 포함되고, 여기에는 중괄호 ({})가 쳐진다.

JET 태그

다음 예제에서는 인풋 모델을 사용할 것이다.


Listing 2. 인풋 모델
                
<app middle="Hello" >
<person name="Chris" gender="Male" />
<person name="Nick" gender="Male" />
<person name="Lee" gender="Male" />
<person name="Yasmary" gender="Female" />
</app>

ws:file
이 태그는 블루프린트의 컨트롤 섹션에 속해있고, 템플릿을 시작한다. 예를 들어,
<ws:file template="templates/house.java.jet"
path="{$org.eclipse.jet.resource.project.name}/house1.java">

이 코드는 인풋 모델에서 house.java.jet 템플릿을 실행하고, 결과를 $(Project Root)/house1.java에 덤핑한다. {$org.eclipse.jet.resource.project.name}은 동적 XPath 식이고, 이것은 스트링을 org.eclipse.jet.resource.project.name 변수의 값으로 대체한다. 이 변수는 JET 엔진에서 정의된다.
c:get
이 태그는 XPath 식의 결과를 작성한다. Pre<c:get select="/app/@middle" />PostPreHelloPost를 작성할 것이다. select 매개변수는 XPath 식을 취한다. 정적 스트링을 기대하는 매개변수 내에서 XPath 식을 사용하려면, 동적 XPath 식 호출은 중괄호 ({})안에 식을 래핑하여 이루어진다.
c:iterate

이 태그는 특정 이름을 가진 노드를 반복하고, 각 노드의 iterate의 바디 부분을 실행한다. 예를 들어,

<c:iterate select="/app/person" var="currNode" delimiter="," > 
Name = <c:get select="$currNode/@name" />
</c:iterate>

이것은 Name = Chris, Name = Nick, Name = Lee, Name = Yasmary를 만들어 낸다.

iterate 태그는 컨트롤 템플릿의 시작 태그 주변에서도 사용된다. 예를 들어, 이 모델의 각 사람에 대해 자바™ 클래스를 만들려면, 다음과 같이 한다.

<c:iterate select="/app/person" var="currPerson">
<ws:file template="templates/PersonClass.java.jet"
path="{$org.eclipse.jet.resource.project.name}/{$currPerson/@name}.java"/>
</c:iterate>

이것은 각각의 파일에 네 개의 자바 클래스--Chris.java, Nick.java, Lee.java, Yasmary.java--를 만들 것이다. 시작 태그의 path 애트리뷰트 내에 {$currPerson/@name} 스트링을 주목하라. path 매개변수는 (select 매개변수가 그렇듯이) XPath 식을 기대하지 않기 때문에, {...} 문자는 JET 엔진에게 XPath 식을 계산함으로써 그 스트링의 섹션을 대체할 것을 명령한다. $currPerson/@name은 엔진에게 currPerson 노드의 name 애트리뷰트를 가진 스트링을 대체할 것을 명령한다. 이것은 iterate 태그에서 정의된 변수이다.

또한, PersonClass.java.jet 템플릿 내에서, iterate 태그에서 정의된 currPerson 노드 변수를 참조할 수 있다. 예를 들어, PersonClass.java.jet의 경우를 생각해 보자.


Listing 3. PersonClass.java.jet
                        
class <c:get select="$currPerson/@name" />Person {
public String getName() {
return "<c:get select="$currPerson/@name" />";
}
public void shout() {
System.out.println("Hello!!!");
}
}

Yasmary.java 는 다음과 같을 것이다.


Listing 4. Yasmary.java
                        
class YasmaryPerson {
public String getName() {
return "Yasmary";
}
public void shout() {
System.out.println("Hello!!!");
}
}

Lee.java는 다음과 같다.


Listing 5. Lee.java
                        
class LeePerson {
public String getName() {
return "Lee";
}
public void shout() {
System.out.println("Hello!!!");
}
}

c:choose c:when
이 태그들은 템플릿이 값에 따라 조건적으로 텍스트를 덤핑할 수 있도록 한다. 아래 코드를 보자.

Listing 6. c:choose/c:when 예제
                        
<c:iterate select="/app/person" var="p" >
<c:choose select="$p/@gender" >
<c:when test="'Male'" > Brother </c:when>
<c:when test="'Female'" > Sister </c:when>
</c:choose>
</c:iterate>

위 코드는 다음과 같은 아웃풋을 만들어 낸다.

Brother
Brother
Brother
Sister

c:when 태그는, XPath 식을 기대하는 test 매개변수를 필요로 한다. select 매개변수를 상수와 비교할 것이기 때문에 상수를 싱글 쿼트('')로 래핑한다.

c:set
이 태그로 템플릿은 인풋 모델의 애트리뷰트를 수정할 수 있다. ChrisChris, chris, ChrisClass, CHRIS_CONSTANT 등으로 매핑되는 것처럼, 하나의 스트링이 텍스트 아웃풋을 통해 많은 방법으로 매핑되는 것도 한 예이다. c:set은 지정된 애트리뷰트를 콘텐트로 설정한다. 다음 예제에서는 각 사람에 대해 className이라고 하는 애트리뷰트를 저장하고, 그 이름 뒤에 Class라는 단어를 붙인다.

Listing 7. c:set 예제
                        
<c:iterate select="/app/person" var="p" >
<c:set select="$p" name="className" >
<c:get select="$p/@name" />Class</c:set>
</c:iterate>

setVariable
이 태그로 템플릿은 글로벌 변수를 선언 및 사용한다. XPath를 활용하여 어떤 지점에서든지 변수를 조작한다. 예를 들어, 인풋 모델에 얼마나 많은 사람 노드들이 제공되었는지를 작성하려면, 다음과 같이 한다.

Listing 8. c:setVariable 예제
                        
<c:setVariable select="0" var="i" />
<c:iterate select="/app/person" var="p" >
<c:setVariable select="$i+1" var="i" />
</c:iterate>
Number of people = <c:get select="$i" />.

이것은 Number of people = 4.라는 아웃풋을 만들어 낸다.

변수들은 위 예제에서처럼, get을 사용하여 작성될 수 있다.

텍스트 아웃풋에 사용할 수 있는 45개 이상의 태그들이 있다. 조건 로직용 태그, 인풋 모델을 동적으로 변경하기, 실행 흐름을 통제하기도 한다.

JET 확장하기

JET는 Eclipse의 확장 포인트 메커니즘을 사용하여 확장 가능하다. 다음은 JET가 제공하는 여섯 개의 확장 포인트이다.

org.eclipse.jet.tagLibraries
태그 라이브러리를 정의한다. JET에는 이미 네 개의 태그 라이브러리(control, format, workspace, java)가 있지만, 태그를 추가하고 싶다면 이것을 사용한다.
org.eclipse.jet.xpathFunctions
JET XPath 실행 중에 커스텀 XPath 식을 사용할 수 있다. 이 확장 포인트(JET 소스 코드의 CamelCaseFunction 참조)를 확장하여 XPath 식의 camelcase를 사용하는 JET의 기능도 한 예가 된다.
org.eclipse.jet.transform
플러그인이 JET 변형을 제공하고 있다는 것을 선언한다. (main.jet 대신) 여러분이 사용하는 시작 템플릿을 변경할 장소이다.
org.eclipse.jet.modelInspectors
JET XPath 엔진을 실행하여 로딩 된 자바 객체들을 XPath 노드로서 인터프리팅하는 인스펙터를 정의한다. 이 인스펙터는 XPath 정보 모델에 객체들을 변형하는 객체이다. 예를 들어, JET는 Eclipse 워크스페이스를 검색하는 모델을 사용한다. 이것은 임시 API이고 곧 변경될 것이다.
org.eclipse.jet.modelLoaders
모델이 JET 변형에 의해 소비되는 방법과 JET <c:load> 태그가 파일시스템에서 로딩되는 방법을 정의한다. JET는 모델 로더 org.eclipse.jet.resource를 제공하는데, 이것은 Eclipse IResource(파일, 폴더, 프로젝트)를 로딩하고, 그 리소스에서 Eclipse 워크스페이스를 검색한다.
org.eclipse.jet.deployTransforms
쉽게 분산될 수 있도록 플러그인(번들)으로 JET 변형을 패키징 한다. 어떤 변형을 사용할 수 있는지를 알아보기 위해 UI에 의해서도 사용된다.

예제: 코드를 작성하는 코드 만들기

다 음 예제는 임의의 속성들을 사용하여 클래스를 만드는 템플릿이다. 각 속성에는 관련된 getter와 setter가 있고, 몇 가지 초기 값들이 포함된다. 또한, 이 템플릿은, 명령행에 호출된 함수의 이름을 프린팅 하여, 간단한 로깅을 각 함수에 추가한다.


Listing 9. 속성 템플릿
                
class <c:get select="/app/@class" /> {
<c:iterate select="/app/property" var="p" >
private <c:get select="$p/@type" /> <c:get select="$p/@name" />;
</c:iterate>

public <c:get select="/app/@class" />() {
<c:iterate select="/app/property" var="p" >
this.<c:get select="$p/@name" /> = <c:choose select="$p/@type" >
<c:when test="'String'">"<c:get select="$p/@initial" />"</c:when>
<c:otherwise><c:get select="$p/@initial" /></c:otherwise>
</c:choose>
;
</c:iterate>
}

<c:iterate select="/app/property" var="p" >
public void set<c:get select=\
"camelCase($p/@name)" />(<c:get select="$p/@type" />
<c:get select="$p/@name" />) {
System.out.println\
("In set<c:get select=\
"camelCase($p/@name)" />()");
this.<c:get select="$p/@name" /> = <c:get select="$p/@name" />;
}

public <c:get select=\
"$p/@type" /> get<c:get select="camelCase($p/@name)" />() {
System.out.println("In get<c:get select="camelCase($p/@name)" />()");
return <c:get select="$p/@name" />;
}

</c:iterate>
}

다음은 이 템플릿용 인풋 모델 예제이다.


Listing 10. 인풋 매개변수
                
<app class="Car">
<property name="model" type="String" initial="Honda Accord" />
<property name="horsepower" type="int" initial="140" />
<property name="spareTires" type="boolean" initial="true" />
</app>

이 인풋 매개변수들은 다음과 같은 클래스를 만들어 낸다.


Listing 11. 생성된 클래스
                
class Car {
private String model;
private int horsepower;
private boolean spareTires;

public Car() {
this.model = "Honda Accord";
this.horsepower = 140;
this.spareTires = true;
}

public void setModel(String model) {
System.out.println("In setModel()");
this.model = model;
}

public String getModel() {
System.out.println("In getModel()");
return model;
}

public void setHorsepower(int horsepower) {
System.out.println("In setHorsepower()");
this.horsepower = horsepower;
}

public int getHorsepower() {
System.out.println("In getHorsepower()");
return horsepower;
}

public void setSparetires(boolean spareTires) {
System.out.println("In setSparetires()");
this.spareTires = spareTires;
}

public boolean getSparetires() {
System.out.println("In getSparetires()");
return spareTires;
}

}

예제: 잡다한 작업을 수행하는 코드 작성하기

JET 가 코드 생성에만 사용되는 것은 아니라는 것을 증명하기 위해, 다양한 무드로 이메일 메시지를 만드는 템플릿을 소개하겠다. 각각 생성되는 이메일은 다양한 아이템을 요청하는 내용이다. 컨트롤 파일(main.jet)과 이것을 호출하는 템플릿(email.jet)만 소개하겠다.


Listing 12. main.jet
                
<c:iterate select="/app/email" var="currEmail" >
<ws:file template="templates/email.jet"
path="{$org.eclipse.jet.resource.project.name}/{$currEmail/@to}.txt" />
</c:iterate>


Listing 13. email.jet
                
<c:setVariable var="numItems" select="0" />
<c:iterate select="$currEmail/request" var="r">
<c:setVariable var="numItems" select="$numItems+1" />
</c:iterate>
<c:set select="$currEmail" name="numItems"><c:get select="$numItems" /></c:set>
<c:choose select="$currEmail/@mood" >
<c:when test="'happy'">My dear</c:when>
<c:when test="'neutral'">Dear</c:when>
<c:when test="'angry'">My enemy</c:when>
</c:choose> <c:get select="$currEmail/@to" />,

I am writing you <c:choose select="$currEmail/@mood" >
<c:when test="'happy'">in joy </c:when>
<c:when test="'neutral'"></c:when>
<c:when test="'angry'">in burning anger </c:when>
</c:choose>to ask for <c:choose select="$currEmail/@numItems" >
<c:when test="1">
a <c:get select="$currEmail/request/@item" />.
</c:when>
<c:otherwise>
the following:

<c:setVariable var="i" select="0" />
<c:iterate select="$currEmail/request" var="r">
<c:setVariable var="i" select="$i+1" />
<c:get select="$i" />. <c:get select="$r/@item" />
</c:iterate>

</c:otherwise>
</c:choose>
<c:choose select="$currEmail/@mood">
<c:when test="'happy'">Please</c:when>
<c:when test="'neutral'">Please</c:when>
<c:when test="'angry'">Either suffer my wrath, or</c:when>
</c:choose> send me <c:choose select="$currEmail/@numItems">
<c:when test="1">
this item</c:when>
<c:otherwise>
these items</c:otherwise>
</c:choose> <c:choose select="$currEmail/@mood" >
<c:when test="'happy'">at your earliest convenience.</c:when>
<c:when test="'neutral'">promptly.</c:when>
<c:when test="'angry'">immediately!</c:when>
</c:choose>

<c:choose select="$currEmail/@mood" >
<c:when test="'happy'">Your friend,</c:when>
<c:when test="'neutral'">Sincerely,</c:when>
<c:when test="'angry'">In rage,</c:when>
</c:choose>

<c:get select="/app/@from" />

다음은 이 템플릿에 대한 인풋 모델 샘플이다.


Listing 14. sample.xml
                
<app from="Nathan" >
<email to="Chris" mood="angry" >
<request item="well-written article" />
</email>
<email to="Nick" mood="happy" >
<request item="Piano" />
<request item="Lollipop" />
<request item="Blank DVDs" />
</email>
</app>

mood 이메일 블루프린트를 이 매개변수에 적용하면 다음과 같이 두 개의 파일이 만들어진다.


Listing 15. Chris.txt
                
My enemy Chris,

I am writing you in burning anger to ask for a well-written article.
Either suffer my wrath, or send me this item immediately!

In rage,
Nathan


Listing 16. Nick.txt
                
My dear Nick,

I am writing you in joy to ask for the following:

1. Piano
2. Lollipop
3. Blank DVDs

Please send me these items at your earliest convenience.

Your friend,
Nathan

맺음말

귀중한 조언을 아끼지 않은 Paul Elder에게 감사의 말을 전하고 싶다. JET는 단순히 코드 생성에만 사용되는 것은 아니다. JET는 새로운 Eclipse 기술 프로젝트이고, 많은 개발자들이 이것을 십분 활용하기를 바란다.

기사의 원문보기



참고자료

교육

제품 및 기술 얻기

토론


필자소개

Chris Aniszczyk

Chris Aniszczyk.은 IBM Lotus의 소프트웨어 엔지니어이고, IBM의 Extreme Blue 인턴쉽 프로그램을 수료했다. 오픈 소스에 대한 열정이 대단하며, Gentoo Linux (http://www.gentoo.org) 작업도 했으며, Eclipse Modeling Framework Technology (EMFT) 프로젝트의 커미터이다.


Nathan Marz는 Stanford University에 재학 중이며, IBM의 Extreme Blue 인턴쉽 프로그램을 수료했다. Blueprint 프로젝트의 기술 인턴이었다.

1370 view

4.0 stars