/** * Un-skolemize a blank node. * * @param term the RDF term * @return a blank node, if a previously-skolemized node; otherwise the original term */ default RDFTerm unskolemize(final RDFTerm term) { if (term instanceof IRI) { final String iri = ((IRI) term).getIRIString(); if (iri.startsWith(TRELLIS_BNODE_PREFIX)) { return getInstance().createBlankNode(iri.substring(TRELLIS_BNODE_PREFIX.length())); } } return term; }
private CompletionStage<Void> handleAclDeletion(final TrellisDataset mutable, final TrellisDataset immutable) { // When deleting just the ACL graph, keep the user managed triples intact try (final Stream<Triple> triples = getResource().stream(PreferUserManaged)) { triples.map(toQuad(PreferUserManaged)).forEachOrdered(mutable::add); } // Note: when deleting ACL resources, the resource itself is not removed and so this is really // more of an update operation. As such, the `replace` method is used and an `update` Audit event // is generated. // Collect the audit data getAuditUpdateData().forEachOrdered(immutable::add); return handleResourceReplacement(mutable, immutable); }
private Stream<Authorization> getAllAuthorizationsFor(final Resource resource, final boolean inherited) { LOGGER.debug("Checking ACL for: {}", resource.getIdentifier()); if (resource.hasAcl()) { try (final WrappedGraph graph = wrap(resource.stream(Trellis.PreferAccessControl).collect(toGraph()))) { final List<Authorization> authorizations = getAuthorizationFromGraph(graph.getGraph()); // Check for any acl:default statements if checking for inheritance if (inherited && authorizations.stream().anyMatch(getInheritedAuth(resource.getIdentifier()))) { return authorizations.stream().filter(getInheritedAuth(resource.getIdentifier())); // If not inheriting, just return the relevant Authorizations in the ACL } else if (!inherited) { return authorizations.stream().filter(getAccessToAuth(resource.getIdentifier())); } } } // Nothing here, check the parent LOGGER.debug("No ACL for {}; looking up parent resource", resource.getIdentifier()); return getContainer(resource.getIdentifier()).map(resourceService::get) .map(CompletionStage::toCompletableFuture).map(CompletableFuture::join) .map(res -> getAllAuthorizationsFor(res, true)).orElseGet(Stream::empty); }
/** * Test creating a resource. * @throws Exception if the operation failed */ @Test @DisplayName("Test creating resource") default void testCreateResource() throws Exception { final RDF rdf = getInstance(); final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + getResourceService().generateIdentifier()); final Dataset dataset = buildDataset(identifier, "Creation Test", SUBJECT1); assertEquals(MISSING_RESOURCE, getResourceService().get(identifier).toCompletableFuture().join(), "Check for no pre-existing LDP-RS"); assertDoesNotThrow(() -> getResourceService().create(Metadata.builder(identifier) .interactionModel(LDP.RDFSource).container(ROOT_CONTAINER).build(), dataset) .toCompletableFuture().join(), "Check that the resource was successfully created"); final Resource res = getResourceService().get(identifier).toCompletableFuture().join(); assertAll("Check resource stream", res.stream(Trellis.PreferUserManaged).map(toQuad(Trellis.PreferUserManaged)) .map(q -> () -> assertTrue(dataset.contains(q), "Verify that the quad is from the dataset: " + q))); }
/** * Retrieve the RDF Quads for a resource. * * @return the RDF quads */ default Dataset dataset() { try (final Stream<Quad> quads = stream()) { return quads.collect(TrellisUtils.toDataset().concurrent()); } }
private Optional<Resource> getNearestResource(final IRI identifier) { final Resource res = resourceService.get(identifier).toCompletableFuture().join(); if (resourceExists(res)) { return of(res); } return getContainer(identifier).flatMap(this::getNearestResource); }
private List<Authorization> getAuthorizationFromGraph(final Graph graph) { return graph.stream().map(Triple::getSubject).distinct().map(subject -> { try (final WrappedGraph subGraph = wrap(graph.stream(subject, null, null).collect(toGraph()))) { return Authorization.from(subject, subGraph.getGraph()); } }).collect(toList()); }
/** * Test creating a resource. * @throws Exception if the operation failed */ @Test @DisplayName("Test creating resource") default void testCreateResource() throws Exception { final RDF rdf = getInstance(); final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + getResourceService().generateIdentifier()); final Dataset dataset = buildDataset(identifier, "Creation Test", SUBJECT1); assertEquals(MISSING_RESOURCE, getResourceService().get(identifier).toCompletableFuture().join(), "Check for no pre-existing LDP-RS"); assertDoesNotThrow(() -> getResourceService().create(Metadata.builder(identifier) .interactionModel(LDP.RDFSource).container(ROOT_CONTAINER).build(), dataset) .toCompletableFuture().join(), "Check that the resource was successfully created"); final Resource res = getResourceService().get(identifier).toCompletableFuture().join(); assertAll("Check resource stream", res.stream(Trellis.PreferUserManaged).map(toQuad(Trellis.PreferUserManaged)) .map(q -> () -> assertTrue(dataset.contains(q), "Verify that the quad is from the dataset: " + q))); }
/** * Retrieve the RDF Quads for a resource. * * @return the RDF quads */ default Dataset dataset() { try (final Stream<Quad> quads = stream()) { return quads.collect(TrellisUtils.toDataset().concurrent()); } }
private CompletionStage<? extends Resource> getParent(final IRI identifier) { final Optional<IRI> parent = getContainer(identifier); if (parent.isPresent()) { return trellis.getResourceService().get(parent.get()); } return completedFuture(MISSING_RESOURCE); }
@Test public void testCollectGraph() { final Graph graph = generate(() -> rdf.createTriple(getIRI(), getIRI(), getIRI())) .parallel().limit(size).collect(toGraph()); assertTrue(size >= graph.size(), "Generated graph has too many triples!"); }
/** * Un-skolemize a blank node. * * @param term the RDF term * @return a blank node, if a previously-skolemized node; otherwise the original term */ default RDFTerm unskolemize(final RDFTerm term) { if (term instanceof IRI) { final String iri = ((IRI) term).getIRIString(); if (iri.startsWith(TRELLIS_BNODE_PREFIX)) { return getInstance().createBlankNode(iri.substring(TRELLIS_BNODE_PREFIX.length())); } } return term; }
@DisplayName("Test adding immutable data") default void testAddImmutableData() throws Exception { final RDF rdf = getInstance(); final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + getResourceService().generateIdentifier()); final Dataset dataset0 = buildDataset(identifier, "Immutable Resource Test", SUBJECT2); assertAll("Check the audit stream", res.stream(Trellis.PreferAudit).map(toQuad(Trellis.PreferAudit)) .map(q -> () -> assertTrue(dataset1.contains(q), "Check that the audit stream includes: " + q))); assertEquals(4L, res.stream(Trellis.PreferAudit).count(), "Check the audit triple count"); dataset2.stream().forEach(combined::add); assertAll("Check the audit stream", res2.stream(Trellis.PreferAudit).map(toQuad(Trellis.PreferAudit)) .map(q -> () -> assertTrue(combined.contains(q), "Check that the audit stream includes: " + q))); assertEquals(8L, res2.stream(Trellis.PreferAudit).count(), "Check the audit triple count");
private CompletionStage<Void> initialize(final IRI id, final Resource res, final TrellisDataset dataset) { if (MISSING_RESOURCE.equals(res) || DELETED_RESOURCE.equals(res)) { LOGGER.info("Initializing root container: {}", id); return trellis.getResourceService().create(Metadata.builder(id).interactionModel(LDP.BasicContainer) .build(), dataset.asDataset()); } else if (!res.hasAcl()) { LOGGER.info("Initializeing root ACL: {}", id); try (final Stream<Triple> triples = res.stream(Trellis.PreferUserManaged)) { triples.map(toQuad(Trellis.PreferUserManaged)).forEach(dataset::add); } return trellis.getResourceService().replace(Metadata.builder(res).build(), dataset.asDataset()); } return completedFuture(null); }
@Test public void testDatasetCollectorFinisher() { final Dataset dataset = generate(() -> rdf.createQuad(getIRI(), getIRI(), getIRI(), getIRI())) .parallel().limit(size).collect(toDataset()); final TrellisUtils.DatasetCollector collector = toDataset(); assertEquals(dataset, collector.finisher().apply(dataset), "Dataset finisher returns the wrong object!"); }
private Set<IRI> getAuthz(final IRI identifier, final IRI agent) { final Set<IRI> modes = getModesFor(identifier, agent); // consider membership resources, if relevant if (checkMembershipResources && hasWritableMode(modes)) { getContainer(identifier).map(resourceService::get).map(CompletionStage::toCompletableFuture) .map(CompletableFuture::join).flatMap(Resource::getMembershipResource) .map(WebACService::cleanIdentifier).map(member -> getModesFor(member, agent)).ifPresent(memberModes -> { if (!memberModes.contains(ACL.Write)) { modes.remove(ACL.Write); } if (!memberModes.contains(ACL.Append)) { modes.remove(ACL.Append); } }); } return modes; }
/** * Return an "internal" representation of an RDF term. * * @param <T> the type of RDF term * @param term the RDF term * @param baseUrl the base URL of the domain * @return the "internal" RDF term */ default <T extends RDFTerm> T toInternal(final T term, final String baseUrl) { if (term instanceof IRI) { final String iri = ((IRI) term).getIRIString(); if (iri.startsWith(baseUrl)) { @SuppressWarnings("unchecked") final T t = (T) getInstance().createIRI(TRELLIS_DATA_PREFIX + iri.substring(baseUrl.length())); return t; } } return term; }
@DisplayName("Test adding immutable data") default void testAddImmutableData() throws Exception { final RDF rdf = getInstance(); final IRI identifier = rdf.createIRI(TRELLIS_DATA_PREFIX + getResourceService().generateIdentifier()); final Dataset dataset0 = buildDataset(identifier, "Immutable Resource Test", SUBJECT2); assertAll("Check the audit stream", res.stream(Trellis.PreferAudit).map(toQuad(Trellis.PreferAudit)) .map(q -> () -> assertTrue(dataset1.contains(q), "Check that the audit stream includes: " + q))); assertEquals(4L, res.stream(Trellis.PreferAudit).count(), "Check the audit triple count"); dataset2.stream().forEach(combined::add); assertAll("Check the audit stream", res2.stream(Trellis.PreferAudit).map(toQuad(Trellis.PreferAudit)) .map(q -> () -> assertTrue(combined.contains(q), "Check that the audit stream includes: " + q))); assertEquals(8L, res2.stream(Trellis.PreferAudit).count(), "Check the audit triple count");
/** * Read an entity into the provided {@link TrellisDataset}. * @param graphName the target graph * @param syntax the entity syntax * @param dataset the dataset */ protected void readEntityIntoDataset(final IRI graphName, final RDFSyntax syntax, final TrellisDataset dataset) { try (final InputStream input = entity) { getServices().getIOService().read(input, syntax, getIdentifier()) .map(skolemizeTriples(getServices().getResourceService(), getBaseUrl())) .filter(triple -> !RDF.type.equals(triple.getPredicate()) || !triple.getObject().ntriplesString().startsWith("<" + LDP.getNamespace())) .filter(triple -> !LDP.contains.equals(triple.getPredicate())) .map(toQuad(graphName)).forEachOrdered(dataset::add); } catch (final RuntimeTrellisException ex) { throw new BadRequestException("Invalid RDF content: " + ex.getMessage()); } catch (final IOException ex) { throw new WebApplicationException("Error processing input: " + ex.getMessage()); } }
@Test public void testDatasetCombiner() { final Set<Quad> quads1 = generate(() -> rdf.createQuad(getIRI(), getIRI(), getIRI(), getIRI())) .parallel().limit(size).collect(toSet()); final Set<Quad> quads2 = generate(() -> rdf.createQuad(getIRI(), getIRI(), getIRI(), getIRI())) .parallel().limit(size).collect(toSet()); final Collector<Quad, Set<Quad>, Dataset> collector = toDataset().concurrent(); assertEquals(quads1.size() + quads2.size(), collector.combiner().apply(quads1, quads2).size(), "Dataset combiner produces the wrong number of quads!"); }