1 package ca.uhn.fhir.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.TreeSet;
28
29 import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
30 import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
31 import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
32 import ca.uhn.fhir.context.ConfigurationException;
33 import ca.uhn.fhir.context.FhirContext;
34 import ca.uhn.fhir.context.RuntimeResourceDefinition;
35 import ca.uhn.fhir.model.api.ExtensionDt;
36 import ca.uhn.fhir.model.api.IElement;
37 import ca.uhn.fhir.model.api.IResource;
38 import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
39 import ca.uhn.fhir.model.dstu.composite.ContainedDt;
40 import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
41 import ca.uhn.fhir.model.primitive.StringDt;
42 import ca.uhn.fhir.parser.DataFormatException;
43
44 public class FhirTerser {
45
46 public FhirTerser(FhirContext theContext) {
47 super();
48 myContext = theContext;
49 }
50
51 private FhirContext myContext;
52
53 public BaseRuntimeChildDefinition getDefinition(Class<? extends IResource> theResourceType, String thePath) {
54 RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
55
56 BaseRuntimeElementCompositeDefinition<?> currentDef = def;
57
58 List<String> parts = Arrays.asList(thePath.split("\\."));
59 List<String> subList = parts.subList(1, parts.size());
60 if (subList.size() < 1) {
61 throw new ConfigurationException("Invalid path: " + thePath);
62 }
63 return getDefinition(currentDef, subList);
64
65 }
66
67 private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
68 BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));
69
70 if (theSubList.size() == 1) {
71 return nextDef;
72 } else {
73 BaseRuntimeElementCompositeDefinition<?> cmp = (BaseRuntimeElementCompositeDefinition<?>) nextDef.getChildByName(theSubList.get(0));
74 return getDefinition(cmp, theSubList.subList(1, theSubList.size()));
75 }
76 }
77
78 public List<Object> getValues(IResource theResource, String thePath) {
79 RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
80
81 BaseRuntimeElementCompositeDefinition<?> currentDef = def;
82 Object currentObj = theResource;
83
84 List<String> parts = Arrays.asList(thePath.split("\\."));
85 List<String> subList = parts.subList(1, parts.size());
86 if (subList.size() < 1) {
87 throw new ConfigurationException("Invalid path: " + thePath);
88 }
89 return getValues(currentDef, currentObj, subList);
90
91 }
92
93 private List<Object> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList) {
94 String name = theSubList.get(0);
95 BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(name);
96 List<? extends IElement> values = nextDef.getAccessor().getValues(theCurrentObj);
97 List<Object> retVal = new ArrayList<Object>();
98
99 if (theSubList.size() == 1) {
100 retVal.addAll(values);
101 } else {
102 for (IElement nextElement : values) {
103 BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
104 List<?> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()));
105 retVal.addAll(foundValues);
106 }
107 }
108 return retVal;
109 }
110
111
112
113
114
115
116
117 public void visit(IResource theResource, IModelVisitor theVisitor) {
118 BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
119 visit(theResource, null, def, theVisitor);
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 public <T extends IElement> List<T> getAllPopulatedChildElementsOfType(IResource theResource, final Class<T> theType) {
142 final ArrayList<T> retVal = new ArrayList<T>();
143 BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
144 visit(theResource, null, def, new IModelVisitor() {
145 @SuppressWarnings("unchecked")
146 @Override
147 public void acceptElement(IElement theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition) {
148 if (theElement == null || theElement.isEmpty()) {
149 return;
150 }
151
152 if (theType.isAssignableFrom(theElement.getClass())) {
153 retVal.add((T) theElement);
154 }
155 }
156
157 @SuppressWarnings("unchecked")
158 @Override
159 public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, ExtensionDt theNextExt) {
160 if (theType.isAssignableFrom(theNextExt.getClass())) {
161 retVal.add((T) theNextExt);
162 }
163 if (theNextExt.getValue() != null && theType.isAssignableFrom(theNextExt.getValue().getClass())) {
164 retVal.add((T) theNextExt.getValue());
165 }
166 }
167 });
168 return retVal;
169 }
170
171 private <T extends IElement> void visit(IElement theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, IModelVisitor theCallback) {
172 theCallback.acceptElement(theElement, theChildDefinition, theDefinition);
173 addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback);
174
175
176
177
178
179 switch (theDefinition.getChildType()) {
180 case PRIMITIVE_XHTML:
181 case PRIMITIVE_DATATYPE:
182 case RESOURCE_REF:
183
184 break;
185 case RESOURCE_BLOCK:
186 case COMPOSITE_DATATYPE:
187 case RESOURCE: {
188 BaseRuntimeElementCompositeDefinition<?> childDef = (BaseRuntimeElementCompositeDefinition<?>) theDefinition;
189 for (BaseRuntimeChildDefinition nextChild : childDef.getChildrenAndExtension()) {
190 List<? extends IElement> values = nextChild.getAccessor().getValues(theElement);
191 if (values != null) {
192 for (IElement nextValue : values) {
193 if (nextValue == null) {
194 continue;
195 }
196 if (nextValue.isEmpty()) {
197 continue;
198 }
199 BaseRuntimeElementDefinition<?> childElementDef;
200 childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass());
201
202 if (childElementDef == null) {
203 StringBuilder b = new StringBuilder();
204 b.append("Found value of type[");
205 b.append(nextValue.getClass().getSimpleName());
206 b.append("] which is not valid for field[");
207 b.append(nextChild.getElementName());
208 b.append("] in ");
209 b.append(childDef.getName());
210 b.append(" - Valid types: ");
211 for (Iterator<String> iter = new TreeSet<String>(nextChild.getValidChildNames()).iterator(); iter.hasNext();) {
212 b.append(nextChild.getChildByName(iter.next()).getImplementingClass().getSimpleName());
213 if (iter.hasNext()) {
214 b.append(", ");
215 }
216 }
217 throw new DataFormatException(b.toString());
218 }
219 visit(nextValue, nextChild, childElementDef, theCallback);
220 }
221 }
222 }
223 break;
224 }
225 case CONTAINED_RESOURCES: {
226 ContainedDt value = (ContainedDt) theElement;
227 for (IResource next : value.getContainedResources()) {
228 BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(next);
229 visit(next, null, def, theCallback);
230 }
231 break;
232 }
233 case EXTENSION_DECLARED:
234 case UNDECL_EXT: {
235 throw new IllegalStateException("state should not happen: " + theDefinition.getChildType());
236 }
237 }
238 }
239
240 private <T extends IElement> void addUndeclaredExtensions(IElement theElement, BaseRuntimeElementDefinition<?> theDefinition, BaseRuntimeChildDefinition theChildDefinition, IModelVisitor theCallback) {
241 if (theElement instanceof ISupportsUndeclaredExtensions) {
242 ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement;
243 for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) {
244 theCallback.acceptUndeclaredExtension(containingElement, theChildDefinition, theDefinition, nextExt);
245 addUndeclaredExtensions(nextExt, theDefinition, theChildDefinition, theCallback);
246 }
247 }
248 }
249
250 }