하려는것

1) Flex 에서 RemoteObject 를 이용해 blazeds 서버의 메서드를 호출하고,
2) 서버는 RemoteClass 로 등록되어있는 객체를 반환하면
3) Flex 가 이를 받아 View 에서 볼 수 있도록 바인딩 한다.

예제1) 간단한 모델

Java

   1: public class Config
   2: {
   3:     private String text;
   4:  
   5:     public String getText()
   6:     {
   7:         return text;
   8:     }
   9:  
  10:     public void setText(s:String)
  11:     {
  12:         text = s;
  13:     }
  14: }

Flex
   1: package com.myapp.model.config
   2: {
   3:     [RemoteClass(alias="com.myapp.model.Config")]
   4:     
   5:     [Bindable]
   6:     public class Config
   7:     {
   8:         private var _text:String;
   9:  
  10:         public function get text():String
  11:         {
  12:             return _text;
  13:         }
  14:  
  15:         public function set text(s:String):void
  16:         {
  17:             _text = s;
  18:         }
  19:     }
  20: }

예제1은 특별히 설명할게 없다. 저렇게 하면 알아서 리모트 클래스로 처리되어 속성을 참조 할 수 있다.

플렉스에서 리모트 클래스로 등록한 Config객체는 text 가 속성으로 되어 있는데

RemoteObject 로 가져올때 자바객체의 getText(), setText() 메서드를 알아서 불러와 text에 집어 넣어준다.

 

예제2) 복잡한 모델

Java

   1: package com.myapp.model;
   2:  
   3: import com.myapp.model.BaseDataModel;
   4:  
   5: public class Config extends BaseDataModel
   6: {
   7:     private int seq;
   8:  
   9:     public int getSeq()
  10:     {
  11:         return seq;
  12:     }
  13:  
  14:     public void setSeq(int i)
  15:     {
  16:         this.seq = i;
  17:     }
  18:  
  19:     public int getInterval()
  20:     {
  21:         return getInt("interval", 60);
  22:     }
  23:  
  24:     public void setInterval(int i)
  25:     {
  26:         setInt("interval", i);
  27:     }
  28: }
   1: import java.util.HashMap;
   2:  
   3: public abstract class BaseDataModel
   4: {
   5:     /**
   6:      * "key1=value1&key2=value2& ... " 와 같은 문자열을 key&value 쌍으로 저장하고 있는 멤버  
   7:      */
   8:     private HashMap<String, String> dataHashMap = new HashMap<String, String>();
   9:     
  10:     /**
  11:      * @return
  12:      * dataHashMap의 요소를 "key=value& ... " 형식 문자열로 만들어 반환한다.
  13:      * 이 메서드는 오버라이드 할 수 없다. 
  14:      */
  15:     public final String getData()
  16:     {
  17:         return DataUtil.getDataString(dataHashMap);
  18:     }
  19:     
  20:     /**
  21:      * "key=value& ... " 형식 문자열을 파싱하여 dataHashMap 에 저장한다.
  22:      * 문자열 전달인자는 파싱되기 전 멤버변수인 data 에 저장된다.
  23:      * 이 메서드는 오버라이드 할 수 없다.
  24:      * @param data
  25:      */
  26:     public final void setData(String data)
  27:     {
  28:         dataHashMap = DataUtil.getDataHashMap(data);
  29:     }
  30:     
  31:     /**
  32:      * int 타입의 값을 문자열로 변환해 dataHashMap 에 저장한다.
  33:      * @param key
  34:      * @param value
  35:      */
  36:     protected void setInt(String key, int value)
  37:     {
  38:         dataHashMap.put(key, Integer.toString(value));
  39:     }
  40:  
  41:     /**
  42:      * dataHashMap 에서 key 에 해당하는 값을 참조해 int 형으로 반환한다.
  43:      * 참조한 값이 null 이면 0을 반환한다.
  44:      * @param key
  45:      * @return
  46:      */
  47:     protected int getInt(String key)
  48:     {
  49:         return Integer.getInteger(dataHashMap.get(key), 0);
  50:     }    
  51: }

 

Flex

   1: package com.myapp.model
   2: {    
   3:     [RemoteClass(alias="com.myapp.model.Config")]
   4:     
   5:     [Bindable]
   6:     public class Config
   7:     {    
   8:         private var _seq:int;
   9:         private var _interval:int;
  10:         private var _data:String;
  11:         
  12:         // ---------------------------------------------------
  13:         // Properties
  14:         // ---------------------------------------------------
  15:         public function get seq():int
  16:         {
  17:             return _seq;
  18:         }
  19:         
  20:         public function set seq(i:int):void
  21:         {
  22:             _seq = i;
  23:         }
  24:         
  25:         public function get interval():int
  26:         {
  27:             return _interval;
  28:         }
  29:         
  30:         public function set interval(i:int):void
  31:         {
  32:             _interval = i;
  33:         }
  34:         
  35:         public function get data():String
  36:         {
  37:             return _data;
  38:         }
  39:         
  40:         public function set data(s:String):void
  41:         {
  42:             _data = s;
  43:         }
  44:     }
  45: }

예제2의 경우를 동작시키기 위해 한 12시간은 쓴거 같다. 플렉스의 객체는 예제1과 동일한 형식이지만 속성이 2개 더 있다. 새로 생긴 2개의 속성은 자바단에서 구현이 예제 1과 다르다.

자바 객체는 다음 특징을 가진다.

1) BaseDataModel을 상속
2) seq는 예제1의 경우와 동일하며 public getter & setter 메서드가 seq 라는 private 변수를 단순 참조하는 전형적인 형태.
3) data 는 부모객체의 구현이며 public getter & setter 메서드가 dataHashMap 이라는 private 변수에 복잡한 연산을 통해 참조하는 형태
4) interval 은 public getter & setter 메서드가 부모객체의 메서드를 이용해 dataHashMap 을 참조하는 형태

이러한 상황을 구현하면서 매핑할 자바 클래스가 부모가 있는 클래스라고 해서 Flex 의 클래스 상속구조가 동일 할 필요는 없다는 사실을 확인했고, interval 과 data 와 같이 전형적인 구조가 아닌 속성을 매핑할때도 어렵게 생각 할 필요가 없었다.

시간을 12시간이나 소모시킨 주범은 다름아닌 데이터형이었다. 자바단에서 getInterval 의 리턴타입이 처음엔 Integer 로 되어 있었는데, 자바단에선 틀림없이 올바른 값이 저장되어 있었지만 플렉스로 넘어오면 무조건 0으로 바뀌는 것이다. 처음엔 리모트 클래스가 이런 유형, 즉, 상속된 객체라던지, getter & setter 에 해당하는 private 변수가 없는 경우를 지원하지 않는 줄 알고 별 방법을 다 동원해보았지만 해결되지 않았다. 모든 방법을 다 시도해봤다고 생각했을 무렵 설마 하고 Interger 로 정의되어 있던 리턴타입을 int 로 바꿨더니 거짓말 처럼 값이 넘어오더라--

새벽까지 이 코드 붙들고 하도 고생을 해서 나중에 잊어 먹고 성질 내지 않도록 남겨 놓는다.ㅎㅎ

Windows 7 을 설치한 이후 내 컴퓨터에서 직접 배포본을 컴파일 하지 않고 있다가, 오늘 컴파일 해야 할 일이 있어서 ant 로 플렉스 컴파일을 시도했으나 “Could not find a jvm” 이라는 에러 메시지를 만나게 되었다.

Error: could not find a JVM.

Error: could not find a JVM.

%JAVA_HOME% 설정이 잘못된 듯 하여 환경변수를 수정해보았다.

image

C:\Program Files (x86)\Java\jre6\bin –> C:\Program Files\Java\jdk1.6.0_17로 변경.
하지만 이번엔 Error: could not find a JVM. 에러 대신 Error loading: c:\Program Files\Java\jdk1.6.0_17\jre\bin\server\jvm.dll 에러가 발생했다.


처음 보는 메시지라 일단 구글 검색을 시도 했더니 두 가지 정도로 해결 방법이 제시 되어 있었다.

  • jvm.config 파일을 수정
  • %JAVA_HOME% 에서 역슬래시(\) 문자 대신 슬래시(/)를 쓰고, 긴 파일이름(LFN) 대신 도스 이름(C:\PROGRA~1)을 쓸 것

두가지 방법을 다 사용해봤지만 별 소용이 없었다.

원인 재분석

처음 만난 에러메시지(Error: could not find a JVM.)는 eclipse 에서 ant 를 이용해 mxmlc를 실행하는 상황에서 mxmlc가 토해내는 메시지다. 근데 왜 오류가 났을까?

1. eclipse는 java 를 이용해 ant 를 실행하고 ant task에서 mxmlc 를 실행한다.
2. mxmlc 는 시스템 환경변수 %JAVA_HOME% 을 참조하여 java 를 실행하고 소스코드를 컴파일 한다.

의문점은 “1번의 java 는 문제 없는데 2번의 java 만 문제가 있을까?” 라는 부분.

하지만 다시 생각하니 문제는 간단했다.
eclipse 에서 ant를 실행하는 java 환경은 eclipse가 제공하는 환경이고
mxmlc가 실행되는 java 환경은 윈도우가 제공하는 환경이다.

즉, 2번에서 문제가 발생하는 것으로 봐서 윈도우의 환경변수 %JAVA_HOME% 가 잘못 설정 된 것이 원인이다.

오류메시지에 대해 생각해보자..

Error loading: c:\Program Files\Java\jdk1.6.0_17\jre\bin\server\jvm.dll 에러 메시지는 왜 나타났을까.
왜 로딩에 실패했다고 나올까… 혹시 mxmlc 가 32bit응용프로그램이라 64bit 자바를 못 쓰는건가? 그럼 자바를 다시 설치해보자.

http://java.sun.com을 방문해 32bit JDK 를 내려 받고 설치.

환경변수 %JAVA_HOME%을 다시 설정하고, mxmlc 를 실행하니 헉~ 잘된다.

결론

mxmlc를 사용하기 위해선 32bit JDK가 필요하다.

get & set 노가다 하기 힘들어서 만들어 봄

+ Recent posts