diff --git a/core/src/main/java/org/mskcc/oncotree/crosswalk/MSKConcept.java b/core/src/main/java/org/mskcc/oncotree/crosswalk/MSKConcept.java index 154846f2..8572f98f 100644 --- a/core/src/main/java/org/mskcc/oncotree/crosswalk/MSKConcept.java +++ b/core/src/main/java/org/mskcc/oncotree/crosswalk/MSKConcept.java @@ -37,6 +37,7 @@ public class MSKConcept { private HashMap> crosswalks; @JsonIgnore private Map additionalProperties = new HashMap(); + private Set history = new HashSet(); /** * No args constructor for use in serialization @@ -81,6 +82,30 @@ public void setCrosswalks(HashMap> crosswalks) { this.crosswalks = crosswalks; } + /** + * + * @return history + */ + public Set getHistory() { + return history; + } + + /** + * + * @param oncotreeCode + */ + public void addHistory(String oncotreeCode) { + this.history.add(oncotreeCode); + } + + /** + * + * @param oncotreeCodes + */ + public void addHistory(Set oncotreeCodes) { + this.history.addAll(oncotreeCodes); + } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; diff --git a/core/src/main/java/org/mskcc/oncotree/crosswalk/MSKConceptCache.java b/core/src/main/java/org/mskcc/oncotree/crosswalk/MSKConceptCache.java index a21ae352..e8a0490e 100644 --- a/core/src/main/java/org/mskcc/oncotree/crosswalk/MSKConceptCache.java +++ b/core/src/main/java/org/mskcc/oncotree/crosswalk/MSKConceptCache.java @@ -25,6 +25,7 @@ import org.mskcc.oncotree.topbraid.OncoTreeNode; import org.mskcc.oncotree.topbraid.OncoTreeRepository; import org.mskcc.oncotree.utils.VersionUtil; +import org.mskcc.oncotree.model.Version; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; @@ -41,6 +42,8 @@ public class MSKConceptCache { private final static Logger logger = Logger.getLogger(MSKConceptCache.class); private static HashMap oncoTreeCodesToMSKConcepts = new HashMap(); + // use this to store and look up previous oncoTree codes + private static HashMap> topBraidURIsToOncotreeCodes = new HashMap>(); @Autowired private OncoTreeRepository oncoTreeRepository; @@ -67,20 +70,38 @@ public MSKConcept get(String oncoTreeCode) { private void resetCache() { logger.info("resetCache() -- clearing Crosswalk MSKConcept cache and refilling"); oncoTreeCodesToMSKConcepts.clear(); - List oncoTreeNodes = oncoTreeRepository.getOncoTree(VersionUtil.getDefaultVersion()); - for (OncoTreeNode node : oncoTreeNodes) { - getFromCrosswalkAndSave(node.getCode()); - } + // versions are ordered in ascending order by release date + for (Version version : VersionUtil.getVersions()) { + List oncoTreeNodes = oncoTreeRepository.getOncoTree(version); + for (OncoTreeNode node : oncoTreeNodes) { + MSKConcept mskConcept = getFromCrosswalkAndSave(node.getCode()); + // get all codes defined so far for this topbraid uri and save in history + if (topBraidURIsToOncotreeCodes.containsKey(node.getURI())) { + // do not add this code to the history, but add any others + HashSet allButThisNode = new HashSet(topBraidURIsToOncotreeCodes.get(node.getURI())); + allButThisNode.remove(node.getCode()); + mskConcept.addHistory(allButThisNode); + } else { + topBraidURIsToOncotreeCodes.put(node.getURI(), new HashSet()); + } + // now save this as onoctree code history for this topbraid uri + topBraidURIsToOncotreeCodes.get(node.getURI()).add(node.getCode()); + } + } } private MSKConcept getFromCrosswalkAndSave(String oncoTreeCode) { - MSKConcept concept = null; + // only save if we have not seen before (UMLS/NCI info will not be different) + if (oncoTreeCodesToMSKConcepts.containsKey(oncoTreeCode)) { + return oncoTreeCodesToMSKConcepts.get(oncoTreeCode); + } + MSKConcept concept = new MSKConcept(); try { concept = crosswalkRepository.getByOncotreeCode(oncoTreeCode); } catch (CrosswalkException e) { // do nothing } - // save even if null + // save even if has no information in it oncoTreeCodesToMSKConcepts.put(oncoTreeCode, concept); return concept; } diff --git a/core/src/main/java/org/mskcc/oncotree/model/History.java b/core/src/main/java/org/mskcc/oncotree/model/History.java deleted file mode 100755 index dfa902df..00000000 --- a/core/src/main/java/org/mskcc/oncotree/model/History.java +++ /dev/null @@ -1,123 +0,0 @@ -package org.mskcc.oncotree.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import org.mskcc.oncotree.model.TumorType; -import org.mskcc.oncotree.model.User; - -import io.swagger.annotations.*; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.Objects; - - -@ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.SpringMVCServerCodegen", date = "2016-04-04T17:16:11.368Z") -public class History { - - private String dateTime = null; - private String operationType = null; - private User user = null; - private TumorType oldValue = null; - private TumorType newValue = null; - - - /** - * Operation time. Please RFC3339 for details. - **/ - @ApiModelProperty(value = "Operation time. Please RFC3339 for details.") - @JsonProperty("dateTime") - public String getDateTime() { - return dateTime; - } - public void setDateTime(String dateTime) { - this.dateTime = dateTime; - } - - - /** - * C, D, U - Create, Delete, Update - **/ - @ApiModelProperty(value = "C, D, U - Create, Delete, Update") - @JsonProperty("operationType") - public String getOperationType() { - return operationType; - } - public void setOperationType(String operationType) { - this.operationType = operationType; - } - - - /** - **/ - @ApiModelProperty(value = "") - @JsonProperty("user") - public User getUser() { - return user; - } - public void setUser(User user) { - this.user = user; - } - - - /** - **/ - @ApiModelProperty(value = "") - @JsonProperty("oldValue") - public TumorType getOldValue() { - return oldValue; - } - public void setOldValue(TumorType oldValue) { - this.oldValue = oldValue; - } - - - /** - **/ - @ApiModelProperty(value = "") - @JsonProperty("newValue") - public TumorType getNewValue() { - return newValue; - } - public void setNewValue(TumorType newValue) { - this.newValue = newValue; - } - - - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - History history = (History) o; - return Objects.equals(dateTime, history.dateTime) && - Objects.equals(operationType, history.operationType) && - Objects.equals(user, history.user) && - Objects.equals(oldValue, history.oldValue) && - Objects.equals(newValue, history.newValue); - } - - @Override - public int hashCode() { - return Objects.hash(dateTime, operationType, user, oldValue, newValue); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class History {\n"); - - sb.append(" dateTime: ").append(dateTime).append("\n"); - sb.append(" operationType: ").append(operationType).append("\n"); - sb.append(" user: ").append(user).append("\n"); - sb.append(" oldValue: ").append(oldValue).append("\n"); - sb.append(" newValue: ").append(newValue).append("\n"); - sb.append("}\n"); - return sb.toString(); - } -} diff --git a/core/src/main/java/org/mskcc/oncotree/model/SearchHistoryResp.java b/core/src/main/java/org/mskcc/oncotree/model/SearchHistoryResp.java deleted file mode 100755 index 8e29d992..00000000 --- a/core/src/main/java/org/mskcc/oncotree/model/SearchHistoryResp.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.mskcc.oncotree.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - - -@ApiModel(description = "") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.SpringMVCServerCodegen", date = "2016-04-04T17:16:11.368Z") -public class SearchHistoryResp { - - private Meta meta = null; - private List data = new ArrayList(); - - - /** - **/ - @ApiModelProperty(value = "") - @JsonProperty("meta") - public Meta getMeta() { - return meta; - } - - public void setMeta(Meta meta) { - this.meta = meta; - } - - - /** - **/ - @ApiModelProperty(value = "") - @JsonProperty("data") - public List getData() { - return data; - } - - public void setData(List data) { - this.data = data; - } - - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SearchHistoryResp searchHistoryResp = (SearchHistoryResp) o; - return Objects.equals(meta, searchHistoryResp.meta) && - Objects.equals(data, searchHistoryResp.data); - } - - @Override - public int hashCode() { - return Objects.hash(meta, data); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class SearchHistoryResp {\n"); - - sb.append(" meta: ").append(meta).append("\n"); - sb.append(" data: ").append(data).append("\n"); - sb.append("}\n"); - return sb.toString(); - } -} diff --git a/core/src/main/java/org/mskcc/oncotree/model/TumorType.java b/core/src/main/java/org/mskcc/oncotree/model/TumorType.java index 2177034f..959078d3 100755 --- a/core/src/main/java/org/mskcc/oncotree/model/TumorType.java +++ b/core/src/main/java/org/mskcc/oncotree/model/TumorType.java @@ -23,7 +23,7 @@ public class TumorType { private Map children = new HashMap(); private String parent = null; private Boolean deprecated = false; - private List history = new ArrayList(); + private List history = new ArrayList(); private Links links = null; private Level level = null; @@ -197,11 +197,11 @@ public void setDeprecated(Boolean deprecated) { **/ @ApiModelProperty(value = "") @JsonProperty("history") - public List getHistory() { + public List getHistory() { return history; } - public void setHistory(List history) { + public void setHistory(List history) { this.history = history; } diff --git a/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeNode.java b/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeNode.java index e660f3e1..bda0064e 100644 --- a/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeNode.java +++ b/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeNode.java @@ -31,17 +31,18 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ + "uri", "code", "name", "mainType", "color", - "nci", - "umls", - "nccn", "parentCode" }) public class OncoTreeNode { + @JsonProperty("uri") + private String uri; + @JsonProperty("code") private String code; @@ -54,21 +55,22 @@ public class OncoTreeNode { @JsonProperty("color") private String color; - @JsonProperty("nci") - private String nci; - - @JsonProperty("umls") - private String umls; - - @JsonProperty("nccn") - private String nccn; - @JsonProperty("parentCode") private String parentCode; @JsonIgnore private Map additionalProperties = new HashMap(); + @JsonProperty("uri") + public String getURI() { + return uri; + } + + @JsonProperty("uri") + public void setURI(String uri) { + this.uri = uri; + } + @JsonProperty("code") public String getCode() { return code; @@ -109,36 +111,6 @@ public void setColor(String color) { this.color = color; } - @JsonProperty("nci") - public String getNci() { - return nci; - } - - @JsonProperty("nci") - public void setNci(String nci) { - this.nci = nci; - } - - @JsonProperty("umls") - public String getUmls() { - return umls; - } - - @JsonProperty("umls") - public void setUmls(String umls) { - this.umls = umls; - } - - @JsonProperty("nccn") - public String getNccn() { - return nccn; - } - - @JsonProperty("nccn") - public void setNccn(String nccn) { - this.nccn = nccn; - } - @JsonProperty("parentCode") public String getParentCode() { return parentCode; diff --git a/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeRepository.java b/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeRepository.java index 6ff9cf11..ac534bff 100644 --- a/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeRepository.java +++ b/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeRepository.java @@ -38,7 +38,7 @@ public class OncoTreeRepository extends TopBraidRepository { private String query = "PREFIX skos: " + "PREFIX onc: " + - "SELECT DISTINCT ?code ?name ?mainType ?color ?nci ?umls ?icdo ?parentCode " + + "SELECT DISTINCT (?s AS ?uri) ?code ?name ?mainType ?color ?parentCode " + "WHERE { " + " GRAPH <%s> { " + " ?s skos:prefLabel ?name;" + @@ -47,9 +47,6 @@ public class OncoTreeRepository extends TopBraidRepository { " ?broader skos:notation ?parentCode}." + " OPTIONAL{?s onc:mainType ?mainType}." + " OPTIONAL{?s onc:color ?color}." + - " OPTIONAL{?s onc:nci ?nci}." + - " OPTIONAL{?s onc:umls ?umls}." + - " OPTIONAL{?s onc:icdo ?icdo}." + " }" + "}"; diff --git a/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeVersionRepository.java b/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeVersionRepository.java index fbd0aa5b..207e08fb 100644 --- a/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeVersionRepository.java +++ b/core/src/main/java/org/mskcc/oncotree/topbraid/OncoTreeVersionRepository.java @@ -36,16 +36,21 @@ public class OncoTreeVersionRepository extends TopBraidRepository { private final static Logger logger = Logger.getLogger(OncoTreeVersionRepository.class); + // NOTE we MUST order by release_date private String query = "PREFIX oncotree-version: " + - "SELECT ?api_identifier ?graph_uri ?description " + + "SELECT ?api_identifier ?graph_uri ?description ?release_date " + "WHERE { " + " GRAPH { " + " ?s oncotree-version:graph_uri ?graph_uri. " + " ?s oncotree-version:api_identifier ?api_identifier. " + + " ?s oncotree-version:release_date ?release_date. " + " OPTIONAL{?s oncotree-version:description ?description.} " + " } " + - "}"; + "} ORDER BY ASC(?release_date)"; + /** + * @return all oncotree versions ordered by ascending release date (development last) + */ public List getOncoTreeVersions() throws TopBraidException { return super.query(query, new ParameterizedTypeReference>(){}); } diff --git a/core/src/main/java/org/mskcc/oncotree/utils/TumorTypesUtil.java b/core/src/main/java/org/mskcc/oncotree/utils/TumorTypesUtil.java index 5a757516..56bc0a42 100644 --- a/core/src/main/java/org/mskcc/oncotree/utils/TumorTypesUtil.java +++ b/core/src/main/java/org/mskcc/oncotree/utils/TumorTypesUtil.java @@ -51,7 +51,7 @@ public class TumorTypesUtil { private final static Logger logger = Logger.getLogger(TumorTypesUtil.class); - public final static String TSV_HEADER = "primary\tsecondary\ttertiary\tquaternary\tquinternary\tmetamaintype\tmetacolor\tmetanci\tmetaumls"; + public final static String TSV_HEADER = "primary\tsecondary\ttertiary\tquaternary\tquinternary\tmetamaintype\tmetacolor\tmetanci\tmetaumls\thistory"; private static OncoTreeRepository oncoTreeRepository; @Autowired @@ -161,6 +161,7 @@ private static void addTumorTypeToRows(TumorType tumorType, List rows, L row.add(StringUtils.defaultString(tumorType.getColor())); row.add(StringUtils.defaultString(StringUtils.join(tumorType.getNCI(), ","))); row.add(StringUtils.defaultString(StringUtils.join(tumorType.getUMLS(), ","))); + row.add(StringUtils.defaultString(StringUtils.join(tumorType.getHistory(), ","))); rows.add(StringUtils.join(row, "\t")); // Prepare for next recursive call @@ -284,10 +285,13 @@ private static Map loadFromRepository(Version version) throws tumorType.setNCI(crosswalks.get("NCI")); } List umlsIds = new ArrayList(); - for (String mskConceptId : mskConcept.getConceptIds()) { - umlsIds.add(mskConceptId.replace("MSK", "C")); + if (mskConcept.getConceptIds() != null) { + for (String mskConceptId : mskConcept.getConceptIds()) { + umlsIds.add(mskConceptId.replace("MSK", "C")); + } } tumorType.setUMLS(umlsIds); + tumorType.setHistory(new ArrayList(mskConcept.getHistory())); } if (rootNodeCodeSet.contains(thisNodeCode)) { continue; //root node has no parent @@ -314,9 +318,6 @@ private static TumorType initTumorType(OncoTreeNode oncoTreeNode, Version versio tumorType.setCode(oncoTreeNode.getCode()); tumorType.setName(oncoTreeNode.getName()); tumorType.setColor(oncoTreeNode.getColor()); - // we no longer get these from TopBraid, we get them from crosswalk, above - //tumorType.setNCI(oncoTreeNode.getNci()); - //tumorType.setUMLS(oncoTreeNode.getUmls()); tumorType.setParent(oncoTreeNode.getParentCode()); return tumorType; } diff --git a/core/src/test/java/org/mskcc/oncotree/utils/OncotreeTestConfig.java b/core/src/test/java/org/mskcc/oncotree/utils/OncotreeTestConfig.java index 99921104..e3e863db 100644 --- a/core/src/test/java/org/mskcc/oncotree/utils/OncotreeTestConfig.java +++ b/core/src/test/java/org/mskcc/oncotree/utils/OncotreeTestConfig.java @@ -158,9 +158,6 @@ private List setupOncotreeRepositoryMockResponse() throws Exceptio nextNode.setName(rawTestValueSource[pos + 1]); nextNode.setMainType(rawTestValueSource[pos + 2]); nextNode.setColor(rawTestValueSource[pos + 3]); - nextNode.setNci(""); - nextNode.setUmls(""); - nextNode.setNccn(""); nextNode.setParentCode(rawTestValueSource[pos + 4]); oncoTreeRepositoryMockResponse.add(nextNode); } diff --git a/web/src/main/java/org/mskcc/oncotree/api/HistoryApi.java b/web/src/main/java/org/mskcc/oncotree/api/HistoryApi.java deleted file mode 100755 index 3781ae3d..00000000 --- a/web/src/main/java/org/mskcc/oncotree/api/HistoryApi.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.mskcc.oncotree.api; - -import io.swagger.annotations.ApiParam; -import org.mskcc.oncotree.model.SearchHistoryResp; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestParam; - -import java.util.Date; - -//@Controller -//@RequestMapping(value = "/api/history", produces = {APPLICATION_JSON_VALUE}) -//@Api(value = "/history", description = "the history API") -@javax.annotation.Generated(value = "class io.swagger.codegen.languages.SpringMVCServerCodegen", date = "2016-04-04T17:16:11.368Z") -public class HistoryApi { -// @ApiOperation(value = "Search all operations.", notes = "...", response = SearchHistoryResp.class) -// @ApiResponses(value = { -// @io.swagger.annotations.ApiResponse(code = 200, message = "An array of tumor types")}) -// @RequestMapping(value = "/search", -// produces = {"application/json"}, -// method = RequestMethod.GET) - public ResponseEntity historySearchGet( - @ApiParam(value = "The start date") @RequestParam(value = "start", required = false) Date start, - @ApiParam(value = "The start date") @RequestParam(value = "end", required = false) Date end -// , @ApiParam(value = "The callback function name. This has to be used with dataType JSONP.") @RequestParam(value = "callback", required = false) String callback - ) - throws NotFoundException { - // do some magic! - return new ResponseEntity(HttpStatus.OK); - } - - - // @ApiOperation(value = "The history of data manipulating.", notes = "...", response = SearchHistoryResp.class) -// @ApiResponses(value = { -// @io.swagger.annotations.ApiResponse(code = 200, message = "An array of tumor types")}) -// @RequestMapping(value = "/search/{type}", -// produces = {"application/json"}, -// method = RequestMethod.GET) - public ResponseEntity historySearchTypeGet( - @ApiParam(value = "Operation type. It could be 'create', 'delete', 'update' or 'all'.", required = true) @PathVariable("type") String type, - @ApiParam(value = "The start date") @RequestParam(value = "start", required = false) Date start, - @ApiParam(value = "The start date") @RequestParam(value = "end", required = false) Date end -// , @ApiParam(value = "The callback function name. This has to be used with dataType JSONP.") @RequestParam(value = "callback", required = false) String callback - ) - throws NotFoundException { - // do some magic! - return new ResponseEntity(HttpStatus.OK); - } - - -} diff --git a/web/src/main/resources/static/js/tree.js b/web/src/main/resources/static/js/tree.js index f505505a..629e8946 100644 --- a/web/src/main/resources/static/js/tree.js +++ b/web/src/main/resources/static/js/tree.js @@ -113,6 +113,10 @@ var tree = (function () { uniqueTreeNode[type].umls = row.metaumls; } + if(row.hasOwnProperty('history')){ + uniqueTreeNode[type].history = row.history; + } + } node = node[type]; } @@ -365,8 +369,10 @@ var tree = (function () { _qtipContent += 'Main type: ' + d.mainType + '
'; _qtipContent += 'NCI: ' + nci_links.join(",") + '
'; _qtipContent += 'UMLS: ' + umls_links.join(",") + '
'; - _qtipContent += 'Color: ' + d.color||'LightBlue' + '
'; - + _qtipContent += 'Color: ' + (d.color||'LightBlue') + '
'; + if (typeof d.history !== 'undefined' && d.history != '') { + _qtipContent += 'Previous codes: ' + d.history + '
'; + } $(this).qtip({ content:{text: _qtipContent}, style: { classes: 'qtip-light qtip-rounded qtip-shadow qtip-grey qtip-wide'}, @@ -592,7 +598,8 @@ var tree = (function () { if (searchKey === '') { d3.select(this).style('fill', 'black'); } else { - if (d.name.toLowerCase().indexOf(searchKey) !== -1) { + if (d.name.toLowerCase().indexOf(searchKey) !== -1 || + (typeof d.history !== 'undefined' && d.history != '' && d.history.toLowerCase().split(",").indexOf(searchKey) !== -1)) { d3.select(this).style('fill', 'red'); } else { d3.select(this).style('fill', 'black'); @@ -604,14 +611,16 @@ var tree = (function () { function findChildContain(parentId, searchKey, node) { parentId = String(parentId); if (node._children) { - if (node.name.toLowerCase().indexOf(searchKey) !== -1) { + if (node.name.toLowerCase().indexOf(searchKey) !== -1 || + (typeof node.history !== 'undefined' && node.history != '' && node.history.toLowerCase().split(",").indexOf(searchKey) !== -1)) { searchResult.push(parentId); } for (var i = 0, numOfChild = node._children.length; i < numOfChild; i++) { findChildContain(parentId + "-" + i, searchKey, node._children[i]); } } else { - if (node.name.toLowerCase().indexOf(searchKey) !== -1) { + if (node.name.toLowerCase().indexOf(searchKey) !== -1 || + (typeof node.history !== 'undefined' && node.history != '' && node.history.toLowerCase().split(",").indexOf(searchKey) !== -1)) { searchResult.push(parentId); } }