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.kernel.impl.services;
019
020import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
021import org.fcrepo.kernel.api.identifiers.FedoraId;
022import org.fcrepo.kernel.api.models.ExternalContent;
023import org.fcrepo.kernel.api.operations.NonRdfSourceOperationBuilder;
024import org.fcrepo.kernel.api.operations.NonRdfSourceOperationFactory;
025import org.fcrepo.kernel.api.services.ReplaceBinariesService;
026import org.fcrepo.persistence.api.PersistentStorageSession;
027import org.fcrepo.persistence.api.PersistentStorageSessionManager;
028import org.fcrepo.persistence.api.exceptions.PersistentStorageException;
029import org.fcrepo.persistence.common.MultiDigestInputStreamWrapper;
030import org.slf4j.Logger;
031import org.springframework.stereotype.Component;
032
033import javax.inject.Inject;
034import java.io.InputStream;
035import java.net.URI;
036import java.util.Collection;
037import java.util.Collections;
038
039import static java.lang.String.format;
040import static org.slf4j.LoggerFactory.getLogger;
041
042/**
043 * Implementation of a service for replacing/updating binary resources
044 *
045 * @author bbpennel
046 */
047@Component
048public class ReplaceBinariesServiceImpl extends AbstractService implements ReplaceBinariesService {
049
050    private static final Logger LOGGER = getLogger(ReplaceBinariesServiceImpl.class);
051
052    @Inject
053    private PersistentStorageSessionManager psManager;
054
055    @Inject
056    private NonRdfSourceOperationFactory factory;
057
058    @Override
059    public void perform(final String txId,
060                        final String userPrincipal,
061                        final FedoraId fedoraId,
062                        final String filename,
063                        final String contentType,
064                        final Collection<URI> digests,
065                        final InputStream contentBody,
066                        final long contentSize,
067                        final ExternalContent externalContent) {
068        try {
069            final PersistentStorageSession pSession = this.psManager.getSession(txId);
070
071            String mimeType = contentType;
072            long size = contentSize;
073            final NonRdfSourceOperationBuilder builder;
074            if (externalContent == null || externalContent.isCopy()) {
075                var contentInputStream = contentBody;
076                if (externalContent != null) {
077                    LOGGER.debug("External content COPY '{}', '{}'", fedoraId, externalContent.getURL());
078                    contentInputStream = externalContent.fetchExternalContent();
079                }
080
081                builder = factory.updateInternalBinaryBuilder(fedoraId, contentInputStream);
082            } else {
083                builder = factory.updateExternalBinaryBuilder(fedoraId,
084                        externalContent.getHandling(),
085                        externalContent.getURI());
086
087                if (contentSize == -1L) {
088                    size = externalContent.getContentSize();
089                }
090                if (!digests.isEmpty()) {
091                    final var multiDigestWrapper = new MultiDigestInputStreamWrapper(
092                            externalContent.fetchExternalContent(),
093                            digests,
094                            Collections.emptyList());
095                    multiDigestWrapper.checkFixity();
096                }
097            }
098
099            if (externalContent != null && externalContent.getContentType() != null) {
100                mimeType = externalContent.getContentType();
101            }
102
103            builder.mimeType(mimeType)
104                   .contentSize(size)
105                   .filename(filename)
106                   .contentDigests(digests)
107                   .userPrincipal(userPrincipal);
108            final var replaceOp = builder.build();
109
110            pSession.persist(replaceOp);
111            recordEvent(txId, fedoraId, replaceOp);
112        } catch (final PersistentStorageException ex) {
113            throw new RepositoryRuntimeException(format("failed to replace binary %s",
114                  fedoraId), ex);
115        }
116    }
117
118}