2014-02-18 08:26:49 -05:00
|
|
|
package ca.uhn.fhir.parser;
|
|
|
|
|
|
|
|
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-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-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-19 17:33:46 -05:00
|
|
|
private enum ResourceReferenceSubState {
|
|
|
|
INITIAL, REFERENCE, DISPLAY
|
|
|
|
}
|
|
|
|
|
|
|
|
private class ResourceReferenceState extends BaseState {
|
|
|
|
|
|
|
|
private ResourceReferenceSubState mySubState;
|
|
|
|
private RuntimeResourceReferenceDefinition myDefinition;
|
|
|
|
private ResourceReference myInstance;
|
|
|
|
|
|
|
|
public ResourceReferenceState(RuntimeResourceReferenceDefinition theDefinition, ResourceReference theInstance) {
|
|
|
|
myDefinition=theDefinition;
|
|
|
|
myInstance = theInstance;
|
|
|
|
mySubState = ResourceReferenceSubState.INITIAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void attributeValue(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 enteringNewElement(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;
|
|
|
|
}
|
|
|
|
// ...else fall through...
|
|
|
|
case DISPLAY:
|
|
|
|
case REFERENCE:
|
|
|
|
throw new DataFormatException("Unexpected element: "+theLocalPart);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void endingElement(String theLocalPart) {
|
|
|
|
mySubState=ResourceReferenceSubState.INITIAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-02-19 11:59:12 -05:00
|
|
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
|
2014-02-18 08:26:49 -05:00
|
|
|
private FhirContext myContext;
|
2014-02-19 11:59:12 -05:00
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
private BaseState myState;
|
2014-02-19 11:59:12 -05:00
|
|
|
private Object myObject;
|
2014-02-18 08:26:49 -05:00
|
|
|
|
|
|
|
public ParserState(FhirContext theContext) {
|
2014-02-19 11:59:12 -05:00
|
|
|
myContext = theContext;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void attributeValue(String theValue) throws DataFormatException {
|
|
|
|
myState.attributeValue(theValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void enteringNewElement(String theLocalPart) throws DataFormatException {
|
|
|
|
myState.enteringNewElement(theLocalPart);
|
|
|
|
}
|
|
|
|
|
|
|
|
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-19 11:59:12 -05:00
|
|
|
private abstract class BaseState {
|
|
|
|
private BaseState myStack;
|
2014-02-18 08:26:49 -05:00
|
|
|
|
2014-02-19 11:59:12 -05:00
|
|
|
public abstract void attributeValue(String theValue) throws DataFormatException;
|
2014-02-18 08:26:49 -05:00
|
|
|
|
2014-02-19 11:59:12 -05:00
|
|
|
public abstract void enteringNewElement(String theLocalPart) throws DataFormatException;
|
|
|
|
|
|
|
|
public void setStack(BaseState theState) {
|
|
|
|
myStack = theState;
|
2014-02-18 08:26:49 -05:00
|
|
|
}
|
|
|
|
|
2014-02-19 11:59:12 -05:00
|
|
|
public abstract void endingElement(String theLocalPart);
|
|
|
|
|
|
|
|
}
|
|
|
|
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
|
|
|
|
public void attributeValue(String theValue) {
|
|
|
|
ourLog.debug("Ignoring attribute value: {}", theValue);
|
|
|
|
}
|
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
@Override
|
|
|
|
public void enteringNewElement(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-18 18:10:50 -05:00
|
|
|
break;
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
case PRIMITIVE_DATATYPE: {
|
|
|
|
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
|
|
|
|
IPrimitiveDatatype<?> newChildInstance = primitiveTarget.newInstance();
|
|
|
|
child.getMutator().addValue(myInstance, newChildInstance);
|
|
|
|
PrimitiveState newState = new PrimitiveState(primitiveTarget, newChildInstance);
|
|
|
|
push(newState);
|
|
|
|
break;
|
|
|
|
}
|
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-18 18:10:50 -05:00
|
|
|
break;
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
2014-02-19 17:33:46 -05:00
|
|
|
case RESOURCE:
|
2014-02-18 18:10:50 -05:00
|
|
|
default:
|
2014-02-19 17:33:46 -05:00
|
|
|
throw new DataFormatException("Illegal resource position: " + target.getChildType());
|
2014-02-19 11:59:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void endingElement(String theLocalPart) {
|
|
|
|
pop();
|
|
|
|
if (myState == null) {
|
|
|
|
myObject = myInstance;
|
2014-02-18 18:10:50 -05:00
|
|
|
}
|
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 RuntimePrimitiveDatatypeDefinition myDefinition;
|
|
|
|
private IPrimitiveDatatype<?> myInstance;
|
|
|
|
|
|
|
|
public PrimitiveState(RuntimePrimitiveDatatypeDefinition theDefinition, IPrimitiveDatatype<?> theInstance) {
|
|
|
|
super();
|
|
|
|
myDefinition = theDefinition;
|
|
|
|
myInstance = theInstance;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void attributeValue(String theValue) throws DataFormatException {
|
|
|
|
myInstance.setValueAsString(theValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void enteringNewElement(String theLocalPart) throws DataFormatException {
|
|
|
|
throw new Error("?? can this happen?"); // TODO: can this happen?
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void endingElement(String theLocalPart) {
|
|
|
|
pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public Object getObject() {
|
|
|
|
return myObject;
|
2014-02-18 08:26:49 -05:00
|
|
|
}
|
2014-02-19 11:59:12 -05:00
|
|
|
|
|
|
|
private void pop() {
|
|
|
|
myState = myState.myStack;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isComplete() {
|
|
|
|
return myObject != null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void endingElement(String theLocalPart) {
|
|
|
|
myState.endingElement(theLocalPart);
|
|
|
|
}
|
|
|
|
|
2014-02-18 08:26:49 -05:00
|
|
|
}
|