Skip to content

Commit ae36140

Browse files
committed
Ensure that LDP type triples are not duplicated
Resolves #619
1 parent f691354 commit ae36140

File tree

12 files changed

+87
-43
lines changed

12 files changed

+87
-43
lines changed

components/file/src/main/java/org/trellisldp/file/FileResource.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static java.util.stream.Stream.empty;
2121
import static org.slf4j.LoggerFactory.getLogger;
2222
import static org.trellisldp.vocabulary.RDF.type;
23+
import static org.trellisldp.vocabulary.Trellis.PreferServerManaged;
2324

2425
import java.io.File;
2526
import java.io.IOException;
@@ -118,7 +119,7 @@ public boolean hasAcl() {
118119

119120
@Override
120121
public Stream<Quad> stream() {
121-
return fetchContent(identifier, file);
122+
return fetchContent(identifier, file).filter(FileUtils::filterServerManagedQuads);
122123
}
123124

124125
private Optional<IRI> asIRI(final IRI predicate) {
@@ -132,7 +133,7 @@ private Optional<String> asLiteral(final IRI predicate) {
132133

133134
private static Map<IRI, RDFTerm> init(final IRI identifier, final File file) {
134135
try (final Stream<Triple> triples = fetchContent(identifier, file).filter(q ->
135-
q.getGraphName().filter(isEqual(Trellis.PreferServerManaged)).isPresent()).map(Quad::asTriple)) {
136+
q.getGraphName().filter(isEqual(PreferServerManaged)).isPresent()).map(Quad::asTriple)) {
136137
return triples.collect(toMap(t -> !t.getSubject().equals(identifier) && DC.modified.equals(t.getPredicate())
137138
? Time.hasTime : t.getPredicate(), Triple::getObject));
138139
}

components/file/src/main/java/org/trellisldp/file/FileUtils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import static org.apache.jena.riot.tokens.TokenizerFactory.makeTokenizerString;
3131
import static org.apache.jena.sparql.core.Quad.create;
3232
import static org.apache.jena.sparql.core.Quad.defaultGraphIRI;
33+
import static org.eclipse.microprofile.config.ConfigProvider.getConfig;
3334
import static org.slf4j.LoggerFactory.getLogger;
3435
import static org.trellisldp.vocabulary.RDF.type;
3536
import static org.trellisldp.vocabulary.Trellis.PreferServerManaged;
@@ -46,6 +47,7 @@
4647
import java.util.Iterator;
4748
import java.util.List;
4849
import java.util.Objects;
50+
import java.util.Optional;
4951
import java.util.StringJoiner;
5052
import java.util.stream.Stream;
5153
import java.util.zip.CRC32;
@@ -67,6 +69,8 @@
6769
*/
6870
public final class FileUtils {
6971

72+
/** The configuration key for controlling LDP type triples. */
73+
public static final String CONFIG_FILE_LDP_TYPE = "trellis.file.ldp-type";
7074
private static final Logger LOGGER = getLogger(FileUtils.class);
7175
private static final JenaRDF rdf = new JenaRDF();
7276
private static final String SEP = " ";
@@ -121,6 +125,19 @@ public static Stream<Quad> parseQuad(final String line) {
121125
}
122126
}
123127

128+
/**
129+
* Filter any server-managed triples from the resource stream.
130+
* @param quad the quad
131+
* @return true if the quad should be kept, false otherwise
132+
*/
133+
public static boolean filterServerManagedQuads(final Quad quad) {
134+
if (quad.getGraphName().equals(Optional.of(PreferServerManaged))) {
135+
return quad.getPredicate().equals(type) && getConfig()
136+
.getOptionalValue(CONFIG_FILE_LDP_TYPE, Boolean.class).orElse(Boolean.TRUE);
137+
}
138+
return true;
139+
}
140+
124141
/**
125142
* Try to delete a file if it exists or throw an unchecked exception.
126143
* @param path the file path

components/file/src/test/java/org/trellisldp/file/FileResourceTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ void testResource() {
5555
assertFalse(res.getContainer().isPresent(), "Unexpected parent resource!");
5656
assertEquals(3L, res.stream(LDP.PreferContainment).count(), "Incorrect containment count!");
5757
assertEquals(3L, res.stream(Trellis.PreferUserManaged).count(), "Incorrect user triple count!");
58-
assertEquals(2L, res.stream(Trellis.PreferServerManaged).count(), "Incorrect server managed count!");
59-
assertEquals(8L, res.stream().count(), "Incorrect total triple count!");
58+
assertEquals(1L, res.stream(Trellis.PreferServerManaged).count(), "Incorrect server managed count!");
59+
assertEquals(7L, res.stream().count(), "Incorrect total triple count!");
6060
}
6161

6262
@Test
@@ -82,8 +82,8 @@ void testBinary() {
8282
assertFalse(res.hasAcl(), "Unexpected ACL present!");
8383
assertEquals(0L, res.stream(LDP.PreferContainment).count(), "Incorrect containment triple count!");
8484
assertEquals(2L, res.stream(Trellis.PreferUserManaged).count(), "Incorrect user triple count!");
85-
assertEquals(6L, res.stream(Trellis.PreferServerManaged).count(), "Incorrect server managed count!");
86-
assertEquals(8L, res.stream().count(), "Incorrect total triple count!");
85+
assertEquals(1L, res.stream(Trellis.PreferServerManaged).count(), "Incorrect server managed count!");
86+
assertEquals(3L, res.stream().count(), "Incorrect total triple count!");
8787
}
8888

8989
@Test
@@ -121,8 +121,8 @@ void testIndirectContainer() {
121121
assertFalse(res.hasAcl(), "Unexpected ACL!");
122122
assertEquals(3L, res.stream(LDP.PreferContainment).count(), "Incorrect containment triple count!");
123123
assertEquals(6L, res.stream(Trellis.PreferUserManaged).count(), "Incorrect user triple count!");
124-
assertEquals(5L, res.stream(Trellis.PreferServerManaged).count(), "Incorrect server triple count!");
125-
assertEquals(14L, res.stream().count(), "Incorrect total triple count!");
124+
assertEquals(1L, res.stream(Trellis.PreferServerManaged).count(), "Incorrect server triple count!");
125+
assertEquals(10L, res.stream().count(), "Incorrect total triple count!");
126126
}
127127

128128
@Test
@@ -146,7 +146,7 @@ void testDirectContainer() {
146146
assertFalse(res.hasAcl(), "Unexpected ACL!");
147147
assertEquals(3L, res.stream(LDP.PreferContainment).count(), "Incorrect containment triple count!");
148148
assertEquals(5L, res.stream(Trellis.PreferUserManaged).count(), "Incorrect user triple count!");
149-
assertEquals(4L, res.stream(Trellis.PreferServerManaged).count(), "Incorrect server triple count!");
150-
assertEquals(12L, res.stream().count(), "Incorrect total triple count!");
149+
assertEquals(1L, res.stream(Trellis.PreferServerManaged).count(), "Incorrect server triple count!");
150+
assertEquals(9L, res.stream().count(), "Incorrect total triple count!");
151151
}
152152
}

components/file/src/test/java/org/trellisldp/file/FileUtilsTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static org.junit.jupiter.api.Assertions.*;
1818
import static org.mockito.Mockito.mock;
1919
import static org.trellisldp.api.TrellisUtils.TRELLIS_DATA_PREFIX;
20+
import static org.trellisldp.vocabulary.RDF.type;
2021

2122
import java.io.File;
2223
import java.io.IOException;
@@ -33,6 +34,7 @@
3334
import org.junit.jupiter.api.Test;
3435
import org.trellisldp.api.Resource;
3536
import org.trellisldp.vocabulary.DC;
37+
import org.trellisldp.vocabulary.LDP;
3638
import org.trellisldp.vocabulary.Trellis;
3739

3840
/**
@@ -142,4 +144,16 @@ void testWriteMementoBadDirectory() {
142144

143145
assertThrows(UncheckedIOException.class, () -> FileUtils.writeMemento(dir, res, now()));
144146
}
147+
148+
@Test
149+
void testFilterServerManaged() {
150+
final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + "resource");
151+
try {
152+
System.setProperty(FileUtils.CONFIG_FILE_LDP_TYPE, "false");
153+
assertFalse(FileUtils.filterServerManagedQuads(rdf.createQuad(Trellis.PreferServerManaged,
154+
identifier, type, LDP.Container)));
155+
} finally {
156+
System.clearProperty(FileUtils.CONFIG_FILE_LDP_TYPE);
157+
}
158+
}
145159
}

components/triplestore/src/main/java/org/trellisldp/triplestore/TriplestoreResource.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public TriplestoreResource(final RDFConnection rdfConnection, final IRI identifi
9595
this.rdfConnection = rdfConnection;
9696
this.includeLdpType = includeLdpType;
9797
graphMapper.put(Trellis.PreferUserManaged, this::fetchUserQuads);
98+
graphMapper.put(Trellis.PreferServerManaged, this::fetchServerQuads);
9899
graphMapper.put(Trellis.PreferAudit, this::fetchAuditQuads);
99100
graphMapper.put(Trellis.PreferAccessControl, this::fetchAclQuads);
100101
graphMapper.put(LDP.PreferContainment, this::fetchContainmentQuads);
@@ -504,13 +505,16 @@ private Stream<Quad> fetchContainmentQuads() {
504505
* </code></pre>
505506
*/
506507
private Stream<Quad> fetchUserQuads() {
508+
return fetchAllFromGraph(identifier.getIRIString(), Trellis.PreferUserManaged);
509+
}
510+
511+
private Stream<Quad> fetchServerQuads() {
507512
if (includeLdpType) {
508513
final IRI ixnModel = getInteractionModel();
509-
return concat(of(rdf.createQuad(Trellis.PreferUserManaged, adjustIdentifier(identifier, ixnModel),
510-
RDF.type, ixnModel)),
511-
fetchAllFromGraph(identifier.getIRIString(), Trellis.PreferUserManaged));
514+
return of(rdf.createQuad(Trellis.PreferServerManaged, adjustIdentifier(identifier, ixnModel),
515+
RDF.type, ixnModel));
512516
}
513-
return fetchAllFromGraph(identifier.getIRIString(), Trellis.PreferUserManaged);
517+
return Stream.empty();
514518
}
515519

516520
private static IRI adjustIdentifier(final IRI identifier, final IRI type) {

components/triplestore/src/test/java/org/trellisldp/triplestore/TriplestoreResourceServiceTest.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,10 +1364,12 @@ private static Stream<Executable> checkBinary(final Resource res, final IRI iden
13641364

13651365
private static Stream<Executable> checkResourceStream(final Resource res, final long userManaged,
13661366
final long accessControl, final long audit, final long membership, final long containment) {
1367-
final long ldpTriples = 1;
1368-
final long total = userManaged + accessControl + audit + membership + containment + ldpTriples;
1367+
final long serverManaged = 1; // LDP type triple
1368+
final long total = userManaged + accessControl + audit + membership + containment + serverManaged;
13691369
return Stream.of(
1370-
() -> assertEquals(userManaged + ldpTriples, res.stream(Trellis.PreferUserManaged).count(),
1370+
() -> assertEquals(serverManaged, res.stream(Trellis.PreferServerManaged).count(),
1371+
"Incorrect server triple count!"),
1372+
() -> assertEquals(userManaged, res.stream(Trellis.PreferUserManaged).count(),
13711373
"Incorrect user triple count!"),
13721374
() -> assertEquals(accessControl, res.stream(Trellis.PreferAccessControl).count(),
13731375
"Incorrect ACL triple count!"),

components/triplestore/src/test/java/org/trellisldp/triplestore/TriplestoreResourceTest.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ void testMinimalResource() {
113113
assertTrue(res.exists(), "Missing resource!");
114114
assertAll("Check resource", checkResource(res, identifier, LDP.RDFSource, false, false, false));
115115
assertAll("Check LDP properties", checkLdpProperties(res, null, null, null, null));
116-
assertAll("Check RDF stream", checkRdfStream(res, 2L, 0L, 0L, 0L, 0L));
116+
assertAll("Check RDF stream", checkRdfStream(res, 2L, 0L, 0L, 0L, 0L, 0L));
117117
}
118118

119119
@Test
@@ -128,7 +128,7 @@ void testResourceWithAuditQuads() {
128128
assertTrue(res.exists(), "Missing resource!");
129129
assertAll("Check resource", checkResource(res, identifier, LDP.RDFSource, false, false, false));
130130
assertAll("Check LDP properties", checkLdpProperties(res, null, null, null, null));
131-
assertAll("Check RDF stream", checkRdfStream(res, 2L, 0L, 5L, 0L, 0L));
131+
assertAll("Check RDF stream", checkRdfStream(res, 2L, 0L, 0L, 5L, 0L, 0L));
132132
}
133133

134134
@Test
@@ -143,7 +143,7 @@ void testResourceWithAuditQuads2() {
143143
assertTrue(res.exists(), "Missing resource!");
144144
assertAll("Check resource", checkResource(res, identifier, LDP.RDFSource, false, false, false));
145145
assertAll("Check LDP properties", checkLdpProperties(res, null, null, null, null));
146-
assertAll("Check RDF stream", checkRdfStream(res, 3L, 0L, 5L, 0L, 0L));
146+
assertAll("Check RDF stream", checkRdfStream(res, 2L, 1L, 0L, 5L, 0L, 0L));
147147
}
148148

149149
@Test
@@ -161,7 +161,7 @@ void testResourceWithAclQuads() {
161161
assertTrue(res.exists(), "Missing resource!");
162162
assertAll("Check resource", checkResource(res, identifier, LDP.RDFSource, false, true, false));
163163
assertAll("Check LDP properties", checkLdpProperties(res, null, null, null, null));
164-
assertAll("Check RDF stream", checkRdfStream(res, 2L, 3L, 5L, 0L, 0L));
164+
assertAll("Check RDF stream", checkRdfStream(res, 2L, 0L, 3L, 5L, 0L, 0L));
165165
}
166166

167167
@Test
@@ -185,7 +185,7 @@ void testBinaryResource() {
185185
});
186186
assertAll("Check resource", checkResource(res, identifier, LDP.NonRDFSource, true, false, false));
187187
assertAll("Check LDP properties", checkLdpProperties(res, null, null, null, null));
188-
assertAll("Check RDF stream", checkRdfStream(res, 3L, 0L, 5L, 0L, 0L));
188+
assertAll("Check RDF stream", checkRdfStream(res, 2L, 1L, 0L, 5L, 0L, 0L));
189189
}
190190

191191
@Test
@@ -204,7 +204,7 @@ void testResourceWithChildren() {
204204
assertTrue(res.exists(), "Missing resource!");
205205
assertAll("Check resource", checkResource(res, identifier, LDP.Container, false, false, true));
206206
assertAll("Check LDP properties", checkLdpProperties(res, null, null, null, null));
207-
assertAll("Check RDF stream", checkRdfStream(res, 2L, 0L, 0L, 0L, 4L));
207+
assertAll("Check RDF stream", checkRdfStream(res, 2L, 0L, 0L, 0L, 0L, 4L));
208208
}
209209

210210
@Test
@@ -219,7 +219,7 @@ void testResourceWithoutChildren() {
219219
assertTrue(res.exists(), "Missing resource!");
220220
assertAll("Check resource", checkResource(res, identifier, LDP.RDFSource, false, false, true));
221221
assertAll("Check LDP properties", checkLdpProperties(res, null, null, null, null));
222-
assertAll("Check RDF stream", checkRdfStream(res, 3L, 0L, 0L, 0L, 0L));
222+
assertAll("Check RDF stream", checkRdfStream(res, 2L, 1L, 0L, 0L, 0L, 0L));
223223
}
224224

225225
@Test
@@ -243,14 +243,14 @@ void testDirectContainer() {
243243
assertTrue(res.exists(), "Missing resource!");
244244
assertAll("Check resource", checkResource(res, identifier, LDP.DirectContainer, false, false, true));
245245
assertAll("Check LDP properties", checkLdpProperties(res, member, DC.subject, null, LDP.MemberSubject));
246-
assertAll("Check RDF stream", checkRdfStream(res, 3L, 0L, 0L, 0L, 4L));
246+
assertAll("Check RDF stream", checkRdfStream(res, 2L, 1L, 0L, 0L, 0L, 4L));
247247

248248
final TriplestoreResource memberRes = new TriplestoreResource(rdfConnection, member, false);
249249
memberRes.fetchData();
250250
assertTrue(memberRes.exists(), "Missing resource!");
251251
assertAll("Check resource", checkResource(memberRes, member, LDP.RDFSource, false, false, true));
252252
assertAll("Check LDP properties", checkLdpProperties(memberRes, null, null, null, null));
253-
assertAll("Check RDF stream", checkRdfStream(memberRes, 1L, 0L, 0L, 4L, 0L));
253+
assertAll("Check RDF stream", checkRdfStream(memberRes, 1L, 0L, 0L, 0L, 4L, 0L));
254254
assertEquals(4L, memberRes.stream(singleton(LDP.PreferMembership)).map(Quad::getPredicate)
255255
.filter(isEqual(DC.subject)).count(), "Incorrect triple count!");
256256

@@ -280,14 +280,14 @@ void testIndirectContainer() {
280280
assertTrue(res.exists(), "Missing resource!");
281281
assertAll("Check resource", checkResource(res, identifier, LDP.IndirectContainer, false, false, true));
282282
assertAll("Check LDP properties", checkLdpProperties(res, member, DC.relation, null, DC.subject));
283-
assertAll("Check RDF stream", checkRdfStream(res, 3L, 0L, 0L, 0L, 4L));
283+
assertAll("Check RDF stream", checkRdfStream(res, 3L, 0L, 0L, 0L, 0L, 4L));
284284

285285
final TriplestoreResource res2 = new TriplestoreResource(rdfConnection, member, false);
286286
res2.fetchData();
287287
assertTrue(res2.exists(), "Missing resource (2)!");
288288
assertAll("Check resource", checkResource(res2, member, LDP.RDFSource, false, false, true));
289289
assertAll("Check LDP properties", checkLdpProperties(res2, null, null, null, null));
290-
assertAll("Check RDF stream", checkRdfStream(res2, 2L, 0L, 0L, 4L, 0L));
290+
assertAll("Check RDF stream", checkRdfStream(res2, 2L, 0L, 0L, 0L, 4L, 0L));
291291
assertEquals(4L, res2.stream(singleton(LDP.PreferMembership)).map(Quad::getPredicate)
292292
.filter(isEqual(DC.relation)).count(), "Incorrect triple count!");
293293

@@ -344,9 +344,11 @@ private static Stream<Executable> checkLdpProperties(final Resource res, final I
344344
}
345345

346346
private static Stream<Executable> checkRdfStream(final Resource res, final long userManaged,
347-
final long acl, final long audit, final long membership, final long containment) {
348-
final long total = userManaged + acl + audit + membership + containment;
347+
final long serverManaged, final long acl, final long audit, final long membership, final long containment) {
348+
final long total = userManaged + acl + audit + membership + containment + serverManaged;
349349
return Stream.of(
350+
() -> assertEquals(serverManaged, res.stream(singleton(Trellis.PreferServerManaged)).count(),
351+
"Incorrect server managed triple count!"),
350352
() -> assertEquals(userManaged, res.stream(singleton(Trellis.PreferUserManaged)).count(),
351353
"Incorrect user managed triple count!"),
352354
() -> assertEquals(acl, res.stream(singleton(Trellis.PreferAccessControl)).count(),

core/http/src/main/java/org/trellisldp/http/core/HttpConstants.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static java.util.Collections.unmodifiableSet;
1818
import static org.trellisldp.vocabulary.LDP.PreferContainment;
1919
import static org.trellisldp.vocabulary.LDP.PreferMembership;
20+
import static org.trellisldp.vocabulary.Trellis.PreferServerManaged;
2021
import static org.trellisldp.vocabulary.Trellis.PreferUserManaged;
2122

2223
import java.util.HashSet;
@@ -127,7 +128,8 @@ public final class HttpConstants {
127128
private static final Set<IRI> DEFAULT_REPRESENTATION_ELEMENTS = new HashSet<>();
128129

129130
static {
130-
addAll(DEFAULT_REPRESENTATION_ELEMENTS, PreferContainment, PreferMembership, PreferUserManaged);
131+
addAll(DEFAULT_REPRESENTATION_ELEMENTS, PreferContainment, PreferMembership, PreferUserManaged,
132+
PreferServerManaged);
131133
}
132134

133135
/** The implied or default set of IRIs used with a Prefer header. */

core/http/src/main/java/org/trellisldp/http/impl/HttpUtils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ public static Set<IRI> triplePreferences(final Prefer prefer) {
129129
}
130130
if (prefer.getOmit().contains(LDP.PreferMinimalContainer.getIRIString())) {
131131
include.remove(Trellis.PreferUserManaged);
132+
include.remove(Trellis.PreferServerManaged);
132133
}
133134
prefer.getOmit().stream().map(rdf::createIRI).forEach(include::remove);
134135
prefer.getInclude().stream().map(rdf::createIRI)

core/http/src/test/java/org/trellisldp/http/AbstractTrellisHttpResourceTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import static org.trellisldp.vocabulary.Trellis.InvalidCardinality;
6767
import static org.trellisldp.vocabulary.Trellis.InvalidRange;
6868
import static org.trellisldp.vocabulary.Trellis.PreferAccessControl;
69+
import static org.trellisldp.vocabulary.Trellis.PreferAudit;
6970
import static org.trellisldp.vocabulary.Trellis.PreferServerManaged;
7071
import static org.trellisldp.vocabulary.Trellis.PreferUserManaged;
7172

@@ -2391,7 +2392,7 @@ static Predicate<Link> hasType(final IRI iri) {
23912392
private Stream<Quad> getPreferQuads() {
23922393
return Stream.of(
23932394
rdf.createQuad(PreferUserManaged, identifier, DC.title, rdf.createLiteral(TITLE_VALUE)),
2394-
rdf.createQuad(PreferServerManaged, identifier, DC.created,
2395+
rdf.createQuad(PreferAudit, identifier, DC.created,
23952396
rdf.createLiteral("2017-04-01T10:15:00Z", XSD.dateTime)),
23962397
rdf.createQuad(LDP.PreferContainment, identifier, LDP.contains,
23972398
rdf.createIRI("trellis:data/resource/child1")),
@@ -2486,7 +2487,7 @@ private Stream<Executable> checkJsonStructure(final Map<String, Object> obj, fin
24862487
include.stream().map(key ->
24872488
() -> assertTrue(obj.containsKey(key), "JSON-LD didn't contain expected key: " + key)),
24882489
omit.stream().map(key ->
2489-
() -> assertFalse(obj.containsKey(key), "JSON-LD caontained extraneous key: " + key)));
2490+
() -> assertFalse(obj.containsKey(key), "JSON-LD contained extraneous key: " + key)));
24902491
}
24912492

24922493
private Stream<Executable> checkSimpleJsonLdResponse(final Response res, final IRI ldpType) {

0 commit comments

Comments
 (0)