package com.wordpress.salaboy.context.tracking;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.neo4j.graphdb.GraphDatabaseService;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.wordpress.salaboy.context.tracking.json.QueryResult;
import com.wordpress.salaboy.context.tracking.json.ResponseNode;
/**
* Implementation of {@link ContextTrackingService} which used Rest API of
* Neo4j.
*
* @author calcacuervo
*/
public class ContextTrackingServiceRest implements ContextTrackingService {
public GraphDatabaseService getGraphDb() {
return null;
}
private static Log LOG = LogFactory.getLog(ContextTrackingServiceRest.class);
private HttpClient httpClient;
private String baseUri;
private static ContextTrackingServiceRest instance;
private String contentType = "application/json";
private String createNodeUrlPath = "/db/data/node";
private String createIndexUrlPath = "/db/data/index/node/";
private String associateNodeToIndexUrlPath = "/db/data/index/node/";
public static ContextTrackingServiceRest getInstance() {
if (instance == null) {
instance = new ContextTrackingServiceRest("http://0.0.0.0:7575");
}
return instance;
}
public ContextTrackingServiceRest(String baseUri) {
this.httpClient = new HttpClient();
this.baseUri = baseUri;
this.createIndexes();
}
@Override
public String newServiceChannelId() {
String channelId = "Channel-" + UUID.randomUUID().toString();
Map<String, String> params = new HashMap<String, String>();
params.put("channelId", channelId);
params.put("name", channelId);
this.createNewNode(params);
this.associateNodeToIndex(this.createNewNode(params), "channels",
params);
return channelId;
}
@Override
public String newProcedureId() {
String procedureId = "Procedure-" + UUID.randomUUID().toString();
Map<String, String> params = new HashMap<String, String>();
params.put("procedureId", procedureId);
params.put("name", procedureId);
this.associateNodeToIndex(this.createNewNode(params), "procedures",
params);
return procedureId;
}
@Override
public String newCallId() {
String callId = "Call-" + UUID.randomUUID().toString();
Map<String, String> params = new HashMap<String, String>();
params.put("callId", callId);
params.put("name", callId);
params.put("phoneNumber", "555-1234");
this.associateNodeToIndex(this.createNewNode(params), "calls", params);
return callId;
}
@Override
public String newVehicleId() {
String vehicleId = "Vehicle-" + UUID.randomUUID().toString();
Map<String, String> params = new HashMap<String, String>();
params.put("vehicleId", vehicleId);
params.put("name", vehicleId);
this.associateNodeToIndex(this.createNewNode(params), "vehicles",
params);
return vehicleId;
}
@Override
public String newEmergencyId() {
String emergencyId = "Emergency-" + UUID.randomUUID().toString();
Map<String, String> params = new HashMap<String, String>();
params.put("emergencyId", emergencyId);
params.put("name", emergencyId);
this.associateNodeToIndex(this.createNewNode(params), "emergencies",
params);
return emergencyId;
}
@Override
public String newEmergencyEntityBuildingId() {
String buildingId = "EntityBuilding-" + UUID.randomUUID().toString();
Map<String, String> params = new HashMap<String, String>();
params.put("buildingId", buildingId);
params.put("name", buildingId);
this.associateNodeToIndex(this.createNewNode(params), "buildings",
params);
return buildingId;
}
@Override
public String newPatientId() {
String patientId = "Patient-" + UUID.randomUUID().toString();
Map<String, String> params = new HashMap<String, String>();
params.put("patientId", patientId);
params.put("name", patientId);
this.associateNodeToIndex(this.createNewNode(params), "patients",
params);
return patientId;
}
private String createRelationship(String nodeFrom, String nodeTo,
String type) {
try {
String relationshipUrl = nodeFrom + "/relationships";
PostMethod method = new PostMethod(relationshipUrl);
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
String body = "{ \"to\": \"" + nodeTo + "\",\"type\":\"" + type
+ "\"}";
method.setRequestEntity(new StringRequestEntity(body,
this.contentType, "UTF-8"));
this.httpClient.executeMethod(method);
Gson gson = new Gson();
ResponseNode node = gson.fromJson(method.getResponseBodyAsString(),
ResponseNode.class);
return node.getSelf();
} catch (Exception e) {
throw new RuntimeException(
"There was an error creating relationship." + nodeFrom
+ " " + nodeTo, e);
}
}
@Override
public void attachEmergency(String callId, String emergencyId) {
try {
GetMethod method = new GetMethod(this.baseUri
+ this.createIndexUrlPath + "calls/callId/" + callId);
method.addRequestHeader("Accept", this.contentType);
this.httpClient.executeMethod(method);
Gson gson = new Gson();
Collection<ResponseNode> node = gson.fromJson(
method.getResponseBodyAsString(),
new TypeToken<Collection<ResponseNode>>() {
}.getType());
String callnode = node.iterator().next().getSelf();
method = new GetMethod(this.baseUri + this.createIndexUrlPath
+ "emergencies/emergencyId/" + emergencyId);
method.addRequestHeader("Accept", this.contentType);
this.httpClient.executeMethod(method);
gson = new Gson();
node = gson.fromJson(method.getResponseBodyAsString(),
new TypeToken<Collection<ResponseNode>>() {
}.getType());
String emergencyNode = node.iterator().next().getSelf();
this.createRelationship(callnode, emergencyNode,
EmergencyRelationshipType.CREATES.name());
} catch (Exception e) {
throw new RuntimeException(
"There was an error attaching the emergency to the call", e);
}
}
@Override
public void attachProcedure(String emergencyId, String procedureId) {
try {
GetMethod method = new GetMethod(this.baseUri
+ this.createIndexUrlPath + "emergencies/emergencyId/"
+ emergencyId);
method.addRequestHeader("Accept", this.contentType);
this.httpClient.executeMethod(method);
Gson gson = new Gson();
Collection<ResponseNode> node = gson.fromJson(
method.getResponseBodyAsString(),
new TypeToken<Collection<ResponseNode>>() {
}.getType());
String emergencynode = node.iterator().next().getSelf();
method = new GetMethod(this.baseUri + this.createIndexUrlPath
+ "procedures/procedureId/" + procedureId);
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
this.httpClient.executeMethod(method);
gson = new Gson();
node = gson.fromJson(method.getResponseBodyAsString(),
new TypeToken<Collection<ResponseNode>>() {
}.getType());
String callNode = node.iterator().next().getSelf();
this.createRelationship(emergencynode, callNode,
EmergencyRelationshipType.INSTANTIATE.name());
} catch (Exception e) {
throw new RuntimeException(
"There was an error attaching procedure", e);
}
}
@Override
public void attachProcedures(String parentProcedureId,
String childProcedureId) {
try {
GetMethod method = new GetMethod(this.baseUri
+ this.createIndexUrlPath + "procedures/procedureId/"
+ parentProcedureId);
method.addRequestHeader("Accept", this.contentType);
this.httpClient.executeMethod(method);
Gson gson = new Gson();
Collection<ResponseNode> node = gson.fromJson(
method.getResponseBodyAsString(),
new TypeToken<Collection<ResponseNode>>() {
}.getType());
String parentNode = node.iterator().next().getSelf();
method = new GetMethod(this.baseUri + this.createIndexUrlPath
+ "procedures/procedureId/" + childProcedureId);
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
this.httpClient.executeMethod(method);
gson = new Gson();
node = gson.fromJson(method.getResponseBodyAsString(),
new TypeToken<Collection<ResponseNode>>() {
}.getType());
String childNode = node.iterator().next().getSelf();
this.createRelationship(parentNode, childNode,
EmergencyRelationshipType.SUB.name());
} catch (Exception e) {
throw new RuntimeException(
"There was an error attaching procedure", e);
}
}
@Override
public void attachVehicle(String procedureId, String vehicleId) {
try {
GetMethod method = new GetMethod(this.baseUri
+ this.createIndexUrlPath + "procedures/procedureId/"
+ procedureId);
method.addRequestHeader("Accept", this.contentType);
this.httpClient.executeMethod(method);
Gson gson = new Gson();
Collection<ResponseNode> node = gson.fromJson(
method.getResponseBodyAsString(),
new TypeToken<Collection<ResponseNode>>() {
}.getType());
String procedureNode = node.iterator().next().getSelf();
method = new GetMethod(this.baseUri + this.createIndexUrlPath
+ "vehicles/vehicleId/" + vehicleId);
method.addRequestHeader("Accept", this.contentType);
this.httpClient.executeMethod(method);
gson = new Gson();
node = gson.fromJson(method.getResponseBodyAsString(),
new TypeToken<Collection<ResponseNode>>() {
}.getType());
String vehicleNode = node.iterator().next().getSelf();
this.createRelationship(procedureNode, vehicleNode,
EmergencyRelationshipType.USE.name());
} catch (Exception e) {
throw new RuntimeException(
"There was a problem attaching vehicle", e);
}
}
@Override
public void attachServiceChannel(String emergencyId, String channelId) {
try {
GetMethod method = new GetMethod(this.baseUri
+ this.createIndexUrlPath + "emergencies/emergencyId/"
+ emergencyId);
method.addRequestHeader("Accept", this.contentType);
this.httpClient.executeMethod(method);
Gson gson = new Gson();
Collection<ResponseNode> node = gson.fromJson(
method.getResponseBodyAsString(),
new TypeToken<Collection<ResponseNode>>() {
}.getType());
String emergencynode = node.iterator().next().getSelf();
method = new GetMethod(this.baseUri + this.createIndexUrlPath
+ "channels/channelId/" + channelId);
method.addRequestHeader("Accept", this.contentType);
this.httpClient.executeMethod(method);
gson = new Gson();
node = gson.fromJson(method.getResponseBodyAsString(),
new TypeToken<Collection<ResponseNode>>() {
}.getType());
String callNode = node.iterator().next().getSelf();
this.createRelationship(emergencynode, callNode,
EmergencyRelationshipType.CONSUME.name());
} catch (Exception e) {
throw new RuntimeException(
"There was an error attaching channel", e);
}
}
//*******************Util methods*********************
private void associateNodeToIndex(String nodeUrl, String indexName,
Map<String, String> props) {
for (String key : props.keySet()) {
PostMethod method = new PostMethod(this.baseUri
+ this.associateNodeToIndexUrlPath + indexName + "/" + key
+ "/" + props.get(key));
try {
method.setRequestEntity(new StringRequestEntity("\"" + nodeUrl
+ "\"", this.contentType, "UTF-8"));
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
this.httpClient.executeMethod(method);
if (method.getStatusCode() > 300) {
LOG.error("Error creating indexes..."
+ method.getResponseBodyAsString());
throw new RuntimeException(
"There was an error associating node to index."
+ nodeUrl + " " + indexName);
}
} catch (Exception e) {
throw new RuntimeException(
"There was an error associating node to index."
+ nodeUrl + " " + indexName, e);
}
}
}
private void createIndexes() {
try {
PostMethod method = new PostMethod(this.baseUri
+ this.createIndexUrlPath);
method.setRequestEntity(new StringRequestEntity("{\"name\": \""
+ "emergencies" + "\"}", this.contentType, "UTF-8"));
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
this.httpClient.executeMethod(method);
LOG.debug(method.getResponseBodyAsString());
method = new PostMethod(this.baseUri + this.createIndexUrlPath);
method.setRequestEntity(new StringRequestEntity("{\"name\": \""
+ "calls" + "\"}", this.contentType, "UTF-8"));
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
this.httpClient.executeMethod(method);
LOG.debug(method.getResponseBodyAsString());
method = new PostMethod(this.baseUri + this.createIndexUrlPath);
method.setRequestEntity(new StringRequestEntity("{\"name\": \""
+ "procedures" + "\"}", this.contentType, "UTF-8"));
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
this.httpClient.executeMethod(method);
LOG.debug(method.getResponseBodyAsString());
method = new PostMethod(this.baseUri + this.createIndexUrlPath);
method.setRequestEntity(new StringRequestEntity("{\"name\": \""
+ "emergencies" + "\"}", this.contentType, "UTF-8"));
method.setRequestEntity(new StringRequestEntity("{\"name\": \""
+ "vehicles" + "\"}", this.contentType, "UTF-8"));
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
this.httpClient.executeMethod(method);
LOG.debug(method.getResponseBodyAsString());
method = new PostMethod(this.baseUri + this.createIndexUrlPath);
method.setRequestEntity(new StringRequestEntity("{\"name\": \""
+ "channels" + "\"}", this.contentType, "UTF-8"));
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
this.httpClient.executeMethod(method);
method = new PostMethod(this.baseUri + this.createIndexUrlPath);
method.setRequestEntity(new StringRequestEntity("{\"name\": \""
+ "buildings" + "\"}", this.contentType, "UTF-8"));
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
this.httpClient.executeMethod(method);
LOG.debug(method.getResponseBodyAsString());
method = new PostMethod(this.baseUri + this.createIndexUrlPath);
method.setRequestEntity(new StringRequestEntity("{\"name\": \""
+ "patients" + "\"}", this.contentType, "UTF-8"));
method.addRequestHeader("Accept", this.contentType);
method.addRequestHeader("Content-Type", this.contentType);
this.httpClient.executeMethod(method);
} catch (Exception e) {
throw new RuntimeException("There was an error creating indexes", e);
}
}
private String createNewNode(Map<String, String> properties) {
PostMethod method = new PostMethod(this.baseUri
+ this.createNodeUrlPath);
for (String key : properties.keySet()) {
method.addParameter(key, properties.get(key));
}
try {
method.addRequestHeader("Accept", this.contentType);
this.httpClient.executeMethod(method);
return method.getResponseHeader("Location").getValue();
} catch (Exception e) {
throw new RuntimeException("There was an error creating indexes", e);
}
}
@Override
public String getProcedureAttachedToVehicle(String vehicleId) {
try {
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(this.baseUri + "/db/data/ext/CypherPlugin/graphdb/execute_query");
method.setRequestHeader("Content-type", "application/json");
method.setRequestHeader("Accept", "application/json");
String content = "{\"query\": \"start v=(vehicles, 'vehicleId:" + vehicleId + "') match (v) <-[USE]- (w) return w\"}";
method.setRequestEntity(new StringRequestEntity(content, "application/json", "UTF-8"));
client.executeMethod(method);
Gson gson = new Gson();
QueryResult result = gson.fromJson(method.getResponseBodyAsString(),
new TypeToken<QueryResult>() {
}.getType());
//TODO CHECK THIS WITH A TEST!
return result.getData().get(0).get(0).getData().get("procedureId");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void clear() {
}
public void detachVehicle(String vehicleId) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void detachProcedure(String procedureId) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void detachEmergency(String emergencyId) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void detachEmergencyEntityBuilding(String entityBuildingId) {
// TODO Auto-generated method stub
}
@Override
public void detachPatient(String patientId) {
// TODO Auto-generated method stub
}
@Override
public void detachServiceChannel(String serviceChannelId) {
// TODO Auto-generated method stub
}
@Override
public String getCallAttachedToEmergency(String emergencyId) {
try {
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(this.baseUri + "/db/data/ext/CypherPlugin/graphdb/execute_query");
method.setRequestHeader("Content-type", "application/json");
method.setRequestHeader("Accept", "application/json");
String content = "{\"query\": \"start e=(emergencies, 'emergencyId:" + emergencyId + "') match (c) -[CREATES]-> (e) return c\"}";
method.setRequestEntity(new StringRequestEntity(content, "application/json", "UTF-8"));
client.executeMethod(method);
Gson gson = new Gson();
QueryResult result = gson.fromJson(method.getResponseBodyAsString(),
new TypeToken<QueryResult>() {
}.getType());
//TODO CHECK THIS WITH A TEST!
if (result.getData().isEmpty()){
//No results
return null;
}
return result.getData().get(0).get(0).getData().get("callId");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String getEmergencyAttachedToCall(String callId) {
try {
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(this.baseUri + "/db/data/ext/CypherPlugin/graphdb/execute_query");
method.setRequestHeader("Content-type", "application/json");
method.setRequestHeader("Accept", "application/json");
String content = "{\"query\": \"start c=(calls, 'callId:" + callId + "') match (c) -[CREATES]-> (e) return e\"}";
method.setRequestEntity(new StringRequestEntity(content, "application/json", "UTF-8"));
client.executeMethod(method);
Gson gson = new Gson();
QueryResult result = gson.fromJson(method.getResponseBodyAsString(),
new TypeToken<QueryResult>() {
}.getType());
//TODO CHECK THIS WITH A TEST!
if (result.getData().isEmpty()){
//No results
return null;
}
return result.getData().get(0).get(0).getData().get("emergencyId");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}