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.persistence.ocfl.impl;
007
008import org.fcrepo.kernel.api.ReadOnlyTransaction;
009import org.fcrepo.kernel.api.Transaction;
010import org.fcrepo.persistence.api.PersistentStorageSession;
011import org.fcrepo.persistence.api.PersistentStorageSessionManager;
012import org.fcrepo.persistence.ocfl.api.FedoraToOcflObjectIndex;
013import org.fcrepo.storage.ocfl.OcflObjectSessionFactory;
014import org.slf4j.Logger;
015import org.slf4j.LoggerFactory;
016import org.springframework.beans.factory.annotation.Autowired;
017import org.springframework.stereotype.Component;
018
019import javax.inject.Inject;
020import java.util.Map;
021import java.util.concurrent.ConcurrentHashMap;
022
023/**
024 * OCFL implementation of PersistentStorageSessionManager
025 *
026 * @author whikloj
027 * @author dbernstein
028 * @since 2019-09-20
029 */
030@Component
031public class OcflPersistentSessionManager implements PersistentStorageSessionManager {
032
033    private static final Logger LOGGER = LoggerFactory.getLogger(OcflPersistentSessionManager.class);
034
035    private volatile PersistentStorageSession readOnlySession;
036
037    private Map<String, PersistentStorageSession> sessionMap;
038
039    @Inject
040    private OcflObjectSessionFactory objectSessionFactory;
041
042    @Inject
043    private FedoraToOcflObjectIndex ocflIndex;
044
045    @Inject
046    private ReindexService reindexService;
047
048    /**
049     * Default constructor
050     */
051    @Autowired
052    public OcflPersistentSessionManager() {
053        this.sessionMap = new ConcurrentHashMap<>();
054    }
055
056    @Override
057    public PersistentStorageSession getSession(final Transaction transaction) {
058        if (transaction == null) {
059            throw new IllegalArgumentException("session id must be non-null");
060        }
061
062        return sessionMap.computeIfAbsent(transaction.getId(), key -> {
063            LOGGER.debug("Creating storage session {}", transaction);
064            return new OcflPersistentStorageSessionMetrics(
065                    new OcflPersistentStorageSession(
066                            transaction,
067                            ocflIndex,
068                            objectSessionFactory,
069                            reindexService));
070        });
071    }
072
073    @Override
074    public PersistentStorageSession getReadOnlySession() {
075        var localSession = this.readOnlySession;
076
077        if (localSession == null) {
078            synchronized (this) {
079                localSession = this.readOnlySession;
080                if (localSession == null) {
081                    this.readOnlySession = new OcflPersistentStorageSessionMetrics(
082                            new OcflPersistentStorageSession(ReadOnlyTransaction.INSTANCE,
083                                    ocflIndex, objectSessionFactory, reindexService));
084                    localSession = this.readOnlySession;
085                }
086            }
087        }
088
089        return localSession;
090    }
091
092    @Override
093    public PersistentStorageSession removeSession(final String sessionId) {
094        LOGGER.debug("Removing storage session {}", sessionId);
095        return sessionMap.remove(sessionId);
096    }
097}