Java tutorial
/* * Licensed to DuraSpace under one or more contributor license agreements. * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. * * DuraSpace licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fcrepo.apix.jena; import static org.fcrepo.apix.model.Ontologies.RDF_TYPE; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.nio.charset.Charset; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; import org.fcrepo.apix.model.WebResource; import org.fcrepo.apix.model.components.ResourceNotFoundException; import org.apache.commons.io.IOUtils; import org.apache.jena.graph.Node; import org.apache.jena.graph.Triple; import org.apache.jena.query.QueryExecutionFactory; import org.apache.jena.query.QueryFactory; import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.Resource; import org.apache.jena.rdf.model.Statement; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFDataMgr; import org.apache.jena.riot.RDFLanguages; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * RDF utility functions. * * @author apb@jhu.edu */ public abstract class Util { private static final Logger LOG = LoggerFactory.getLogger(Util.class); /** * Parse serialized rdf into a jena Model. * * @param r resource containing serialized rdf * @param base base URI for the purpose of relative URIs * @return The model */ public static Model parse(final WebResource r, final String base) { if (r instanceof JenaResource && ((JenaResource) r).model() != null) { return ((JenaResource) r).model(); } final Model model = ModelFactory.createDefaultModel(); final Lang lang = rdfLanguage(r.contentType()); try (InputStream representation = r.representation()) { RDFDataMgr.read(model, representation, base, lang); } catch (final IOException e) { throw new RuntimeException(e); } return model; } /** * Determine the jena language from a content type string * * @param contentType content type * @return language */ public static final Lang rdfLanguage(final String contentType) { final int separator = contentType.indexOf(';'); if (separator < 0) { return RDFLanguages.contentTypeToLang(contentType); } else { return RDFLanguages.contentTypeToLang(contentType.substring(0, separator)); } } /** * Parse serialized rdf into a jena Model. * <p> * If the resource has a URI, that uri will be used as the base for the purpose of relative URIs. * </p> * * @param r resource containing serialized rdf * @return The model */ public static Model parse(final WebResource r) { return parse(r, r.uri() == null ? "" : r.uri().toString()); } /** * Object resources of triples with the given subject and predicates. * * @param s Subject * @param p Predicate * @param model Model to search in * @return All matching object resources, as URIs. */ public static List<URI> objectResourcesOf(final String s, final String p, final Model model) { return model.listStatements(s != null ? model.getResource(s) : null, model.getProperty(p), (RDFNode) null) .mapWith(Statement::getObject).filterKeep(RDFNode::isURIResource).mapWith(RDFNode::asResource) .mapWith(Resource::getURI).mapWith(URI::create).toList(); } /** * Object literals of triples with the given subject and predicates. * * @param s Subject * @param p Predicate * @param model Model to search in * @return All matching object literals, as strings */ public static List<String> objectLiteralsOf(final String s, final String p, final Model model) { return model.listStatements(s != null ? model.getResource(s) : null, model.getProperty(p), (RDFNode) null) .mapWith(Statement::getObject).filterKeep(RDFNode::isLiteral).mapWith(RDFNode::asLiteral) .mapWith(Literal::getString).toList(); } /** * Single object literal of triples with the given subject and predicates. * * @param s Subject * @param p Predicate * @param model Model to search in * @return matching object literal, or runtime exception if there is more than one match. */ public static String objectLiteralOf(final String s, final String p, final Model model) { return one(s, p, objectLiteralsOf(s, p, model)); } /** * Single object resource of triples with the given subject and predicates. * * @param s Subject * @param p Predicate * @param model Model to search in * @return matching object resource * @throws ResourceNotFoundException if the number of matching resources is not exactly one. */ public static URI objectResourceOf(final String s, final String p, final Model model) { return one(s, p, objectResourcesOf(s, p, model)); } private static <T> T one(final String s, final String p, final List<T> list) { if (list.size() > 1) { throw new ResourceNotFoundException( String.format("Expected number of predicates in <%s>, <%s>, ? to be 0 or 1; encountered %d", s, p, list.size())); } return list.isEmpty() ? null : list.get(0); } /** * Returns true if the given subject is of the given type. * * @param type Type URI * @param subject Subject URI * @param model model to search in * @return True if the subject is the given type. */ public static boolean isA(final String type, final String subject, final Model model) { return objectResourcesOf(subject, RDF_TYPE, model).contains(URI.create(type)); } /** * Produce N-triples string. * * @param s Subject URI * @param p Predicate URI * @param o Object URI * @return N-triples string. */ public static String triple(final String s, final String p, final String o) { return String.format("<%s> <%s> <%s> .\n", s, p, o); } /** * Produce N-triples string. * * @param s Subject URI * @param p Predicate URI * @param o Object literal * @return N-triples string. */ public static String ltriple(final String s, final String p, final String o) { return String.format("<%s> <%s> \"%s\" .\n", s, p, o); } /** * Perform a sparql query against a model. * * @param sparql A sparql CONSTRUCT query * @param model the model * @return Stream of matching triples. */ public static Stream<Triple> query(final String sparql, final Model model) { final Iterable<Triple> i = () -> QueryExecutionFactory.create(QueryFactory.create(sparql), model) .execConstructTriples(); return StreamSupport.stream(i.spliterator(), false); } /** * Find the set of subjects of the given triples. * * @param triples Stream of triples * @return Set of subject URIs. */ public static Set<URI> subjectsOf(final Stream<Triple> triples) { return triples.map(Triple::getSubject).filter(n -> !n.isBlank()).map(Node::getURI).map(URI::create) .collect(Collectors.toSet()); } /** * Get all subjects of statements with the given predicate and object. * * @param p predicate URI * @param o object URI * @param model model to search in * @return list of subjects */ public static List<URI> subjectsOf(final String p, final String o, final Model model) { return model.listSubjectsWithProperty(model.getProperty(p), o != null ? model.getResource(o) : null) .filterKeep(Resource::isURIResource).mapWith(Resource::getURI).mapWith(URI::create).toList(); } /** * Get the singular subject of a statement with the given predicate and object. * * @param p predicate URI * @param o object URI * @param model model to search in * @return the matching URI * @throws ResourceNotFoundException if there is not exactly one match */ public static URI subjectOf(final String p, final String o, final Model model) { final List<URI> subjects = subjectsOf(p, o, model); if (subjects.size() != 1) { throw new ResourceNotFoundException( String.format("Expecting to find exactly one subject of ? <%s> <%s>", p, o)); } return subjects.get(0); } /** * Create an turtle resource from a text stream. * * @param uri URI of the resource * @param rdf String containing n-triples or turtle. * @param name desired resource name; * @return web resource containing the given serialization. */ public static WebResource rdfResource(final String uri, final String rdf, final String name) { return new WebResource() { @Override public void close() throws Exception { // nothing } @Override public URI uri() { return uri != null ? URI.create(uri) : null; } @Override public InputStream representation() { return IOUtils.toInputStream(rdf, Charset.forName("UTF-8")); } @Override public String name() { return name; } @Override public String contentType() { return "text/turtle"; } }; } /** * Create an turtle resource from a text stream. * * @param uri URI of the resource * @param rdf String containing n-triples or turtle. * @return web resource containing the given serialization. */ public static WebResource rdfResource(final String uri, final String rdf) { return rdfResource(uri, rdf, null); } }