From 503652796c62eb75d2ae9333f4ef309aacb6e1ef Mon Sep 17 00:00:00 2001 From: rjy7 Date: Fri, 24 Sep 2010 21:35:03 +0000 Subject: [PATCH] Merge r5933:5935 and r5937 from nihvivo-rel-1.1-maint --- .../EntityMergedPropertyListController.java | 459 ++++++++++++------ 1 file changed, 312 insertions(+), 147 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/EntityMergedPropertyListController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/EntityMergedPropertyListController.java index 0f6c2e402..7a69920bf 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/EntityMergedPropertyListController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/EntityMergedPropertyListController.java @@ -63,15 +63,15 @@ public class EntityMergedPropertyListController extends VitroHttpServlet { private static final int MAX_GROUP_DISPLAY_RANK = 99; /** Don't include these properties in the list. */ - private static final Collection SUPPRESSED_OBJECT_PROPERTIES = Collections - .unmodifiableCollection(Arrays - .asList(new String[] { VitroVocabulary.IND_MAIN_IMAGE })); + private static final Collection SUPPRESSED_OBJECT_PROPERTIES = Collections + .unmodifiableCollection(Arrays + .asList(new String[] { VitroVocabulary.IND_MAIN_IMAGE })); public void doGet( HttpServletRequest request, HttpServletResponse res ) throws IOException, ServletException { - - VitroRequest req = new VitroRequest(request); - + + VitroRequest req = new VitroRequest(request); + try { super.doGet(req, res); Object obj = req.getAttribute("entity"); @@ -118,12 +118,12 @@ public class EntityMergedPropertyListController extends VitroHttpServlet { List objectPropertyList = subject.getObjectPropertyList(); for (ObjectProperty op : objectPropertyList) { - if (!SUPPRESSED_OBJECT_PROPERTIES.contains(op)) { + if (!SUPPRESSED_OBJECT_PROPERTIES.contains(op)) { op.setEditLabel(op.getDomainPublic()); mergedPropertyList.add(op); - }else{ - log.debug("suppressed " + op.getURI()); - } + }else{ + log.debug("suppressed " + op.getURI()); + } } if (editMode) { @@ -215,10 +215,16 @@ public class EntityMergedPropertyListController extends VitroHttpServlet { if (g.getPropertyList()!=null && g.getPropertyList().size()>0) { for (Property p : g.getPropertyList()) { if (p instanceof ObjectProperty) { - ObjectProperty op = (ObjectProperty)p; - if (op.getObjectPropertyStatements()!=null && op.getObjectPropertyStatements().size()>0) { - statementCount += op.getObjectPropertyStatements().size(); - } + ObjectProperty op = (ObjectProperty)p; + List opStmts = op.getObjectPropertyStatements(); + if (op.getObjectPropertyStatements()!=null && opStmts.size()>0) { + statementCount += opStmts.size(); + + // If not collated, we need to apply custom sorting now. + applyCustomSortToUncollatedProperty(op, opStmts); + } + + } } } @@ -228,18 +234,26 @@ public class EntityMergedPropertyListController extends VitroHttpServlet { } catch (Exception ex) { log.error("Exception on trying to prune groups list with properties: "+ex.getMessage()); } - mergedPropertyList.clear(); + mergedPropertyList.clear(); + + } else { // ungrouped mode + for (Property p : mergedPropertyList) { + if (p instanceof ObjectProperty) { + ObjectProperty op = (ObjectProperty)p; + applyCustomSortToUncollatedProperty(op, op.getObjectPropertyStatements()); + } + } } } if (groupedMode) { req.setAttribute("groupsList",groupsList); } else { - UnaryFunctor,List> entityPropertyListFilter = PropertyMaskingSetup.getEntityPropertyListFilter(getServletContext()); - if (entityPropertyListFilter != null) { - mergedPropertyList = entityPropertyListFilter.fn(mergedPropertyList); - } - + UnaryFunctor,List> entityPropertyListFilter = PropertyMaskingSetup.getEntityPropertyListFilter(getServletContext()); + if (entityPropertyListFilter != null) { + mergedPropertyList = entityPropertyListFilter.fn(mergedPropertyList); + } + req.setAttribute("mergedList",mergedPropertyList); } @@ -260,7 +274,7 @@ public class EntityMergedPropertyListController extends VitroHttpServlet { - public void doPost(HttpServletRequest request, HttpServletResponse response) + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException { doGet(request, response); } @@ -299,7 +313,7 @@ public class EntityMergedPropertyListController extends VitroHttpServlet { } switch (count) { case 0: log.warn("groupsList has no groups on entering populateGroupsListWithProperties(); will create a new group \"other\""); - break; + break; case 1: break; default: try { Collections.sort(groupsList); @@ -439,13 +453,20 @@ public class EntityMergedPropertyListController extends VitroHttpServlet { private List collateBySubclass(List mergedPropertyList) { - for( Property prop : mergedPropertyList){ - if( prop instanceof ObjectProperty && ((ObjectProperty)prop).getCollateBySubclass() ){ - collateBySubclass((ObjectProperty)prop); - } - } - return mergedPropertyList; - } + for( Property prop : mergedPropertyList){ + if( prop instanceof ObjectProperty ) { + ObjectProperty op = (ObjectProperty) prop; + if (op.getCollateBySubclass() ){ + log.debug("Collating property " + prop.getURI() + " by subclass"); + collateBySubclass(op); + } else { + + } + } + } + + return mergedPropertyList; + } /** * Sort the object property statements for each property so that they @@ -454,128 +475,272 @@ public class EntityMergedPropertyListController extends VitroHttpServlet { * This will be tricky since "subclass" is vaguely defined. Here directly * asserted classes are used. */ - private void collateBySubclass(ObjectProperty prop) { - List orgStmtList = prop.getObjectPropertyStatements(); - if( orgStmtList == null ) - return; - Map directClasses = getDirectClasses( getObjectsFromStmts( orgStmtList ) ); - //don't do collateBySubclass if there is only one class - if( directClasses.size() < 2 ) - prop.setCollateBySubclass(false); //this overrides the value from the model - else{ - System.out.println("statements for object property: " + orgStmtList.size()); - //get list of direct classes and sort them - List vclasses = new LinkedList(directClasses.values()); - Collections.sort( - vclasses, - new Comparator(){ - public int compare(VClass o1, VClass o2) { - return o1.getName().compareTo(o2.getName()); - } - }); - - //order object property statements by sorted direct class list - List sortedStmtList = new LinkedList(); - for (VClass clazz : vclasses) { - // get all obj prop stmts with objects of this class - List stmtsForClass = new ArrayList(); - - System.out.println("statements for object property: " + orgStmtList.size()); - Iterator it = orgStmtList.iterator(); - while( it.hasNext()){ - ObjectPropertyStatement stmt = it.next(); - //if (stmt.getObject().getVClasses(true).contains(clazz)) { - - Individual obj = stmt.getObject(); - List vclassesForObj = obj.getVClasses(true); - if (vclassesForObj != null && vclassesForObj.contains(clazz)) { - System.out.println("adding " + stmt + " to class " - + clazz.getURI()); - System.out.println("subjectURI " + stmt.getSubjectURI() - + " objectURI" + stmt.getObject().getURI()); - System.out.println("stmtsForclass size: " - + stmtsForClass.size()); - System.out.println("stmtsForclass size: " - + stmtsForClass.size()); - - stmtsForClass.add(stmt); - } - } - - //bdc34: What do we do if a object individual is directly asserted to two different - //types? For now we just show them in whichever type shows up first. related to NIHVIVO-876 - orgStmtList.removeAll(stmtsForClass); - - Collections.sort(stmtsForClass, - new Comparator() { - public int compare(ObjectPropertyStatement o1, - ObjectPropertyStatement o2) { - return o1.getObject().getName().compareTo( - o2.getObject().getName()); - } - }); - System.out.println("stmtsForclass size after sort: " - + stmtsForClass.size()); - System.out.println("sortedStmtList size before add: " - + sortedStmtList.size()); - sortedStmtList.addAll(stmtsForClass); - System.out.println("sortedStmtList size after add: " - + sortedStmtList.size()); - } - prop.setObjectPropertyStatements(sortedStmtList); - } - - } + private void collateBySubclass(ObjectProperty prop) { + List orgStmtList = prop.getObjectPropertyStatements(); + if( orgStmtList == null ) + return; + Map directClasses = getDirectClasses( getObjectsFromStmts( orgStmtList ) ); + //don't do collateBySubclass if there is only one class + if( directClasses.size() < 2 ) { + prop.setCollateBySubclass(false); //this overrides the value from the model + } + else{ + log.debug("statements for object property: " + orgStmtList.size()); + //get list of direct classes and sort them + List vclasses = new LinkedList(directClasses.values()); + Collections.sort( + vclasses, + new Comparator(){ + public int compare(VClass o1, VClass o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + + //order object property statements by sorted direct class list + List sortedStmtList = new LinkedList(); + for (VClass clazz : vclasses) { + // get all obj prop stmts with objects of this class + List stmtsForClass = new ArrayList(); + + log.debug("statements for object property: " + orgStmtList.size()); + Iterator it = orgStmtList.iterator(); + while( it.hasNext()){ + ObjectPropertyStatement stmt = it.next(); + //if (stmt.getObject().getVClasses(true).contains(clazz)) { + + Individual obj = stmt.getObject(); + List vclassesForObj = obj.getVClasses(true); + if (vclassesForObj != null && vclassesForObj.contains(clazz)) { + log.debug("adding " + stmt + " to class " + + clazz.getURI()); + log.debug("subjectURI " + stmt.getSubjectURI() + + " objectURI" + stmt.getObject().getURI()); + log.debug("stmtsForclass size: " + + stmtsForClass.size()); + log.debug("stmtsForclass size: " + + stmtsForClass.size()); + + stmtsForClass.add(stmt); + } + } + + //bdc34: What do we do if a object individual is directly asserted to two different + //types? For now we just show them in whichever type shows up first. related to NIHVIVO-876 + orgStmtList.removeAll(stmtsForClass); + + sortStatements(prop, stmtsForClass); + + log.debug("stmtsForclass size after sort: " + + stmtsForClass.size()); + log.debug("sortedStmtList size before add: " + + sortedStmtList.size()); + + sortedStmtList.addAll(stmtsForClass); + + log.debug("sortedStmtList size after add: " + + sortedStmtList.size()); + } + prop.setObjectPropertyStatements(sortedStmtList); + } + + } + private void sortStatements(ObjectProperty prop, List statements) { + + if (!applyCustomSort(prop, statements)) { + Collections.sort(statements, + new Comparator() { + public int compare(ObjectPropertyStatement o1, + ObjectPropertyStatement o2) { + return o1.getObject().getName().compareTo( + o2.getObject().getName()); + } + }); + } + } + // rjy7 Quick and dirty fix to achieve custom sorting for specific properties in the VIVO ontology. + // See NIHVIVO-426, NIHVIVO-1158, NIHVIVO-1160. Some of these involve sorting on data properties of an + // individual two graph edges away from the individual being displayed, for which there is currently + // no provision. A better strategy will be designed and implemented in a later version, in particular + // one that does not involve hard-coded references to the VIVO ontology in the Vitro core. + private boolean applyCustomSort(ObjectProperty prop, List statements) { + + String vivoCoreOntology = "http://vivoweb.org/ontology/core#"; + String propertyUri = prop.getURI(); + + // Positions in an organization + if (propertyUri.equals(vivoCoreOntology + "organizationForPosition")) { + sortByRelatedIndividualNames(statements, vivoCoreOntology + "positionForPerson"); + return true; + } + + // Person's positions + if (propertyUri.equals(vivoCoreOntology + "personInPosition")) { + sortReverseChron(statements, vivoCoreOntology + "endYear", vivoCoreOntology + "startYear"); + return true; + } + +// // Person's publications +// if (propertyUri.equals(vivoCoreOntology + "authorInAuthorship")) { +// sortByReverseChronAndRelatedIndividualName(statements, vivoCoreOntology + " ", vivoCoreOntology + " "); +// return true; +// } + + return false; + } - private List getObjectsFromStmts(List orgStmtList) { - List individuals = new LinkedList(); - for( ObjectPropertyStatement stmt : orgStmtList ){ - individuals.add( stmt.getObject() ); - } - return individuals; - } + // Apply custom sorting to an uncollated property. If the property is collated, the custom sorting has already + // been applied to each subclass listing individually. + private void applyCustomSortToUncollatedProperty(ObjectProperty op, List opStmts) { + // This includes the case where the ontology doesn't specify collating, as well as the case + // where we don't collate because only one subclass is populated, since then we've set + // the collation value to false. + if (!op.getCollateBySubclass()) { + if (applyCustomSort(op, opStmts)) { + op.setObjectPropertyStatements(opStmts); + } + } + } + + private void sortReverseChron(List statements, String endYearPredicate, String startYearPredicate) { + // 1. Sort by end date descending, null dates first + // 2. Then by start date descending, null dates last + // 3. No sorting for entries with no start or end date - just put at the bottom in random order + final String endYearProperty = endYearPredicate; + final String startYearProperty = startYearPredicate; + Collections.sort(statements, new Comparator() { + public int compare(ObjectPropertyStatement left, ObjectPropertyStatement right) { + String endLeftValue = left.getObject().getDataValue(endYearProperty); + Integer endLeft = endLeftValue == null ? null : Integer.valueOf(endLeftValue); - private Map getDirectClasses(List objectsFromStmts) { - Map directClasses = new HashMap(); + String startLeftValue = left.getObject().getDataValue(startYearProperty); + Integer startLeft = startLeftValue == null ? null : Integer.valueOf(startLeftValue); + + String endRightValue = right.getObject().getDataValue(endYearProperty); + Integer endRight = endRightValue == null ? null : Integer.valueOf(endRightValue); - for (Individual ind : objectsFromStmts) { - for (VClass clazz : ind.getVClasses(true)) { - directClasses.put(clazz.getURI(),clazz); - } - } - return directClasses; - } + String startRightValue = right.getObject().getDataValue(startYearProperty); + Integer startRight = startRightValue == null ? null : Integer.valueOf(startRightValue); + + // No sorting for entries with no start or end date - just put at the bottom in random order + if (endLeft == null && startLeft == null) { + return 1; + } + if (endRight == null && startRight == null) { + return -1; + } + + // First sort by end date + // A null end date precedes + // But if both end dates are null, compare start dates + if ( ! (endLeft == null && endRight == null) ) { + if (endLeft == null) { + return -1; + } + if (endRight == null) { + return 1; + } + + int endComp = endLeft.compareTo(endRight); + if (endComp != 0) { + return 0 - endComp; + } + } + + // If end dates are equal, sort by start date + // A null start date follows + if (startLeft == null) { + return 1; + } + if (startRight == null) { + return -1; + } + + return 0 - startLeft.compareTo(startRight); + } + }); + } + +// private void sortByReverseChronAndRelatedIndividualName(List statements, +// String datePredicate, String relatedIndividualPredicate) { +// +// } + + // Sort statements by the name of the individual on the other side of the context node. + private void sortByRelatedIndividualNames(List statements, String predicateUri) { + + log.debug("In sortByRelatedIndividualNames(), before sorting"); + if (log.isDebugEnabled()) { + for (ObjectPropertyStatement ops : statements) { + log.debug(ops.getObject().getRelatedIndividual(predicateUri).getName()); + } + } + + final String propertyUri = predicateUri; + Collections.sort(statements, new Comparator() { + public int compare(ObjectPropertyStatement left, ObjectPropertyStatement right) { + Individual indLeft = left.getObject().getRelatedIndividual(propertyUri); + Individual indRight = right.getObject().getRelatedIndividual(propertyUri); + return indLeft.getName().compareTo(indRight.getName()); + } + }); + + log.debug("In sortByRelatedIndividualNames(), after sorting"); + if (log.isDebugEnabled()) { + for (ObjectPropertyStatement ops : statements) { + log.debug(ops.getObject().getRelatedIndividual(predicateUri).getName()); + } + } + } - /** - * Look for filter in servlet context and filter properties with it if there is one. - * - * This allows a vitro instance to have specialized filtering for display. It was originally - * created to deal with problems caused by custom short views. - * * - * @param objectPropertyList - * @param wdf - * @return - */ - private Individual filterFromContext(Individual ind ) { - try{ - UnaryFunctor filter = getMergedPropertyListFilter(getServletContext()); - if( filter == null ) - return ind; - else - return filter.fn(ind); - }catch(Throwable t){ - log.error(t,t); - } - return ind; - } - - public static void setMergedPropertyListFilter( UnaryFunctorfn, ServletContext sc){ - sc.setAttribute("EntityMergedPropertyListController.toFilteringIndividual", fn); - } - - public static UnaryFunctor getMergedPropertyListFilter( ServletContext sc){ - return(UnaryFunctor)sc.getAttribute("EntityMergedPropertyListController.toFilteringIndividual"); - } + private List getObjectsFromStmts(List orgStmtList) { + List individuals = new LinkedList(); + for( ObjectPropertyStatement stmt : orgStmtList ){ + individuals.add( stmt.getObject() ); + } + return individuals; + } + + private Map getDirectClasses(List objectsFromStmts) { + Map directClasses = new HashMap(); + + for (Individual ind : objectsFromStmts) { + for (VClass clazz : ind.getVClasses(true)) { + directClasses.put(clazz.getURI(),clazz); + } + } + return directClasses; + } + + /** + * Look for filter in servlet context and filter properties with it if there is one. + * + * This allows a vitro instance to have specialized filtering for display. It was originally + * created to deal with problems caused by custom short views. + * * + * @param objectPropertyList + * @param wdf + * @return + */ + private Individual filterFromContext(Individual ind ) { + try{ + UnaryFunctor filter = getMergedPropertyListFilter(getServletContext()); + if( filter == null ) + return ind; + else + return filter.fn(ind); + }catch(Throwable t){ + log.error(t,t); + } + return ind; + } + + public static void setMergedPropertyListFilter( UnaryFunctorfn, ServletContext sc){ + sc.setAttribute("EntityMergedPropertyListController.toFilteringIndividual", fn); + } + + public static UnaryFunctor getMergedPropertyListFilter( ServletContext sc){ + return(UnaryFunctor)sc.getAttribute("EntityMergedPropertyListController.toFilteringIndividual"); + } }