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 try { 070 final PersistentStorageSession pSession = this.psManager.getSession(tx); 071 072 String mimeType = contentType; 073 long size = contentSize; 074 final NonRdfSourceOperationBuilder builder; 075 if (externalContent == null || externalContent.isCopy()) { 076 var contentInputStream = contentBody; 077 if (externalContent != null) { 078 LOGGER.debug("External content COPY '{}', '{}'", fedoraId, externalContent.getURL()); 079 contentInputStream = externalContent.fetchExternalContent(); 080 } 081 082 builder = factory.updateInternalBinaryBuilder(tx, fedoraId, contentInputStream); 083 } else { 084 builder = factory.updateExternalBinaryBuilder(tx, fedoraId, 085 externalContent.getHandling(), 086 externalContent.getURI()); 087 088 if (contentSize == -1L) { 089 size = externalContent.getContentSize(); 090 } 091 if (!digests.isEmpty()) { 092 final var multiDigestWrapper = new MultiDigestInputStreamWrapper( 093 externalContent.fetchExternalContent(), 094 digests, 095 Collections.emptyList()); 096 multiDigestWrapper.checkFixity(); 097 } 098 } 099 100 if (externalContent != null && externalContent.getContentType() != null) { 101 mimeType = externalContent.getContentType(); 102 } 103 104 builder.mimeType(mimeType) 105 .contentSize(size) 106 .filename(filename) 107 .contentDigests(digests) 108 .userPrincipal(userPrincipal); 109 final var replaceOp = builder.build(); 110 111 lockArchivalGroupResource(tx, pSession, fedoraId); 112 tx.lockResource(fedoraId); 113 tx.lockResource(fedoraId.asDescription()); 114 115 pSession.persist(replaceOp); 116 this.searchIndex.addUpdateIndex(tx, pSession.getHeaders(fedoraId, null)); 117 recordEvent(tx, fedoraId, replaceOp); 118 } catch (final PersistentStorageException ex) { 119 throw new RepositoryRuntimeException(format("failed to replace binary %s", 120 fedoraId), ex); 121 } 122 } 123 124}