2014-02-18 08:26:49 -05:00
|
|
|
package ca.uhn.fhir.parser;
|
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
import java.io.StringWriter;
|
|
|
|
|
|
|
|
import javax.xml.stream.XMLEventFactory;
|
|
|
|
import javax.xml.stream.XMLEventWriter;
|
|
|
|
import javax.xml.stream.XMLOutputFactory;
|
|
|
|
import javax.xml.stream.XMLStreamException;
|
|
|
|
import javax.xml.stream.events.Attribute;
|
|
|
|
import javax.xml.stream.events.EndElement;
|
|
|
|
import javax.xml.stream.events.StartElement;
|
|
|
|
import javax.xml.stream.events.XMLEvent;
|
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
2014-02-19 11:59:12 -05:00
|
|
|
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
2014-02-18 08:26:49 -05:00
|
|
|
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
|
|
|
import ca.uhn.fhir.context.FhirContext;
|
2014-02-19 11:59:12 -05:00
|
|
|
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
|
2014-02-20 12:13:05 -05:00
|
|
|
import ca.uhn.fhir.context.RuntimeResourceBlockDefinition;
|
2014-02-18 08:26:49 -05:00
|
|
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
2014-02-19 17:33:46 -05:00
|
|
|
import ca.uhn.fhir.context.RuntimeResourceReferenceDefinition;
|
2014-02-19 11:59:12 -05:00
|
|
|
import ca.uhn.fhir.model.api.ICompositeDatatype;
|
|
|
|
import ca.uhn.fhir.model.api.ICompositeElement;
|
|
|
|
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
2014-02-18 08:26:49 -05:00
|
|
|
import ca.uhn.fhir.model.api.IResource;
|
2014-02-20 12:13:05 -05:00
|
|
|
import ca.uhn.fhir.model.api.IResourceBlock;
|
2014-02-19 17:33:46 -05:00
|
|
|
import ca.uhn.fhir.model.api.ResourceReference;
|
2014-02-18 08:26:49 -05:00
|
|
|
|
|
|
|
class ParserState {
|
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
|
2014-02-19 17:33:46 -05:00
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
private FhirContext myContext;
|
2014-02-19 17:33:46 -05:00
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
private Object myObject;
|
|
|
|
private BaseState myState;
|
2014-02-19 17:33:46 -05:00
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
public ParserState(FhirContext theContext) {
|
|
|
|
myContext = theContext;
|
|
|
|
}
|
2014-02-19 17:33:46 -05:00
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
public void attributeValue(Attribute theAttribute, String theValue) throws DataFormatException {
|
|
|
|
myState.attributeValue(theAttribute, theValue);
|
2014-02-19 17:33:46 -05:00
|
|
|
}
|
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
public void endingElement(EndElement theElem) throws DataFormatException {
|
|
|
|
myState.endingElement(theElem);
|
|
|
|
}
|
2014-02-19 11:59:12 -05:00
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
public void enteringNewElement(StartElement theElement, String theName) throws DataFormatException {
|
|
|
|
myState.enteringNewElement(theElement, theName);
|
|
|
|
}
|
2014-02-18 08:26:49 -05:00
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
public Object getObject() {
|
|
|
|
return myObject;
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
public boolean isComplete() {
|
|
|
|
return myObject != null;
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
private void pop() {
|
|
|
|
myState = myState.myStack;
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
private void push(BaseState theState) {
|
|
|
|
theState.setStack(myState);
|
|
|
|
myState = theState;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setState(BaseState theState) {
|
|
|
|
myState = theState;
|
2014-02-18 08:26:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public static ParserState getResourceInstance(FhirContext theContext, String theLocalPart) throws DataFormatException {
|
2014-02-18 18:10:50 -05:00
|
|
|
BaseRuntimeElementDefinition<?> definition = theContext.getNameToResourceDefinition().get(theLocalPart);
|
2014-02-18 08:26:49 -05:00
|
|
|
if (!(definition instanceof RuntimeResourceDefinition)) {
|
|
|
|
throw new DataFormatException("Element '" + theLocalPart + "' is not a resource, expected a resource at this position");
|
|
|
|
}
|
2014-02-19 11:59:12 -05:00
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
RuntimeResourceDefinition def = (RuntimeResourceDefinition) definition;
|
|
|
|
IResource instance = def.newInstance();
|
2014-02-19 11:59:12 -05:00
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
ParserState retVal = new ParserState(theContext);
|
2014-02-19 11:59:12 -05:00
|
|
|
retVal.setState(retVal.new ContainerState(def, instance));
|
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
2014-02-20 12:13:05 -05:00
|
|
|
private abstract class BaseState {
|
|
|
|
private BaseState myStack;
|
2014-02-18 08:26:49 -05:00
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
public abstract void attributeValue(Attribute theAttribute, String theValue) throws DataFormatException;
|
|
|
|
|
|
|
|
public abstract void endingElement(EndElement theElem) throws DataFormatException;
|
2014-02-19 11:59:12 -05:00
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
public abstract void enteringNewElement(StartElement theElement, String theLocalPart) throws DataFormatException;
|
2014-02-18 08:26:49 -05:00
|
|
|
|
2014-02-20 12:13:05 -05:00
|
|
|
public void setStack(BaseState theState) {
|
|
|
|
myStack = theState;
|
|
|
|
}
|
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
public abstract void otherEvent(XMLEvent theEvent);
|
2014-02-20 12:13:05 -05:00
|
|
|
|
|
|
|
}
|
2014-02-19 11:59:12 -05:00
|
|
|
|
|
|
|
private class ContainerState extends BaseState {
|
|
|
|
|
|
|
|
private BaseRuntimeElementCompositeDefinition<?> myDefinition;
|
|
|
|
private ICompositeElement myInstance;
|
2014-02-18 08:26:49 -05:00
|
|
|
|
2014-02-19 11:59:12 -05:00
|
|
|
public ContainerState(BaseRuntimeElementCompositeDefinition<?> theDef, ICompositeElement theInstance) {
|
|
|
|
myDefinition = theDef;
|
2014-02-18 08:26:49 -05:00
|
|
|
myInstance = theInstance;
|
|
|
|
}
|
|
|
|
|
2014-02-19 11:59:12 -05:00
|
|
|
@Override
|
2014-02-21 21:06:11 -05:00
|
|
|
public void attributeValue(Attribute theAttribute, String theValue) {
|
2014-02-19 11:59:12 -05:00
|
|
|
ourLog.debug("Ignoring attribute value: {}", theValue);
|
|
|
|
}
|
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
@Override
|
2014-02-21 21:06:11 -05:00
|
|
|
public void endingElement(EndElement theElem) {
|
|
|
|
pop();
|
|
|
|
if (myState == null) {
|
|
|
|
myObject = myInstance;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void enteringNewElement(StartElement theElement, String theChildName) throws DataFormatException {
|
2014-02-19 11:59:12 -05:00
|
|
|
BaseRuntimeChildDefinition child = myDefinition.getChildByNameOrThrowDataFormatException(theChildName);
|
|
|
|
BaseRuntimeElementDefinition<?> target = child.getChildByName(theChildName);
|
|
|
|
|
|
|
|
switch (target.getChildType()) {
|
|
|
|
case COMPOSITE_DATATYPE: {
|
|
|
|
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
|
|
|
|
ICompositeDatatype newChildInstance = (ICompositeDatatype) compositeTarget.newInstance();
|
|
|
|
child.getMutator().addValue(myInstance, newChildInstance);
|
|
|
|
ContainerState newState = new ContainerState(compositeTarget, newChildInstance);
|
|
|
|
push(newState);
|
2014-02-20 12:13:05 -05:00
|
|
|
return;
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
case PRIMITIVE_DATATYPE: {
|
|
|
|
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
|
|
|
|
IPrimitiveDatatype<?> newChildInstance = primitiveTarget.newInstance();
|
|
|
|
child.getMutator().addValue(myInstance, newChildInstance);
|
2014-02-20 12:13:05 -05:00
|
|
|
PrimitiveState newState = new PrimitiveState(newChildInstance);
|
2014-02-19 11:59:12 -05:00
|
|
|
push(newState);
|
2014-02-20 12:13:05 -05:00
|
|
|
return;
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
2014-02-19 17:33:46 -05:00
|
|
|
case RESOURCE_REF: {
|
|
|
|
RuntimeResourceReferenceDefinition resourceRefTarget = (RuntimeResourceReferenceDefinition) target;
|
|
|
|
ResourceReference newChildInstance = new ResourceReference();
|
|
|
|
child.getMutator().addValue(myInstance, newChildInstance);
|
|
|
|
ResourceReferenceState newState = new ResourceReferenceState(resourceRefTarget, newChildInstance);
|
|
|
|
push(newState);
|
2014-02-20 12:13:05 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
case RESOURCE_BLOCK: {
|
|
|
|
RuntimeResourceBlockDefinition blockTarget = (RuntimeResourceBlockDefinition) target;
|
|
|
|
IResourceBlock newBlockInstance = blockTarget.newInstance();
|
|
|
|
child.getMutator().addValue(myInstance, newBlockInstance);
|
|
|
|
ContainerState newState = new ContainerState(blockTarget, newBlockInstance);
|
|
|
|
push(newState);
|
|
|
|
return;
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
2014-02-21 21:06:11 -05:00
|
|
|
case RESOURCE: {
|
2014-02-20 12:13:05 -05:00
|
|
|
// Throw an exception because this shouldn't happen here
|
|
|
|
break;
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
2014-02-21 21:06:11 -05:00
|
|
|
case PRIMITIVE_XHTML: {
|
2014-02-19 11:59:12 -05:00
|
|
|
|
2014-02-18 18:10:50 -05:00
|
|
|
}
|
2014-02-21 21:06:11 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
throw new DataFormatException("Illegal resource position: " + target.getChildType());
|
2014-02-18 08:26:49 -05:00
|
|
|
}
|
2014-02-19 11:59:12 -05:00
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
}
|
|
|
|
|
2014-02-19 11:59:12 -05:00
|
|
|
private class PrimitiveState extends BaseState {
|
|
|
|
private IPrimitiveDatatype<?> myInstance;
|
|
|
|
|
2014-02-20 12:13:05 -05:00
|
|
|
public PrimitiveState(IPrimitiveDatatype<?> theInstance) {
|
2014-02-19 11:59:12 -05:00
|
|
|
super();
|
|
|
|
myInstance = theInstance;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2014-02-21 21:06:11 -05:00
|
|
|
public void attributeValue(Attribute theAttribute, String theValue) throws DataFormatException {
|
2014-02-19 11:59:12 -05:00
|
|
|
myInstance.setValueAsString(theValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2014-02-21 21:06:11 -05:00
|
|
|
public void endingElement(EndElement theElem) {
|
|
|
|
pop();
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2014-02-21 21:06:11 -05:00
|
|
|
public void enteringNewElement(StartElement theElement, String theLocalPart) throws DataFormatException {
|
|
|
|
throw new Error("?? can this happen?"); // TODO: can this happen?
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
private class ResourceReferenceState extends BaseState {
|
|
|
|
|
|
|
|
private RuntimeResourceReferenceDefinition myDefinition;
|
|
|
|
private ResourceReference myInstance;
|
|
|
|
private ResourceReferenceSubState mySubState;
|
|
|
|
|
|
|
|
public ResourceReferenceState(RuntimeResourceReferenceDefinition theDefinition, ResourceReference theInstance) {
|
|
|
|
myDefinition = theDefinition;
|
|
|
|
myInstance = theInstance;
|
|
|
|
mySubState = ResourceReferenceSubState.INITIAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void attributeValue(Attribute theAttribute, String theValue) throws DataFormatException {
|
|
|
|
switch (mySubState) {
|
|
|
|
case DISPLAY:
|
|
|
|
myInstance.setDisplay(theValue);
|
|
|
|
break;
|
|
|
|
case INITIAL:
|
|
|
|
throw new DataFormatException("Unexpected attribute: " + theValue);
|
|
|
|
case REFERENCE:
|
|
|
|
myInstance.setReference(theValue);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void endingElement(EndElement theElement) {
|
|
|
|
switch (mySubState) {
|
|
|
|
case INITIAL:
|
|
|
|
pop();
|
|
|
|
break;
|
|
|
|
case DISPLAY:
|
|
|
|
case REFERENCE:
|
|
|
|
mySubState = ResourceReferenceSubState.INITIAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void enteringNewElement(StartElement theElem, String theLocalPart) throws DataFormatException {
|
|
|
|
switch (mySubState) {
|
|
|
|
case INITIAL:
|
|
|
|
if ("display".equals(theLocalPart)) {
|
|
|
|
mySubState = ResourceReferenceSubState.DISPLAY;
|
|
|
|
break;
|
|
|
|
} else if ("reference".equals(theLocalPart)) {
|
|
|
|
mySubState = ResourceReferenceSubState.REFERENCE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//$FALL-THROUGH$
|
|
|
|
case DISPLAY:
|
|
|
|
case REFERENCE:
|
|
|
|
throw new DataFormatException("Unexpected element: " + theLocalPart);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
}
|
2014-02-19 11:59:12 -05:00
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
private enum ResourceReferenceSubState {
|
|
|
|
DISPLAY, INITIAL, REFERENCE
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
private class XhtmlState extends BaseState {
|
|
|
|
private StringWriter myStringWriter;
|
|
|
|
private XMLEventWriter myEventWriter;
|
|
|
|
private XMLEventFactory myEventFactory;
|
|
|
|
|
|
|
|
private XhtmlState() throws DataFormatException {
|
|
|
|
try {
|
|
|
|
XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
|
|
|
|
myStringWriter = new StringWriter();
|
|
|
|
myEventWriter = xmlFactory.createXMLEventWriter(myStringWriter);
|
|
|
|
} catch (XMLStreamException e) {
|
|
|
|
throw new DataFormatException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void attributeValue(Attribute theAttr, String theValue) throws DataFormatException {
|
|
|
|
try {
|
|
|
|
myEventWriter.add(theAttr);
|
|
|
|
} catch (XMLStreamException e) {
|
|
|
|
throw new DataFormatException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void endingElement(EndElement theElement) throws DataFormatException {
|
|
|
|
try {
|
|
|
|
myEventWriter.add(theElement);
|
|
|
|
} catch (XMLStreamException e) {
|
|
|
|
throw new DataFormatException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void enteringNewElement(StartElement theElem, String theLocalPart) throws DataFormatException {
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
|
|
|
|
}
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
|
2014-02-21 21:06:11 -05:00
|
|
|
public void otherEvent(XMLEvent theEvent) {
|
|
|
|
myState.otherEvent(theEvent);
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
}
|