001/* 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 */ 006package org.fcrepo.integration.rdf; 007 008import org.apache.jena.datatypes.xsd.XSDDatatype; 009import org.apache.jena.graph.Graph; 010import org.apache.jena.graph.Node; 011import org.apache.jena.graph.Triple; 012import org.apache.jena.query.Dataset; 013import org.apache.jena.rdf.model.Model; 014import org.apache.jena.rdf.model.ModelFactory; 015import org.apache.jena.sparql.core.DatasetGraph; 016import org.apache.jena.sparql.graph.GraphFactory; 017import org.apache.jena.util.iterator.ExtendedIterator; 018import org.apache.commons.io.IOUtils; 019import org.apache.http.HttpResponse; 020import org.apache.http.client.methods.HttpGet; 021import org.apache.http.client.methods.HttpPut; 022import org.apache.http.entity.BasicHttpEntity; 023import org.apache.jena.riot.RDFDataMgr; 024import org.apache.jena.riot.RDFLanguages; 025import org.fcrepo.integration.http.api.AbstractResourceIT; 026 027import javax.ws.rs.core.Response; 028import java.io.ByteArrayOutputStream; 029import java.io.IOException; 030import java.net.URI; 031import java.util.HashMap; 032import java.util.Map; 033 034import static java.nio.charset.StandardCharsets.UTF_8; 035import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE; 036import static javax.ws.rs.core.Response.Status.CREATED; 037import static org.apache.jena.graph.NodeFactory.createBlankNode; 038import static org.apache.jena.graph.NodeFactory.createLiteral; 039import static org.junit.Assert.assertEquals; 040import static org.junit.Assert.assertFalse; 041import static org.junit.Assert.assertTrue; 042 043/** 044 * @author cabeer 045 * @author ajs6f 046 */ 047public abstract class AbstractIntegrationRdfIT extends AbstractResourceIT { 048 049 protected HttpResponse createLDPRSAndCheckResponse(final String pid, final String body) { 050 return createLDPRSAndCheckResponse(pid, body, null); 051 } 052 053 protected HttpResponse createLDPRSAndCheckResponse(final String pid, final String body, 054 final Map<String, String> headers) { 055 try { 056 final HttpPut httpPut = new HttpPut(serverAddress + pid); 057 if (headers != null && !headers.isEmpty()) { 058 headers.keySet().stream().forEach(k -> httpPut.addHeader(k, headers.get(k))); 059 } 060 if (httpPut.getFirstHeader(CONTENT_TYPE) == null) { 061 httpPut.addHeader(CONTENT_TYPE, "text/turtle"); 062 } 063 httpPut.setHeader("Slug", pid); 064 final BasicHttpEntity e = new BasicHttpEntity(); 065 e.setContent(IOUtils.toInputStream(body, UTF_8)); 066 httpPut.setEntity(e); 067 final HttpResponse response = client.execute(httpPut); 068 checkResponse(response, CREATED); 069 070 final String location = response.getFirstHeader("Location").getValue(); 071 072 final HttpGet httpGet = new HttpGet(location); 073 httpGet.addHeader("Prefer", "return=representation; " + 074 "include=\"http://www.w3.org/ns/ldp#PreferMinimalContainer\"; " + 075 "omit=\"http://fedora.info/definitions/v4/repository#ServerManaged\""); 076 final Dataset dataset = getDataset(httpGet); 077 078 final DatasetGraph graphStore = dataset.asDatasetGraph(); 079 assertFalse(graphStore.isEmpty()); 080 081 final Graph tidiedGraph = getTidiedGraph(graphStore); 082 final Model expected = ModelFactory.createDefaultModel().read( 083 IOUtils.toInputStream(body, UTF_8), location, "TTL"); 084 085 final boolean isomorphicWith = tidiedGraph.isIsomorphicWith(getTidiedGraph(expected.getGraph())); 086 087 final String description; 088 089 if (!isomorphicWith) { 090 final ByteArrayOutputStream o = new ByteArrayOutputStream(); 091 092 final Model tidiedModel = ModelFactory.createModelForGraph(tidiedGraph); 093 tidiedModel.setNsPrefixes(expected.getNsPrefixMap()); 094 o.write("Expected: ".getBytes()); 095 RDFDataMgr.write(o, expected, RDFLanguages.TTL); 096 o.write("to be isomorphic with: ".getBytes()); 097 RDFDataMgr.write(o, tidiedModel, RDFLanguages.TTL); 098 description = IOUtils.toString(o.toByteArray(), "UTF-8"); 099 } else { 100 description = ""; 101 } 102 103 104 assertTrue(description, isomorphicWith); 105 106 return response; 107 } catch (final IOException e) { 108 assertTrue("Got IOException " + e, false); 109 return null; 110 } 111 } 112 113 private static Graph getTidiedGraph(final DatasetGraph graph) { 114 return getTidiedGraph(graph.getDefaultGraph()); 115 } 116 117 private static Graph getTidiedGraph(final Graph graph) { 118 final Graph betterGraph = GraphFactory.createDefaultGraph(); 119 final ExtendedIterator<Triple> triples = graph.find(Node.ANY, Node.ANY, Node.ANY); 120 final Map<Node, Node> bnodeMap = new HashMap<>(); 121 122 while (triples.hasNext()) { 123 final Triple next = triples.next(); 124 125 Triple replacement = next; 126 127 if (isSkolemizedBnode(replacement.getSubject())) { 128 if (!bnodeMap.containsKey(replacement.getSubject())) { 129 bnodeMap.put(replacement.getSubject(), createBlankNode()); 130 } 131 132 replacement = new Triple(bnodeMap.get(replacement.getSubject()), 133 replacement.getPredicate(), 134 replacement.getObject()); 135 } 136 137 if (isSkolemizedBnode(replacement.getObject())) { 138 139 if (!bnodeMap.containsKey(replacement.getObject())) { 140 bnodeMap.put(replacement.getObject(), createBlankNode()); 141 } 142 143 replacement = new Triple(replacement.getSubject(), 144 replacement.getPredicate(), 145 bnodeMap.get(replacement.getObject())); 146 } 147 148 if (replacement.getObject().isLiteral() 149 && replacement.getObject().getLiteral().getDatatype() != null 150 && replacement.getObject().getLiteral().getDatatype().equals(XSDDatatype.XSDstring)) { 151 replacement = new Triple(replacement.getSubject(), 152 replacement.getPredicate(), 153 createLiteral(replacement.getObject().getLiteral().getLexicalForm())); 154 } 155 156 betterGraph.add(replacement); 157 } 158 return betterGraph; 159 } 160 161 private static boolean isSkolemizedBnode(final Node node) { 162 if (!node.isURI()) { 163 return false; 164 } 165 final URI uri = URI.create(node.toString()); 166 return uri.getFragment() != null && uri.getFragment().startsWith("genid"); 167 } 168 169 protected void checkResponse(final HttpResponse response, final Response.StatusType expected) { 170 final int actual = response.getStatusLine().getStatusCode(); 171 assertEquals("Didn't get a CREATED response!", expected.getStatusCode(), actual); 172 } 173 174 protected String getContentFromClasspath(final String path) throws IOException { 175 return IOUtils.toString(this.getClass().getResourceAsStream(path), UTF_8); 176 } 177 178 179}