Scope

Direct Web Remoting 2012.11.16 13:22

DWR 설정 중 <create> 엘리먼트는 DWR Call로 Client 접근하여 호출할 수 있는 클래스(Remote Proxy Class)를 정해주는 역할을 한다. 이 <create> 엘리먼트 속성 중 'scope' 속성은 <create>로 설정한 클래스의 LifeCycle 범위를 지정하는데 이는 Sevlet Spec 에서의 scope의 역할과 거의 유사하다. (DWR에서는 script 범위 추가)  이번에는 이 scope의 종류와 범위를 알아보도록 하겠다.


* page (default)
page는 DWR Call 단위로 DWR Call 할 때 마다 Remote Proxy Class 인스턴스를 생성한다. 따라서 page 범위에서는 어떤 Servlet 속성, 범위에 저장되지 않고 매번 인스턴스를 생성하게 된다. page 범위는 default 값으로 scope 속성에 따로 설정하지 않아도 된다.

// dwr.xml
<create creator="new" javascript="WIScopeTest" scope="page">  // 또는 scope 생략.


// log

DEBUG impl.DefaultRemoter [userid=,ip=] --Object created,  not stored. id=0



* application

application은 ServletContext 범위에 해당하며 최초 Remote Proxy Class 인스턴스가 생성이 된 후 ServletContext의 속성에 저장한다. 그 후에는 Remote Proxy Class를 새로 인스턴스를 생성하지 않고 최초에 ServletContext에 저장해 둔 인스턴스를 사용하게 된다.


// dwr.xml
<create creator="new" javascript="WIScopeTest" scope="application">


// log

DEBUG impl.DefaultRemoter [userid=,ip=] --Object created,  stored in application. id=0   <!-- first call -->

DEBUG impl.DefaultRemoter [userid=,ip=] --Object found in application. id=0                 <!-- second call -->



* script

script는 ScriptSession 범위에 해당하는데 이 ScrptSession은 Serlvet Spec에는 없는 범위이다. 이 범위는 쉽게 말하자면 우리가 보는 페이지 단위의 범위로 최초 로드한 페이지에서 페이지 이동 없이 여러번 DWR Call을 할 경우 생성된 Remote Proxy Class 인스턴스를 ScrptSession에 저장하여 관리하게 된다. 그러나 페이지를 리프레시 하거나 이동한 다음 DWR Call을 할 경우에는 ScrptSession이 새로 생성이 되기 때문에 다시 Remote Proxy Class 인스턴스 생성하여 ScrptSession 저장해야 한다.


// dwr.xml
<create creator="new" javascript="WIScopeTest" scope="script">


// log

DEBUG impl.DefaultRemoter [userid=,ip=] --Object created,  stored in script. id=0  <!-- first call -->

DEBUG impl.DefaultRemoter [userid=,ip=] --Object found in script. id=0            <!-- second call -->


<!-- do page refresh -->


DEBUG impl.DefaultRemoter [userid=,ip=] --Object created,  stored in script. id=0  <!-- first call -->

DEBUG impl.DefaultRemoter [userid=,ip=] --Object found in script. id=0            <!-- second call -->



* request

request는 HttpServletRequest 범위에 해당하여 HttpSerlvetRequest의 속성으로 관리하게 된다. 즉, HTTP Request 당 하나의 Remote Proxy Class 인스턴스를 생성하게 된다. request 범위가 page 범위와 다른 점은 DWR Call을 batch로 묶어서 처리할 경우 하나의 HTTP Request에 여러게 DWR Call이 존재하기 때문에 page 범위로 할 경우 batch로 묶인 DWR Call 개수 만큼 Remote Proxy Class 인스턴스가 생성이 되고, request로 할 경우에는 하나의 Remote Proxy Class 인스턴스를 생성하여 HttpSerlvetRequest의 속성으로 추가하여 재사용하게 된다.



// dwr.xml
<create creator="new" javascript="WIScopeTest" scope="request">


// log

<!-- batch start -->

DEBUG impl.DefaultRemoter [userid=,ip=] --Object created,  stored in request. id=0   <!-- 1-1 call -->

DEBUG impl.DefaultRemoter [userid=,ip=] --Object found in request. id=1                 <!-- 1-2 call -->

<!-- batch end -->


<!-- batch start -->

DEBUG impl.DefaultRemoter [userid=,ip=] --Object created,  stored in request. id=0   <!-- 2-1 call -->

DEBUG impl.DefaultRemoter [userid=,ip=] --Object found in request. id=1                 <!-- 2-2 call -->

<!-- batch end -->



* session

session은 HttpSession 범위에 해당하여 Client가 동일 세션을 유지하는 동안 Remote Proxy Class 인스턴스를 관리 재사용 하게 된다.


// dwr.xml
<create creator="new" javascript="WIScopeTest" scope="session">


// log

<!-- keep session -->

DEBUG impl.DefaultRemoter [userid=,ip=] --Object created,  stored in session. id=0 

DEBUG impl.DefaultRemoter [userid=,ip=] --Object found in session. id=0          



따라서 Remote Proxy Class 인스턴스를 매번 생성할지 아니면 Servlet 범위 속성으로 관리하여 재사용할지는 인스턴스 생성에 따른 성능 이슈나 동기화 문제등을 고려하여 적용하면 되겠다.



참고 : http://directwebremoting.org/dwr/documentation/server/configuration/dwrxml/creators/index.html


'Direct Web Remoting' 카테고리의 다른 글

Scope  (0) 2012.11.16
Annotations Configuration  (0) 2012.11.16
Configuration  (0) 2012.11.16
Plug-ins  (0) 2012.11.16
Mapping Java classes to JavaScript classes  (0) 2012.11.16
Signatures  (0) 2012.11.16

Annotations Configuration

Direct Web Remoting 2012.11.16 13:22

DWR은 기본적으로 dwr.xml 파일에 xml형태로 설정을 할 수 있는데 별도의 xml 파일이 아닌 소스코드에 Annotation을 이용하여 설정을 할 수 있다. 그러면 구동 초기화 시 Annotation을 읽어 들여 환경설정을 하게 된다. Annotation 설정은 'AnnotationsConfigurator' 클래스가 담당하며 물론 plug-ins 기술을 이용하여 customizing을 할 수도 있다. 그러면 설정 관련 Annotation이 어떤것들이 있는지 알아보고 이를 이용하여 설정하는 방법을 알아보자.


* web.xml

우선 'classes' <init-param>에 Annotation을 적용한 클래스들을 명시해 주어야 한다. 그래야 AnnotationsConfigurator가 명시한 클래스들을 대상으로 스캔하여 설정을 하기 때문이다. 사실 이 과정이 생략이 되고 자동으로 스캔을 할 수 있다면 더 좋은 방법이겠지만 그렇다고 전체를 스캔하기에는 비효율적일 것 같다. 클래스들은 ',' 를 구분자로 표기를 해주면 된다.


// web.xml

<init-param>

    <param-name>classes</param-name>

    <param-value>

        com.example.RemoteFunctions,

        com.example.RemoteBean

    </param-value>

</init-param>



* @RemoteProxy

@RemoteProxy는 dwr.xml의 <create> 엘리먼트에 해당되며 Client에서 접근할 수 있는 클래스를 설정하는 역할을 한다. 이와 관련된 속성들은 아래와 같다.

    • name : <create>엘리먼트의 'javascript' 속성과 일치. 기본값은 클래스의 패키지명이 생략된 Simple Name으로 설정된다.
    • creator : <create>엘리먼트의 'creator' 속성과 일치. 기본값은 'NewCreator.class'로 xml에 "new"로 설정한것과 같다.
    • creatorParams : <create>엘리먼트의 하위 엘리먼트 <param>과 일치. @Param 이용 설정.
    • scope : <create>엘리먼트의 scope 속성과 일치. 기본값은 'ScriptScope.PAGE'로 xml에 "page"로 설정한것과 같다.

dwr.xml에서는 <param>엘리먼트로 Client가 접근할 수 있는 클래스명을 명시해주어야 했지만, Annotation으로 설정할 경우 이미 해당 클래스를 DWR이 알고 있으므로 생략을 하면 된다.


@RemoteProxy

name = "WIAnnotationConfiguration", // 생략가능 (default : Class' simple name)

creator = NewCreator.class, // 생략가능 (default : NewCreator.class)

scope = ScriptScope.PAGE, // 생략가능 ( default : ScriptScope.PAGE)

        creatorParams = {@Param(name = "class", value = "net.daum.bestna.WIAnnotationConfiguration"),                 

                                 @Param(name="foo",value="var")} // 생략가능

)

public class WIAnnotationConfiguration {


@RemoteMethod

public void iamRemoteMethod(String aa) {

System.out.println(aa);

}

}



* @RemoteMethod

@RemoteMethod는 @RemoteProxy 클래스에서 접근을 허용할 메소드에 명시를 하며 <create>엘리먼트의 <include>하위 엘리먼트와 동일하다. @RemoteMethod가 없는 메소드는 자연히 접근할 수 가 없다. 이는 xml설정의 경우 <inlcude>엘리먼트만 있으면 나머지 메소드들은 자동으로 exclude되고 <exclude>엘리먼트만 있으면 나머지 메소드들은 자동으로 include 되게 설정이 되어 있지만 Annotation설정의 경우 include,exclude를 설정하는 속성이 없어 해당 기능을 적용할 수 없는 것 이다. @RemoteMethod는 속성값이 없다.



* @DataTransferObject

@DataTransferObject는 Client와 Server간에 전송되는 DTO와 이를 변환해주는 converter를 설정해주는 <convert>엘리먼트와 동일하다. 이와 관련된 속성은 아래와 같다.

    • converter : <convert>엘리먼트의 converter 속성과 일치. 기본값은 'BeanConverter.class' 이다.
    • params : <convert>엘리먼트에서 설정하는 param 리스트. @Param을 이용하여 설정한다.

converter가 DTO를 변환할때 특정 맴버변수를 포함시키거나 제외시키는 <convert>엘리먼트의 하위 엘리먼트인 <include>, <exclude>엘리먼트와 DTO의 타입을 보존시켜주는 <convert>엘리먼트의 'javascript'속성도 @DataTransferObject Annotation의 'params' 속성을 이용해서 설정하면 된다.


@DataTransferObject(

converter=BeanConverter.class,

params={

@Param(name="exclude",value="age"),

@Param(name="javascript",value="Person")

}

)

public class Person {

private String name; // include

private int age; // exclude

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public int getAge() { return age; }

public void setAge(int age) { this.age = age; }

}


@Param을 이용하여 맴버변수의 in/exclude를 설정하는 방법 외에 @RemoteProperty를 이용해서 설정할 수 있는데 이 Annotation이 명시된 맴버변수만 include가 되고 나머지 맴버변수들은 자동으로 exclude가 된다.


@DataTransferObject(

converter=BeanConverter.class,

params={

@Param(name="javascript",value="Person")

}

)

public class Person {

private String name; // exclude

@RemoteProperty private int age; // include

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public int getAge() { return age; }

public void setAge(int age) { this.age = age; }

}



* @GlobalFilter

@GlobalFilter는 dwr.xml의 <allow> 엘리먼트 하위에 설정하는 <filter>와 동일하며 모든 DWR call에 대한 필터 역할을 담당하고 있다. 해당 Annotation을 적용하는 클래스는 'org.directwebremoting.AjaxFilter' 인터페이스를 구현해야만 한다. @GlobalFilter에는 params 속성이 하나 있으며 @Param을 이용하여 설정하면 된다. 만일 @Param(name="foo",value="var") 라고 선언을 하였다면 DWR은 filter 클래스의 setFoo 함수를 호출하고 파라미터로 "var" 값을 전달하게 된다.


@GlobalFilter(params = { @Param(name = "foo", value = "var") })

public class WIGlobalFilter implements AjaxFilter {


public void setFoo(String value) {

System.out.println("Param value is : " + value);

}


@Override

public Object doFilter(Object obj, Method method, Object[] params,

AjaxFilterChain chain) throws Exception {

// do something.

return chain.doFilter(obj, method, params);

}

}



* @Filters, @Filter

@GlobalFilter가 DWR call 전체에 대한 글로벌 필터라면 @Filters, @Filter는 @RemoteProxy를 선언한 클래스에서 선언하면 해당 클래스에서만 적용되는 필터이다. 하나의 필터만 적용할 경우에는 @Filter를 여러개의 필터를 적용하고 싶다면 @Filters를 사용하면 된다. @Filters 속성으로는 'values'로 @Filter의 리스트 타입을 나타내며 @Filter 속성으로 'type' 은 필터 기능을 구현한 기능으로 <filter>엘리먼트와 동일며 'params' 은 @GlobalFilter의 params와 동일하다.


@RemoteProxy

@Filter(

type=WIFilter.class,

params={@Param(name="foo",value="var")}

)

public class WISingleFilterTest {

@RemoteMethod

public String iamFilterTest() {

return "I am Filter Test";

}

}


@RemoteProxy

@Filters(value = { @Filter(type = WIFilter.class) })

public class WIMultipleFilterTest {

@RemoteMethod

public String iamFilterTest() {

return "I am Filter Test";

}

}



* @Auth

@Auth는 Servlet Container의 인증과 관련된 Annotation으로 <create> 엘리먼트 하위에서 선언하던 <auth>와 동일하다. <auth> 엘리먼트는 'method' 속성과 'role'속성을 가지고 있으며 'method'에는 인증을 적용할 메소드, 'role'에는 접근권한을 설정해준다. @Auth의 경우는 메소드단위로 설정하기 때문에 'method'속성은 제외하고 'role' 속성만 설정해주면 된다.


@RemoteMethod

@Auth(role = "admin")

public String iamFilterTest() {

return "I am Filter Test";

}



참고 : http://directwebremoting.org/dwr/documentation/server/configuration/annotations.html

'Direct Web Remoting' 카테고리의 다른 글

Scope  (0) 2012.11.16
Annotations Configuration  (0) 2012.11.16
Configuration  (0) 2012.11.16
Plug-ins  (0) 2012.11.16
Mapping Java classes to JavaScript classes  (0) 2012.11.16
Signatures  (0) 2012.11.16

Configuration

Direct Web Remoting 2012.11.16 13:20

DWR을 사용하기 위해서는 Client에서 Server로 호출할 메소드들과 DTO(Data Transfer Object)들을 설정 해줘야 한다. 해당 설정을 하는 방법은 여러가지가 있는데 기본적으로는 dwr.xml 파일에 <convert>나 <create> 엘리먼트를 이용하여 설정한다. 이번 포스팅에서는 DWR 초기 구동 과정을 살펴보면서 DWR 설정하는 여러 방법들을 알아본다.


Step 1. Configure System dwr.xml

첫 번째로 dwr.jar 내에 있는 dwr.xml을 설정한다. 해당 dwr.xml에는 DWR에서 사용될 기본적인 creator와 converter등을 사용할 수 있다. 우리가 int같은 기본타입 이나 String 등을 따로 설정하지 않아도 되는 이유는 이 파일에 선언되어 있기 때문이다. (@see java/org/directwebremoting/dwr.xml)


// java/org/directwebremoting/dwr.xml 中

...

<convert converter="primitive" match="int"/>

...

<convert converter="string" match="java.lang.String"/>

...



Step 2. Find <init-param> start with 'config'

두 번째로 'config'으로 시작하는 <init-param>을 찾은 뒤 <init-value>에 설정한 xml파일을 가지고 설정한다. 이런 컨벤션을 이용한 설정을 지원하기 때문에 DWR 설정을 하나가 아닌 복수의 파일로 분리하여 관리할 수 가 있다.


<init-param>

<param-name>config-article</param-name>

<param-value>/WEB-INF/dwr_article.xml</param-value>

<description>configuration for article</description>

</init-param>

<init-param>

<param-name>config-comment</param-name>

<param-value>/WEB-INF/dwr_comment.xml</param-value>

<description>configuration for comment</description>

</init-param>



Step 3. Custom Configuration

만일 Step 2.에서 config로 시작하는 <init-param>을 하나도 못 찾았다면 'customConfigurator' <init-param>을 찾고, <init-value> 설정된 클래스 파일을 가지고 설정을 한다. DWR 기본적으로 xml 형태의 파일을 가지고 설정을 하기 되는데 'customConfigurator'을 이용하면 xml형태가 아닌 클래스 파일로 설정이 가능하다. 또한 클래스 파일로 구성되기 때문에 필요 시 동적 설정도 가능할 수 있겠다. 해당 클래스 파일은 org.directwebremoting.fluent.FluentConfigurator 추상클래스를 상속하여야 한다.


<init-param>

<param-name>customConfigurator</param-name>

<param-value>net.daum.blog.bestna.FluentConfiguratorCustomImpl</param-value>

<description>FluentConfiguratorCustomImpl extends FluentConfigurator</description>

</init-param>


// 참고 : http://directwebremoting.org/dwr/documentation/server/configuration/fluent.html

public class FluentConfiguratorCustomImpl extends FluentConfigurator

{

  @override

  public void configure() {

    withConverterType("dog", "com.yourcompany.beans.Dog");

    withCreatorType("ejb", "com.yourcompany.dwr.creator.EJBCreator");

    withCreator("new", "ApartmentDAO")

        .addParam("scope", "session")

        .addParam("class", "com.yourcompany.dao.ApartmentDAO")

        .exclude("saveApartment")

        .withAuth("method", "role");

    withCreator("struts", "DogDAO")

        .addParam("clas", "com.yourcompany.dao.DogDAO")

        .include("getDog")

        .include("getColor");

    withConverter("dog", "*.Dog")

        .addParam("name", "value");

    withSignature()

        .addLine("import java.util.List;")

        .addLine("import com.example.Check;")

        .addLine("Check.setLotteryResults(List<Integer> nos);");

  }

}



Step 4. Configure Default dwr.xml

Step2와 Step3 과정을 모두 거치지 않았다면 '/WEB-INF/dwr.xml'을 가지고 설정을 하게 된다. 이는 문서에서 기본적으로 설명하고 있는 기본 파일이다. 만일 'skipDefaultConfig' <init-param> 값을 'true'로 설정 할 경우 이 과정도 skip 하게 된다.


<init-param>

<param-name>skipDefaultConfig</param-name>

<param-value>true</param-value>

<description>Skip the default configuration</description>

</init-param>



Step 5. Annotations Configuration

위 과정이 끝난 후 최종적으로 어노테이션을 이용하여 DWR 설정을 하게 되며, 이와 관련된 내용은 다음 포스팅에 다루도록 하겠다.



아래는 위 과정들의 Activity Diagram 이다.





<DWR Configuration Activity Diagram>

'Direct Web Remoting' 카테고리의 다른 글

Scope  (0) 2012.11.16
Annotations Configuration  (0) 2012.11.16
Configuration  (0) 2012.11.16
Plug-ins  (0) 2012.11.16
Mapping Java classes to JavaScript classes  (0) 2012.11.16
Signatures  (0) 2012.11.16