1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.caravan.io.http.impl.servletclient;
21
22 import java.io.IOException;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.concurrent.ConcurrentMap;
26 import java.util.concurrent.ConcurrentSkipListMap;
27
28 import javax.servlet.Servlet;
29 import javax.servlet.ServletException;
30
31 import org.apache.felix.scr.annotations.Component;
32 import org.apache.felix.scr.annotations.Reference;
33 import org.apache.felix.scr.annotations.ReferenceCardinality;
34 import org.apache.felix.scr.annotations.ReferencePolicy;
35 import org.apache.felix.scr.annotations.Service;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import com.google.common.collect.Sets;
40
41 import io.wcm.caravan.io.http.CaravanHttpClient;
42 import io.wcm.caravan.io.http.IllegalResponseRuntimeException;
43 import io.wcm.caravan.io.http.RequestFailedRuntimeException;
44 import io.wcm.caravan.io.http.impl.CaravanHttpServiceConfigValidator;
45 import io.wcm.caravan.io.http.request.CaravanHttpRequest;
46 import io.wcm.caravan.io.http.response.CaravanHttpResponse;
47 import rx.Observable;
48
49
50
51
52 @Component
53 @Service(ServletHttpClient.class)
54 public class ServletHttpClient implements CaravanHttpClient {
55
56 private static final Logger LOG = LoggerFactory.getLogger(ServletHttpClient.class);
57
58 @Reference(referenceInterface = Servlet.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
59 private final ConcurrentMap<String, Servlet> servlets = new ConcurrentSkipListMap<>();
60
61 private final Set<String> failedServices = Sets.newHashSet();
62 protected void bindServlet(Servlet servlet, Map<String, Object> config) {
63 String serviceId = (String)config.get("alias");
64 if (serviceId != null) {
65 servlets.put(serviceId, servlet);
66 }
67 }
68
69 protected void unbindServlet(Servlet servle, Map<String, Object> config) {
70 String serviceId = (String)config.get("alias");
71 if (serviceId != null) {
72 servlets.remove(serviceId);
73 }
74 }
75
76 @Override
77 public Observable<CaravanHttpResponse> execute(CaravanHttpRequest request) {
78 return Observable.just(request.getServiceId())
79 .map(serviceId -> getServlet(serviceId))
80 .map(servlet -> executeServlet(servlet, request));
81 }
82
83 @Override
84 public Observable<CaravanHttpResponse> execute(CaravanHttpRequest request, Observable<CaravanHttpResponse> fallback) {
85 return execute(request);
86 }
87
88 @Override
89 public boolean hasValidConfiguration(String serviceId) {
90 return servlets.containsKey(serviceId) && !failedServices.contains(serviceId);
91 }
92
93 private Servlet getServlet(String serviceId) {
94
95 Servlet servlet = servlets.get(serviceId);
96 if (servlet == null) {
97 throw new IllegalStateException("No local servlet registered for " + serviceId);
98 }
99 return servlet;
100
101 }
102
103 private CaravanHttpResponse executeServlet(Servlet servlet, CaravanHttpRequest request) {
104
105 LOG.debug("Execute: {},\n{}", request.toString(), request.getCorrelationId());
106 HttpServletRequestMapper requestMapper = new HttpServletRequestMapper(request);
107 HttpServletResponseMapper responseMapper = new HttpServletResponseMapper();
108 try {
109 servlet.service(requestMapper, responseMapper);
110 CaravanHttpResponse response = responseMapper.getResponse();
111
112 int status = response.status();
113 boolean throwExceptionForStatus500 = CaravanHttpServiceConfigValidator.throwExceptionForStatus500(request.getServiceId());
114 if (status >= 500 && throwExceptionForStatus500) {
115 String requestUrl = request.getUrl();
116 String responseBody = response.body().asString();
117 throw new IllegalResponseRuntimeException(request, requestUrl, status, responseBody,
118 "Executing '" + requestUrl + "' failed: " + responseBody);
119 }
120 return response;
121 }
122 catch (NotSupportedByRequestMapperException ex) {
123 failedServices.add(request.getServiceId());
124 throw ex;
125 }
126 catch (ServletException | IOException ex) {
127 throw new RequestFailedRuntimeException(request, ex.getMessage(), ex);
128 }
129
130 }
131
132 }