Java™ API 모범 사례

Adobe Experience Manager(AEM)는 개발 중에 사용할 수 있도록 많은 Java™ API를 노출하는 풍부한 오픈 소스 소프트웨어 스택을 기반으로 구축됩니다. 이 문서에서는 주요 API와 이러한 API를 사용해야 하는 시기 및 이유를 살펴봅니다.

AEM은 4개의 기본 Java™ API 세트를 기반으로 구축됩니다.

  • Adobe Experience Manager(AEM)

    • 페이지, 에셋, 워크플로 등과 같은 제품 추상화
  • Apache Sling 웹 프레임워크

    • 리소스, 값 맵 및 HTTP 요청과 같은 REST 및 리소스 기반 추상화입니다.
  • JCR(Apache Jackrabbit Oak)

    • 노드, 속성 및 세션과 같은 데이터 및 콘텐츠 추상화입니다.
  • OSGi(Apache Felix)

    • 서비스 및 (OSGi) 구성 요소와 같은 OSGi 애플리케이션 컨테이너 추상.

Java™ API 환경 설정 "경험에 근거한 규칙"

일반적인 규칙은 다음 순서로 API/추상화를 선호하는 것입니다.

  1. AEM
  2. Sling
  3. JCR
  4. OSGi

AEM에서 API를 제공하는 경우 Sling, JCR 및 OSGi보다 선호합니다. AEM에서 API를 제공하지 않는 경우 JCR 및 OSGi보다 Sling을(를) 선호합니다.

이 순서는 일반적인 규칙이며, 예외가 존재함을 의미합니다. 이 규칙을 벗어나는 데 사용할 수 있는 이유는 다음과 같습니다.

  • 아래에 설명된 대로 잘 알려진 예외 사항입니다.

  • 필요한 기능은 더 높은 수준의 API에서 사용할 수 없습니다.

  • 자체 선호도가 낮은 API를 사용하는 기존 코드(사용자 지정 또는 AEM 제품 코드) 컨텍스트에서 작동하고 새 API로 이동하는 비용은 정당하지 않습니다.

    • 혼합을 만드는 것보다 더 낮은 수준의 API를 일관되게 사용하는 것이 더 좋습니다.

AEM API

AEM API는 제품화된 사용 사례와 관련된 추상화 및 기능을 제공합니다.

예를 들어 AEM의 PageManagerPage API는 웹 페이지를 나타내는 AEM의 cq:Page 노드에 대한 추상을 제공합니다.

Sling API를 리소스로 사용하고 JCR API를 노드로 사용하여 이러한 노드를 사용할 수 있지만, AEM의 API는 일반적인 사용 사례에 대한 추상을 제공합니다. AEM API를 사용하면 AEM 제품과 AEM에 대한 사용자 지정 및 확장 간에 일관된 동작이 보장됩니다.

com.adobe.*과(와) com.day 비교.*개 API

AEM API에는 기본 설정 순서로 다음 Java™ 패키지로 식별되는 패키지 내 기본 설정이 있습니다.

  1. com.adobe.cq
  2. com.adobe.granite
  3. com.day.cq

com.adobe.cq 패키지는 제품 사용 사례를 지원하는 반면 com.adobe.granite은(는) 워크플로 또는 작업(AEM Assets, Sites 등 제품에서 사용됨)과 같은 제품 간 플랫폼 사용 사례를 지원합니다.

com.day.cq 패키지에 "원본" API가 포함되어 있습니다. 이러한 API는 Adobe이 Day CQ을(를) 획득하기 전 및/또는 주변에서 존재했던 핵심 추상 및 기능을 해결합니다. com.adobe.cq 또는 com.adobe.granite 패키지가 (최신) 대체 요소를 제공하지 않는 한 이러한 API는 지원되며 사용하지 않아야 합니다.

Content Fragments 및 Experience Fragments과(와) 같은 새 추상이 아래 설명된 com.day.cq이(가) 아닌 com.adobe.cq 공간에 작성되었습니다.

쿼리 API

AEM은 여러 쿼리 언어를 지원합니다. 세 가지 주요 언어는 JCR-SQL2, XPath 및 AEM Query Builder입니다.

가장 중요한 문제는 코드 베이스 전반에 걸쳐 일관된 쿼리 언어를 유지함으로써 복잡성과 이해 비용을 줄이는 것입니다.

Apache Oak이(가) 최종 쿼리 실행을 위해 JCR-SQL2에 트랜스-더미하므로 모든 쿼리 언어에는 효과적으로 동일한 성능 프로필이 있으며 JCR-SQL2로의 전환 시간은 쿼리 시간 자체에 비해 무시할 수 있습니다.

기본 API는 최상위 수준의 추상화이며 쿼리에 대한 결과를 구성, 실행 및 검색하는 강력한 API를 제공하는 AEM Query Builder이며, 다음을 제공합니다.

CAUTION
AEM QueryBuilder API가 ResourceResolver 개체를 누출합니다. 이 누출을 완화하려면 이 코드 샘플을 따르십시오.

Sling개 API

Apache Sling은(는) AEM의 기반이 되는 RESTful 웹 프레임워크입니다. Sling은(는) HTTP 요청 라우팅을 제공하고, JCR 노드를 리소스로 모델링하고, 보안 컨텍스트를 제공하는 등의 다양한 기능을 제공합니다.

Sling API에는 확장용으로 빌드되는 추가적인 이점이 있습니다. 즉, 확장 가능성이 낮은 JCR API보다 Sling API를 사용하여 빌드된 응용 프로그램의 동작을 더 쉽고 안전하게 늘릴 수 있습니다.

Sling API의 일반적인 사용

JCR API

JCR(Java™ Content Repository) 2.0 API는 JCR 구현 사양의 일부입니다(AEM의 경우 Apache Jackrabbit Oak). 모든 JCR 구현은 이러한 API를 준수하고 구현해야 하며, 따라서 AEM 콘텐츠와 상호 작용하기 위한 가장 낮은 수준의 API입니다.

JCR 자체는 AEM이 컨텐츠 저장소로 사용하는 계층/트리 기반의 NoSQL 데이터 저장소입니다. JCR에는 콘텐츠 CRUD에서 콘텐츠 쿼리에 이르기까지 지원되는 다양한 API가 있습니다. 이러한 강력한 API에도 불구하고 높은 수준의 AEM 및 Sling 추상화보다 선호되는 경우는 거의 없습니다.

항상 Apache Jackrabbit Oak API보다 JCR API를 선호합니다. JCR API는 JCR 리포지토리와 상호 작용 ​하는 데 사용되는 반면, Oak API는 JCR 리포지토리를 구현 ​하는 데 사용됩니다.

JCR API에 대한 일반적인 오해

JCR은 AEM의 콘텐츠 저장소이지만 해당 API는 콘텐츠와 상호 작용하기 위한 기본 방법이 아닙니다. 대신 더 나은 추상화를 제공할 수 있으므로 AEM API(페이지, Assets, 태그 등) 또는 Sling 리소스 API를 선호합니다.

CAUTION
AEM 애플리케이션에서 JCR API의 세션 및 노드 인터페이스를 광범위하게 사용하는 것은 코드 효과입니다. 대신 Sling API를 사용해야 합니다.

JCR API의 일반적인 사용

OSGi API

OSGi API와 상위 수준 API(AEM, Sling 및 JCR) 간에 겹치는 부분이 거의 없으며, OSGi API를 사용해야 하는 경우는 드물어 높은 수준의 AEM 개발 전문 지식이 필요합니다.

OSGi와 Apache Felix API 비교

OSGi는 모든 OSGi 컨테이너가 구현하고 준수해야 하는 사양을 정의합니다. AEM의 OSGi 구현인 Apache Felix는 몇 가지 자체 API도 제공합니다.

  • Apache Felix API(org.apache.felix)보다 OSGi API(org.osgi)를 선호합니다.

OSGi API의 일반적인 사용

규칙에 대한 예외

다음은 위에서 정의한 규칙에 대한 일반적인 예외입니다.

OSGi API

OSGi 구성 요소 속성에서 정의하거나 읽는 것과 같은 낮은 수준의 OSGi 추상을 처리할 때, org.osgi에서 제공하는 최신 추상이 높은 수준의 Sling 추정보다 선호됩니다. 경쟁하는 Sling 추상이 @Deprecated(으)로 표시되지 않았으며 org.osgi 대체 요소를 제안합니다.

또한 OSGi 구성 노드 정의는 sling:OsgiConfig 형식보다 cfg.json을(를) 선호합니다.

AEM Asset API

  • com.adobe.granite.asset.api보다 com.day.cq.dam.api을(를) 선호합니다.

    • com.day.cq Assets API는 AEM의 에셋 관리 사용 사례에 더 많은 무료 도구를 제공합니다.
    • Granite Assets API는 낮은 수준의 에셋 관리 사용 사례(버전, 관계)를 지원합니다.

쿼리 API

  • AEM QueryBuilder는 제안, 맞춤법 검사 및 인덱스 힌트와 같은 덜 일반적인 함수 중 특정 쿼리 함수를 지원하지 않습니다. 이러한 함수로 쿼리하려면 JCR-SQL2가 좋습니다.

Sling 서블릿 등록 sling-servlet-registration

Sling 필터 등록 sling-filter-registration

유용한 코드 조각

다음은 논의된 API를 사용하는 일반적인 사용 사례에 대한 모범 사례를 보여 주는 유용한 Java™ 코드 조각입니다. 이러한 스니펫은 선호도가 낮은 API에서 선호도가 높은 API로 이동하는 방법을 보여 줍니다.

Sling ResourceResolver에 대한 JCR 세션

Sling ResourceResolver 자동 닫기

AEM 6.2 이후 Sling ResourceResolver는 try-with-resources 문에서 AutoClosable입니다. 이 구문을 사용하면 resourceResolver .close()에 대한 명시적 호출이 필요하지 않습니다.

@Reference
ResourceResolverFactory rrf;
...
Map<String, Object> authInfo = new HashMap<String, Object>();
authInfo.put(JcrResourceConstants.AUTHENTICATION_INFO_SESSION, jcrSession);

try (ResourceResolver resourceResolver = rrf.getResourceResolver(authInfo)) {
    // Do work with the resourceResolver
} catch (LoginException e) { .. }

Sling ResourceResolver를 수동으로 닫음

위에 표시된 자동 닫기 기술을 사용할 수 없는 경우 finally 블록에서 ResourceResolver를 수동으로 닫아야 합니다.

@Reference
ResourceResolverFactory rrf;
...
Map<String, Object> authInfo = new HashMap<String, Object>();
authInfo.put(JcrResourceConstants.AUTHENTICATION_INFO_SESSION, jcrSession);

ResourceResolver resourceResolver = null;

try {
    resourceResolver = rrf.getResourceResolver(authInfo);
    // Do work with the resourceResolver
} catch (LoginException e) {
   ...
} finally {
    if (resourceResolver != null) { resourceResolver.close(); }
}

Sling Resource에 대한 JCR 경로

Resource resource = ResourceResolver.getResource("/path/to/the/resource");

Sling Resource에 대한 JCR 노드

Resource resource = resourceResolver.getResource(node.getPath());

AEM 자산에 대한 Sling Resource

권장 접근 방식

DamUtil.resolveToAsset(..) 함수는 필요에 따라 트리 위로 이동하여 dam:Asset 아래의 모든 리소스를 에셋 개체로 확인합니다.

Asset asset = DamUtil.resolveToAsset(resource);

대안적 접근

리소스를 자산에 적용하려면 리소스 자체가 dam:Asset 노드여야 합니다.

Asset asset = resource.adaptTo(Asset.class);

AEM 페이지에 대한 Sling 리소스

권장 접근 방식

pageManager.getContainingPage(..)은(는) 필요에 따라 트리 위로 이동하여 cq:Page 아래의 모든 리소스를 페이지 개체로 확인합니다.

PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
Page page = pageManager.getContainingPage(resource);
Page page2 = pageManager.getContainingPage("/content/path/to/page/jcr:content/or/component");

대안적 접근 alternative-approach-1

리소스를 페이지에 적용하려면 리소스 자체가 cq:Page 노드여야 합니다.

Page page = resource.adaptTo(Page.class);

AEM 페이지 속성 읽기

Page 개체의 getter를 사용하여 잘 알려진 속성(getTitle(), getDescription() 등)을 가져오고 page.getProperties()을(를) 사용하여 다른 속성을 검색하기 위한 [cq:Page]/jcr:content ValueMap을 가져옵니다.

Page page = resource.adaptTo(Page.class);
String title = page.getTitle();
Calendar value = page.getProperties().get("cq:lastModified", Calendar.getInstance());

AEM Asset 메타데이터 속성 읽기

Asset API는 [dam:Asset]/jcr:content/metadata 노드에서 속성을 읽는 데 편리한 방법을 제공합니다. 이 매개 변수는 ValueMap이 아니며 두 번째 매개 변수(기본값 및 자동 유형 캐스팅)는 지원되지 않습니다.

Asset asset = resource.adaptTo(Asset.class);
String title = asset.getMetadataValue("dc:title");
Calendar lastModified = (Calendar) asset.getMetadata("cq:lastModified");

Sling Resource 속성 읽기 read-sling-resource-properties

AEM API(Page, Asset)가 직접 액세스할 수 없는 위치(속성 또는 상대 리소스)에 속성이 저장되면 Sling 리소스 및 ValueMaps를 사용하여 데이터를 가져올 수 있습니다.

ValueMap properties = resource.getValueMap();
String value = properties.get("jcr:title", "Default title");
String relativeResourceValue = properties.get("relative/propertyName", "Default value");

이 경우 원하는 속성이나 하위 리소스를 효율적으로 찾으려면 AEM 개체를 Sling Resource (으)로 변환해야 할 수 있습니다.

Sling Resource (으)로 페이지 AEM

Resource resource = page.adaptTo(Resource.class);

자산을 Sling Resource (으)로 AEM

Resource resource = asset.adaptTo(Resource.class);

Sling의 ModifiableValueMap을 사용하여 속성을 씁니다.

Sling의 ModifiableValueMap을(를) 사용하여 노드에 속성을 씁니다. 직접 실행 노드에만 쓸 수 있습니다(상대 속성 경로는 지원되지 않음).

.adaptTo(ModifiableValueMap.class)을(를) 호출하려면 리소스에 대한 쓰기 권한이 필요하지만 그렇지 않으면 null을 반환합니다.

ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class);

properties.put("newPropertyName", "new value");
properties.put("propertyNameToUpdate", "updated value");
properties.remove("propertyToRemove");

resource.getResourceResolver().commit();

AEM 페이지 만들기

AEM에서 페이지를 제대로 정의하고 초기화하는 데 필요한 페이지 템플릿 을 사용할 때 항상 페이지 관리자를 사용하여 페이지를 만듭니다.

String templatePath = "/conf/my-app/settings/wcm/templates/content-page";
boolean autoSave = true;

PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
pageManager.create("/content/parent/path", "my-new-page", templatePath, "My New Page Title", autoSave);

if (!autoSave) { resourceResolver.commit(); }

Sling 리소스 만들기

ResourceResolver는 리소스를 만드는 기본 작업을 지원합니다. 상위 수준 추상화(AEM Pages, Assets, Tags 등)를 만들 때는 해당 관리자가 제공하는 메서드를 사용합니다.

resourceResolver.create(parentResource, "my-node-name", new ImmutableMap.Builder<String, Object>()
           .put("jcr:primaryType", "nt:unstructured")
           .put("jcr:title", "Hello world")
           .put("propertyName", "Other initial properties")
           .build());

resourceResolver.commit();

Sling 리소스 삭제

ResourceResolver가 리소스 제거를 지원합니다. 상위 수준 추상화(AEM Pages, Assets, Tags 등)를 만들 때는 해당 관리자가 제공하는 메서드를 사용합니다.

resourceResolver.delete(resource);

resourceResolver.commit();
recommendation-more-help
c92bdb17-1e49-4e76-bcdd-89e4f85f45e6