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; 038import org.fcrepo.kernel.modeshape.utils.BNodeSkolemizationUtil; 039 040import javax.ws.rs.core.Response; 041import java.io.ByteArrayOutputStream; 042import java.io.IOException; 043import java.net.URI; 044import java.util.HashMap; 045import java.util.Map; 046 047import static java.nio.charset.StandardCharsets.UTF_8; 048import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE; 049import static javax.ws.rs.core.Response.Status.CREATED; 050import static org.apache.jena.graph.NodeFactory.createBlankNode; 051import static org.apache.jena.graph.NodeFactory.createLiteral; 052import static org.junit.Assert.assertEquals; 053import static org.junit.Assert.assertFalse; 054import static org.junit.Assert.assertTrue; 055 056/** 057 * @author cabeer 058 * @author ajs6f 059 */ 060public abstract class AbstractIntegrationRdfIT extends AbstractResourceIT { 061 062 protected HttpResponse createLDPRSAndCheckResponse(final String pid, final String body) { 063 try { 064 final HttpPut httpPut = new HttpPut(serverAddress + pid); 065 httpPut.addHeader("Slug", pid); 066 httpPut.addHeader(CONTENT_TYPE, "text/turtle"); 067 final BasicHttpEntity e = new BasicHttpEntity(); 068 e.setContent(IOUtils.toInputStream(body, UTF_8)); 069 httpPut.setEntity(e); 070 final HttpResponse response = client.execute(httpPut); 071 checkResponse(response, CREATED); 072 073 final String location = response.getFirstHeader("Location").getValue(); 074 075 final HttpGet httpGet = new HttpGet(location); 076 httpGet.addHeader("Prefer", "return=representation; " + 077 "include=\"http://www.w3.org/ns/ldp#PreferMinimalContainer\"; " + 078 "omit=\"http://fedora.info/definitions/v4/repository#ServerManaged\""); 079 final Dataset dataset = getDataset(httpGet); 080 081 final DatasetGraph graphStore = dataset.asDatasetGraph(); 082 assertFalse(graphStore.isEmpty()); 083 084 final Graph tidiedGraph = getTidiedGraph(graphStore); 085 final Model expected = ModelFactory.createDefaultModel().read( 086 IOUtils.toInputStream(body, UTF_8), location, "TTL"); 087 088 final boolean isomorphicWith = tidiedGraph.isIsomorphicWith(getTidiedGraph(expected.getGraph())); 089 090 final String description; 091 092 if (!isomorphicWith) { 093 final ByteArrayOutputStream o = new ByteArrayOutputStream(); 094 095 final Model tidiedModel = ModelFactory.createModelForGraph(tidiedGraph); 096 tidiedModel.setNsPrefixes(expected.getNsPrefixMap()); 097 o.write("Expected: ".getBytes()); 098 RDFDataMgr.write(o, expected, RDFLanguages.TTL); 099 o.write("to be isomorphic with: ".getBytes()); 100 RDFDataMgr.write(o, tidiedModel, RDFLanguages.TTL); 101 description = IOUtils.toString(o.toByteArray(), "UTF-8"); 102 } else { 103 description = ""; 104 } 105 106 107 assertTrue(description, isomorphicWith); 108 109 return response; 110 } catch (final IOException e) { 111 assertTrue("Got IOException " + e, false); 112 return null; 113 } 114 } 115 116 private static Graph getTidiedGraph(final DatasetGraph graph) { 117 return getTidiedGraph(graph.getDefaultGraph()); 118 } 119 120 private static Graph getTidiedGraph(final Graph graph) { 121 final Graph betterGraph = GraphFactory.createDefaultGraph(); 122 final ExtendedIterator<Triple> triples = graph.find(Node.ANY, Node.ANY, Node.ANY); 123 final Map<Node, Node> bnodeMap = new HashMap<>(); 124 125 while (triples.hasNext()) { 126 final Triple next = triples.next(); 127 128 Triple replacement = next; 129 130 if (isSkolemizedBnode(replacement.getSubject())) { 131 if (!bnodeMap.containsKey(replacement.getSubject())) { 132 bnodeMap.put(replacement.getSubject(), createBlankNode()); 133 } 134 135 replacement = new Triple(bnodeMap.get(replacement.getSubject()), 136 replacement.getPredicate(), 137 replacement.getObject()); 138 } 139 140 if (isSkolemizedBnode(replacement.getObject())) { 141 142 if (!bnodeMap.containsKey(replacement.getObject())) { 143 bnodeMap.put(replacement.getObject(), createBlankNode()); 144 } 145 146 replacement = new Triple(replacement.getSubject(), 147 replacement.getPredicate(), 148 bnodeMap.get(replacement.getObject())); 149 } 150 151 if (replacement.getObject().isLiteral() 152 && replacement.getObject().getLiteral().getDatatype() != null 153 && replacement.getObject().getLiteral().getDatatype().equals(XSDDatatype.XSDstring)) { 154 replacement = new Triple(replacement.getSubject(), 155 replacement.getPredicate(), 156 createLiteral(replacement.getObject().getLiteral().getLexicalForm())); 157 } 158 159 betterGraph.add(replacement); 160 } 161 return betterGraph; 162 } 163 164 private static boolean isSkolemizedBnode(final Node node) { 165 if (!node.isURI()) { 166 return false; 167 } 168 169 if (BNodeSkolemizationUtil.isSkolemizeToHashURIs()) { 170 final URI uri = URI.create(node.toString()); 171 return uri.getFragment() != null && uri.getFragment().startsWith("genid"); 172 } else { 173 return node.toString().contains(".well-known"); 174 } 175 } 176 177 protected void checkResponse(final HttpResponse response, final Response.StatusType expected) { 178 final int actual = response.getStatusLine().getStatusCode(); 179 assertEquals("Didn't get a CREATED response!", expected.getStatusCode(), actual); 180 } 181 182 protected String getContentFromClasspath(final String path) throws IOException { 183 return IOUtils.toString(this.getClass().getResourceAsStream(path), UTF_8); 184 } 185 186 187}