diff --git a/pom.xml b/pom.xml
index afbbfc74..8fc84ec4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -102,6 +102,13 @@
2.6
+
+
+ org.apache.poi
+ poi-ooxml
+ 5.2.5
+
+
org.hamcrest
diff --git a/src/main/java/cz/cvut/kbss/study/model/export/ExportRecord.java b/src/main/java/cz/cvut/kbss/study/model/export/ExportRecord.java
new file mode 100644
index 00000000..fd861648
--- /dev/null
+++ b/src/main/java/cz/cvut/kbss/study/model/export/ExportRecord.java
@@ -0,0 +1,311 @@
+package cz.cvut.kbss.study.model.export;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+
+public class ExportRecord {
+
+ private URI uri;
+
+
+ private Date created;
+
+ private Date modified;
+
+ private String label;
+
+ private String phase;
+
+ private String institution;
+
+ private String aircraftType;
+
+ private String fuselage;
+
+ private URI ac_comp;
+
+ private String ac_compName;
+
+
+ private List path;
+
+ private String failDate;
+
+
+ private String flightHours;
+
+ private Integer numberOfAirframeOverhauls;
+
+ private String classificationOfOccurrence;
+
+ private String failureAscertainmentCircumstances;
+
+ private String repeatedFailure;
+
+ private String failureCause;
+
+ private String consequence;
+
+ private String mission;
+
+ private String repair;
+
+ private String repairDuration;
+
+ private Double averageNumberOfMenDuringRepairment;
+
+ private String failureDescription;
+
+ private String descriptionOfCorrectiveAction;
+
+ private String yearOfProductionOfDefectiveEquipment;
+
+ private Integer numberOfOverhaulsOfDefectiveEquipment;
+
+ private String serialNoOf;
+
+ private String notes;
+
+ private String fhaEvent;
+
+ public URI getUri() {
+ return uri;
+ }
+
+ public void setUri(URI uri) {
+ this.uri = uri;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public Date getModified() {
+ return modified;
+ }
+
+ public void setModified(Date modified) {
+ this.modified = modified;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public String getPhase() {
+ return phase;
+ }
+
+ public void setPhase(String phase) {
+ this.phase = phase;
+ }
+
+ public String getInstitution() {
+ return institution;
+ }
+
+ public void setInstitution(String institution) {
+ this.institution = institution;
+ }
+
+ public String getAircraftType() {
+ return aircraftType;
+ }
+
+ public void setAircraftType(String aircraftType) {
+ this.aircraftType = aircraftType;
+ }
+
+ public String getFuselage() {
+ return fuselage;
+ }
+
+ public void setFuselage(String fuselage) {
+ this.fuselage = fuselage;
+ }
+
+ public URI getAc_comp() {
+ return ac_comp;
+ }
+
+ public void setAc_comp(URI ac_comp) {
+ this.ac_comp = ac_comp;
+ }
+
+ public String getAc_compName() {
+ return ac_compName;
+ }
+
+ public void setAc_compName(String ac_compName) {
+ this.ac_compName = ac_compName;
+ }
+
+ public List getPath() {
+ return path;
+ }
+
+ public void setPath(List path) {
+ this.path = path;
+ }
+
+ public String getFailDate() {
+ return failDate;
+ }
+
+ public void setFailDate(String failDate) {
+ this.failDate = failDate;
+ }
+
+ public String getFlightHours() {
+ return flightHours;
+ }
+
+ public void setFlightHours(String flightHours) {
+ this.flightHours = flightHours;
+ }
+
+ public Integer getNumberOfAirframeOverhauls() {
+ return numberOfAirframeOverhauls;
+ }
+
+ public void setNumberOfAirframeOverhauls(Integer numberOfAirframeOverhauls) {
+ this.numberOfAirframeOverhauls = numberOfAirframeOverhauls;
+ }
+
+ public String getClassificationOfOccurrence() {
+ return classificationOfOccurrence;
+ }
+
+ public void setClassificationOfOccurrence(String classificationOfOccurrence) {
+ this.classificationOfOccurrence = classificationOfOccurrence;
+ }
+
+ public String getFailureAscertainmentCircumstances() {
+ return failureAscertainmentCircumstances;
+ }
+
+ public void setFailureAscertainmentCircumstances(String failureAscertainmentCircumstances) {
+ this.failureAscertainmentCircumstances = failureAscertainmentCircumstances;
+ }
+
+ public String getRepeatedFailure() {
+ return repeatedFailure;
+ }
+
+ public void setRepeatedFailure(String repeatedFailure) {
+ this.repeatedFailure = repeatedFailure;
+ }
+
+ public String getFailureCause() {
+ return failureCause;
+ }
+
+ public void setFailureCause(String failureCause) {
+ this.failureCause = failureCause;
+ }
+
+ public String getConsequence() {
+ return consequence;
+ }
+
+ public void setConsequence(String consequence) {
+ this.consequence = consequence;
+ }
+
+ public String getMission() {
+ return mission;
+ }
+
+ public void setMission(String mission) {
+ this.mission = mission;
+ }
+
+ public String getRepair() {
+ return repair;
+ }
+
+ public void setRepair(String repair) {
+ this.repair = repair;
+ }
+
+ public String getRepairDuration() {
+ return repairDuration;
+ }
+
+ public void setRepairDuration(String repairDuration) {
+ this.repairDuration = repairDuration;
+ }
+
+ public Double getAverageNumberOfMenDuringRepairment() {
+ return averageNumberOfMenDuringRepairment;
+ }
+
+ public void setAverageNumberOfMenDuringRepairment(Double averageNumberOfMenDuringRepairment) {
+ this.averageNumberOfMenDuringRepairment = averageNumberOfMenDuringRepairment;
+ }
+
+ public String getFailureDescription() {
+ return failureDescription;
+ }
+
+ public void setFailureDescription(String failureDescription) {
+ this.failureDescription = failureDescription;
+ }
+
+ public String getDescriptionOfCorrectiveAction() {
+ return descriptionOfCorrectiveAction;
+ }
+
+ public void setDescriptionOfCorrectiveAction(String descriptionOfCorrectiveAction) {
+ this.descriptionOfCorrectiveAction = descriptionOfCorrectiveAction;
+ }
+
+ public String getYearOfProductionOfDefectiveEquipment() {
+ return yearOfProductionOfDefectiveEquipment;
+ }
+
+ public void setYearOfProductionOfDefectiveEquipment(String yearOfProductionOfDefectiveEquipment) {
+ this.yearOfProductionOfDefectiveEquipment = yearOfProductionOfDefectiveEquipment;
+ }
+
+ public Integer getNumberOfOverhaulsOfDefectiveEquipment() {
+ return numberOfOverhaulsOfDefectiveEquipment;
+ }
+
+ public void setNumberOfOverhaulsOfDefectiveEquipment(Integer numberOfOverhaulsOfDefectiveEquipment) {
+ this.numberOfOverhaulsOfDefectiveEquipment = numberOfOverhaulsOfDefectiveEquipment;
+ }
+
+ public String getSerialNoOf() {
+ return serialNoOf;
+ }
+
+ public void setSerialNoOf(String serialNoOf) {
+ this.serialNoOf = serialNoOf;
+ }
+
+ public String getNotes() {
+ return notes;
+ }
+
+ public void setNotes(String notes) {
+ this.notes = notes;
+ }
+
+ public String getFhaEvent() {
+ return fhaEvent;
+ }
+
+ public void setFhaEvent(String fhaEvent) {
+ this.fhaEvent = fhaEvent;
+ }
+}
diff --git a/src/main/java/cz/cvut/kbss/study/model/export/NamedItem.java b/src/main/java/cz/cvut/kbss/study/model/export/NamedItem.java
new file mode 100644
index 00000000..f83bebf1
--- /dev/null
+++ b/src/main/java/cz/cvut/kbss/study/model/export/NamedItem.java
@@ -0,0 +1,23 @@
+package cz.cvut.kbss.study.model.export;
+
+import cz.cvut.kbss.jopa.model.annotations.*;
+import cz.cvut.kbss.study.model.AbstractEntity;
+
+@SparqlResultSetMappings(value =
+@SparqlResultSetMapping(name = "NamedItem", entities = {
+ @EntityResult(entityClass = NamedItem.class)
+})
+)
+@OWLClass(iri = "http://named-item")
+public class NamedItem extends AbstractEntity {
+ @OWLDataProperty(iri = "http://name")
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/cz/cvut/kbss/study/model/export/Path.java b/src/main/java/cz/cvut/kbss/study/model/export/Path.java
new file mode 100644
index 00000000..3b0d51ca
--- /dev/null
+++ b/src/main/java/cz/cvut/kbss/study/model/export/Path.java
@@ -0,0 +1,67 @@
+package cz.cvut.kbss.study.model.export;
+
+
+import cz.cvut.kbss.jopa.model.annotations.*;
+import cz.cvut.kbss.study.model.AbstractEntity;
+
+import java.net.URI;
+
+@SparqlResultSetMappings(value =
+@SparqlResultSetMapping(name = "Path", entities = {
+ @EntityResult(entityClass = Path.class)
+})
+)
+@OWLClass(iri = "http://path")
+public class Path extends AbstractEntity {
+
+ @OWLDataProperty(iri = "http://l1")
+ protected URI l1;
+ @OWLDataProperty(iri = "http://l2")
+ protected URI l2;
+ @OWLDataProperty(iri = "http://l3")
+ protected URI l3;
+ @OWLDataProperty(iri = "http://l4")
+ protected URI l4;
+ @OWLDataProperty(iri = "http://l5")
+ protected URI l5;
+
+ public URI getL1() {
+ return l1;
+ }
+
+ public void setL1(URI l1) {
+ this.l1 = l1;
+ }
+
+ public URI getL2() {
+ return l2;
+ }
+
+ public void setL2(URI l2) {
+ this.l2 = l2;
+ }
+
+ public URI getL3() {
+ return l3;
+ }
+
+ public void setL3(URI l3) {
+ this.l3 = l3;
+ }
+
+ public URI getL4() {
+ return l4;
+ }
+
+ public void setL4(URI l4) {
+ this.l4 = l4;
+ }
+
+ public URI getL5() {
+ return l5;
+ }
+
+ public void setL5(URI l5) {
+ this.l5 = l5;
+ }
+}
diff --git a/src/main/java/cz/cvut/kbss/study/model/export/RawRecord.java b/src/main/java/cz/cvut/kbss/study/model/export/RawRecord.java
new file mode 100644
index 00000000..843f5cde
--- /dev/null
+++ b/src/main/java/cz/cvut/kbss/study/model/export/RawRecord.java
@@ -0,0 +1,299 @@
+package cz.cvut.kbss.study.model.export;
+
+import cz.cvut.kbss.jopa.model.annotations.*;
+import cz.cvut.kbss.study.model.Vocabulary;
+
+import java.net.URI;
+import java.util.Date;
+
+@SparqlResultSetMappings(value =
+@SparqlResultSetMapping(name = "RawRecord", entities = {
+ @EntityResult(entityClass = RawRecord.class)
+})
+)
+@OWLClass(iri = Vocabulary.s_c_patient_record)
+public class RawRecord {
+ @Id
+ private URI uri;
+
+ @OWLDataProperty(iri = "http://created")
+ private Date created;
+ @OWLDataProperty(iri = "http://modified")
+ private Date modified;
+ @OWLDataProperty(iri = "http://label")
+ private String label;
+ @OWLObjectProperty(iri = "http://phase")
+ private URI phase;
+ @OWLObjectProperty(iri = "http://institution")
+ private URI institution;
+ @OWLObjectProperty(iri = "http://aircraftType")
+ private URI aircraftType;
+ @OWLObjectProperty(iri = "http://fuselage")
+ private String fuselage;
+ @OWLObjectProperty(iri = "http://ac_comp")
+ private URI ac_comp;
+ @OWLDataProperty(iri = "http://failDate")
+ private String failDate;
+
+ @OWLDataProperty(iri = "http://flightHours")
+ private String flightHours;
+ @OWLDataProperty(iri = "http://numberOfAirframeOverhauls")
+ private Integer numberOfAirframeOverhauls;
+ @OWLObjectProperty(iri = "http://classificationOfOccurrence")
+ private URI classificationOfOccurrence;
+ @OWLObjectProperty(iri = "http://failureAscertainmentCircumstances")
+ private URI failureAscertainmentCircumstances;
+ @OWLObjectProperty(iri = "http://repeatedFailure")
+ private URI repeatedFailure;
+ @OWLObjectProperty(iri = "http://failureCause")
+ private URI failureCause;
+ @OWLObjectProperty(iri = "http://consequence")
+ private URI consequence;
+ @OWLObjectProperty(iri = "http://mission")
+ private URI mission;
+ @OWLObjectProperty(iri = "http://repair")
+ private URI repair;
+ @OWLDataProperty(iri = "http://repairDuration")
+ private String repairDuration;
+ @OWLDataProperty(iri = "http://averageNumberOfMenDuringRepairment")
+ private Double averageNumberOfMenDuringRepairment;
+ @OWLDataProperty(iri = "http://failureDescription")
+ private String failureDescription;
+ @OWLDataProperty(iri = "http://descriptionOfCorrectiveAction")
+ private String descriptionOfCorrectiveAction;
+ @OWLDataProperty(iri = "http://yearOfProductionOfDefectiveEquipment")
+ private String yearOfProductionOfDefectiveEquipment;
+ @OWLDataProperty(iri = "http://numberOfOverhaulsOfDefectiveEquipment")
+ private Integer numberOfOverhaulsOfDefectiveEquipment;
+ @OWLDataProperty(iri = "http://serialNoOf")
+ private String serialNoOf;
+ @OWLDataProperty(iri = "http://notes")
+ private String notes;
+ @OWLObjectProperty(iri = "http://fhaEvent")
+ private URI fhaEvent;
+
+
+ public URI getUri() {
+ return uri;
+ }
+
+ public void setUri(URI uri) {
+ this.uri = uri;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public Date getModified() {
+ return modified;
+ }
+
+ public void setModified(Date modified) {
+ this.modified = modified;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public URI getPhase() {
+ return phase;
+ }
+
+ public void setPhase(URI phase) {
+ this.phase = phase;
+ }
+
+ public URI getInstitution() {
+ return institution;
+ }
+
+ public void setInstitution(URI institution) {
+ this.institution = institution;
+ }
+
+ public URI getAircraftType() {
+ return aircraftType;
+ }
+
+ public void setAircraftType(URI aircraftType) {
+ this.aircraftType = aircraftType;
+ }
+
+ public String getFuselage() {
+ return fuselage;
+ }
+
+ public void setFuselage(String fuselage) {
+ this.fuselage = fuselage;
+ }
+
+ public URI getAc_comp() {
+ return ac_comp;
+ }
+
+ public void setAc_comp(URI ac_comp) {
+ this.ac_comp = ac_comp;
+ }
+
+ public String getFailDate() {
+ return failDate;
+ }
+
+ public void setFailDate(String failDate) {
+ this.failDate = failDate;
+ }
+
+ public String getFlightHours() {
+ return flightHours;
+ }
+
+ public void setFlightHours(String flightHours) {
+ this.flightHours = flightHours;
+ }
+
+ public Integer getNumberOfAirframeOverhauls() {
+ return numberOfAirframeOverhauls;
+ }
+
+ public void setNumberOfAirframeOverhauls(Integer numberOfAirframeOverhauls) {
+ this.numberOfAirframeOverhauls = numberOfAirframeOverhauls;
+ }
+
+ public URI getClassificationOfOccurrence() {
+ return classificationOfOccurrence;
+ }
+
+ public void setClassificationOfOccurrence(URI classificationOfOccurrence) {
+ this.classificationOfOccurrence = classificationOfOccurrence;
+ }
+
+ public URI getFailureAscertainmentCircumstances() {
+ return failureAscertainmentCircumstances;
+ }
+
+ public void setFailureAscertainmentCircumstances(URI failureAscertainmentCircumstances) {
+ this.failureAscertainmentCircumstances = failureAscertainmentCircumstances;
+ }
+
+ public URI getRepeatedFailure() {
+ return repeatedFailure;
+ }
+
+ public void setRepeatedFailure(URI repeatedFailure) {
+ this.repeatedFailure = repeatedFailure;
+ }
+
+ public URI getFailureCause() {
+ return failureCause;
+ }
+
+ public void setFailureCause(URI failureCause) {
+ this.failureCause = failureCause;
+ }
+
+ public URI getConsequence() {
+ return consequence;
+ }
+
+ public void setConsequence(URI consequence) {
+ this.consequence = consequence;
+ }
+
+ public URI getMission() {
+ return mission;
+ }
+
+ public void setMission(URI mission) {
+ this.mission = mission;
+ }
+
+ public URI getRepair() {
+ return repair;
+ }
+
+ public void setRepair(URI repair) {
+ this.repair = repair;
+ }
+
+ public String getRepairDuration() {
+ return repairDuration;
+ }
+
+ public void setRepairDuration(String repairDuration) {
+ this.repairDuration = repairDuration;
+ }
+
+ public Double getAverageNumberOfMenDuringRepairment() {
+ return averageNumberOfMenDuringRepairment;
+ }
+
+ public void setAverageNumberOfMenDuringRepairment(Double averageNumberOfMenDuringRepairment) {
+ this.averageNumberOfMenDuringRepairment = averageNumberOfMenDuringRepairment;
+ }
+
+ public String getFailureDescription() {
+ return failureDescription;
+ }
+
+ public void setFailureDescription(String failureDescription) {
+ this.failureDescription = failureDescription;
+ }
+
+ public String getDescriptionOfCorrectiveAction() {
+ return descriptionOfCorrectiveAction;
+ }
+
+ public void setDescriptionOfCorrectiveAction(String descriptionOfCorrectiveAction) {
+ this.descriptionOfCorrectiveAction = descriptionOfCorrectiveAction;
+ }
+
+ public String getYearOfProductionOfDefectiveEquipment() {
+ return yearOfProductionOfDefectiveEquipment;
+ }
+
+ public void setYearOfProductionOfDefectiveEquipment(String yearOfProductionOfDefectiveEquipment) {
+ this.yearOfProductionOfDefectiveEquipment = yearOfProductionOfDefectiveEquipment;
+ }
+
+ public Integer getNumberOfOverhaulsOfDefectiveEquipment() {
+ return numberOfOverhaulsOfDefectiveEquipment;
+ }
+
+ public void setNumberOfOverhaulsOfDefectiveEquipment(Integer numberOfOverhaulsOfDefectiveEquipment) {
+ this.numberOfOverhaulsOfDefectiveEquipment = numberOfOverhaulsOfDefectiveEquipment;
+ }
+
+ public String getSerialNoOf() {
+ return serialNoOf;
+ }
+
+ public void setSerialNoOf(String serialNoOf) {
+ this.serialNoOf = serialNoOf;
+ }
+
+ public String getNotes() {
+ return notes;
+ }
+
+ public void setNotes(String notes) {
+ this.notes = notes;
+ }
+
+ public URI getFhaEvent() {
+ return fhaEvent;
+ }
+
+ public void setFhaEvent(URI fhaEvent) {
+ this.fhaEvent = fhaEvent;
+ }
+}
diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/CodeListValuesDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/CodeListValuesDao.java
new file mode 100644
index 00000000..416df4c1
--- /dev/null
+++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/CodeListValuesDao.java
@@ -0,0 +1,185 @@
+package cz.cvut.kbss.study.persistence.dao;
+
+import cz.cvut.kbss.jopa.model.EntityManager;
+import cz.cvut.kbss.study.model.Vocabulary;
+import cz.cvut.kbss.study.model.export.NamedItem;
+import cz.cvut.kbss.study.model.export.Path;
+import org.springframework.stereotype.Repository;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Repository
+public class CodeListValuesDao {
+
+ private final EntityManager em;
+
+ public CodeListValuesDao(EntityManager em) {
+ this.em = em;
+ }
+
+
+
+ public List findClassificationOfOccurrence() {
+ return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/classification-of-occurrence"));
+ }
+
+
+ public List findConsequence() {
+ return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/consequence"));
+ }
+
+
+ public List findFailureAscertainmentCircumstances() {
+ return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/failure-ascertainment-circumstances"));
+ }
+
+
+ public List findFailureCause() {
+ return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/failure-cause"));
+ }
+
+
+ public List findFhaEvent() {
+ return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/fha-event"));
+ }
+
+
+ public List findMission() {
+ return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/mission"));
+ }
+
+
+ public List findRepair() {
+ return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/repair"));
+ }
+
+
+ public List findRepeatedFailure() {
+ return findItems(URI.create("http://vfn.cz/ontologies/ava-study/model/repeated-failure"));
+ }
+
+ public List findInstitutions(){
+ return em.createNativeQuery("""
+ PREFIX rm:
+ PREFIX rdfs:
+
+ SELECT ?uri (str(?_name) as ?name) {
+ ?uri a ?type.
+ ?uri rdfs:label ?_name
+ }
+ """, NamedItem.class.getSimpleName())
+ .setParameter("type", URI.create(Vocabulary.s_c_institution))
+ .getResultList();
+ }
+
+ public List findItems(URI type){
+ return em.createNativeQuery("""
+ PREFIX rm:
+ PREFIX rdfs:
+
+ SELECT ?uri (str(?_name) as ?name) {
+ SERVICE {
+ ?uri a ?type.
+ ?uri rdfs:label ?_name
+ }
+ }
+ """, NamedItem.class.getSimpleName())
+ .setParameter("type", type)
+ .getResultList();
+ }
+
+ public List findItems(Collection items){
+ String queryString = """
+ PREFIX rm:
+ PREFIX rdfs:
+
+ SELECT ?uri (str(?_name) as ?name) {
+ SERVICE {
+ ?uri rdfs:label ?_name
+ }
+ }VALUES ?uri {
+ ###items###
+ }
+ """;
+ if(items != null) {
+ queryString = queryString.replaceFirst(
+ "###items###",
+ items.stream().map(u -> "<%s>".formatted(u)).collect(Collectors.joining("\n"))
+ );
+ }
+ return em.createNativeQuery(queryString, NamedItem.class.getSimpleName())
+ .getResultList();
+ }
+
+
+
+ public List findAircraft(){
+ return em.createNativeQuery("""
+ PREFIX rdfs:
+ PREFIX form:
+
+ SELECT ?uri ?name {
+ SERVICE {
+ ?uri a form:form-template.
+ ?uri rdfs:label ?name.
+ }
+ }
+ """, NamedItem.class.getSimpleName()).getResultList();
+ }
+
+ public List findAircraftParts(){
+ return em.createNativeQuery("""
+ PREFIX rdfs:
+ PREFIX form:
+
+ SELECT ?uri ?name {
+ SERVICE {
+ ?uri a form:form-template.
+ ?uri rdfs:label ?name.
+ }
+ }
+ """, NamedItem.class.getSimpleName()).getResultList();
+ }
+
+ public List getBroaderPath(Collection elements){
+ String queryString = """
+ PREFIX skos:
+ SELECT ?l1 ?l2 ?l3 ?l4 ?l5 (?p as ?uri) {
+ SERVICE {
+ OPTIONAL{
+ ?p skos:broader+ ?l1.
+ FILTER NOT EXISTS{
+ ?l1 skos:broader ?l0 .
+ }
+ OPTIONAL{
+ ?l2 skos:broader ?l1 .
+ ?p skos:broader+ ?l2.
+ OPTIONAL{
+ ?l3 skos:broader ?l2 .
+ ?p skos:broader+ ?l3.
+ OPTIONAL{
+ ?l4 skos:broader ?l3 .
+ ?p skos:broader+ ?l4.
+ OPTIONAL{
+ ?l5 skos:broader ?l4 .
+ ?p skos:broader+ ?l5.
+ }
+ }
+ }
+ }
+ }
+ }
+ }VALUES ?p {
+ %s
+ }
+ """;
+ queryString = queryString.formatted(elements.stream().map(u -> "<%s>".formatted(u.toString()))
+ .collect(Collectors.joining("\n")));
+ return em.createNativeQuery(queryString, Path.class.getSimpleName())
+ .getResultList();
+ }
+
+}
diff --git a/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java b/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java
index 6fd233ef..a64d6e19 100644
--- a/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java
+++ b/src/main/java/cz/cvut/kbss/study/persistence/dao/PatientRecordDao.java
@@ -5,6 +5,7 @@
import cz.cvut.kbss.jopa.model.descriptors.Descriptor;
import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor;
import cz.cvut.kbss.jopa.model.metamodel.EntityType;
+import cz.cvut.kbss.jopa.model.query.Query;
import cz.cvut.kbss.jopa.model.query.TypedQuery;
import cz.cvut.kbss.ontodriver.model.LangString;
import cz.cvut.kbss.study.dto.PatientRecordDto;
@@ -14,11 +15,13 @@
import cz.cvut.kbss.study.model.PatientRecord;
import cz.cvut.kbss.study.model.User;
import cz.cvut.kbss.study.model.Vocabulary;
+import cz.cvut.kbss.study.model.export.RawRecord;
import cz.cvut.kbss.study.persistence.dao.util.QuestionSaver;
import cz.cvut.kbss.study.persistence.dao.util.RecordFilterParams;
import cz.cvut.kbss.study.persistence.dao.util.RecordSort;
import cz.cvut.kbss.study.util.Constants;
import cz.cvut.kbss.study.util.IdentificationUtils;
+import cz.cvut.kbss.study.util.Utils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
@@ -38,6 +41,9 @@
@Repository
public class PatientRecordDao extends OwlKeySupportingDao {
+ public static final String FIND_ALL_RAW_PATIENT_RECORDS = "find-raw-records.sparql";
+ public static final String RECORDS_CLAUSE_TEMPLATE_VAR = "###RECORD_CLAUSE###";
+
public PatientRecordDao(EntityManager em) {
super(PatientRecord.class, em);
}
@@ -237,7 +243,40 @@ private Page findRecords(RecordFilterParams filters, Pageable pageSpec, C
return new PageImpl<>(records, pageSpec, totalCount);
}
- private void setQueryParameters(TypedQuery> query, Map queryParams) {
+ public Page findAllRecordsRaw(RecordFilterParams filters, Pageable pageSpec){
+ final Map queryParams = new HashMap<>();
+ final String whereClause = constructWhereClause(filters, queryParams);
+
+ final String queryStringNoPaging = Utils.loadQuery(FIND_ALL_RAW_PATIENT_RECORDS)
+ .replaceFirst(RECORDS_CLAUSE_TEMPLATE_VAR, whereClause);
+ final String queryString = queryStringNoPaging + (pageSpec.isPaged()
+ ? resolveOrderBy(pageSpec.getSortOr(RecordSort.defaultSort()))
+ : ""
+ );
+
+ Query query = em.createNativeQuery(queryString, RawRecord.class.getSimpleName());
+ queryParams.forEach(query::setParameter);
+
+ if (pageSpec.isPaged()) {
+ query.setFirstResult((int) pageSpec.getOffset());
+ query.setMaxResults(pageSpec.getPageSize());
+ }
+ setQueryParameters(query, queryParams);
+ List result = query.getResultList();
+ Integer totalCount = result.size();
+ if(pageSpec.isPaged()){
+ TypedQuery countQuery = em.createNativeQuery(
+ "SELECT (COUNT(?r) as ?cnt) WHERE {%s}".formatted(whereClause),
+ Integer.class);
+
+ setQueryParameters(countQuery, queryParams);
+ totalCount = countQuery.getSingleResult();
+ }
+
+ return new PageImpl<>(result, pageSpec, totalCount);
+ }
+
+ private void setQueryParameters(Query query, Map queryParams) {
query.setParameter("type", typeUri)
.setParameter("hasPhase", URI.create(Vocabulary.s_p_has_phase))
.setParameter("hasFormTemplate", URI.create(Vocabulary.s_p_has_form_template))
diff --git a/src/main/java/cz/cvut/kbss/study/rest/PatientRecordController.java b/src/main/java/cz/cvut/kbss/study/rest/PatientRecordController.java
index 5bc4d9ff..7a5ad4a7 100644
--- a/src/main/java/cz/cvut/kbss/study/rest/PatientRecordController.java
+++ b/src/main/java/cz/cvut/kbss/study/rest/PatientRecordController.java
@@ -5,34 +5,32 @@
import cz.cvut.kbss.study.exception.NotFoundException;
import cz.cvut.kbss.study.model.PatientRecord;
import cz.cvut.kbss.study.model.RecordPhase;
+import cz.cvut.kbss.study.model.export.RawRecord;
+import cz.cvut.kbss.study.persistence.dao.util.RecordFilterParams;
import cz.cvut.kbss.study.rest.event.PaginatedResultRetrievedEvent;
import cz.cvut.kbss.study.rest.exception.BadRequestException;
import cz.cvut.kbss.study.rest.util.RecordFilterMapper;
import cz.cvut.kbss.study.rest.util.RestUtils;
import cz.cvut.kbss.study.security.SecurityConstants;
+import cz.cvut.kbss.study.service.ExcelRecordConverter;
import cz.cvut.kbss.study.service.PatientRecordService;
+import cz.cvut.kbss.study.util.Constants;
+import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.core.io.InputStreamResource;
import org.springframework.data.domain.Page;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
+import org.springframework.http.*;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.MultiValueMap;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;
+import java.io.InputStream;
+import java.util.Comparator;
import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
@RestController
@PreAuthorize("hasRole('" + SecurityConstants.ROLE_USER + "')")
@@ -42,10 +40,12 @@ public class PatientRecordController extends BaseController {
private final PatientRecordService recordService;
private final ApplicationEventPublisher eventPublisher;
+ private final ExcelRecordConverter excelRecordConverter;
- public PatientRecordController(PatientRecordService recordService, ApplicationEventPublisher eventPublisher) {
+ public PatientRecordController(PatientRecordService recordService, ApplicationEventPublisher eventPublisher, ExcelRecordConverter excelRecordConverter) {
this.recordService = recordService;
this.eventPublisher = eventPublisher;
+ this.excelRecordConverter = excelRecordConverter;
}
@PreAuthorize("hasRole('" + SecurityConstants.ROLE_ADMIN + "') or @securityUtils.isMemberOfInstitution(#institutionKey)")
@@ -62,15 +62,56 @@ public List getRecords(
@PreAuthorize(
"hasRole('" + SecurityConstants.ROLE_ADMIN + "') or @securityUtils.isMemberOfInstitution(#institutionKey)")
- @GetMapping(value = "/export", produces = MediaType.APPLICATION_JSON_VALUE)
- public List exportRecords(
+ @GetMapping(value = "/export", produces = {MediaType.APPLICATION_JSON_VALUE, Constants.MEDIA_TYPE_EXCEL})
+ public ResponseEntity> exportRecords(
@RequestParam(name = "institution", required = false) String institutionKey,
- @RequestParam MultiValueMap params,
- UriComponentsBuilder uriBuilder, HttpServletResponse response) {
+ @RequestParam(required = false) MultiValueMap params,
+ UriComponentsBuilder uriBuilder, HttpServletRequest request, HttpServletResponse response) {
+ MediaType exportType = Stream.of(
+ Optional.ofNullable(params).map(p -> p.getFirst(Constants.EXPORT_TYPE_PARAM)),
+ Optional.ofNullable(request.getHeader(HttpHeaders.ACCEPT))
+ ).filter(Optional::isPresent)
+ .findFirst()
+ .orElse(Optional.empty())
+ .flatMap(s -> MediaType.parseMediaTypes(s).stream()
+ .max(Comparator.comparing(MediaType::getQualityValue))
+ ).orElse(MediaType.APPLICATION_JSON)
+ .removeQualityValue();
+
+ return switch (exportType.toString()){
+ case Constants.MEDIA_TYPE_EXCEL -> exportRecordsExcel(params, uriBuilder, response);
+ case MediaType.APPLICATION_JSON_VALUE -> exportRecordsAsJson(params, uriBuilder, response);
+ default -> throw new IllegalArgumentException("Unsupported export type: " + exportType);
+ };
+ }
+
+ protected ResponseEntity> exportRecordsAsJson(
+ MultiValueMap params,
+ UriComponentsBuilder uriBuilder, HttpServletResponse response){
final Page result = recordService.findAllFull(RecordFilterMapper.constructRecordFilter(params),
- RestUtils.resolvePaging(params));
+ RestUtils.resolvePaging(params));
eventPublisher.publishEvent(new PaginatedResultRetrievedEvent(this, uriBuilder, response, result));
- return result.getContent();
+ return ResponseEntity.ok()
+ .contentType(MediaType.APPLICATION_JSON)
+ .body(result.getContent());
+ }
+
+ public ResponseEntity exportRecordsExcel(MultiValueMap params,
+ UriComponentsBuilder uriBuilder, HttpServletResponse response){
+ RecordFilterParams filterParams = new RecordFilterParams();
+ filterParams.setMinModifiedDate(null);
+ filterParams.setMaxModifiedDate(null);
+ RecordFilterMapper.constructRecordFilter(filterParams, params);
+
+ Page result = recordService.exportRecords(filterParams, RestUtils.resolvePaging(params));
+
+ InputStream stream = excelRecordConverter.convert(result.getContent());
+ eventPublisher.publishEvent(new PaginatedResultRetrievedEvent(this, uriBuilder, response, result));
+ ContentDisposition contentDisposition = ContentDisposition.attachment().filename("export.xlsx").build();
+ return ResponseEntity.ok()
+ .contentType(MediaType.parseMediaType(Constants.MEDIA_TYPE_EXCEL))
+ .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString())
+ .body(new InputStreamResource(stream));
}
@PreAuthorize("hasRole('" + SecurityConstants.ROLE_ADMIN + "') or @securityUtils.isRecordInUsersInstitution(#key)")
diff --git a/src/main/java/cz/cvut/kbss/study/rest/util/RecordFilterMapper.java b/src/main/java/cz/cvut/kbss/study/rest/util/RecordFilterMapper.java
index a3473cd0..4b13df8a 100644
--- a/src/main/java/cz/cvut/kbss/study/rest/util/RecordFilterMapper.java
+++ b/src/main/java/cz/cvut/kbss/study/rest/util/RecordFilterMapper.java
@@ -45,16 +45,18 @@ public class RecordFilterMapper {
public static RecordFilterParams constructRecordFilter(String param, String value) {
return constructRecordFilter(new LinkedMultiValueMap<>(Map.of(param, List.of(value))));
}
-
+ public static RecordFilterParams constructRecordFilter(MultiValueMap params) {
+ final RecordFilterParams result = new RecordFilterParams();
+ return constructRecordFilter(result, new LinkedMultiValueMap<>(params));
+ }
/**
* Maps the specified parameters to a new {@link RecordFilterParams} instance.
*
* @param params Request parameters to map
* @return New {@code RecordFilterParams} instance
*/
- public static RecordFilterParams constructRecordFilter(MultiValueMap params) {
+ public static RecordFilterParams constructRecordFilter(final RecordFilterParams result, MultiValueMap params) {
Objects.requireNonNull(params);
- final RecordFilterParams result = new RecordFilterParams();
getSingleValue(MIN_DATE_PARAM, params).ifPresent(s -> {
try {
result.setMinModifiedDate(LocalDate.parse(s));
diff --git a/src/main/java/cz/cvut/kbss/study/service/ExcelRecordConverter.java b/src/main/java/cz/cvut/kbss/study/service/ExcelRecordConverter.java
new file mode 100644
index 00000000..dfea8f4c
--- /dev/null
+++ b/src/main/java/cz/cvut/kbss/study/service/ExcelRecordConverter.java
@@ -0,0 +1,161 @@
+package cz.cvut.kbss.study.service;
+
+import cz.cvut.kbss.study.model.export.ExportRecord;
+import cz.cvut.kbss.study.model.export.Path;
+import cz.cvut.kbss.study.model.export.RawRecord;
+import cz.cvut.kbss.study.persistence.dao.CodeListValuesDao;
+import cz.cvut.kbss.study.util.Utils;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.stereotype.Service;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Service
+public class ExcelRecordConverter {
+
+ private final CodeListValuesDao codeListValuesDao;
+
+ public ExcelRecordConverter(CodeListValuesDao codeListValuesDao) {
+ this.codeListValuesDao = codeListValuesDao;
+ }
+
+ public InputStream convert(List rawRecords){
+ try {
+ XSSFWorkbook workbook = new XSSFWorkbook(Utils.class.getClassLoader().getResourceAsStream("templates/record-export-template.xlsx"));
+ List exportRecords = findExportRecordsData(rawRecords);
+ addDataToExcel(workbook, exportRecords);
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ workbook.write(output);
+ return new ByteArrayInputStream(output.toByteArray());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private List findExportRecordsData(List rawRecords){
+ Map translatorMap = new HashMap<>();
+ List paths = codeListValuesDao.getBroaderPath(rawRecords.stream().map(r -> r.getAc_comp()).collect(Collectors.toSet()));
+ Set uris = rawRecords.stream().flatMap(r -> Stream.of(
+ r.getClassificationOfOccurrence(), r.getConsequence(), r.getFailureAscertainmentCircumstances(),
+ r.getFailureCause(), r.getAc_comp(), r.getFhaEvent(), r.getMission(), r.getRepair(),
+ r.getRepeatedFailure()))
+ .distinct()
+ .filter(u -> u != null)
+ .collect(Collectors.toSet());
+
+ uris.addAll(paths.stream()
+ .flatMap(p -> Stream.of(p.getL1(), p.getL2(), p.getL3(), p.getL4(), p.getL5()))
+ .filter(u -> u != null).collect(Collectors.toSet())
+ );
+
+
+ codeListValuesDao.findItems(uris).forEach(i -> translatorMap.put(i.getUri(), i.getName()));
+ codeListValuesDao.findAircraft().forEach(i -> translatorMap.put(i.getUri(), i.getName()));
+ codeListValuesDao.findInstitutions().forEach(i -> translatorMap.put(i.getUri(), i.getName()));
+
+ Map> pathMap = new HashMap<>();
+ paths.forEach(p -> pathMap.put(p.getUri(), Arrays.asList(
+ translatorMap.get(p.getL1()),
+ translatorMap.get(p.getL2()),
+ translatorMap.get(p.getL3()),
+ translatorMap.get(p.getL4()),
+ translatorMap.get(p.getL5())
+ )));
+
+ List exportRecords = new ArrayList<>();
+
+ for(RawRecord r : rawRecords){
+ ExportRecord er = new ExportRecord();
+ exportRecords.add(er);
+ er.setPath(pathMap.get(r.getAc_comp()));
+ er.setInstitution(translatorMap.get(r.getInstitution()));
+ er.setAircraftType(translatorMap.get(r.getAircraftType()));
+ er.setAc_compName(translatorMap.get(r.getAc_comp()));
+ er.setClassificationOfOccurrence(translatorMap.get(r.getClassificationOfOccurrence()));
+ er.setConsequence(translatorMap.get(r.getConsequence()));
+ er.setFailureCause(translatorMap.get(r.getFailureCause()));
+ er.setFhaEvent(translatorMap.get(r.getFhaEvent()));
+ er.setMission(translatorMap.get(r.getMission()));
+ er.setRepair(translatorMap.get(r.getRepair()));
+ er.setRepeatedFailure(translatorMap.get(r.getRepeatedFailure()));
+
+ er.setFuselage(r.getFuselage());
+ er.setUri(r.getUri());
+ er.setCreated(r.getCreated());
+ er.setModified(r.getModified());
+ er.setLabel(r.getLabel());
+ er.setFailDate(r.getFailDate());
+ er.setFlightHours(r.getFlightHours());
+ er.setNumberOfAirframeOverhauls(r.getNumberOfAirframeOverhauls());
+ er.setRepairDuration(r.getRepairDuration());
+ er.setAverageNumberOfMenDuringRepairment(r.getAverageNumberOfMenDuringRepairment());
+ er.setFailureDescription(r.getFailureDescription());
+ er.setDescriptionOfCorrectiveAction(r.getDescriptionOfCorrectiveAction());
+ er.setNumberOfOverhaulsOfDefectiveEquipment(r.getNumberOfOverhaulsOfDefectiveEquipment());
+ er.setSerialNoOf(r.getSerialNoOf());
+ er.setNotes(r.getNotes());
+ }
+
+ return exportRecords;
+ }
+
+
+ private void addDataToExcel(XSSFWorkbook workbook, List data) throws IOException {
+ XSSFSheet s = workbook.getSheetAt(1);
+
+ int rowIndex = 1;
+ for(ExportRecord rec : data) {
+ XSSFRow r = s.createRow(rowIndex++);
+ r.createCell(0).setCellValue(rowIndex);
+// r.createCell(1).setCellValue(rowIndex);
+ r.createCell(2).setCellValue(rec.getCreated());
+// r.createCell(3).setCellValue(rec.ed);
+// r.createCell(4).setCellValue(rec.);
+ r.createCell(5).setCellValue(rec.getModified());
+ r.createCell(6).setCellValue(rec.getLabel());
+ r.createCell(7).setCellValue(rec.getInstitution());
+ r.createCell(8).setCellValue(rec.getAircraftType());
+ r.createCell(10).setCellValue(rec.getFuselage());
+ r.createCell(11).setCellValue(rec.getFailDate());
+ r.createCell(12).setCellValue(rec.getFlightHours());
+ r.createCell(13).setCellValue(rec.getNumberOfAirframeOverhauls());
+ r.createCell(14).setCellValue(rec.getClassificationOfOccurrence());
+ r.createCell(15).setCellValue(rec.getFailureAscertainmentCircumstances());
+ r.createCell(16).setCellValue(rec.getRepeatedFailure());
+ r.createCell(17).setCellValue(rec.getFailureCause());
+ r.createCell(18).setCellValue(rec.getConsequence());
+ r.createCell(19).setCellValue(rec.getMission());
+ r.createCell(20).setCellValue(rec.getRepair());
+ r.createCell(21).setCellValue(rec.getRepairDuration());
+ r.createCell(22).setCellValue(rec.getAverageNumberOfMenDuringRepairment());
+ r.createCell(23).setCellValue(rec.getFailureDescription());
+ r.createCell(24).setCellValue(rec.getDescriptionOfCorrectiveAction());
+ r.createCell(25).setCellValue(rec.getAc_compName());
+ if (rec.getPath() != null){
+ r.createCell(26).setCellValue(rec.getPath().get(0));
+ r.createCell(27).setCellValue(rec.getPath().get(1));
+ r.createCell(28).setCellValue(rec.getPath().get(2));
+ r.createCell(29).setCellValue(rec.getPath().get(3));
+ r.createCell(30).setCellValue(rec.getPath().get(4));
+ }
+// r.createCell(31).setCellValue(rec.get());
+// r.createCell(32).setCellValue(rec.get());
+ r.createCell(31).setCellValue(rec.getYearOfProductionOfDefectiveEquipment());
+
+ Optional.ofNullable(rec.getNumberOfOverhaulsOfDefectiveEquipment()).ifPresent(v -> r.createCell(29).setCellValue(v));
+ r.createCell(33).setCellValue(rec.getSerialNoOf());
+ r.createCell(34).setCellValue(rec.getNotes());
+ r.createCell(35).setCellValue(rec.getFhaEvent());
+ }
+ }
+
+}
diff --git a/src/main/java/cz/cvut/kbss/study/service/PatientRecordService.java b/src/main/java/cz/cvut/kbss/study/service/PatientRecordService.java
index 91322af1..83eb8965 100644
--- a/src/main/java/cz/cvut/kbss/study/service/PatientRecordService.java
+++ b/src/main/java/cz/cvut/kbss/study/service/PatientRecordService.java
@@ -4,6 +4,7 @@
import cz.cvut.kbss.study.dto.RecordImportResult;
import cz.cvut.kbss.study.model.PatientRecord;
import cz.cvut.kbss.study.model.RecordPhase;
+import cz.cvut.kbss.study.model.export.RawRecord;
import cz.cvut.kbss.study.persistence.dao.util.RecordFilterParams;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -77,4 +78,12 @@ public interface PatientRecordService extends BaseService {
* repository
*/
RecordImportResult importRecords(List records, RecordPhase targetPhase);
+
+ /**
+ *
+ * @param filters Record filtering criteria
+ * @param pageSpec Specification of page and sorting to retrieve
+ * @return List of matching records
+ */
+ Page exportRecords(RecordFilterParams filters, Pageable pageSpec);
}
diff --git a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java
index 8aaf2c9c..d524a105 100644
--- a/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java
+++ b/src/main/java/cz/cvut/kbss/study/service/repository/RepositoryPatientRecordService.java
@@ -6,6 +6,7 @@
import cz.cvut.kbss.study.model.PatientRecord;
import cz.cvut.kbss.study.model.RecordPhase;
import cz.cvut.kbss.study.model.User;
+import cz.cvut.kbss.study.model.export.RawRecord;
import cz.cvut.kbss.study.persistence.dao.OwlKeySupportingDao;
import cz.cvut.kbss.study.persistence.dao.PatientRecordDao;
import cz.cvut.kbss.study.persistence.dao.util.RecordFilterParams;
@@ -36,12 +37,14 @@ public class RepositoryPatientRecordService extends KeySupportingRepositoryServi
private final SecurityUtils securityUtils;
private final UserService userService;
+ private final PatientRecordDao patientRecordDao;
public RepositoryPatientRecordService(PatientRecordDao recordDao, SecurityUtils securityUtils,
- UserService userService) {
+ UserService userService, PatientRecordDao patientRecordDao) {
this.recordDao = recordDao;
this.securityUtils = securityUtils;
this.userService = userService;
+ this.patientRecordDao = patientRecordDao;
}
@Override
@@ -125,4 +128,9 @@ public RecordImportResult importRecords(List records, RecordPhase
LOG.debug("Importing records to target phase '{}'.", targetPhase);
return importRecordsImpl(records, Optional.ofNullable(targetPhase));
}
+
+ @Override
+ public Page exportRecords(RecordFilterParams filters, Pageable pageSpec){
+ return patientRecordDao.findAllRecordsRaw(filters, pageSpec);
+ }
}
diff --git a/src/main/java/cz/cvut/kbss/study/util/Constants.java b/src/main/java/cz/cvut/kbss/study/util/Constants.java
index 45369d2f..58289c76 100644
--- a/src/main/java/cz/cvut/kbss/study/util/Constants.java
+++ b/src/main/java/cz/cvut/kbss/study/util/Constants.java
@@ -53,9 +53,19 @@ private Constants() {
*/
public static final String SORT_PARAM = "sort";
+ /**
+ * Name of the request parameter specifying record the export type.
+ */
+ public static final String EXPORT_TYPE_PARAM = "exportType";
+
/**
* Represents the X-Total-Count HTTP header used to convey the total number of items in paged or otherwise
* restricted response.
*/
public static final String X_TOTAL_COUNT_HEADER = "X-Total-Count";
+
+ /**
+ * Excel MIME type
+ */
+ public static final String MEDIA_TYPE_EXCEL = "application/vnd.ms-excel";
}
diff --git a/src/main/resources/query/find-raw-records.sparql b/src/main/resources/query/find-raw-records.sparql
new file mode 100644
index 00000000..902cf11a
--- /dev/null
+++ b/src/main/resources/query/find-raw-records.sparql
@@ -0,0 +1,203 @@
+PREFIX av:
+PREFIX dc:
+PREFIX doc:
+PREFIX form:
+PREFIX form-lt:
+PREFIX owl:
+PREFIX rdfs:
+PREFIX skos:
+PREFIX vs-f:
+PREFIX vs-m:
+PREFIX xsd:
+PREFIX avadom:
+
+PREFIX avamod:
+PREFIX rm:
+PREFIX dcterms:
+PREFIX spif:
+
+SELECT ?r (?r as ?uri)
+?created ?label ?lastModified ?phase ?institution ?institutionKey ?formTemplate (IRI(str(?formTemplate)) as ?aircraftType) (str(?fus) as ?fuselage) ?ac_comp (str(?failDateStr) as ?failDate)
+?flightHours ?numberOfAirframeOverhauls ?classificationOfOccurrence ?failureAscertainmentCircumstances (?repeatedFailureCode as ?repeatedFailure) ?failureCause ?consequence ?mission ?repair (str(?repairDurationStr) as ?repairDuration) ?averageNumberOfMenDuringRepairment ?failureDescription ?descriptionOfCorrectiveAction ?yearOfProductionOfDefectiveEquipment ?numberOfOverhaulsOfDefectiveEquipment ?serialNoOf ?notes ?fhaEvent
+{
+ ###RECORD_CLAUSE###
+
+ ?r rm:has-question ?f.
+ ?f doc:has_related_question ?s1.
+ ?f doc:has_related_question ?s2.
+ FILTER(?s2 != ?s1)
+ ?s2 doc:has_related_question ?fhaEventQ.
+ ?fhaEventQ form:has-question-origin avamod:fha-event.
+
+ ?s1 doc:has_related_question ?FUSq.
+ ?FUSq form:has-question-origin avamod:fuselage-no.
+
+ ?s1 doc:has_related_question ?Cq.
+ ?Cq form:has-question-origin ?componentQuestionOrigin.
+ FILTER(contains(str(?componentQuestionOrigin), "http://vfn.cz/ontologies/ava-study/model/system-equipment-block-part-"))
+
+ ?s1 doc:has_related_question ?failDateq.
+ ?failDateq form:has-question-origin avamod:date-of-failure-ascertainment.
+
+ ?s1 doc:has_related_question ?FHq.
+ ?FHq form:has-question-origin avamod:flight-hours-of-airframe-since-the-service-beginning.
+
+ ?s1 doc:has_related_question ?classificationOfOccurrenceQ.
+ ?classificationOfOccurrenceQ form:has-question-origin avamod:classification-of-occurrence.
+
+ ?s1 doc:has_related_question ?failureAscertainmentCircumstancesQ.
+ ?failureAscertainmentCircumstancesQ form:has-question-origin avamod:failure-ascertainment-circumstances.
+
+ ?s1 doc:has_related_question ?repeatedFailureQ.
+ ?repeatedFailureQ form:has-question-origin avamod:repeated-failure.
+
+ ?s1 doc:has_related_question ?failureCauseQ.
+ ?failureCauseQ form:has-question-origin avamod:failure-cause .
+
+ ?s1 doc:has_related_question ?consequenceQ.
+ ?consequenceQ form:has-question-origin avamod:consequence.
+
+ ?s1 doc:has_related_question ?missionQ.
+ ?missionQ form:has-question-origin avamod:mission.
+
+ ?s1 doc:has_related_question ?repairQ.
+ ?repairQ form:has-question-origin avamod:repair.
+
+ ?s1 doc:has_related_question ?repairDurationQ.
+ ?repairDurationQ form:has-question-origin avamod:repair-duration.
+
+ ?s1 doc:has_related_question ?averageNumberOfMenDuringRepairmentQ.
+ ?averageNumberOfMenDuringRepairmentQ form:has-question-origin avamod:average-number-of-men-during-repairment.
+
+ ?s1 doc:has_related_question ?failureDescriptionQ.
+ ?failureDescriptionQ form:has-question-origin avamod:failure-description.
+
+ ?s1 doc:has_related_question ?descriptionOfCorrectiveActionQ.
+ ?descriptionOfCorrectiveActionQ form:has-question-origin avamod:description-of-corrective-action.
+
+ ?s1 doc:has_related_question ?numberOfAirframeOverhaulsQ.
+ ?numberOfAirframeOverhaulsQ form:has-question-origin avamod:number-of-airframe-overhauls.
+
+ ?s1 doc:has_related_question ?yearOfProductionOfDefectiveEquipmentQ.
+ ?yearOfProductionOfDefectiveEquipmentQ form:has-question-origin avamod:year-of-production-of-defective-equipment.
+
+ ?s1 doc:has_related_question ?numberOfOverhaulsOfDefectiveEquipmentQ.
+ ?numberOfOverhaulsOfDefectiveEquipmentQ form:has-question-origin avamod:number-of-overhauls-of-defective-equipment.
+
+# ?s1 doc:has_related_question ?serialNoOfQ.
+# ?serialNoOfQ form:has-question-origin avamod:serial-no-of.
+
+ ?s1 doc:has_related_question ?notesQ.
+ ?notesQ form:has-question-origin avamod:notes.
+ OPTIONAL {
+ # avamod:fuselage-no
+ ?FUSq doc:has_answer ?FUSa.
+ ?FUSa doc:has_data_value ?fus.
+
+ #avamod:system-equipment-block-part-l-39ng.a1
+ # ?comp - label of general component/system
+ # ?comp_iri - iri of component type specific to the aircraft
+ ?Cq doc:has_answer ?Ca.
+ ?Ca doc:has_object_value ?ac_comp.
+
+ #avamod:date-of-failure-ascertainment
+ # ?failDate - creation date filter
+ ?failDateq doc:has_answer ?failDatea.
+ ?failDatea doc:has_data_value ?failDateStr.
+ # BIND(spif:parseDate(?failDateStr, "DD-MM-yyyy") as ?failDate)
+ # FILTER((!BOUND(?createdBefore) || ?createdBefore < ?failDate ) && (!BOUND(?createdAfter) || ?createdAfter >= ?failDate ))
+
+ #avamod:flight-hours-of-airframe-since-the-service-beginning
+
+ ?FHq doc:has_answer ?FHa.
+ ?FHa doc:has_data_value ?flightHours.
+
+ #avamod:classification-of-occurrence
+ ?classificationOfOccurrenceQ doc:has_answer ?classificationOfOccurrenceA.
+ ?classificationOfOccurrenceA doc:has_object_value ?classificationOfOccurrence.
+
+ #avamod:failure-ascertainment-circumstances
+
+ ?failureAscertainmentCircumstancesQ doc:has_answer ?failureAscertainmentCircumstancesA.
+ ?failureAscertainmentCircumstancesA doc:has_object_value ?failureAscertainmentCircumstances.
+
+ # during flight
+ # BIND(IF(BOUND(?failureAscertainmentCircumstances) && ?failureAscertainmentCircumstances = avadom:during-flight, 1, 0) as ?duringFlight)
+
+ #avamod:repeated-failure
+ ?repeatedFailureQ doc:has_answer ?repeatedFailureA.
+ ?repeatedFailureA doc:has_object_value ?repeatedFailureCode.
+
+ OPTIONAL{
+ #avamod:failure-cause
+ ?failureCauseQ doc:has_answer ?failureCauseA.
+ ?failureCauseA doc:has_object_value ?failureCause.
+ }
+ #avamod:consequence
+
+ ?consequenceQ doc:has_answer ?consequenceA.
+ ?consequenceA doc:has_object_value ?consequence.
+
+ #avamod:mission
+ ?missionQ doc:has_answer ?missionA.
+ ?missionA doc:has_object_value ?mission.
+
+ #avamod:repair
+ ?repairQ doc:has_answer ?repairA.
+ ?repairA doc:has_object_value ?repair.
+
+ #avamod:repair-duration
+ ?repairDurationQ doc:has_answer ?repairDurationA.
+ ?repairDurationA doc:has_data_value ?repairDurationStr.
+
+ #avamod:average-number-of-men-during-repairment
+ ?averageNumberOfMenDuringRepairmentQ doc:has_answer ?averageNumberOfMenDuringRepairmentA.
+ ?averageNumberOfMenDuringRepairmentA doc:has_data_value ?averageNumberOfMenDuringRepairmentStr.
+ BIND(xsd:decimal(str(?averageNumberOfMenDuringRepairmentStr)) as ?averageNumberOfMenDuringRepairment)
+
+ #avamod:failure-description
+ ?failureDescriptionQ doc:has_answer ?failureDescriptionA.
+ ?failureDescriptionA doc:has_data_value ?failureDescription.
+
+ #avamod:description-of-corrective-action
+ ?descriptionOfCorrectiveActionQ doc:has_answer ?descriptionOfCorrectiveActionA.
+ ?descriptionOfCorrectiveActionA doc:has_data_value ?descriptionOfCorrectiveAction.
+
+ OPTIONAL {
+ #avamod:number-of-airframe-overhauls
+ ?numberOfAirframeOverhaulsQ doc:has_answer ?numberOfAirframeOverhaulsA.
+ ?numberOfAirframeOverhaulsA doc:has_data_value ?numberOfAirframeOverhaulsStr.
+ BIND(xsd:integer(str(?numberOfAirframeOverhaulsStr)) as ?numberOfAirframeOverhauls)
+ }
+
+ OPTIONAL {
+ #avamod:year-of-production-of-defective-equipment
+ ?yearOfProductionOfDefectiveEquipmentQ doc:has_answer ?yearOfProductionOfDefectiveEquipmentA.
+ ?yearOfProductionOfDefectiveEquipmentA doc:has_data_value ?yearOfProductionOfDefectiveEquipment.# TODO - transform to more suitable datatype
+ FILTER(str(spif:trim(?yearOfProductionOfDefectiveEquipment)) != "" )
+ }
+
+ OPTIONAL {
+ #avamod:number-of-overhauls-of-defective-equipment
+ ?numberOfOverhaulsOfDefectiveEquipmentQ doc:has_answer ?numberOfOverhaulsOfDefectiveEquipmentA.
+ ?numberOfOverhaulsOfDefectiveEquipmentA doc:has_data_value ?numberOfOverhaulsOfDefectiveEquipment.# TODO - transform to more suitable datatype
+ FILTER(str(spif:trim(?numberOfOverhaulsOfDefectiveEquipment)) != "" )
+ # }
+ # OPTIONAL{
+ # #avamod:serial-no-of
+ # ?serialNoOfQ doc:has_answer ?serialNoOfA.
+ # ?serialNoOfA doc:has_data_value ?serialNoOf.
+ }
+ OPTIONAL{
+ #avamod:notes
+ ?notesQ doc:has_answer ?notesA.
+ ?notesA doc:has_data_value ?notes.
+ FILTER(str(spif:trim(?notes)) != "" )
+ }
+ OPTIONAL{
+ #avamod:fha-event
+ ?fhaEventQ doc:has_answer ?fhaEventA.
+ ?fhaEventA doc:has_object_value ?fhaEvent.
+ }
+ }
+}
diff --git a/src/main/resources/templates/record-export-template.xlsx b/src/main/resources/templates/record-export-template.xlsx
new file mode 100644
index 00000000..942bcbec
Binary files /dev/null and b/src/main/resources/templates/record-export-template.xlsx differ