Commit d9546276 authored by R.W.Majeed's avatar R.W.Majeed

JAXB classes for query exchange moved to project broker-api

parent fbd580d8
......@@ -12,33 +12,7 @@
<version>0.1-SNAPSHOT</version>
</parent>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>target/generated-resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<executions>
<execution>
<id>schemagen</id>
<goals>
<goal>schemagen</goal>
</goals>
</execution>
</executions>
<configuration>
<locale>en</locale>
<sources>
<source>src/main/java/org/aktin/exchange</source>
</sources>
</configuration>
</plugin>
<plugin>
<!-- this is only needed for generating sequence diagrams
for the documentation -->
......
package org.aktin.exchange;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Status for a data warehouse node
*
* @author R.W.Majeed
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="node-status")
public class NodeStatus {
public NodeStatus(){
}
/**
* Version of the dwh-api component
*/
Instant timestamp;
Duration uptime;
@XmlElement(name="module")
List<SoftwareModule> modules;
}
package org.aktin.exchange;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
/**
* Principal of a query.
* @author R.W.Majeed
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
public class Principal {
/**
* Principal's full name
*/
@XmlElement(required=true)
public String name;
/**
* Principal's organisation
*/
@XmlElement(required=true)
public String organisation;
@XmlElement(required=true)
public String email;
@XmlElement(required=true)
public String phone;
/**
* Postal address
*/
public String address;
/**
* Web page URL
*/
public String url;
}
package org.aktin.exchange;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.w3c.dom.Element;
/**
* Query which can be executed in an i2b2
* data warehouse by the AKTIN remote query
* plugin.
*
* @author R.W.Majeed
*
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Query {
/**
* Unique identifier for this query. This identifier
* will not change, even if a query scheduled for repeated
* executions.
*/
@XmlElement(required=true)
public String id;
/**
* Human readable description of the query.
*/
@XmlElement(required=true)
public String description;
/**
* Contact for inquiries and further
* information about the query and research
* project.
*/
@XmlElement(required=true)
public Principal principal;
/**
* Execution schedule for the query. For now,
* only {@link SingleExecution} and {@link RepeatedExecution}
* are supported.
*/
@XmlElement(required=true)
public QuerySchedule schedule;
/**
* Extension to specify export definition and query definition.
* <p>
* E.g. for native i2b2: elements {@code query_definition} and {@code result_output_list}
* from XML namespace {@code http://www.i2b2.org/xsd/cell/crc/psm/1.1/}.
* </p>
*/
@XmlAnyElement
public List<Element> extensions;
}
package org.aktin.exchange;
import java.time.Instant;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class QueryRequest {
/**
* Unique id for the query request.
* This id will always be unique and different
* for multiple (e.g. recurring) requests for
* the same query.
* The id is given by the broker.
*/
@XmlElement(required=true)
String id;
/**
* Date reference for recurring queries. A recurring
* query may be requested once per month. The reference
* date will then be used to determine the time frame
* for the query. In other words, the reference date is used
* to fill a placeholder in the recurring query.
*/
@XmlElement(required=false)
Instant referenceDate;
/**
* Time stamp when the request was published at the query broker.
*/
@XmlElement(required=true)
Instant published;
/**
* Time stamp for the earliest execution / when the request is open.
* If unspecified, the query can be executed at any time (usually
* before the deadline)
*/
@XmlElement(required=false)
Instant scheduled;
/**
* Due date until which the query results have to be submitted.
*/
@XmlElement(required=true)
Instant deadline;
/**
* Date when the request was closed by the query broker. While
* this date is unset/null, results can be sumitted at any time.
*/
Instant closed;
/**
* Date when the request was canceled. This indicates abnormal
* or unsuccessful termination of the request.
* A request can not be closed and canceled at the same time.
*/
Instant canceled;
/**
* Query to execute
*/
@XmlElement(required=true)
Query query;
@XmlElement(name="signature", required=false)
Signature[] signatures;
}
package org.aktin.exchange;
import java.time.Period;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
/**
* Abstract query schedule
* @author R.W.Majeed
*
*/
@XmlSeeAlso({SingleExecution.class, RepeatedExecution.class})
public abstract class QuerySchedule {
/**
* Duration for the queried data, relative to the request reference date
* {@link QueryRequest#referenceDate}. Usually negative: e.g. -D1M for previous month.
*/
@XmlElement(required=true)
public Period duration;
}
package org.aktin.exchange;
import java.time.Duration;
/**
* Repeated execution schedule for a query.
*
* The repeated execution does not contain a reference timestamp. Instead, the reference
* timestamp is provided by the query request from the broker.
*
* @author R.W.Majeed
*
*/
public class RepeatedExecution extends QuerySchedule{
/**
* Estimated repeating interval. Only positive periods allowed.
* This property will not cause any execution on the data warehouse side.
* It is solely for information purposes.
*/
public Duration interval;
}
package org.aktin.exchange;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlValue;
/**
* Signature during query exchange
*
* @author R.W.Majeed
*
*/
public class Signature {
/** Signature author */
@XmlAttribute
String from;
/** Signature algorithm */
@XmlAttribute
String algorithm;
@XmlValue
byte[] value;
// TODO add code to verify content
}
package org.aktin.exchange;
import java.time.Instant;
import javax.xml.bind.annotation.XmlElement;
/**
* Single execution schedule for a query.
*
* A reference time stamp is provided.
*
* @author R.W.Majeed
*
*/
public class SingleExecution extends QuerySchedule{
/**
* Reference time stamp for queries. If
*/
@XmlElement(required=false)
public Instant reference;
}
package org.aktin.exchange;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
@XmlAccessorType(XmlAccessType.FIELD)
public class SoftwareModule {
@XmlAttribute
String id;
String version;
String url;
}
package org.aktin.exchange;
import javax.xml.bind.annotation.XmlTransient;
@XmlTransient
public class XMLConstants {
public static final String XML_NAMESPACE="http://aktin.org/ns/exchange";
}
/**
* Interfaces for the AKTIN data exchange.
* Requests for query executions, query definitions,
* query responses.
*
* @author R.W.Majeed
*
*/
@XmlSchema(namespace=XMLConstants.XML_NAMESPACE,
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns = {
@XmlNs(prefix = "xsi", namespaceURI = javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)
//"http://www.w3.org/2001/XMLSchema-instance"
}
)
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters({
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(type=java.time.Duration.class,value=org.aktin.xml.DurationAdapter.class),
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(type=java.time.Period.class,value=org.aktin.xml.PeriodAdapter.class),
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(type=java.time.Instant.class,value=org.aktin.xml.InstantAdapter.class)
})
package org.aktin.exchange;
import javax.xml.bind.annotation.*;
\ No newline at end of file
package org.aktin.xml;
import java.time.Duration;
import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
* JAXB adapter for processing java.time.Duration.
* This can be removed later on when native support is added to the JAXB implementation
*
*/
public class DurationAdapter extends XmlAdapter<String, Duration>{
@Override
public String marshal(Duration v) throws Exception {
if( v == null )return null;
else return v.toString();
}
@Override
public Duration unmarshal(String v) throws Exception {
if( v == null )return null;
else return Duration.parse(v);
}
}
\ No newline at end of file
package org.aktin.xml;
import java.time.Instant;
import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
* JAXB adapter for processing java.time.Instant.
* This can be removed later on when native support is added to the JAXB implementation
*
*/
public class InstantAdapter extends XmlAdapter<String, Instant>{
@Override
public Instant unmarshal(String v) throws Exception {
if( v == null )return null;
else return Instant.parse(v);
}
@Override
public String marshal(Instant v) throws Exception {
if( v == null )return null;
else return v.toString();
}
}
\ No newline at end of file
package org.aktin.xml;
import java.time.Period;
import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
* JAXB adapter for processing java.time.Duration.
* This can be removed later on when native support is added to the JAXB implementation
*
*/
public class PeriodAdapter extends XmlAdapter<String, Period>{
@Override
public String marshal(Period v) throws Exception {
if( v == null )return null;
else return v.toString();
}
@Override
public Period unmarshal(String v) throws Exception {
if( v == null )return null;
else return Period.parse(v);
}
}
\ No newline at end of file
package org.aktin.exchange;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.xml.bind.JAXB;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
public class TestUnmarshallDocuments {
XMLReader reader;
Validator validator;
@Before
public void initializeXIncludeReader() throws SAXException{
SAXParser parser;
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setXIncludeAware(true);
factory.setNamespaceAware(true);
// do not insert xml:base attributes for XIncludes
factory.setFeature("http://apache.org/xml/features/xinclude/fixup-base-uris", false);
parser = factory.newSAXParser();
} catch (ParserConfigurationException e) {
throw new SAXException(e);
}
reader = parser.getXMLReader();
}
@Before
public void initializeValidator() throws IOException, SAXException{
URL xsd = getClass().getResource("/schemagen/schema1.xsd");
SchemaFactory factory =
SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema;
try( InputStream in = xsd.openStream() ){
schema = factory.newSchema(new StreamSource(in));
}
validator = schema.newValidator();
}
private Source getResource(URL url){
SAXSource xml = new SAXSource(reader, new InputSource(url.toString()));
//xml.setSystemId(doc.toString());
return xml;
}
private Source getResource(String name){
return getResource(getClass().getResource(name));
}
@Test
public void validateQuery() throws IOException, SAXException{
validator.validate(getResource("/query.xml"));
}
@Test
public void unmarshallQuery() throws IOException, SAXException{
Source xml = getResource("/query.xml");
Query query = JAXB.unmarshal(xml, Query.class);
Assert.assertEquals(SingleExecution.class, query.schedule.getClass());
SingleExecution se = (SingleExecution)query.schedule;
Assert.assertNotNull(se.duration);
Assert.assertNotNull(se.reference);
//System.out.println("Duration:"+se.duration);
//System.out.println("Reference:"+se.reference);
for( Element el : query.extensions ){
System.out.println("Extension name="+el.getLocalName()+", ns="+el.getNamespaceURI());
}
}
@Test
public void validateQueryRequest() throws IOException, SAXException, TransformerException{
validator.validate(getResource("/request.xml"));
}
@Test
public void unmarshallRequest(){
QueryRequest r = JAXB.unmarshal(getResource("/request.xml"), QueryRequest.class);
Assert.assertNotNull(r.published);
Assert.assertNotNull(r.deadline);
}
@Test
public void unmarshall_node_status(){
NodeStatus n = JAXB.unmarshal(getResource("/node-status.xml"), NodeStatus.class);
Assert.assertNotNull(n.timestamp);
Assert.assertNotNull(n.uptime);
}
}
<broker-status>
<timestamp></timestamp>
<uptime></uptime>
<!-- latest software for nodes -->
<node-software>
<module id="dwh">
<version></version>
<url></url>
</module>
<module id="aktin.art-decor.runtime">
<version></version>
<url></url>
</module>
</node-software>
</broker-status>
\ No newline at end of file
<node-status xmlns="http://aktin.org/ns/exchange">
<!-- when the status was collected -->
<timestamp>2016-07-08T00:00:00Z</timestamp>
<!-- duration the (application)server is running -->
<uptime>PT15S</uptime>
<!-- timestamp when the latest data/CDA was imported -->
<latest-import></latest-import>
<!-- version number of the running EAR, all other versions
can be deduced from the release POM -->
<!-- get this info via new InitialContext().lookup("java:app/AppName") -->
<module id="dwh">
<version>dwh-ear-0.2-SNAPSHOT</version>
</module>
<module id="aktin.art-decor.runtime">
<version></version>
</module>
</node-status>
\ No newline at end of file
<query xmlns="http://aktin.org/ns/exchange"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dwh="http://aktin.org/ns/dwh"
xmlns:psm="http://www.i2b2.org/xsd/cell/crc/psm/1.1/">
<id>123</id>
<description>Lala</description>
<principal>
<name>Principal</name>
<organisation>AKTIN</organisation>
<email>it-support@aktin.org</email>
<phone>+49 (441) 798 - 2772</phone>
</principal>
<schedule xsi:type="repeatedExecution">
<duration>-1W</duration>
<interval>P1D</interval>
<!-- created timestamp? -->
</schedule>
<concepts>
<concept id="birthdate" xsi:type="raw"/>
</concepts>
<!-- also possible: xsi:type="psm:query_definition" -->
<!-- also possible: xsi:type="dwh:eclectic_query",
see http://methods.schattauer.de/en/contents/archivestandard/issue/2168/manuscript/21349/show.html
-->
<dwh:sql xsi:type="dwh:sqlt">
SELECT a, b;
</dwh:sql>
</query>
<query-result request-ref="1" xmlns="http://aktin.org/ns/exchange"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<timestamp>2015-12-02T18:30:14</timestamp>
<execution-time>P10S</execution-time>
<result xsi:type="result-tables">
<table id="patients">
<thead>
<tr>
<td>id</td>
<td>birthdate</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2010-01-01</td>
</tr>
</tbody>
</table>
<table id="visits">
<headers>
<header>patient-ref</header>
<header>id</header>
<header>start</header>
</headers>
<tr>
<td>1</td>
<td>1</td>
<td>2016-05-08T09:32:00</td>
</tr>
</table>
<table id="diagnoses">
<headers>
<header>patient-ref</header>
<header>visit-ref</header>
<header>start</header>
<header>code</header>
</headers>
<tr>
<td>1</td>
<td>1</td>
<td>2016-05-08T09:32:00</td>
<td>R46.1</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>2016-05-08T09:32:00</td>
<td>W46.05</td>
</tr>
</table>
</result>
<!-- OR <result xsi:type="aggragated-result"> <value id="cedis-count">321</value>
<breakdown id="gender"> <value id="male">110</value> <value id="female">112</value>
</breakdown> </result> -->
</query-result>
\ No newline at end of file
<query xmlns="http://aktin.org/ns/exchange" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dwh="http://aktin.org/ns/dwh" xmlns:psm="http://www.i2b2.org/xsd/cell/crc/psm/1.1/">
<id>123</id>
<description>Lala</description>
<principal>
<name>Prince Ipal</name>
<organisation>AKTIN</organisation>
<email>it-support@aktin.org</email>
<phone>+49 (441) 798 - 2772</phone>
<!-- optional cryptographic signature at a later release <signature></signature> -->
</principal>
<schedule xsi:type="singleExecution">