001package ca.uhn.fhir.jpa.api.model; 002 003/*- 004 * #%L 005 * HAPI FHIR Storage api 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import org.apache.commons.lang3.Validate; 024import org.hl7.fhir.instance.model.api.IIdType; 025import org.springframework.util.Assert; 026 027import java.util.ArrayList; 028import java.util.HashSet; 029import java.util.Iterator; 030import java.util.List; 031import java.util.Set; 032import java.util.function.Predicate; 033 034public class DeleteConflictList implements Iterable<DeleteConflict> { 035 private final List<DeleteConflict> myList = new ArrayList<>(); 036 private final Set<String> myResourceIdsMarkedForDeletion; 037 private final Set<String> myResourceIdsToIgnoreConflict; 038 private int myRemoveModCount; 039 040 /** 041 * Constructor 042 */ 043 public DeleteConflictList() { 044 myResourceIdsMarkedForDeletion = new HashSet<>(); 045 myResourceIdsToIgnoreConflict = new HashSet<>(); 046 } 047 048 /** 049 * Constructor that shares (i.e. uses the same list, as opposed to cloning it) 050 * of {@link #isResourceIdMarkedForDeletion(IIdType) resources marked for deletion} 051 */ 052 public DeleteConflictList(DeleteConflictList theParentList) { 053 myResourceIdsMarkedForDeletion = theParentList.myResourceIdsMarkedForDeletion; 054 myResourceIdsToIgnoreConflict = theParentList.myResourceIdsToIgnoreConflict; 055 } 056 057 058 public boolean isResourceIdMarkedForDeletion(IIdType theIdType) { 059 Validate.notNull(theIdType); 060 Validate.notBlank(theIdType.toUnqualifiedVersionless().getValue()); 061 return myResourceIdsMarkedForDeletion.contains(theIdType.toUnqualifiedVersionless().getValue()); 062 } 063 064 public void setResourceIdMarkedForDeletion(IIdType theIdType) { 065 Validate.notNull(theIdType); 066 Validate.notBlank(theIdType.toUnqualifiedVersionless().getValue()); 067 myResourceIdsMarkedForDeletion.add(theIdType.toUnqualifiedVersionless().getValue()); 068 } 069 070 public boolean isResourceIdToIgnoreConflict(IIdType theIdType) { 071 Validate.notNull(theIdType); 072 Validate.notBlank(theIdType.toUnqualifiedVersionless().getValue()); 073 return myResourceIdsToIgnoreConflict.contains(theIdType.toUnqualifiedVersionless().getValue()); 074 } 075 076 public void setResourceIdToIgnoreConflict(IIdType theIdType) { 077 Validate.notNull(theIdType); 078 Validate.notBlank(theIdType.toUnqualifiedVersionless().getValue()); 079 myResourceIdsToIgnoreConflict.add(theIdType.toUnqualifiedVersionless().getValue()); 080 } 081 082 public void add(DeleteConflict theDeleteConflict) { 083 myList.add(theDeleteConflict); 084 } 085 086 public boolean isEmpty() { 087 return myList.isEmpty(); 088 } 089 090 @Override 091 public Iterator<DeleteConflict> iterator() { 092 // Note that handlers may add items to this list, so we're using a special iterator 093 // that is ok with this. Only removals from the list should trigger a concurrent modification 094 // issue 095 return new Iterator<DeleteConflict>() { 096 097 private final int myOriginalRemoveModCont = myRemoveModCount; 098 private int myNextIndex = 0; 099 private boolean myLastOperationWasNext; 100 101 @Override 102 public boolean hasNext() { 103 checkForCoModification(); 104 myLastOperationWasNext = false; 105 return myNextIndex < myList.size(); 106 } 107 108 @Override 109 public DeleteConflict next() { 110 checkForCoModification(); 111 myLastOperationWasNext = true; 112 return myList.get(myNextIndex++); 113 } 114 115 @Override 116 public void remove() { 117 Assert.isTrue(myLastOperationWasNext); 118 myNextIndex--; 119 myList.remove(myNextIndex); 120 myLastOperationWasNext = false; 121 } 122 123 private void checkForCoModification() { 124 Validate.isTrue(myOriginalRemoveModCont == myRemoveModCount); 125 } 126 }; 127 } 128 129 public boolean removeIf(Predicate<DeleteConflict> theFilter) { 130 boolean retVal = myList.removeIf(theFilter); 131 if (retVal) { 132 myRemoveModCount++; 133 } 134 return retVal; 135 } 136 137 public void addAll(DeleteConflictList theNewConflicts) { 138 myList.addAll(theNewConflicts.myList); 139 } 140 141 public int size() { 142 return myList.size(); 143 } 144 145 public void removeAll() { 146 this.removeIf(x -> true); 147 } 148 149 @Override 150 public String toString() { 151 return myList.toString(); 152 } 153}