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