View Javadoc
1   package ca.uhn.fhir.parser;
2   
3   /*
4    * #%L
5    * HAPI FHIR - Core Library
6    * %%
7    * Copyright (C) 2014 - 2018 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   * http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  import static org.apache.commons.lang3.StringUtils.*;
23  
24  import java.util.*;
25  
26  import javax.xml.stream.events.StartElement;
27  import javax.xml.stream.events.XMLEvent;
28  
29  import org.apache.commons.lang3.StringUtils;
30  import org.apache.commons.lang3.Validate;
31  import org.apache.commons.lang3.tuple.Pair;
32  import org.hl7.fhir.instance.model.api.*;
33  
34  import ca.uhn.fhir.context.*;
35  import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IMutator;
36  import ca.uhn.fhir.model.api.*;
37  import ca.uhn.fhir.model.api.annotation.Child;
38  import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
39  import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
40  import ca.uhn.fhir.model.primitive.*;
41  import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType;
42  import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
43  import ca.uhn.fhir.util.*;
44  
45  class ParserState<T> {
46  
47  	private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
48  
49  	private List<String> myComments = new ArrayList<String>(2);
50  	private final FhirContext myContext;
51  	private final IParserErrorHandler myErrorHandler;
52  	private final boolean myJsonMode;
53  	private T myObject;
54  	private final IParser myParser;
55  	private IBase myPreviousElement;
56  	private BaseState myState;
57  
58  	private ParserState(IParser theParser, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
59  		myParser = theParser;
60  		myContext = theContext;
61  		myJsonMode = theJsonMode;
62  		myErrorHandler = theErrorHandler;
63  	}
64  
65  	public void attributeValue(String theName, String theValue) throws DataFormatException {
66  		myState.attributeValue(theName, theValue);
67  	}
68  
69  	public void commentPost(String theCommentText) {
70  		if (myPreviousElement != null) {
71  			myPreviousElement.getFormatCommentsPost().add(theCommentText);
72  		}
73  	}
74  
75  	public void commentPre(String theCommentText) {
76  		if (myState.getCurrentElement() != null) {
77  			IBase element = myState.getCurrentElement();
78  			element.getFormatCommentsPre().add(theCommentText);
79  		}
80  	}
81  
82  	public boolean elementIsRepeating(String theChildName) {
83  		return myState.elementIsRepeating(theChildName);
84  	}
85  
86  	public void endingElement() throws DataFormatException {
87  		myState.endingElement();
88  	}
89  
90  	public void enteringNewElement(String theNamespaceUri, String theName) throws DataFormatException {
91  		myState.enteringNewElement(theNamespaceUri, theName);
92  	}
93  
94  	public void enteringNewElementExtension(StartElement theElem, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) {
95  		myState.enteringNewElementExtension(theElem, theUrlAttr, theIsModifier, baseServerUrl);
96  	}
97  
98  	public T getObject() {
99  		return myObject;
100 	}
101 
102 	public boolean isPreResource() {
103 		return myState.isPreResource();
104 	}
105 
106 	private Object newContainedDt(IResource theTarget) {
107 		return ReflectionUtil.newInstance(theTarget.getStructureFhirVersionEnum().getVersionImplementation().getContainedType());
108 	}
109 
110 	@SuppressWarnings("unchecked")
111 	private void pop() {
112 		myPreviousElement = myState.getCurrentElement();
113 		if (myState.myStack != null) {
114 			myState = myState.myStack;
115 			myState.wereBack();
116 		} else {
117 			myObject = (T) myState.getCurrentElement();
118 			myState = null;
119 		}
120 	}
121 
122 	private void push(BaseState theState) {
123 		theState.setStack(myState);
124 		myState = theState;
125 		if (myComments.isEmpty() == false) {
126 			if (myState.getCurrentElement() != null) {
127 				myState.getCurrentElement().getFormatCommentsPre().addAll(myComments);
128 				myComments.clear();
129 			}
130 		}
131 	}
132 
133 
134 	public void string(String theData) {
135 		myState.string(theData);
136 	}
137 
138 	public boolean verifyNamespace(String theExpect, String theActual) {
139 		if (myJsonMode) {
140 			return true;
141 		}
142 		return StringUtils.equals(theExpect, theActual);
143 	}
144 
145 	/**
146 	 * Invoked after any new XML event is individually processed, containing a copy of the XML event. This is basically
147 	 * intended for embedded XHTML content
148 	 */
149 	public void xmlEvent(XMLEvent theNextEvent) {
150 		if (myState != null) {
151 			myState.xmlEvent(theNextEvent);
152 		}
153 	}
154 
155 
156 	/**
157 	 * @param theResourceType
158 	 *           May be null
159 	 */
160 	static <T extends IBaseResource> ParserState<T> getPreResourceInstance(IParser theParser, Class<T> theResourceType, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler)
161 			throws DataFormatException {
162 		ParserState<T> retVal = new ParserState<T>(theParser, theContext, theJsonMode, theErrorHandler);
163 		if (theResourceType == null) {
164 			if (theContext.getVersion().getVersion().isRi()) {
165 				retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
166 			} else {
167 				retVal.push(retVal.new PreResourceStateHapi(theResourceType));
168 			}
169 		} else {
170 			if (IResource.class.isAssignableFrom(theResourceType)) {
171 				retVal.push(retVal.new PreResourceStateHapi(theResourceType));
172 			} else {
173 				retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
174 			}
175 		}
176 		return retVal;
177 	}
178 
179 	static ParserState<TagList> getPreTagListInstance(IParser theParser, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
180 		ParserState<TagList> retVal = new ParserState<TagList>(theParser, theContext, theJsonMode, theErrorHandler);
181 		retVal.push(retVal.new PreTagListState());
182 		return retVal;
183 	}
184 
185 
186 
187 	private abstract class BaseState {
188 
189 		private PreResourceState myPreResourceState;
190 		private BaseState myStack;
191 
192 		public BaseState(PreResourceState thePreResourceState) {
193 			super();
194 			myPreResourceState = thePreResourceState;
195 		}
196 
197 		/**
198 		 * @param theValue
199 		 *           The attribute value
200 		 */
201 		public void attributeValue(String theName, String theValue) throws DataFormatException {
202 			myErrorHandler.unknownAttribute(null, theName);
203 		}
204 
205 		public boolean elementIsRepeating(String theChildName) {
206 			return false;
207 		}
208 
209 		public void endingElement() throws DataFormatException {
210 			// ignore by default
211 		}
212 
213 		/**
214 		 * @param theNamespaceUri
215 		 *           The XML namespace (if XML) or null
216 		 */
217 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
218 			myErrorHandler.unknownElement(null, theLocalPart);
219 		}
220 
221 		/**
222 		 * Default implementation just handles undeclared extensions
223 		 */
224 		@SuppressWarnings("unused")
225 		public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) {
226 			if (myPreResourceState != null && getCurrentElement() instanceof ISupportsUndeclaredExtensions) {
227 				ExtensionDt newExtension = new ExtensionDt(theIsModifier);
228 				newExtension.setUrl(theUrlAttr);
229 				ISupportsUndeclaredExtensions elem = (ISupportsUndeclaredExtensions) getCurrentElement();
230 				elem.addUndeclaredExtension(newExtension);
231 				ExtensionState newState = new ExtensionState(myPreResourceState, newExtension);
232 				push(newState);
233 			} else {
234 				if (theIsModifier == false) {
235 					if (getCurrentElement() instanceof IBaseHasExtensions) {
236 						IBaseExtension<?, ?> ext = ((IBaseHasExtensions) getCurrentElement()).addExtension();
237 						ext.setUrl(theUrlAttr);
238 						ParserState<T>.ExtensionState newState = new ExtensionState(myPreResourceState, ext);
239 						push(newState);
240 					} else {
241 						logAndSwallowUnexpectedElement("extension");
242 					}
243 				} else {
244 					if (getCurrentElement() instanceof IBaseHasModifierExtensions) {
245 						IBaseExtension<?, ?> ext = ((IBaseHasModifierExtensions) getCurrentElement()).addModifierExtension();
246 						ext.setUrl(theUrlAttr);
247 						ParserState<T>.ExtensionState newState = new ExtensionState(myPreResourceState, ext);
248 						push(newState);
249 					} else {
250 						logAndSwallowUnexpectedElement("modifierExtension");
251 					}
252 				}
253 			}
254 		}
255 
256 		protected IBase getCurrentElement() {
257 			return null;
258 		}
259 
260 		public PreResourceState getPreResourceState() {
261 			return myPreResourceState;
262 		}
263 
264 		public boolean isPreResource() {
265 			return false;
266 		}
267 
268 		protected void logAndSwallowUnexpectedElement(String theLocalPart) {
269 			myErrorHandler.unknownElement(null, theLocalPart);
270 			push(new SwallowChildrenWholeState(getPreResourceState()));
271 		}
272 
273 		public void setStack(BaseState theState) {
274 			myStack = theState;
275 		}
276 
277 		/**
278 		 * @param theData
279 		 *           The string value
280 		 */
281 		public void string(String theData) {
282 			// ignore by default
283 		}
284 
285 		public void wereBack() {
286 			// allow an implementor to override
287 		}
288 
289 		/**
290 		 * @param theNextEvent
291 		 *           The XML event
292 		 */
293 		public void xmlEvent(XMLEvent theNextEvent) {
294 			// ignore
295 		}
296 
297 	}
298 
299 	private class ContainedResourcesStateHapi extends PreResourceState {
300 
301 		public ContainedResourcesStateHapi(PreResourceState thePreResourcesState) {
302 			super(thePreResourcesState, ((IResource) thePreResourcesState.myInstance).getStructureFhirVersionEnum());
303 		}
304 
305 		@Override
306 		public void endingElement() throws DataFormatException {
307 			pop();
308 		}
309 
310 		@Override
311 		protected void populateTarget() {
312 			// nothing
313 		}
314 
315 		@Override
316 		public void wereBack() {
317 			super.wereBack();
318 
319 			IResource res = (IResource) getCurrentElement();
320 			assert res != null;
321 			if (res.getId() == null || res.getId().isEmpty()) {
322 				// If there is no ID, we don't keep the resource because it's useless (contained resources
323 				// need an ID to be referred to)
324 				myErrorHandler.containedResourceWithNoId(null);
325 			} else {
326 				if (!res.getId().isLocal()) {
327 					res.setId(new IdDt('#' + res.getId().getIdPart()));
328 				}
329 				getPreResourceState().getContainedResources().put(res.getId().getValueAsString(), res);
330 			}
331 			IResource preResCurrentElement = (IResource) getPreResourceState().getCurrentElement();
332 
333 			@SuppressWarnings("unchecked")
334 			List<IResource> containedResources = (List<IResource>) preResCurrentElement.getContained().getContainedResources();
335 			containedResources.add(res);
336 
337 		}
338 
339 	}
340 
341 	private class ContainedResourcesStateHl7Org extends PreResourceState {
342 
343 		public ContainedResourcesStateHl7Org(PreResourceState thePreResourcesState) {
344 			super(thePreResourcesState, thePreResourcesState.myParentVersion);
345 		}
346 
347 		@Override
348 		public void endingElement() throws DataFormatException {
349 			pop();
350 		}
351 
352 		@Override
353 		protected void populateTarget() {
354 			// nothing
355 		}
356 
357 		@Override
358 		public void wereBack() {
359 			super.wereBack();
360 
361 			IBaseResource res = getCurrentElement();
362 			assert res != null;
363 			if (res.getIdElement() == null || res.getIdElement().isEmpty()) {
364 				// If there is no ID, we don't keep the resource because it's useless (contained resources
365 				// need an ID to be referred to)
366 				myErrorHandler.containedResourceWithNoId(null);
367 			} else {
368 				res.getIdElement().setValue('#' + res.getIdElement().getIdPart());
369 				getPreResourceState().getContainedResources().put(res.getIdElement().getValue(), res);
370 			}
371 
372 			IBaseResource preResCurrentElement = getPreResourceState().getCurrentElement();
373 			RuntimeResourceDefinition def = myContext.getResourceDefinition(preResCurrentElement);
374 			def.getChildByName("contained").getMutator().addValue(preResCurrentElement, res);
375 		}
376 
377 	}
378 
379 	private class DeclaredExtensionState extends BaseState {
380 
381 		private IBase myChildInstance;
382 		private RuntimeChildDeclaredExtensionDefinition myDefinition;
383 		private IBase myParentInstance;
384 		private PreResourceState myPreResourceState;
385 
386 		public DeclaredExtensionState(PreResourceState thePreResourceState, RuntimeChildDeclaredExtensionDefinition theDefinition, IBase theParentInstance) {
387 			super(thePreResourceState);
388 			myPreResourceState = thePreResourceState;
389 			myDefinition = theDefinition;
390 			myParentInstance = theParentInstance;
391 		}
392 
393 		@Override
394 		public void attributeValue(String theName, String theValue) throws DataFormatException {
395 			if (theName.equals("url")) {
396 				// This can be ignored
397 				return;
398 			}
399 			super.attributeValue(theName, theValue);
400 		}
401 
402 		@Override
403 		public void endingElement() throws DataFormatException {
404 			pop();
405 		}
406 
407 		@Override
408 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
409 			BaseRuntimeElementDefinition<?> target = myDefinition.getChildByName(theLocalPart);
410 			if (target == null) {
411 				myErrorHandler.unknownElement(null, theLocalPart);
412 				push(new SwallowChildrenWholeState(getPreResourceState()));
413 				return;
414 			}
415 
416 			switch (target.getChildType()) {
417 			case COMPOSITE_DATATYPE: {
418 				BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
419 				ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(myDefinition.getInstanceConstructorArguments());
420 				myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
421 				ElementCompositeState newState = new ElementCompositeState(myPreResourceState, theLocalPart, compositeTarget, newChildInstance);
422 				push(newState);
423 				return;
424 			}
425       case ID_DATATYPE:
426 			case PRIMITIVE_DATATYPE: {
427 				RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
428 				IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance(myDefinition.getInstanceConstructorArguments());
429 				myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
430 				PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
431 				push(newState);
432 				return;
433 			}
434 			case PRIMITIVE_XHTML:
435 			case RESOURCE:
436 			case RESOURCE_BLOCK:
437 			case UNDECL_EXT:
438 			case EXTENSION_DECLARED:
439 			default:
440 				break;
441 			}
442 		}
443 
444 		@Override
445 		public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) {
446 			RuntimeChildDeclaredExtensionDefinition declaredExtension = myDefinition.getChildExtensionForUrl(theUrlAttr);
447 			if (declaredExtension != null) {
448 				if (myChildInstance == null) {
449 					myChildInstance = myDefinition.newInstance();
450 					myDefinition.getMutator().addValue(myParentInstance, myChildInstance);
451 				}
452 				BaseState newState = new DeclaredExtensionState(getPreResourceState(), declaredExtension, myChildInstance);
453 				push(newState);
454 			} else {
455 				super.enteringNewElementExtension(theElement, theUrlAttr, theIsModifier, baseServerUrl);
456 			}
457 		}
458 
459 		@Override
460 		protected IBase getCurrentElement() {
461 			return myParentInstance;
462 		}
463 
464 	}
465 
466 	private class ElementCompositeState extends BaseState {
467 
468 		private BaseRuntimeElementCompositeDefinition<?> myDefinition;
469 		private IBase myInstance;
470 		private Set<String> myParsedNonRepeatableNames = new HashSet<String>();
471 		private String myElementName;
472 
473 		public ElementCompositeState(PreResourceState thePreResourceState, String theElementName, BaseRuntimeElementCompositeDefinition<?> theDef, IBase theInstance) {
474 			super(thePreResourceState);
475 			myDefinition = theDef;
476 			myInstance = theInstance;
477 			myElementName = theElementName;
478 		}
479 
480 		@Override
481 		public void attributeValue(String theName, String theValue) throws DataFormatException {
482 			if ("id".equals(theName)) {
483 				if (myInstance instanceof IIdentifiableElement) {
484 					((IIdentifiableElement) myInstance).setElementSpecificId((theValue));
485 				} else if (myInstance instanceof IBaseElement) {
486 					((IBaseElement) myInstance).setId(theValue);
487 				} else if (myInstance instanceof IBaseResource) {
488 					new IdDt(theValue).applyTo((IBaseResource) myInstance);
489 				}
490 			} else if ("url".equals(theName) && myInstance instanceof ExtensionDt) {
491 				((ExtensionDt) myInstance).setUrl(theValue);
492 			} else {
493 				if (myJsonMode) {
494 					myErrorHandler.incorrectJsonType(null, myElementName, ValueType.OBJECT, null, ValueType.SCALAR, ScalarType.STRING);
495 				} else {
496 					myErrorHandler.unknownAttribute(null, theName);
497 				}
498 			}
499 		}
500 
501 		@Override
502 		public boolean elementIsRepeating(String theChildName) {
503 			BaseRuntimeChildDefinition child = myDefinition.getChildByName(theChildName);
504 			if (child == null) {
505 				return false;
506 			}
507 			return child.getMax() > 1 || child.getMax() == Child.MAX_UNLIMITED;
508 		}
509 
510 		@Override
511 		public void endingElement() {
512 			pop();
513 		}
514 
515 		@Override
516 		public void enteringNewElement(String theNamespace, String theChildName) throws DataFormatException {
517 			BaseRuntimeChildDefinition child = myDefinition.getChildByName(theChildName);
518 			if (child == null) {
519 				if (theChildName.equals("id")) {
520 					if (getCurrentElement() instanceof IIdentifiableElement) {
521 						push(new IdentifiableElementIdState(getPreResourceState(), (IIdentifiableElement) getCurrentElement()));
522 						return;
523 					}
524 				}
525 
526 				/*
527 				 * This means we've found an element that doesn't exist on the structure. If the error handler doesn't throw
528 				 * an exception, swallow the element silently along with any child elements
529 				 */
530 				myErrorHandler.unknownElement(null, theChildName);
531 				push(new SwallowChildrenWholeState(getPreResourceState()));
532 				return;
533 			}
534 
535 			if ((child.getMax() == 0 || child.getMax() == 1) && !myParsedNonRepeatableNames.add(theChildName)) {
536 				myErrorHandler.unexpectedRepeatingElement(null, theChildName);
537 				push(new SwallowChildrenWholeState(getPreResourceState()));
538 				return;
539 			}
540 
541 			BaseRuntimeElementDefinition<?> target = child.getChildByName(theChildName);
542 			if (target == null) {
543 				// This is a bug with the structures and shouldn't happen..
544 				throw new DataFormatException("Found unexpected element '" + theChildName + "' in parent element '" + myDefinition.getName() + "'. Valid names are: " + child.getValidChildNames());
545 			}
546 
547 			switch (target.getChildType()) {
548 			case COMPOSITE_DATATYPE: {
549 				BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
550 				ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(child.getInstanceConstructorArguments());
551 				child.getMutator().addValue(myInstance, newChildInstance);
552 				ParserState<T>.ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theChildName, compositeTarget, newChildInstance);
553 				push(newState);
554 				return;
555 			}
556 			case ID_DATATYPE:
557 			case PRIMITIVE_DATATYPE: {
558 				RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
559 				IPrimitiveType<?> newChildInstance;
560 				newChildInstance = primitiveTarget.newInstance(child.getInstanceConstructorArguments());
561 				child.getMutator().addValue(myInstance, newChildInstance);
562 				PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
563 				push(newState);
564 				return;
565 			}
566 			case RESOURCE_BLOCK: {
567 				RuntimeResourceBlockDefinition blockTarget = (RuntimeResourceBlockDefinition) target;
568 				IBase newBlockInstance = blockTarget.newInstance();
569 				child.getMutator().addValue(myInstance, newBlockInstance);
570 				ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theChildName, blockTarget, newBlockInstance);
571 				push(newState);
572 				return;
573 			}
574 			case PRIMITIVE_XHTML: {
575 				RuntimePrimitiveDatatypeNarrativeDefinition xhtmlTarget = (RuntimePrimitiveDatatypeNarrativeDefinition) target;
576 				XhtmlDt newDt = xhtmlTarget.newInstance();
577 				child.getMutator().addValue(myInstance, newDt);
578 				XhtmlState state = new XhtmlState(getPreResourceState(), newDt, true);
579 				push(state);
580 				return;
581 			}
582 			case PRIMITIVE_XHTML_HL7ORG: {
583 				RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition xhtmlTarget = (RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition) target;
584 				IBaseXhtml newDt = xhtmlTarget.newInstance();
585 				child.getMutator().addValue(myInstance, newDt);
586 				XhtmlStateHl7Org state = new XhtmlStateHl7Org(getPreResourceState(), newDt);
587 				push(state);
588 				return;
589 			}
590 			case CONTAINED_RESOURCES: {
591 				List<? extends IBase> values = child.getAccessor().getValues(myInstance);
592 				Object newDt;
593 				if (values == null || values.isEmpty() || values.get(0) == null) {
594 					newDt = newContainedDt((IResource) getPreResourceState().myInstance);
595 					child.getMutator().addValue(myInstance, (IBase) newDt);
596 				} else {
597 					newDt = values.get(0);
598 				}
599 				ContainedResourcesStateHapi state = new ContainedResourcesStateHapi(getPreResourceState());
600 				push(state);
601 				return;
602 			}
603 			case CONTAINED_RESOURCE_LIST: {
604 				ContainedResourcesStateHl7Org state = new ContainedResourcesStateHl7Org(getPreResourceState());
605 				push(state);
606 				return;
607 			}
608 			case RESOURCE: {
609 				if (myInstance instanceof IAnyResource || myInstance instanceof IBaseBackboneElement || myInstance instanceof IBaseElement) {
610 					ParserState<T>.PreResourceStateHl7Org state = new PreResourceStateHl7Org(myInstance, child.getMutator(), null);
611 					push(state);
612 				} else {
613 					ParserState<T>.PreResourceStateHapi state = new PreResourceStateHapi(myInstance, child.getMutator(), null);
614 					push(state);
615 				}
616 				return;
617 			}
618 			case UNDECL_EXT:
619 			case EXTENSION_DECLARED: {
620 				// Throw an exception because this shouldn't happen here
621 				break;
622 			}
623 			}
624 
625 			throw new DataFormatException("Illegal resource position: " + target.getChildType());
626 		}
627 
628 		@Override
629 		public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) {
630 			RuntimeChildDeclaredExtensionDefinition declaredExtension = myDefinition.getDeclaredExtension(theUrlAttr, baseServerUrl);
631 			if (declaredExtension != null) {
632 				BaseState newState = new DeclaredExtensionState(getPreResourceState(), declaredExtension, myInstance);
633 				push(newState);
634 			} else {
635 				super.enteringNewElementExtension(theElement, theUrlAttr, theIsModifier, baseServerUrl);
636 			}
637 		}
638 
639 		@Override
640 		protected IBase getCurrentElement() {
641 			return myInstance;
642 		}
643 
644 	}
645 
646 	public class ElementIdState extends BaseState {
647 
648 		private IBaseElement myElement;
649 
650 		public ElementIdState(ParserState<T>.PreResourceState thePreResourceState, IBaseElement theElement) {
651 			super(thePreResourceState);
652 			myElement = theElement;
653 		}
654 
655 		@Override
656 		public void attributeValue(String theName, String theValue) throws DataFormatException {
657 			myElement.setId(theValue);
658 		}
659 
660 		@Override
661 		public void endingElement() {
662 			pop();
663 		}
664 
665 	}
666 
667 	private class ExtensionState extends BaseState {
668 
669 		private IBaseExtension<?, ?> myExtension;
670 
671 		public ExtensionState(PreResourceState thePreResourceState, IBaseExtension<?, ?> theExtension) {
672 			super(thePreResourceState);
673 			myExtension = theExtension;
674 		}
675 
676 		@Override
677 		public void attributeValue(String theName, String theValue) throws DataFormatException {
678 			if ("url".equals(theName)) {
679 				// The URL attribute is handles in the XML loop as a special case since it is "url" instead
680 				// of "value" like every single other place
681 				return;
682 			}
683 			if ("id".equals(theName)) {
684 				if (getCurrentElement() instanceof IBaseElement) {
685 					((IBaseElement) getCurrentElement()).setId(theValue);
686 					return;
687 				} else if (getCurrentElement() instanceof IIdentifiableElement) {
688 					((IIdentifiableElement) getCurrentElement()).setElementSpecificId(theValue);
689 					return;
690 				}
691 			}
692 			super.attributeValue(theName, theValue);
693 		}
694 
695 		@Override
696 		public void endingElement() throws DataFormatException {
697 			if (myExtension.getValue() != null && myExtension.getExtension().size() > 0) {
698 				throw new DataFormatException("Extension (URL='" + myExtension.getUrl() + "') must not have both a value and other contained extensions");
699 			}
700 			pop();
701 		}
702 
703 		@Override
704 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
705 			if (theLocalPart.equals("id")) {
706 				if (getCurrentElement() instanceof IBaseElement) {
707 					push(new ElementIdState(getPreResourceState(), (IBaseElement) getCurrentElement()));
708 					return;
709 				} else if (getCurrentElement() instanceof IIdentifiableElement) {
710 					push(new IdentifiableElementIdState(getPreResourceState(), (IIdentifiableElement) getCurrentElement()));
711 					return;
712 				}
713 			}
714 
715 			BaseRuntimeElementDefinition<?> target = myContext.getRuntimeChildUndeclaredExtensionDefinition().getChildByName(theLocalPart);
716 
717 			if (target != null) {
718 				switch (target.getChildType()) {
719 				case COMPOSITE_DATATYPE: {
720 					BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
721 					ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance();
722 					myExtension.setValue(newChildInstance);
723 					ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theLocalPart, compositeTarget, newChildInstance);
724 					push(newState);
725 					return;
726 				}
727 				case ID_DATATYPE:
728 				case PRIMITIVE_DATATYPE: {
729 					RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
730 					IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance();
731 					myExtension.setValue(newChildInstance);
732 					PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
733 					push(newState);
734 					return;
735 				}
736 				case CONTAINED_RESOURCES:
737 				case CONTAINED_RESOURCE_LIST:
738 				case EXTENSION_DECLARED:
739 				case PRIMITIVE_XHTML:
740 				case PRIMITIVE_XHTML_HL7ORG:
741 				case RESOURCE:
742 				case RESOURCE_BLOCK:
743 				case UNDECL_EXT:
744 					break;
745 				}
746 			}
747 
748 			// We hit an invalid type for the extension
749 			myErrorHandler.unknownElement(null, theLocalPart);
750 			push(new SwallowChildrenWholeState(getPreResourceState()));
751 			return;
752 		}
753 
754 		@Override
755 		protected IBaseExtension<?, ?> getCurrentElement() {
756 			return myExtension;
757 		}
758 
759 	}
760 
761 	public class IdentifiableElementIdState extends BaseState {
762 
763 		private IIdentifiableElement myElement;
764 
765 		public IdentifiableElementIdState(ParserState<T>.PreResourceState thePreResourceState, IIdentifiableElement theElement) {
766 			super(thePreResourceState);
767 			myElement = theElement;
768 		}
769 
770 		@Override
771 		public void attributeValue(String theName, String theValue) throws DataFormatException {
772 			myElement.setElementSpecificId(theValue);
773 		}
774 
775 		@Override
776 		public void endingElement() {
777 			pop();
778 		}
779 
780 	}
781 
782 	private class MetaElementState extends BaseState {
783 		private ResourceMetadataMap myMap;
784 
785 		public MetaElementState(ParserState<T>.PreResourceState thePreResourceState, ResourceMetadataMap theMap) {
786 			super(thePreResourceState);
787 			myMap = theMap;
788 		}
789 
790 		@Override
791 		public void endingElement() throws DataFormatException {
792 			pop();
793 		}
794 
795 		@Override
796 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
797 			if (theLocalPart.equals("versionId")) {
798 				push(new MetaVersionElementState(getPreResourceState(), myMap));
799 				// } else if (theLocalPart.equals("profile")) {
800 				//
801 			} else if (theLocalPart.equals("lastUpdated")) {
802 				InstantDt updated = new InstantDt();
803 				push(new PrimitiveState(getPreResourceState(), updated));
804 				myMap.put(ResourceMetadataKeyEnum.UPDATED, updated);
805 			} else if (theLocalPart.equals("security")) {
806 				@SuppressWarnings("unchecked")
807 				List<IBase> securityLabels = (List<IBase>) myMap.get(ResourceMetadataKeyEnum.SECURITY_LABELS);
808 				if (securityLabels == null) {
809 					securityLabels = new ArrayList<>();
810 					myMap.put(ResourceMetadataKeyEnum.SECURITY_LABELS, securityLabels);
811 				}
812 				IBase securityLabel = myContext.getVersion().newCodingDt();
813 				BaseRuntimeElementCompositeDefinition<?> codinfDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(securityLabel.getClass());
814 				push(new SecurityLabelElementStateHapi(getPreResourceState(), codinfDef, securityLabel));
815 				securityLabels.add(securityLabel);
816 			} else if (theLocalPart.equals("profile")) {
817 				@SuppressWarnings("unchecked")
818 				List<IdDt> profiles = (List<IdDt>) myMap.get(ResourceMetadataKeyEnum.PROFILES);
819 				List<IdDt> newProfiles;
820 				if (profiles != null) {
821 					newProfiles = new ArrayList<IdDt>(profiles.size() + 1);
822 					newProfiles.addAll(profiles);
823 				} else {
824 					newProfiles = new ArrayList<IdDt>(1);
825 				}
826 				IdDt profile = new IdDt();
827 				push(new PrimitiveState(getPreResourceState(), profile));
828 				newProfiles.add(profile);
829 				myMap.put(ResourceMetadataKeyEnum.PROFILES, Collections.unmodifiableList(newProfiles));
830 			} else if (theLocalPart.equals("tag")) {
831 				TagList tagList = (TagList) myMap.get(ResourceMetadataKeyEnum.TAG_LIST);
832 				if (tagList == null) {
833 					tagList = new TagList();
834 					myMap.put(ResourceMetadataKeyEnum.TAG_LIST, tagList);
835 				}
836 				push(new TagState(tagList));
837 			} else {
838 				myErrorHandler.unknownElement(null, theLocalPart);
839 				push(new SwallowChildrenWholeState(getPreResourceState()));
840 				return;
841 			}
842 		}
843 
844 		@Override
845 		public void enteringNewElementExtension(StartElement theElem, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) {
846 			ResourceMetadataKeyEnum.ExtensionResourceMetadataKey resourceMetadataKeyEnum = new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey(theUrlAttr);
847 			Object metadataValue = myMap.get(resourceMetadataKeyEnum);
848 			ExtensionDt newExtension;
849 			if (metadataValue == null) {
850 				newExtension = new ExtensionDt(theIsModifier);
851 			} else if (metadataValue instanceof ExtensionDt) {
852 				newExtension = (ExtensionDt) metadataValue;
853 			} else {
854 				throw new IllegalStateException("Expected ExtensionDt as custom resource metadata type, got: " + metadataValue.getClass().getSimpleName());
855 			}
856 			newExtension.setUrl(theUrlAttr);
857 			myMap.put(resourceMetadataKeyEnum, newExtension);
858 
859 			ExtensionState newState = new ExtensionState(getPreResourceState(), newExtension);
860 			push(newState);
861 		}
862 
863 	}
864 
865 	private class MetaVersionElementState extends BaseState {
866 
867 		private ResourceMetadataMap myMap;
868 
869 		public MetaVersionElementState(ParserState<T>.PreResourceState thePreResourceState, ResourceMetadataMap theMap) {
870 			super(thePreResourceState);
871 			myMap = theMap;
872 		}
873 
874 		@Override
875 		public void attributeValue(String theName, String theValue) throws DataFormatException {
876 			myMap.put(ResourceMetadataKeyEnum.VERSION, theValue);
877 		}
878 
879 		@Override
880 		public void endingElement() throws DataFormatException {
881 			pop();
882 		}
883 
884 		@Override
885 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
886 			myErrorHandler.unknownElement(null, theLocalPart);
887 			push(new SwallowChildrenWholeState(getPreResourceState()));
888 			return;
889 		}
890 
891 	}
892 
893 
894 	private abstract class PreResourceState extends BaseState {
895 
896 		private Map<String, IBaseResource> myContainedResources;
897 		private IBaseResource myInstance;
898 		private FhirVersionEnum myParentVersion;
899 		private boolean myRequireResourceType = true;
900 		private Class<? extends IBaseResource> myResourceType;
901 
902 		public PreResourceState(Class<? extends IBaseResource> theResourceType) {
903 			super(null);
904 			myResourceType = theResourceType;
905 			myContainedResources = new HashMap<String, IBaseResource>();
906 			if (theResourceType != null) {
907 				myParentVersion = myContext.getResourceDefinition(theResourceType).getStructureVersion();
908 			} else {
909 				myParentVersion = myContext.getVersion().getVersion();
910 			}
911 		}
912 
913 		public PreResourceState(PreResourceState thePreResourcesState, FhirVersionEnum theParentVersion) {
914 			super(thePreResourcesState);
915 			Validate.notNull(theParentVersion);
916 			myParentVersion = theParentVersion;
917 			myContainedResources = thePreResourcesState.getContainedResources();
918 		}
919 
920 		@Override
921 		public void endingElement() throws DataFormatException {
922 			stitchBundleCrossReferences();
923 			pop();
924 		}
925 
926 		@Override
927 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
928 			BaseRuntimeElementDefinition<?> definition;
929 			if (myResourceType == null) {
930 				definition = null;
931 				if (myParser.getPreferTypes() != null) {
932 					for (Class<? extends IBaseResource> next : myParser.getPreferTypes()) {
933 						RuntimeResourceDefinition nextDef = myContext.getResourceDefinition(next);
934 						if (nextDef.getName().equals(theLocalPart)) {
935 							definition = nextDef;
936 						}
937 					}
938 				}
939 				if (definition == null) {
940 					definition = myContext.getResourceDefinition(myParentVersion, theLocalPart);
941 				}
942 				if ((definition == null)) {
943 					throw new DataFormatException("Element '" + theLocalPart + "' is not a known resource type, expected a resource at this position");
944 				}
945 			} else {
946 				definition = myContext.getResourceDefinition(myResourceType);
947 				if (!StringUtils.equals(theLocalPart, definition.getName())) {
948 					if (myRequireResourceType) {
949 						throw new DataFormatException(myContext.getLocalizer().getMessage(ParserState.class, "wrongResourceTypeFound", definition.getName(), theLocalPart));
950 					}
951 					definition = myContext.getResourceDefinition(theLocalPart);
952 					if (!(definition instanceof RuntimeResourceDefinition)) {
953 						throw new DataFormatException("Element '" + theLocalPart + "' is not a resource, expected a resource at this position");
954 					}
955 				}
956 			}
957 
958 			RuntimeResourceDefinition def = (RuntimeResourceDefinition) definition;
959 			if (!definition.getName().equals(theLocalPart) && definition.getName().equalsIgnoreCase(theLocalPart)) {
960 				throw new DataFormatException("Unknown resource type '" + theLocalPart + "': Resource names are case sensitive, found similar name: '" + definition.getName() + "'");
961 			}
962 			myInstance = def.newInstance();
963 
964 			if (myInstance instanceof IResource) {
965 				push(new ResourceStateHapi(getRootPreResourceState(), def, (IResource) myInstance));
966 			} else {
967 				push(new ResourceStateHl7Org(getRootPreResourceState(), def, myInstance));
968 			}
969 		}
970 
971 		public Map<String, IBaseResource> getContainedResources() {
972 			return myContainedResources;
973 		}
974 
975 		@Override
976 		protected IBaseResource getCurrentElement() {
977 			return myInstance;
978 		}
979 
980 		private PreResourceState getRootPreResourceState() {
981 			if (getPreResourceState() != null) {
982 				return getPreResourceState();
983 			}
984 			return this;
985 		}
986 
987 		@Override
988 		public boolean isPreResource() {
989 			return true;
990 		}
991 
992 		protected abstract void populateTarget();
993 
994 		private void postProcess() {
995 			if (myContext.hasDefaultTypeForProfile()) {
996 				IBaseMetaType meta = myInstance.getMeta();
997 				Class<? extends IBaseResource> wantedProfileType = null;
998 				String usedProfile = null;
999 				for (IPrimitiveType<String> next : meta.getProfile()) {
1000 					if (isNotBlank(next.getValue())) {
1001 						wantedProfileType = myContext.getDefaultTypeForProfile(next.getValue());
1002 						if (wantedProfileType != null) {
1003 							usedProfile = next.getValue();
1004 							break;
1005 						}
1006 					}
1007 				}
1008 
1009 				if (wantedProfileType != null && !wantedProfileType.equals(myInstance.getClass())) {
1010 					if (myResourceType == null || myResourceType.isAssignableFrom(wantedProfileType)) {
1011 						ourLog.debug("Converting resource of type {} to type defined for profile \"{}\": {}", new Object[] { myInstance.getClass().getName(), usedProfile, wantedProfileType });
1012 
1013 						/*
1014 						 * This isn't the most efficient thing really.. If we want a specific
1015 						 * type we just re-parse into that type. The problem is that we don't know
1016 						 * until we've parsed the resource which type we want to use because the
1017 						 * profile declarations are in the text of the resource itself.
1018 						 * 
1019 						 * At some point it would be good to write code which can present a view
1020 						 * of one type backed by another type and use that.
1021 						 */
1022 						IParser parser = myContext.newJsonParser();
1023 						String asString = parser.encodeResourceToString(myInstance);
1024 						myInstance = parser.parseResource(wantedProfileType, asString);
1025 					}
1026 				}
1027 			}
1028 
1029 			populateTarget();
1030 		}
1031 
1032 		private void stitchBundleCrossReferences() {
1033 			final boolean bundle = "Bundle".equals(myContext.getResourceDefinition(myInstance).getName());
1034 			if (bundle) {
1035 
1036 				FhirTerser t = myContext.newTerser();
1037 
1038 				Map<String, IBaseResource> idToResource = new HashMap<String, IBaseResource>();
1039 				List<IBase> entries = t.getValues(myInstance, "Bundle.entry", IBase.class);
1040 				for (IBase nextEntry : entries) {
1041 					IPrimitiveType<?> fullUrl = t.getSingleValueOrNull(nextEntry, "fullUrl", IPrimitiveType.class);
1042 					if (fullUrl != null && isNotBlank(fullUrl.getValueAsString())) {
1043 						IBaseResource resource = t.getSingleValueOrNull(nextEntry, "resource", IBaseResource.class);
1044 						if (resource != null) {
1045 							idToResource.put(fullUrl.getValueAsString(), resource);
1046 						}
1047 					}
1048 				}
1049 
1050 				/*
1051 				 * Stitch together resource references
1052 				 */
1053 				List<IBaseResource> resources = t.getAllPopulatedChildElementsOfType(myInstance, IBaseResource.class);
1054 				for (IBaseResource next : resources) {
1055 					IIdType id = next.getIdElement();
1056 					if (id != null && id.isEmpty() == false) {
1057 						String resName = myContext.getResourceDefinition(next).getName();
1058 						IIdType idType = id.withResourceType(resName).toUnqualifiedVersionless();
1059 						idToResource.put(idType.getValueAsString(), next);
1060 					}
1061 				}
1062 
1063 				for (IBaseResource next : resources) {
1064 					List<IBaseReference> refs = myContext.newTerser().getAllPopulatedChildElementsOfType(next, IBaseReference.class);
1065 					for (IBaseReference nextRef : refs) {
1066 						if (nextRef.isEmpty() == false && nextRef.getReferenceElement() != null) {
1067 							IIdType unqualifiedVersionless = nextRef.getReferenceElement().toUnqualifiedVersionless();
1068 							IBaseResource target = idToResource.get(unqualifiedVersionless.getValueAsString());
1069 							if (target != null) {
1070 								nextRef.setResource(target);
1071 							}
1072 						}
1073 					}
1074 				}
1075 
1076 				/*
1077 				 * Set resource IDs based on Bundle.entry.request.url
1078 				 */
1079 				List<Pair<String, IBaseResource>> urlsAndResources = BundleUtil.getBundleEntryUrlsAndResources(myContext, (IBaseBundle) myInstance);
1080 				for (Pair<String, IBaseResource> pair : urlsAndResources) {
1081 					if (pair.getRight() != null && isNotBlank(pair.getLeft()) && pair.getRight().getIdElement().isEmpty()) {
1082 						if (pair.getLeft().startsWith("urn:")) {
1083 							pair.getRight().setId(pair.getLeft());
1084 						}
1085 					}
1086 				}
1087 
1088 			}
1089 		}
1090 
1091 		protected void weaveContainedResources() {
1092 			FhirTerser terser = myContext.newTerser();
1093 			terser.visit(myInstance, new IModelVisitor() {
1094 
1095 				@Override
1096 				public void acceptElement(IBaseResource theResource, IBase theElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition,
1097 						BaseRuntimeElementDefinition<?> theDefinition) {
1098 					if (theElement instanceof BaseResourceReferenceDt) {
1099 						BaseResourceReferenceDt nextRef = (BaseResourceReferenceDt) theElement;
1100 						String ref = nextRef.getReference().getValue();
1101 						if (isNotBlank(ref)) {
1102 							if (ref.startsWith("#")) {
1103 								IResource target = (IResource) myContainedResources.get(ref);
1104 								if (target != null) {
1105 									ourLog.debug("Resource contains local ref {} in field {}", ref, thePathToElement);
1106 									nextRef.setResource(target);
1107 								} else {
1108 									myErrorHandler.unknownReference(null, ref);
1109 								}
1110 							}
1111 						}
1112 					} else if (theElement instanceof IBaseReference) {
1113 						IBaseReference nextRef = (IBaseReference) theElement;
1114 						String ref = nextRef.getReferenceElement().getValue();
1115 						if (isNotBlank(ref)) {
1116 							if (ref.startsWith("#")) {
1117 								IBaseResource target = myContainedResources.get(ref);
1118 								if (target != null) {
1119 									ourLog.debug("Resource contains local ref {} in field {}", ref, thePathToElement);
1120 									nextRef.setResource(target);
1121 								} else {
1122 									myErrorHandler.unknownReference(null, ref);
1123 								}
1124 							}
1125 						}
1126 					}
1127 				}
1128 			});
1129 		}
1130 
1131 		@Override
1132 		public void wereBack() {
1133 			postProcess();
1134 		}
1135 
1136 	}
1137 
1138 	private class PreResourceStateHapi extends PreResourceState {
1139 		private IMutator myMutator;
1140 		private Object myTarget;
1141 
1142 
1143 		public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) {
1144 			super(theResourceType);
1145 			assert theResourceType == null || IResource.class.isAssignableFrom(theResourceType);
1146 		}
1147 
1148 		public PreResourceStateHapi(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
1149 			super(theResourceType);
1150 			myTarget = theTarget;
1151 			myMutator = theMutator;
1152 			assert theResourceType == null || IResource.class.isAssignableFrom(theResourceType);
1153 		}
1154 
1155 		// @Override
1156 		// public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
1157 		// super.enteringNewElement(theNamespaceUri, theLocalPart);
1158 		// populateTarget();
1159 		// }
1160 
1161 		@Override
1162 		protected void populateTarget() {
1163 			weaveContainedResources();
1164 			if (myMutator != null) {
1165 				myMutator.setValue(myTarget, getCurrentElement());
1166 			}
1167 		}
1168 
1169 		@Override
1170 		public void wereBack() {
1171 			super.wereBack();
1172 
1173 			IResource nextResource = (IResource) getCurrentElement();
1174 			String version = ResourceMetadataKeyEnum.VERSION.get(nextResource);
1175 			String resourceName = myContext.getResourceDefinition(nextResource).getName();
1176 			String bundleIdPart = nextResource.getId().getIdPart();
1177 			if (isNotBlank(bundleIdPart)) {
1178         // if (isNotBlank(entryBaseUrl)) {
1179         // nextResource.setId(new IdDt(entryBaseUrl, resourceName, bundleIdPart, version));
1180         // } else {
1181         IdDt previousId = nextResource.getId();
1182         nextResource.setId(new IdDt(null, resourceName, bundleIdPart, version));
1183         // Copy extensions
1184         if (!previousId.getAllUndeclaredExtensions().isEmpty()) {
1185           for (final ExtensionDt ext : previousId.getAllUndeclaredExtensions()) {
1186             nextResource.getId().addUndeclaredExtension(ext);
1187           }
1188         }
1189        // }
1190 			}
1191 		}
1192 
1193 	}
1194 
1195 	private class PreResourceStateHl7Org extends PreResourceState {
1196 
1197 		private IMutator myMutator;
1198 		private Object myTarget;
1199 
1200 		public PreResourceStateHl7Org(Class<? extends IBaseResource> theResourceType) {
1201 			super(theResourceType);
1202 		}
1203 
1204 		public PreResourceStateHl7Org(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
1205 			super(theResourceType);
1206 			myMutator = theMutator;
1207 			myTarget = theTarget;
1208 		}
1209 
1210 		@Override
1211 		protected void populateTarget() {
1212 			weaveContainedResources();
1213 			if (myMutator != null) {
1214 				myMutator.setValue(myTarget, getCurrentElement());
1215 			}
1216 		}
1217 
1218 		@Override
1219 		public void wereBack() {
1220 			super.wereBack();
1221 
1222 			if (getCurrentElement() instanceof IDomainResource) {
1223 				IDomainResource elem = (IDomainResource) getCurrentElement();
1224 				String resourceName = myContext.getResourceDefinition(elem).getName();
1225 				String versionId = elem.getMeta().getVersionId();
1226 				if (StringUtils.isBlank(elem.getIdElement().getIdPart())) {
1227 					// Resource has no ID
1228 				} else if (StringUtils.isNotBlank(versionId)) {
1229 					elem.getIdElement().setValue(resourceName + "/" + elem.getIdElement().getIdPart() + "/_history/" + versionId);
1230 				} else {
1231 					elem.getIdElement().setValue(resourceName + "/" + elem.getIdElement().getIdPart());
1232 				}
1233 			}
1234 		}
1235 
1236 	}
1237 
1238 	private class PreTagListState extends BaseState {
1239 
1240 		private TagList myTagList;
1241 
1242 		public PreTagListState() {
1243 			super(null);
1244 			myTagList = new TagList();
1245 		}
1246 
1247 		@Override
1248 		public void endingElement() throws DataFormatException {
1249 			pop();
1250 		}
1251 
1252 		@Override
1253 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
1254 			if (!TagList.ELEMENT_NAME_LC.equals(theLocalPart.toLowerCase())) {
1255 				throw new DataFormatException("resourceType does not appear to be 'TagList', found: " + theLocalPart);
1256 			}
1257 
1258 			push(new TagListState(myTagList));
1259 		}
1260 
1261 		@Override
1262 		protected IBase getCurrentElement() {
1263 			return myTagList;
1264 		}
1265 
1266 		@Override
1267 		public boolean isPreResource() {
1268 			return true;
1269 		}
1270 
1271 	}
1272 
1273 	private class PrimitiveState extends BaseState {
1274 		private IPrimitiveType<?> myInstance;
1275 
1276 		public PrimitiveState(PreResourceState thePreResourceState, IPrimitiveType<?> theInstance) {
1277 			super(thePreResourceState);
1278 			myInstance = theInstance;
1279 		}
1280 
1281 		@Override
1282 		public void attributeValue(String theName, String theValue) throws DataFormatException {
1283 			if ("value".equals(theName)) {
1284 				if ("".equals(theValue)) {
1285 					myErrorHandler.invalidValue(null, theValue, "Attribute values must not be empty (\"\")");
1286 				} else {
1287 					try {
1288 						myInstance.setValueAsString(theValue);
1289 					} catch (DataFormatException e) {
1290 						myErrorHandler.invalidValue(null, theValue, e.getMessage());
1291 					} catch (IllegalArgumentException e) {
1292 						myErrorHandler.invalidValue(null, theValue, e.getMessage());
1293 					}
1294 				}
1295 			} else if ("id".equals(theName)) {
1296 				if (myInstance instanceof IIdentifiableElement) {
1297 					((IIdentifiableElement) myInstance).setElementSpecificId(theValue);
1298 				} else if (myInstance instanceof IBaseElement) {
1299 					((IBaseElement) myInstance).setId(theValue);
1300 				} else if (myInstance instanceof IBaseResource) {
1301 					new IdDt(theValue).applyTo((org.hl7.fhir.instance.model.api.IBaseResource) myInstance);
1302 				} else {
1303 					myErrorHandler.unknownAttribute(null, theName);
1304 				}
1305 			} else {
1306 				myErrorHandler.unknownAttribute(null, theName);
1307 			}
1308 		}
1309 
1310 		@Override
1311 		public void endingElement() {
1312 			pop();
1313 		}
1314 
1315 		// @Override
1316 		// public void enteringNewElementExtension(StartElement theElement,
1317 		// String theUrlAttr) {
1318 		// if (myInstance instanceof ISupportsUndeclaredExtensions) {
1319 		// UndeclaredExtension ext = new UndeclaredExtension(theUrlAttr);
1320 		// ((ISupportsUndeclaredExtensions)
1321 		// myInstance).getUndeclaredExtensions().add(ext);
1322 		// push(new ExtensionState(ext));
1323 		// }
1324 		// }
1325 
1326 		@Override
1327 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
1328 			myErrorHandler.unknownElement(null, theLocalPart);
1329 			push(new SwallowChildrenWholeState(getPreResourceState()));
1330 			return;
1331 		}
1332 
1333 		@Override
1334 		protected IBase getCurrentElement() {
1335 			return myInstance;
1336 		}
1337 
1338 	}
1339 
1340 	private class ResourceStateHapi extends ElementCompositeState {
1341 
1342 		private IResource myInstance;
1343 
1344 		public ResourceStateHapi(PreResourceState thePreResourceState, BaseRuntimeElementCompositeDefinition<?> theDef, IResource theInstance) {
1345 			super(thePreResourceState, theDef.getName(), theDef, theInstance);
1346 			myInstance = theInstance;
1347 		}
1348 
1349 		@Override
1350 		public void enteringNewElement(String theNamespace, String theChildName) throws DataFormatException {
1351 			if ("id".equals(theChildName)) {
1352 				push(new PrimitiveState(getPreResourceState(), myInstance.getId()));
1353 			} else if ("meta".equals(theChildName)) {
1354 				push(new MetaElementState(getPreResourceState(), myInstance.getResourceMetadata()));
1355 			} else {
1356 				super.enteringNewElement(theNamespace, theChildName);
1357 			}
1358 		}
1359 	}
1360 
1361 	private class ResourceStateHl7Org extends ElementCompositeState {
1362 
1363 		public ResourceStateHl7Org(PreResourceState thePreResourceState, BaseRuntimeElementCompositeDefinition<?> theDef, IBaseResource theInstance) {
1364 			super(thePreResourceState, theDef.getName(), theDef, theInstance);
1365 		}
1366 
1367 	}
1368 
1369 	private class SecurityLabelElementStateHapi extends ElementCompositeState {
1370 
1371 		public SecurityLabelElementStateHapi(ParserState<T>.PreResourceState thePreResourceState, BaseRuntimeElementCompositeDefinition<?> theDef, IBase codingDt) {
1372 			super(thePreResourceState, theDef.getName(), theDef, codingDt);
1373 		}
1374 
1375 		@Override
1376 		public void endingElement() throws DataFormatException {
1377 			pop();
1378 		}
1379 
1380 	}
1381 
1382 	private class SwallowChildrenWholeState extends BaseState {
1383 
1384 		private int myDepth;
1385 
1386 		public SwallowChildrenWholeState(PreResourceState thePreResourceState) {
1387 			super(thePreResourceState);
1388 		}
1389 
1390 		@Override
1391 		public void attributeValue(String theName, String theValue) throws DataFormatException {
1392 			// ignore
1393 		}
1394 
1395 		@Override
1396 		public void endingElement() throws DataFormatException {
1397 			myDepth--;
1398 			if (myDepth < 0) {
1399 				pop();
1400 			}
1401 		}
1402 
1403 		@Override
1404 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
1405 			myDepth++;
1406 		}
1407 
1408 		@Override
1409 		public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) {
1410 			myDepth++;
1411 		}
1412 
1413 	}
1414 
1415 	private class TagListState extends BaseState {
1416 
1417 		private TagList myTagList;
1418 
1419 		public TagListState(TagList theTagList) {
1420 			super(null);
1421 			myTagList = theTagList;
1422 		}
1423 
1424 		@Override
1425 		public void endingElement() throws DataFormatException {
1426 			pop();
1427 		}
1428 
1429 		@Override
1430 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
1431 			if (TagList.ATTR_CATEGORY.equals(theLocalPart)) {
1432 				push(new TagState(myTagList));
1433 			} else {
1434 				throw new DataFormatException("Unexpected element: " + theLocalPart);
1435 			}
1436 		}
1437 
1438 		@Override
1439 		protected IBase getCurrentElement() {
1440 			return myTagList;
1441 		}
1442 
1443 	}
1444 
1445 	private class TagState extends BaseState {
1446 
1447 		private static final int LABEL = 2;
1448 		private static final int NONE = 0;
1449 
1450 		private static final int SCHEME = 3;
1451 		private static final int TERM = 1;
1452 		private String myLabel;
1453 		private String myScheme;
1454 		private int mySubState = 0;
1455 		private TagList myTagList;
1456 		private String myTerm;
1457 
1458 		public TagState(TagList theTagList) {
1459 			super(null);
1460 			myTagList = theTagList;
1461 		}
1462 
1463 		@Override
1464 		public void attributeValue(String theName, String theValue) throws DataFormatException {
1465 			String value = defaultIfBlank(theValue, null);
1466 
1467 			switch (mySubState) {
1468 			case TERM:
1469 				myTerm = (value);
1470 				break;
1471 			case LABEL:
1472 				myLabel = (value);
1473 				break;
1474 			case SCHEME:
1475 				myScheme = (value);
1476 				break;
1477 			case NONE:
1478 				// This handles JSON encoding, which is a bit weird
1479 				enteringNewElement(null, theName);
1480 				attributeValue(null, value);
1481 				endingElement();
1482 				break;
1483 			}
1484 		}
1485 
1486 		@Override
1487 		public void endingElement() throws DataFormatException {
1488 			if (mySubState != NONE) {
1489 				mySubState = NONE;
1490 			} else {
1491 				if (isNotEmpty(myScheme) || isNotBlank(myTerm) || isNotBlank(myLabel)) {
1492 					myTagList.addTag(myScheme, myTerm, myLabel);
1493 				}
1494 				pop();
1495 			}
1496 		}
1497 
1498 		@Override
1499 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
1500 			/*
1501 			 * We allow for both the DSTU1 and DSTU2 names here
1502 			 */
1503 			if (Tag.ATTR_TERM.equals(theLocalPart) || "code".equals(theLocalPart)) {
1504 				mySubState = TERM;
1505 			} else if (Tag.ATTR_SCHEME.equals(theLocalPart) || "system".equals(theLocalPart)) {
1506 				mySubState = SCHEME;
1507 			} else if (Tag.ATTR_LABEL.equals(theLocalPart) || "display".equals(theLocalPart)) {
1508 				mySubState = LABEL;
1509 			} else {
1510 				throw new DataFormatException("Unexpected element: " + theLocalPart);
1511 			}
1512 		}
1513 
1514 	}
1515 
1516 	private class XhtmlState extends BaseState {
1517 		private int myDepth;
1518 		private XhtmlDt myDt;
1519 		private List<XMLEvent> myEvents = new ArrayList<XMLEvent>();
1520 		private boolean myIncludeOuterEvent;
1521 
1522 		private XhtmlState(PreResourceState thePreResourceState, XhtmlDt theXhtmlDt, boolean theIncludeOuterEvent) throws DataFormatException {
1523 			super(thePreResourceState);
1524 			myDepth = 0;
1525 			myDt = theXhtmlDt;
1526 			myIncludeOuterEvent = theIncludeOuterEvent;
1527 		}
1528 
1529 		@Override
1530 		public void attributeValue(String theName, String theValue) throws DataFormatException {
1531 			if (myJsonMode) {
1532 				myDt.setValueAsString(theValue);
1533 			} else {
1534 				// IGNORE - don't handle this as an error, we process these as XML events
1535 			}
1536 		}
1537 
1538 		protected void doPop() {
1539 			pop();
1540 		}
1541 
1542 		@Override
1543 		public void endingElement() throws DataFormatException {
1544 			if (myJsonMode) {
1545 				doPop();
1546 				return;
1547 			}
1548 			super.endingElement();
1549 		}
1550 
1551 		@Override
1552 		public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
1553 			// IGNORE - don't handle this as an error, we process these as XML events
1554 		}
1555 
1556 		@Override
1557 		protected IElement getCurrentElement() {
1558 			return myDt;
1559 		}
1560 
1561 		public XhtmlDt getDt() {
1562 			return myDt;
1563 		}
1564 
1565 		@Override
1566 		public void xmlEvent(XMLEvent theEvent) {
1567 			if (theEvent.isEndElement()) {
1568 				myDepth--;
1569 			}
1570 
1571 			if (myIncludeOuterEvent || myDepth > 0) {
1572 				myEvents.add(theEvent);
1573 			}
1574 
1575 			if (theEvent.isStartElement()) {
1576 				myDepth++;
1577 			}
1578 
1579 			if (theEvent.isEndElement()) {
1580 				if (myDepth == 0) {
1581 					String eventsAsString = XmlUtil.encode(myEvents);
1582 					myDt.setValue(eventsAsString);
1583 					doPop();
1584 				}
1585 			}
1586 		}
1587 
1588 	}
1589 
1590 	private class XhtmlStateHl7Org extends XhtmlState {
1591 		private IBaseXhtml myHl7OrgDatatype;
1592 
1593 		private XhtmlStateHl7Org(PreResourceState thePreResourceState, IBaseXhtml theHl7OrgDatatype) {
1594 			super(thePreResourceState, new XhtmlDt(), true);
1595 			myHl7OrgDatatype = theHl7OrgDatatype;
1596 		}
1597 
1598 		@Override
1599 		public void doPop() {
1600 			// TODO: this is not very efficient
1601 			String value = getDt().getValueAsString();
1602 			myHl7OrgDatatype.setValueAsString(value);
1603 
1604 			super.doPop();
1605 		}
1606 
1607 	}
1608 
1609 }