001/*
002 * Copyright 2019 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.fcrepo.migration;
018
019import com.fasterxml.jackson.annotation.JsonInclude;
020import com.fasterxml.jackson.databind.ObjectMapper;
021import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
022
023import edu.wisc.library.ocfl.api.OcflConfig;
024import edu.wisc.library.ocfl.api.model.DigestAlgorithm;
025import edu.wisc.library.ocfl.core.OcflRepositoryBuilder;
026import edu.wisc.library.ocfl.core.extension.storage.layout.config.HashedNTupleLayoutConfig;
027import edu.wisc.library.ocfl.core.path.mapper.LogicalPathMappers;
028import edu.wisc.library.ocfl.core.storage.filesystem.FileSystemOcflStorage;
029import org.apache.commons.lang3.SystemUtils;
030import org.fcrepo.migration.handlers.ocfl.PlainOcflObjectSessionFactory;
031import org.fcrepo.storage.ocfl.CommitType;
032import org.fcrepo.storage.ocfl.DefaultOcflObjectSessionFactory;
033import org.fcrepo.storage.ocfl.OcflObjectSessionFactory;
034import org.fcrepo.storage.ocfl.cache.NoOpCache;
035import org.springframework.beans.factory.FactoryBean;
036
037import java.nio.file.Path;
038
039import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;
040
041/**
042 * Spring FactoryBean for easy OcflObjectSessionFactory creation.
043 *
044 * @author pwinckles
045 */
046public class OcflSessionFactoryFactoryBean implements FactoryBean<OcflObjectSessionFactory> {
047
048    private final Path ocflRoot;
049    private final Path stagingDir;
050    private final MigrationType migrationType;
051    private final String user;
052    private final String userUri;
053    private final DigestAlgorithm digestAlgorithm;
054
055    /**
056     * @param ocflRoot OCFL storage root
057     * @param stagingDir OCFL staging dir
058     * @param migrationType migration type
059     * @param user user to add to OCFL versions
060     * @param userUri user's address
061     * @param digestAlgorithm The digest algorithm to use.
062     */
063    public OcflSessionFactoryFactoryBean(final Path ocflRoot,
064                                         final Path stagingDir,
065                                         final MigrationType migrationType,
066                                         final String user,
067                                         final String userUri,
068                                         final DigestAlgorithm digestAlgorithm) {
069        this.ocflRoot = ocflRoot;
070        this.stagingDir = stagingDir;
071        this.migrationType = migrationType;
072        this.user = user;
073        this.userUri = userUri;
074        this.digestAlgorithm = digestAlgorithm;
075    }
076
077    /**
078     * @param ocflRoot OCFL storage root
079     * @param stagingDir OCFL staging dir
080     * @param migrationType migration type
081     * @param user user to add to OCFL versions
082     * @param userUri user's address
083     */
084    public OcflSessionFactoryFactoryBean(final Path ocflRoot,
085                                         final Path stagingDir,
086                                         final MigrationType migrationType,
087                                         final String user,
088                                         final String userUri) {
089        this(ocflRoot, stagingDir, migrationType, user, userUri, DigestAlgorithm.sha512);
090    }
091
092    @Override
093    public OcflObjectSessionFactory getObject() {
094        final var logicalPathMapper = SystemUtils.IS_OS_WINDOWS ?
095                LogicalPathMappers.percentEncodingWindowsMapper() : LogicalPathMappers.percentEncodingLinuxMapper();
096
097        final var config = new OcflConfig();
098        config.setDefaultDigestAlgorithm(this.digestAlgorithm);
099
100        final var ocflRepo =  new OcflRepositoryBuilder()
101                .defaultLayoutConfig(new HashedNTupleLayoutConfig())
102                .logicalPathMapper(logicalPathMapper)
103                .storage(FileSystemOcflStorage.builder().repositoryRoot(ocflRoot).build())
104                .workDir(stagingDir)
105                .ocflConfig(config)
106                .buildMutable();
107
108        if (migrationType == MigrationType.FEDORA_OCFL) {
109            final var objectMapper = new ObjectMapper()
110                    .configure(WRITE_DATES_AS_TIMESTAMPS, false)
111                    .registerModule(new JavaTimeModule())
112                    .setSerializationInclusion(JsonInclude.Include.NON_NULL);
113
114            return new DefaultOcflObjectSessionFactory(ocflRepo, stagingDir, objectMapper,
115                    new NoOpCache<>(), CommitType.NEW_VERSION,
116                    "Generated by Fedora 3 to Fedora 6 migration", user, userUri);
117        } else {
118            return new PlainOcflObjectSessionFactory(ocflRepo, stagingDir,
119                    "Generated by Fedora 3 to Fedora 6 migration", user, userUri);
120        }
121    }
122
123    @Override
124    public Class<?> getObjectType() {
125        return OcflObjectSessionFactory.class;
126    }
127
128    @Override
129    public boolean isSingleton() {
130        return true;
131    }
132
133}