314 lines
9.3 KiB
Java
Raw Normal View History

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
}