package org.deri.grefine.reconcile.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
import org.deri.grefine.reconcile.model.ReconciliationCandidate;
import org.deri.grefine.reconcile.model.ReconciliationRequest;
import org.deri.grefine.reconcile.model.ReconciliationResponse;
import org.deri.grefine.reconcile.model.ReconciliationService;
import org.deri.grefine.reconcile.model.SearchResultItem;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
public class GRefineJsonUtilitiesImpl implements GRefineJsonUtilities{
@Override
public String getServiceMetadataAsJsonP(ReconciliationService service, String callback, String baseServiceUrl){
ObjectMapper mapper = new ObjectMapper();
ObjectNode obj = mapper.createObjectNode();
obj.put("name", service.getName());
obj.put("schemaSpace", URI_SPACE);
obj.put("identifierSpace", URI_SPACE);
//view object
ObjectNode viewObj = mapper.createObjectNode();
viewObj.put("url", baseServiceUrl + "/view?id={{id}}");
obj.put("view", viewObj);
//preview object
ObjectNode previewObj = mapper.createObjectNode();
previewObj.put("url", baseServiceUrl + "/preview/template?id={{id}}");
previewObj.put("width",430);
previewObj.put("height",300);
obj.put("preview", previewObj);
//suggest
//Global suggest object
ObjectNode suggestObj = mapper.createObjectNode();
//type suggest (autocomplete)
ObjectNode typeSuggestObj = mapper.createObjectNode();
typeSuggestObj.put("service_url", baseServiceUrl);
typeSuggestObj.put("service_path", "/suggest/type");
typeSuggestObj.put("flyout_service_url", baseServiceUrl);
typeSuggestObj.put("flyout_service_path" , "/suggest/type/preview");
suggestObj.put("type", typeSuggestObj);
//property suggest (autocomplete)
ObjectNode propertySuggestObj = mapper.createObjectNode();
propertySuggestObj.put("service_url", baseServiceUrl);
propertySuggestObj.put("service_path", "/suggest/property");
propertySuggestObj.put("flyout_service_url", baseServiceUrl);
propertySuggestObj.put("flyout_service_path" , "/suggest/property/preview");
suggestObj.put("property", propertySuggestObj);
//entity search
ObjectNode entitySearchObj = mapper.createObjectNode();
entitySearchObj.put("service_url", baseServiceUrl);
entitySearchObj.put("service_path", "/suggest/entity");
entitySearchObj.put("flyout_service_url", baseServiceUrl);
entitySearchObj.put("flyout_service_path" , "/suggest/entity/preview");
suggestObj.put("entity", entitySearchObj);
obj.put("suggest", suggestObj);
return getJsonP(callback, obj);
}
@Override
public ImmutableMap<String, ReconciliationRequest> getMultipleRequest(String queries)
throws JsonParseException, JsonMappingException, IOException{
Map<String, ReconciliationRequest> multiRequest = new HashMap<String, ReconciliationRequest>();
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readValue(queries, JsonNode.class);
Iterator<String> keysIter = root.getFieldNames();
while(keysIter.hasNext()){
String key = keysIter.next();
//FIXME parsed twice
ReconciliationRequest request = ReconciliationRequest.valueOf(root.path(key).toString());
multiRequest.put(key, request);
}
return ImmutableMap.copyOf(multiRequest);
}
@Override
public ObjectNode getMultipleResponse(ImmutableMap<String,ReconciliationResponse> multiResponse, PrefixManager prefixManager) {
ObjectMapper mapper = new ObjectMapper();
ObjectNode multiResponseObj = mapper.createObjectNode();
for(Entry<String, ReconciliationResponse> entry: multiResponse.entrySet()){
String key = entry.getKey();
ReconciliationResponse response = entry.getValue();
multiResponseObj.put(key, getResponse(response,prefixManager));
}
return multiResponseObj;
}
@Override
public ObjectNode jsonizeSearchResult(ImmutableList<SearchResultItem> results, String prefix) throws JsonGenerationException, JsonMappingException, IOException{
ObjectMapper mapper = new ObjectMapper();
ObjectNode resultObj = mapper.createObjectNode();
resultObj.put("code", "/api/status/ok");
resultObj.put("status", "200 OK");
resultObj.put("prefix", prefix);
ArrayNode resultArr = mapper.createArrayNode();
for(SearchResultItem item: results){
ObjectNode resultItemObj = mapper.createObjectNode();
resultItemObj.put("id", item.getId());
resultItemObj.put("name", item.getName());
//FIXME id is used instead of type to enable the suggest autocomplete to function as it doesn't work when no type is given
ObjectNode tmpObj = mapper.createObjectNode();
tmpObj.put("id", item.getId());
tmpObj.put("name", item.getId());
resultItemObj.put("type", tmpObj);
resultArr.add(resultItemObj);
}
resultObj.put("result", resultArr);
return resultObj;
}
@Override
public ObjectNode jsonizeHtml(String html, String id){
ObjectMapper mapper = new ObjectMapper();
ObjectNode resultObj = mapper.createObjectNode();
resultObj.put("html",html);
resultObj.put("id", id);
return resultObj;
}
@Override
public String getJsonP(String callback, ObjectNode obj){
return callback + "(" + obj + ");";
}
@Override
public JSONObject getJSONObjectFromUrl(URL url) throws JSONException, IOException{
URLConnection connection = url.openConnection();
connection.setRequestProperty("Accept", "application/json");
connection.setConnectTimeout(30000);
connection.setDoOutput(true);
connection.connect();
InputStream is = connection.getInputStream();
Reader reader = new InputStreamReader(is, "UTF-8");
String s;
try {
StringBuffer sb = new StringBuffer();
char[] chars = new char[8192];
int c;
while ((c = reader.read(chars)) > 0) {
sb.insert(sb.length(), chars, 0, c);
}
s = sb.toString();
} finally {
reader.close();
}
JSONTokener t = new JSONTokener(s);
Object o = t.nextValue();
if (o instanceof JSONObject) {
return (JSONObject) o;
} else {
throw new JSONException(s + " couldn't be parsed as JSON object");
}
}
private ObjectNode getResponse(ReconciliationResponse response, PrefixManager prefixManager) {
ObjectMapper mapper = new ObjectMapper();
ObjectNode responseObj = mapper.createObjectNode();
ArrayNode resultArr = mapper.createArrayNode();
for(ReconciliationCandidate result:response.getResults()){
ObjectNode resultItemObj = getResultItem(result,prefixManager);
resultArr.add(resultItemObj);
}
responseObj.put("result", resultArr);
return responseObj;
}
private ObjectNode getResultItem(ReconciliationCandidate item, PrefixManager prefixManager){
ObjectMapper mapper = new ObjectMapper();
ObjectNode resultItemObj = mapper.createObjectNode();
resultItemObj.put("id", item.getId());
resultItemObj.put("name", item.getName());
resultItemObj.put("score", item.getScore());
resultItemObj.put("match", item.isMatch());
ArrayNode typesArr = mapper.createArrayNode();
for(int i=0;i<item.getTypes().length;i++){
String id = item.getTypes()[i];
int index = getNamespaceEndPosition(id);
String prefix = prefixManager.getPrefix(id.substring(0,index));
ObjectNode typeObj = mapper.createObjectNode();
typeObj.put("id", id);
if(prefix!=null){
String localName = id.substring(index);
typeObj.put("name", prefix +":" + localName);
}else{
typeObj.put("name", id);
}
typesArr.add(typeObj);
}
resultItemObj.put("type", typesArr);
return resultItemObj;
}
private int getNamespaceEndPosition(String uri){
if(uri.indexOf("#")!=-1){
return uri.indexOf("#")+1;
}else{
return uri.lastIndexOf("/") + 1;
}
}
private static final String URI_SPACE = "http://www.ietf.org/rfc/rfc3986";
}