2008년 2월 1일 금요일

RIFE 시작하기(6) - A friends database

http://rifers.org 에서 발췌한 내용을 번역 하였습니다.
번역: 이원찬(wonchan.lee@gmail.com)
-------------------------------------------------------

A friends database

- Introduction

숫자맞추기 게임에서 submission과 템플릿을 이용해 사용자의 입력을 처리하는과정을 통해 몇가지 RIFE의 강력한 기능을 살펴보았다. 이제 friend 데이터베이스 어플리케이션을 통해 좀 더 발전된 어플리케이션을 개발해 보기로 하겠다.

이 어플리케이션은 제목과 친구들 목록을 보여주고 또 새로운 친구를 데이터베이스에 추가할 수 있다. 또한, 어플리케이션의 사본을 친구에게 보내어 그가 이것을 사용할 수 있도록 할것이다. 하지만, 그가 제목을 변경하기 위해 코드를 수정하는것은 원치 않는다. 단지, 설정(configuration)을 통해 이를 쉽게 할 수 있도록 할것이다.

이 예제의 소스 역시 RIFE예제 패키지에 포함되어 있다. 이해를 돕기위해 어플리케이션의 디렉토리 구조를 살펴 보겠다.

------------------------------------------------------------------
friend 어플리케이션의 디렉토리 구조
------------------------------------------------------------------
src/
elements/
add.xml
display.xml
install.xml
menu.xml
remove.xml

implementations/
tutorial/
friends/
Add.java
Display.java
Install.java
Remove.java

rep/
config.xml
datasources.xml
participants.xml

sites/
friends.xml

templates/
add.html
display.html
install.html
menu.html
remove.html

tutorial/
friends/
backend/
Friend.java
FriendManager.java
------------------------------------------------------------------

어플리케이션은 다섯개의 요소로 구성되어 있다. 그 다섯개의 요소는 고유의 자바 구현체를 가지고 있으며 각 구현체는 이미 RIFE를 통해 요소(element)에 접근한다. 모든 컨텐츠는 템플릿을 통해 생성되고 각 요소는 하나의 템플릿과 연동된다. 친구는 Friend객체로 표현되며, 모든 친구들은 FriendManager에 의해 관리되어 진다. 먼저 site정의를 성정하는것으로 시작해 친구들을 출력하기 위한 DISPLAY요소를 정의하고 어플리케이션을 활용(navigating)하기 위해 MENU요소도 정의할 것이다.

이전 예제에서 처럼 ParticipantSite 참여자를 사용해 메인사이트 파일을 정의한다.

------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rep SYSTEM "/dtd/rep.dtd">

<rep>
<participant param="sites/friends.xml">ParticipantSite</participant>
</rep>
------------------------------------------------------------------

- Defining and connection the elements

이제 DISPLAY와 MENU요소를 정의하고 연결할 것이다. 데이터베이스장이 끝날때쯤 나머지 요소들도 모두 추가되어 모든 기능이 구현될 것이다.

------------------------------------------------------------------
DISPLAY 요소
------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE element SYSTEM "/dtd/element.dtd">

<element implementation="tutorial.friends.Display"/>
------------------------------------------------------------------

------------------------------------------------------------------
MENU 요소
------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE element SYSTEM "/dtd/element.dtd">

<element implementation="com.uwyn.rife.engine.elements.PrintTemplate">
<property name="template_name">menu</property>

<exit name="install"/>
<exit name="add"/>
<exit name="remove"/>
<exit name="display"/>
</element>
------------------------------------------------------------------

DISPLAY요소는 전혀 놀랍지 않지만 MENU요소에는 뭔가 새로운 것이 있다. 이것은 내장요소구현체(built-in element implementation)인 PrintTemplate를 사용하고 있다. 이것은 속성(properties)을 초기화 하는데 사용하기 위해 파라미터를 받는다.

- Properties

속성(property)을 사용하면 요소에 고정된 값을 제공할 수 있다. 이것은 데이터흐름의 일부가 아닌 대부분 요소에 특화된 설정을 목적으로 사용된다. 위의 경우 템플릿의 이름을 제공하는데 사용되었다. PrintTemplate은 속성값을 읽고, 템플릿의 인스턴스를 생성하는데 사용한 후 출력하였다. 자바 코드에서 property속성이 어떻게 사용되는지는 아래의 PrintTemplate구현 자바코드를 보라.

------------------------------------------------------------------
package com.uwyn.rife.engine.elements;

import com.uwyn.rife.engine.Element;
import com.uwyn.rife.engine.exceptions.PropertyRequiredException;
import com.uwyn.rife.template.Template;

public class PrintTemplate extends Element
{
public void processElement()
{
if (hasProperty("name"))
{
Template template;

template = getHtmlTemplate(getPropertyString("name"));

print(template);
}
else
{
throw new PropertyRequiredException(getDeclarationName(), "name");
}
}
}
------------------------------------------------------------------

속성을 조회하는 대신, 속성명과 setter를 이용해 RIFE는 값을 자동으로 주입(inject)할 수도 있다.

------------------------------------------------------------------
package com.uwyn.rife.engine.elements;

import com.uwyn.rife.engine.Element;
import com.uwyn.rife.engine.exceptions.PropertyRequiredException;
import com.uwyn.rife.template.Template;

public class PrintTemplate extends Element
{
private String name;
public void setName(String name) { this.name = name }

public void processElement()
{
if (null == name)
{
throw new PropertyRequiredException(getDeclarationName(), "name");
}

Template template;
template = getHtmlTemplate(name);

print(template);
}
}
------------------------------------------------------------------

이처럼 내장된(built-in)요소를 사용하면 자바요소에 대해 매번 구현하지 않고 템플릿을 출력할 수 있다. 이와 똑같은 작업은 고유의 구현으로도 분명히 가능하며 이것은 요소의 재사용과 Data links, Flow links의 흐름을 통해 어플리케이션을 전반적으로 통제할 수 있는 강력한 기능을 제공한다.

- The site definition

MENU 요소 정의에서 본것과 같이, 네개의 출그(exit)를 가지고 있다: 하나는 어플리케이션의 각 페이지 이다. 아직, INSTALL, ADD, REMOVE요소를 위한 요소를 추가하지 않았다. 지금은 그냥 놔두자.

------------------------------------------------------------------
사이트 정의의 맨첨부분
------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE site SYSTEM "/dtd/site.dtd">

<site>
<arrival destid="DISPLAY"/>

<globalexit name="menu" destid="MENU"/>

<element id="DISPLAY" file="display.xml" url="/display"/>

<element id="MENU" file="menu.xml" url="/menu">
<flowlink srcexit="display" destid="DISPLAY"/>
</element>
</site>
------------------------------------------------------------------

- Global exits

사이트 정의는 주된 요소가 DISPLAY인것을 보여주며 일반적인 HTML인 index.html 페이지로 보여지길 원한다. 브라우저는 특정 url을 생략했을 경우 이페이지가 홈페이지가 될것이다. 그리고, 공통출구를 globalexit태그로 정의하였다. 공통출구(global exit)는 모든 요소에 적용된다. 이경우 우리는 display.html과 같은 모든 페이지에서 메뉴로 링크될 수 있도록 할 수 있다.

------------------------------------------------------------------
친구목록 출력을 위한 템플릿
------------------------------------------------------------------
<html>
<head><title>My friends</title></head>
<body>
<h3>My Friends</h3>

<p>This is a list of my friends that have interesting websites to visit.</p>

<!--V 'content'/-->

<!--BV 'content'-->
<table border="1" cellpadding="5" cellspacing="0">
<tr>
<th>firstname</th>
<th>lastname</th>
<th>website</th>
</tr>
<!--V 'rows'--><!--/V-->
<!--B 'row'-->
<tr valign="top">
<td><!--V 'firstname'/--></td>
<td><!--V 'lastname'/--></td>
<td><a href="[!V 'url'/]"><!--V 'description'/--></a></td>
</tr>
<!--/B-->
</table>
<!--/BV-->

<!--B 'content_error'-->
<p>The display couldn't be performed due to the following error:</p>
<p style="color: #990000;"><!--V 'error'/--></p>
<!--/B-->

<p><a href="[!V 'EXIT:QUERY:menu'/]">go to menu</a></p>
</body>
</html>
------------------------------------------------------------------

마지막 부분에서 보듯, 메뉴링크가 일반적인 출구와 같이 처리되었다.

- Displaying the friends
위의 템플릿에서, rows값과 row블랙을 주의해서 보라. 각 row는 한명의 친구를 나타내며 데이터베이스의 모든 친구를 순환하며 rows에 추가로 출력 할 것이다. 이것은 자바구현체에서 appendBlock을 호출하면 된다. DISPLAY요소의 구현부분을 보자.

------------------------------------------------------------------
mTemplate.setValue("firstname", encodeHtml(resultSet.getString("firstname")));
mTemplate.setValue("lastname", encodeHtml(resultSet.getString("lastname")));
mTemplate.setValue("description", encodeHtml(resultSet.getString("description")));
mTemplate.setValue("url", encodeHtml(resultSet.getString("url")));
mTemplate.appendBlock("rows", "row");
------------------------------------------------------------------

이 코드는 친구 한명당 한번 호출된다. 여기에서 흥미로운 부분은 이전예제에서 처럼 setValue로 값을 설정한다는 것이다. 하지만 마지막에 setBlock대신 appendBlock을 사용했다. 이것은 RIFE가 블럭의 값의 마지막 부분을 교체하지 않고 추가하도록 한다. 결과적으로 데이터베이스로 부터 불러온 모든 친구는 하나씩 목록으로 출력될 것이다.

이 예제는 RIFE가 어떻게 로직과 출력을 분리하는지를 잘 보여준다. 템플릿에는 단지 블럭과 값위치지정자만 정의되어 있다. 이것은 나중에 자바코드에서 요소의 논리적 흐름에 따라 페이지를 생성한다.

이제 기본적인 요소는 자리잡았으니 어플리케이션을 설정(configuration)할 필요가 있다.

댓글 없음: