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.http.api;
019
020import static java.nio.charset.StandardCharsets.UTF_8;
021import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
022import static javax.ws.rs.core.HttpHeaders.LINK;
023import static javax.ws.rs.core.Response.Status.CREATED;
024import static javax.ws.rs.core.Response.Status.NO_CONTENT;
025import static javax.ws.rs.core.Response.Status.OK;
026import static org.apache.jena.graph.Node.ANY;
027import static org.apache.jena.graph.NodeFactory.createLiteral;
028import static org.apache.jena.graph.NodeFactory.createURI;
029import static org.apache.jena.vocabulary.DC_11.title;
030import static org.fcrepo.kernel.api.RdfLexicon.BASIC_CONTAINER;
031import static org.fcrepo.kernel.api.RdfLexicon.CONTAINER;
032import static org.fcrepo.kernel.api.RdfLexicon.CONTAINS;
033import static org.fcrepo.kernel.api.RdfLexicon.CREATED_DATE;
034import static org.fcrepo.kernel.api.RdfLexicon.DIRECT_CONTAINER;
035import static org.fcrepo.kernel.api.RdfLexicon.EMBED_CONTAINED;
036import static org.fcrepo.kernel.api.RdfLexicon.FEDORA_CONTAINER;
037import static org.fcrepo.kernel.api.RdfLexicon.FEDORA_RESOURCE;
038import static org.fcrepo.kernel.api.RdfLexicon.HAS_MEMBER_RELATION;
039import static org.fcrepo.kernel.api.RdfLexicon.INBOUND_REFERENCES;
040import static org.fcrepo.kernel.api.RdfLexicon.LAST_MODIFIED_DATE;
041import static org.fcrepo.kernel.api.RdfLexicon.LDP_MEMBER;
042import static org.fcrepo.kernel.api.RdfLexicon.MEMBERSHIP_RESOURCE;
043import static org.fcrepo.kernel.api.RdfLexicon.PREFER_CONTAINMENT;
044import static org.fcrepo.kernel.api.RdfLexicon.PREFER_MEMBERSHIP;
045import static org.fcrepo.kernel.api.RdfLexicon.PREFER_MINIMAL_CONTAINER;
046import static org.fcrepo.kernel.api.RdfLexicon.PREFER_SERVER_MANAGED;
047import static org.fcrepo.kernel.api.RdfLexicon.RDF_SOURCE;
048import static org.junit.Assert.assertEquals;
049import static org.junit.Assert.assertFalse;
050import static org.junit.Assert.assertNotEquals;
051import static org.junit.Assert.assertTrue;
052
053import java.io.IOException;
054import java.nio.charset.StandardCharsets;
055import java.util.Collection;
056
057import org.fcrepo.http.commons.test.util.CloseableDataset;
058
059import org.apache.http.client.methods.CloseableHttpResponse;
060import org.apache.http.client.methods.HttpGet;
061import org.apache.http.client.methods.HttpPatch;
062import org.apache.http.client.methods.HttpPost;
063import org.apache.http.client.methods.HttpPut;
064import org.apache.http.client.methods.HttpUriRequest;
065import org.apache.http.entity.StringEntity;
066import org.apache.jena.graph.Node;
067import org.apache.jena.sparql.core.DatasetGraph;
068import org.apache.jena.sparql.core.Quad;
069import org.apache.jena.vocabulary.DC_11;
070import org.junit.Test;
071import org.springframework.test.context.TestExecutionListeners;
072
073/**
074 * Integration tests for various Prefer headers
075 * @author whikloj
076 * @since 6.0.0
077 */
078@TestExecutionListeners(
079        listeners = { TestIsolationExecutionListener.class },
080        mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
081public class PrefersLdpIT extends AbstractResourceIT {
082
083    private String mainResource;
084
085    private Quad userRdfTriple;
086
087    private Quad systemManagedPropertyTriple;
088
089    private Quad membershipTriple;
090
091    private Quad inboundReferenceTriple;
092
093    private Quad containmentTriple;
094
095    private Quad embededTriple;
096
097    /**
098     * Execute a request, test for a CREATED response code and return the location.
099     * @param request the request.
100     * @return the location URI.
101     * @throws Exception on problems with request.
102     */
103    private String createAndGetLocation(final HttpUriRequest request) throws Exception {
104        try (final var response = execute(request)) {
105            assertEquals(CREATED.getStatusCode(), getStatus(response));
106            return getLocation(response);
107        }
108    }
109
110    /**
111     * Generate a quad.
112     * @param subject the subject
113     * @param predicate the predicate
114     * @param object the object
115     * @return the quad
116     */
117    private Quad generateQuad(final String subject, final String predicate, final Node object) {
118        return generateQuad(createURI(subject), predicate, object);
119    }
120
121    /**
122     * Generate a quad.
123     * @param subject the subject
124     * @param predicate the predicate
125     * @param object the object
126     * @return the quad
127     */
128    private Quad generateQuad(final Node subject, final String predicate, final String object) {
129        final Node objectNode = (object == null ? ANY : createURI(object));
130        return generateQuad(subject, predicate, objectNode);
131    }
132
133    /**
134     * Generate a quad.
135     * @param subject the subject
136     * @param predicate the predicate
137     * @param object the object
138     * @return the quad
139     */
140    private Quad generateQuad(final Node subject, final String predicate, final Node object) {
141        return Quad.create(ANY, subject, createURI(predicate), object);
142    }
143
144    /**
145     * Generate a common set of triples for the Prefer header tests.
146     * @throws Exception problems with a http request.
147     */
148    private void generateResources() throws Exception {
149        // Make the main resource to check with a user triple.
150        final var postMain = postObjMethod();
151        final String body = "<> <" + DC_11.title + "> \"The object's title\" .";
152        postMain.setHeader(CONTENT_TYPE, "text/turtle");
153        postMain.setEntity(new StringEntity(body, StandardCharsets.UTF_8));
154        mainResource = createAndGetLocation(postMain);
155        final Node mainNode = createURI(mainResource);
156        userRdfTriple = generateQuad(mainNode, DC_11.title.getURI(), createLiteral("The object's title"));
157        systemManagedPropertyTriple = generateQuad(mainNode, CREATED_DATE.getURI(), ANY);
158        // Make a DirectContainer pointing at the main resource.
159        final var postDC = postObjMethod();
160        postDC.setHeader("Link", "<" + DIRECT_CONTAINER + ">; rel=\"type\"");
161        final String pcdmHasMember = "http://pcdm.org/models#hasMember";
162        final String dcBody =
163                "@prefix ldp: <http://www.w3.org/ns/ldp#> . <> " +
164                        "ldp:membershipResource <" + mainResource + "> ; ldp:hasMemberRelation " +
165                        "<" + pcdmHasMember + "> .";
166        postDC.setHeader(CONTENT_TYPE, "text/turtle");
167        postDC.setEntity(new StringEntity(dcBody, StandardCharsets.UTF_8));
168        final String directResource = createAndGetLocation(postDC);
169        // Make a member of the DC.
170        final var postDCchild = new HttpPost(directResource);
171        final String directResourceReference = createAndGetLocation(postDCchild);
172        membershipTriple = generateQuad(mainNode, pcdmHasMember, directResourceReference);
173        // Make a contained resource.
174        final var postChild = new HttpPost(mainResource);
175        final String childBody = "<> <" + DC_11.title + "> \"The child's title\" .";
176        postChild.setHeader(CONTENT_TYPE, "text/turtle");
177        postChild.setEntity(new StringEntity(childBody, StandardCharsets.UTF_8));
178        final String containedResource = createAndGetLocation(postChild);
179        containmentTriple = generateQuad(mainNode, CONTAINS.getURI(), containedResource);
180        embededTriple = generateQuad(containedResource, DC_11.title.getURI(), createLiteral("The child's title"));
181        // Make an inbound reference.
182        final var otherRef = postObjMethod();
183        final String refBody = "<> <http://example.org/related> <" + mainResource + "> .";
184        otherRef.setHeader(CONTENT_TYPE, "text/turtle");
185        otherRef.setEntity(new StringEntity(refBody, StandardCharsets.UTF_8));
186        final String otherReference = createAndGetLocation(otherRef);
187        inboundReferenceTriple = generateQuad(otherReference, "http://example.org/related", mainNode);
188    }
189
190    @Test
191    public void testNormalTriples() throws Exception {
192        generateResources();
193        final var getReq = new HttpGet(mainResource);
194        try (final var dataset = getDataset(getReq)) {
195            final var graph = dataset.asDatasetGraph();
196            assertTrue(graph.contains(userRdfTriple));
197            assertTrue(graph.contains(systemManagedPropertyTriple));
198            assertTrue(graph.contains(containmentTriple));
199            assertTrue(graph.contains(membershipTriple));
200            assertFalse(graph.contains(inboundReferenceTriple));
201            assertFalse(graph.contains(embededTriple));
202        }
203    }
204
205    @Test
206    public void testPreferIncludeMinimal() throws Exception {
207        generateResources();
208        final var getReq = new HttpGet(mainResource);
209        getReq.setHeader("Prefer", preferLink(PREFER_MINIMAL_CONTAINER.getURI(), null));
210        try (final var dataset = getDataset(getReq)) {
211            final var graph = dataset.asDatasetGraph();
212            assertTrue(graph.contains(userRdfTriple));
213            assertTrue(graph.contains(systemManagedPropertyTriple));
214            assertFalse(graph.contains(containmentTriple));
215            assertFalse(graph.contains(membershipTriple));
216            assertFalse(graph.contains(inboundReferenceTriple));
217            assertFalse(graph.contains(embededTriple));
218        }
219    }
220
221    @Test
222    public void testPreferOmitMinimal() throws Exception {
223        generateResources();
224        final var getReq = new HttpGet(mainResource);
225        getReq.setHeader("Prefer", preferLink(null, PREFER_MINIMAL_CONTAINER.getURI()));
226        try (final var dataset = getDataset(getReq)) {
227            final var graph = dataset.asDatasetGraph();
228            assertFalse(graph.contains(userRdfTriple));
229            assertFalse(graph.contains(systemManagedPropertyTriple));
230            assertTrue(graph.contains(containmentTriple));
231            assertTrue(graph.contains(membershipTriple));
232            assertFalse(graph.contains(inboundReferenceTriple));
233            assertFalse(graph.contains(embededTriple));
234        }
235    }
236
237    @Test
238    public void testPreferIncludeMinimalAndSystem() throws Exception {
239        generateResources();
240        final var getReq = new HttpGet(mainResource);
241        getReq.setHeader("Prefer", preferLink(
242                PREFER_MINIMAL_CONTAINER.getURI() + " " + PREFER_SERVER_MANAGED.getURI(),
243                null));
244        try (final var dataset = getDataset(getReq)) {
245            final var graph = dataset.asDatasetGraph();
246            assertTrue(graph.contains(userRdfTriple));
247            assertTrue(graph.contains(systemManagedPropertyTriple));
248            assertFalse(graph.contains(containmentTriple));
249            assertFalse(graph.contains(membershipTriple));
250            assertFalse(graph.contains(inboundReferenceTriple));
251            assertFalse(graph.contains(embededTriple));
252        }
253    }
254
255    @Test
256    public void testPreferOmitSystem() throws Exception {
257        generateResources();
258        final var getReq = new HttpGet(mainResource);
259        getReq.setHeader("Prefer", preferLink(
260                null,
261                PREFER_SERVER_MANAGED.getURI()));
262        try (final var dataset = getDataset(getReq)) {
263            final var graph = dataset.asDatasetGraph();
264            assertTrue(graph.contains(userRdfTriple));
265            assertFalse(graph.contains(systemManagedPropertyTriple));
266            // Containment is consider system managed.
267            assertFalse(graph.contains(containmentTriple));
268            // Membership is considered system managed.
269            assertFalse(graph.contains(membershipTriple));
270            assertFalse(graph.contains(inboundReferenceTriple));
271            assertFalse(graph.contains(embededTriple));
272        }
273    }
274
275    @Test
276    public void testPreferOmitSystemIncludeContainment() throws Exception {
277        generateResources();
278        final var getReq = new HttpGet(mainResource);
279        getReq.setHeader("Prefer", preferLink(
280                PREFER_CONTAINMENT.getURI(),
281                PREFER_SERVER_MANAGED.getURI()));
282        try (final var dataset = getDataset(getReq)) {
283            final var graph = dataset.asDatasetGraph();
284            assertTrue(graph.contains(userRdfTriple));
285            assertFalse(graph.contains(systemManagedPropertyTriple));
286            assertTrue(graph.contains(containmentTriple));
287            assertFalse(graph.contains(membershipTriple));
288            assertFalse(graph.contains(inboundReferenceTriple));
289            assertFalse(graph.contains(embededTriple));
290        }
291    }
292
293    @Test
294    public void testPreferIncludeMinimalOmitSystem() throws Exception {
295        generateResources();
296        final var getReq = new HttpGet(mainResource);
297        getReq.setHeader("Prefer", preferLink(
298                PREFER_MINIMAL_CONTAINER.getURI(),
299                PREFER_SERVER_MANAGED.getURI()));
300        try (final var dataset = getDataset(getReq)) {
301            final var graph = dataset.asDatasetGraph();
302            assertTrue(graph.contains(userRdfTriple));
303            assertFalse(graph.contains(systemManagedPropertyTriple));
304            assertFalse(graph.contains(containmentTriple));
305            assertFalse(graph.contains(membershipTriple));
306            assertFalse(graph.contains(inboundReferenceTriple));
307            assertFalse(graph.contains(embededTriple));
308        }
309    }
310
311    @Test
312    public void testPreferExcludeMembership() throws Exception {
313        generateResources();
314        final var getReq = new HttpGet(mainResource);
315        getReq.setHeader("Prefer", preferLink(
316                null,
317                PREFER_MEMBERSHIP.getURI()));
318        try (final var dataset = getDataset(getReq)) {
319            final var graph = dataset.asDatasetGraph();
320            assertTrue(graph.contains(userRdfTriple));
321            assertTrue(graph.contains(systemManagedPropertyTriple));
322            assertTrue(graph.contains(containmentTriple));
323            assertFalse(graph.contains(membershipTriple));
324            assertFalse(graph.contains(inboundReferenceTriple));
325            assertFalse(graph.contains(embededTriple));
326        }
327    }
328
329    @Test
330    public void testPreferIncludeInbound() throws Exception {
331        generateResources();
332        final var getReq = new HttpGet(mainResource);
333        getReq.setHeader("Prefer", preferLink(
334                INBOUND_REFERENCES.getURI(),
335                null));
336        try (final var dataset = getDataset(getReq)) {
337            final var graph = dataset.asDatasetGraph();
338            assertTrue(graph.contains(userRdfTriple));
339            assertTrue(graph.contains(systemManagedPropertyTriple));
340            assertTrue(graph.contains(containmentTriple));
341            assertTrue(graph.contains(membershipTriple));
342            assertTrue(graph.contains(inboundReferenceTriple));
343            assertFalse(graph.contains(embededTriple));
344        }
345    }
346
347    @Test
348    public void testPreferIncludeEmbed() throws Exception {
349        generateResources();
350        final var getReq = new HttpGet(mainResource);
351        getReq.setHeader("Prefer", preferLink(
352                EMBED_CONTAINED.getURI(),
353                null));
354        try (final var dataset = getDataset(getReq)) {
355            final var graph = dataset.asDatasetGraph();
356            assertTrue(graph.contains(userRdfTriple));
357            assertTrue(graph.contains(systemManagedPropertyTriple));
358            assertTrue(graph.contains(containmentTriple));
359            assertTrue(graph.contains(membershipTriple));
360            assertFalse(graph.contains(inboundReferenceTriple));
361            assertTrue(graph.contains(embededTriple));
362        }
363    }
364
365    @Test
366    public void testPreferIncludeEmbedInbound_OmitMinimal() throws Exception {
367        generateResources();
368        final var getReq = new HttpGet(mainResource);
369        getReq.setHeader("Prefer", preferLink(
370                EMBED_CONTAINED.getURI() + " " + INBOUND_REFERENCES.getURI(),
371                PREFER_MINIMAL_CONTAINER.getURI()));
372        try (final var dataset = getDataset(getReq)) {
373            final var graph = dataset.asDatasetGraph();
374            assertFalse(graph.contains(userRdfTriple));
375            assertFalse(graph.contains(systemManagedPropertyTriple));
376            assertTrue(graph.contains(containmentTriple));
377            assertTrue(graph.contains(membershipTriple));
378            assertTrue(graph.contains(inboundReferenceTriple));
379            // Omitting minimal removes user rdf, this also happens to the embedded resources.
380            assertFalse(graph.contains(embededTriple));
381        }
382    }
383
384    @Test
385    public void testGetObjectGraphMinimal() throws IOException {
386        final String uri;
387        final HttpPost httpPost = postObjMethod();
388        httpPost.setHeader("Link", BASIC_CONTAINER_LINK_HEADER);
389        httpPost.setHeader(CONTENT_TYPE, "text/turtle");
390        httpPost.setEntity(new StringEntity("<> <" + DCTITLE.getURI() + "> \"The title\" ."));
391        try (final CloseableHttpResponse response = execute(httpPost)) {
392            assertEquals(CREATED.getStatusCode(), getStatus(response));
393            uri = getLocation(response);
394        }
395        final Node resource = createURI(uri);
396        // Create a contained child.
397        final HttpPut httpPut = new HttpPut(uri + "/a");
398        assertEquals(CREATED.getStatusCode(), getStatus(httpPut));
399
400        // Now test with include preference
401        final HttpGet httpGet = new HttpGet(uri);
402        final String preferHeader2 = preferLink(PREFER_MINIMAL_CONTAINER.toString(), null);
403        httpGet.setHeader("Prefer", preferHeader2);
404        try (final CloseableHttpResponse response = execute(httpGet);
405             final CloseableDataset dataset = getDataset(response)) {
406            assertEquals(OK.getStatusCode(), getStatus(response));
407            final DatasetGraph graph = dataset.asDatasetGraph();
408            assertFalse("Didn't expect members", graph.find(ANY, resource, CONTAINS.asNode(), ANY).hasNext());
409            final Collection<String> preferenceApplied = getHeader(response, "Preference-Applied");
410            assertTrue("Preference-Applied header doesn't matched",
411                    preferenceApplied.contains(preferHeader2));
412            assertTrue("Missing a user RDF triple", graph.contains(ANY, resource, DCTITLE, ANY));
413        }
414        // Now try with Omit minimal
415        final HttpGet getOmit = new HttpGet(uri);
416        final String preferOmitHeader = preferLink(null, PREFER_MINIMAL_CONTAINER.toString());
417        getOmit.addHeader("Prefer", preferOmitHeader);
418        try (final CloseableHttpResponse response = execute(getOmit);
419             final CloseableDataset dataset = getDataset(response)) {
420            assertEquals(OK.getStatusCode(), getStatus(response));
421            final DatasetGraph graph = dataset.asDatasetGraph();
422            assertTrue("Expected members", graph.find(ANY, resource, CONTAINS.asNode(), ANY).hasNext());
423            final Collection<String> preferenceApplied = getHeader(response, "Preference-Applied");
424            assertTrue("Preference-Applied header doesn't matched",
425                    preferenceApplied.contains(preferOmitHeader));
426            assertFalse("Should not return user RDF triples", graph.contains(ANY, resource, DCTITLE, ANY));
427        }
428    }
429
430    @Test
431    public void testGetObjectOmitMembership() throws IOException {
432        final String id = getRandomUniqueId();
433        final Node resource = createURI(serverAddress + id);
434        createObjectAndClose(id, BASIC_CONTAINER_LINK_HEADER);
435        final String initialEtag = getEtag(serverAddress + id);
436        createObjectAndClose(id + "/a");
437        final String withChildEtag = getEtag(serverAddress + id);
438        assertNotEquals(initialEtag, withChildEtag);
439        final HttpGet getObjMethod = getObjMethod(id);
440        getObjMethod.addHeader("Prefer", preferLink(null, PREFER_CONTAINMENT + " " + PREFER_MEMBERSHIP));
441        final String omitEtag = getEtag(getObjMethod);
442        assertEquals(initialEtag, omitEtag);
443        assertNotEquals(withChildEtag, omitEtag);
444        try (final CloseableDataset dataset = getDataset(getObjMethod)) {
445            final DatasetGraph graph = dataset.asDatasetGraph();
446            assertTrue("Expected server managed", graph.find(ANY, resource, ANY, CONTAINER.asNode()).hasNext());
447            assertTrue("Expected server managed", graph.find(ANY, resource, ANY, BASIC_CONTAINER.asNode()).hasNext());
448            assertTrue("Expected server managed", graph.find(ANY, resource, ANY, RDF_SOURCE.asNode()).hasNext());
449            assertTrue("Expected server managed", graph.find(ANY, resource, ANY, FEDORA_CONTAINER.asNode()).hasNext());
450            assertTrue("Expected server managed", graph.find(ANY, resource, ANY, FEDORA_RESOURCE.asNode()).hasNext());
451            assertTrue("Expected server managed", graph.find(ANY, resource, CREATED_DATE.asNode(), ANY).hasNext());
452            assertTrue("Expected server managed",
453                    graph.find(ANY, resource, LAST_MODIFIED_DATE.asNode(), ANY).hasNext());
454            assertFalse("Expected no members", graph.find(ANY, resource, CONTAINS.asNode(), ANY).hasNext());
455        }
456    }
457
458    @Test
459    public void testGetObjectOmitContainment() throws IOException {
460        final String id = getRandomUniqueId();
461        createObjectAndClose(id);
462        final String initialEtag = getEtag(serverAddress + id);
463        final String location = serverAddress + id;
464        final String updateString = "<> <" + MEMBERSHIP_RESOURCE.getURI() +
465                "> <" + location + "> ; <" + HAS_MEMBER_RELATION + "> <" + LDP_MEMBER + "> .";
466        final HttpPut put = putObjMethod(id + "/a", "text/turtle", updateString);
467        put.setHeader(LINK, DIRECT_CONTAINER_LINK_HEADER);
468        assertEquals(CREATED.getStatusCode(), getStatus(put));
469        assertTrue(getLinkHeaders(getObjMethod(id + "/a")).contains(DIRECT_CONTAINER_LINK_HEADER));
470        createObject(id + "/a/1");
471
472        final String withMemberEtag = getEtag(serverAddress + id);
473        assertNotEquals(initialEtag, withMemberEtag);
474
475        final HttpGet getObjMethod = getObjMethod(id);
476        getObjMethod.addHeader("Prefer", preferLink(null, PREFER_CONTAINMENT.toString()));
477        final String omitEtag = getEtag(getObjMethod);
478        assertNotEquals("Should not match initial because of membership", initialEtag, omitEtag);
479        assertNotEquals(withMemberEtag, omitEtag);
480        try (final CloseableDataset dataset = getDataset(getObjMethod)) {
481            final DatasetGraph graph = dataset.asDatasetGraph();
482            final Node resource = createURI(serverAddress + id);
483            assertTrue("Didn't find member resources", graph.find(ANY, resource, LDP_MEMBER.asNode(), ANY).hasNext());
484            assertTrue("Expected server managed", graph.find(ANY, resource, ANY, CONTAINER.asNode()).hasNext());
485            assertTrue("Expected server managed", graph.find(ANY, resource, ANY, BASIC_CONTAINER.asNode()).hasNext());
486            assertTrue("Expected server managed", graph.find(ANY, resource, ANY, RDF_SOURCE.asNode()).hasNext());
487            assertTrue("Expected server managed", graph.find(ANY, resource, ANY, FEDORA_CONTAINER.asNode()).hasNext());
488            assertTrue("Expected server managed", graph.find(ANY, resource, ANY, FEDORA_RESOURCE.asNode()).hasNext());
489            assertTrue("Expected server managed", graph.find(ANY, resource, CREATED_DATE.asNode(), ANY).hasNext());
490            assertTrue("Expected server managed",
491                    graph.find(ANY, resource, LAST_MODIFIED_DATE.asNode(), ANY).hasNext());
492            assertFalse("Expected nothing contained", graph.find(ANY, resource, CONTAINS.asNode(), ANY).hasNext());
493        }
494    }
495
496    @Test
497    public void testGetObjectOmitServerManaged() throws IOException {
498        final String id = getRandomUniqueId();
499        createObjectAndClose(id);
500
501        final String location = serverAddress + id;
502        final String updateString = "<> <" + MEMBERSHIP_RESOURCE.getURI() +
503                "> <" + location + "> ; <" + HAS_MEMBER_RELATION + "> <" + LDP_MEMBER + "> .";
504        final HttpPut put = putObjMethod(id + "/a", "text/turtle", updateString);
505        put.setHeader(LINK, DIRECT_CONTAINER_LINK_HEADER);
506        assertEquals(CREATED.getStatusCode(), getStatus(put));
507        assertTrue(getLinkHeaders(getObjMethod(id + "/a")).contains(DIRECT_CONTAINER_LINK_HEADER));
508        createObject(id + "/a/1");
509
510        final String withMemberEtag = getEtag(serverAddress + id);
511
512        final HttpGet getObjMethod = getObjMethod(id);
513        getObjMethod.addHeader("Prefer", preferLink(null, PREFER_SERVER_MANAGED.toString()));
514        assertNotEquals("Etag should not match with SMTs excluded", withMemberEtag, getEtag(getObjMethod));
515        try (final CloseableDataset dataset = getDataset(getObjMethod)) {
516            final DatasetGraph graph = dataset.asDatasetGraph();
517            final Node resource = createURI(serverAddress + id);
518            // Membership is now consider system managed and so is removed with the rest.
519            assertFalse("Didn't find member resources", graph.find(ANY, resource, LDP_MEMBER.asNode(), ANY).hasNext());
520            assertFalse("Expected nothing server managed",
521                    graph.find(ANY, resource, CONTAINS.asNode(), ANY).hasNext());
522            assertFalse("Expected nothing server managed",
523                    graph.find(ANY, resource, ANY, CONTAINER.asNode()).hasNext());
524            assertFalse("Expected nothing server managed",
525                    graph.find(ANY, resource, ANY, BASIC_CONTAINER.asNode()).hasNext());
526            assertFalse("Expected nothing server managed",
527                    graph.find(ANY, resource, ANY, RDF_SOURCE.asNode()).hasNext());
528            assertFalse("Expected nothing server managed",
529                    graph.find(ANY, resource, ANY, FEDORA_CONTAINER.asNode()).hasNext());
530            assertFalse("Expected nothing server managed",
531                    graph.find(ANY, resource, ANY, FEDORA_RESOURCE.asNode()).hasNext());
532            assertFalse("Expected nothing server managed",
533                    graph.find(ANY, resource, CREATED_DATE.asNode(), ANY).hasNext());
534            assertFalse("Expected nothing server managed",
535                    graph.find(ANY, resource, LAST_MODIFIED_DATE.asNode(), ANY).hasNext());
536        }
537    }
538
539    @Test
540    public void testGetObjectIncludeContainmentAndOmitServerManaged() throws IOException {
541        final String id = getRandomUniqueId();
542        createObjectAndClose(id);
543        final String location = serverAddress + id;
544        final String updateString = "<> <" + MEMBERSHIP_RESOURCE.getURI() +
545                "> <" + location + "> ; <" + HAS_MEMBER_RELATION + "> <" + LDP_MEMBER + "> .";
546        final HttpPut put = putObjMethod(id + "/a", "text/turtle", updateString);
547        put.setHeader(LINK, DIRECT_CONTAINER_LINK_HEADER);
548        assertEquals(CREATED.getStatusCode(), getStatus(put));
549        assertTrue(getLinkHeaders(getObjMethod(id + "/a")).contains(DIRECT_CONTAINER_LINK_HEADER));
550        createObject(id + "/a/1");
551
552        final String withMemberEtag = getEtag(serverAddress + id);
553
554        final HttpGet getObjMethod = getObjMethod(id);
555        getObjMethod.addHeader("Prefer", preferLink(PREFER_CONTAINMENT.toString(), PREFER_SERVER_MANAGED.toString()));
556        assertNotEquals("Etag should not match with SMTs excluded", withMemberEtag, getEtag(getObjMethod));
557        try (final CloseableDataset dataset = getDataset(getObjMethod)) {
558            final DatasetGraph graph = dataset.asDatasetGraph();
559            final Node resource = createURI(serverAddress + id);
560            assertTrue("Didn't find ldp containment", graph.find(ANY, resource, CONTAINS.asNode(), ANY).hasNext());
561        }
562    }
563
564    @Test
565    public void testGetLDPRmOmitServerManaged() throws Exception {
566        final String versionedResourceURI = createAndGetLocation(postObjMethod());
567        final String mementoResourceURI = getLocation(new HttpPost(versionedResourceURI + "/fcr:versions"));
568        final String mementoEtag = getEtag(mementoResourceURI);
569
570        final HttpGet mementoGetMethod = new HttpGet(mementoResourceURI);
571        mementoGetMethod.addHeader("Prefer", preferLink(null, PREFER_SERVER_MANAGED.toString()));
572        assertNotEquals(mementoEtag, getEtag(mementoGetMethod));
573        try (final CloseableDataset dataset = getDataset(mementoGetMethod)) {
574            final DatasetGraph graph = dataset.asDatasetGraph();
575            final Node resource = createURI(versionedResourceURI);
576            assertFalse("Expected nothing server managed",
577                    graph.find(ANY, resource, ANY, CONTAINER.asNode()).hasNext());
578            assertFalse("Expected nothing server managed",
579                    graph.find(ANY, resource, ANY, RDF_SOURCE.asNode()).hasNext());
580            assertFalse("Expected nothing server managed",
581                    graph.find(ANY, resource, ANY, FEDORA_CONTAINER.asNode()).hasNext());
582            assertFalse("Expected nothing server managed",
583                    graph.find(ANY, resource, ANY, FEDORA_RESOURCE.asNode()).hasNext());
584            assertFalse("Expected nothing server managed",
585                    graph.find(ANY, resource, CREATED_DATE.asNode(), ANY).hasNext());
586            assertFalse("Expected nothing server managed",
587                    graph.find(ANY, resource, LAST_MODIFIED_DATE.asNode(), ANY).hasNext());
588        }
589    }
590
591    @Test
592    public void testGetLDPRmWithoutOmitServerManager() throws Exception {
593        final String versionedResourceURI = createAndGetLocation(postObjMethod());
594        final String mementoResourceURI = getLocation(new HttpPost(versionedResourceURI + "/fcr:versions"));
595
596        final HttpGet mementoGetMethod = new HttpGet(mementoResourceURI);
597        try (final CloseableDataset dataset = getDataset(mementoGetMethod)) {
598            final DatasetGraph graph = dataset.asDatasetGraph();
599            final Node resource = createURI(versionedResourceURI);
600            assertTrue("Expected server managed",
601                    graph.find(ANY, resource, ANY, CONTAINER.asNode()).hasNext());
602            assertTrue("Expected server managed",
603                    graph.find(ANY, resource, ANY, RDF_SOURCE.asNode()).hasNext());
604            assertTrue("Expected server managed",
605                    graph.find(ANY, resource, ANY, FEDORA_CONTAINER.asNode()).hasNext());
606            assertTrue("Expected server managed",
607                    graph.find(ANY, resource, ANY, FEDORA_RESOURCE.asNode()).hasNext());
608            assertTrue("Expected server managed",
609                    graph.find(ANY, resource, CREATED_DATE.asNode(), ANY).hasNext());
610            assertTrue("Expected server managed",
611                    graph.find(ANY, resource, LAST_MODIFIED_DATE.asNode(), ANY).hasNext());
612        }
613    }
614
615    @Test
616    public void testEmbeddedContainedResources() throws IOException {
617        final String id = getRandomUniqueId();
618        final String binaryId = "binary0";
619        final String preferEmbed = preferLink(EMBED_CONTAINED.toString(), null);
620
621        assertEquals(CREATED.getStatusCode(), getStatus(putObjMethod(id)));
622        assertEquals(CREATED.getStatusCode(), getStatus(putDSMethod(id, binaryId, "some test content")));
623
624        final HttpPatch httpPatch = patchObjMethod(id + "/" + binaryId + "/fcr:metadata");
625        httpPatch.addHeader(CONTENT_TYPE, "application/sparql-update");
626        httpPatch.setEntity(new StringEntity(
627                "INSERT { <> <http://purl.org/dc/elements/1.1/title> 'this is a title' } WHERE {}"));
628        assertEquals(NO_CONTENT.getStatusCode(), getStatus(httpPatch));
629
630        final String withoutEmbedEtag = getEtag(serverAddress + id);
631
632        final HttpGet httpGet = getObjMethod(id);
633        httpGet.setHeader("Prefer", preferEmbed);
634        assertNotEquals(withoutEmbedEtag, getEtag(httpGet));
635        try (final CloseableHttpResponse response = execute(httpGet)) {
636            final Collection<String> preferenceApplied = getHeader(response, "Preference-Applied");
637            assertTrue("Preference-Applied header doesn't match", preferenceApplied.contains(preferEmbed));
638
639            final DatasetGraph graphStore = getDataset(response).asDatasetGraph();
640            assertTrue("Property on child binary should be found!" + graphStore, graphStore.contains(ANY,
641                    createURI(serverAddress + id + "/" + binaryId),
642                    title.asNode(), createLiteral("this is a title")));
643        }
644    }
645
646    @Test
647    public void testEmbeddedContainedResourcesNotToDeep() throws IOException {
648        final String id = getRandomUniqueId();
649        final String level1 = id + "/" + getRandomUniqueId();
650        final String level2 = level1 + "/" + getRandomUniqueId();
651        final String preferEmbed = preferLink(EMBED_CONTAINED.toString(), null);
652
653        assertEquals(CREATED.getStatusCode(), getStatus(putObjMethod(id)));
654
655        final HttpPut putLevel1 = putObjMethod(level1);
656        putLevel1.addHeader(CONTENT_TYPE, "text/turtle");
657        putLevel1.setEntity(new StringEntity("<> <" + title + "> \"First level\"", UTF_8));
658        assertEquals(CREATED.getStatusCode(), getStatus(putLevel1));
659
660        final HttpPut putLevel2 = putObjMethod(level2);
661        putLevel2.addHeader(CONTENT_TYPE, "text/turtle");
662        putLevel2.setEntity(new StringEntity("<> <" + title + "> \"Second level\"", UTF_8));
663        assertEquals(CREATED.getStatusCode(), getStatus(putLevel2));
664
665        final HttpGet httpGet = getObjMethod(id);
666        httpGet.setHeader("Prefer", preferEmbed);
667        try (final CloseableHttpResponse response = execute(httpGet)) {
668            final Collection<String> preferenceApplied = getHeader(response, "Preference-Applied");
669            assertTrue("Preference-Applied header doesn't match", preferenceApplied.contains(preferEmbed));
670
671            final DatasetGraph graphStore = getDataset(response).asDatasetGraph();
672            assertTrue("Property on child binary should be found!" + graphStore, graphStore.contains(ANY,
673                    createURI(serverAddress + level1),
674                    title.asNode(), createLiteral("First level")));
675            assertFalse("Property from embedded resource's own child should not be found.",
676                    graphStore.contains(ANY,
677                            createURI(serverAddress + level2),
678                            title.asNode(), createLiteral("Second level")
679                    )
680            );
681        }
682    }
683}