1 package ca.uhn.fhir.model.api;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import static org.apache.commons.lang3.StringUtils.*;
24
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.commons.lang3.Validate;
32 import org.apache.commons.lang3.builder.ToStringBuilder;
33 import org.apache.commons.lang3.builder.ToStringStyle;
34
35 import ca.uhn.fhir.context.FhirContext;
36 import ca.uhn.fhir.context.RuntimeResourceDefinition;
37 import ca.uhn.fhir.model.primitive.IdDt;
38 import ca.uhn.fhir.model.primitive.InstantDt;
39 import ca.uhn.fhir.model.primitive.IntegerDt;
40 import ca.uhn.fhir.model.primitive.StringDt;
41 import ca.uhn.fhir.rest.server.Constants;
42 import ca.uhn.fhir.util.UrlUtil;
43
44 public class Bundle extends BaseBundle {
45
46 private StringDt myBundleId;
47
48 private TagList myCategories;
49 private List<BundleEntry> myEntries;
50 private volatile transient Map<IdDt, IResource> myIdToEntries;
51 private StringDt myLinkBase;
52 private StringDt myLinkFirst;
53 private StringDt myLinkLast;
54 private StringDt myLinkNext;
55 private StringDt myLinkPrevious;
56 private StringDt myLinkSelf;
57 private InstantDt myPublished;
58 private StringDt myTitle;
59 private IntegerDt myTotalResults;
60 private InstantDt myUpdated;
61
62
63
64
65 public Tag addCategory() {
66 Tag retVal = new Tag();
67 getCategories().add(retVal);
68 return retVal;
69 }
70
71 public void addCategory(String theScheme, String theTerm, String theLabel) {
72 getCategories().add(new Tag(theScheme, theTerm, theLabel));
73 }
74
75
76 public void addCategory(Tag theTag) {
77 getCategories().add(theTag);
78 }
79
80
81
82
83 public BundleEntry addEntry() {
84 BundleEntry retVal = new BundleEntry();
85 getEntries().add(retVal);
86 return retVal;
87 }
88
89
90
91
92
93
94
95 public void addEntry(BundleEntry theBundleEntry) {
96 Validate.notNull(theBundleEntry, "theBundleEntry can not be null");
97 getEntries().add(theBundleEntry);
98 }
99
100
101
102
103
104
105
106
107 public BundleEntry addResource(IResource theResource, FhirContext theContext, String theServerBase) {
108 BundleEntry entry = addEntry();
109 entry.setResource(theResource);
110
111 RuntimeResourceDefinition def = theContext.getResourceDefinition(theResource);
112
113 String title = ResourceMetadataKeyEnum.TITLE.get(theResource);
114 if (title != null) {
115 entry.getTitle().setValue(title);
116 } else {
117 entry.getTitle().setValue(def.getName() + " " + StringUtils.defaultString(theResource.getId().getValue(), "(no ID)"));
118 }
119
120 if (theResource.getId() != null && StringUtils.isNotBlank(theResource.getId().getValue())) {
121
122 StringBuilder b = new StringBuilder();
123 b.append(theServerBase);
124 if (b.length() > 0 && b.charAt(b.length() - 1) != '/') {
125 b.append('/');
126 }
127 b.append(def.getName());
128 b.append('/');
129 String resId = theResource.getId().getIdPart();
130 b.append(resId);
131
132 entry.getId().setValue(b.toString());
133
134 if (isNotBlank(theResource.getId().getVersionIdPart())) {
135 b.append('/');
136 b.append(Constants.PARAM_HISTORY);
137 b.append('/');
138 b.append(theResource.getId().getVersionIdPart());
139 } else {
140 IdDt versionId = (IdDt) ResourceMetadataKeyEnum.VERSION_ID.get(theResource);
141 if (versionId != null) {
142 b.append('/');
143 b.append(Constants.PARAM_HISTORY);
144 b.append('/');
145 b.append(versionId.getValue());
146 }
147 }
148
149 String qualifiedId = b.toString();
150 entry.getLinkSelf().setValue(qualifiedId);
151
152
153
154 String linkSearch = ResourceMetadataKeyEnum.LINK_SEARCH.get(theResource);
155 if (isNotBlank(linkSearch)) {
156 if (!UrlUtil.isAbsolute(linkSearch)) {
157 linkSearch = (theServerBase + "/" + linkSearch);
158 }
159 entry.getLinkSearch().setValue(linkSearch);
160 }
161
162 String linkAlternate = ResourceMetadataKeyEnum.LINK_ALTERNATE.get(theResource);
163 if (isNotBlank(linkAlternate)) {
164 if (!UrlUtil.isAbsolute(linkAlternate)) {
165 linkSearch = (theServerBase + "/" + linkAlternate);
166 }
167 entry.getLinkAlternate().setValue(linkSearch);
168 }
169
170 }
171
172 InstantDt published = ResourceMetadataKeyEnum.PUBLISHED.get(theResource);
173 if (published == null) {
174 entry.getPublished().setToCurrentTimeInLocalTimeZone();
175 } else {
176 entry.setPublished(published);
177 }
178
179 InstantDt updated = ResourceMetadataKeyEnum.UPDATED.get(theResource);
180 if (updated != null) {
181 entry.setUpdated(updated);
182 }
183
184 InstantDt deleted = ResourceMetadataKeyEnum.DELETED_AT.get(theResource);
185 if (deleted != null) {
186 entry.setDeleted(deleted);
187 }
188
189 IdDt previous = ResourceMetadataKeyEnum.PREVIOUS_ID.get(theResource);
190 if (previous != null) {
191 entry.getLinkAlternate().setValue(previous.withServerBase(theServerBase, def.getName()));
192 }
193
194 TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(theResource);
195 if (tagList != null) {
196 for (Tag nextTag : tagList) {
197 entry.addCategory(nextTag);
198 }
199 }
200
201 return entry;
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 public StringDt getBundleId() {
231 if (myBundleId == null) {
232 myBundleId = new StringDt();
233 }
234 return myBundleId;
235 }
236
237 public TagList getCategories() {
238 if (myCategories == null) {
239 myCategories = new TagList();
240 }
241 return myCategories;
242 }
243
244 public List<BundleEntry> getEntries() {
245 if (myEntries == null) {
246 myEntries = new ArrayList<BundleEntry>();
247 }
248 return myEntries;
249 }
250
251 public StringDt getLinkBase() {
252 if (myLinkBase == null) {
253 myLinkBase = new StringDt();
254 }
255 return myLinkBase;
256 }
257
258 public StringDt getLinkFirst() {
259 if (myLinkFirst == null) {
260 myLinkFirst = new StringDt();
261 }
262 return myLinkFirst;
263 }
264
265 public StringDt getLinkLast() {
266 if (myLinkLast == null) {
267 myLinkLast = new StringDt();
268 }
269 return myLinkLast;
270 }
271
272 public StringDt getLinkNext() {
273 if (myLinkNext == null) {
274 myLinkNext = new StringDt();
275 }
276 return myLinkNext;
277 }
278
279 public StringDt getLinkPrevious() {
280 if (myLinkPrevious == null) {
281 myLinkPrevious = new StringDt();
282 }
283 return myLinkPrevious;
284 }
285
286 public StringDt getLinkSelf() {
287 if (myLinkSelf == null) {
288 myLinkSelf = new StringDt();
289 }
290 return myLinkSelf;
291 }
292
293 public InstantDt getPublished() {
294 if (myPublished == null) {
295 myPublished = new InstantDt();
296 }
297 return myPublished;
298 }
299
300
301
302
303
304
305
306
307
308
309
310
311
312 public IResource getResourceById(IdDt theId) {
313 Map<IdDt, IResource> map = myIdToEntries;
314 if (map == null) {
315 map = new HashMap<IdDt, IResource>();
316 for (BundleEntry next : this.getEntries()) {
317 if (next.getId().isEmpty() == false) {
318 map.put(next.getId().toUnqualified(), next.getResource());
319 }
320 }
321 myIdToEntries = map;
322 }
323 return map.get(theId.toUnqualified());
324 }
325
326
327
328
329 public <T extends IResource> List<T> getResources(Class<T> theClass) {
330 ArrayList<T> retVal = new ArrayList<T>();
331 for (BundleEntry next : getEntries()) {
332 if (next.getResource() != null && theClass.isAssignableFrom(next.getResource().getClass())) {
333 @SuppressWarnings("unchecked")
334 T resource = (T) next.getResource();
335 retVal.add(resource);
336 }
337 }
338 return retVal;
339 }
340
341 public StringDt getTitle() {
342 if (myTitle == null) {
343 myTitle = new StringDt();
344 }
345 return myTitle;
346 }
347
348 public IntegerDt getTotalResults() {
349 if (myTotalResults == null) {
350 myTotalResults = new IntegerDt();
351 }
352 return myTotalResults;
353 }
354
355 public InstantDt getUpdated() {
356 if (myUpdated == null) {
357 myUpdated = new InstantDt();
358 }
359 return myUpdated;
360 }
361
362
363
364
365 @Override
366 public boolean isEmpty() {
367 return getEntries().isEmpty();
368 }
369
370 public void setCategories(TagList theCategories) {
371 myCategories = theCategories;
372 }
373
374 public void setPublished(InstantDt thePublished) {
375 myPublished = thePublished;
376 }
377
378
379
380
381 public int size() {
382 return getEntries().size();
383 }
384
385 public List<IResource> toListOfResources() {
386 ArrayList<IResource> retVal = new ArrayList<IResource>();
387 for (BundleEntry next : getEntries()) {
388 if (next.getResource() != null) {
389 retVal.add(next.getResource());
390 }
391 }
392 return retVal;
393 }
394
395 @Override
396 public String toString() {
397 ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
398 b.append(getEntries().size() + " entries");
399 b.append("id", getId());
400 return b.toString();
401 }
402
403 public static Bundle withResources(List<IResource> theResources, FhirContext theContext, String theServerBase) {
404 Bundle retVal = new Bundle();
405 for (IResource next : theResources) {
406 retVal.addResource(next, theContext, theServerBase);
407 }
408 return retVal;
409 }
410
411 public static Bundle withSingleResource(IResource theResource) {
412 Bundle retVal = new Bundle();
413 retVal.addEntry().setResource(theResource);
414 return retVal;
415 }
416
417 }