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 static java.lang.String.format; 021 022import javax.inject.Inject; 023 024import java.util.stream.Stream; 025 026import org.fcrepo.kernel.api.Transaction; 027import org.fcrepo.kernel.api.exception.PathNotFoundException; 028import org.fcrepo.kernel.api.exception.PathNotFoundRuntimeException; 029import org.fcrepo.kernel.api.exception.RepositoryRuntimeException; 030import org.fcrepo.kernel.api.identifiers.FedoraId; 031import org.fcrepo.kernel.api.models.Binary; 032import org.fcrepo.kernel.api.models.Container; 033import org.fcrepo.kernel.api.models.FedoraResource; 034import org.fcrepo.kernel.api.models.NonRdfSourceDescription; 035import org.fcrepo.kernel.api.models.ResourceFactory; 036import org.fcrepo.kernel.api.models.Tombstone; 037import org.fcrepo.persistence.api.PersistentStorageSession; 038import org.fcrepo.persistence.api.PersistentStorageSessionManager; 039import org.fcrepo.persistence.api.exceptions.PersistentStorageException; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043/** 044 * Shared delete/purge code. 045 * @author whikloj 046 */ 047abstract public class AbstractDeleteResourceService extends AbstractService { 048 049 private final static Logger log = LoggerFactory.getLogger(AbstractDeleteResourceService.class); 050 051 @Inject 052 protected ResourceFactory resourceFactory; 053 054 @Inject 055 protected PersistentStorageSessionManager psManager; 056 057 /** 058 * The starts the service, does initial checks and setups for processing. 059 * @param tx the transaction. 060 * @param fedoraResource the resource to start delete/purging. 061 * @param userPrincipal the user performing the action. 062 */ 063 public void perform(final Transaction tx, final FedoraResource fedoraResource, final String userPrincipal) { 064 final String fedoraResourceId = fedoraResource.getId(); 065 066 if (fedoraResource instanceof NonRdfSourceDescription) { 067 throw new RepositoryRuntimeException( 068 format("A NonRdfSourceDescription cannot be deleted independently of the NonRDFSource: %s", 069 fedoraResourceId)); 070 } 071 072 try { 073 log.debug("operating on {}", fedoraResourceId); 074 final PersistentStorageSession pSession = this.psManager.getSession(tx.getId()); 075 deleteDepthFirst(tx, pSession, fedoraResource, userPrincipal); 076 } catch (final PersistentStorageException ex) { 077 throw new RepositoryRuntimeException(format("failed to delete/purge resource %s", fedoraResourceId), ex); 078 } 079 } 080 081 /** 082 * Code to perform the recursion of containers. 083 * @param tx the transaction 084 * @param pSession the persistent storage session 085 * @param fedoraResource the current resource to check for any children. 086 * @param userPrincipal the user performing the action. 087 * @throws PersistentStorageException any problems accessing the underlying storage. 088 */ 089 private void deleteDepthFirst(final Transaction tx, final PersistentStorageSession pSession, 090 final FedoraResource fedoraResource, final String userPrincipal) 091 throws PersistentStorageException { 092 093 final FedoraId fedoraId = fedoraResource.getFedoraId(); 094 095 if (fedoraResource instanceof Container) { 096 final Stream<String> children = getContained(tx, fedoraResource); 097 children.forEach(childResourceId -> { 098 try { 099 100 final FedoraResource res = resourceFactory.getResource(tx, FedoraId.create(childResourceId)); 101 if (res instanceof Tombstone) { 102 deleteDepthFirst(tx, pSession, ((Tombstone) res).getDeletedObject(), userPrincipal); 103 } else { 104 deleteDepthFirst(tx, pSession, res, userPrincipal); 105 } 106 } catch (final PathNotFoundException ex) { 107 log.error("Path not found for {}: {}", fedoraId.getFullId(), ex.getMessage()); 108 throw new PathNotFoundRuntimeException(ex.getMessage(), ex); 109 } catch (final PersistentStorageException ex) { 110 throw new RepositoryRuntimeException(format("failed to delete resource %s", fedoraId.getFullId()), 111 ex); 112 } 113 }); 114 } else if (fedoraResource instanceof Binary) { 115 doAction(tx, pSession, fedoraResource.getDescription().getFedoraId(), userPrincipal); 116 } 117 118 //delete/purge the acl if this is not the acl 119 if (!fedoraResource.isAcl()) { 120 final FedoraResource acl = fedoraResource.getAcl(); 121 if (acl != null) { 122 doAction(tx, pSession, acl.getFedoraId(), userPrincipal); 123 } 124 } 125 126 //delete/purge the resource itself 127 doAction(tx, pSession, fedoraId, userPrincipal); 128 } 129 130 /** 131 * Get the contained resources to act upon. 132 * @param tx the transaction this occurs in. 133 * @param resource the parent resource to find contained resources for. 134 * @return stream of child ids. 135 */ 136 abstract protected Stream<String> getContained(final Transaction tx, final FedoraResource resource); 137 138 /** 139 * Perform the actual delete or purge action 140 * @param tx the transaction this occurs in. 141 * @param pSession the persistent storage session. 142 * @param resourceId the resource to perform the action on. 143 * @param userPrincipal the user performing the action 144 * @throws PersistentStorageException if problem performing the action. 145 */ 146 abstract protected void doAction(final Transaction tx, final PersistentStorageSession pSession, 147 final FedoraId resourceId, final String userPrincipal) 148 throws PersistentStorageException; 149}