ActorsRepositoryDefault.java
package org.linkedopenactors.rdfpub.adapter.driven;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.model.Namespace;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.util.ModelBuilder;
import org.eclipse.rdf4j.model.util.Values;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.query.QueryResults;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.linkedopenactors.rdfpub.domain.ActivityPubObject;
import org.linkedopenactors.rdfpub.domain.Actor;
import org.linkedopenactors.rdfpub.domain.DomainObjectBuilders;
import org.linkedopenactors.rdfpub.domain.IRI;
import org.linkedopenactors.rdfpub.domain.ResourceFactory;
import org.linkedopenactors.rdfpub.domain.service.ActorsRepository;
import org.linkedopenactors.rdfpub.rdf4j.ModelToRdfObject;
import org.springframework.stereotype.Component;
import de.naturzukunft.rdf4j.vocabulary.AS;
import lombok.extern.slf4j.Slf4j;
/**
*
*/
@Slf4j
@Component
public class ActorsRepositoryDefault implements ActorsRepository {
private final Repository repository;
private final ModelToRdfObject modelToRdfObject;
private final ResourceFactory resourceFactory;
private final DomainObjectBuilders domainObjectBuilders;
/**
* @param repository
* @param modelToRdfObject
* @param resourceFactory
* @param domainObjectBuilders
*/
public ActorsRepositoryDefault(Repository repository,ModelToRdfObject modelToRdfObject, ResourceFactory resourceFactory, DomainObjectBuilders domainObjectBuilders) {
this.repository = repository;
this.modelToRdfObject = modelToRdfObject;
this.resourceFactory = resourceFactory;
this.domainObjectBuilders = domainObjectBuilders;
}
/**
* @return {@link List} of all {@link Actor}s of this instance.
*/
private List<Actor> findAll() {
log.trace("->findAll()");
List<Actor> actors = new ArrayList<>();
try (RepositoryConnection con = repository.getConnection()) {
Resource[] ctx = new Resource[] {AS.Public};
Model all = new ModelBuilder().build();
all.addAll(QueryResults.asModel(con.getStatements(null, RDF.TYPE, AS.Application, ctx)));
all.addAll(QueryResults.asModel(con.getStatements(null, RDF.TYPE, AS.Group, ctx)));
all.addAll(QueryResults.asModel(con.getStatements(null, RDF.TYPE, AS.Organization, ctx)));
all.addAll(QueryResults.asModel(con.getStatements(null, RDF.TYPE, AS.Person, ctx)));
all.addAll(QueryResults.asModel(con.getStatements(null, RDF.TYPE, AS.Service, ctx)));
Set<Resource> actorSubjects = all.stream()
.map(stmt->stmt.getSubject())
.collect(Collectors.toSet());
actors = actorSubjects.stream()
.map(as->{
Model m = QueryResults.asModel(con.getStatements(as, null, null, ctx));
ActivityPubObject r = createRdfObject(resourceFactory.iri(as.stringValue()), m);
addContexts(r, m);
copyNamespaces(r, con);
return domainObjectBuilders.actorBuilder().rdfObject(r).build();
})
.collect(Collectors.toList());
}
log.trace("<-findAll()");
return actors;
}
private ActivityPubObject createRdfObject(IRI subject, Model resultModel) {
return modelToRdfObject.toActivityPubObject(Values.iri(subject.toString()), resultModel);
}
private void addContexts(ActivityPubObject result, Model resultModel) {
Optional<ActivityPubObject> resultOpt = Optional.ofNullable(result);
Set<IRI> contexts = StreamSupport.stream(resultModel.getStatements(null, null, null).spliterator(), false)
.map(stmt->stmt.getContext())
.map(Resource::stringValue)
.map(resourceFactory::iri)
.collect(Collectors.toSet());
resultOpt.ifPresent(e->e.addContext(contexts));
}
private void copyNamespaces(ActivityPubObject rdfObject, RepositoryConnection con) {
Optional<ActivityPubObject> rdfObjectOpt = Optional.ofNullable(rdfObject);
List<Namespace> namespaces = new ArrayList<>();
con.getNamespaces().forEach(ns->namespaces.add(ns));
rdfObjectOpt.ifPresent(r->{
namespaces.forEach(nns->r.addNamespace(nns.getPrefix(), resourceFactory.iri(nns.getName())));
});
}
@Override
public Optional<Actor> findByPreferredUsername(String preferredUsername) {
Optional<Actor> found = Optional.empty();
if(Objects.nonNull(preferredUsername)) {
List<Actor> actors = findAll().stream()
.filter(a->matchPreferredUsername(a, preferredUsername))
.collect(Collectors.toList());
if(actors.size()>1) {
throw new IllegalStateException("preferredUsername '"+preferredUsername+"' is not unique!");
}
else if(!actors.isEmpty()) {
found = Optional.ofNullable(actors.get(0));
}
}
return found;
}
@Override
public Optional<Actor> findByOauth2IssuerUserId(String issuerUserId, URI issuer) {
String oauth2IssuerUserId = issuerUserId + "@" + issuer.getRawAuthority();
Optional<Actor> found = Optional.empty();
// TODO optimize, only query for the target user
List<Actor> actors = findAll().stream()
.filter(a->matchOauth2IssuerUserId(a, oauth2IssuerUserId))
.collect(Collectors.toList());
if(actors.size()>1) {
throw new IllegalStateException("oauth2IssuerUserId '"+oauth2IssuerUserId+"' is not unique!");
}
else if(!actors.isEmpty()) {
found = Optional.ofNullable(actors.get(0));
}
return found;
}
@Override
public Optional<Actor> findByIdentifier(String identifier) {
Optional<Actor> found = Optional.empty();
if(Objects.nonNull(identifier)) {
List<Actor> actors = findAll().stream()
.filter(a->identifier.equals(a.getIdentifier()))
// .filter(a->matchIdentifier(a, identifier))
.collect(Collectors.toList());
if(actors.size()>1) {
throw new IllegalStateException("identifier '"+identifier+"' is not unique!");
}
else if(!actors.isEmpty()) {
found = Optional.ofNullable(actors.get(0));
}
}
return found;
}
private boolean matchPreferredUsername(Actor actor, String preferredUsername) {
return actor.getPreferredUsername()
.map(p->p.equals(preferredUsername))
.orElse(false);
}
private boolean matchOauth2IssuerUserId(Actor actor, String oauth2IssuerUserId) {
return actor.getOuth2IssuerUserId()
.map(p->p.equals(oauth2IssuerUserId))
.orElse(false);
}
}