Skip to content

Commit

Permalink
Dynamic Media with OpenAPI: Add support for local assets (#52)
Browse files Browse the repository at this point in the history
also rename "Next Generation Dynamic Media" to "Dynamic Media with OpenAPI"
  • Loading branch information
stefanseifert authored Jun 17, 2024
1 parent dcacef7 commit 045ccf5
Show file tree
Hide file tree
Showing 27 changed files with 825 additions and 212 deletions.
17 changes: 10 additions & 7 deletions changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@
xsi:schemaLocation="http://maven.apache.org/changes/1.0.0 http://maven.apache.org/plugins/maven-changes-plugin/xsd/changes-1.0.0.xsd">
<body>

<release version="2.0.10" date="not released">
<release version="2.1.0" date="not released">
<action type="add" dev="sseifert" issue="52">
Dynamic Media with OpenAPI: Support Dynamic Media with OpenAPI also for local assets.
</action>
<action type="update" dev="sseifert" issue="53">
Improve trace logging: Make log messages involving value maps and resource/page objects more compact and better readable.
</action>
Expand All @@ -50,16 +53,16 @@

<release version="2.0.2" date="2024-03-13">
<action type="update" dev="sseifert" issue="44">
Next Generation Dynamic Media: Support non-image assets and SVG assets.
Dynamic Media with OpenAPI: Support non-image assets and SVG assets.
</action>
<action type="update" dev="sseifert" issue="45">
Next Generation Dynamic Media: Use latest NextGen Dynamic Media Asset URLs and make them configurable via OSGi config.
Dynamic Media with OpenAPI: Use latest NextGen Dynamic Media Asset URLs and make them configurable via OSGi config.
</action>
<action type="update" dev="sseifert" issue="47">
Next Generation Dynamic Media: Replace fileupload default pick/remote trigger with customized one to display the customized asset selector dialog.
Dynamic Media with OpenAPI: Replace fileupload default pick/remote trigger with customized one to display the customized asset selector dialog.
</action>
<action type="update" dev="sseifert" issue="48">
Next Generation Dynamic Media: Optionally fetch metadata of NGDM asset reference to check for validity and maximum possible resolution.
Dynamic Media with OpenAPI: Optionally fetch metadata of NGDM asset reference to check for validity and maximum possible resolution.
</action>
</release>

Expand All @@ -68,11 +71,11 @@
Version 2.0.0 contains minor breaking API changes, see <a href=https://wcm-io.atlassian.net/wiki/x/AYBxsw">Migrate from wcm.io Handler 1.x to 2.x</a> for details.
]]></action>
<action type="add" dev="sseifert" issue="30"><![CDATA[
Add support for Web-Optimized Image Delivery (part of Next Generation Dynamic Media) - rendering asset renditions from AEM Sites instance on the edge.<br/>
Add support for Web-Optimized Image Delivery (part of Dynamic Media with OpenAPI) - rendering asset renditions from AEM Sites instance on the edge.<br/>
<b>This feature is active by default on AEMaaCS cloud instances, can be disabled via OSGi configuration</b>.
]]></action>
<action type="add" dev="sseifert" issue="38">
Add support for Next Generation Dynamic Media remote assets. This is a first experimental support and will be finalized in release 2.0.2.
Add support for Dynamic Media with OpenAPI (also known as Next Generation Dynamic Media) remote assets. This is a first experimental support and will be finalized in release 2.0.2.
</action>
<action type="add" dev="sseifert" issue="33">
Allow to set image quality per media request.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -115,17 +116,30 @@ final class NextGenDynamicMediaAsset implements Asset {
}

@Override
public <AdapterType> @Nullable AdapterType adaptTo(@NotNull Class<AdapterType> arg0) {
// not adaption supported
@SuppressWarnings("unchecked")
public <AdapterType> @Nullable AdapterType adaptTo(@NotNull Class<AdapterType> type) {
com.day.cq.dam.api.Asset asset = context.getReference().getAsset();
if (asset != null) {
if (type == com.day.cq.dam.api.Asset.class) {
return (AdapterType)asset;
}
if (type == Resource.class) {
return (AdapterType)asset.adaptTo(Resource.class);
}
}
return null;
}

@Override
public String toString() {
return new ToStringBuilder(this)
ToStringBuilder sb = new ToStringBuilder(this)
.append("reference", context.getReference())
.append("metadata", context.getMetadata())
.toString();
.append("metadata", context.getMetadata());
com.day.cq.dam.api.Asset asset = context.getReference().getAsset();
if (asset != null) {
sb.append("asset", asset.getPath());
}
return sb.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -40,7 +39,7 @@
import io.wcm.handler.mediasource.ngdm.impl.NextGenDynamicMediaConfigService;

/**
* Prepares Next Generation Dynamic Media configuration for GraniteUI components (fileupload, pathfield).
* Prepares Next Generation Dynamic Media Remote Assets configuration for GraniteUI components (fileupload, pathfield).
*/
@Model(adaptables = SlingHttpServletRequest.class)
@ProviderType
Expand All @@ -49,7 +48,7 @@ public final class NextGenDynamicMediaConfigModel {
private static final JsonMapper MAPPER = JsonMapper.builder().build();
private static final Logger log = LoggerFactory.getLogger(NextGenDynamicMediaConfigModel.class);

@OSGiService(injectionStrategy = InjectionStrategy.OPTIONAL)
@OSGiService
private NextGenDynamicMediaConfigService config;

private boolean enabled;
Expand All @@ -58,16 +57,14 @@ public final class NextGenDynamicMediaConfigModel {

@PostConstruct
private void activate() {
if (config != null) {
enabled = config.enabled();
assetSelectorsJsUrl = config.getAssetSelectorsJsUrl();
configJson = buildConfigJsonString(config);
}
enabled = config.isEnabledRemoteAssets();
assetSelectorsJsUrl = config.getAssetSelectorsJsUrl();
configJson = buildConfigJsonString(config);
}

private static String buildConfigJsonString(@NotNull NextGenDynamicMediaConfigService config) {
Map<String, Object> map = new TreeMap<>();
map.put("repositoryId", config.getRepositoryId());
map.put("repositoryId", config.getRemoteAssetsRepositoryId());
map.put("apiKey", config.getApiKey());
map.put("env", config.getEnv());
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.adapter.Adaptable;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.commons.mime.MimeTypeService;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osgi.annotation.versioning.ProviderType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.dam.api.Asset;
import com.day.cq.wcm.api.WCMMode;
import com.day.cq.wcm.api.components.ComponentContext;
import com.day.cq.wcm.api.components.EditConfig;
Expand Down Expand Up @@ -71,6 +72,8 @@ public final class NextGenDynamicMediaMediaSource extends MediaSource {
private Adaptable adaptable;
@Self
private MediaHandlerConfig mediaHandlerConfig;
@SlingObject
private ResourceResolver resourceResolver;
@OSGiService(injectionStrategy = InjectionStrategy.OPTIONAL)
private NextGenDynamicMediaConfigService nextGenDynamicMediaConfig;
@OSGiService(injectionStrategy = InjectionStrategy.OPTIONAL)
Expand All @@ -83,24 +86,22 @@ public final class NextGenDynamicMediaMediaSource extends MediaSource {
@AemObject(injectionStrategy = InjectionStrategy.OPTIONAL)
private ComponentContext componentContext;

private static final Logger log = LoggerFactory.getLogger(NextGenDynamicMediaMediaSource.class);

@Override
public @NotNull String getId() {
return ID;
}

@Override
public boolean accepts(@Nullable String mediaRef) {
return isNextGenDynamicMediaEnabled() && NextGenDynamicMediaReference.isReference(mediaRef);
}

private boolean isNextGenDynamicMediaEnabled() {
if (nextGenDynamicMediaConfig == null) {
log.debug("NGDM media source is disabled: com.adobe.cq.ui.wcm.commons.config.NextGenDynamicMediaConfig is not available.");
return false;
}
return nextGenDynamicMediaConfig.enabled();
return (nextGenDynamicMediaConfig.isEnabledRemoteAssets() && NextGenDynamicMediaReference.isReference(mediaRef))
|| (nextGenDynamicMediaConfig.isEnabledLocalAssets() && isDamAssetReference(mediaRef));
}

private boolean isDamAssetReference(@Nullable String mediaRef) {
return StringUtils.startsWith(mediaRef, "/content/dam/");
}

@Override
Expand All @@ -114,8 +115,8 @@ private boolean isNextGenDynamicMediaEnabled() {
MediaArgs mediaArgs = media.getMediaRequest().getMediaArgs();

// check reference and enabled status
NextGenDynamicMediaReference reference = NextGenDynamicMediaReference.fromReference(mediaRef);
if (reference == null || !isNextGenDynamicMediaEnabled()) {
NextGenDynamicMediaReference reference = toNextGenDynamicMediaReference(mediaRef);
if (reference == null || nextGenDynamicMediaConfig == null) {
if (StringUtils.isEmpty(mediaRef)) {
media.setMediaInvalidReason(MediaInvalidReason.MEDIA_REFERENCE_MISSING);
}
Expand All @@ -127,7 +128,11 @@ private boolean isNextGenDynamicMediaEnabled() {

// If enabled: Fetch asset metadata to validate existence and get original dimensions
NextGenDynamicMediaMetadata metadata = null;
if (metadataService != null && metadataService.isEnabled()) {
Asset localAsset = reference.getAsset();
if (localAsset != null) {
metadata = getMetadataFromAsset(localAsset);
}
else if (metadataService != null && metadataService.isEnabled()) {
metadata = metadataService.fetchMetadata(reference);
if (metadata == null) {
media.setMediaInvalidReason(MediaInvalidReason.MEDIA_REFERENCE_INVALID);
Expand Down Expand Up @@ -162,6 +167,26 @@ private boolean isNextGenDynamicMediaEnabled() {
return media;
}

private @Nullable NextGenDynamicMediaReference toNextGenDynamicMediaReference(@Nullable String mediaRef) {
if (nextGenDynamicMediaConfig != null) {
if (nextGenDynamicMediaConfig.isEnabledRemoteAssets() && NextGenDynamicMediaReference.isReference(mediaRef)) {
return NextGenDynamicMediaReference.fromReference(mediaRef);
}
else if (nextGenDynamicMediaConfig.isEnabledLocalAssets() && isDamAssetReference(mediaRef)) {
return NextGenDynamicMediaReference.fromDamAssetReference(mediaRef, resourceResolver);
}
}
return null;
}

private @Nullable NextGenDynamicMediaMetadata getMetadataFromAsset(@NotNull Asset asset) {
NextGenDynamicMediaMetadata metadata = NextGenDynamicMediaMetadata.fromAsset(asset);
if (metadata.isValid()) {
return metadata;
}
return null;
}

@Override
public void enableMediaDrop(@NotNull HtmlElement element, @NotNull MediaRequest mediaRequest) {
if (wcmMode == WCMMode.DISABLED || wcmMode == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ final class NextGenDynamicMediaRendition implements Rendition {
private MediaFormat resolvedMediaFormat;
private long width;
private long height;
private String fileExtension;

private static final Logger log = LoggerFactory.getLogger(NextGenDynamicMediaRendition.class);

Expand Down Expand Up @@ -87,6 +88,11 @@ final class NextGenDynamicMediaRendition implements Rendition {
}
}

this.fileExtension = mediaArgs.getEnforceOutputFileExtension();
if (StringUtils.isEmpty(this.fileExtension)) {
this.fileExtension = FilenameUtils.getExtension(reference.getFileName());
}

if (isVectorImage() || !isImage()) {
// deliver as binary
this.url = buildBinaryUrl();
Expand All @@ -98,6 +104,7 @@ else if (isRequestedDimensionLargerThanOriginal()) {
else {
// deliver scaled image rendition
this.url = buildImageRenditionUrl();
this.fileExtension = new NextGenDynamicMediaImageUrlBuilder(context).getFileExtension();
}
}

Expand Down Expand Up @@ -169,11 +176,7 @@ private String buildBinaryUrl() {

@Override
public @Nullable String getFileExtension() {
String extension = mediaArgs.getEnforceOutputFileExtension();
if (StringUtils.isEmpty(extension)) {
extension = FilenameUtils.getExtension(reference.getFileName());
}
return extension;
return this.fileExtension;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,15 @@ public NextGenDynamicMediaBinaryUrlBuilder(@NotNull NextGenDynamicMediaContext c
public @Nullable String build() {

// get parameters from nextgen dynamic media config for URL parameters
String repositoryId = context.getNextGenDynamicMediaConfig().getRepositoryId();
String repositoryId;
if (context.getReference().getAsset() != null) {
repositoryId = context.getNextGenDynamicMediaConfig().getLocalAssetsRepositoryId();
}
else {
repositoryId = context.getNextGenDynamicMediaConfig().getRemoteAssetsRepositoryId();
}
String binaryDeliveryPath = context.getNextGenDynamicMediaConfig().getAssetOriginalBinaryDeliveryPath();
if (StringUtils.isAnyEmpty(repositoryId, binaryDeliveryPath)) {
if (StringUtils.isAnyBlank(repositoryId, binaryDeliveryPath)) {
return null;
}

Expand Down
Loading

0 comments on commit 045ccf5

Please sign in to comment.