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