LCDS, BlazeDS, ZendAMF등을 이용해 AMF(ActionScript Message Format)으로 데이터를 주고받는 형태는 이미 많은 예제들과 문서들이 있다. AMF는 데이터 통신을 위한 일종의 약속된 규약이고 이 데이터를 주고 받고 하는 과정에서 서로의 언어에 맞게 직렬화(Serialization)하는 것은 각 언어에서 지원해주는 라이브러리를 사용하면 된다. ActionScript 3.0은 기본 API에서 지원해준다. 자바의 경우는 BlazeDS나 LCDS를 사용하면 된다. PHP의 경우에는 ZendAMF를 사용하면 된다. 이들을 이용하면 가령, 자바와 java.lang.Interger는 ActionScript의 int나 uint로... java.lang.Double은 ActionScript의 Number형과 직렬화된다. 이는 일종의 기본적으로 지원되는 직렬화이다.

다음은 BlazeDS에서 기본적으로 지원되는 직렬화이다.
Serializing between ActionScript and Java

하지만 이런 기본 직렬화과정을 사용하지 않고 직렬화 자체를 커스터마이징(customizing)할 수 있다. 가령 클라이언트(예,Flash 애플리케이션)에서는 아이디, 이름, 속성, 가격의 정보가 중요하지만 서버(예,자바)에서는 재고(inventory)가 중요한 경우가 있다. 이런 경우에는 Flex와 Java쪽의 직렬화하는 클래스를 다음과 같이 디자인 할 수 있겠다.

// Product.as
package samples.externalizable {

import flash.utils.IExternalizable;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;

[RemoteClass(alias="samples.externalizable.Product")]
public class Product implements IExternalizable {
    public function Product(name:String=null) {
        this.name = name;
    }

    public var id:int;
    public var name:String;
    public var properties:Object;
    public var price:Number;

    public function readExternal(input:IDataInput):void {
        name = input.readObject() as String;
        properties = input.readObject();
        price = input.readFloat();
    }

    public function writeExternal(output:IDataOutput):void {
        output.writeObject(name);
        output.writeObject(properties);
        output.writeFloat(price);
    }
}
}


// Product.java
package samples.externalizable;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Map;

/**
* This Externalizable class requires that clients sending and 
* receiving instances of this type adhere to the data format
* required for serialization.
*/
public class Product implements Externalizable {
    private String inventoryId;
    public String name;
    public Map properties;
    public float price;

    public Product()
    {
    }

        /**
        * Local identity used to track third party inventory. This property is
        * not sent to the client because it is server-specific.
        * The identity must start with an 'X'.
        */
        public String getInventoryId() {
            return inventoryId;
        }

        public void setInventoryId(String inventoryId) {
            if (inventoryId != null && inventoryId.startsWith("X"))
            {
                this.inventoryId = inventoryId;
            }
            else
            {
                throw new IllegalArgumentException("3rd party product
                inventory identities must start with 'X'");
            }
        }

        /**
         * Deserializes the client state of an instance of ThirdPartyProxy
         * by reading in String for the name, a Map of properties
         * for the description, and 
         * a floating point integer (single precision) for the price. 
         */
        public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
            // Read in the server properties from the client representation.
            name = (String)in.readObject();
            properties = (Map)in.readObject();
            price = in.readFloat();
            setInventoryId(lookupInventoryId(name, price));
        }
        /**
         * Serializes the server state of an instance of ThirdPartyProxy
         * by sending a String for the name, a Map of properties
         * String for the description, and a floating point
         * integer (single precision) for the price. Notice that the inventory 
         * identifier is not sent to external clients.
         */
        public void writeExternal(ObjectOutput out) throws IOException {
            // Write out the client properties from the server representation
            out.writeObject(name);
            out.writeObject(properties);
            out.writeFloat(price);
        }
        
        private static String lookupInventoryId(String name, float price) {
            String inventoryId = "X" + name + Math.rint(price);
            return inventoryId;
        }
}

위 코드는 ActionScript의 flash.utils.IExternalizable 인터페이스와 Java의 java.io.Externalizable 인터페이스를 이용해 기본직렬화를 무시하고 이들 인터페이스에 정의된 readExternal와 writeExternal 메소드를 호출하여 직렬화 자체를 커스터마이징 할 수 있다는 것을 의미한다. Externalizable 인터페이스를 구현한 클래스에 정의된 메소드가 기본 직렬화보다 우선순위가 높다는 것을 기억하면 되겠다.

Flex의 ArrayCollection을 다시 한번 보기 바란다. 이 클래스는 flash.utils.IExternalizable를 구현했다.
mx.collections.ArrayCollection

꼭 이런 경우만은 아니다. 쓸데없는 데이터의 크기를 줄이기 위한 방법도 해당한다. 예를들어 ActionScript 코드를 보면 다음과 같다.


class Example implements IExternalizable {
  
      public var one:Boolean;
      public var two:Boolean;
      public var three:Boolean;
      public var four:Boolean;
      public var five:Boolean;
      public var six:Boolean;
      public var seven:Boolean;
      public var eight:Boolean;
       public function writeExternal(output:IDataOutput) {
           var flag:int = 0;
           if (one) flag |= 1;
          if (two) flag |= 2;
          if (three) flag |= 4;
          if (four) flag |= 8;
          if (five) flag |= 16;
          if (six) flag |= 32;
          if (seven) flag |= 64;
          if (eight) flag |= 128;
           output.writeByte(flag);
      }
       public function readExternal(input:IDataInput) {
           var flag:int = input.readByte();
           one = (flag & 1) != 0;
          two = (flag & 2) != 0;
          three = (flag & 4) != 0;
          four = (flag & 8) != 0;
          five = (flag & 16) != 0;
          six = (flag & 32) != 0;
          seven = (flag & 64) != 0;
          eight = (flag & 128) != 0;
      }
 }

데이터 통신을 위해 쓸데없이 Boolean객체를 주고 받을 필요없다. 위 코드처럼 직렬화를 커스터마이징한다면 송수신 데이터 자체의 크기도 줄일 수 있다. 이는 매우 유용하다.


참고글
flash.utils.IExternalizable
커스텀 직렬화의 사용
ActionScript 3.0 데이터 유형 및 직렬화(serialization)
Serializing between ActionScript and Java
AMF 3 스팩
AS3 BitmapData AMF solution using IExternalizable
Flex and PHP: remoting with Zend AMF

글쓴이 : 지돌스타(http://blog.jidolstar.com/644)

어제 무사히 Flex 기술세미나를 마쳤습니다.

(비트기술세미나라고 명칭되어 있었네요. 그게 좀 전달이 안된 것 같네요.)

 

무려 200개의 자리를 꽉 채울 정도로 많은 분들이 밤 늦은 시간까지 경청하시고 가셨습니다. 정말 수고 많으셨어요. ^^

 

세미나에서 옥상훈님께서는 UX(User Experience)에 대해서 매우 자세히 잘 말씀해주셨습니다. UX에 대해 다시 한번 생각해보는 계기가 되었구요. 또 배준균님께서 BlazeDS에 대해 현업에서 어떻게 쓰일지에 대해서 자세히 말씀해 주셨습니다. 아쉽게도 인터넷이 잘 안되어서 난감해 하셨는데... 알고보니 그거 유동IP가 아니라 고정IP였다는... ^^

 

저는 Flex 4에 대해 설명드렸습니다. 사실 저도 Flex 4를 공부한다는 마음을 가지고 이번 세미나 주제로 다룬겁니다. 덕분에 저도 열심히 공부할 수 있었고 많은 분들에게 Flex 4에 대해서 처음으로 소개할 수 있게 되어서 기분도 좋았답니다. 하지만 시간이 촉박해서 마지막에 질의시간을 가지지 못한 것 죄송합니다.

 

Flex 4에 대해 잠깐 언급했고 Flex 4를 이용해서 개발하는 툴인 Flash Builder 4와 Flash Catalyst에 대해서 소개했습니다. CSS, FXG, Namespace, State, Data Binding, Effect, None Visual Component 다루는 법, Spark Component와 Spark Layout 등에 대해서 약간 맛배기 정도로 다뤘습니다. 사실 소개드린 하나하나가 무거운 주제로 다루어도 몇시간씩은 해야하는 것들입니다. 그러므로 더 깊이 있는 공부를 위해서 관련 내용을 프리젠테이션에 있는 링크를 보시고 습득하시길 바래요.


아래 파일은 어제 발표했던 프리젠테이션 파일입니다.


 

아래 파일들은 어제 다뤘던 예제입니다.

 

invalid-file

출처 : http://evtimmy.com/2009/06/wheellayout-source-and-quick-mashup/

 

아래 두개는 시간이 없어서 소개하지 못한것인데 Flex 4를 이용해 컴포넌트를 만든 예제입니다. (제가 만든거 아닙니다. ^^)

invalid-file

출처 : http://www.hulstkamp.com/2009/07/09/custom-popup-rating-component-in-spark-flex-4-gumbo/464

invalid-file

참고 : http://blog.jidolstar.com/570

 

위 예제를 실험하기 위해서는 Flash Builder 4를 다운 받아야겠지요?
http://www.adoberia.co.kr/pds/down.html?src=text&kw=000026 

위의 예제는 Flash Builder 4에서 import 해서 사용할 수 있는데 다음과 같이 해보세요.

  1. Flash Builder 4를 실행
  2. File > New > Flex Project를 통해 Project를 생성
  3. File > Import > Other 선택
  4. 새창이 뜨면 General > Archive File 선택 후 Next 버튼 클릭
  5. "From archive file"에서 Browse 버튼을 클릭하여 위 Zip파일중 하나를 선택
  6. "Into folder" 에서 Browse 버튼을 눌러 새로 생성한 프로젝트를 선택후 Finish 버튼 클릭 (진행도중 Overwrite 경고 뜨면 모두 Overwrite합니다.)
  7. src 폴더에 들어간 mxml파일은 모두 Application입니다. 이중 하나를 열고 Run 메뉴에서 실행하거나 Ctrl+F11로 실행하면 되겠습니다.

 

다른 분의 자료는 http://okgosu.net 에서 제공이 될겁니다.

 

개인적인 소망이 있습니다. 많은 분들이 제 블로그를 통해 Flex 관련자료를 접하고 계신것 잘 알고 있습니다. 하지만 저도 다른 사람들을 통해서 많이 배우고 싶은 사람입니다. 서로 소통이 되어야 진정으로 정보공유라고 생각하고 바람직한 방향이라고 생각해요. 앞으로 Flex 4든 Flash Platform에 대한 어떤 자료든지 아시는 것있다면 함께 공유해서 함께 커갔으면 합니다. 어짜피 기술이라는 것은 시간이 지나면 또 바뀌고 사라질 수도 있잖아요? 자기만 알고 있다고 해서 다 좋은 것은 아니라는 겁니다. Flex 5, Flex 6가 나올때도 한국에서 한국 블로거 또는 카페등을 통해 매일 피상적인 정보만 얻어가는 정도나 질문에만 답해야하는 그런 상황이 반복된다면 정말 암울할 것 같아요. 정보생산의 주체가 적어도 어제 참석한 분들의 수만 되도 한국의 IT 미래는 매우 밝아질 것입니다.

 

 

012345

 

글쓴이 : 지돌스타(http://blog.jidolstar.com/579)

후기 : http://blog.jidolstar.com/579

내일 okgosu.net Flex 세미나가 있습니다.

자세한 내용은 다음과 같습니다.

 

■ 주제:
1. Flex 활용 UX 구현 테크닉
2. BlazeDS 활용
3. Flex 4의 새로운 기능

■ 대상 : 웹전산학관련 학과생 및 졸업생, IT분야 종사자, 플렉스 개발자

■ 내용
1. Flex 활용 UX 구현 테크닉
- UX 개요
- Flex UX 기획 및 설계
- UX를 위한 Flex 테크닉
2. BlazeDS 활용
- BlazeDS의 개요
- BlazeDS의 주요 기능
- LCDS와 BlazeDS의 차이
- Flex 연동 방법
3. Flex 4의 새로운 기능
- Flex 3와의 차이점
- Flex 4의 새로운 기능
- Flex의 비전

■ 일시 : 2009년 8월 13일(목요일) 19:00~ 22:00

■ 장소 :  비트교육센터 지하 2층 멀티미디어관(서울 서초구 서초 2동 1327-15 비트아카데미빌딩)

주차지원안됨

지하철 2호선 강남역 3번 출구 삼성화재 건물까지 직진 후,
오른쪽 골목길로 50M 가량 직진하면 우측에 일식집 “일조수사” 건물

■ 형식 : 전문강사의 세미나와 질의 응답

■ 시간별 진행일정
오프닝: 19:00 ~ 19:10
세션1: 19:10~20:00 Flex를 활용한 UX 구현 테크닉 - 옥상훈
세션2: 20:10~21:00 BlazeDS 활용 - 배준균
세션3: 21:10~22:00 Flex 4 새로운 기능 - 지용호

■ 강사소개

옥상훈
OkGosu.Net 운영자
한국SW아키텍트 연합회장
예제로 배우는 플렉스 저자
전 한국 Adobe 컨설턴트
배준균
Adobe Community Champion
한국 키스코 플렉스 개발팀장
지용호
Adobe Community Champion
flexdocs.kr 운영자
위콘 커뮤니케이션 UI 개발팀장


■ 후원
OkGosu.Net

 

접수는 http://www.bitacademy.com/etc/semina_info.asp  에서 하시면 됩니다.

 

아참~ 참석비용 없습니다.

 

Adobe RIA에 대한 정보에 대한 소통의 도구로 네이버 오픈캐스트를 개설했습니다. Flex, Flash, ActionScript 3.0을 주로 다룰 것이고 그와 관련된 LCDS, BlazeDS, ColdFusion등, 다양한 Adobe RIA와 관련된 기술도 공유하고자 합니다.

 

제 오픈 케스트에 올라왔으면 하는 글 있으면 언제든지 추천해주시고요.

구독도 많이 해주세요~~~

더욱 좋은 정보 공유를 위해 앞장서도록 노력하겠습니다. ^^

 

지금 생각하는 주제를 몇가지 적어보면

한글문제, 3D, 컴포넌트 제작, 보안, Stratus, Alchemy, LCDS, BlazeDS, CF.... , 또... 이들에 대한 세부 주제까지... 정말 많네요. ㅎㅎ

 

지돌스타의 Adobe RIA 오픈캐스트 : http://opencast.naver.com/FL188

 

 

이 글은 ActionScript 3.0 프로젝트에서 BlazeDS와 통신하는 환경을 배경으로 한다.  Flex MXML를 배제하고 단지 Flex에 제공되는 RPC, 리모팅 관련 클래스를 사용하고자 한다. Flex MXML를 배제하는 이유는 다음과 같다.

 

Flex SDK의 Visual 컴포넌트들은 일반 솔루션 제품을 개발하는데 매우 유용하지만 어떤 경우에는 프로그램의 용량과 퍼포먼스 향상에는 도움이 안될 수 있다. 가령, Flex SDK에서 제공하는 Button과 List만 사용한다고 가정하자. 이 컴포넌트만 사용하는데도 불구하고 Flex 컴파일러는 그와 관련된 클래스까지 함께 컴파일해서 프로그램 용량을 크게 한다. 또한 Visual 컴포넌트들은 커다란 프레임워크로 만들어져 있기 때문에 Sprite만을 이용해서 만든 프로그램보다 퍼포먼스가 떨어진다.

 

물론 Flex에서 제공하는 컴포넌트를 적극적으로 다양하게 사용할 필요가 있다면 개발 효율성 및 유지보수 측면에서 Flex 프로젝트로 개발해야한다. 하지만 겨우 컴포넌트 몇개만 가져다가 사용하는 경우에는 Flex로 개발하는 것이 오히려 프로그램의 질을 떨어뜨릴 수 있는 결과를 초래할 수 있게 된다.(Flex가 나쁘다는 것이 아니라 필요에 맞게 사용해야한다는 것을 언급하는 것임을 강조한다.)  

 

Flex 환경에서 AMF3 통신

 

다음 예를 보자.

 

아래처럼 Flex 프로젝트로 만들어 Release 버전으로 컴파일 하게 되면 262kb가 나온다. 매우 단순한 프로그램인데도 불구하고 용량이 꽤 크다. 이유는 앞서 설명했다.

 

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:RemoteObject id="ro" destination="my-dest" showBusyCursor="true">
		<mx:method
			name="getData"
			result="returnHandler(event)"
			fault="mx.controls.Alert.show(event.fault.faultString)"/>
	</mx:RemoteObject>
	<mx:Button name="load" click="load()"/>
	 <mx:Script>
	<![CDATA[
		import mx.rpc.events.ResultEvent;

		private function returnHandler(e:ResultEvent):void
		{
			trace( e.result );
		}

		private function load():void
		{
			ro.getData( 1, 2 );
		}
	]]>
	</mx:Script>
</mx:Application>

 

 

AMF3 직렬화 처리가 안된 ActionScript 3.0 프로젝트 개발

 

AMF3 통신만 원한다면 앞서 설명한 이유 때문에 굳이 Flex로 개발할 필요가 없다. ActionScript 3.0 프로젝트 환경에서도 충분히 AMF 통신이 가능하기 때문이다. 아래는 OpenAMF나 PHPAMF와 같은 서버측 프로그램을 이용할 때 ActionScript 3.0 코드이다.

 

package {
	import flash.display.Sprite;
	import flash.net.NetConnection;
	import flash.net.ObjectEncoding;
	import flash.net.Responder;
	import flash.net.registerClassAlias;

	public class AS3NetConnectionTest extends Sprite
	{
		private var nc:NetConnection;

		public function AS3NetConnectionTest()
		{
			//create a netconnection
			nc = new NetConnection();
			nc.objectEncoding = ObjectEncoding.AMF3;
			nc.connect("http://192.168.*.*/_FLEX/amf");

			//create a responder
			var responder:Responder = new Responder(result, fault);

			//make the call
			nc.call("com.jidolstar.service.MyClass.getData", responder, 2);
		}

		private function result( data:Object ):void
		{
			trace("RPC Ok");
		}

		private function fault( event:Object ):void {
			 trace("RPC Fail");
			 trace(ObjectUtil.toString(event););
		}
	}
}

 

위 코드는 Flex에 관련된 것이 없고 단순히 flash.* 패키지 기반의 순수 ActionScript 3.0 환경에서 개발한 것이다. 용량도 Release로 컴파일하면 1kb도 안된다. Flex로 개발할때와 거의 250배 이상 용량차이를 보인다.

 

 

AMF3 직렬화 처리가 된 ActionScript 3.0 프로젝트 개발

 

하지만 BlazeDS, LCDS 서버의 리모트 객체와 클라이언트 객체간에 직렬화(serialization)가 필요한 경우 위 ActionScript 코드만으로는 해결할 수 없다. 이 문제는 본인의 경우 기존 프로젝트에서 BlazeDS로 만들어진 서버측의 코드를 변경하지 않고 Flex대신 ActionScript 3.0로 개발할때 문제가 발생했다. Flex Builder에서 ActionScript 3.0 프로젝트로 하면 playerglobal.swc, flex.swc, utilites.swc만 라이브러리로 등록되어 있기 때문에 BlazeDS에서 AMF3를 통해 넘겨주는 message관련 객체나 ArrayCollection 객체등을 직렬화 처리를 할 수 없게 된다. 왜냐하면 이들 3개 swc에는 이와 관련된 클래스가 정의되어 있지 않기 때문이다.

 

BlazeDS의 message관련 객체에 대한 직렬화를 위해서는 Flex SDK에 있는 rpc.swc가 필요하다. 또 ArrayCollection 직렬화를 위해서는 framework.swc 가 필요하다. 그럼 Flex를 사용하는 것과 무엇이 다르냐라고 반문할 수 있다.  그러나 ActionScript 3.0 기반이기 때문에 framework.swc에 정의된 비주얼 컴포넌트를 전부 사용하지 않고 단지 ArrayCollection과 그와 관련된 클래스만 사용하기 때문에 이것만으로도 프로그램의 용량을 획기적으로 줄이게 된다.

 

아래에서 설명하는 대로 프로젝트 환경을 구성해보자.

 

 

1. Flex Builder 3 Professional에서 ActionScript 3.0 프로젝트를 만든다.

 

2. 프로젝트에 Flex SDK에 있는 rpc.swc, rpc_rb.swc, framework.swc, framework_rb.swc를 라이브러리로 추가한다.

 

참고로, SWC는 윈도우의 경우 C:/Program Files/Adobe/Flex Builder 3/sdks/SDK버전/frameworks/에 libs 폴더와 locale 폴더에 있다. SWC에서 _rb라고 붙은 것은 resource bundle의 약어이다. Flex는 리소스 번들을 지원해주는데 우리의 목적과는 상관없는 것이지만 컴파일을 위해서는 추가해주어야 에러가 없이 컴파일이 된다.

 

 

3. 아래처럼 컴파일러 옵션에 -locale=en_US -include-resource-bundles=collections,rpc,messaging 를 추가한다.

 

 

4. 아래 코드처럼 코딩한다. (서버측 BlazeDS 설정은 여기서 설명을 생략한다.)

 

package {
	import com.jidolstar.vo.Class1;
	import com.jidolstar.vo.Class2;

	import flash.display.Sprite;
	import flash.net.registerClassAlias;

	import mx.collections.ArrayCollection;
	import mx.collections.ArrayList;
	import mx.core.mx_internal;
	import mx.logging.targets.TraceTarget;
	import mx.messaging.ChannelSet;
	import mx.messaging.channels.AMFChannel;
	import mx.messaging.config.ConfigMap;
	import mx.messaging.config.LoaderConfig;
	import mx.messaging.events.*;
	import mx.messaging.messages.*;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.remoting.RemoteObject;
	import mx.utils.ObjectProxy;

	use namespace mx_internal;

	/**
	 * RemoteObject 이용
	 */
	public class AS3RemoteObjectTest extends Sprite
	{
		public function AS3RemoteObjectTest()
		{

			registerClassAlias("flex.messaging.messages.CommandMessage",CommandMessage);
			registerClassAlias("flex.messaging.messages.RemotingMessage",RemotingMessage);
			registerClassAlias("flex.messaging.messages.AcknowledgeMessage", AcknowledgeMessage);
			registerClassAlias("flex.messaging.messages.ErrorMessage",ErrorMessage);
			registerClassAlias("flex.messaging.io.ArrayList", ArrayList);
			registerClassAlias("flex.messaging.config.ConfigMap",ConfigMap);
			registerClassAlias("flex.messaging.io.ArrayCollection",ArrayCollection);
			registerClassAlias("flex.messaging.io.ObjectProxy",ObjectProxy);
			registerClassAlias("flex.messaging.messages.HTTPMessage",HTTPRequestMessage);
			registerClassAlias("flex.messaging.messages.SOAPMessage",SOAPMessage);
			registerClassAlias("flex.messaging.messages.AsyncMessage",AsyncMessage);
			registerClassAlias("flex.messaging.messages.MessagePerformanceInfo", MessagePerformanceInfo);
			registerClassAlias("DSA", AsyncMessageExt);
			registerClassAlias("DSC", CommandMessageExt);
			registerClassAlias("DSK", AcknowledgeMessageExt);

			registerClassAlias("com.jidolstar.service.domain.Class1", Class1 );
			registerClassAlias("com.jidolstar.service.domain.Class2", Class2);

			//Sets up some more descriptive tracing on the client
			var target:TraceTarget = new TraceTarget();
			target.level = 0;

			//This is needed so the Flex libraries have access to the root objects properties
			var swfURL:String = this.loaderInfo.url;
			LoaderConfig.mx_internal::_url = this.loaderInfo.url;
			LoaderConfig.mx_internal::_parameters = this.loaderInfo.parameters;

			//This is the channel definition
			//This tells RemoteObject where to go
			var amfChannel:AMFChannel = new AMFChannel( "my-amf", "http://192.168.0.17/amf" );
			amfChannel.requestTimeout = 3;
			amfChannel.connectTimeout = 3;
			amfChannel.addEventListener(ChannelFaultEvent.FAULT, handleChannelFault);
			amfChannel.addEventListener(ChannelEvent.CONNECT, handleChannelConnect);
			amfChannel.addEventListener(ChannelEvent.DISCONNECT, handleChannelDisconnect);

			var channelSet:ChannelSet = new ChannelSet();
			channelSet.addChannel( amfChannel );

			//Make sure you include the right RemoteObject at
			//import mx.rpc.remoting.RemoteObject;
			//not
			//import  mx.rpc.remoting.mxml.RemoteObject;
			var ro:RemoteObject = new RemoteObject;
			ro.destination = "mydest";
			ro.channelSet = channelSet;
			ro.addEventListener(ResultEvent.RESULT, onResult );
			ro.addEventListener(FaultEvent.FAULT, onFault );
			ro.getData( 1, "jidolstar" );
		}

		public function onResult(event:ResultEvent):void
		{
			trace("RPC Ok");
			trace(event.result);

		}

		public function onFault(event:FaultEvent):void
		{
			trace("RPC Fail");
        	trace(event.message);
		}

		public function handleChannelFault(e:ChannelFaultEvent):void {
		    trace("Channel Fault");
			trace(e);
		}		

		public function handleChannelConnect(e:ChannelEvent):void {
		    trace("Channel Connect");
			trace(e);
		}

		public function handleChannelDisconnect(e:ChannelEvent):void {
		    trace("Channel Disconnect");
			trace(e);
		}

	}
}

 

위 코드는 BlazeDS나 LCDS 환경에서 RPC기반인 RemoteObject로 AMF3 통신처리를 하는 ActionScript 3.0 프로젝트 예제이다.

 

registerClassAlias()는 BlazeDS에서 오는 AMF3 메시지 객체를 ActionScript 3.0으로 직렬화처리를 위한 것이다. 이 함수에 message관련 클래스와 ArrayCollection이 등록되어 있는 것을 확인하기 바란다. 이것으로서 ActionScript 3.0 프로젝트를 통해서도 충분히 ArrayCollection을 쓸 수 있게 된다.

 

registerClassAlias("com.jidolstar.service.domain.Class1", Class1 )는 서버측에 정의된 com.jidolstar.service.domain.Class1 객체를 ActionScript 3.0에 정의된 com.jidolstar.vo.Class1으로 직렬화해준다. Flex에서는 com.jidolstar.vo.Class1이 만들어진 Class1.as파일의 Class명 위에 [RemoteClass(alias="com.jidolstar.service.domain.Class1")] 를 정의함으로서 registerClassAlias()에서 한 것과 동일하게 처리할 수 있지만 ActionScript 3.0환경에서 개발하므로 [RemoteClass]는 사용하기에 적합하지 못하다.

이 프로그램을 Release모드로 컴파일하면 89kb였다. Flex로 개발시에 262kb이였던 것에 비해서 분명 크게 줄었다. 이는 Flex 비주얼 컴포넌트에 관련된 것이 컴파일에서 제외되었기 때문이다. 하지만 순수하게 NetConnection으로만 만들었던 것이 1kb였다는 것을 감안한다면 여전히 크기가 크다. 위 코드에서는 RemoteObject를 이용했는데 NetConnection을 이용해보면 어떨까? 다음 코드를 보자.

 

package {
	import com.jidolstar.vo.Class1;
	import com.jidolstar.vo.Class2;

	import flash.display.Sprite;
	import flash.net.NetConnection;
	import flash.net.ObjectEncoding;
	import flash.net.Responder;
	import flash.net.registerClassAlias;

	import mx.collections.ArrayCollection;
	import mx.messaging.messages.*;

	/**
	 * NetConnection이용
	 */
	public class AS3NetConnectionTest extends Sprite
	{
		public function AS3NetConnectionTest()
		{
			registerClassAlias("flex.messaging.messages.RemotingMessage",RemotingMessage);
			registerClassAlias("flex.messaging.messages.AcknowledgeMessage", AcknowledgeMessage);
			registerClassAlias("flex.messaging.messages.ErrorMessage",ErrorMessage);
			registerClassAlias("flex.messaging.io.ArrayCollection",ArrayCollection);

			registerClassAlias("com.jidolstar.service.domain.Class1", Class1  );
			registerClassAlias("com.jidolstar.service.domain.Class2", Class2  );

			//create a netconnection
			var nc:NetConnection = new NetConnection();
			nc.objectEncoding = ObjectEncoding.AMF3;
			nc.connect("http://192.168.0.17/amf");

			//create the arguments that will be sent to the method
			var methodArguments:Array = [ 1, "jidolstar" ];

			//create a remoting message
			var remotingMessage:RemotingMessage = new RemotingMessage();
			remotingMessage.operation = "getData";
			remotingMessage.body = methodArguments;

			//The values of these 2 values come from the services-config.xml which is located in the ColfFusion server
			remotingMessage.destination = "mydest";
			remotingMessage.headers = {DSEndpoint: "my-amf"};

			//create a responder
			var responder:Responder = new Responder(result, fault);

			//make the call
			nc.call(null, responder, remotingMessage);
		}

		private function result(e:AcknowledgeMessage):void
		{
			trace("RPC Ok");
			trace(e.body);
		}

		private function fault(e:ErrorMessage):void {
			 trace("RPC Fail");
			 trace(e.faultString);
		}
	}
}

 

위 프로그램은 RemoteObject를 사용할 때와 동일하게 동작한다. 하지만 더 저레벨로 만들었기 때문에 프로그램 용량은 44kb로 RemoteObject를 사용할때보다 1/2로 줄었다. Flex로 개발할때와 비교할때 거의 6배 차이가 난다. 그러나 여전히 순수하게 NetConnection만으로 만들었을 때와 용량차이가 나는데 그것은 메시지 관련 클래스와 ArrayCollection을 컴파일할때 그와 연관된 클래스들이 포함되어 컴파일 되기 때문이다. 그 중에서는 우리의 목적인 AMF3 직렬화와는 상관없는 resource bundle에 관련된 것도 포함되어 있다. 필요하다면 resource bundle부분을 제외한 라이브러리를 만들어 내는 것도 하나의 방법이 될 수 있겠다. 일단 6배 이상 프로그램 용량을 줄일 수 있다는 것에 만족하려고 한다. 만약 이 부분에 대해서 더욱 가볍게 만드신 분이 있다면 함께 공유했으면 한다.(제가 그것까지 하기에는 시간이 ^^;;)

 

위 프로그램은 단순한 예제이므로 필요할 때 클래스화 시켜서 만드는 것이 좋을 것이라 생각한다.

 

 

관련글

 

 

+ Recent posts