001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.persistence.ocfl.impl;
019
020import org.fcrepo.kernel.api.ReadOnlyTransaction;
021import org.fcrepo.kernel.api.Transaction;
022import org.fcrepo.persistence.api.PersistentStorageSession;
023import org.fcrepo.persistence.api.PersistentStorageSessionManager;
024import org.fcrepo.persistence.ocfl.api.FedoraToOcflObjectIndex;
025import org.fcrepo.storage.ocfl.OcflObjectSessionFactory;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028import org.springframework.beans.factory.annotation.Autowired;
029import org.springframework.stereotype.Component;
030
031import javax.inject.Inject;
032import java.util.Map;
033import java.util.concurrent.ConcurrentHashMap;
034
035/**
036 * OCFL implementation of PersistentStorageSessionManager
037 *
038 * @author whikloj
039 * @author dbernstein
040 * @since 2019-09-20
041 */
042@Component
043public class OcflPersistentSessionManager implements PersistentStorageSessionManager {
044
045    private static final Logger LOGGER = LoggerFactory.getLogger(OcflPersistentSessionManager.class);
046
047    private volatile PersistentStorageSession readOnlySession;
048
049    private Map<String, PersistentStorageSession> sessionMap;
050
051    @Inject
052    private OcflObjectSessionFactory objectSessionFactory;
053
054    @Inject
055    private FedoraToOcflObjectIndex ocflIndex;
056
057    @Inject
058    private ReindexService reindexService;
059
060    /**
061     * Default constructor
062     */
063    @Autowired
064    public OcflPersistentSessionManager() {
065        this.sessionMap = new ConcurrentHashMap<>();
066    }
067
068    @Override
069    public PersistentStorageSession getSession(final Transaction transaction) {
070        if (transaction == null) {
071            throw new IllegalArgumentException("session id must be non-null");
072        }
073
074        return sessionMap.computeIfAbsent(transaction.getId(), key -> {
075            LOGGER.debug("Creating storage session {}", transaction);
076            return new OcflPersistentStorageSessionMetrics(
077                    new OcflPersistentStorageSession(
078                            transaction,
079                            ocflIndex,
080                            objectSessionFactory,
081                            reindexService));
082        });
083    }
084
085    @Override
086    public PersistentStorageSession getReadOnlySession() {
087        var localSession = this.readOnlySession;
088
089        if (localSession == null) {
090            synchronized (this) {
091                localSession = this.readOnlySession;
092                if (localSession == null) {
093                    this.readOnlySession = new OcflPersistentStorageSessionMetrics(
094                            new OcflPersistentStorageSession(ReadOnlyTransaction.INSTANCE,
095                                    ocflIndex, objectSessionFactory, reindexService));
096                    localSession = this.readOnlySession;
097                }
098            }
099        }
100
101        return localSession;
102    }
103
104    @Override
105    public PersistentStorageSession removeSession(final String sessionId) {
106        LOGGER.debug("Removing storage session {}", sessionId);
107        return sessionMap.remove(sessionId);
108    }
109}