1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.common.keymaster.client.self;
20
21 import java.util.List;
22 import java.util.Map;
23 import java.util.concurrent.CompletionStage;
24 import javax.ws.rs.Path;
25 import javax.ws.rs.client.Entity;
26 import javax.ws.rs.core.MediaType;
27 import javax.ws.rs.core.Response;
28 import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
29 import org.apache.syncope.common.keymaster.client.api.KeymasterException;
30 import org.apache.syncope.common.keymaster.client.api.ServiceOps;
31 import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
32 import org.apache.syncope.common.keymaster.rest.api.service.NetworkServiceService;
33 import org.apache.syncope.common.keymaster.rest.api.service.NetworkServiceService.Action;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.springframework.util.backoff.BackOffExecution;
37 import org.springframework.util.backoff.ExponentialBackOff;
38
39 public class SelfKeymasterServiceOps extends SelfKeymasterOps implements ServiceOps {
40
41 private static final Logger LOG = LoggerFactory.getLogger(ServiceOps.class);
42
43 private final int maxRetries;
44
45 private final String path;
46
47 public SelfKeymasterServiceOps(final JAXRSClientFactoryBean clientFactory, final int maxRetries) {
48 super(clientFactory);
49 this.maxRetries = maxRetries;
50 this.path = NetworkServiceService.class.getAnnotation(Path.class).value();
51 }
52
53 @Override
54 public List<NetworkService> list(final NetworkService.Type serviceType) {
55 try {
56 return client(NetworkServiceService.class, Map.of()).list(serviceType);
57 } catch (KeymasterException e) {
58 throw e;
59 } catch (Exception e) {
60 throw new KeymasterException(e);
61 }
62 }
63
64 @Override
65 public NetworkService get(final NetworkService.Type serviceType) {
66 try {
67 return client(NetworkServiceService.class, Map.of()).get(serviceType);
68 } catch (KeymasterException e) {
69 throw e;
70 } catch (Exception e) {
71 throw new KeymasterException(e);
72 }
73 }
74
75 private void handleRetry(
76 final NetworkService service,
77 final Action action,
78 final int retries,
79 final BackOffExecution backOffExecution) {
80
81 try {
82 if (action == Action.register && retries > 0) {
83 long nextBackoff = backOffExecution.nextBackOff();
84
85 LOG.debug("Still {} retries available for {}; waiting for {} ms", retries, service, nextBackoff);
86 try {
87 Thread.sleep(nextBackoff);
88 } catch (InterruptedException e) {
89
90 }
91
92 retry(completionStage(action, service), service, action, retries - 1, backOffExecution);
93 } else {
94 LOG.debug("No more retries {} for {}", action, service);
95 }
96 } catch (Throwable t) {
97 LOG.error("Could not continue {} for {}, aborting", action, service, t);
98 }
99 }
100
101 private void retry(
102 final CompletionStage<Response> completionStage,
103 final NetworkService service,
104 final Action action,
105 final int retries,
106 final BackOffExecution backOffExecution) {
107
108 completionStage.whenComplete((response, throwable) -> {
109 if (throwable == null && response.getStatus() < 300) {
110 LOG.info("{} successfully " + action + "ed", service);
111 } else {
112 LOG.error("Could not " + action + " {}", service, throwable);
113
114 handleRetry(service, action, retries, backOffExecution);
115 }
116 }).exceptionally(throwable -> {
117 LOG.error("Could not " + action + " {}", service, throwable);
118
119 handleRetry(service, action, retries, backOffExecution);
120
121 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
122 });
123 }
124
125 private CompletionStage<Response> completionStage(final Action action, final NetworkService service) {
126 return rx(path + "?action=" + action.name()).post(Entity.entity(service, MediaType.APPLICATION_JSON));
127 }
128
129 @Override
130 public void register(final NetworkService service) {
131 retry(completionStage(Action.register, service),
132 service, Action.register, maxRetries, new ExponentialBackOff(5000L, 1.5).start());
133 }
134
135 @Override
136 public void unregister(final NetworkService service) {
137 retry(completionStage(Action.unregister, service),
138 service, Action.unregister, maxRetries, new ExponentialBackOff(5000L, 1.5).start());
139 }
140 }