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}