본문 바로가기

IT/Flex

제4회 Flex의 체제, Cairngorm로 샘플 어플리케이션 작성

출처 : http://2005elc.elancer.co.kr/eTimes/page/eTimes_view.html?str=c2VsdW5vPTUwNjA=

1. 프로젝트의 작성(1)
2007/01/10  

프로젝트의 작성

 전회(Flex의 체제, Cairngorm의 아키텍쳐 )에서는 Cairngorm Framework에 부속되어 있는 로그인 샘플을 구성하는 클래스를 보면서 체제의 아키텍쳐에 대하여 이야기하였습니다. 이번 회부터 2회에 걸쳐서 실제로 Cairngorm Framework를 사용하여 웹 애플리케이션 서버의 검색/등록/갱신/삭제를 실시하는 간단한 샘플 어플리를 작성하고자 합니다. 이번 회에는 전편으로서 서버 측에 제휴할 때까지의 부분(View~Command)을 작성할 것입니다.

 우선, 처음에 샘플 애플리케이션용 프로젝트를 작성합니다. 개발 환경의 구축이 되어 있지 않은 분은 제2회(Flex의 체제, Cairngorm를 사용해 보자)를 참조하여 개발 환경을 구축하기 바랍니다. 아래에는 제2회에서 구축한 개발 환경을 기반으로 샘플 애플리케이션을 작성할 것입니다.

 프로젝트는 로그인 샘플을 움직였을 때 만든 프로젝트와 동일한 순서로 작성합니다. 우선, Eclipse를 가동시키면 Eclipse의 패키지 익스플로러 상에서 오른쪽 클릭 → [새로 만들기] → [그 외]를 선택합니다. 그러면, 아래와 같은 다이얼로그가 표시되고, [웹] → [Dynamic Web Project]를 선택하고 다음 버튼을 누릅니다.

화면 1 프로젝트 선택의 마법사

 그러면 아래와 같은 다이얼로그가 나타나므로 여기에서는 Project Name에 cairngorm-sample이라고 입력합니다. Target runtime에 개발 환경 구축 시에 설정한 Tomcat이 선택되어 있는 것이 확인되면 종료 버튼을 누릅니다.

화면 2 Dynamic Web Project의 작성



2. 프로젝트의 작성(2)
2007/01/10  

 계속해서 Flex 애플리케이션에 필요한 라이브러리와 Cairngorm Framework의 라이브러리를 프로젝트에 복사합니다. 여기도 로그인 샘플을 움직였을 때의 순서와 같지만 4.의 작업이 새로 추가되었으므로 잊어서는 안됩니다.

  1. Flex를 인스톨한 디렉토리(Windows 환경의 경우, C:\Program Files\Macromedia\Flex 등)에 있는 flex.war를 풀어서 Web-INF 아래의 전부를 cairngorm-sample/Web Content/Web-INF에 덮어써서 복사합니다
  2. Cairngorm Framework의 zip 파일(cairngorm-0.99.zip)을 풀어서 생긴 있던 디렉토리의 bin 디렉토리에 있는 cairngorm.swc를 cairngorm-sample/Web Content/Web-INF/flex/user_classes에 둔다
  3. 동일하게 bin 디렉토리에 있는 cairngorm-manifest.xml를 cairngorm-sample/Web Content/Web-INF/flex에 둔다
  4. cairngorm-sample/Web Content/Web-INF/flex 디렉토리에 있는 flex-config.xml에 Cairngorm Framework를 사용하기 위한 이름 공간을 아래의 리스트와 같이 추가한다(97행째 부근)

리스트 1 flex-config.xml(발췌)

<namespaces>
     <namespace uri="http://www.macromedia.com/2003/mxml">
         <manifest>/Web-INF/flex/mxml-manifest.xml</manifest>
     </namespace>
    <!-- Cairngorm의 이름 공간을 추가  -->
     <namespace uri="http://www.iterationtwo.com/
cairngorm">
(본래는 1행)
         <manifest>/Web-INF/flex/cairngorm-manifest.xml
</manifest>
(본래는 1행)
     </namespace>

</namespaces>

XML이름 공간

XML 이름 공간은 1개의 XML 문서 속에서 여러개의 schema를 사용할 수 있도록 하기 위한 구조입니다. 예를 들면, A schema와 B schema의 양쪽 모두에 hoge라는 같은 이름의 태그가 존재하는 경우 <hoge>라고 기술해도 그것이 어느 쪽의 schema에 속하는 태그인지 식별할 수 없습니다.

이름 공간을 사용하면 <A:hoge>, <B:hoge> 등과 같이 각각의 schema를 구별하여 기술할 수 있기 때문에 같은 이름의 태그가 있어도 한번에 식별할 수 있습니다. 이 태그를 식별하기 위한 정보가 URI입니다. Flex에서는 flex-config.xml의 namespaces 태그 내에 URI를 다시 선언 파일(XML 파일)로 연결시킵니다.

XML의 schema를 기술하는 방식으로는 종래 DTD(Document Type Definition)이 사용되었지만 DTD는 이름 공간을 지원하지 않기 때문에 최근에는 이름 공간을 지원하는 XML Schema라는 기술 방식이 많이 사용되고 있습니다. XML Schema는 W3C에 책정되어 있어서 이름 공간에 대해서는 Namespaces in XML이라는 사양이 있습니다.

 마지막으로 지금부터 만들 MXML이나 Action Script의 파일을 저장하기 위한 디렉토리를 작성합니다. 우선, cairngorm-sample/Web Content 바로 아래에 sample라는 디렉토리를 작성합니다. 그 다음으로 그 sample 디렉토리 안에 business, commands, control, model, view, vo의 6개의 디렉토리를 작성합시다. 이 디렉토리 구성은 로그인 샘플의 그것과 같습니다.

 이것으로 샘플 애플리케이션용 프로젝트의 작성은 완료되었습니다. 이 때 프로젝트의 구성이 아래와 같은지 확인하도록 합니다.

화면 3 프로젝트의 구성



3. 샘플 애플리케이션의 사양
2007/01/10  

샘플 애플리케이션의 사양

 프로젝트의 작성이 완료되었다면 지금부터 샘플 애플리케이션의 작성에 들어갑니다 .이번 작성하는 샘플 애플리케이션은, 애플리케이션 서버의 검색/추가/갱신/삭제를 실시하는 간단한 것입니다.화면의 완성 이미지는, 아래와 같이 됩니다.

화면 4 화면의 완성 이미지

 구체적으로는 제품 코드로 애플리케이션 서버를 검색하여 해당의 애플리케이션 서버를 데이터 그리드에 표시합니다. 데이터 그리드의 표시 항목은 제품 코드, 제품명, 벤더, 가격, 비고의 5개입니다. 데이터 그리드 아래에는 이들 5개 항목의 텍스트 인풋이 있으며 데이터 그리드의 행을 선택하면 텍스트 인풋에 선택된 애플리케이션 서버의 정보를 표시합니다.

 이 텍스트 인풋의 정보를 수정하여 갱신 버튼을 누르면 애플리케이션 서버의 정보를 갱신합니다. 또, 데이터 그리드의 행이 선택된 상태에서 삭제 버튼을 누르면 해당 애플리케이션 서버를 삭제합니다. 새로운 애플리케이션 서버를 추가하고 싶을 때는 텍스트 인풋에 애플리케이션 서버의 정보를 입력하여 추가 버튼을 누릅니다.

 실제의 검색/추가/갱신/삭제의 각 처리는 서버 사이드의 서비스(Remote Object)로서 구현합니다.




4. View(MXML)의 작성
2007/01/10  

View(MXML)의 작성

 그러면, 우선 화면인 View(MXML)부터 작성합니다. 아래의 리스트는 샘플 애플리케이션의 View인 APServerList.mxml입니다. 이것을 cairngorm-sample/Web Content/sample/view에 작성하도록 합시다.

리스트 2 APServerList.mxml

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
   xmlns:view="sample.view.*"
   xmlns:business="sample.business.*"
   xmlns:control="sample.control.*"

   pageTitle="Flex 샘플 애플리케이션" marginTop="20" horizontalAlign="
center">(본래는 1행)

   <!-- ViewHelper -->
   <view:APServerListViewHelper id="apServerList
ViewHelper" />
(본래는 1행)

   <!-- ServiceLocator -->
   <business:SampleappServices id="sampleappServices" />

   <!-- Controller -->
   <control:SampleappControl id="sampleappController" />


   <mx:Panel title="Flex샘플 애플리케이션"
     height="600" width="800" marginTop="10" marginLeft="20">

     <mx:Script>
       <![CDATA[

       import sample.model.SampleappModelLocator;

       ]]>
     </mx:Script>

     <mx:Label text="JavaEE 웹애플리케이션 서버 일람" fontSize="12" />

     <mx:HBox horizontalAlign="center" marginTop="10" >
       <mx:Label text="제품 코드" />
       <mx:TextInput id="searchCond" width="50" maxChars="3" />
       <mx:Button label="검색" click="apServerList
ViewHelper.searchAPServer();" />
(본래는1행)
     </mx:HBox>

     <mx:DataGrid id="dg" rowCount="10" dataProvider="
{SampleappModelLocator.apServerListModel}">
(본래는1행)
       <mx:columns>
         <mx:Array>
           <mx:DataGridColumn columnName="productCode" headerText=
"제품 코드" width="60" textAlign="center"/>(본래는 1행)
           <mx:DataGridColumn columnName="productName" headerText=
"제품명" width="200" />(본래는 1행)
           <mx:DataGridColumn columnName="vendor" headerText=
"벤더" width="200" />(본래는 1행)
           <mx:DataGridColumn columnName="price" headerText="가격"
width="80" textAlign="right" />(본래는 1행)
           <mx:DataGridColumn columnName="note" headerText="비고"
width="180" />(본래는 1행)
         </mx:Array>
       </mx:columns>
     </mx:DataGrid>

     <mx:Form>
       <mx:FormItem label="제품 코드">
         <mx:TextInput id="productCode" width="50" maxChars="3"
text="{dg.selectedItem.productCode}" />(본래는 1행)
       </mx:FormItem>
       <mx:FormItem label="제품명">
         <mx:TextInput id="productName" width="200" maxChars="20"
  text="{dg.selectedItem.productName}" />(본래는 1행)
       </mx:FormItem>
       <mx:FormItem label="벤더">
         <mx:TextInput id="vendor" width="200" maxChars="20"
text="{dg.selectedItem.vendor}" />(본래는 1행)
       </mx:FormItem>
       <mx:FormItem label="가격">
         <mx:TextInput id="price" width="80" maxChars="8"
text="{dg.selectedItem.price}" />(본래는 1행)
       </mx:FormItem>
       <mx:FormItem label="비고">
         <mx:TextInput id="note" width="200" maxChars="20"
text="{dg.selectedItem.note}" />(본래는 1행)
       </mx:FormItem>
       <mx:FormItem>  
         <mx:HBox>
         <mx:Button label="추가" click="apServerList
ViewHelper.registAPServer();" />
(본래는1행)
         <mx:Button label="갱신" click="apServerListViewHelper.updateAPServer();" />
(본래는 1행)
         <mx:Button label="삭제" click="apServerListViewHelper.removeAPServer();" />
(본래는 1행)
         </mx:HBox>
       </mx:FormItem>
     </mx:Form>

   </mx:Panel>
</mx:Application>

 이 MXML은 완성 이미지에서 보았던 화면에 대응하는 것입니다. 라벨, 텍스트 인풋, 버튼, 데이터 그리드 등, 화면을 구성하는 컴포넌트를 배치하였습니다.

 그리고, Cairngorm Framework를 사용하기 위해서 ViewHelper, ServiceLocator, Controller를 <mx:Application> 태그 아래에서 인스턴스화하였습니다. <mx:Application> 태그에서는 view, business, control의 각 패키지에 대해서 이름 공간을 설정하였습니다. 이름 공간을 설정하려면 xmlns:프리픽스=”URI”라는 기술을 합니다. 이렇게 함으로써 그 URI에 속하는 태그를 프리픽스:태그 명이라는 형식으로 표기할 수 있습니다. MXML 태그는 URI를 지정하여 이름 공간을 설정하였는데, view, business, control에 대해서는 URI가 아니라 패키지를 지정하였습니다. URI 부분에 패키지를 지정함으로써 해당 패키지에 속하는 클래스를 view:APServerListViewHelper와 같이 지정할 수 있습니다.

 <mx:Script>태그에서는 로그인 샘플과 같이 ModelLocator를 임포트하였습니다. ModelLocator의 apServerListModel 속성은 검색 결과의 애플리케이션 서버의 정보를 보관 유지하고 있는 속성이며 데이터 그리드에 데이터 바인딩하였습니다.

 검색, 추가, 갱신, 삭제의 각 버튼에 대해서는 버튼이 클릭되었을 때에 각각 ViewHelper의 메소드를 호출하도록 하고 클릭되었을 때의 구체적인 처리는 View가 아닌 ViewHelper쪽으로 구현하도록 하였습니다.

MXML컴포넌트의 인스턴스화

 MXML 컴포넌트는 <mx:XXX>라는 태그를 씀으로써 인스턴스화 합니다. Flex에 준비되어 있는 MXML 태그는 모두 Action Script의 클래스에 대응하고 있기 때문에 내부적으로는 Action Script의 클래스를 생성하였습니다. ViewHelper나 Controller 등도 이와 같이 태그로 기술함으로써 인스턴스화 합니다.




5. ViewHelper의 작성
2007/01/11  

ViewHelper의 작성

 다음으로 ViewHelper를 작성합니다. 아래의 리스트는 샘플 애플리케이션의 ViewHelper인 APServerListViewHelper.as입니다.이것을 cairngorm-sample/WebContent/sample/view에 작성해 주세요.

리스트 3 APServerListViewHelper.as

import org.nevis.cairngorm.view.ViewHelper;
import org.nevis.cairngorm.control.EventBroadcaster;
import sample.control.SampleappControl;
import sample.vo.APServerVO;

class sample.view.APServerListViewHelper extends ViewHelper {

     public function searchAPServer() {
         var searchCond : String = view.searchCond.text;

         EventBroadcaster.getInstance().broadcastEvent(Sampl
eappControl.EVENT_APSERVER_SEARCH, searchCond);(본래는 1행)
     }
   
     public function registAPServer() {
         var apServerVO : APServerVO = new APServerVO();
         apServerVO.productCode = view.productCode.text;
         apServerVO.productName = view.productName.text;
         apServerVO.vendor = view.vendor.text;
         apServerVO.price = view.price.text;
         apServerVO.note = view.note.text;

         EventBroadcaster.getInstance().broadcastEvent(Sampleapp
Control.EVENT APSERVER_REGIST, apServerVO);(본래는 1행)

         view.dg.addItem( {productCode: view.productCode.text,
productName: (본래는 1행)
view.productName.text, vendor: view.vendor.text, price: view.
price.text, note: view.note.text} );(본래는 1행)
     }

     public function updateAPServer() {
         if (view.dg.selectedIndex == undefined) {
             mx.controls.Alert.show('갱신하는 행이 선택되고
있지 않습니다.', '소식');(본래는 1행)
             return;
         }

         var apServerVO : APServerVO = new APServerVO();
         apServerVO.productCode = view.dg.selectedItem.
productCode;(본래는 1행)
         apServerVO.productName = view.productName.text;
         apServerVO.vendor = view.vendor.text;
         apServerVO.price = view.price.text;
         apServerVO.note = view.note.text;

         EventBroadcaster.getInstance().broadcastEvent
(SampleappControl.EVENT APSERVER_UPDATE, apServerVO);(본래는 1행)

         view.dg.replaceItemAt(view.dg.selectedIndex,
  {productCode: view.dg.selectedItem.productCode, productName:
  view.productName.text, vendor: view.vendor.text, price: 
view.price.text, note: view.note.text} );(본래는 1행)
     }

     public function removeAPServer() {
         if (view.dg.selectedIndex == undefined) {
             mx.controls.Alert.show('삭제하는 행이 선택되고 있지 않습니다.
', '소식');(본래는 1행)
             return;
         }

         var selectedNo : String = view.dg.selectedItem.
productCode;        EventBroadcaster.getInstance().broadcast
Event(SampleappControl.EVENT_APSERVER_REMOVE, selectedNo);
(본래는 1행)

         view.dg.removeItemAt(view.dg.selectedIndex);
         clearInputFields();
     }

     private function clearInputFields() {
         view.productCode.text = "";
         view.productName.text = "";
         view.vendor.text = "";
         view.price.text = "";
         view.note.text = "";
     }
}

 ViewHelper는 Cairngorm Framework의 ViewHelper 클래스를 계승해 작성합니다.ViewHelper로 구현하는 처리는 화면의 검색 버튼, 추가 버튼, 갱신 버튼, 삭제 버튼을 각각 눌렀을 때의 처리입니다.

 검색 버튼을 눌렀을 때에는 searchAPServer 메소드가 호출됩니다. 이 메소드에서는 화면의 검색 조건(제품 코드)을 입력하는 텍스트 인풋에서 값을 취득하고 EventBroadcaster 클래스의 broadcastEvent 메소드를 사용하여 이벤트를 발생시킵니다. 전 회에 설명한 바와 같이 broadcastEvent 메소드의 제1 인수에는 발생시키고 싶은 이벤트명을, 제2 인수에는 커맨드 클래스에 건네주고 싶은 데이터를 지정합니다. 여기에서는 Controller 클래스에 정의한 검색 이벤트와 화면으로부터 취득한 검색 조건을 인수에게 건네었습니다.

 추가, 갱신 버튼을 눌렀을 때는 각각 registAPServer 메소드와 updateAPServer 메소드가 호출됩니다. 이러한 메소드 중에서는 각각 ValueObject의 속성에 화면의 입력값를 설정하고 EventBroadcaster 클래스의 broadcastEvent 메소드를 사용하여 이벤트를 발생시킵니다. 그 후, 데이터 그리드에 대해서 등록된 행의 추가나 갱신된 행의 치환을 실시하고 있습니다. 또, 행을 선택하지 않고 갱신 버튼을 눌렀을 경우에는 경계체제 메세지를 표시하도록 합니다.

 삭제 버튼을 눌렀을 때는 removeAPServer 메소드가 호출됩니다. 이 메소드에서는 데이터 그리드에서 선택된 애플리케이션 서버의 제품 코드를 취득하고 다른 버튼을 눌렀을 때의 처리와 동일하게 EventBroadcaster 클래스의 broadcastEvent 메소드를 사용하여 이벤트를 발생시켰습니다. 그 후, 데이터 그리드로부터 선택된 행을 삭제하고 텍스트 인풋의 입력 구역을 비웠습니다. 갱신 버튼을 눌렀을 때의 처리와 동일하게 행을 선택하지 않고 삭제 버튼을 눌렀을 경우에는 경계체제 메세지를 표시하도록 합니다.





6. ValueObject의 작성
2007/01/11  

ValueObject의 작성

 계속해서 ValueObject를 작성합니다. 아래의 리스트는 샘플 애플리케이션의 ValueObject인 APServerVO.as입니다. 이것을 cairngorm-sample/WebContent/sample/vo에 작성합니다.

리스트 4 APServerVO.as

import org.nevis.cairngorm.vo.ValueObject;

class sample.vo.APServerVO implements ValueObject {

     public static var registered:Boolean = Object.
registerClass("sample.vo.APServerVO", APServerVO);
(본래는 1행)

     public var productCode : String;

     public var productName : String;

     public var vendor : String;

     public var price : String;

     public var note : String;
}

 ValueObject는 Cairngorm Framework의 ValueObject 인터페이스를 구현하여 작성합니다. 여기에서는 제품 코드, 제품명, 벤더, 가격, 비고의 5개를 모두 String형의 속성으로서 정의하였습니다. 또한, 로그인 샘플에서는 구현되고 있던 toString 메소드는 구현이 필수는 아니기 때문에 이 샘플에서는 생략하였습니다.

 ValueObject는 서버 사이드에서도 사용하므로 이 Action Script의 클래스에 대응하는 Java의 클래스도 필요합니다. 아래의 리스트는 위의 Action Script에 대응하는 Java의 ValueObject입니다. 이것을 cairngorm-sample/src/sample/vo에 작성해 주세요.

리스트 5 APServerVO.java

package sample.vo;

import java.io.Serializable;

public class APServerVO implements Serializable {

     private String productCode;

     private String productName;
     private String vendor;

     private String price;

     private String note;

     // 이하, getter/setter는 생략(각각 추가하십시오)

}

 Action Script의 ValueObject는 서버 사이드에게 건네지면 Flex의 구조에 의해서 자동적으로 Java의 클래스에 변환됩니다(그림 1 참조).

 그 변환을 하기 위해서는 전 회의 로그인 샘플에서도 조금 접했었는데 Object 클래스의 registerClass 메소드를 이용하여 ActionScript와 Java의 클래스를 매핑 해 둘 필요가 있습니다. 이 메소드의 제1 인수에는 Java 클래스의 완전 수식명, 제2 인수에는 Action Script의 클래스명을 지정합니다.

그림 1 Action Script와 Java의 데이터형 변환

 변환을 적절히 실시하기 위해서는 그 외에도 아래와 같은 룰이 있기 때문에 주의해야 합니다.

  • Action Script 클래스와 Java 클래스의 필드명은 대문자 소문자도 맞추어 같게 만든다
  • Action Script의 데이터형을 Java 클래스의 데이터형에 대응하도록 한다(대응표에 대해서는 Flex의 문서를 참조)
  • 필수는 아니지만 Action Script 클래스와 Java 클래스의 패키지는 가능한 한 갖추도록 한다



7. Controller의 작성
2007/01/11  

Controller의 작성

 다음으로 Controller를 작성합니다. 아래의 리스트는 샘플 애플리케이션의 Controller인 SampleappControl.as입니다. 이것을 cairngorm-sample/WebContent/sample/control에 작성하도록 합니다.

리스트 6 SampleappControl.as

import org.nevis.cairngorm.control.FrontController;
import sample.commands.APServerSearchCommand;
import sample.commands.APServerRegistCommand;
import sample.commands.APServerUpdateCommand;
import sample.commands.APServerRemoveCommand;

class sample.control.SampleappControl extends FrontController {

     public static var EVENT_APSERVER_SEARCH = "apserver_search";

     public static var EVENT_APSERVER_REGIST = "apserver_regist";

     public static var EVENT_APSERVER_UPDATE = "apserver_update";

     public static var EVENT_APSERVER_REMOVE = "apserver_remove";

     public function SampleappControl() {
         addCommand(SampleappControl.EVENT_APSERVER_SEARCH, new
APServerSearchCommand());(본래는 1행)
         addCommand(SampleappControl.EVENT_APSERVER_REGIST, new
APServerRegistCommand());(본래는 1행)
         addCommand(SampleappControl.EVENT_APSERVER_UPDATE, new
APServerUpdateCommand());(본래는 1행)
         addCommand(SampleappControl.EVENT_APSERVER_REMOVE, new
APServerRemoveCommand());(본래는 1행)
}

 Controller는 Cairngorm Framework의 FrontController 클래스를 계승하여 작성합니다. Controller 클래스에서 구현해야 할 것은 이벤트명을 정의하는 것과 그 이벤트가 일어났을 때 호출하고 싶은 커맨드를 이벤트명으로 대응시켜서 등록하는 것의 2가지입니다.

 여기에서는 화면의 버튼을 눌렀을 때 각각 발생하는 검색/등록/갱신/삭제의 각 이벤트를 클래스 변수로서 정의하였습니다. 그 아래의 constructor에서는 부모 클래스의 addCommand 메소드를 사용하여 커맨드 클래스의 인스턴스를 이벤트에 대응시켜 등록하였습니다.





8. Command의 작성
2007/01/11  

Command의 작성

 계속해서 Command를 작성합니다. 아래의 4개의 리스트는 샘플 애플리케이션의 Command입니다. Command는 검색/등록/갱신/삭제의 각 이벤트에 대응하여 4개가 있습니다. 이것을 cairngorm-sample/WebContent/sample/commands에 작성합니다.

리스트 7 APServerSearchCommand.as

import org.nevis.cairngorm.business.Responder;
import org.nevis.cairngorm.commands.Command;
import org.nevis.cairngorm.control.Event;
import sample.business.SampleappBusinessDelegate;
import sample.model.SampleappModelLocator;

class sample.commands.APServerSearchCommand implements
Command, Responder {(본래는 1행)

     public function execute(event:Event) : Void {
         var delegate: SampleappBusinessDelegate = new
SampleappBusiness(본래는 1행)
Delegate(this);(본래는 1행)
         var searchCond : String = String(event.data);
         delegate.searchAPServer(searchCond);
     }

     public function onResult(event : Object) : Void {
         SampleappModelLocator.apServerListModel = event.result;
     }

     public function onFault(event : Object) : Void {
         mx.controls.Alert.show(event.fault.faultstring,
'에러');(본래는 1행)
     }
}

리스트 8 APServerRegistCommand.as

import org.nevis.cairngorm.business.Responder;
import org.nevis.cairngorm.commands.Command;
import org.nevis.cairngorm.control.Event;
import sample.business.SampleappBusinessDelegate;
import sample.vo.APServerVO;

class sample.commands.APServerRegistCommand implements
Command, Responder {(본래는 1행)

     public function execute(event:Event) : Void {
         var delegate: SampleappBusinessDelegate = new
SampleappBusiness Delegate(this);(본래는 1행)
         var apServerVO : APServerVO = APServerVO
(event.data);(본래는 1행)
         delegate.registAPServer(apServerVO);
     }

     public function onResult(event : Object) : Void {
         mx.controls.Alert.show('등록했습니다.', '소식');
     }

     public function onFault(event : Object) : Void {
         mx.controls.Alert.show(event.fault.faultstring,
'에러');(본래는 1행)
     }
}

리스트 9 APServerUpdateCommand.as

import org.nevis.cairngorm.business.Responder;
import org.nevis.cairngorm.commands.Command;
import org.nevis.cairngorm.control.Event;
import sample.business.SampleappBusinessDelegate;
import sample.vo.APServerVO;

class sample.commands.APServerUpdateCommand implements
Command, Responder {(본래는 1행)

     public function execute(event:Event) : Void {
         var delegate: SampleappBusinessDelegate = new
SampleappBusinessDelegate(this);(본래는 1행)
         var apServerVO : APServerVO = APServerVO(event.data);
         delegate.updateAPServer(apServerVO);
     }

     public function onResult(event : Object) : Void {
         mx.controls.Alert.show('갱신했습니다.', '소식') ;
     }

     public function onFault(event : Object) : Void {
         mx.controls.Alert.show(event.fault.faultstring, '에러');
     }
}

리스트 10 APServerRemoveCommand.as

import org.nevis.cairngorm.business.Responder;
import org.nevis.cairngorm.commands.Command;
import org.nevis.cairngorm.control.Event;
import sample.business.SampleappBusinessDelegate;

class sample.commands.APServerRemoveCommand implements Command,
Responder {(본래는 1행)

     public function execute(event:Event) : Void {
         var delegate: SampleappBusinessDelegate = new
  SampleappBusiness(본래는 1행)
Delegate(this);(본래는 1행)
         var selectedNo : String = String(event.data);
         delegate.removeAPServer(selectedNo);
     }

     public function onResult(event : Object) : Void {
         mx.controls.Alert.show('삭제했습니다.', '소식') ;
     }

     public function onFault(event : Object) : Void {
         mx.controls.Alert.show(event.fault.faultstring, '에러') ;
     }
}

 Command는 Cairngorm Framework의 Command 인터페이스와 Responder 인터페이스를 구현하여 작성합니다. Command 인터페이스에서는 execute 메소드가, Responder 인터페이스에는 onResult와 onFault 메소드가 정의되어 있기 때문에 각각의 Command 클래스에서는 이것들 3개의 메소드를 구현합니다.

 execute 메소드에서는 서버 사이드의 서비스(Remote Object)에 액세스하기 위해서 BusinessDelegate를 생성하고 그 메소드를 호출합니다. event의 data 속성에는 이벤트를 발생시켰을 때에 건네준 데이터가 들어가 있으므로 각각 적절한 데이터형에 캐스트하였습니다. .

 onResult 메소드에서는 서버 사이드의 호출에 성공했을 경우의 핸들링을 실시합니다. 검색의 Command에서는 검색 결과를 ModelLocator의 apServerListModel 속성에 유지하도록 하였습니다. 등록/갱신/삭제의 각 Command에서는 단지 메세지를 표시하도록 하고 있을 뿐입니다.

 onFault 메소드에서는 서버 사이드의 호출에 실패했을 경우의 핸들링을 실시합니다. 여기는 모든 Command로 에러 메세지를 표시하도록 하였습니다.




9. ModelLocator의 작성
2007/01/11  

ModelLocator의 작성

 마지막으로 ModelLocator를 작성합니다. 아래의 리스트는 샘플 애플리케이션의 ModelLocator입니다. 이것을 cairngorm-sample/ Web Content/ sample/ model에 작성합니다.

리스트 11 SampleappModelLocator.as

import org.nevis.cairngorm.model.ModelLocator;

class sample.model.SampleappModelLocator implements ModelLocator {

     public static var apServerListModel : Object;

}

 ModelLocator는 Cairngorm Framework의 ModelLocator 인터페이스를 구현해 작성합니다.ModelLocator에서는 화면에서 표시하는 데이터 모델을 자유롭게 정의할 수 있습니다. 여기에서는 데이터 그리드에 표시하는 검색 결과의 데이터 모델을 속성으로 정의하였습니다.

 이상으로 이번 회에는 Cairngorm Framework를 사용하여 샘플 애플리케이션을 작성했습니다. Cairngorm Framework의 흐름을 잊어 버린 독자들은 전 회에 설명한 아키텍쳐의 전체상과 로그인 샘플의 코드를 한번 더 보고 복습해보시기 바랍니다.

 다음 회에는 샘플 애플리케이션의 나머지의 부분(서버 사이드 제휴 부분)을 작성하여 샘플 애플리케이션을 완성시킵니다.