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;
007
008
009import org.fcrepo.config.FedoraPropsConfig;
010import org.fcrepo.config.OcflPropsConfig;
011import org.fcrepo.kernel.api.TransactionManager;
012import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
013import org.fcrepo.kernel.api.identifiers.FedoraId;
014import org.fcrepo.kernel.api.operations.RdfSourceOperation;
015import org.fcrepo.kernel.api.operations.RdfSourceOperationFactory;
016import org.fcrepo.kernel.api.operations.VersionResourceOperationFactory;
017import org.fcrepo.persistence.api.PersistentStorageSession;
018import org.fcrepo.persistence.api.exceptions.PersistentItemNotFoundException;
019import org.fcrepo.persistence.api.exceptions.PersistentStorageException;
020import org.fcrepo.persistence.ocfl.api.IndexBuilder;
021import org.fcrepo.persistence.ocfl.impl.OcflPersistentSessionManager;
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024import org.springframework.context.ConfigurableApplicationContext;
025import org.springframework.context.event.ContextRefreshedEvent;
026import org.springframework.context.event.EventListener;
027import org.springframework.scheduling.annotation.Async;
028import org.springframework.stereotype.Component;
029
030import javax.inject.Inject;
031
032import static org.fcrepo.kernel.api.RdfLexicon.BASIC_CONTAINER;
033
034import java.util.concurrent.atomic.AtomicBoolean;
035
036/**
037 * This class is responsible for initializing the repository on start-up.
038 *
039 * @author dbernstein
040 */
041@Component
042public class RepositoryInitializer {
043
044    private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryInitializer.class);
045
046    @Inject
047    private OcflPersistentSessionManager sessionManager;
048
049    @Inject
050    private RdfSourceOperationFactory operationFactory;
051
052    @Inject
053    private IndexBuilder indexBuilder;
054
055    @Inject
056    private VersionResourceOperationFactory versionResourceOperationFactory;
057
058    @Inject
059    private OcflPropsConfig config;
060
061    @Inject
062    private FedoraPropsConfig fedoraPropsConfig;
063
064    @Inject
065    private TransactionManager txManager;
066
067    private final AtomicBoolean initializationComplete = new AtomicBoolean(false);
068
069    // This is used in-place of @PostConstruct so that it is called _after_ the rest of context has been
070    // completely initialized.
071    @Async
072    @EventListener
073    public void onApplicationEvent(final ContextRefreshedEvent event) {
074        try {
075            initialize();
076        } catch (Exception e) {
077            LOGGER.error("Failed to initialize repository", e);
078            ((ConfigurableApplicationContext) event.getApplicationContext()).close();
079        } finally {
080            initializationComplete.set(true);
081        }
082    }
083
084    /**
085     * Initializes the repository
086     */
087    public void initialize() {
088        LOGGER.info("Initializing repository");
089
090        indexBuilder.rebuildIfNecessary();
091
092        final var root = FedoraId.getRepositoryRootId();
093
094        try {
095            //check that the root is initialized
096            final var transaction = txManager.create();
097            transaction.setShortLived(true);
098            final PersistentStorageSession session = this.sessionManager.getSession(transaction);
099
100            try {
101                session.getHeaders(root, null);
102            } catch (final PersistentItemNotFoundException e) {
103                LOGGER.debug("Repository root ({}) not found. Creating...", root);
104                final RdfSourceOperation operation = this.operationFactory.createBuilder(transaction, root,
105                        BASIC_CONTAINER.getURI(), fedoraPropsConfig.getServerManagedPropsMode())
106                        .parentId(root).build();
107
108                session.persist(operation);
109
110                //if auto versioning is not enabled, be sure to create an immutable version
111                if (!config.isAutoVersioningEnabled()) {
112                    final var versionOperation = this.versionResourceOperationFactory
113                            .createBuilder(transaction, root).build();
114                    session.persist(versionOperation);
115                }
116
117                transaction.commit();
118
119                LOGGER.debug("Successfully created repository root ({}).", root);
120            }
121
122        } catch (final PersistentStorageException ex) {
123            throw new RepositoryRuntimeException(ex.getMessage(), ex);
124        }
125    }
126
127    public boolean isInitializationComplete() {
128        return initializationComplete.get();
129    }
130
131}