1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.handler.mediasource.ngdm.impl.metadata;
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.List;
26
27 import org.apache.commons.lang3.StringUtils;
28 import org.apache.http.Header;
29 import org.apache.http.HttpHost;
30 import org.apache.http.HttpStatus;
31 import org.apache.http.client.config.RequestConfig;
32 import org.apache.http.client.methods.CloseableHttpResponse;
33 import org.apache.http.client.methods.HttpGet;
34 import org.apache.http.impl.client.CloseableHttpClient;
35 import org.apache.http.impl.client.HttpClientBuilder;
36 import org.apache.http.message.BasicHeader;
37 import org.apache.http.util.EntityUtils;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
40 import org.osgi.service.component.annotations.Activate;
41 import org.osgi.service.component.annotations.Component;
42 import org.osgi.service.component.annotations.Deactivate;
43 import org.osgi.service.component.annotations.Reference;
44 import org.osgi.service.component.annotations.ReferencePolicy;
45 import org.osgi.service.component.annotations.ReferencePolicyOption;
46 import org.osgi.service.metatype.annotations.AttributeDefinition;
47 import org.osgi.service.metatype.annotations.Designate;
48 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 import io.wcm.handler.mediasource.ngdm.impl.NextGenDynamicMediaConfigService;
53 import io.wcm.handler.mediasource.ngdm.impl.NextGenDynamicMediaReference;
54
55
56
57
58 @Component(service = NextGenDynamicMediaMetadataService.class, immediate = true)
59 @Designate(ocd = NextGenDynamicMediaMetadataServiceImpl.Config.class)
60 public class NextGenDynamicMediaMetadataServiceImpl implements NextGenDynamicMediaMetadataService {
61
62 @ObjectClassDefinition(
63 name = "wcm.io Media Handler Next Generation Dynamic Media Metadata Service",
64 description = "Fetches metadata for Next Generation Dynamic Media assets.")
65 @interface Config {
66
67 @AttributeDefinition(
68 name = "Enabled",
69 description = "When enabled, metadata is fetched for each resolved asset. This checks for validity/existence of "
70 + "the asset and for the maximum supported resolution of the original image.")
71 boolean enabled() default false;
72
73 @AttributeDefinition(
74 name = "HTTP Headers",
75 description = "HTTP headers to be send with the asset metadata request. "
76 + "Format: 'header1:value1'.")
77 String[] httpHeaders() default { "X-Adobe-Accept-Experimental:1" };
78
79 @AttributeDefinition(
80 name = "Connect Timeout",
81 description = "HTTP Connect timeout in milliseconds.")
82 int connectTimeout() default 5000;
83
84 @AttributeDefinition(
85 name = "Connection Request Timeout",
86 description = "HTTP connection request timeout in milliseconds.")
87 int connectionRequestTimeout() default 5000;
88
89 @AttributeDefinition(
90 name = "Socket Timeout",
91 description = "HTTP socket timeout in milliseconds.")
92 int socketTimeout() default 5000;
93
94 @AttributeDefinition(
95 name = "Proxy Host",
96 description = "Proxy host name")
97 String proxyHost();
98
99 @AttributeDefinition(
100 name = "Proxy Port",
101 description = "Proxy port")
102 int proxyPort();
103
104 }
105
106 @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY)
107 private NextGenDynamicMediaConfigService nextGenDynamicMediaConfig;
108
109 private boolean enabled;
110 private CloseableHttpClient httpClient;
111
112 private static final Logger log = LoggerFactory.getLogger(NextGenDynamicMediaMetadataServiceImpl.class);
113
114 @Activate
115 private void activate(Config config) {
116 this.enabled = config.enabled();
117 if (enabled) {
118 httpClient = createHttpClient(config);
119 }
120 }
121
122 private static CloseableHttpClient createHttpClient(Config config) {
123 RequestConfig requestConfig = RequestConfig.custom()
124 .setConnectTimeout(config.connectTimeout())
125 .setConnectionRequestTimeout(config.connectionRequestTimeout())
126 .setSocketTimeout(config.socketTimeout())
127 .build();
128 HttpClientBuilder builder = HttpClientBuilder.create()
129 .setDefaultRequestConfig(requestConfig)
130 .setDefaultHeaders(convertHeaders(config.httpHeaders()));
131 if (StringUtils.isNotBlank(config.proxyHost()) && config.proxyPort() > 0) {
132 builder.setProxy(new HttpHost(config.proxyHost(), config.proxyPort()));
133 }
134 return builder.build();
135 }
136
137 private static Collection<Header> convertHeaders(String[] headers) {
138 List<Header> result = new ArrayList<>();
139 for (String header : headers) {
140 String[] parts = header.split(":", 2);
141 if (parts.length == 2) {
142 result.add(new BasicHeader(parts[0], parts[1]));
143 }
144 }
145 return result;
146 }
147
148 @Deactivate
149 private void deactivate() throws IOException {
150 if (httpClient != null) {
151 httpClient.close();
152 }
153 }
154
155 @Override
156 public boolean isEnabled() {
157 return enabled;
158 }
159
160
161
162
163
164
165 @Override
166 public @Nullable NextGenDynamicMediaMetadata fetchMetadata(@NotNull NextGenDynamicMediaReference reference) {
167 if (!enabled) {
168 return null;
169 }
170 String metadataUrl = new NextGenDynamicMediaMetadataUrlBuilder(nextGenDynamicMediaConfig).build(reference);
171 if (metadataUrl == null) {
172 return null;
173 }
174
175 HttpGet httpGet = new HttpGet(metadataUrl);
176 try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
177 return processResponse(response, metadataUrl);
178 }
179 catch (IOException ex) {
180 log.warn("Unable to fetch NGDM asset metadata from URL {}", metadataUrl, ex);
181 return null;
182 }
183 }
184
185 private @Nullable NextGenDynamicMediaMetadata processResponse(@NotNull CloseableHttpResponse response,
186 @NotNull String metadataUrl) throws IOException {
187 switch (response.getStatusLine().getStatusCode()) {
188 case HttpStatus.SC_OK:
189 String jsonResponse = EntityUtils.toString(response.getEntity());
190 NextGenDynamicMediaMetadata metadata = NextGenDynamicMediaMetadata.fromJson(jsonResponse);
191 log.trace("HTTP response for NGDM asset metadata {} returns: {}", metadataUrl, metadata);
192 if (metadata.isValid()) {
193 return metadata;
194 }
195 break;
196 case HttpStatus.SC_NOT_FOUND:
197 log.trace("HTTP response for NGDM asset metadata {} returns HTTP 404", metadataUrl);
198 break;
199 default:
200 log.warn("Unexpected HTTP response for NGDM asset metadata {}: {}", metadataUrl, response.getStatusLine());
201 break;
202 }
203 return null;
204 }
205
206 }