1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.caravan.pipeline.extensions.hal.client.action;
21
22 import static io.wcm.caravan.io.http.request.CaravanHttpRequest.CORRELATION_ID_HEADER_NAME;
23
24 import java.util.Collection;
25 import java.util.Map;
26
27 import org.apache.commons.lang3.StringUtils;
28 import org.apache.http.client.methods.HttpGet;
29 import org.osgi.annotation.versioning.ProviderType;
30
31 import com.google.common.collect.Multimap;
32
33 import io.wcm.caravan.hal.resource.Link;
34 import io.wcm.caravan.io.http.request.CaravanHttpRequest;
35 import io.wcm.caravan.io.http.request.CaravanHttpRequestBuilder;
36 import io.wcm.caravan.pipeline.JsonPipeline;
37 import io.wcm.caravan.pipeline.JsonPipelineContext;
38 import io.wcm.caravan.pipeline.JsonPipelineExceptionHandler;
39 import io.wcm.caravan.pipeline.JsonPipelineOutput;
40 import io.wcm.caravan.pipeline.cache.CacheControlUtils;
41 import io.wcm.caravan.pipeline.cache.CacheStrategy;
42 import io.wcm.caravan.pipeline.extensions.hal.client.ServiceIdExtractor;
43 import rx.Observable;
44
45
46
47
48 @ProviderType
49 public final class LoadLink extends AbstractHalClientAction {
50
51 private final ServiceIdExtractor serviceId;
52 private final Link link;
53 private final Map<String, Object> parameters;
54 private String httpMethod = HttpGet.METHOD_NAME;
55
56
57
58
59
60
61 public LoadLink(String serviceId, Link link, Map<String, Object> parameters) {
62 this.serviceId = (path) -> serviceId;
63 this.link = link;
64 this.parameters = parameters;
65 }
66
67
68
69
70
71
72 public LoadLink(ServiceIdExtractor serviceId, Link link, Map<String, Object> parameters) {
73 this.serviceId = serviceId;
74 this.link = link;
75 this.parameters = parameters;
76 }
77
78 @Override
79 public String getId() {
80 return "LOAD-LINK(" + httpMethod + "-" + serviceId.getServiceId(link.getHref()) + '-' + StringUtils.defaultIfBlank(link.getName(), "") + '-'
81 + parameters.hashCode() + ")";
82 }
83
84 @Override
85 public Observable<JsonPipelineOutput> execute(JsonPipelineOutput previousStepOutput, JsonPipelineContext pipelineContext) {
86
87 CaravanHttpRequest request = createRequest(previousStepOutput);
88 JsonPipeline pipeline = createPipeline(pipelineContext, request);
89 return pipeline.getOutput().map(jsonPipelineOutput -> {
90
91 int maxAge = CacheControlUtils.getLowestMaxAge(jsonPipelineOutput, previousStepOutput);
92 return jsonPipelineOutput.withMaxAge(maxAge);
93
94 });
95
96 }
97
98
99
100
101
102 public HalClientAction withHttpMethod(String httpMethodToUse) {
103 this.httpMethod = httpMethodToUse;
104 return this;
105 }
106
107 private CaravanHttpRequest createRequest(JsonPipelineOutput previousStepOutput) {
108
109 CaravanHttpRequestBuilder builder = getRequestBuilder();
110 builder = setCacheControlHeaderIfExists(builder, previousStepOutput);
111 builder = setCorrelationIdIfExists(builder, previousStepOutput);
112 builder = setAdditionalHttpHeadersIfExists(builder);
113 builder = builder.method(httpMethod);
114 return builder.build(parameters);
115
116 }
117
118 private JsonPipeline createPipeline(JsonPipelineContext context, CaravanHttpRequest request) {
119
120 if (hasLogger()) {
121 getLogger().debug("Execute request: " + request);
122 }
123 JsonPipeline pipeline = context.getFactory().create(request, context.getProperties());
124 pipeline = setCacheStrategyIfExists(pipeline);
125 pipeline = addExceptionHandlers(pipeline);
126 return pipeline;
127
128 }
129
130
131
132
133 public String getUrl() {
134 return getRequestBuilder().build(parameters).getUrl();
135 }
136
137 private CaravanHttpRequestBuilder getRequestBuilder() {
138 return new CaravanHttpRequestBuilder(serviceId.getServiceId(link.getHref())).append(link.getHref());
139 }
140
141
142
143
144
145
146 private JsonPipeline setCacheStrategyIfExists(JsonPipeline pipeline) {
147 if (!HttpGet.METHOD_NAME.equals(httpMethod)) {
148 return pipeline;
149 }
150 else {
151 CacheStrategy cacheStrategy = getCacheStrategy();
152 return cacheStrategy == null ? pipeline : pipeline.addCachePoint(cacheStrategy);
153 }
154 }
155
156
157
158
159
160
161
162 private CaravanHttpRequestBuilder setCacheControlHeaderIfExists(CaravanHttpRequestBuilder builder, JsonPipelineOutput previousStepOutput) {
163
164 if (previousStepOutput.getRequests().isEmpty()) {
165 return builder;
166 }
167 CaravanHttpRequest previousRequest = previousStepOutput.getRequests().get(0);
168 Collection<String> cacheControlHeader = previousRequest.getHeaders().get("Cache-Control");
169 if (cacheControlHeader == null || cacheControlHeader.isEmpty()) {
170 return builder;
171 }
172 return builder.header("Cache-Control", cacheControlHeader);
173
174 }
175
176
177
178
179
180
181
182
183 private CaravanHttpRequestBuilder setCorrelationIdIfExists(CaravanHttpRequestBuilder builder, JsonPipelineOutput previousStepOutput) {
184 return previousStepOutput.getCorrelationId() == null ? builder : builder.header(CORRELATION_ID_HEADER_NAME, previousStepOutput.getCorrelationId());
185 }
186
187
188
189
190
191
192 private JsonPipeline addExceptionHandlers(JsonPipeline pipeline) {
193
194 JsonPipeline newPipeline = pipeline;
195 for (JsonPipelineExceptionHandler handler : getExceptionHandlers()) {
196 newPipeline = newPipeline.handleException(handler);
197 }
198 return newPipeline;
199
200 }
201
202
203
204
205
206
207 private CaravanHttpRequestBuilder setAdditionalHttpHeadersIfExists(CaravanHttpRequestBuilder builder) {
208 getHttpHeaders().keySet().forEach(name -> builder.header(name, getHttpHeaders().get(name)));
209 return builder;
210 }
211
212 }