Java tutorial
/* $This file is distributed under the terms of the license in /doc/license.txt$ */ package edu.cornell.mannlib.vitro.webapp.dao.jena; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.joda.time.DateTime; import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.UnionClass; import com.hp.hpl.jena.query.Dataset; import com.hp.hpl.jena.query.Query; import com.hp.hpl.jena.query.QueryExecution; import com.hp.hpl.jena.query.QueryExecutionFactory; import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.query.QuerySolution; import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.query.ResultSetFactory; import com.hp.hpl.jena.rdf.model.AnonId; 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; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.vocabulary.RDFS; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.jena.IndividualSDB.IndividualNotFoundException; import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactorySDB.SDBDatasetMode; import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; public class IndividualDaoSDB extends IndividualDaoJena { private DatasetWrapperFactory dwf; private SDBDatasetMode datasetMode; private WebappDaoFactorySDB wadf; public IndividualDaoSDB(DatasetWrapperFactory dwf, SDBDatasetMode datasetMode, WebappDaoFactorySDB wadf) { super(wadf); this.dwf = dwf; this.datasetMode = datasetMode; this.wadf = wadf; } protected DatasetWrapper getDatasetWrapper() { return dwf.getDatasetWrapper(); } protected Individual makeIndividual(String individualURI) { try { return new IndividualSDB(individualURI, this.dwf, datasetMode, wadf); } catch (IndividualNotFoundException e) { // If the individual does not exist, return null. return null; } catch (Exception ex) { //Should some other error occur, please log it here log.error("An error occurred trying to make an individual ", ex); if (StringUtils.isNotEmpty(individualURI)) { log.error("IndividualURI equals " + individualURI); } else { log.error("IndividualURI is null or empty"); } return null; } } private static final Log log = LogFactory.getLog(IndividualDaoSDB.class.getName()); @Override protected OntModel getOntModel() { return getOntModelSelector().getABoxModel(); } private static final boolean SKIP_INITIALIZATION = true; @Override public List getIndividualsByVClassURI(String vclassURI, int offset, int quantity) { if (vclassURI == null) { return null; } List<Individual> ents = new ArrayList<Individual>(); Resource theClass = (vclassURI.indexOf(PSEUDO_BNODE_NS) == 0) ? getOntModel().createResource(new AnonId(vclassURI.split("#")[1])) : ResourceFactory.createResource(vclassURI); if (theClass.isAnon() && theClass.canAs(UnionClass.class)) { UnionClass u = theClass.as(UnionClass.class); for (OntClass operand : u.listOperands().toList()) { VClass vc = new VClassJena(operand, getWebappDaoFactory()); ents.addAll(getIndividualsByVClass(vc)); } } else { List<Individual> individualList; // Check if there is a graph filter. // If so, we will use it in a slightly strange way. Unfortunately, // performance is quite bad if we add several graph variables in // order to account for the fact that an individual's type // declaration may be in a different graph from its label. // Thus, we will run two queries: one with a single // graph variable to get the list of URIs, and a second against // the union graph to get individuals with their labels. // We will then toss out any individual in the second // list that is not also in the first list. // Annoying, yes, but better than the alternative. // Note that both queries need to sort identically or // the results may be very strange. String[] graphVars = { "?g" }; String filterStr = WebappDaoFactorySDB.getFilterBlock(graphVars, datasetMode); if (!StringUtils.isEmpty(filterStr)) { List<Individual> graphFilteredIndividualList = getGraphFilteredIndividualList(theClass, filterStr); List<Individual> unfilteredIndividualList = getIndividualList(theClass); Iterator<Individual> unfilteredIt = unfilteredIndividualList.iterator(); for (Individual filt : graphFilteredIndividualList) { Individual unfilt = unfilteredIt.next(); while (!unfilt.getURI().equals(filt.getURI())) { unfilt = unfilteredIt.next(); } ents.add(unfilt); } } else { ents = getIndividualList(theClass); } } java.util.Collections.sort(ents); if (quantity > 0 && offset > 0) { List<Individual> sublist = new ArrayList<Individual>(); for (int i = offset - 1; i < ((offset - 1) + quantity); i++) { sublist.add(ents.get(i)); } return sublist; } return ents; } private List<Individual> getIndividualList(Resource theClass) { List<Individual> ents = new ArrayList<Individual>(); DatasetWrapper w = getDatasetWrapper(); Dataset dataset = w.getDataset(); dataset.getLock().enterCriticalSection(Lock.READ); try { String query = "SELECT DISTINCT ?ind ?label " + "WHERE " + "{ \n" + "{ ?ind a <" + theClass.getURI() + "> } \n" + "UNION { \n" + " ?ind a <" + theClass.getURI() + "> . \n" + " ?ind <" + RDFS.label.getURI() + "> ?label \n" + "} \n" + "} ORDER BY ?ind ?label"; RDFService rdfService = wadf.getRDFService(); InputStream in = null; try { in = rdfService.sparqlSelectQuery(query, RDFService.ResultFormat.JSON); } catch (RDFServiceException e) { log.debug(e, e); throw new RuntimeException(e); } ResultSet rs = ResultSetFactory.fromJSON(in); String uri = null; String label = null; while (rs.hasNext()) { QuerySolution sol = rs.nextSolution(); Resource currRes = sol.getResource("ind"); if (currRes.isAnon()) { continue; } if (uri != null && !uri.equals(currRes.getURI())) { try { ents.add(makeIndividual(uri, label)); } catch (IndividualNotFoundException e) { // don't add } uri = currRes.getURI(); label = null; } else if (uri == null) { uri = currRes.getURI(); } Literal labelLit = sol.getLiteral("label"); if (labelLit != null) { label = labelLit.getLexicalForm(); } if (!rs.hasNext()) { try { ents.add(makeIndividual(uri, label)); } catch (IndividualNotFoundException e) { // don't add } } } } finally { dataset.getLock().leaveCriticalSection(); w.close(); } return ents; } private List<Individual> getGraphFilteredIndividualList(Resource theClass, String filterStr) { List<Individual> filteredIndividualList = new ArrayList<Individual>(); DatasetWrapper w = getDatasetWrapper(); Dataset dataset = w.getDataset(); dataset.getLock().enterCriticalSection(Lock.READ); try { String query = "SELECT DISTINCT ?ind " + "WHERE " + "{ GRAPH ?g { \n" + "{ ?ind a <" + theClass.getURI() + "> } \n" + " } \n" + filterStr + "} ORDER BY ?ind"; RDFService rdfService = wadf.getRDFService(); InputStream in = null; try { in = rdfService.sparqlSelectQuery(query, RDFService.ResultFormat.JSON); } catch (RDFServiceException e) { log.debug(e, e); throw new RuntimeException(e); } ResultSet rs = ResultSetFactory.fromJSON(in); while (rs.hasNext()) { QuerySolution sol = rs.nextSolution(); Resource currRes = sol.getResource("ind"); if (currRes.isAnon()) { continue; } try { filteredIndividualList.add(makeIndividual(currRes.getURI(), null)); } catch (IndividualNotFoundException e) { // don't add } } } finally { dataset.getLock().leaveCriticalSection(); w.close(); } return filteredIndividualList; } private Individual makeIndividual(String uri, String label) throws IndividualNotFoundException { Individual ent = new IndividualSDB(uri, this.dwf, datasetMode, wadf, SKIP_INITIALIZATION); ent.setName(label); ent.setRdfsLabel(label); return ent; } @Override public Individual getIndividualByURI(String entityURI) { if (entityURI == null || entityURI.length() == 0) { return null; } else { return makeIndividual(entityURI); } } /** * fills in the Individual objects needed for any ObjectPropertyStatements * attached to the specified individual. * @param entity */ private void fillIndividualsForObjectPropertyStatements(Individual entity) { getOntModel().enterCriticalSection(Lock.READ); try { Iterator e2eIt = entity.getObjectPropertyStatements().iterator(); while (e2eIt.hasNext()) { ObjectPropertyStatement e2e = (ObjectPropertyStatement) e2eIt.next(); e2e.setSubject(makeIndividual(e2e.getSubjectURI())); e2e.setObject(makeIndividual(e2e.getObjectURI())); } } finally { getOntModel().leaveCriticalSection(); } } /** * In Jena it can be difficult to get an object with a given dataproperty if * you do not care about the datatype or lang of the literal. Use this * method if you would like to ignore the lang and datatype. * * Note: this method doesn't require that a property be declared in the * ontology as a data property -- only that it behaves as one. */ @Override public List<Individual> getIndividualsByDataProperty(String dataPropertyUri, String value) { OntModel fullModel = getOntModelSelector().getFullModel(); Property prop = null; if (RDFS.label.getURI().equals(dataPropertyUri)) { prop = RDFS.label; } else { prop = fullModel.getProperty(dataPropertyUri); } if (prop == null) { log.debug("Could not getIndividualsByDataProperty() " + "because " + dataPropertyUri + "was not found in model."); return Collections.emptyList(); } if (value == null) { log.debug("Could not getIndividualsByDataProperty() " + "because value was null"); return Collections.emptyList(); } Literal litv1 = fullModel.createLiteral(value); Literal litv2 = fullModel.createTypedLiteral(value); //warning: this assumes that any language tags will be EN Literal litv3 = fullModel.createLiteral(value, "EN"); HashMap<String, Individual> individualsMap = new HashMap<String, Individual>(); fullModel.enterCriticalSection(Lock.READ); int count = 0; try { StmtIterator stmts = fullModel.listStatements((Resource) null, prop, litv1); while (stmts.hasNext()) { count++; Statement stmt = stmts.nextStatement(); RDFNode sub = stmt.getSubject(); if (sub == null || sub.isAnon() || sub.isLiteral()) continue; RDFNode obj = stmt.getObject(); if (obj == null || !obj.isLiteral()) continue; Literal literal = (Literal) obj; Object v = literal.getValue(); if (v == null) continue; String subUri = ((Resource) sub).getURI(); if (!individualsMap.containsKey(subUri)) { individualsMap.put(subUri, makeIndividual(subUri)); } } stmts = fullModel.listStatements((Resource) null, prop, litv2); while (stmts.hasNext()) { count++; Statement stmt = stmts.nextStatement(); RDFNode sub = stmt.getSubject(); if (sub == null || sub.isAnon() || sub.isLiteral()) continue; RDFNode obj = stmt.getObject(); if (obj == null || !obj.isLiteral()) continue; Literal literal = (Literal) obj; Object v = literal.getValue(); if (v == null) continue; String subUri = ((Resource) sub).getURI(); if (!individualsMap.containsKey(subUri)) { individualsMap.put(subUri, makeIndividual(subUri)); } } stmts = fullModel.listStatements((Resource) null, prop, litv3); while (stmts.hasNext()) { count++; Statement stmt = stmts.nextStatement(); RDFNode sub = stmt.getSubject(); if (sub == null || sub.isAnon() || sub.isLiteral()) continue; RDFNode obj = stmt.getObject(); if (obj == null || !obj.isLiteral()) continue; Literal literal = (Literal) obj; Object v = literal.getValue(); if (v == null) continue; String subUri = ((Resource) sub).getURI(); if (!individualsMap.containsKey(subUri)) { individualsMap.put(subUri, makeIndividual(subUri)); } } } finally { fullModel.leaveCriticalSection(); } List<Individual> rv = new ArrayList(individualsMap.size()); rv.addAll(individualsMap.values()); return rv; } @Override public Collection<String> getAllIndividualUris() { final List<String> list = new LinkedList<String>(); // get all labeled resources from any non-tbox and non-metadata graphs, // as well as the unnamed graph (first pattern below) String query = "SELECT DISTINCT ?ind WHERE { \n" + " { ?ind <" + RDFS.label.getURI() + "> ?label } " + " UNION { " + " GRAPH ?g { ?ind <" + RDFS.label.getURI() + "> ?label } \n" + " FILTER (?g != <" + ModelNames.APPLICATION_METADATA + "> " + " && !regex(str(?g),\"tbox\")) \n " + " } " + "}"; Query q = QueryFactory.create(query); DatasetWrapper w = getDatasetWrapper(); Dataset dataset = w.getDataset(); dataset.getLock().enterCriticalSection(Lock.READ); QueryExecution qe = QueryExecutionFactory.create(q, dataset); try { ResultSet rs = qe.execSelect(); while (rs.hasNext()) { Resource res = rs.next().getResource("ind"); if (!res.isAnon()) { list.add(res.getURI()); } } } finally { qe.close(); dataset.getLock().leaveCriticalSection(); w.close(); } return list; } private Iterator<Individual> getIndividualIterator(final List<String> individualURIs) { if (individualURIs.size() > 0) { log.info("Number of individuals from source: " + individualURIs.size()); return new Iterator<Individual>() { Iterator<String> innerIt = individualURIs.iterator(); public boolean hasNext() { return innerIt.hasNext(); } public Individual next() { String indURI = innerIt.next(); Individual ind = makeIndividual(indURI); if (ind != null) { return ind; } else { return new IndividualImpl(indURI); } } public void remove() { //not used } }; } else return null; } @Override public Iterator<String> getUpdatedSinceIterator(long updatedSince) { List<String> individualURIs = new ArrayList<String>(); Date since = new DateTime(updatedSince).toDate(); String sinceStr = xsdDateTimeFormat.format(since); getOntModel().enterCriticalSection(Lock.READ); try { String queryStr = "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> " + "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>" + "SELECT ?ent " + "WHERE { " + " ?ent vitro:modTime ?modTime ." + " FILTER (xsd:dateTime(?modTime) >= \"" + sinceStr + "\"^^xsd:dateTime) " + "}"; Query query = QueryFactory.create(queryStr); QueryExecution qe = QueryExecutionFactory.create(query, getOntModel()); try { ResultSet results = qe.execSelect(); while (results.hasNext()) { QuerySolution qs = results.next(); Resource res = (Resource) qs.get("?ent"); if (res.getURI() != null) { individualURIs.add(res.getURI()); } } } finally { qe.close(); } } finally { getOntModel().leaveCriticalSection(); } return individualURIs.iterator(); } }