View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2024 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.handler.mediasource.ngdm.impl;
21  
22  import java.util.regex.Matcher;
23  import java.util.regex.Pattern;
24  
25  import org.apache.commons.lang3.StringUtils;
26  import org.apache.sling.api.resource.Resource;
27  import org.apache.sling.api.resource.ResourceResolver;
28  import org.jetbrains.annotations.NotNull;
29  import org.jetbrains.annotations.Nullable;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  import com.day.cq.dam.api.Asset;
34  
35  /**
36   * Parses and validates Dynamic Media with OpenAPI asset references.
37   *
38   * <p>
39   * Example: <code>/urn:aaid:aem:12345678-abcd-abcd-abcd-abcd12345678/my-image.jpg</code>
40   * </p>
41   */
42  public final class NextGenDynamicMediaReference {
43  
44    private static final Pattern REFERENCE_PATTERN = Pattern.compile("^/(urn:[^/]+)/([^/]+)$");
45    private static final String ASSET_ID_PREFIX = "urn:";
46  
47    private final String assetId;
48    private final String fileName;
49    private final Asset asset;
50  
51    private static final Logger log = LoggerFactory.getLogger(NextGenDynamicMediaReference.class);
52  
53    /**
54     * @param assetId Asset ID (has to start with "urn:")
55     * @param fileName File name
56     */
57    public NextGenDynamicMediaReference(@NotNull String assetId, @NotNull String fileName) {
58      this(assetId, fileName, null);
59    }
60  
61    /**
62     * @param assetId Asset ID (has to start with "urn:")
63     * @param fileName File name
64     */
65    public NextGenDynamicMediaReference(@NotNull String assetId, @NotNull String fileName, @Nullable Asset asset) {
66      if (!StringUtils.startsWith(assetId, ASSET_ID_PREFIX)) {
67        throw new IllegalArgumentException("Asset ID must start with '" + ASSET_ID_PREFIX + "'");
68      }
69      this.assetId = assetId;
70      this.fileName = fileName;
71      this.asset = asset;
72    }
73  
74    /**
75     * @return Asset ID
76     */
77    public @NotNull String getAssetId() {
78      return assetId;
79    }
80  
81    /**
82     * @return File name
83     */
84    public @NotNull String getFileName() {
85      return fileName;
86    }
87  
88    /**
89     * @return Asset (if reference points to local asset)
90     */
91    public @Nullable Asset getAsset() {
92      return asset;
93    }
94  
95    /**
96     * @return True if reference points to local asset.
97     */
98    public boolean isLocal() {
99      return asset != null;
100   }
101 
102   /**
103    * @return Reference
104    */
105   public @NotNull String toReference() {
106     return "/" + assetId + "/" + fileName;
107   }
108 
109   /**
110    * Parses a next generation dynamic media reference.
111    * @param reference Reference
112    * @return Parsed reference or null if reference is invalid
113    */
114   public static @Nullable NextGenDynamicMediaReference fromReference(@Nullable String reference) {
115     if (reference == null) {
116       return null;
117     }
118     Matcher matcher = REFERENCE_PATTERN.matcher(reference);
119     if (!matcher.matches()) {
120       return null;
121     }
122     String assetId = matcher.group(1);
123     String fileName = matcher.group(2);
124     return new NextGenDynamicMediaReference(assetId, fileName);
125   }
126 
127   /**
128    * Parses a next generation dynamic media reference.
129    * @param reference Reference
130    * @return Parsed reference or null if reference is invalid
131    */
132   public static @Nullable NextGenDynamicMediaReference fromDamAssetReference(@Nullable String reference, @NotNull ResourceResolver resourceResolver) {
133     if (reference == null) {
134       return null;
135     }
136     Resource resource = resourceResolver.getResource(reference);
137     if (resource == null) {
138       return null;
139     }
140     Asset asset = resource.adaptTo(Asset.class);
141     if (asset == null) {
142       return null;
143     }
144     String uuid = asset.getID();
145     if (StringUtils.isBlank(uuid)) {
146       log.trace("Ignoring DAM asset without UUID: {}", asset.getPath());
147       return null;
148     }
149     String assetId = "urn:aaid:aem:" + uuid;
150     String fileName = asset.getName();
151     return new NextGenDynamicMediaReference(assetId, fileName, asset);
152   }
153 
154   /**
155    * Checks if given string is a valid next generation dynamic media reference.
156    * @param reference Reference
157    * @return true if reference is valid
158    */
159   public static boolean isReference(@Nullable String reference) {
160     return reference != null && REFERENCE_PATTERN.matcher(reference).matches();
161   }
162 
163   @Override
164   public String toString() {
165     return toReference();
166   }
167 
168 }