NIHVIVO-2186 Modify custom list view queries to filter out statements with no linked individual when user is not editing the page. Involves pruning the grouped property list of properties and groups which are thereby empty.

This commit is contained in:
ryounes 2011-03-21 22:24:33 +00:00
parent 6ea23218c9
commit f398183c94
6 changed files with 73 additions and 21 deletions

View file

@ -82,6 +82,11 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
}
}
@Override
protected boolean isEmpty() {
return subclasses.isEmpty();
}
protected ConfigError checkQuery(String queryString) {
if (StringUtils.isBlank(queryString)) {

View file

@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
@ -102,6 +103,37 @@ public class GroupedPropertyList extends BaseTemplateModel {
policyHelper, populatedDataPropertyList, populatedObjectPropertyList));
}
if (!editing) {
pruneEmptyProperties();
}
}
// It's possible that a collated object property retrieved in the call to getPopulatedObjectPropertyList()
// is now empty of statements, because if not editing, some statements without a linked individual
// are not retrieved by the query. (See <linked-individual-required> elements in queries.)
// Remove these properties, and also remove any groups with no remaining properties.
private void pruneEmptyProperties() {
Iterator<PropertyGroupTemplateModel> iGroups = groups.iterator();
while (iGroups.hasNext()) {
PropertyGroupTemplateModel pgtm = iGroups.next();
Iterator<PropertyTemplateModel> iProperties = pgtm.getProperties().iterator();
while (iProperties.hasNext()) {
PropertyTemplateModel property = iProperties.next();
if (property instanceof ObjectPropertyTemplateModel) {
// It's not necessary to do comparable pruning of the subclass list
// of a CollatedObjectPropertyTemplateModel, because the collated subclass
// list is compiled on the basis of existing statements. There will not
// be any empty subclasses.
if ( ( (ObjectPropertyTemplateModel) property).isEmpty() ) {
iProperties.remove();
}
}
}
if (pgtm.isEmpty()) {
iGroups.remove();
}
}
}
@SuppressWarnings("unchecked")
@ -422,9 +454,13 @@ public class GroupedPropertyList extends BaseTemplateModel {
List<PropertyTemplateModel> properties = pgtm.getProperties();
for (PropertyTemplateModel ptm : properties) {
if (propertyUri.equals(ptm.getUri())) {
// Remove the property from the group
// Remove the property from the group.
// NB Works with a for-each loop instead of an iterator, since
// iteration doesn't continue after the remove.
properties.remove(ptm);
// If this is the only property in the group, remove the group as well
// If this is the only property in the group, remove the group as well.
// NB Works with a for-each loop instead of an iterator, since
// iteration doesn't continue after the remove.
if (properties.size() == 0) {
groups.remove(pgtm);
}

View file

@ -118,6 +118,8 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
}
}
protected abstract boolean isEmpty();
@Override
protected int getPropertyDisplayTier(Property p) {
// For some reason ObjectProperty.getDomainDisplayTier() returns a String
@ -324,8 +326,8 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
private static final String NODE_NAME_QUERY_SELECT = "query-select";
private static final String NODE_NAME_TEMPLATE = "template";
private static final String NODE_NAME_POSTPROCESSOR = "postprocessor";
private static final String NODE_NAME_COLLATION_FRAGMENT = "collation-fragment";
private static final String NODE_NAME_LINKED_INDIVIDUAL_OPTIONAL = "linked-individual-optional";
private static final String NODE_NAME_COLLATED = "collated";
private static final String NODE_NAME_LINKED_INDIVIDUAL_REQUIRED = "linked-individual-required";
/* NB The default post-processor is not the same as the post-processor for the default view. The latter
* actually defines its own post-processor, whereas the default post-processor is used for custom views
@ -463,27 +465,27 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
Node selectQueryNode = doc.getElementsByTagName(NODE_NAME_QUERY_SELECT).item(0);
String value = null;
if (selectQueryNode != null) {
boolean removeCollationFragments = ObjectPropertyTemplateModel.this instanceof UncollatedObjectPropertyTemplateModel;
/* If editing the page (policyHelper != null), show statements with missing linked individual; otherwise, hide these
boolean collated = ObjectPropertyTemplateModel.this instanceof CollatedObjectPropertyTemplateModel;
/* If not editing the page (policyHelper == null), hide statements with missing linked individual; otherwise, show these
* statements. We might want to refine this based on whether the user can edit the statement in question, but that
* would require a completely different approach: including the statement in the query results, and then during the
* postprocessing phase, checking the editing policy, and removing the statement if it's not editable. We would not
* would require a completely different approach: include the statement in the query results, and then during the
* postprocessing phase, check the editing policy, and remove the statement if it's not editable. We would not
* preprocess the query, as here.
*/
boolean linkedIndividualOptional = policyHelper != null;
boolean linkedIndividualRequired = policyHelper == null;
NodeList children = selectQueryNode.getChildNodes();
int childCount = children.getLength();
value = "";
for (int i = 0; i < childCount; i++) {
Node node = children.item(i);
if (node.getNodeName().equals(NODE_NAME_COLLATION_FRAGMENT)) {
if (!removeCollationFragments) {
if (node.getNodeName().equals(NODE_NAME_COLLATED)) {
if (collated) {
value += node.getChildNodes().item(0).getNodeValue();
}
} else if (node.getNodeName().equals(NODE_NAME_LINKED_INDIVIDUAL_OPTIONAL)) {
if (linkedIndividualOptional) {
} // else ignore this node
} else if (node.getNodeName().equals(NODE_NAME_LINKED_INDIVIDUAL_REQUIRED)) {
if (linkedIndividualRequired) {
value += node.getChildNodes().item(0).getNodeValue();
}
} // else ignore this node
} else {
value += node.getNodeValue();
}

View file

@ -41,6 +41,10 @@ public class PropertyGroupTemplateModel extends BaseTemplateModel {
}
}
protected boolean isEmpty() {
return properties.isEmpty();
}
protected void remove(PropertyTemplateModel ptm) {
properties.remove(ptm);
}

View file

@ -55,6 +55,11 @@ public class UncollatedObjectPropertyTemplateModel extends ObjectPropertyTemplat
}
}
@Override
protected boolean isEmpty() {
return statements.isEmpty();
}
/* Access methods for templates */
public List<ObjectPropertyStatementTemplateModel> getStatements() {

View file

@ -11,15 +11,15 @@
PREFIX rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#&gt;
PREFIX afn: &lt;http://jena.hpl.hp.com/ARQ/function#&gt;
SELECT <collation-fragment> ?subclass </collation-fragment>
SELECT <collated> ?subclass </collated>
?object ?name ?moniker WHERE {
?subject ?property ?object
<collation-fragment> OPTIONAL { ?object a ?subclass }
<collated> OPTIONAL { ?object a ?subclass }
FILTER ( afn:namespace(?subclass) != "http://vitro.mannlib.cornell.edu/ns/vitro/0.7#" )
</collation-fragment>
</collated>
OPTIONAL { ?object rdfs:label ?name }
OPTIONAL { ?object vitro:moniker ?moniker }
} ORDER BY <collation-fragment> ?subclass </collation-fragment> ?name ?object
} ORDER BY <collated> ?subclass </collated> ?name ?object
</query-select>
<query-construct>