NIHVIVO-1333 Display of uncollated object property statements with default view

This commit is contained in:
rjy7 2010-12-13 15:27:22 +00:00
parent ca2d8dfb4c
commit 838713d669
18 changed files with 220 additions and 83 deletions

View file

@ -204,11 +204,6 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
writePage(root, config, vreq, response);
}
private void processSetupTemplate(Configuration config, HttpServletRequest request, Map<String, Object> map) {
TemplateProcessingHelper helper = new TemplateProcessingHelper(config, request, getServletContext());
helper.processTemplate(Template.SETUP.toString(), map);
}
protected void doRedirect(HttpServletRequest request, HttpServletResponse response, ResponseValues values)
throws ServletException, IOException {
String redirectUrl = values.getRedirectUrl();
@ -331,12 +326,20 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
return urls;
}
protected BeansWrapper getNonDefaultBeansWrapper(int exposureLevel) {
BeansWrapper wrapper = new DefaultObjectWrapper();
// Too bad exposure levels are ints instead of enum values; what happens if
// we send an int that's not a defined exposure level?
wrapper.setExposureLevel(exposureLevel);
return wrapper;
}
private TemplateModel getStylesheetList(String themeDir) {
// For script and stylesheet lists, use an object wrapper that exposes write methods,
// instead of the configuration's object wrapper, which doesn't. The templates can
// add stylesheets and scripts to the lists by calling their add() methods.
BeansWrapper wrapper = new DefaultObjectWrapper();
BeansWrapper wrapper = getNonDefaultBeansWrapper(BeansWrapper.EXPOSE_SAFE);
try {
// Here themeDir SHOULD NOT have the context path already added to it.
return wrapper.wrap(new Stylesheets(themeDir));
@ -351,7 +354,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
// For script and stylesheet lists, use an object wrapper that exposes write methods,
// instead of the configuration's object wrapper, which doesn't. The templates can
// add stylesheets and scripts to the lists by calling their add() methods.
BeansWrapper wrapper = new DefaultObjectWrapper();
BeansWrapper wrapper = getNonDefaultBeansWrapper(BeansWrapper.EXPOSE_SAFE);
try {
return wrapper.wrap(new Scripts(themeDir));
} catch (TemplateModelException e) {

View file

@ -58,6 +58,7 @@ import edu.cornell.mannlib.vitro.webapp.utils.NamespaceMapperFactory;
import edu.cornell.mannlib.vitro.webapp.web.ContentType;
import edu.cornell.mannlib.vitro.webapp.web.jsptags.StringProcessorTag;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.IndividualTemplateModel;
import freemarker.ext.beans.BeansWrapper;
/**
* Handles requests for entity information.
@ -118,8 +119,14 @@ public class IndividualController extends FreemarkerHttpServlet {
body.put("relatedSubject", getRelatedSubject(vreq));
IndividualTemplateModel ind = getIndividualTemplateModel(vreq, individual);
body.put("individual", ind);
IndividualTemplateModel ind = getIndividualTemplateModel(vreq, individual);
/* We need to expose non-getters in displaying the individual's property list,
* since it requires calls to methods with parameters.
* This is still safe, because we are only putting BaseTemplateModel objects
* into the data model. No real data can be modified.
* RY Not sure this will be needed; postpone.
*/
body.put("individual", ind); //getNonDefaultBeansWrapper(BeansWrapper.EXPOSE_SAFE).wrap(ind));
String template = getIndividualTemplate(individual);

View file

@ -89,6 +89,8 @@ public class SamplesController extends FreemarkerHttpServlet {
body.put("bookTitle", "Pride and Prejudice");
body.put("bookTitle", "Persuasion");
body.put("year", "2001");
body.put("title", "Freemarker Samples");
return new TemplateResponseValues(TEMPLATE_DEFAULT, body);

View file

@ -6,12 +6,19 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openrdf.model.URI;
import org.openrdf.model.impl.URIImpl;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.Portal;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.filters.PortalPickerFilter;
import edu.cornell.mannlib.vitro.webapp.utils.StringUtils;
@ -236,6 +243,31 @@ public class UrlBuilder {
public static String getPath(Route route, ParamMap params) {
return getPath(route.path(), params);
}
public static String getIndividualProfileUrl(Individual individual, WebappDaoFactory wadf) {
String profileUrl = null;
String individualUri = individual.getURI();
URI uri = new URIImpl(individualUri);
String namespace = uri.getNamespace();
String defaultNamespace = wadf.getDefaultNamespace();
String localName = individual.getLocalName();
if (defaultNamespace.equals(namespace)) {
profileUrl = getUrl(Route.INDIVIDUAL.path() + "/" + localName);
} else {
List<String> externallyLinkedNamespaces = wadf.getApplicationDao().getExternallyLinkedNamespaces();
if (externallyLinkedNamespaces.contains(namespace)) {
log.debug("Found externally linked namespace " + namespace);
profileUrl = namespace + "/" + localName;
} else {
ParamMap params = new ParamMap("uri", individualUri);
profileUrl = getUrl("/individual", params);
}
}
return profileUrl;
}
public static String urlEncode(String url) {
String encoding = "ISO-8859-1";

View file

@ -3,6 +3,7 @@
package edu.cornell.mannlib.vitro.webapp.dao;
import java.util.List;
import java.util.Map;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
@ -29,5 +30,5 @@ public interface ObjectPropertyStatementDao {
int insertNewObjectPropertyStatement(ObjectPropertyStatement objPropertyStmt );
public List<ObjectPropertyStatement> getObjectPropertyStatementsForIndividualByProperty(Individual subject, ObjectProperty property, String query);
public List<Map<String, Object>> getObjectPropertyStatementsForIndividualByProperty(String subjectUri, String propertyUri, String query);
}

View file

@ -4,9 +4,9 @@ package edu.cornell.mannlib.vitro.webapp.dao.filtering;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.sf.jga.algorithms.Filter;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
@ -84,9 +84,9 @@ class ObjectPropertyStatementDaoFiltering extends BaseFiltering implements Objec
@Override
// RY What about filtering?
public List<ObjectPropertyStatement> getObjectPropertyStatementsForIndividualByProperty(
Individual subject, ObjectProperty property, String query) {
return innerObjectPropertyStatementDao.getObjectPropertyStatementsForIndividualByProperty(subject, property, query);
public List<Map<String, Object>> getObjectPropertyStatementsForIndividualByProperty(
String subjectUri, String propertyUri, String query) {
return innerObjectPropertyStatementDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, query);
}
}

View file

@ -4,9 +4,13 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
@ -15,7 +19,9 @@ import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.QuerySolutionMap;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.rdf.model.Statement;
@ -32,6 +38,8 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualUpdateEvent;
public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements ObjectPropertyStatementDao {
protected static final Log log = LogFactory.getLog(ObjectPropertyStatementDaoJena.class);
public ObjectPropertyStatementDaoJena(WebappDaoFactoryJena wadf) {
super(wadf);
}
@ -237,9 +245,13 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec
@Override
/*
* SPARQL-based method for getting the individual's values for a single data property.
* SPARQL-based method for getting values related to a single object property.
* We cannot return a List<ObjectPropertyStatement> here, the way the corresponding method of
* DataPropertyStatementDaoJena returns a List<DataPropertyStatement>. We need to accomodate
* custom queries that could request any data in addition to just the object of the statement.
* However, we do need to get the object of the statement so that we have it to create editing links.
*/
public List<ObjectPropertyStatement> getObjectPropertyStatementsForIndividualByProperty(Individual subject, ObjectProperty property, String queryString) {
public List<Map<String, Object>> getObjectPropertyStatementsForIndividualByProperty(String subjectUri, String propertyUri, String queryString) {
log.debug("Object property query string: " + queryString);
@ -250,9 +262,6 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec
log.error("could not create SPARQL query for query string " + th.getMessage());
log.error(queryString);
}
String subjectUri = subject.getURI();
String propertyUri = property.getURI();
QuerySolutionMap bindings = new QuerySolutionMap();
bindings.add("subject", ResourceFactory.createResource(subjectUri));
@ -260,15 +269,44 @@ public class ObjectPropertyStatementDaoJena extends JenaBaseDao implements Objec
// Run the SPARQL query to get the properties
QueryExecution qexec = QueryExecutionFactory.create(query, getOntModelSelector().getFullModel(), bindings);
ResultSet results = qexec.execSelect();
List<ObjectPropertyStatement> statements = new ArrayList<ObjectPropertyStatement>();
return executeQueryToObjectValueCollection(qexec);
}
protected List<Map<String, Object>> executeQueryToObjectValueCollection(
QueryExecution qexec) {
List<Map<String, Object>> rv = new ArrayList<Map<String, Object>>();
ResultSet results = qexec.execSelect();
while (results.hasNext()) {
QuerySolution sol = results.next();
Resource resource = sol.getResource("object");
ObjectPropertyStatement ops = new ObjectPropertyStatementImpl(subjectUri, propertyUri, resource.getURI());
statements.add(ops);
QuerySolution soln = results.nextSolution();
rv.add(querySolutionToObjectValueMap(soln));
}
return rv;
}
protected Map<String,Object> querySolutionToObjectValueMap( QuerySolution soln){
Map<String,Object> map = new HashMap<String,Object>();
Iterator<String> varNames = soln.varNames();
while(varNames.hasNext()){
String varName = varNames.next();
map.put(varName, nodeToObject( soln.get(varName)));
}
return map;
}
protected Object nodeToObject( RDFNode node ){
if( node == null ){
return "";
}else if( node.isLiteral() ){
Literal literal = node.asLiteral();
return literal.getValue();
}else if( node.isURIResource() ){
Resource resource = node.asResource();
return getWebappDaoFactory().getIndividualDao().getIndividualByURI(resource.getURI());
}else if( node.isAnon() ){
Resource resource = node.asResource();
return resource.getId().getLabelString(); //get b-node id
}else{
return "";
}
return statements;
}
}

View file

@ -40,36 +40,9 @@ public class IndividualTemplateModel extends BaseTemplateModel {
}
/* These methods perform some manipulation of the data returned by the Individual methods */
// RY Individiual.getMoniker() was already trying to do this, but due to errors in the code it was not.
// That's fixed now.
// public String getTagline() {
// String tagline = individual.getMoniker();
// return StringUtils.isEmpty(tagline) ? individual.getVClass().getName() : tagline;
// }
public String getProfileUrl() {
String profileUrl = null;
String individualUri = individual.getURI();
URI uri = new URIImpl(individualUri);
String namespace = uri.getNamespace();
WebappDaoFactory wadf = vreq.getWebappDaoFactory();
String defaultNamespace = wadf.getDefaultNamespace();
if (defaultNamespace.equals(namespace)) {
profileUrl = getUrl(PATH + "/" + individual.getLocalName());
} else {
List<String> externallyLinkedNamespaces = wadf.getApplicationDao().getExternallyLinkedNamespaces();
if (externallyLinkedNamespaces.contains(namespace)) {
log.debug("Found externally linked namespace " + namespace);
profileUrl = namespace + "/" + individual.getLocalName();
} else {
ParamMap params = new ParamMap("uri", individualUri);
profileUrl = getUrl("/individual", params);
}
}
return profileUrl;
return UrlBuilder.getIndividualProfileUrl(individual, vreq.getWebappDaoFactory());
}
public String getVisualizationUrl() {

View file

@ -2,29 +2,100 @@
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel;
public class ObjectPropertyStatementTemplateModel extends BaseTemplateModel {
private static final Log log = LogFactory.getLog(ObjectPropertyStatementTemplateModel.class);
private ObjectPropertyStatement statement;
private String subjectUri; // we'll use these to make the edit links
private String propertyUri;
private Map<String, Object> data;
private WebappDaoFactory wdf;
ObjectPropertyStatementTemplateModel(ObjectPropertyStatement statement) {
this.statement = statement;
ObjectPropertyStatementTemplateModel(String subjectUri, String propertyUri, Map<String, Object> data, WebappDaoFactory wdf) {
this.subjectUri = subjectUri;
this.propertyUri = propertyUri;
this.wdf = wdf;
this.data = new HashMap<String, Object>(data.size());
// See comments above StatementIndividual class definition on why we don't just set this.data = data.
for (String key : data.keySet()) {
Object value = data.get(key);
if (value instanceof Individual) {
Individual i = (Individual) value;
this.data.put(key, new StatementObject(i));
} else {
this.data.put(key, value);
}
}
}
/* This is a hopefully temporary solution to account for the fact that in the default
* object property list view we are displaying the object's name and moniker. These
* cannot be derived from a simple sparql query. The name is either the label, localName, or id,
* because context nodes do not have labels. But in general we do not want to display context nodes
* in the property list view; we are only displaying them temporarily until custom list views
* are implemented. In general any object that we want to display in a custom view should have a label,
* and we can get that directly from the sparql query. Note that we can get the localName using an ARQ
* function: PREFIX afn: <http://jena.hpl.hp.com/ARQ/function#>
* SELECT ?object (afn:localname(?object) AS ?localName) ...
* but it is harder (or impossible) to do what the individual.getName() function does in a SPARQL query.
*
* In the case of moniker, the Individual.getMoniker()
* returns the VClass if moniker is null. But moniker is a vitro namespace property which will be
* eliminated in a future version, and the get-vclass-if-no-moniker logic should be moved into the
* display modules where it belongs. In general any information that we would want to display in the custom
* list view should be obtained directly in the sparql query.
*
* We don't want to put an Individual into the template model, because the beans wrapper used in IndividualController
* has exposure level EXPOSE_SAFE, due to the need to call methods with parameters rather than simple parameterless
* getters. We don't want to expose the Individual's setters to the template, so we wrap it in an individual that
* only has getters.
*/
public class StatementObject {
private Individual individual;
StatementObject(Individual individual) {
this.individual = individual;
}
public String getName() {
return individual.getName();
}
public String getMoniker() {
return individual.getMoniker();
}
public String getUrl() {
return UrlBuilder.getIndividualProfileUrl(individual, wdf);
}
}
/* Access methods for templates */
public Individual getObject() {
return statement.getObject();
public Object get(String key) {
return data.get(key);
}
// public IndividualTemplateModel getIndividual(String key) {
// IndividualDao iDao = vreq.getWebappDaoFactory().getIndividualDao();
// Individual individual = iDao.getIndividualByURI(data.get(key));
// return new IndividualTemplateModel(individual, vreq);
// }
public String getEditLink() {
return null;
}

View file

@ -3,6 +3,7 @@
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
import java.io.File;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

View file

@ -79,9 +79,11 @@ public class PropertyListBuilder {
}
// Now do much the same with data properties: get the list of populated data properties, then add in placeholders for missing ones
// If we're going to create a new template model object property with a name,
// don't need to set editLabel, can just do this:
//propertyList.addAll(subject.getPopulatedDataPropertyList());
// rjy7 Currently we are getting the list of properties in one sparql query, then doing a separate query
// to get values for each property. This could be optimized by doing a single query to get a map of properties to
// DataPropertyStatements. Note that this does not apply to object properties, because the queries
// can be customized and thus differ from property to property. So it's easier for now to keep the
// two working in parallel.
List<DataProperty> dataPropertyList = subject.getPopulatedDataPropertyList();
for (DataProperty dp : dataPropertyList) {
dp.setLabel(dp.getPublicName());

View file

@ -4,13 +4,13 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
@ -23,23 +23,21 @@ public class UncollatedObjectPropertyTemplateModel extends ObjectPropertyTemplat
UncollatedObjectPropertyTemplateModel(ObjectProperty op, Individual subject, WebappDaoFactory wdf) {
super(op, subject, wdf);
ObjectPropertyStatementDao opDao = wdf.getObjectPropertyStatementDao();
List<ObjectPropertyStatement> opStatements = opDao.getObjectPropertyStatementsForIndividualByProperty(subject, op, getQueryString());
statements = new ArrayList<ObjectPropertyStatementTemplateModel>();
for (ObjectPropertyStatement ops : opStatements) {
statements.add(new ObjectPropertyStatementTemplateModel(ops));
String subjectUri = subject.getURI();
String propertyUri = op.getURI();
List<Map<String, Object>> statementData = opDao.getObjectPropertyStatementsForIndividualByProperty(subjectUri, propertyUri, getQueryString());
statements = new ArrayList<ObjectPropertyStatementTemplateModel>(statementData.size());
for (Map<String, Object> map : statementData) {
statements.add(new ObjectPropertyStatementTemplateModel(subjectUri, propertyUri, map, wdf));
}
}
/* Access methods for templates */
public List<ObjectPropertyStatementTemplateModel> getStatements() {
return statements;
}
// public List<SubclassList> getStatements() {
// return subclassList;
// }
/* Access methods for templates */
@Override
public boolean isCollatedBySubclass() {
return false;