Oracle EBS OAF 개발 완벽 가이드 2편 – 개인화, 확장, 커스텀 페이지 개발과 R12.2 배포

1편에서 JDeveloper를 띄우고 Hello World까지 확인했다면, 이제 진짜 일이 들어옵니다. “공급업체 화면에 관리항목 하나 추가해 주세요”라는 요청을 받았을 때, 이걸 클릭 몇 번으로 끝낼 수 있는지 자바 클래스를 새로 짜야 하는지 판단하는 것이 OAF 개발자의 첫 번째 실력입니다. 판단을 잘못하면 30분이면 될 일이 3일이 되거나, 반대로 패치 한 번에 날아갈 코드를 만들게 됩니다.

01 — Decision세 가지 길: 개인화 · 확장 · 신규 개발

OAF에서 화면을 바꾸는 방법은 크게 세 가지입니다. 그리고 세 가지는 난이도, 소요 시간, 패치 내구성이 전부 다릅니다. 요구사항을 받으면 코드를 열기 전에 이 분류부터 하세요.

OAF 요구사항 분류 결정 트리 — 개인화, 확장, 신규 개발 중 선택하는 기준
FIG.05 — 요구사항 분류 결정 트리. 표준 페이지의 XML이나 자바 소스를 직접 수정하는 선택지는 이 트리에 없습니다. 오라클이 지원하지 않는 방식이기 때문입니다.
절대 금지

표준 OAF 페이지의 XML이나 오라클이 제공한 .class 파일을 직접 수정하거나 덮어쓰는 방식은 오라클 미지원(unsupported)입니다. 패치가 올라오면 파일이 원본으로 교체되면서 작업이 통째로 사라지고, SR을 열어도 지원받지 못합니다. 반드시 위 세 가지 중 하나로 처리하세요.

STEP 1

Personalization — 코딩 없이 화면 바꾸기

OAF로 만들어진 페이지는 기본적으로 전부 개인화가 가능합니다. 개발자가 특정 속성을 꺼두거나 프로그램으로 동적 생성한 항목만 예외입니다. 실무 요구사항의 절반 이상이 이 단계에서 끝납니다.

1-1. 준비: 프로파일 옵션

1편에서 켰던 Personalize Self-Service Defn = Yes가 되어 있어야 페이지 상단에 Personalize Page 링크가 나타납니다.

1-2. 개인화 레벨 이해하기

가장 헷갈리는 부분입니다. 개인화는 어느 레벨에 저장하느냐에 따라 적용 범위가 달라집니다.

레벨적용 대상우선순위실무 용도
Site인스턴스 전체 사용자가장 낮음전사 공통 화면 정비
Organization특정 조직법인별 항목 차이
Responsibility특정 책임가장 많이 씀. 부서별 화면 분리
User개인가장 높음사용자 본인 설정. 타인에게 안 보임

충돌하면 더 좁은 범위가 이깁니다. Site에서 숨긴 항목을 특정 Responsibility에서 다시 보이게 할 수 있습니다.

1-3. 실습: 필드 하나 숨기기

  1. 대상 페이지에서 Personalize Page 클릭
  2. 상단에서 개인화 레벨(보통 Responsibility) 선택 후 Expand All
  3. 트리에서 대상 Item 찾기 — 이름이 비슷한 게 많아서 헷갈리면, 화면으로 돌아가 About this Page > Page Definition에서 실제 Item ID를 먼저 확인
  4. 해당 행의 연필 아이콘(Personalize) 클릭
  5. Rendered 속성을 False로 변경 후 Apply

페이지로 돌아가면 즉시 반영돼 있습니다. 서버 재기동도, 캐시 삭제도 필요 없습니다.

이것도 가능

Personalization으로 새 버튼이나 링크를 추가하는 것도 됩니다. Region에 Create Item으로 버튼을 만들고 Destination URI에 다른 OAF 페이지나 함수를 연결하면, 자바 코드 한 줄 없이 화면 간 이동을 붙일 수 있습니다. DFF 세그먼트 노출/숨김도 여기서 처리합니다.

1-4. 개인화 이관과 관리

개인화 결과는 파일이 아니라 DB의 JDR 저장소에 XML 문서로 저장됩니다. 그래서 개발기에서 운영기로 옮기려면 XML로 뽑아서 넣어야 합니다. Functional Administrator 책임의 Personalization > Import/Export 화면을 쓰거나, 서버에서 XMLExporter/XMLImporter를 직접 실행합니다.

어떤 개인화가 걸려 있는지 확인할 때는 JDR_UTILS 패키지가 유용합니다.

-- 특정 패키지 경로에 걸린 커스터마이징 목록 조회
SET SERVEROUTPUT ON SIZE 1000000;
EXEC jdr_utils.listCustomizations('/oracle/apps/pos/supplier/webui/SuppSummPG');

-- 해당 문서 내용을 XML로 출력
EXEC jdr_utils.printDocument('/oracle/apps/pos/.../customizations/site/0/SuppSummPG');

-- 잘못 만든 개인화 삭제 (운영 반영 전 반드시 백업)
EXEC jdr_utils.deleteDocument('...위 경로...');
COMMIT;
STEP 2

커스텀 페이지 개발 — 만드는 순서가 정해져 있다

신규 페이지를 만들 때는 Model 계층을 먼저, View를 나중에 만듭니다. 화면부터 그리면 나중에 데이터를 붙일 때 다 갈아엎게 됩니다. 순서는 아래와 같습니다.

OAF 커스텀 페이지 개발 7단계 순서 — EO, AO, VO, AM에서 Page, Region, Controller까지
FIG.06 — 커스텀 페이지 개발 순서. Model(1~4) → View(5~6) → Controller(7). 이 순서를 지키면 중간에 되돌아가는 일이 거의 없습니다.

최소 골격 코드

AM에 조회 메서드를 하나 만들고, CO에서 호출하는 가장 기본적인 형태입니다.

// ── AM: XXInvoiceAMImpl.java ─────────────────────────
public void initInvoiceQuery(String vendorId) {
    XXInvoiceVOImpl vo = getXXInvoiceVO1();     // AM에 붙인 VO 인스턴스
    vo.setWhereClauseParams(null);              // 이전 파라미터 초기화 (필수)
    vo.setWhereClauseParam(0, vendorId);
    vo.executeQuery();
}

// ── CO: XXInvoiceCO.java ─────────────────────────────
public void processRequest(OAPageContext pageContext, OAWebBean webBean) {
    super.processRequest(pageContext, webBean);

    OAApplicationModule am = pageContext.getApplicationModule(webBean);
    String vendorId = pageContext.getParameter("VendorId");
    am.invokeMethod("initInvoiceQuery", new Serializable[]{ vendorId });
}

public void processFormRequest(OAPageContext pageContext, OAWebBean webBean) {
    super.processFormRequest(pageContext, webBean);

    if (pageContext.getParameter("ApplyBtn") != null) {
        OAApplicationModule am = pageContext.getApplicationModule(webBean);
        am.invokeMethod("saveInvoice");
        pageContext.forwardImmediatelyToCurrentPage(null, true, ADD_BREAD_CRUMB_NO);
    }
}
자주 나는 버그

setWhereClauseParams(null)을 빼먹으면 파라미터가 계속 누적돼서 두 번째 조회부터 JBO-27122 같은 오류가 납니다. VO에 조건을 넣기 전에는 항상 초기화 먼저입니다.

STEP 3

네이밍 규칙 — 여기서 어긋나면 배포가 안 됩니다

OAF에서 커스텀 오브젝트의 패키지 경로는 취향의 문제가 아니라 규칙입니다. 규칙을 어기면 EBS 패치가 내 파일을 덮어쓰거나, R12.2 온라인 패치 환경에서 배포 자체가 실패합니다.

OAF 커스텀 패키지 네이밍 규칙 분해도 — 접두어, 모듈, webui/server 계층 구분
FIG.07 — 커스텀 패키지 네이밍 규칙. 접두어(xxkal)를 맨 앞에 두는 것이 핵심이며, R12.2에서는 이 규칙이 특히 엄격합니다.
R12.2 주의

커스텀 클래스의 패키지를 oracle.apps.xx...처럼 oracle로 시작하게 만들면 안 됩니다. 오라클 소유 네임스페이스를 침범하는 것이라 온라인 패치 과정에서 문제가 생깁니다. 반드시 xxkal.oracle.apps.... 형태로 커스텀 접두어를 맨 앞에 두세요. 관련 내용은 MOS Doc ID 1609939.1에 정리돼 있습니다.

STEP 4

Extension — 표준 화면의 동작 바꾸기

Personalization으로는 안 되고, 그렇다고 화면을 새로 만들 수도 없을 때 쓰는 방법입니다. 원리는 단순합니다. 오라클 표준 클래스를 상속받아 내 클래스를 만들고, 런타임에 표준 대신 내 것이 호출되게 바꿔치기합니다.

OAF VO Extension과 CO Extension 구조 비교 — 표준 클래스 상속과 Substitution 적용 방식
FIG.08 — VO Extension과 CO Extension의 차이. VO는 JPX 임포트로 치환하고, CO는 개인화 화면에서 클래스 경로만 바꿔 끼웁니다.

CO Extension 예시

package xxkal.oracle.apps.pos.supplier.webui;

import oracle.apps.pos.supplier.webui.SuppSummCO;

public class XXSuppSummCO extends SuppSummCO {

  public void processRequest(OAPageContext pageContext, OAWebBean webBean) {
    super.processRequest(pageContext, webBean);   // ← 절대 빼먹지 말 것

    // 표준 화면이 다 그려진 뒤, 내 로직 추가
    OAMessageCheckBoxBean cb =
        (OAMessageCheckBoxBean) webBean.findChildRecursive("TaxYnFlag");
    if (cb != null) {
      cb.setValue(pageContext, "Y");              // 기본값 체크 상태로
    }
  }

  public void processFormRequest(OAPageContext pageContext, OAWebBean webBean) {
    // 표준 로직 실행 전에 검증을 넣고 싶다면 super 앞에 배치
    if (pageContext.getParameter("Apply") != null) {
      String v = pageContext.getParameter("XXCustomField");
      if (v == null || v.trim().length() == 0) {
        throw new OAException("필수 항목을 입력하세요.", OAException.ERROR);
      }
    }
    super.processFormRequest(pageContext, webBean);
  }
}
순서가 곧 로직

super 호출을 앞에 두면 표준 동작이 끝난 뒤 내 코드가 실행되고(후처리), 뒤에 두면 표준 동작 전에 내 코드가 먼저 실행됩니다(전처리·검증). 검증은 대개 super 앞, 값 세팅은 super 뒤입니다.

STEP 5

배포 — R12.1과 R12.2는 절차가 다릅니다

OAF 산출물은 성격이 두 가지입니다. 자바 클래스(.class)는 파일시스템에, 페이지 정의(.xml)는 DB의 JDR 저장소에 들어갑니다. 그래서 배포도 두 갈래로 진행됩니다.

Oracle EBS R12.2 온라인 패치 환경의 OAF 배포 흐름 — fs1과 fs2 파일시스템, cutover 절차
FIG.09 — R12.2 배포 흐름. 12.1.3까지는 RUN 파일시스템에 바로 복사하면 됐지만, 12.2는 PATCH 에디션에 작업한 뒤 cutover로 전환하는 구조입니다.

XML 임포트 명령

# 환경변수 로드 후 실행
$ import XXInvoicePG.xml \
    -username apps -password <apps_pwd> \
    -rootdir /home/appluser/deploy \
    -dbconnection "(description=(address_list=(address=(protocol=tcp)
       (host=ebsdb.example.com)(port=1521))) (connect_data=(sid=EBSPRD)))"

VO Substitution 등록 (JPX)

$ java oracle.jrad.tools.xml.importer.JPXImporter XXPOSExt.jpx \
    -username apps -password <apps_pwd> \
    -dbconnection "(description=(address_list=(address=(protocol=tcp)
       (host=ebsdb.example.com)(port=1521))) (connect_data=(sid=EBSPRD)))"

# 임포트 후 반드시 미들티어 캐시 초기화 또는 재기동
반영이 안 될 때

배포했는데 화면이 그대로라면 대부분 캐시 문제입니다. Functional Administrator 책임 > Core Services > Caching Framework > Global Configuration에서 해당 캐시를 Clear 하거나, 개발 환경이라면 adopmnctl.sh로 OACore를 바운스하세요. JPX 임포트 후에는 재기동이 사실상 필수입니다.

02 — Debugging디버깅 실전

OAF는 서버에서 무슨 일이 일어나는지 보기가 까다롭습니다. 세 가지 무기를 씁니다.

1. 로그 남기기

if (pageContext.isLoggingEnabled(OAFwkConstants.STATEMENT)) {
    pageContext.writeDiagnostics(this,
        "[XXInvoiceCO] vendorId = " + vendorId, OAFwkConstants.STATEMENT);
}

프로파일 FND: Debug Log Enabled = Yes, FND: Debug Log Level = Statement를 켜고, FND_LOG_MESSAGES 테이블을 조회하면 됩니다.

2. About This Page 활용

페이지 하단 링크에서 Page Definition 탭을 열면 실행 중인 페이지의 Region/Item ID, 연결된 VO, 적용된 Controller 클래스가 전부 보입니다. “이 필드 이름이 뭐지?”를 추측하지 말고 여기서 확인하세요.

3. VO 쿼리 확인

ViewObject vo = am.findViewObject("XXInvoiceVO1");
pageContext.writeDiagnostics(this,
    "SQL = " + vo.getQuery(), OAFwkConstants.STATEMENT);
pageContext.writeDiagnostics(this,
    "ROWS = " + vo.getRowCount(), OAFwkConstants.STATEMENT);

바인드 변수가 실제로 어떻게 들어갔는지, 행이 0건인지 아닌지 여기서 바로 갈립니다.

03 — Checklist운영 반영 전 점검표

  • 커스텀 패키지가 xx 접두어로 시작하는가 (표준 네임스페이스 침범 없음)
  • 표준 오브젝트를 직접 수정한 곳이 없는가
  • CO Extension에서 super 호출을 빠뜨린 메서드가 없는가
  • VO Extension에서 표준 컬럼의 순서나 이름을 바꾸지 않았는가
  • 하드코딩된 조직 ID, 사용자 ID, 책임 ID가 없는가
  • 메시지를 코드에 직접 쓰지 않고 FND_NEW_MESSAGES에 등록했는가 (다국어 대응)
  • 개인화를 개발기에서 운영기로 이관할 XML을 확보했는가
  • JPX 임포트 후 미들티어 재기동 계획이 잡혀 있는가
  • 롤백 시나리오 — jdr_utils.deleteDocument 대상 경로를 미리 기록했는가

04 — Reference참고 문서

문서번호내용
OAF Developer’s Guide버전별 PDF8장 코딩 표준 필독. Oracle Help Center에 공개
OAF Personalization GuideR12.2 문서개인화로 가능한 범위 전체 목록
JDeveloper 패치 대응표Doc ID 416708.1EBS 버전별 JDev 패치 번호
R12.2 커스터마이징 개발·배포Doc ID 1577661.11.6.3.5절이 OAF 확장 배포
커스텀 패키지 네이밍Doc ID 1609939.112.2에서의 패키지 접두어 규칙
R12.2 OAF 업그레이드 고려사항Doc ID 1927975.1기존 커스터마이징의 12.2 전환

정리

OAF 개발의 실력 차이는 화려한 화면을 만드는 데서 나오지 않습니다. 요구사항을 받았을 때 개인화로 끝낼지 확장으로 갈지 정확히 판단하고, 다음 패치에도 살아남는 방식으로 구현하는 것 — 이게 전부입니다. FIG.05의 결정 트리와 FIG.07의 네이밍 규칙 두 장만 몸에 붙어 있어도 대부분의 프로젝트는 무난히 굴러갑니다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤