View Javadoc
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 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 }