Commit 76ba58c6 authored by R.W.Majeed's avatar R.W.Majeed
Browse files

default local time zone can be specified in GroupedXMLReader. Tests for timestamp handling

parent 67e399fd
...@@ -4,6 +4,7 @@ import java.io.IOException; ...@@ -4,6 +4,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.text.ParseException; import java.text.ParseException;
import java.time.ZoneId;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -29,6 +30,7 @@ import de.sekmi.histream.impl.ExternalSourceImpl; ...@@ -29,6 +30,7 @@ import de.sekmi.histream.impl.ExternalSourceImpl;
import de.sekmi.histream.impl.Meta; import de.sekmi.histream.impl.Meta;
import de.sekmi.histream.impl.ObservationFactoryImpl; import de.sekmi.histream.impl.ObservationFactoryImpl;
import de.sekmi.histream.impl.ObservationImpl; import de.sekmi.histream.impl.ObservationImpl;
import de.sekmi.histream.xml.DateTimeAccuracyAdapter;
/** /**
* Read grouped observations from XML * Read grouped observations from XML
...@@ -61,32 +63,50 @@ public class GroupedXMLReader implements ObservationSupplier { ...@@ -61,32 +63,50 @@ public class GroupedXMLReader implements ObservationSupplier {
private DateTimeAccuracy encounterStart; private DateTimeAccuracy encounterStart;
private DateTimeAccuracy encounterEnd; private DateTimeAccuracy encounterEnd;
private Map<String,String> visitData; private Map<String,String> visitData;
private ZoneId zoneId;
public GroupedXMLReader(ObservationFactory factory, InputStream input)throws JAXBException, XMLStreamException, FactoryConfigurationError{
this(factory, input, null);
}
/** /**
* The provided {@code input} is not closed by a call to {@link #close()} * The provided {@code input} is not closed by a call to {@link #close()}
* *
* @param factory observation factory * @param factory observation factory
* @param input XML input * @param input XML input
* @param localZone zone to use for local timestamps
* @throws JAXBException JAXB error * @throws JAXBException JAXB error
* @throws XMLStreamException XML stream error * @throws XMLStreamException XML stream error
* @throws FactoryConfigurationError other error * @throws FactoryConfigurationError other error
*/ */
public GroupedXMLReader(ObservationFactory factory, InputStream input)throws JAXBException, XMLStreamException, FactoryConfigurationError{ public GroupedXMLReader(ObservationFactory factory, InputStream input, ZoneId localZone)throws JAXBException, XMLStreamException, FactoryConfigurationError{
this(factory, XMLInputFactory.newInstance().createXMLStreamReader(input)); this(factory, XMLInputFactory.newInstance().createXMLStreamReader(input), localZone);
}
public GroupedXMLReader(ObservationFactory factory, XMLStreamReader reader) throws JAXBException, XMLStreamException{
this(factory,reader,null);
} }
/** /**
* Construct a reader with a {@link XMLStreamReader}. The {@code reader} is closed when {@link #close()} is called. * Construct a reader with a {@link XMLStreamReader}. The {@code reader} is closed when {@link #close()} is called.
* @param factory observation factory * @param factory observation factory
* @param reader xml reader * @param reader xml reader
* @param localZone zone to use for local timestamps
* @throws JAXBException jaxb error * @throws JAXBException jaxb error
* @throws XMLStreamException stream error * @throws XMLStreamException stream error
*/ */
public GroupedXMLReader(ObservationFactory factory, XMLStreamReader reader) throws JAXBException, XMLStreamException{ public GroupedXMLReader(ObservationFactory factory, XMLStreamReader reader, ZoneId localZone) throws JAXBException, XMLStreamException{
super(); super();
this.factory = factory; this.factory = factory;
this.patientData = new HashMap<>(); this.patientData = new HashMap<>();
this.visitData = new HashMap<>(); this.visitData = new HashMap<>();
unmarshaller = JAXBContext.newInstance(ObservationImpl.class,Meta.class).createUnmarshaller(); unmarshaller = JAXBContext.newInstance(ObservationImpl.class,Meta.class).createUnmarshaller();
this.zoneId = localZone;
if( zoneId != null ){
// modify marshaller to use the timezone for timestamps
DateTimeAccuracyAdapter a = new DateTimeAccuracyAdapter();
a.setZoneId(zoneId);
unmarshaller.setAdapter(DateTimeAccuracyAdapter.class, a);
}
// TODO: set schema // TODO: set schema
//unmarshaller.setSchema(schema); //unmarshaller.setSchema(schema);
this.reader = reader; this.reader = reader;
...@@ -103,7 +123,7 @@ public class GroupedXMLReader implements ObservationSupplier { ...@@ -103,7 +123,7 @@ public class GroupedXMLReader implements ObservationSupplier {
readPatient(); readPatient();
readEncounter(); readEncounter();
} }
private void readToRoot() throws XMLStreamException{ private void readToRoot() throws XMLStreamException{
while( reader.hasNext() ){ while( reader.hasNext() ){
reader.next(); reader.next();
...@@ -155,7 +175,7 @@ public class GroupedXMLReader implements ObservationSupplier { ...@@ -155,7 +175,7 @@ public class GroupedXMLReader implements ObservationSupplier {
if( patientData.containsKey("birthdate") ){ if( patientData.containsKey("birthdate") ){
String dob = patientData.get("birthdate"); String dob = patientData.get("birthdate");
try { try {
currentPatient.setBirthDate(DateTimeAccuracy.parsePartialIso8601(dob)); currentPatient.setBirthDate(DateTimeAccuracy.parsePartialIso8601(dob, zoneId));
} catch (ParseException e) { } catch (ParseException e) {
throw new XMLStreamException("Unable to parse birthdate: "+dob, reader.getLocation(), e); throw new XMLStreamException("Unable to parse birthdate: "+dob, reader.getLocation(), e);
} }
...@@ -167,7 +187,7 @@ public class GroupedXMLReader implements ObservationSupplier { ...@@ -167,7 +187,7 @@ public class GroupedXMLReader implements ObservationSupplier {
// will be empty string for <deceased/> // will be empty string for <deceased/>
if( date != null && date.length() != 0 ){ if( date != null && date.length() != 0 ){
try { try {
currentPatient.setDeathDate(DateTimeAccuracy.parsePartialIso8601(date)); currentPatient.setDeathDate(DateTimeAccuracy.parsePartialIso8601(date, zoneId));
} catch (ParseException e) { } catch (ParseException e) {
throw new XMLStreamException("Unable to parse deceased date: "+date, reader.getLocation(), e); throw new XMLStreamException("Unable to parse deceased date: "+date, reader.getLocation(), e);
} }
...@@ -238,7 +258,7 @@ public class GroupedXMLReader implements ObservationSupplier { ...@@ -238,7 +258,7 @@ public class GroupedXMLReader implements ObservationSupplier {
if( visitData.containsKey("start") ){ if( visitData.containsKey("start") ){
String date = visitData.get("start"); String date = visitData.get("start");
try { try {
encounterStart = DateTimeAccuracy.parsePartialIso8601(date); encounterStart = DateTimeAccuracy.parsePartialIso8601(date, zoneId);
} catch (ParseException e) { } catch (ParseException e) {
throw new XMLStreamException("Unable to parse encounter/start: "+date, reader.getLocation(), e); throw new XMLStreamException("Unable to parse encounter/start: "+date, reader.getLocation(), e);
} }
...@@ -248,7 +268,7 @@ public class GroupedXMLReader implements ObservationSupplier { ...@@ -248,7 +268,7 @@ public class GroupedXMLReader implements ObservationSupplier {
if( visitData.containsKey("end") ){ if( visitData.containsKey("end") ){
String date = visitData.get("end"); String date = visitData.get("end");
try { try {
encounterEnd = DateTimeAccuracy.parsePartialIso8601(date); encounterEnd = DateTimeAccuracy.parsePartialIso8601(date, zoneId);
} catch (ParseException e) { } catch (ParseException e) {
throw new XMLStreamException("Unable to parse encounter/end: "+date, reader.getLocation(), e); throw new XMLStreamException("Unable to parse encounter/end: "+date, reader.getLocation(), e);
} }
......
...@@ -31,8 +31,8 @@ public class DateTimeAccuracyAdapter extends XmlAdapter<String, DateTimeAccuracy ...@@ -31,8 +31,8 @@ public class DateTimeAccuracyAdapter extends XmlAdapter<String, DateTimeAccuracy
public DateTimeAccuracy unmarshal(String v) throws ParseException { public DateTimeAccuracy unmarshal(String v) throws ParseException {
if( v == null )return null; if( v == null )return null;
// parsing will support any zone offset // parsing will support any zone offset
// TODO if zone is missing, assume specified zone // if zone is missing, assume specified zone
return DateTimeAccuracy.parsePartialIso8601(v); return DateTimeAccuracy.parsePartialIso8601(v, zoneId);
} }
@Override @Override
......
...@@ -32,6 +32,7 @@ import org.w3c.dom.Document; ...@@ -32,6 +32,7 @@ import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import de.sekmi.histream.DateTimeAccuracy;
import de.sekmi.histream.ObservationException; import de.sekmi.histream.ObservationException;
import de.sekmi.histream.ObservationSupplier; import de.sekmi.histream.ObservationSupplier;
import de.sekmi.histream.impl.ExternalSourceImpl; import de.sekmi.histream.impl.ExternalSourceImpl;
...@@ -171,6 +172,7 @@ public class TestXMLWriter { ...@@ -171,6 +172,7 @@ public class TestXMLWriter {
ObservationSupplier s = t.getExampleSupplier(); ObservationSupplier s = t.getExampleSupplier();
Document doc = createDocument(); Document doc = createDocument();
GroupedXMLWriter w = new GroupedXMLWriter(new DOMResult(doc)); GroupedXMLWriter w = new GroupedXMLWriter(new DOMResult(doc));
w.setZoneId(ZoneId.of("Asia/Shanghai"));
Meta.transfer(s, w); Meta.transfer(s, w);
Streams.transfer(s, w); Streams.transfer(s, w);
w.close(); w.close();
...@@ -178,6 +180,8 @@ public class TestXMLWriter { ...@@ -178,6 +180,8 @@ public class TestXMLWriter {
doc.normalizeDocument(); doc.normalizeDocument();
XMLUtils.printDOM(doc, debugLog); XMLUtils.printDOM(doc, debugLog);
// read back DOM
} }
@Test @Test
public void testWriteStream() throws Exception{ public void testWriteStream() throws Exception{
...@@ -192,15 +196,42 @@ public class TestXMLWriter { ...@@ -192,15 +196,42 @@ public class TestXMLWriter {
} }
@Test @Test
public void testTimestampsWithZoneOffset() throws Exception{ public void testTimestampsWithZoneOffset() throws Exception{
ZoneId zone = ZoneId.of("Asia/Shanghai");
FileObservationProviderTest t = new FileObservationProviderTest(); FileObservationProviderTest t = new FileObservationProviderTest();
t.initializeObservationFactory(); t.initializeObservationFactory();
ObservationSupplier s = t.getExampleSupplier(); ObservationSupplier s = t.getExampleSupplier();
GroupedXMLWriter w = new GroupedXMLWriter(debugLog); Path temp = Files.createTempFile("eav", ".xml");
w.setZoneId(ZoneId.of("Asia/Shanghai")); try( OutputStream out = Files.newOutputStream(temp) ){
Meta.transfer(s, w); GroupedXMLWriter w = new GroupedXMLWriter(out);
Streams.transfer(s, w); w.setZoneId(zone);
w.close(); Meta.transfer(s, w);
s.close(); Streams.transfer(s, w);
w.close();
s.close();
}
System.out.println("XML output written to "+temp);
// read back XML
try( InputStream in = Files.newInputStream(temp) ){
GroupedXMLReader reader = new GroupedXMLReader(t.getFactory(), in);
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2014-09-07T18:40:03+0800"), reader.get().getStartTime());
reader.close();
}
// delete temp file
Files.delete(temp);
// read without zone
try( InputStream in = getClass().getResourceAsStream("/dwh.xml") ){
GroupedXMLReader reader = new GroupedXMLReader(t.getFactory(), in);
// local timestamps treated as UTC
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2014-09-07T18:40:03+0800"), reader.get().getStartTime());
reader.close();
}
try( InputStream in = getClass().getResourceAsStream("/dwh.xml") ){
// local timestamps treated as CST
GroupedXMLReader reader = new GroupedXMLReader(t.getFactory(), in, zone);
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2014-09-07T10:40:03+0800"), reader.get().getStartTime());
reader.close();
}
} }
@Test @Test
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment