001/*
002 * #%L
003 * HAPI FHIR - Server Framework
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.rest.server;
021
022import ca.uhn.fhir.model.primitive.InstantDt;
023import ca.uhn.fhir.rest.api.server.IBundleProvider;
024import ca.uhn.fhir.rest.server.method.ResponsePage;
025import jakarta.annotation.Nonnull;
026import org.apache.commons.lang3.builder.ToStringBuilder;
027import org.hl7.fhir.instance.model.api.IBaseResource;
028import org.hl7.fhir.instance.model.api.IPrimitiveType;
029
030import java.util.Arrays;
031import java.util.Collections;
032import java.util.Date;
033import java.util.List;
034
035public class SimpleBundleProvider implements IBundleProvider {
036
037        private final List<? extends IBaseResource> myList;
038        private final String myUuid;
039        private Integer myPreferredPageSize;
040        private Integer mySize;
041        private IPrimitiveType<Date> myPublished = InstantDt.withCurrentTime();
042        private Integer myCurrentPageOffset;
043        private Integer myCurrentPageSize;
044        private ResponsePage.ResponsePageBuilder myPageBuilder;
045
046        /**
047         * The actual number of resources we have tried to fetch.
048         * This value will only be populated if there is a
049         * _count query parameter provided.
050         * In which case, it will be the total number of resources
051         * we tried to fetch (should be _count + 1 for accurate paging)
052         */
053        private int myTotalResourcesRequestedReturned = -1;
054
055        /**
056         * Constructor
057         */
058        public SimpleBundleProvider(IBaseResource theResource) {
059                this(Collections.singletonList(theResource));
060        }
061
062        /**
063         * Create an empty bundle
064         */
065        public SimpleBundleProvider() {
066                this(Collections.emptyList());
067        }
068
069        /**
070         * Constructor
071         */
072        public SimpleBundleProvider(List<? extends IBaseResource> theList) {
073                this(theList, null);
074        }
075
076        /**
077         * Constructor
078         *
079         * @since 6.8.0
080         */
081        public SimpleBundleProvider(IBaseResource... theList) {
082                this(Arrays.asList(theList), null);
083        }
084
085        public SimpleBundleProvider(List<? extends IBaseResource> theList, String theUuid) {
086                myList = theList;
087                myUuid = theUuid;
088                setSize(theList.size());
089        }
090
091        /**
092         * Constructor that provides only a size but no actual data (useful for _count = 0)
093         */
094        public SimpleBundleProvider(int theSize) {
095                myList = Collections.emptyList();
096                myUuid = null;
097                setSize(theSize);
098        }
099
100        /**
101         * @since 5.5.0
102         */
103        @Override
104        public Integer getCurrentPageOffset() {
105                return myCurrentPageOffset;
106        }
107
108        /**
109         * @since 5.5.0
110         */
111        public void setCurrentPageOffset(Integer theCurrentPageOffset) {
112                myCurrentPageOffset = theCurrentPageOffset;
113        }
114
115        /**
116         * @since 5.5.0
117         */
118        @Override
119        public Integer getCurrentPageSize() {
120                return myCurrentPageSize;
121        }
122
123        /**
124         * @since 5.5.0
125         */
126        public void setCurrentPageSize(Integer theCurrentPageSize) {
127                myCurrentPageSize = theCurrentPageSize;
128        }
129
130        /**
131         * Returns the results stored in this provider
132         */
133        protected List<? extends IBaseResource> getList() {
134                return myList;
135        }
136
137        @Override
138        public IPrimitiveType<Date> getPublished() {
139                return myPublished;
140        }
141
142        /**
143         * By default this class uses the object creation date/time (for this object)
144         * to determine {@link #getPublished() the published date} but this
145         * method may be used to specify an alternate date/time
146         */
147        public void setPublished(IPrimitiveType<Date> thePublished) {
148                myPublished = thePublished;
149        }
150
151        @SuppressWarnings("unchecked")
152        @Nonnull
153        @Override
154        public List<IBaseResource> getResources(
155                        int theFromIndex, int theToIndex, @Nonnull ResponsePage.ResponsePageBuilder theResponsePageBuilder) {
156                theResponsePageBuilder.setTotalRequestedResourcesFetched(myTotalResourcesRequestedReturned);
157                return (List<IBaseResource>)
158                                myList.subList(Math.min(theFromIndex, myList.size()), Math.min(theToIndex, myList.size()));
159        }
160
161        @Override
162        public String getUuid() {
163                return myUuid;
164        }
165
166        public void setTotalResourcesRequestedReturned(int theAmount) {
167                myTotalResourcesRequestedReturned = theAmount;
168        }
169
170        /**
171         * Defaults to null
172         */
173        @Override
174        public Integer preferredPageSize() {
175                return myPreferredPageSize;
176        }
177
178        /**
179         * Sets the preferred page size to be returned by {@link #preferredPageSize()}.
180         * Default is <code>null</code>.
181         */
182        public void setPreferredPageSize(Integer thePreferredPageSize) {
183                myPreferredPageSize = thePreferredPageSize;
184        }
185
186        /**
187         * Sets the total number of results, if this provider
188         * corresponds to a single page within a larger search result
189         */
190        public SimpleBundleProvider setSize(Integer theSize) {
191                mySize = theSize;
192                return this;
193        }
194
195        @Override
196        public Integer size() {
197                return mySize;
198        }
199
200        @Override
201        public String toString() {
202                return new ToStringBuilder(this).append("mySize", mySize).toString();
203        }
204}