package com.hubspot.baragon.data;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.curator.framework.CuratorFramework;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.hubspot.baragon.config.ZooKeeperConfiguration;
import com.hubspot.baragon.models.AgentRequestId;
import com.hubspot.baragon.models.AgentRequestType;
import com.hubspot.baragon.models.AgentResponse;
import com.hubspot.baragon.models.AgentResponseId;
@Singleton
public class BaragonAgentResponseDatastore extends AbstractDataStore {
public static final String PENDING_REQUEST_FORMAT = "/request/%s/pendingRequests/%s";
public static final String AGENT_REQUESTS_FORMAT = "/request/%s/agent";
public static final String AGENT_RESPONSES_FORMAT = AGENT_REQUESTS_FORMAT + "/%s-%s";
public static final String CREATE_AGENT_RESPONSE_FORMAT = AGENT_RESPONSES_FORMAT + "/%s-%s-";
public static final String AGENT_RESPONSE_FORMAT = AGENT_RESPONSES_FORMAT + "/%s";
@Inject
public BaragonAgentResponseDatastore(CuratorFramework curatorFramework, ObjectMapper objectMapper, ZooKeeperConfiguration zooKeeperConfiguration) {
super(curatorFramework, objectMapper, zooKeeperConfiguration);
}
@Timed
public AgentResponse addAgentResponse(String requestId, AgentRequestType requestType, String baseUrl, String url, Optional<Integer> statusCode, Optional<String> content, Optional<String> exception) {
final String path = createPersistentSequentialNode(String.format(CREATE_AGENT_RESPONSE_FORMAT, requestId, requestType, encodeUrl(baseUrl), statusCode.or(0), exception.isPresent()));
final int attempt = Integer.parseInt(path.substring(path.length() - 10));
final AgentResponse agentResponse = new AgentResponse(url, attempt, statusCode, content, exception);
writeToZk(path, agentResponse);
return agentResponse;
}
@Timed
public Collection<AgentRequestId> getAgentRequestIds(String requestId) {
final Collection<String> nodes = getChildren(String.format(AGENT_REQUESTS_FORMAT, requestId));
final Collection<AgentRequestId> agentRequestIds = Lists.newArrayListWithCapacity(nodes.size());
for (String node : nodes) {
agentRequestIds.add(AgentRequestId.fromString(node));
}
return agentRequestIds;
}
@Timed
public List<String> getAgentResponseIds(String requestId, AgentRequestType requestType, String baseUrl) {
return getChildren(String.format(AGENT_RESPONSES_FORMAT, requestId, requestType, encodeUrl(baseUrl)));
}
@Timed
public void setPendingRequestStatus(String requestId, String baseUrl, boolean value) {
if (value) {
writeToZk(String.format(PENDING_REQUEST_FORMAT, requestId, encodeUrl(baseUrl)), System.currentTimeMillis());
} else {
deleteNode(String.format(PENDING_REQUEST_FORMAT, requestId, encodeUrl(baseUrl)));
}
}
@Timed
public Optional<Long> getPendingRequest(String requestId, String baseUrl) {
return readFromZk(String.format(PENDING_REQUEST_FORMAT, requestId, encodeUrl(baseUrl)), Long.class);
}
@Timed
public Optional<AgentResponseId> getLastAgentResponseId(String requestId, AgentRequestType requestType, String baseUrl) {
final List<String> agentResponseIds = getAgentResponseIds(requestId, requestType, baseUrl);
if (agentResponseIds.isEmpty()) {
return Optional.absent();
}
Collections.sort(agentResponseIds, SEQUENCE_NODE_COMPARATOR_HIGH_TO_LOW);
return Optional.of(AgentResponseId.fromString(agentResponseIds.get(0)));
}
@Timed
public Map<String, Collection<AgentResponse>> getLastResponses(String requestId) {
final Map<String, Collection<AgentResponse>> responses = Maps.newHashMap();
for (AgentRequestId agentRequestId : getAgentRequestIds(requestId)) {
final Optional<AgentResponseId> maybeAgentResponseId = getLastAgentResponseId(requestId, agentRequestId.getType(), agentRequestId.getBaseUrl());
if (maybeAgentResponseId.isPresent()) {
final Optional<AgentResponse> maybeAgentResponse = getAgentResponse(requestId, agentRequestId, maybeAgentResponseId.get());
if (maybeAgentResponse.isPresent()) {
if (!responses.containsKey(agentRequestId.getType().name())) {
responses.put(agentRequestId.getType().name(), Lists.<AgentResponse>newArrayList());
}
responses.get(agentRequestId.getType().name()).add(maybeAgentResponse.get());
}
}
}
return responses;
}
@Timed
public Optional<AgentResponse> getAgentResponse(String requestId, AgentRequestType requestType, AgentResponseId agentResponseId, String baseUrl) {
return readFromZk(String.format(AGENT_RESPONSE_FORMAT, requestId, requestType, encodeUrl(baseUrl), agentResponseId.getId()), AgentResponse.class);
}
@Timed
public Optional<AgentResponse> getAgentResponse(String requestId, AgentRequestId agentRequestId, AgentResponseId agentResponseId) {
return readFromZk(String.format(AGENT_RESPONSE_FORMAT, requestId, agentRequestId.getType(), encodeUrl(agentRequestId.getBaseUrl()), agentResponseId.getId()), AgentResponse.class);
}
}