001/*
002 * The contents of this file are subject to the license and copyright
003 * detailed in the LICENSE and NOTICE files at the root of the source
004 * tree.
005 */
006package org.fcrepo.kernel.impl.services;
007
008import static org.fcrepo.kernel.api.RdfLexicon.FEDORA_WEBAC_ACL_URI;
009import static org.fcrepo.kernel.api.rdf.DefaultRdfStream.fromModel;
010
011import java.util.Optional;
012
013import javax.inject.Inject;
014
015import org.fcrepo.kernel.api.RdfStream;
016import org.fcrepo.kernel.api.Transaction;
017import org.fcrepo.kernel.api.auth.ACLHandle;
018import org.fcrepo.kernel.api.exception.PathNotFoundException;
019import org.fcrepo.kernel.api.exception.PathNotFoundRuntimeException;
020import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
021import org.fcrepo.kernel.api.identifiers.FedoraId;
022import org.fcrepo.kernel.api.models.ResourceFactory;
023import org.fcrepo.kernel.api.models.WebacAcl;
024import org.fcrepo.kernel.api.operations.RdfSourceOperation;
025import org.fcrepo.kernel.api.operations.RdfSourceOperationFactory;
026import org.fcrepo.kernel.api.services.WebacAclService;
027import org.fcrepo.kernel.impl.models.WebacAclImpl;
028import org.fcrepo.persistence.api.PersistentStorageSession;
029import org.fcrepo.persistence.api.PersistentStorageSessionManager;
030import org.fcrepo.persistence.api.exceptions.PersistentStorageException;
031import org.springframework.stereotype.Component;
032
033import org.apache.jena.rdf.model.Model;
034
035import com.github.benmanes.caffeine.cache.Cache;
036
037/**
038 * Implementation of {@link WebacAclService}
039 *
040 * @author dbernstein
041 */
042@Component
043public class WebacAclServiceImpl extends AbstractService implements WebacAclService {
044
045    @Inject
046    private PersistentStorageSessionManager psManager;
047
048    @Inject
049    private ResourceFactory resourceFactory;
050
051    @Inject
052    private RdfSourceOperationFactory rdfSourceOperationFactory;
053
054    @Inject
055    private Cache<String, Optional<ACLHandle>> authHandleCache;
056
057    @Override
058    public WebacAcl find(final Transaction transaction, final FedoraId fedoraId) {
059        try {
060            return resourceFactory.getResource(transaction, fedoraId, WebacAclImpl.class);
061        } catch (final PathNotFoundException exc) {
062            throw new PathNotFoundRuntimeException(exc.getMessage(), exc);
063        }
064    }
065
066    @Override
067    public void create(final Transaction transaction, final FedoraId fedoraId, final String userPrincipal,
068                                 final Model model) {
069        final PersistentStorageSession pSession = this.psManager.getSession(transaction);
070
071        ensureValidACLAuthorization(model);
072
073        final RdfStream stream = fromModel(model.getResource(fedoraId.getFullId()).asNode(), model);
074
075        final RdfSourceOperation createOp = rdfSourceOperationFactory
076                .createBuilder(transaction, fedoraId, FEDORA_WEBAC_ACL_URI,
077                        fedoraPropsConfig.getServerManagedPropsMode())
078                .parentId(fedoraId.asBaseId())
079                .triples(stream)
080                .relaxedProperties(model)
081                .userPrincipal(userPrincipal)
082                .build();
083
084        lockParent(transaction, pSession, fedoraId.asBaseId());
085        transaction.lockResource(fedoraId);
086
087        try {
088            pSession.persist(createOp);
089            recordEvent(transaction, fedoraId, createOp);
090            // Flush ACL cache on any ACL creation/update/deletion.
091            authHandleCache.invalidateAll();
092        } catch (final PersistentStorageException exc) {
093            throw new RepositoryRuntimeException(String.format("failed to create resource %s", fedoraId), exc);
094        }
095    }
096
097}