목차
Behavior Implementation
이전시간에 생성한 Behavior Definition은 기능들을 선언만 해두는 껍데기일 뿐이고 진짜 ABAP코딩은 다른곳에서 이루어 집니다. 이번 시간에는 RAP 모델의 심장이자 비즈니스 로직의 실체인 Behavior Implementation에 대해서 알아보겠습니다.
Behavior Implementation 이란?
개발자 관점에서 간단히 설명하면 Behavior Implementation은 실제 작동하는 ABAP 소스코드를 채워넣는 특수 ABAP Class입니다. 이 Class는 일반 클래스(SE24)와 달리 FOR BEHAVIOR OF 라는 특수 구문이 붙으며 Eclipse ADT환경에서만 관리가 가능한 RAP전용 비즈니스 로직 Class입니다. 이런 특징이 있고 실제 코딩은 일반 클래스와 동일하니 ABAP개발자가 개발하기에 어려움은 없습니다.
내부 구조: 두 개의 강력한 페이즈(Phase)
이부분은 워낙 중요한 개념이라 설명을 하고 넘어가겠습니다. Behaviro Implementation 클래스 내부를 보면 (보통 Local Type Tab에 숨겨져 있습니다) 두개의 단계로 명확하게 나뉘어 작동합니다.
- Interaction Phase (상호단계: LCL_HANDLER) : 사용자가 화면에서 값을 바꾸거나 버튼을 누르는 실시간 이벤트 처리를 하는 곳입니다. 저장 전까지의 기능들이 이곳에서 처리 된다고 생각하시면 됩니다.
- Save Sequence Phase (저장단계: LCL_SAVER) : 사용자가 최종(Save)버튼을 눌러 데이터가 DB로 완전히 들어가는 순간 한번 실행되는 단계입니다.
두개의 Phase에서 수행할 수 있는 메소드는 각각 정해져 있고 우리가 Behavior Definition에서 기능을 선언하게 되면 그 기능이 자동으로 메소드화 되어 개발자는 해당 메소드 안에 필요한 로직만 구현하면 됩니다.
EML (Entity Manipulation Language)
데이터베이스 테이블을 직접 건드리지 않고 RAP 비즈니스 객체의 엔티티 단위를 안전하게 읽고(READ), 수정(MODIFY)하고, 실행(EXECUTE)하기 위해 만든 RAP전용 ABAP확장 문법입니다. Transaction Buffer를 사용하는 BO에서 직접 DB SELECT를 하게되면 최신 DATA를 못가져오는 경우가 발생할 수 있습니다. 이러한 문제점 때문에 EML 문법을 통한 로직을 구현해야 합니다.
EML에 대해서는 따로 시간을 할애하여 자세하게 설명하도록 하겠습니다.
자 이제 다시 App을 실행시켜 보겠습니다. 저번시간에 Go 버튼을 눌렀을때 에러가 발생했습니다. Eclipse로 가서 에러 원인을 확인해 보겠습니다.

Eclipse 하단에 Feed Reader 텝을 들어가 보겠습니다.

혹시 Feed Reader 텝이 없으면 Window -> Show View -> Other... 에서 feed로 검색하면 나옵니다.

서버명 위에 마우스 오른쪽 클릭 후 Refresh 를 클릭합니다.

시간대를 확인하고 실제 Go 버튼을 누른 시간과 비슷한 시간대의 덤프Log 를 더블클릭 합니다. 더블클릭하면 우측화면 또는 상단 화면에서 덤프내역을 확인 할 수 있습니다. 덤프확인은 SAP GUI에서 확인하는 방식으로 확인하면 됩니다. (오류 내역 복사해서 AI로 확인 또는 구글에서 확인) RAP개발을 계속 하다보면 자주 발생하는 덤프는 에러유형만 봐도 원인파악이 가능해 집니다.

덤프내용을 보면 INSTANCE_AUTHORIZATION Method가 구현되지 않았다고 합니다. Behavior Implementation의 Class를 생성해서 본격적으로 구현을 해보겠습니다. 다시 Behavior Definition으로 이동합니다.

Interface Behavior Definition이 생성될때 Class이름이 자동으로 지정이 됩니다. Class이름에 마우스 커스를 놓고 Ctrl + 1 을 눌러 Quick Assist를 엽니다. 그리고 Create Behavior Implementation class.. 를 더블클릭 합니다.

Next 버튼을 클릭합니다.

아래와 같이 Class가 생성되었습니다. 현재 만들고 있는 App에서 기능을 구현하기 위해 ABAP로직이 필요하면 이 Class에 모두 구현한다고 생각하시면 됩니다. 앞으로 자주 와야될 곳입니다. 아래 보면 몇개의 Method가 생성되어 있습니다. 그중에 get_instance_authorizations 라는 Method도 있습니다. 일단 활성화 하고 App을 다시한번 실행해 보겠습니다.

Go 버튼을 누르면 이번엔 정상적으로 조회됩니다. 그럼 저 Method들이 왜 생겼는지 살펴보겠습니다. 다시 Interface Behavior Definition으로 가보겠습니다.

Interface Behavior Definition을 생성했을때 기본으로 존재하는 instance authorization 이 있고 global authorization 이 있습니다. 그리고 Draft 기능을 사용하기 위해 아직은 어떤 기능인지 잘 모르지만 draft action 4개도 추가했습니다. 이 상태에서 Class를 생성하게 되면 시스템이 Class를 생성할때 Interface Behavior Definition을 확인하고 Method가 필요한 기능들은 자동으로 Method를 생성해 줍니다. Method가 존재한다고 하는건 우리가 해당 Method에 로직을 추가하여 제어할 수 있는 기능이라고 생각하시면 됩니다. Class가 생성된 후에 기능추가시에도 추가한 기능이 Method가 필요한 기능이라면 Quick Assist 기능으로 Method를 추가할 수 있습니다. 이건 앞으로 실습해 볼때 보여드리겠습니다.

다시 App으로 돌아가 보겠습니다. 현재 조회된 데이터를 한번 확인하시고 Create 버튼을 클릭해 보겠습니다.

생성화면으로 이동했습니다. 생성은 우리가 만든 Object Page에서 생성하게 됩니다. Travel 정보를 생성하는 것이기 때문에 Travel 정보를 입력하는 필드들이 Edit 필드로 되어 있습니다. Travel ID 필드는 Key필드라 비활성화 되어 있습니다. 자동으로 비활성화 되는건 아니고 Interface Behavior Definition을 보면 Travel ID필드는 readonly로 되어 있습니다. Key필드는 자동으로 채번되도록 구현할 예정입니다. 먼저 Draft기능이 어떻게 작동되는지 확인해 보겠습니다. 아래와 같이 입력을 하고 저장 하지 않은 상태에서 Draft 테이블을 확인해 보겠습니다.

Shift + Ctrl + A를 눌러 Draft 테이블 ZEVER_TRAVEL_D를 입력합니다. 그리고 조회된 테이블을 선택하고 OK 버튼을 클릭합니다.

입력한 데이터가 Draft 테이블에 즉시 저장이 된 걸 확인할 수 있습니다. 실제 테이블에는 저장되기 전입니다. 이 상태에서 현재 실행되어 있는 App창을 닫고 다시 실행해 보겠습니다.

실행해보면 방금 작업중인 데이터도 같이 조회가 됩니다. 이처럼 Draft 기능을 활성화 하면 작업중이던 정보를 임시저장하고 예기치 못한 상황이 발생 하더라도 이어서 작업할 수 있게 됩니다. 작업중이던 데이터를 선택해서 Object Page로 들어가 봅니다.

여기에서 Create 버튼을 누르면 입력한 정보가 본 테이블에 저장이 되면서 Draft 테이블의 정보는 삭제가 됩니다. 만약 본 테이블에 저장하지 않고 Draft 테이블만 삭제할때는 Discard Draft 버튼을 누르면 됩니다. Discard Draft 버튼을 눌러보겠습니다. 그리고 다시 Draft 테이블을 확인해 보겠습니다.

Draft 테이블에서 데이터가 삭제되었습니다. Draft 기능과 관련된 기본 기능들은 시스템이 알아서 해줍니다. 어떻게 알고 시스템이 알아서 처리해줄까요? 네 눈치 채셨겠지만 바로 Interface Behavior Definition에 Draft 관련 Action 을 추가해 주었기 때문입니다. Action 추가만으로 시스템은 Draft 의 기본기능을 수행해 주고 기본 기능이외의 로직을 추가하고 싶다면 Implementation Class의 Draft 관련 Method에 로직을 추가해 주면 됩니다. 하지만 이번 실습에서는 Draft 기본기능만으로도 충분합니다.

다음시간에는 Travel ID를 자동채번해서 실제 데이터를 생성해 보겠습니다. 지금은 생성할때마다 Key값을 빈값으로 생성하려고 시도하기 때문에 Key중복으로 오류가 발생할 것입니다.