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