1 package net.avcompris.status.dao.impl;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4 import static com.google.common.base.Preconditions.checkState;
5 import static com.google.common.collect.Maps.newHashMap;
6 import static net.avcompris.commons3.databeans.DataBeans.instantiate;
7 import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric;
8
9 import java.io.IOException;
10 import java.sql.SQLException;
11 import java.util.Comparator;
12 import java.util.Map;
13
14 import javax.annotation.Nullable;
15
16 import org.apache.commons.lang3.NotImplementedException;
17 import org.springframework.beans.factory.annotation.Autowired;
18 import org.springframework.stereotype.Component;
19
20 import com.google.common.collect.Multimap;
21 import com.google.common.collect.TreeMultimap;
22
23 import net.avcompris.commons3.dao.impl.AbstractDao;
24 import net.avcompris.commons3.utils.Clock;
25 import net.avcompris.status.dao.CheckDto;
26 import net.avcompris.status.dao.EndpointDto;
27 import net.avcompris.status.dao.ServicesStatusHistoryDto;
28 import net.avcompris.status.dao.StatusDao;
29 import net.avcompris.status.query.CheckStatus;
30
31 @Component
32 public final class StatusDaoInMemory extends AbstractDao implements StatusDao {
33
34 private final Multimap<String, CheckDto> checksByEndpoints = TreeMultimap.create(
35 new Comparator<String>() {
36 @Override
37 public int compare(final String s1, final String s2) {
38 return s1.compareTo(s2);
39 }
40 },
41 new Comparator<CheckDto>() {
42 @Override
43 public int compare(final CheckDto/CheckDto.html#CheckDto">CheckDto c1, final CheckDto c2) {
44 return -c1.getStartedAt().compareTo(c2.getStartedAt());
45 }
46 });
47
48 private final Map<String, MutableCheckDto> checksByIds = newHashMap();
49
50 private final Multimap<String, String> errorMessages = TreeMultimap.create();
51
52 @Autowired
53 public StatusDaoInMemory(final Clock clock) {
54
55 super(clock);
56 }
57
58 @Override
59 public ServicesStatusHistoryDto getServicesCachedStatus(final EndpointDto... endpoints)
60 throws SQLException, IOException {
61
62 checkNotNull(endpoints, "endpoints");
63
64 final MutableServicesStatusHistoryDto servicesStatus = instantiate(MutableServicesStatusHistoryDto.class);
65
66 for (final EndpointDto e : endpoints) {
67
68 final String serviceId = e.getServiceId();
69 final String endpoint = e.getEndpoint();
70
71 final MutableServiceStatusHistoryDto serviceStatusHistory = instantiate(
72 MutableServiceStatusHistoryDto.class)
73 .setServiceId(serviceId)
74 .setEndpoint(endpoint)
75 .setStart(0)
76 .setTotal(checksByEndpoints.get(endpoint).size());
77
78 for (final CheckDto check : checksByEndpoints.get(endpoint)) {
79
80 serviceStatusHistory.addToChecks(check);
81 }
82
83 servicesStatus.addToItems(serviceStatusHistory);
84 }
85
86 return servicesStatus;
87 }
88
89 @Override
90 public String initCheck(
91 final String serviceId,
92 final String endpoint
93 ) throws SQLException, IOException {
94
95 checkNotNull(serviceId, "serviceId");
96 checkNotNull(endpoint, "endpoint");
97
98 final String checkId = "K-"
99 + System.currentTimeMillis() + "-"
100 + randomAlphanumeric(20);
101
102 final MutableCheckDto check = instantiate(MutableCheckDto.class)
103 .setId(checkId)
104 .setStartedAt(clock.now())
105 .setStatus(CheckStatus.RUNNING);
106
107 checksByEndpoints.put(endpoint, check);
108
109 checksByIds.compute(checkId, (key, oldValue) -> {
110 checkState(oldValue == null, "checkId: %s has already a value: %s", checkId, oldValue);
111 return check;
112 });
113
114 return checkId;
115 }
116
117 @Override
118 public void addCheckError(
119 final String serviceId,
120 final String endpoint,
121 @Nullable final String checkId,
122 final String errorMessage
123 ) throws SQLException, IOException {
124
125 checkNotNull(serviceId, "serviceId");
126 checkNotNull(endpoint, "endpoint");
127 checkNotNull(errorMessage, "errorMessage");
128
129 if (checkId == null) {
130 throw new NotImplementedException("checkId: " + checkId);
131 }
132
133 final MutableCheckDto check = checksByIds.get(checkId);
134
135 if (check.getEndedAt() == null) {
136 check.setEndedAt(clock.now());
137 }
138
139 check.setStatus(CheckStatus.ERROR);
140
141 if (check.getErrorMessage() == null) {
142 check.setErrorMessage(errorMessage);
143 }
144 }
145
146 @Override
147 public CheckDto getCheck(
148 final String checkId
149 ) throws SQLException, IOException {
150
151 checkNotNull(checkId, "checkId");
152
153 return checksByIds.get(checkId);
154 }
155
156 @Override
157 public void endCheck(
158 final String checkId,
159 final int elapsedMs,
160 final int statusCode
161 ) throws SQLException, IOException {
162
163 checkNotNull(checkId, "checkId");
164
165 final MutableCheckDto check = checksByIds.get(checkId);
166
167 synchronized (check) {
168
169 checkState(check.getEndedAt() == null, "check.endedAt for checkId: %s should be null, but was: %s", checkId,
170 check.getEndedAt());
171 checkState(check.getErrorMessage() == null,
172 "check.errorMessage for checkId: %s should be null, but was: %s", checkId, check.getErrorMessage());
173 checkState(check.getStatus() == CheckStatus.RUNNING,
174 "check.status for checkId: %s should be RUNNING, but was: %s", checkId, check.getStatus());
175
176 check.setEndedAt(clock.now());
177 check.setElapsedMs(elapsedMs);
178 check.setStatusCode(statusCode);
179 check.setStatus(CheckStatus.SUCCESS);
180 }
181 }
182 }