001/*- 002 * #%L 003 * HAPI FHIR Storage api 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.jpa.api.model; 021 022import org.apache.commons.lang3.Validate; 023import org.hl7.fhir.instance.model.api.IIdType; 024import org.springframework.util.Assert; 025 026import java.util.ArrayList; 027import java.util.HashSet; 028import java.util.Iterator; 029import java.util.List; 030import java.util.Set; 031import java.util.function.Predicate; 032 033public class DeleteConflictList implements Iterable<DeleteConflict> { 034 private final List<DeleteConflict> myList = new ArrayList<>(); 035 private final Set<String> myResourceIdsMarkedForDeletion; 036 private final Set<String> myResourceIdsToIgnoreConflict; 037 private int myRemoveModCount; 038 039 /** 040 * Constructor 041 */ 042 public DeleteConflictList() { 043 myResourceIdsMarkedForDeletion = new HashSet<>(); 044 myResourceIdsToIgnoreConflict = new HashSet<>(); 045 } 046 047 /** 048 * Constructor that shares (i.e. uses the same list, as opposed to cloning it) 049 * of {@link #isResourceIdMarkedForDeletion(IIdType) resources marked for deletion} 050 */ 051 public DeleteConflictList(DeleteConflictList theParentList) { 052 myResourceIdsMarkedForDeletion = theParentList.myResourceIdsMarkedForDeletion; 053 myResourceIdsToIgnoreConflict = theParentList.myResourceIdsToIgnoreConflict; 054 } 055 056 public boolean isResourceIdMarkedForDeletion(IIdType theIdType) { 057 Validate.notNull(theIdType); 058 Validate.notBlank(theIdType.toUnqualifiedVersionless().getValue()); 059 return myResourceIdsMarkedForDeletion.contains( 060 theIdType.toUnqualifiedVersionless().getValue()); 061 } 062 063 public void setResourceIdMarkedForDeletion(IIdType theIdType) { 064 Validate.notNull(theIdType); 065 Validate.notBlank(theIdType.toUnqualifiedVersionless().getValue()); 066 myResourceIdsMarkedForDeletion.add(theIdType.toUnqualifiedVersionless().getValue()); 067 } 068 069 public boolean isResourceIdToIgnoreConflict(IIdType theIdType) { 070 Validate.notNull(theIdType); 071 Validate.notBlank(theIdType.toUnqualifiedVersionless().getValue()); 072 return myResourceIdsToIgnoreConflict.contains( 073 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, "myLastOperationWasNext is not true"); 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}