Commit 9e987b20 authored by R.W.Majeed's avatar R.W.Majeed

date parsing will throw checked ParseException

parent 4fa410e4
package de.sekmi.histream;
import java.text.ParseException;
import java.time.DateTimeException;
/*
......@@ -194,14 +195,16 @@ public class DateTimeAccuracy implements Temporal, Comparable<DateTimeAccuracy>
* @return date time with accuracy as derived from parse
* @throws IllegalArgumentException for unparsable string
*/
public static DateTimeAccuracy parsePartialIso8601(String str)throws IllegalArgumentException{
if( str.length() < 4 )throw new IllegalArgumentException("Need at least 4 characters for year: "+str);
public static DateTimeAccuracy parsePartialIso8601(String str)throws ParseException{
if( str.length() < 4 )throw new ParseException("Need at least 4 characters for year: "+str, str.length());
// parse year
int year = Integer.parseInt(str.substring(0, 4));
if( str.length() == 4 ){ // specified to accuracy of years
return new DateTimeAccuracy(year);
}else if( str.length() < 7 || str.charAt(4) != '-' ){
throw new IllegalArgumentException("Expected YYYY-MM");
}else if( str.length() < 7 ){
throw new ParseException("Expected YYYY-MM", str.length());
}else if( str.charAt(4) != '-' ){
throw new ParseException("Expected YYYY-MM", 4);
}
// parse month
int month = Integer.parseInt(str.substring(5, 7));
......
......@@ -27,6 +27,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Hashtable;
......@@ -253,7 +254,7 @@ public class FlatObservationSupplier extends AbstractObservationParser implement
currentVisit = visitAccessor.accessStatic(visitId,currentPatient,(ExternalSourceType)this);
}
}
private void specialFields(SpecialConcept special, Record record){
private void specialFields(SpecialConcept special, Record record) throws ParseException{
// make sure current patient is valid
lazyCreatePatient(record.getPatID());
......@@ -325,7 +326,7 @@ public class FlatObservationSupplier extends AbstractObservationParser implement
return value;
}
private void newObservation(Record record){
private void newObservation(Record record) throws ParseException{
DateTimeAccuracy ts;
DateTimeAccuracy sourceTs = getSourceDateTime();
if( record.getStartDate() == null ){
......@@ -413,28 +414,33 @@ public class FlatObservationSupplier extends AbstractObservationParser implement
// continue;
}else{
// parse observation
Record fields = new Record(fieldSeparatorPattern.split(line, maxFields));
// fields: 0 patid, 1 encounter, 2 concept, 3: type, 4: value, 5: starttime,
// handle special concepts (defined by previous commands)
SpecialConcept special = specialConcepts.get(fields.getConcept());
if( special != null ){
specialFields(special, fields);
// continue;
}else if( inGroup ){
// first item is fact, following items are modifiers
if( fact == null ){
newObservation(fields);
try{
Record fields = new Record(fieldSeparatorPattern.split(line, maxFields));
// fields: 0 patid, 1 encounter, 2 concept, 3: type, 4: value, 5: starttime,
// handle special concepts (defined by previous commands)
SpecialConcept special = specialConcepts.get(fields.getConcept());
if( special != null ){
specialFields(special, fields);
// continue;
}else if( inGroup ){
// first item is fact, following items are modifiers
if( fact == null ){
newObservation(fields);
}else{
appendModifier(fields);
}
// continue;
// group ends with #@group(end)
}else{
appendModifier(fields);
// assert( fact == null )
newObservation(fields);
break;
}
// continue;
// group ends with #@group(end)
}else{
// assert( fact == null )
newObservation(fields);
break;
} catch (ParseException e) {
throw new UncheckedIOException(new IOException(e));
}
}
}while( true );
Observation ret = fact;
......
......@@ -3,6 +3,7 @@ package de.sekmi.histream.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
......@@ -146,16 +147,29 @@ public class GroupedXMLReader implements ObservationSupplier {
// register with extension
currentPatient = patientAccessor.accessStatic(patientId, (ExternalSourceType)es);
// immediately set source timestamp
if( es != null ){
currentPatient.setSourceTimestamp(es.getSourceTimestamp());
}
// TODO set patient data
if( patientData.containsKey("birthdate") ){
currentPatient.setBirthDate(DateTimeAccuracy.parsePartialIso8601(patientData.get("birthdate")));
String dob = patientData.get("birthdate");
try {
currentPatient.setBirthDate(DateTimeAccuracy.parsePartialIso8601(dob));
} catch (ParseException e) {
throw new XMLStreamException("Unable to parse birthdate: "+dob, reader.getLocation(), e);
}
}
if( patientData.containsKey("deceased") ){
// patient known to be deceased
currentPatient.setDeceased(true);
String date = patientData.get("deceased");
if( date != null ){
currentPatient.setDeathDate(DateTimeAccuracy.parsePartialIso8601(date));
try {
currentPatient.setDeathDate(DateTimeAccuracy.parsePartialIso8601(date));
} catch (ParseException e) {
throw new XMLStreamException("Unable to parse deceased date: "+date, reader.getLocation(), e);
}
}
}
if( patientData.containsKey("gender") ){
......@@ -167,9 +181,6 @@ public class GroupedXMLReader implements ObservationSupplier {
if( patientData.containsKey("given-name") ){
currentPatient.setGivenName(patientData.get("given-name"));
}
if( es != null ){
currentPatient.setSourceTimestamp(es.getSourceTimestamp());
}
}
......@@ -224,12 +235,22 @@ public class GroupedXMLReader implements ObservationSupplier {
reader.nextTag();
}
if( visitData.containsKey("start") ){
encounterStart = DateTimeAccuracy.parsePartialIso8601(visitData.get("start"));
String date = visitData.get("start");
try {
encounterStart = DateTimeAccuracy.parsePartialIso8601(date);
} catch (ParseException e) {
throw new XMLStreamException("Unable to parse encounter/start: "+date, reader.getLocation(), e);
}
}else{
encounterStart = null;
}
if( visitData.containsKey("end") ){
encounterEnd = DateTimeAccuracy.parsePartialIso8601(visitData.get("end"));
String date = visitData.get("end");
try {
encounterEnd = DateTimeAccuracy.parsePartialIso8601(date);
} catch (ParseException e) {
throw new XMLStreamException("Unable to parse encounter/end: "+date, reader.getLocation(), e);
}
}else{
encounterEnd = null;
}
......
......@@ -22,6 +22,7 @@ package de.sekmi.histream.io;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
......@@ -104,7 +105,7 @@ class XMLObservationParser extends AbstractObservationParser{
// TODO: log error
}
}
protected void newObservation(AttributeAccessor atts){
protected void newObservation(AttributeAccessor atts) throws ParseException{
// determine start time
DateTimeAccuracy start;
String ts = atts.getValue("start");
......@@ -213,7 +214,7 @@ class XMLObservationParser extends AbstractObservationParser{
setMeta(ObservationSupplier.META_SOURCE_TIMESTAMP, atts.getValue("timestamp"));
setMeta(ObservationSupplier.META_SOURCE_ID, atts.getValue("id"));
}
protected void parseEncounter(AttributeAccessor atts){
protected void parseEncounter(AttributeAccessor atts) throws ParseException{
encounterStart = DateTimeAccuracy.parsePartialIso8601(atts.getValue("start"));
if( atts.getValue("end") != null ){
encounterEnd = DateTimeAccuracy.parsePartialIso8601(atts.getValue("end"));
......
......@@ -24,6 +24,7 @@ package de.sekmi.histream.io;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.text.ParseException;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
......@@ -118,7 +119,11 @@ public class XMLObservationSupplier extends XMLObservationParser implements Obse
// read visit attributes
if( reader.getLocalName().equals("encounter") ){
parseEncounter(atts);
try {
parseEncounter(atts);
} catch (ParseException e) {
throw new XMLStreamException("Unable to parse encounter", reader.getLocation(), e);
}
}
String text = reader.getElementText();
......@@ -158,7 +163,11 @@ public class XMLObservationSupplier extends XMLObservationParser implements Obse
|| reader.getLocalName().equals("eav-group")) ){
throw new XMLStreamException("Element eav-item or eav-group expected instead of "+reader.getLocalName(), reader.getLocation());
}
newObservation(atts);
try {
newObservation(atts);
} catch (ParseException e) {
throw new XMLStreamException("Unable to parse observation", reader.getLocation(), e);
}
if( reader.getLocalName().equals("eav-group") ){
// group item can have value
parseValueAttributes(atts);
......
package de.sekmi.histream.xml;
import java.text.ParseException;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import de.sekmi.histream.DateTimeAccuracy;
......@@ -13,7 +15,7 @@ import de.sekmi.histream.DateTimeAccuracy;
public class DateTimeAccuracyAdapter extends XmlAdapter<String, DateTimeAccuracy>{
@Override
public DateTimeAccuracy unmarshal(String v) {
public DateTimeAccuracy unmarshal(String v) throws ParseException {
if( v == null )return null;
return DateTimeAccuracy.parsePartialIso8601(v);
}
......
package de.sekmi.histream.impl;
import java.text.ParseException;
/*
* #%L
* histream
......@@ -40,7 +42,7 @@ public class TestDateTimeAccuracy {
}
}
@Test
public void testParseToString(){
public void testParseToString() throws ParseException{
final String[] str = new String[]{"2001-03-04T10:16:07", "2001-03-04T10:16:00"};
DateTimeAccuracy a = DateTimeAccuracy.parsePartialIso8601(str[0]);
Assert.assertEquals(ChronoUnit.SECONDS, a.getAccuracy());
......@@ -52,7 +54,7 @@ public class TestDateTimeAccuracy {
}
@Test
public void testPartialDates(){
public void testPartialDates() throws ParseException{
final String[] str = {"2001-03-04T05:06","2001-03-04T05","2001-03-04","2001-03","2001"};
final ChronoUnit[] expectedAccuracy = {ChronoUnit.MINUTES, ChronoUnit.HOURS, ChronoUnit.DAYS, ChronoUnit.MONTHS, ChronoUnit.YEARS};
for( int i=0; i<expectedAccuracy.length; i++ ){
......
......@@ -24,11 +24,13 @@ package de.sekmi.histream.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.util.Iterator;
import java.util.function.Supplier;
import java.math.BigDecimal;
import java.text.ParseException;
import javax.xml.bind.JAXBException;
import javax.xml.stream.FactoryConfigurationError;
......@@ -81,8 +83,12 @@ public class FileObservationProviderTest {
Assert.assertNotNull("Patient extension required", p);
Assert.assertEquals("XX12345", p.getId());
Assert.assertEquals(Boolean.TRUE, p.getDeceased());
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2001-01-01"), p.getBirthDate());
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2020"), p.getDeathDate());
try {
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2001-01-01"), p.getBirthDate());
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2020"), p.getDeathDate());
} catch (ParseException e) {
throw new RuntimeException(e);
}
Assert.assertEquals(Sex.female, p.getSex());
Assert.assertEquals("A B", p.getGivenName());
Assert.assertEquals("Dampf", p.getSurname());
......@@ -93,8 +99,12 @@ public class FileObservationProviderTest {
Visit v = o.getExtension(Visit.class);
Assert.assertNotNull("Visit extension required", v);
Assert.assertEquals("Zuhause", v.getLocationId());
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2014-01-01T10:30:00"), v.getStartTime());
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2014-01-05T10:30:00"), v.getEndTime());
try{
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2014-01-01T10:30:00"), v.getStartTime());
Assert.assertEquals(DateTimeAccuracy.parsePartialIso8601("2014-01-05T10:30:00"), v.getEndTime());
} catch (ParseException e) {
throw new RuntimeException(e);
}
// TODO test visit information
// test source
......
......@@ -3,7 +3,6 @@ package de.sekmi.histream.etl;
import java.io.IOException;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.net.URL;
import javax.script.ScriptException;
......
......@@ -7,7 +7,6 @@ import java.net.URLConnection;
import java.util.Arrays;
import java.util.List;
import javax.script.ScriptException;
import javax.xml.bind.JAXB;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
......@@ -19,7 +18,6 @@ import javax.xml.bind.annotation.XmlSeeAlso;
import de.sekmi.histream.ObservationFactory;
import de.sekmi.histream.etl.FactGroupingQueue;
import de.sekmi.histream.etl.ScriptProcessingQueue;
import de.sekmi.histream.etl.VisitPostProcessorQueue;
/**
* Data source configuration.
......
......@@ -3,7 +3,6 @@ package de.sekmi.histream.etl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.junit.After;
import org.junit.Assert;
......@@ -98,7 +97,7 @@ public class TestETLSupplier {
}
@Test
public void testPatientExtension() throws IOException{
public void testPatientExtension() throws IOException, java.text.ParseException{
Observation fact = os.get();
Assert.assertNotNull(fact);
Patient p = fact.getExtension(Patient.class);
......@@ -119,7 +118,7 @@ public class TestETLSupplier {
// nothing to do anymore
}
@Test
public void testVisitExtension() throws IOException{
public void testVisitExtension() throws IOException, java.text.ParseException{
Observation fact = os.get();
Assert.assertNotNull(fact);
......
package de.sekmi.histream.scripting;
import java.math.BigDecimal;
import java.text.ParseException;
import de.sekmi.histream.DateTimeAccuracy;
import de.sekmi.histream.Observation;
import de.sekmi.histream.Value;
import de.sekmi.histream.impl.NumericValue;
import de.sekmi.histream.impl.StringValue;
......@@ -20,11 +20,11 @@ public class Fact {
return observation.getConceptId();
}
public Fact start(String incompleteDateTime){
public Fact start(String incompleteDateTime) throws ParseException{
observation.setStartTime(DateTimeAccuracy.parsePartialIso8601(incompleteDateTime));
return this;
}
public Fact end(String incompleteDateTime){
public Fact end(String incompleteDateTime) throws ParseException{
observation.setEndTime(DateTimeAccuracy.parsePartialIso8601(incompleteDateTime));
return this;
}
......
package de.sekmi.histream.scripting;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
......@@ -26,13 +27,13 @@ public class TestFacts {
DateTimeAccuracy defaultStart;
@Before
public void setup() throws ScriptException{
public void setup() throws ScriptException, ParseException{
sem = new ScriptEngineManager();
engine = sem.getEngineByName("nashorn");
// enable strict mode
engine.eval("'use strict';");
factory = new ObservationFactoryImpl();
defaultStart = DateTimeAccuracy.parsePartialIso8601("2016");
Observation[] facts = new Observation[]{
factory.createObservation("P1", "C1", DateTimeAccuracy.parsePartialIso8601("2011")),
......
......@@ -52,14 +52,13 @@
</license>
</licenses>
<modules>
<!--
<module>histream-i2b2</module>
<module>histream-core</module>
<module>histream-hl7</module>
<module>histream-skos</module>
<module>histream-import</module>
<module>histream-export</module>
<module>histream-js</module>-->
<module>histream-js</module>
<module>histream-maven-plugin</module>
<!--
<module>i2b2-integration-tests</module>
......
Markdown is supported
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