Skip to content

Commit

Permalink
Refactored code. Extracted common logic into utility files. Built Ins…
Browse files Browse the repository at this point in the history
…ertQueryBuilder. Fixed deletion bug as well as some minor bugs.
  • Loading branch information
ivanmrsulja committed Oct 2, 2024
1 parent e631cde commit a1738f9
Show file tree
Hide file tree
Showing 8 changed files with 576 additions and 466 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package edu.cornell.mannlib.vitro.webapp.controller.software;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Objects;
import java.util.UUID;
import java.util.function.BiConsumer;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset;
import edu.cornell.mannlib.vitro.webapp.modules.searchIndexer.SearchIndexer;
import org.apache.jena.query.Dataset;
import org.apache.jena.query.ReadWrite;
import org.apache.jena.update.GraphStore;
import org.apache.jena.update.GraphStoreFactory;

public class IndividualApiCommonCRUDUtility {

public static void executeWithTransaction(HttpServletRequest req, HttpServletResponse resp,
BiConsumer<GraphStore, String> action) throws IOException {
VitroRequest vreq = new VitroRequest(req);
SearchIndexer indexer = ApplicationUtils.instance().getSearchIndexer();
Dataset ds = new RDFServiceDataset(vreq.getUnfilteredRDFService());
GraphStore graphStore = GraphStoreFactory.create(ds);

String entityUri;
if (req.getMethod().equalsIgnoreCase("POST")) {
entityUri = IndividualApiSparqlUtility.buildIndividualUri(UUID.randomUUID().toString());
} else {
String pathInfo = req.getPathInfo();
if (Objects.isNull(pathInfo) || pathInfo.isEmpty()) {
IndividualApiNetworkUtility.do400BadRequest("You have to provide a record identifier.", resp);
return;
}

entityUri = IndividualApiSparqlUtility.buildIndividualUri(pathInfo.substring(1));
}

try {
pauseIndexer(indexer);
beginTransaction(ds);

action.accept(graphStore, entityUri);

} finally {
commitTransaction(ds);
unpauseIndexer(indexer);
}
}

private static void pauseIndexer(SearchIndexer indexer) {
if (indexer != null) {
indexer.pause();
}
}

private static void unpauseIndexer(SearchIndexer indexer) {
if (indexer != null) {
indexer.unpause();
}
}

private static void beginTransaction(Dataset ds) {
if (ds.supportsTransactions()) {
ds.begin(ReadWrite.WRITE);
}
}

private static void commitTransaction(Dataset ds) {
if (ds.supportsTransactions()) {
ds.commit();
ds.end();
}
}

public static void performDeleteOperation(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String pathInfo = req.getPathInfo();
if (Objects.isNull(pathInfo) || pathInfo.isEmpty()) {
IndividualApiNetworkUtility.do400BadRequest("You have to provide a record identifier.", resp);
return;
}

VitroRequest vreq = new VitroRequest(req);
ApplicationBean appBean = vreq.getAppBean();
String appName = appBean.getApplicationName().toLowerCase();
URL url = new URL("http://" + req.getServerName() + ":" + req.getServerPort() + "/" + appName +
"/deleteIndividualController?individualUri=" +
URLEncoder.encode(IndividualApiSparqlUtility.buildIndividualUri(pathInfo.substring(1))) +
"&redirectUrl=%2F");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/json");

addCookiesToRequest(req, connection);

connection.getResponseCode();

resp.setStatus(HttpServletResponse.SC_NO_CONTENT);

connection.disconnect();
}

private static void addCookiesToRequest(HttpServletRequest req, HttpURLConnection connection) {
Cookie[] cookies = req.getCookies();
if (cookies != null) {
StringBuilder cookieHeader = new StringBuilder();
for (Cookie cookie : cookies) {
cookieHeader.append(cookie.getName()).append("=").append(cookie.getValue()).append("; ");
}
// Remove the trailing "; " at the end of the cookie string
if (cookieHeader.length() > 0) {
cookieHeader.setLength(cookieHeader.length() - 2);
}
connection.setRequestProperty("Cookie", cookieHeader.toString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package edu.cornell.mannlib.vitro.webapp.controller.software;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.InvalidQueryTypeException;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
import org.apache.jena.query.QueryParseException;

public class IndividualApiNetworkUtility {

public static void handleResponseContentType(HttpServletRequest req, HttpServletResponse resp) {
String acceptHeader = req.getHeader("Accept");
if (acceptHeader != null && !acceptHeader.isEmpty()) {
resp.setContentType(acceptHeader);
} else {
resp.setContentType("application/json");
}
}

public static String serializeToJSON(Object serializationObject) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
return objectMapper.writeValueAsString(serializationObject);
}

public static boolean isJsonRequest(HttpServletRequest req) {
String acceptHeader = req.getHeader("Accept");
return acceptHeader != null && acceptHeader.equals("application/json");
}

public static <T> T parseRequestBody(HttpServletRequest req, Class<T> clazz) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(req.getInputStream(), clazz);
}

public static void handleException(Exception e, String queryString, HttpServletResponse resp) throws IOException {
if (e instanceof InvalidQueryTypeException) {
do400BadRequest("Invalid query type: '" + queryString + "'", resp);
} else if (e instanceof QueryParseException) {
do400BadRequest("Failed to parse query: '" + queryString + "'", resp);
} else if (e instanceof RDFServiceException) {
do500InternalServerError("Problem executing the query.", e, resp);
}
}

public static void do400BadRequest(String message, HttpServletResponse resp)
throws IOException {
resp.setStatus(400);
resp.getWriter().println(message);
}

public static void do404NotFound(String message, HttpServletResponse resp)
throws IOException {
resp.setStatus(404);
resp.getWriter().println(message);
}

public static void do500InternalServerError(String message, Exception e,
HttpServletResponse resp) throws IOException {
resp.setStatus(500);
PrintWriter w = resp.getWriter();
w.println(message);
e.printStackTrace(w);

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

Error information
can be exposed to an external user.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package edu.cornell.mannlib.vitro.webapp.controller.software;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.controller.api.sparqlquery.SparqlQueryApiExecutor;
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.jena.update.GraphStore;
import org.apache.jena.update.UpdateAction;
import org.apache.jena.update.UpdateFactory;
import org.apache.jena.update.UpdateRequest;

public class IndividualApiSparqlUtility {

public static String getSparqlQueryResponse(SparqlQueryApiExecutor core) throws IOException, RDFServiceException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
core.executeAndFormat(outputStream);

String sparqlResponse = outputStream.toString("UTF-8");

outputStream.close();

return sparqlResponse;
}

public static List<Map<String, String>> parseBindings(String jsonResponse) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(jsonResponse);

JsonNode bindingsNode = rootNode.path("results").path("bindings");

List<Map<String, String>> recordsList = new ArrayList<>();

for (JsonNode bindingNode : bindingsNode) {
Map<String, String> recordMap = new HashMap<>();

Iterator<Map.Entry<String, JsonNode>> fieldsIterator = bindingNode.fields();
while (fieldsIterator.hasNext()) {
Map.Entry<String, JsonNode> field = fieldsIterator.next();

String fieldName = field.getKey();
String fieldValue = field.getValue().path("value").asText();

recordMap.put(fieldName, fieldValue);
}

recordsList.add(recordMap);
}

return recordsList;
}

public static void addPrefixClauses(StringBuilder queryBuilder) {
queryBuilder
.append("PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n")
.append("PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n")
.append("PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>\n")
.append("PREFIX owl: <http://www.w3.org/2002/07/owl#>\n")
.append("PREFIX swrl: <http://www.w3.org/2003/11/swrl#>\n")
.append("PREFIX swrlb: <http://www.w3.org/2003/11/swrlb#>\n")
.append("PREFIX vitro: <http://vitro.mannlib.cornell.edu/ns/vitro/0.7#>\n")
.append("PREFIX bibo: <http://purl.org/ontology/bibo/>\n")
.append("PREFIX c4o: <http://purl.org/spar/c4o/>\n")
.append("PREFIX cito: <http://purl.org/spar/cito/>\n")
.append("PREFIX dcterms: <http://purl.org/dc/terms/>\n")
.append("PREFIX event: <http://purl.org/NET/c4dm/event.owl#>\n")
.append("PREFIX fabio: <http://purl.org/spar/fabio/>\n")
.append("PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n")
.append("PREFIX geo: <http://aims.fao.org/aos/geopolitical.owl#>\n")
.append("PREFIX obo: <http://purl.obolibrary.org/obo/>\n")
.append("PREFIX vivo: <http://vivoweb.org/ontology/core#>\n")
.append("PREFIX vcard: <http://www.w3.org/2006/vcard/ns#>\n");
}

public static void executeUpdate(GraphStore graphStore, String query) {
UpdateRequest updateRequest = UpdateFactory.create(query);
UpdateAction.execute(updateRequest, graphStore);
}

public static String buildIndividualUri(String entityId) {
String defaultNamespace =
Objects.requireNonNull(ConfigurationProperties.getInstance().getProperty("Vitro.defaultNamespace"));
return defaultNamespace + StringEscapeUtils.escapeJava(entityId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package edu.cornell.mannlib.vitro.webapp.controller.software;

import java.util.ArrayList;
import java.util.List;

public class InformationContentEntityResponseDTO {

public String internalIdentifier;

public String name;

public String datePublished;

public List<AuthorDTO> authors = new ArrayList<>();

public List<String> fundings = new ArrayList<>();

public List<FunderResponseDTO> funders = new ArrayList<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package edu.cornell.mannlib.vitro.webapp.controller.software;

import java.util.Map;
import java.util.Objects;

public class InformationContentEntityResponseUtility {

public static void addAuthorToICE(Map<String, String> binding, InformationContentEntityResponseDTO entity) {
if (!Objects.nonNull(binding.get("author"))) {
return;
}

if (entity.authors.stream().anyMatch(author -> author.name.equals(binding.get("author")))) {
return;
}

AuthorDTO author = new AuthorDTO();
author.name = binding.getOrDefault("author", null);
author.type = binding.getOrDefault("authorType", null);
author.identifier = binding.getOrDefault("authorIdentifier", null);
entity.authors.add(author);
}

public static void addFundingToICE(Map<String, String> binding, InformationContentEntityResponseDTO entity) {
if (!Objects.nonNull(binding.get("funding"))) {
return;
}

if (entity.fundings.stream().anyMatch(funding -> funding.equals(binding.get("funding")))) {
return;
}

entity.fundings.add(binding.get("funding"));
}

public static void addFundersToICE(Map<String, String> binding, InformationContentEntityResponseDTO entity) {
if (!Objects.nonNull(binding.get("funder"))) {
return;
}

if (entity.funders.stream().anyMatch(funder -> funder.name.equals(binding.get("funder")))) {
return;
}

FunderResponseDTO funder = new FunderResponseDTO();
funder.name = binding.get("funder");
funder.type = binding.getOrDefault("funderType", null);
entity.funders.add(funder);
}
}
Loading

0 comments on commit a1738f9

Please sign in to comment.