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