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}