1 package ca.uhn.fhir.parser;
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.isBlank;
24
25 import java.io.IOException;
26 import java.io.Reader;
27 import java.io.StringReader;
28 import java.io.StringWriter;
29 import java.io.Writer;
30 import java.util.ArrayList;
31 import java.util.HashSet;
32 import java.util.IdentityHashMap;
33 import java.util.List;
34 import java.util.Set;
35
36 import org.apache.commons.lang3.StringUtils;
37
38 import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
39 import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition;
40 import ca.uhn.fhir.context.ConfigurationException;
41 import ca.uhn.fhir.context.FhirContext;
42 import ca.uhn.fhir.context.RuntimeChildChoiceDefinition;
43 import ca.uhn.fhir.model.api.Bundle;
44 import ca.uhn.fhir.model.api.IElement;
45 import ca.uhn.fhir.model.api.IResource;
46 import ca.uhn.fhir.model.api.TagList;
47 import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
48 import ca.uhn.fhir.model.primitive.IdDt;
49
50 public abstract class BaseParser implements IParser {
51
52 private ContainedResources myContainedResources;
53 private FhirContext myContext;
54 private boolean mySuppressNarratives;
55
56 public BaseParser(FhirContext theContext) {
57 myContext = theContext;
58 }
59
60 protected String fixContainedResourceId(String theValue) {
61 if (StringUtils.isNotBlank(theValue)&&theValue.charAt(0)=='#') {
62 return theValue.substring(1);
63 }
64 return theValue;
65 }
66
67
68 private void containResourcesForEncoding(ContainedResources theContained, IResource theResource, IResource theTarget) {
69 List<ResourceReferenceDt> allElements = myContext.newTerser().getAllPopulatedChildElementsOfType(theResource, ResourceReferenceDt.class);
70
71 Set<String> allIds = new HashSet<String>();
72
73 for (IResource next : theTarget.getContained().getContainedResources()) {
74 String nextId = next.getId().getValue();
75 if (StringUtils.isNotBlank(nextId)) {
76 allIds.add(nextId);
77 }
78 }
79
80 for (ResourceReferenceDt next : allElements) {
81 IResource resource = next.getResource();
82 if (resource != null) {
83 if (resource.getId().isEmpty() || resource.getId().isLocal()) {
84 theContained.addContained(resource);
85 } else {
86 continue;
87 }
88
89 containResourcesForEncoding(theContained, resource, theTarget);
90 }
91 }
92
93 }
94
95 public void containResourcesForEncoding(IResource theResource) {
96 ContainedResources contained = new ContainedResources();
97 containResourcesForEncoding(contained, theResource, theResource);
98 myContainedResources = contained;
99 }
100
101 @Override
102 public String encodeBundleToString(Bundle theBundle) throws DataFormatException {
103 if (theBundle == null) {
104 throw new NullPointerException("Bundle can not be null");
105 }
106 StringWriter stringWriter = new StringWriter();
107 try {
108 encodeBundleToWriter(theBundle, stringWriter);
109 } catch (IOException e) {
110 throw new Error("Encountered IOException during write to string - This should not happen!");
111 }
112
113 return stringWriter.toString();
114 }
115
116 @Override
117 public String encodeResourceToString(IResource theResource) throws DataFormatException {
118 Writer stringWriter = new StringWriter();
119 try {
120 encodeResourceToWriter(theResource, stringWriter);
121 } catch (IOException e) {
122 throw new Error("Encountered IOException during write to string - This should not happen!");
123 }
124 return stringWriter.toString();
125 }
126
127 @Override
128 public String encodeTagListToString(TagList theTagList) {
129 Writer stringWriter = new StringWriter();
130 try {
131 encodeTagListToWriter(theTagList, stringWriter);
132 } catch (IOException e) {
133 throw new Error("Encountered IOException during write to string - This should not happen!");
134 }
135 return stringWriter.toString();
136 }
137
138 ContainedResources getContainedResources() {
139 return myContainedResources;
140 }
141
142
143
144
145 public boolean getSuppressNarratives() {
146 return mySuppressNarratives;
147 }
148
149 @Override
150 public Bundle parseBundle(Reader theReader) {
151 return parseBundle(null, theReader);
152 }
153
154 @Override
155 public Bundle parseBundle(String theXml) throws ConfigurationException, DataFormatException {
156 StringReader reader = new StringReader(theXml);
157 return parseBundle(reader);
158 }
159
160 @SuppressWarnings("cast")
161 @Override
162 public <T extends IResource> T parseResource(Class<T> theResourceType, String theMessageString) {
163 StringReader reader = new StringReader(theMessageString);
164 return (T) parseResource(theResourceType, reader);
165 }
166
167 @Override
168 public IResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException {
169 return parseResource(null, theReader);
170 }
171
172 @Override
173 public IResource parseResource(String theMessageString) throws ConfigurationException, DataFormatException {
174 return parseResource(null, theMessageString);
175 }
176
177 @Override
178 public TagList parseTagList(String theString) {
179 return parseTagList(new StringReader(theString));
180 }
181
182 @Override
183 public IParser setSuppressNarratives(boolean theSuppressNarratives) {
184 mySuppressNarratives = theSuppressNarratives;
185 return this;
186 }
187
188 protected void throwExceptionForUnknownChildType(BaseRuntimeChildDefinition nextChild, Class<? extends IElement> type) {
189 if (nextChild instanceof BaseRuntimeDeclaredChildDefinition) {
190 StringBuilder b = new StringBuilder();
191 b.append(((BaseRuntimeDeclaredChildDefinition) nextChild).getElementName());
192 b.append(" has type ");
193 b.append(type);
194 b.append(" but this is not a valid type for this element");
195 if (nextChild instanceof RuntimeChildChoiceDefinition) {
196 RuntimeChildChoiceDefinition choice = (RuntimeChildChoiceDefinition) nextChild;
197 b.append(" - Expected one of: " + choice.getValidChildTypes());
198 }
199 throw new DataFormatException(b.toString());
200 }
201 throw new DataFormatException(nextChild + " has no child of type " + type);
202 }
203
204 protected String determineReferenceText(ResourceReferenceDt theRef) {
205 String reference = theRef.getReference().getValue();
206 if (isBlank(reference)) {
207 if (theRef.getResource() != null) {
208 IdDt containedId = getContainedResources().getResourceId(theRef.getResource());
209 if (containedId != null && !containedId.isEmpty()) {
210 if (containedId.isLocal()) {
211 reference = containedId.getValue();
212 } else {
213 reference = "#" + containedId.getValue();
214 }
215 } else if (theRef.getResource().getId() != null && theRef.getResource().getId().hasIdPart()) {
216 reference = theRef.getResource().getId().getValue();
217 }
218 }
219 }
220 return reference;
221 }
222
223
224 static class ContainedResources {
225 private long myNextContainedId = 1;
226
227 private IdentityHashMap<IResource, IdDt> myResourceToId = new IdentityHashMap<IResource, IdDt>();
228 private List<IResource> myResources = new ArrayList<IResource>();
229
230 public void addContained(IResource theResource) {
231 if (myResourceToId.containsKey(theResource)) {
232 return;
233 }
234
235 IdDt newId;
236 if (theResource.getId().isLocal()) {
237 newId = theResource.getId();
238 } else {
239
240
241 newId = new IdDt(myNextContainedId++);
242 }
243
244 myResourceToId.put(theResource, newId);
245 myResources.add(theResource);
246 }
247
248 public List<IResource> getContainedResources() {
249 return myResources;
250 }
251
252 public IdDt getResourceId(IResource theResource) {
253 return myResourceToId.get(theResource);
254 }
255
256 public boolean isEmpty() {
257 return myResourceToId.isEmpty();
258 }
259
260 }
261
262 }