From 558985d5422a33b8baaf4d1e9973c06f417570ac Mon Sep 17 00:00:00 2001 From: hjkhjk54 Date: Wed, 29 Feb 2012 19:18:07 +0000 Subject: [PATCH] updates for sparql data getter and updates to data getter utils --- .../utils/dataGetter/DataGetterUtils.java | 215 +++++++++++++++++- .../dataGetter/SparqlQueryDataGetter.java | 8 +- .../ontologies/app/menuload/displayTBOX.n3 | 13 +- webapp/web/css/menupage/sparqlresults.css | 13 ++ .../body/menupage/menupage--defaultSparql.ftl | 32 +++ 5 files changed, 274 insertions(+), 7 deletions(-) create mode 100644 webapp/web/css/menupage/sparqlresults.css create mode 100644 webapp/web/templates/freemarker/body/menupage/menupage--defaultSparql.ftl diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtils.java index b5a3c7745..b62e57fd5 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/DataGetterUtils.java @@ -3,12 +3,20 @@ package edu.cornell.mannlib.vitro.webapp.utils.dataGetter; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.net.URLEncoder; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.json.JSONObject; import com.hp.hpl.jena.query.Query; import com.hp.hpl.jena.query.QueryExecution; @@ -17,13 +25,26 @@ 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.Model; +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.shared.Lock; import com.hp.hpl.jena.vocabulary.OWL; +import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.beans.VClass; +import edu.cornell.mannlib.vitro.webapp.controller.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.JsonServlet; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.IndividualListController.PageRecord; import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.utils.pageDataGetter.PageDataGetterUtils; public class DataGetterUtils { @@ -180,13 +201,205 @@ public class DataGetterUtils { } throw new IllegalAccessException("No useful type defined for <" + dataGetterURI + ">"); } - + //Copied from PageDaoJena + static protected String nodeToString( RDFNode node ){ + if( node == null ){ + return ""; + }else if( node.isLiteral() ){ + Literal literal = node.asLiteral(); + return literal.getLexicalForm(); + }else if( node.isURIResource() ){ + Resource resource = node.asResource(); + return resource.getURI(); + }else if( node.isAnon() ){ + Resource resource = node.asResource(); + return resource.getId().getLabelString(); //get b-node id + }else{ + return ""; + } + } + static final String prefixes = "PREFIX rdf: <" + VitroVocabulary.RDF +"> \n" + "PREFIX rdfs: <" + VitroVocabulary.RDFS +"> \n" + "PREFIX xsd: \n" + "PREFIX display: <" + DisplayVocabulary.DISPLAY_NS +"> \n"; + //This query is used in more than one place, so can be placed here + //An alternative is to have individuals for classes data getter extend classgroupdatagetter + //This currently assumes one class group uri per data getter, but this can be extended + /** + * For page data getter conversions + */ + /** + * Get Individual count for Solr query for intersection of multiple classes + */ + public static long getIndividualCountForIntersection(VitroRequest vreq, ServletContext context, List classUris) { + return IndividualListController.getIndividualCount(classUris, vreq.getWebappDaoFactory().getIndividualDao(), context); + } + + //Return data getter type to be employed in display model + public static String generateDataGetterTypeURI(String dataGetterClassName) { + return "java:" + dataGetterClassName; + } + + public static final String getClassGroupForDataGetter(Model displayModel, String dataGetterURI) { + String classGroupUri = null; + QuerySolutionMap initBindings = new QuerySolutionMap(); + initBindings.add("dataGetterURI", ResourceFactory.createResource(dataGetterURI)); + + int count = 0; + //Get the class group + Query dataGetterConfigurationQuery = QueryFactory.create(classGroupForDataGetterQuery) ; + displayModel.enterCriticalSection(Lock.READ); + try{ + QueryExecution qexec = QueryExecutionFactory.create( + dataGetterConfigurationQuery, displayModel, initBindings) ; + ResultSet res = qexec.execSelect(); + try{ + while( res.hasNext() ){ + count++; + QuerySolution soln = res.next(); + + + + //model is OPTIONAL + RDFNode node = soln.getResource("classGroupUri"); + if( node != null && node.isURIResource() ){ + classGroupUri = node.asResource().getURI(); + }else{ + classGroupUri = null; + } + + } + }finally{ qexec.close(); } + }finally{ displayModel.leaveCriticalSection(); } + return classGroupUri; + } + + /** + * Process results related to VClass or vclasses. Handles both single and multiple vclasses being sent. + */ + public static JSONObject processVclassResultsJSON(Map map, VitroRequest vreq, boolean multipleVclasses) { + JSONObject rObj = new JSONObject(); + VClass vclass=null; + + try { + + // Properties from ontologies used by VIVO - should not be in vitro + DataProperty fNameDp = (new DataProperty()); + fNameDp.setURI("http://xmlns.com/foaf/0.1/firstName"); + DataProperty lNameDp = (new DataProperty()); + lNameDp.setURI("http://xmlns.com/foaf/0.1/lastName"); + DataProperty preferredTitleDp = (new DataProperty()); + preferredTitleDp.setURI("http://vivoweb.org/ontology/core#preferredTitle"); + + if( log.isDebugEnabled() ){ + @SuppressWarnings("unchecked") + Enumeration e = vreq.getParameterNames(); + while(e.hasMoreElements()){ + String name = (String)e.nextElement(); + log.debug("parameter: " + name); + for( String value : vreq.getParameterValues(name) ){ + log.debug("value for " + name + ": '" + value + "'"); + } + } + } + + //need an unfiltered dao to get firstnames and lastnames + WebappDaoFactory fullWdf = vreq.getFullWebappDaoFactory(); + + String[] vitroClassIdStr = vreq.getParameterValues("vclassId"); + if ( vitroClassIdStr != null && vitroClassIdStr.length > 0){ + for(String vclassId: vitroClassIdStr) { + vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vclassId); + if (vclass == null) { + log.error("Couldn't retrieve vclass "); + throw new Exception ("Class " + vclassId + " not found"); + } + } + }else{ + log.error("parameter vclassId URI parameter expected "); + throw new Exception("parameter vclassId URI parameter expected "); + } + List vclassIds = Arrays.asList(vitroClassIdStr); + //if single vclass expected, then include vclass. This relates to what the expected behavior is, not size of list + if(!multipleVclasses) { + //currently used for ClassGroupPage + rObj.put("vclass", + new JSONObject().put("URI",vclass.getURI()) + .put("name",vclass.getName())); + } else { + //For now, utilize very last VClass (assume that that is the one to be employed) + //TODO: Find more general way of dealing with this + //put multiple ones in? + if(vclassIds.size() > 0) { + int numberVClasses = vclassIds.size(); + vclass = vreq.getWebappDaoFactory().getVClassDao().getVClassByURI(vclassIds.get(numberVClasses - 1)); + rObj.put("vclass", new JSONObject().put("URI",vclass.getURI()) + .put("name",vclass.getName())); + } + // rObj.put("vclasses", new JSONObject().put("URIs",vitroClassIdStr) + // .put("name",vclass.getName())); + } + if (vclass != null) { + + rObj.put("totalCount", map.get("totalCount")); + rObj.put("alpha", map.get("alpha")); + + List inds = (List)map.get("entities"); + log.debug("Number of individuals returned from request: " + inds.size()); + JSONArray jInds = new JSONArray(); + for(Individual ind : inds ){ + JSONObject jo = new JSONObject(); + jo.put("URI", ind.getURI()); + jo.put("label",ind.getRdfsLabel()); + jo.put("name",ind.getName()); + jo.put("thumbUrl", ind.getThumbUrl()); + jo.put("imageUrl", ind.getImageUrl()); + jo.put("profileUrl", UrlBuilder.getIndividualProfileUrl(ind, vreq)); + + jo.put("mostSpecificTypes", JsonServlet.getMostSpecificTypes(ind,fullWdf)); + jo.put("preferredTitle", JsonServlet.getDataPropertyValue(ind, preferredTitleDp, fullWdf)); + + jInds.put(jo); + } + rObj.put("individuals", jInds); + + JSONArray wpages = new JSONArray(); + //Made sure that PageRecord here is SolrIndividualListController not IndividualListController + List pages = (List)map.get("pages"); + for( PageRecord pr: pages ){ + JSONObject p = new JSONObject(); + p.put("text", pr.text); + p.put("param", pr.param); + p.put("index", pr.index); + wpages.put( p ); + } + rObj.put("pages",wpages); + + JSONArray jletters = new JSONArray(); + List letters = Controllers.getLetters(); + for( String s : letters){ + JSONObject jo = new JSONObject(); + jo.put("text", s); + jo.put("param", "alpha=" + URLEncoder.encode(s, "UTF-8")); + jletters.put( jo ); + } + rObj.put("letters", jletters); + } + } catch(Exception ex) { + log.error("Error occurred in processing JSON object", ex); + } + return rObj; + } + + private static final String forClassGroupURI = "<" + DisplayVocabulary.FOR_CLASSGROUP + ">"; + private static final String classGroupForDataGetterQuery = + "PREFIX display: <" + DisplayVocabulary.DISPLAY_NS +"> \n" + + "SELECT ?classGroupUri WHERE { \n" + + " ?dataGetterUri "+forClassGroupURI+" ?classGroupUri . \n" + + "}"; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java index 880de90ba..4a31d0dd8 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/utils/dataGetter/SparqlQueryDataGetter.java @@ -206,14 +206,14 @@ public class SparqlQueryDataGetter extends DataGetterBase implements DataGetter{ public static final String defaultVarNameForResults = "results"; /** - * Query to get the definition of the SparqlDataGetter for a given URI. + * Query to get the definition of the SparqlDataGetter for a given data getter URI. */ private static final String dataGetterQuery = "PREFIX display: <" + DisplayVocabulary.DISPLAY_NS +"> \n" + "SELECT ?query ?saveToVar ?model WHERE { \n" + - " ?pageUri "+queryPropertyURI+" ?query . \n" + - " OPTIONAL{ ?pageUri "+saveToVarPropertyURI+" ?saveToVar } \n " + - " OPTIONAL{ ?pageUri "+queryModelPropertyURI+" ?queryModel } \n" + + " ?dataGetterUri "+queryPropertyURI+" ?query . \n" + + " OPTIONAL{ ?dataGetterUri "+saveToVarPropertyURI+" ?saveToVar } \n " + + " OPTIONAL{ ?dataGetterUri "+queryModelPropertyURI+" ?model } \n" + "}"; diff --git a/webapp/web/WEB-INF/ontologies/app/menuload/displayTBOX.n3 b/webapp/web/WEB-INF/ontologies/app/menuload/displayTBOX.n3 index 14d647f80..3edde1625 100644 --- a/webapp/web/WEB-INF/ontologies/app/menuload/displayTBOX.n3 +++ b/webapp/web/WEB-INF/ontologies/app/menuload/displayTBOX.n3 @@ -102,7 +102,13 @@ owl:versionInfo a owl:DatatypeProperty . - +###Custom data getters that may or may not be associated with a page use the following relationships +###E.g. sparql data getters can specify the query to be used as well as what variable in the template +###should store the results + + a owl:DatatypeProperty . + + a owl:DatatypeProperty . ######### Object Properties######### ###Basic rdfs:range @@ -173,4 +179,7 @@ owl:topObjectProperty a owl:ObjectProperty . - +###Custom data getters that may or may not be associated with a page use the following relationships +###E.g. sparql data getters can specify what model to use for querying + + a owl:ObjectProperty . diff --git a/webapp/web/css/menupage/sparqlresults.css b/webapp/web/css/menupage/sparqlresults.css new file mode 100644 index 000000000..e402134dd --- /dev/null +++ b/webapp/web/css/menupage/sparqlresults.css @@ -0,0 +1,13 @@ +.resultRow { +float:none; +clear:both; +} + +.resultCell { +float:left; +border:1px solid #000000; +} + +.resultHeading { +font-weight:bold; +} \ No newline at end of file diff --git a/webapp/web/templates/freemarker/body/menupage/menupage--defaultSparql.ftl b/webapp/web/templates/freemarker/body/menupage/menupage--defaultSparql.ftl new file mode 100644 index 000000000..aab9ca6bb --- /dev/null +++ b/webapp/web/templates/freemarker/body/menupage/menupage--defaultSparql.ftl @@ -0,0 +1,32 @@ +<#--Save to variable is sparqlResults --> +<#assign resultsExist = false/> +<#if sparqlResults?has_content> + <#assign resultsExist = true/> + + +

Sparql Query Results

+<#if resultsExist> + <#assign numberRows = sparqlResults?size/> + <#assign firstRow = false/> + <#list sparqlResults as resultRow> + <#assign resultKeys = resultRow?keys /> + <#if firstRow = false> +
+ <#list resultKeys as resultKey> +
${resultKey}
+ +
+ <#assign firstRow = true/> + +
+ <#list resultKeys as resultKey> +
${resultRow[resultKey]}
+ +
+ +<#else> + No results were returned. + + +${stylesheets.add('')} +