Whiteship's Note


SWF 2장 플로우 정의하기



참조: http://static.springframework.org/spring-webflow/docs/2.0.x/reference/html/index.html

2.1. 개요

이번 장은 User Section으로 시작한다. 플로우 정의 언어(flow definition language)를 사용하여 플로우를 구현하는 방법을 살펴볼 것이다. 이번 장이 끝날 때 여러분은 언어 구조를 이해하고 플로우를 정의할 수 있을 것이다.

2.2 플로우란 무엇인가?

플로우는 여러 문맥에서 실행될 수 있는 재사용 가능한 스탭의 연속체를 캡슐화 한 것이다. 아래 그림은 Garrett Inforamtion Architecture 다이어그램으로 호텔 예약 프로세스의 단계를 캡슐화한 플로우를 보여주고 있다.

사용자 삽입 이미지

플로우를 나타내는 사이트 맵

2.3. 일반적인 플로우의 구성요소는 무엇인가?

스프링 웹 플로우에서, 플로우는 스테이트("states")라고 부르는 스탭의 일련으로 구성한다. 하나의 스테이트로 들어가면 보통 사용자에게 어떤 뷰 하나를 보여주게 된다. 해당 뷰에서, 스테이트가 처리할 사용자 이벤트가 발생한다. 이런 이벤트는 다른 스테이트로 이동(transition)을 시켜서 뷰 네이게이션을 하게 한다.

아래 예제는 앞선 다이어그램에서 살펴본 호텔 예약 플로우 구조를 보여주고 있다.

사용자 삽입 이미지
플로우 다이어그램

2.4. 어떻게 플로우를 작성하는가?

플로우는 웹 애플리케이션 개발자들이 간단한 XML 기반 플로우 정의 언어를 사용하여 작성한다. 이번 가이드의 다음 단계에서 이 언어의 구성 요소를 살펴보겠다.

2.5. 기본적인 언어 구성 요소

2.5.1 플로우(flow)

모든 플로우는 다음의 루트 엘리먼트로 시작한다.

<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

</flow>

플로우의 모든 스테이트(state)를 이 엘리먼트 안에 정의한다. 처음에 정의한 스테이트가 플로우의 시작점이 된다.

2.5.2. 뷰-스테이트(view-state)

view-state 엘리먼트를 사용하여 플로우에서 뷰를 보여주는 단계를 정의한다.

<view-state id="enterBookingDetails" />

기본적으로(by convention), 뷰-스테이트는 자신의 id를 플로우가 위치한 디렉터리의 뷰 템플릿으로 맵핑한다. 예를 들어, 위의 스테이트는 만약 플로우가 /WEB-INF/hotels/booking 디렉터리에 있었다면, /WEB-INF/hotels/booking/enterBookingDetails.xhtml을 사용자에게 보여줄 것이다.(rendering)

2.5.3. 트랜지션(transition)

transition 엘리먼트를 사용하여 스테이트에서 발생한 이벤트를 처리한다.

<view-state id="enterBookingDetails">
    <transition on="submit" to="reviewBooking" />
</view-state>
       
이런 트랜지션이 뷰 네이게이션을 끌어낸다.

2.5.4. end-state

end-state 엘리먼트를 사용하여 플로우 종료를 정의한다.

<end-state id="bookingCancelled" />

플로우 트랜지션이 종료-상태에 다다르면 플로우를 끝내고 결과를 반환한다.

2.5.5. 체크포인트: 기본 언어 구성 요소

세 개의 구성 요소 view-state, transition, end-state를 가지고 여러분은 빠르게 여러분의 뷰 네비게이션 로직을 표현할 수 있다. 팀에서 플로우 행동을 추가하기 전에 이 작업을 해봄으로써 먼저 사용자와 함께 애플리케이션 UI를 개발에 집중할 수 있다. 아래 예제는 이들 엘리먼트를 사용하여 뷰 네비게이션 로직을 구현한 것이다.

<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

    <view-state id="enterBookingDetails">
        <transition on="submit" to="reviewBooking" />
    </view-state>
   
    <view-state id="reviewBooking">
        <transition on="confirm" to="bookingConfirmed" />
        <transition on="revise" to="enterBookingDetails" />
        <transition on="cancel" to="bookingCancelled" />
    </view-state>
   
    <end-state id="bookingConfirmed" />

    <end-state id="bookingCancelled" />
       
</flow>   

2.6. 액션(Actions)

대부분의 플로우는 단순히 뷰 네비게이션 로직 보다 더 많은 것을 표현할 필요가 있다. 일반적으로 애플리케이션의 비즈니스 서비스 또는 다른 액션을 호출할 필요가 있다.

플로우에서 여러분이 액션을 실행할 수 있는 몇몇 포인트(point)가 있다.
  • On flow start
  • On state entry
  • On view render
  • On transition execution
  • On state exit
  • On flow end
액션은 간결한 EL(expression language)로 정의한다. 스프링 웹 플로우는 기본적으로 UEL(Unified EL)을 사용한다. 다음의 몇몇 절에서 액션을 정의할 때 사용하는 기본 언어 구성 요소를 살펴보겠다.

2.6.1. evaluate

여러분이 사용할 대부분의 액션 엘리먼트는 evaluate 엘리먼트일 것이다. evaluate 엘리먼트를 사용하여 플로우의 어떤 순간(point)에 표현식의 값을 구할 수 있다. 이 태그 하나로 스프링 빈 또는 다른 플로우 변수의 메소드를 호출할 수 있다. 예를 들어 다음과 같이 사용할 수 있다.

<evaluate expression="entityManager.persist(booking)" />

2.6.1.1. evaluate 결과값 대입하기

만약 표현식이 값을 반환한다면, 그 값을 플로우의 데이터 모델 flowScope에 저장할 수 있다.

<evaluate expression="bookingService.findHotels(searchCriteria)" result="flowScope.hotels" />

2.6.1.2. evaluate 결과값 변경하기

만약 표현식이 반환하는 값이 컨버팅이 필요하다면, 원하는 타입을 result-type 속성에 명시할 수 있다.

<evaluate expression="bookingService.findHotels(searchCriteria)" result="flowScope.hotels"
          result-type="dataModel"/>
               
2.6.2. 체크포인트: 플로우 액션

이제 예제 예약 플로우에 액션을 추가해보자.

<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

    <input name="hotelId" />

    <on-start>
        <evaluate expression="bookingService.createBooking(hotelId, currentUser.name)"
                  result="flowScope.booking" />
    </on-start>

    <view-state id="enterBookingDetails">
        <transition on="submit" to="reviewBooking" />
    </view-state>
   
    <view-state id="reviewBooking">
        <transition on="confirm" to="bookingConfirmed" />
        <transition on="revise" to="enterBookingDetails" />
        <transition on="cancel" to="bookingCancelled" />
    </view-state>
   
    <end-state id="bookingConfirmed" />

    <end-state id="bookingCancelled" />
       
</flow>   

이 플로우는 이제 플로우가 시작되면 Booking 객체를 플로우에 생성한다. 예약하려는 호텔의 id는 플로우 input 속성에서 얻어온다.

2.7. Input/Output 맵핑

각각의 플로우는 잘 정의되어 있는 input/output 제약을 가지고 있다. 플로우를 시작할 때 input 속성에 flow를 넘겨줄 수 있고, 플로우가 끝날 때 flow를 output 속성에 넘겨줄 수 있다. 플로우를 호출하는 것은 다음 시그너처를 가진 메소드를 호출하는 것과 비슷하다.

FlowOutcome flowId(Map<String, Object> inputAttributes);

FlowOutcome은 다음과 같이 생겼다.

public interface FlowOutcome {
   public String getName();               
   public Map<String, Object> getOutputAttributes();
}

2.7.1. input

input 엘리먼트를 사용하여 플로우의 input 속성을 선언한다.

<input name="hotelId" />

입력한 값은 속성의 name으로 flow 스코프에 저장된다. 예를 들어, 위의 input은 hotelId라는 이름으로 저장될 것이다.

2.7.1.1. input 타입 선언하기

type 속성을 사용하여 input 속성의 타입을 선언할 수 있다.

<input name="hotelId" type="long" />

만약 input 값이 선언한 타입과 일치하지 않으면, 타입 전환을 시도한다.

2.7.1.2. input 값 대입하기

value 속성을 사용하여 input 값에 대입할 표현식을 기술할 수 있다.

<input name="hotelId" value="flowScope.myParameterObject.hotelId" />

type 속성을 기술하지 않아을 때, 표현식 값의 타입을 판별할 수 있다면 해당 메타데이터를 타입 제약으로 사용할 것이다.

2.7.1.3. input을 필수로 만들기

required 속성을 사용하여 input이 null이거나 빈값이 아니도록 강제할 수 있다.

<input name="hotelId" type="long" value="flowScope.hotelId" required="true" />

2.7.2. output

output 엘리먼트를 사용하여 플로우 output 속성을 선언할 수 있다. output 속성은 특정 플로우 종료를 나타내는 end-states 내부에 선언한다.

<end-state id="bookingConfirmed">
    <output name="bookingId" /> 
</end-state>
       
output 값은 name 속성 값과 일치하는 것을 flow 스코프에서 가져온다. 예를 들어, 위의 output은 bookingId 변수의 값을 대입할 것이다.

2.7.2.1. output 값 기술하기

value 속성을 사용하여 output 값 표현식을 기술할 수 있다.

<output name="confirmationNumber" value="booking.confirmationNumber" /> 

2.7.3. 체크포인트: input/output 맵핑

이제 예제 예약 플로우에서 input/output 맵핑을 다시 살펴보자.

<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

    <input name="hotelId" />

    <on-start>
        <evaluate expression="bookingService.createBooking(hotelId, currentUser.name)"
                  result="flowScope.booking" />
    </on-start>

    <view-state id="enterBookingDetails">
        <transition on="submit" to="reviewBooking" />
    </view-state>
   
    <view-state id="reviewBooking">
        <transition on="confirm" to="bookingConfirmed" />
        <transition on="revise" to="enterBookingDetails" />
        <transition on="cancel" to="bookingCancelled" />
    </view-state>
   
    <end-state id="bookingConfirmed" >
        <output name="bookingId" value="booking.id"/>
    </end-state>

    <end-state id="bookingCancelled" />
       
</flow>   

플로우는 hotelId라는 input 속성을 받고 새로운 예약이 확정되면 bookingId라는 output 속성을 반환한다.

2.8. 변수(Variables)

플로우는 한 개 이상의 변수를 선언할 수 있다. 이들 변수는 플로우가 시작할 때 자리를 잡는다. 변수들이 가지고 있는 모든 @Autowired 임시 레퍼런스들 또한 플로우가 재시작 할 때 다시 와이어링한다.

2.8.1. var

var 엘리먼트를 사용하여 플로우 변수를 선언한다.

<var name="searchCriteria" class="com.mycompany.myapp.hotels.search.SearchCriteria"/>

여러 플로우 요청(request)에 걸쳐 인스턴스 상태를 저장할 때 해당 클래스가 java.io.Serializable을 구현했는지 확인하라.

2.9. subflow 호출하기

플로우에서 다른 플로우를 하위 플로우(subflow)로 호출할 수 있다. 플로우는 서브플로우가 끝날 때까지 기다렸다가 반환값이 오면 그때 서브 플로우 결과에 응답(response)을 한다.

2.9.1. subflow-state

subflow-state 엘리먼트를 사용하여 다른 플로우를 서브플로우로 호출하기

<subflow-state id="addGuest" subflow="createGuest">
    <transition on="guestCreated" to="reviewBooking">
        <evaluate expression="booking.guests.add(currentEvent.attributes.guest)" /> 
    </transition>
    <transition on="creationCancelled" to="reviewBooking" />
</subfow-state>

위의 예제는 createGuest를 호출하고 있다. 그런 다음 반환되기를 기다린다. 플로우가 guestCreated라는 결과를 받으면, 새로운 guest를 booking guest 리스트에 추가한다.

2.9.1.1. subflow input 전달하기

input 엘리먼트를 사용하여 input을 서브플로우에 전달한다.

<subflow-state id="addGuest" subflow="createGuest">
    <input name="booking" />
    <transition to="reviewBooking" />
</subfow-state>

2.9.1.2. 서브플로우 output 맵핑하기

간단하게 서브플로우 output 속성을 결과 트랜지션에서 그 이름으로 참조할 수 있다.

<transition on="guestCreated" to="reviewBooking">
    <evaluate expression="booking.guests.add(currentEvent.attributes.guest)" /> 
</transition>
       
위에서 guest는 guestCreated 결과에 의해 반환되는 output 속성 이름이다.

2.9.2. 체크포인트: 서브플로우 호출하기

<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

    <input name="hotelId" />

    <on-start>
        <evaluate expression="bookingService.createBooking(hotelId, currentUser.name)"
                  result="flowScope.booking" />
    </on-start>

    <view-state id="enterBookingDetails">
        <transition on="submit" to="reviewBooking" />
    </view-state>

    <view-state id="reviewBooking">
        <transition on="addGuest" to="addGuest" />
        <transition on="confirm" to="bookingConfirmed" />
        <transition on="revise" to="enterBookingDetails" />
        <transition on="cancel" to="bookingCancelled" />
    </view-state>

    <subflow-state id="addGuest" subflow="createGuest">
        <transition on="guestCreated" to="reviewBooking">
            <evaluate expression="booking.guests.add(currentEvent.attributes.guest)" /> 
        </transition>
        <transition on="creationCancelled" to="reviewBooking" />
    </subfow-state>
       
    <end-state id="bookingConfirmed" >
        <output name="bookingId" value="booking.id" />
    </end-state>

    <end-state id="bookingCancelled" />
       
</flow>       

플로우는 이제 createGuest 서브플로우를 호출하여 새로운 게스트를 게스트 목록에 추가한다.

'Spring Web Flow > Chapter 2' 카테고리의 다른 글

SWF 2장 플로우 정의하기  (0) 2009.01.02
top


Security Namespace Configuration PART 2



2.3. Advanced Web Features

2.3.1. Adding HTTP/HTTPS Channel Security

애플리케이션에서 요청을 HTTP와 HTTPS로 아무거나 셋 중 하나의 채널로 받아들이도록 설정하려면 <intercept-irl> 의 requires-channel 속성을 사용한다.

  <http>
    <intercept-url pattern="/secure/**" access="ROLE_USER" requires-channel="https"/>
    <intercept-url pattern="/**" access="ROLE_USER" requires-channel="any"/>
    ...
  </http>

/secure/** 패턴의 HTTP를 사용해서 접근하면 HTTPS URL로 리다이렉트 된다. 가용한 옵션은 "http", "https", "any"(둘 중 아무거나)가 있음.

위 프로토콜을 기본 포트가 아닌 다른 포트에서 사용할 때는 포트 맵핑을 해준다.

  <http>
    ...
    <port-mappings>
      <port-mapping http="9080" https="9443"/>
    </port-mappings>
  </http>

채널에 대해서는 여기서 자세히

2.3.2. Concurrent Session Control


단일 사용자 계정을 한 명(세션)만 사용하도록 제한할 수 있다.
먼저 web.xml에 다음 리스너를 등록한다.

<listener>
  <listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class>
</listener>

그리고 application context에 다음을 추가한다.

  <http>
    ...
    <concurrent-session-control max-sessions="1" />
  </http>

이렇게 하면, 같은 계정으로 두 번 로그인 하면, 첫 번째 로그인한 유저가 invalid하게 된다. 두 번째 로그인하는 걸 막고 싶으면 다음과 같이 설정한다.

  <http>
    ...
    <concurrent-session-control max-sessions="1" exception-if-maximum-exceeded="true"/>
  </http>

mac-sessions 속성으로 한 계정당 가용한 세션 수를 정할 수 있나봅니다.

2.3.3. OpenID Login

  <http auto-config='true'>
    <intercept-url pattern="/**" access="ROLE_USER" />
    <openid-login />
  </http>

저렇게 설정하면, OpenID 로그인을 사용하게 된다. 그리고 자신의 OpenID 계정을 설정해야 한다. 그리고 사용자 정보를 in-memory <user-service>에 추가한다.(이건 어떻게 하는거지..?)

<user name="http://jimi.hendrix.myopenid.com/" password="notused" authorities="ROLE_USER" />

2.3.4. Adding in Your Own Filters

이전 버전의 Acegi에서는 커스텀 필터를 필터 체인 중에 끼워넣을 수 있었다. 또는 이미 존재하는 필터를 커스터마이징해서 사용하고 싶을 수 있다. 2.0 이후 부터는 필터 체인이 명시적으로 보이지 않는데 어떻게 해야할까?

네임스페이스를 사용할 때 필터의 순서는 항상 고정되어 있다. 각각의 필터들은 스프링의 Ordered 인터페이스를 구현했고 그에 따라서 초기화 과정에서 정렬된다. 각각 필터들은 다음과 같은 이름으로 맵핑되어 있다.

Alias

Filter Class

CHANNEL_FILTER

ChannelProcessingFilter

CONCURRENT_SESSION_FILTER

ConcurrentSessionFilter

SESSION_CONTEXT_INTEGRATION_FILTER

HttpSessionContextIntegrationFilter

LOGOUT_FILTER

LogoutFilter

X509_FILTER

X509PreAuthenticatedProcessigFilter

PRE_AUTH_FILTER

Subclass of AstractPreAuthenticatedProcessingFilter

CAS_PROCESSING_FILTER

CasProcessingFilter

AUTHENTICATION_PROCESSING_FILTER

AuthenticationProcessingFilter

BASIC_PROCESSING_FILTER

BasicProcessingFilter

SERVLET_API_SUPPORT_FILTER

classname

REMEMBER_ME_FILTER

RememberMeProcessingFilter

ANONYMOUS_FILTER

AnonymousProcessingFilter

EXCEPTION_TRANSLATION_FILTER

ExceptionTranslationFilter

NTLM_FILTER

NtlmProcessingFilter

FILTER_SECURITY_INTERCEPTOR

FilterSecurityInterceptor

SWITCH_USER_FILTER

SwitchUserProcessingFilter



커스텀 필터는 <custom-filter> 엘리먼트를 사용해서 체인에 있는 필터를 교체 할 수 있다.

  <beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter">
    <custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
  </beans:bean>

필터 전 후에 끼워넣고 싶을 때는 after나 before 속성을 사용할 수 있으며 필터 이름 앞에 FIRST나 LAST를 붙일 수 있다.

2.3.5. Session Fixation 공격 방어

세션을 만들어서 사이트에 접속하려는 Session Fixation 공격이 있다. Spring Security는 사용자가 로그인 할 때 자동으로 새로운 세션을 만들어서 이 공격을 막는다. <http> 에 있는 session0-fixation-protection 속성에 다음과 같은 옵션을 사용하여 설정할 수 있다.
  • migrateSession - 새 세션을 만들고 기존의 세션 속성을 새 세션으로 복사한다. 이게 기본값이다.
  • none - 아무것도 하지 않음. 원래 세션을 유지한다.
  • newSession - 완전히 비어있는 clean 세션을 생성하고 기존 세션으로부터 아무것도 복사하지 않는다.
2.3.6. Setting a Custom AuthenticationEntryPoint

네임스페이스가 지원하는 인증 방식이 아닌 다른 방법을 사용하고 있어서 새로운 인증 필터와 Entry Point를 사용한다면 이 것들을 네임스페이스에 끼워넣고 싶을 것이다. AuthenticationEntryPoint 구현체를 <http>의 entry-point-ref 속성에 설정하면 된다.

2.4. Method Security

스프링 시큐리티 2.0 부터는 서비스 계층의 메소드에 JSR-250 시큐리티 애노테이션과 프레임워크의 @Secured 애노테이션을 사용할 수 있다. 빈 설정에 intercept-methods 엘리먼트를 추가하거나 AspectJ 스타일 포인트 컷으로 여러 개의 빈에 적용할 수 있다.

2.4.1. The <global-method-security> Element

이 엘리먼트를 등록해서 애노테이션 기반 보안이 가능하도록 설정한다.

<global-method-security secured-annotations="enabled" jsr250-annotations="true"/>


두 가지 타입의 애노테이션을 모두 지원하도록 설정했다.

2.4.1.1. Adding Security Pointcuts using protect-pointcut

<global-method-security>
    <protect-pointcut expression="execution(* com.mycompany.*Service.*(..))" access="ROLE_USER"/>
</global-method-security>

위 설정은 com.mycompany 패키지에 Service 라는 이름이 들어가는 빈들의 모든 메소드를 보안하도록 설정. ROLE_USER인 사용자만 해당 클래스의 메소드를 호출할 수 있다.

2.5. The Default AccessDecisionManager

여기는 기본적인 롤(ROLE) 기반의 접근 권한 관리 말고 좀 더 커스터마이징 하고자하는 분들을 위한 것임.

네임스페이스를 사용하면 기본 AccessDecisionManager 객체를 생성하고 등록해준다. 그리고 이 녀석을 사용해서 메소드 호출과 web URL 접근 가능 여부를 intercept-url와 protect-pointcut 설정을 바탕으로 결정한다.
기존 전략은 RoleVoter와 AuthenticatedVoter를 하나씩 가지고 있는 AffirmativeBased AccessDecisionManager를 사용한다.

2.5.1. Customizing the AccessDecisionManager

좀 더 복잡한 접근 제어 전략을 사용하려면 메소드와 웹 보안 둘에 대한 대체제를 설정하면 ㅕ된다.

메소드 보안을 용도로는 AccessDecisionmanager 빈을 가리키도록 gloval-security 엘리먼트의 acess-decision-manager-ref 속성을 사용한다.

  <global-method-security access-decision-manager-ref="myAccessDecisionManagerBean">
    ...
  </global-method-security>

웹 보안 접근 제어 대체제는 <http> 에 설정한다.

  <http access-decision-manager-ref="myAccessDecisionManagerBean">
    ...
  </http>

2.5.2. The Authentication Manager

스프링 시큐리티의 네임스페이스를 사용하면 인증 관리자 객체인 ProviderManager 타입의 객체도 생성해서 등록해준다. 이전 버전을 사용해봤다면 매우 친숙한 객체일 것이다.

추가적인 AuthenticationManager를 추가 등록하고 싶을 때 <custom-authentication0provider> 속성을 사용할 수 있다.

  <bean id="casAuthenticationProvider"
      class="org.springframework.security.providers.cas.CasAuthenticationProvider">
    <security:custom-authentication-provider />
    ...
  </bean>

그리고 이렇게 등록한 빈을 컨텍스트 안에 있는 다른 빈들이 AhtehnticationManager라고 참조하도록 별칭을 등록할 수 있다.

  <security:authentication-manager alias="authenticationManager"/>
  <bean id="casProcessingFilter" class="org.springframework.security.ui.cas.CasProcessingFilter">
     <security:custom-filter position="CAS_PROCESSING_FILTER"/>
     <property name="authenticationManager" ref="authenticationManager"/>
     ...
  </bean>




'Spring Security > Chapter 2' 카테고리의 다른 글

Security Namespace Configuration PART 2  (0) 2008.05.07
Security Namespace Configuration PART 1  (8) 2008.05.07
top


Requirements

Spring DM/Chapter 2 : 2008.04.09 12:02


스프링 다이내믹 모듈(DM) 1.0은 JDK 1.4 이상과 OSGi R4 이상을 지원한다.

스프링 DM을 사용해서 배포하는 번들은 반드시 MENIFEST.MF에 "Bundle-ManifestVersion: 2"라고 명시해야 한다.

저게 무슨 뜻이냐면, OSGi R4를 따르는 번들이라는 뜻이다. 스프링 DM이 OSGi R4 이상을 지원하니까 저렇게 해야한다. 2 말고 1이라고 할 수도 있는데 그건 OSGi R3 스펙을 따르는 번들이라는 뜻이다.

스프링 DM은 Continuous Integration의 일부로 Equinox 3.2.2, Felix 1.0.3, Knopflerfish 2.0.4에서 테스트를 한다고 합니다. 멋있어!

'Spring DM > Chapter 2' 카테고리의 다른 글

Requirements  (0) 2008.04.09
top