From 709775579acfbdb05d5526d245abe53077256c4b Mon Sep 17 00:00:00 2001 From: erinz2020 Date: Tue, 7 May 2024 22:07:36 +0000 Subject: [PATCH 1/7] display relationship chart and update relationship table --- .../bubbleDiagram/encounter-calls.js | 85 ++++++++++--------- .../relationshipDiagrams/jsonParser.js | 47 +++++++--- .../relationshipDiagrams/socialGraph.js | 2 +- 3 files changed, 82 insertions(+), 52 deletions(-) diff --git a/src/main/webapp/javascript/bubbleDiagram/encounter-calls.js b/src/main/webapp/javascript/bubbleDiagram/encounter-calls.js index 43ebe9086c..0358869fea 100644 --- a/src/main/webapp/javascript/bubbleDiagram/encounter-calls.js +++ b/src/main/webapp/javascript/bubbleDiagram/encounter-calls.js @@ -426,7 +426,7 @@ var makeRelTable = function(items, tableHeadLocation, tableBodyLocation, sortOn) return "

Are you sure you want to delete this relationship?

"; } if(d.length > 2) { - return "" + d[5] + "
" + dict['nickname'] + " : " + d[1]+ "
" + dict['alternateID'] + ": " + d[2] + "
" + dict['sex'] + ": " + d[3] + "
" + dict['haplotype'] +": " + d[4] + ""; + return "" + d[5] + "
" + dict['nickname'] + " : " + (d[1] ?? "")+ "
" + dict['alternateID'] + ": " + (d[2] ?? "") + "
" + dict['sex'] + ": " + (d[3] ?? "") + "
" + dict['haplotype'] +": " + (d[4] ?? "") + ""; } return d[0].italics() + "-" + d[1]; //} @@ -687,48 +687,53 @@ var getRelationshipTableData = function(individualID) { relationship = {"roles": [markedIndividualRole, relationshipWithRole], "relationshipWith": [whaleID], "type": type, "socialUnit": relatedSocialUnitName, "edit": ["edit", relationshipID], "remove": ["remove", relationshipID]}; relationshipArray.push(relationship); } - getIndividualData(relationshipArray); - console.log("gonna makeRelTable"); - makeRelTable(relationshipArray, "#relationshipHead", "#relationshipBody", "text"); + getIndividualData(relationshipArray, function (relationshipTableData) { + console.log("All data has been processed:", JSON.stringify(relationshipTableData)); + makeRelTable(relationshipTableData, "#relationshipHead", "#relationshipBody", "text"); + }); + }); } -var getIndividualData = function(relationshipArray) { - console.log("getIndividualData"); - var relationshipTableData = []; - for(var i=0; i < relationshipArray.length; i++) { - d3.json(wildbookGlobals.baseUrl + "/api/org.ecocean.MarkedIndividual/" + relationshipArray[i].relationshipWith[0], function(error, json) { - if(error) { - console.log("error") - } - //console.log("json: "+JSON.stringify(json)); - let jsonData = json; - var individualInfo = relationshipArray.filter(function(obj) { - return obj.relationshipWith[0] === jsonData.individualID; - })[0]; - console.log(individualInfo.relationshipWith); - individualInfo.relationshipWith[1] = jsonData.nickName; - individualInfo.relationshipWith[2] = jsonData.alternateid; - individualInfo.relationshipWith[3] = jsonData.sex; - individualInfo.relationshipWith[4] = jsonData.localHaplotypeReflection; - individualInfo.relationshipWith[5] = jsonData.displayName; - relationshipTableData.push(individualInfo); - - if(relationshipTableData.length == relationshipArray.length) { - for(var j = 0; j < relationshipArray.length; j++) { - if(relationshipArray[j].relationshipWith.length == 1) { - relationshipArray[j].relationshipWith[1] = jsonData.nickName; - relationshipArray[j].relationshipWith[2] = jsonData.alternateid; - relationshipArray[j].relationshipWith[3] = jsonData.sex; - relationshipArray[j].relationshipWith[4] = jsonData.localHaplotypeReflection; - relationshipArray[j].relationshipWith[5] = jsonData.displayName; - } - } - - } - }); - } +var getIndividualData = function (relationshipArray, onComplete) { + var relationshipTableData = []; + var completedRequests = 0; + + for (var i = 0; i < relationshipArray.length; i++) { + d3.json(wildbookGlobals.baseUrl + "/api/org.ecocean.MarkedIndividual/" + relationshipArray[i].relationshipWith[0], function (error, json) { + if (error) { + console.log("Error loading data"); + return; + } + let jsonData = json; + var individualInfo = relationshipArray.filter(function (obj) { + return obj.relationshipWith[0] === jsonData.individualID; + })[0]; + + individualInfo.relationshipWith[1] = jsonData.nickName; + individualInfo.relationshipWith[2] = jsonData.alternateid; + individualInfo.relationshipWith[3] = jsonData.sex; + individualInfo.relationshipWith[4] = jsonData.localHaplotypeReflection; + individualInfo.relationshipWith[5] = jsonData.displayName; + + relationshipTableData.push(individualInfo); + completedRequests++; + + if (completedRequests === relationshipArray.length) { + for (var j = 0; j < relationshipArray.length; j++) { + if (relationshipArray[j].relationshipWith.length == 1) { + relationshipArray[j].relationshipWith[1] = jsonData.nickName; + relationshipArray[j].relationshipWith[2] = jsonData.alternateid; + relationshipArray[j].relationshipWith[3] = jsonData.sex; + relationshipArray[j].relationshipWith[4] = jsonData.localHaplotypeReflection; + relationshipArray[j].relationshipWith[5] = jsonData.displayName; + } + } + onComplete(relationshipTableData); + } + }); + } } function whatIsIt(object) { @@ -753,4 +758,4 @@ function whatIsIt(object) { { return "don't know"; } -} +} \ No newline at end of file diff --git a/src/main/webapp/javascript/relationshipDiagrams/jsonParser.js b/src/main/webapp/javascript/relationshipDiagrams/jsonParser.js index dc887242be..14cdaa2e78 100644 --- a/src/main/webapp/javascript/relationshipDiagrams/jsonParser.js +++ b/src/main/webapp/javascript/relationshipDiagrams/jsonParser.js @@ -97,6 +97,7 @@ class JSONQuerier { */ async preFetchData(iId, genus, epithet, callbacks, diagramIds, parsers=[]) { await this.queryIndividualIDNodeData(iId); + await this.queryIndividualIDRelatedNodeData(iId); await this.queryIndividualIDRelationshipData(iId); await this.queryIndividualIDOccurrences(iId); @@ -139,6 +140,16 @@ class JSONQuerier { return this.queryData("nodeData", query, this.storeQueryAsDict); } + queryIndividualIDRelatedNodeData(individualID) { + let query; + if (!this.localFiles) { + query = wildbookGlobals.baseUrl + "/encounters/relatedIndividuals.jsp?"; + if (individualID) query += "individualID=" + individualID; + } + else query = "./MarkedIndividual.json"; + return this.queryData("relatedNodeData", query, this.storeQueryAsDict); + } + /** * Query wrapper for the storage of Relationship data @@ -316,7 +327,7 @@ class JSONParser { */ processNodeData(iId, isCoOccurrence) { //Generate a two way mapping of all node relationships - let nodes = this.getNodeSelection(); + let nodes = this.getNodeSelection(isCoOccurrence); let relationships = this.mapRelationships(nodes); let [graphNodes, groupNum] = this.traverseRelationshipTree(iId, nodes, relationships, isCoOccurrence); @@ -613,17 +624,31 @@ class JSONParser { * Return node data as filtered by selected nodes * @return {nodeData} [array] - Any node data matching {selectedNodes} ids */ - getNodeSelection() { - if (this.selectedNodes) { - let nodes = {}; - Object.entries(JSONParser.nodeData).forEach(([key, data]) => { - if (this.selectedNodes.has(key)) { //Filter out any keys not in {selectedNodes} - nodes[key] = data; + getNodeSelection(isCoOccurrence) { + if (isCoOccurrence) { + if (this.selectedNodes) { + let nodes = {}; + Object.entries(JSONParser.nodeData).forEach(([key, data]) => { + if (this.selectedNodes.has(key)) { //Filter out any keys not in {selectedNodes} + nodes[key] = data; + } + }); + return nodes; + } + return JSONParser.nodeData; + }else { + if (this.selectedNodes) { + let nodes = {}; + Object.entries(JSONParser.relatedNodeData).forEach(([key, data]) => { + if (this.selectedNodes.has(key)) { //Filter out any keys not in {selectedNodes} + nodes[key] = data; + } + }); + return nodes; + } + return JSONParser.relatedNodeData; } - }); - return nodes; - } - return JSONParser.nodeData; + } /** diff --git a/src/main/webapp/javascript/relationshipDiagrams/socialGraph.js b/src/main/webapp/javascript/relationshipDiagrams/socialGraph.js index 5e664f5ae1..394061e8b0 100644 --- a/src/main/webapp/javascript/relationshipDiagrams/socialGraph.js +++ b/src/main/webapp/javascript/relationshipDiagrams/socialGraph.js @@ -28,7 +28,7 @@ class SocialGraph extends ForceLayoutAbstract { * Wrapper function to gather species data from the Wildbook DB and generate a graph */ applySocialData() { - this.parser.processJSON((nodes, links) => this.graphSocialData(nodes, links), this.id); + this.parser.processJSON((nodes, links) => this.graphSocialData(nodes, links), this.id, false); } /** From 32517e2ec5c7d5e1be0939cf2faccd99fdbf247a Mon Sep 17 00:00:00 2001 From: Jon Van Oast Date: Thu, 2 May 2024 14:12:58 -0600 Subject: [PATCH 2/7] add a couple more fields to indiv.uiJson() --- src/main/java/org/ecocean/MarkedIndividual.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/ecocean/MarkedIndividual.java b/src/main/java/org/ecocean/MarkedIndividual.java index 1fd59f8d76..d37f86d372 100755 --- a/src/main/java/org/ecocean/MarkedIndividual.java +++ b/src/main/java/org/ecocean/MarkedIndividual.java @@ -2258,14 +2258,20 @@ public JSONObject uiJson(HttpServletRequest request, boolean includeEncounters) jobj.put("maxYearsBetweenResightings", getMaxNumYearsBetweenSightings()); // note this does not re-compute thumbnail url (so we can get thumbnails on searchResults in a reasonable time) jobj.put("thumbnailUrl", this.thumbnailUrl); + jobj.put("livingStatus", this.isDeceased() ? "dead" : "alive"); - if(includeEncounters) { - Vector encIDs = new Vector(); - for (Encounter enc : this.encounters) { + Vector encIDs = new Vector(); + Encounter firstEncounter = null; + Encounter lastEncounter = null; + for (Encounter enc : this.getDateSortedEncounters()) { encIDs.add(enc.getCatalogNumber()); - } - jobj.put("encounterIDs", encIDs.toArray()); + if (firstEncounter == null) firstEncounter = enc; + lastEncounter = enc; } + if (includeEncounters) jobj.put("encounterIDs", encIDs.toArray()); + if (firstEncounter != null) jobj.put("firstSightingDate", firstEncounter.getDate()); + if (lastEncounter != null) jobj.put("mostRecentSightingDate", lastEncounter.getDate()); + return sanitizeJson(request,decorateJson(request, jobj)); } From ad27ff20345aa6a9540f9bc8262996f22dc5bedf Mon Sep 17 00:00:00 2001 From: Jon Van Oast Date: Thu, 2 May 2024 16:03:28 -0600 Subject: [PATCH 3/7] bugfix --- src/main/java/org/ecocean/MarkedIndividual.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/ecocean/MarkedIndividual.java b/src/main/java/org/ecocean/MarkedIndividual.java index d37f86d372..7c5b4eddcd 100755 --- a/src/main/java/org/ecocean/MarkedIndividual.java +++ b/src/main/java/org/ecocean/MarkedIndividual.java @@ -614,7 +614,7 @@ public boolean isDeceased() { //} for (int c = 0; c < encounters.size(); c++) { Encounter temp = (Encounter) encounters.get(c); - if (temp.getLivingStatus().equals("dead")) { + if ((temp.getLivingStatus() != null) && temp.getLivingStatus().equals("dead")) { return true; } } From 2dc43328b9ab152cbcda806cc78836d29864526a Mon Sep 17 00:00:00 2001 From: Jon Van Oast Date: Tue, 7 May 2024 10:58:07 -0600 Subject: [PATCH 4/7] take 1 on getting some related indiv data --- .../webapp/encounters/relatedIndividuals.jsp | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/main/webapp/encounters/relatedIndividuals.jsp diff --git a/src/main/webapp/encounters/relatedIndividuals.jsp b/src/main/webapp/encounters/relatedIndividuals.jsp new file mode 100644 index 0000000000..8143ff431e --- /dev/null +++ b/src/main/webapp/encounters/relatedIndividuals.jsp @@ -0,0 +1,120 @@ +<%@ page contentType="application/json; charset=utf-8" language="java" import="org.joda.time.LocalDateTime, +org.joda.time.format.DateTimeFormatter, +org.joda.time.format.ISODateTimeFormat,java.net.*, +org.ecocean.grid.*,org.ecocean.ia.*,java.util.*, +java.io.*,java.util.*, java.io.FileInputStream, + +org.datanucleus.api.rest.orgjson.JSONArray, +org.datanucleus.api.rest.orgjson.JSONException, +org.datanucleus.api.rest.orgjson.JSONObject, +org.datanucleus.api.rest.RESTUtils, +org.datanucleus.ExecutionContext, +java.util.Set, java.util.HashSet, +java.lang.reflect.Method, +org.datanucleus.api.jdo.JDOPersistenceManager, +org.ecocean.cache.*, +org.ecocean.social.Relationship, +java.util.zip.GZIPOutputStream, +java.io.File, java.io.FileNotFoundException, org.ecocean.*,org.ecocean.servlet.*,javax.jdo.*, java.lang.StringBuffer, java.util.Vector, java.util.Iterator, java.lang.NumberFormatException"%> +<%! + +// Returns a somewhat rest-like JSON object containing the metadata +public JSONObject uiJson(MarkedIndividual indy, HttpServletRequest request) throws JSONException { + JSONObject jobj = new JSONObject(); + + jobj.put("individualID", indy.getIndividualID()); + jobj.put("displayName", indy.getDisplayName(request)); + jobj.put("sex", indy.getSex()); + jobj.put("nickname", indy.getNickName()); + jobj.put("nickname", indy.getNickName()); + jobj.put("timeOfBirth", indy.getTimeOfBirth()); + jobj.put("timeOfDeath", indy.getTimeofDeath()); + jobj.put("dateFirstIdentified", indy.getDateFirstIdentified()); + jobj.put("dateTimeLatestSighting", indy.getDateLatestSighting()); + jobj.put("genus", request.getParameter("genus")); + jobj.put("specificEpithet", request.getParameter("specificEpithet")); + jobj.put("numberEncounters", indy.getNumEncounters()); + + JSONArray jArray =new JSONArray(); + for (Encounter enc : indy.getEncounterList()) { + JSONObject jobjEnc = new JSONObject(); + jobjEnc.put("lifeStage", enc.getLifeStage()); + jobjEnc.put("dateInMilliseconds", enc.getDateInMilliseconds()); + jobjEnc.put("decimalLatitude", enc.getDecimalLatitude()); + jobjEnc.put("decimalLongitude", enc.getDecimalLongitude()); + jobjEnc.put("year", enc.getYear()); + jobjEnc.put("month", enc.getMonth()); + jobjEnc.put("day", enc.getDay()); + jArray.put(jobjEnc); + } + jobj.put("encounters",jArray); + return jobj; +} + +%> +<%! + +void tryCompress(HttpServletRequest req, HttpServletResponse resp, JSONArray jo, boolean useComp) throws IOException, JSONException { + //System.out.println("??? TRY COMPRESS ??"); + //String s = scrubJson(req, jo).toString(); + String s = jo.toString(); + if (!useComp || (s.length() < 3000)) { //kinda guessing on size here, probably doesnt matter + resp.getWriter().write(s); + } else { + resp.setHeader("Content-Encoding", "gzip"); + OutputStream o = resp.getOutputStream(); + GZIPOutputStream gz = new GZIPOutputStream(o); + gz.write(s.getBytes()); + gz.flush(); + gz.close(); + o.close(); + } +} + +%> +<% + +response.setHeader("Access-Control-Allow-Origin", "*"); + +String context="context0"; +context=ServletUtilities.getContext(request); + +Shepherd myShepherd=new Shepherd(context); +myShepherd.setAction("relatedIndividuals.jsp"); + + + + + + + +MarkedIndividual indiv = myShepherd.getMarkedIndividual(request.getParameter("individualID")); +if (indiv == null) { + response.setStatus(404); + myShepherd.rollbackDBTransaction(); + myShepherd.closeDBTransaction(); + return; +} + + +Set already = new HashSet(); +try { + JSONArray jarr = new JSONArray(); + for (Relationship rel : indiv.getAllRelationships(myShepherd)) { + MarkedIndividual other = rel.getMarkedIndividual1(); + if (other.getId().equals(indiv.getId())) other = rel.getMarkedIndividual2(); + if (already.contains(other)) continue; + already.add(other); + jarr.put(uiJson(other, request)); + } + out.println(jarr.toString()); + +} catch(Exception e){ + e.printStackTrace(); +} +finally{ + myShepherd.rollbackDBTransaction(); + myShepherd.closeDBTransaction(); + +} +%> From bda04291284ed3e46495e3fbbab2e36ed564ad56 Mon Sep 17 00:00:00 2001 From: Jon Van Oast Date: Tue, 7 May 2024 12:45:25 -0600 Subject: [PATCH 5/7] add subject individual as 0th element --- src/main/webapp/encounters/relatedIndividuals.jsp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/webapp/encounters/relatedIndividuals.jsp b/src/main/webapp/encounters/relatedIndividuals.jsp index 8143ff431e..fe59dc51de 100644 --- a/src/main/webapp/encounters/relatedIndividuals.jsp +++ b/src/main/webapp/encounters/relatedIndividuals.jsp @@ -100,6 +100,7 @@ if (indiv == null) { Set already = new HashSet(); try { JSONArray jarr = new JSONArray(); + jarr.put(uiJson(indiv, request)); for (Relationship rel : indiv.getAllRelationships(myShepherd)) { MarkedIndividual other = rel.getMarkedIndividual1(); if (other.getId().equals(indiv.getId())) other = rel.getMarkedIndividual2(); From 4e685368564174c4e4f50a40d09c03a868372c02 Mon Sep 17 00:00:00 2001 From: Jon Van Oast Date: Wed, 8 May 2024 11:06:53 -0600 Subject: [PATCH 6/7] bonus bugfix: close db connection --- src/main/java/org/ecocean/api/Login.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/ecocean/api/Login.java b/src/main/java/org/ecocean/api/Login.java index d1098e9472..31dc777b2c 100644 --- a/src/main/java/org/ecocean/api/Login.java +++ b/src/main/java/org/ecocean/api/Login.java @@ -105,6 +105,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) } response.setHeader("Content-Type", "application/json"); response.getWriter().write(results.toString()); + myShepherd.rollbackAndClose(); } } From df723c435eac0ce31a2c73912342593cecf3f6e9 Mon Sep 17 00:00:00 2001 From: Jon Van Oast Date: Wed, 8 May 2024 13:13:13 -0600 Subject: [PATCH 7/7] block error --- src/main/java/org/ecocean/api/Login.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/ecocean/api/Login.java b/src/main/java/org/ecocean/api/Login.java index 31dc777b2c..cb66daa126 100644 --- a/src/main/java/org/ecocean/api/Login.java +++ b/src/main/java/org/ecocean/api/Login.java @@ -96,6 +96,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) myShepherd.closeDBTransaction(); } } + myShepherd.rollbackAndClose(); } if (success) { @@ -105,7 +106,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) } response.setHeader("Content-Type", "application/json"); response.getWriter().write(results.toString()); - myShepherd.rollbackAndClose(); } }