diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 000000000..125e89012 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,20 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java CI with Maven + +on: [push, pull_request] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Build with Maven + run: mvn -B package --file pom.xml diff --git a/.travis.yml b/.travis.yml deleted file mode 100755 index 901eabbd4..000000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: java -jdk: -- openjdk11 -- oraclejdk11 -install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -Dgpg.skip -B -V \ No newline at end of file diff --git a/README.md b/README.md index fca706734..322349b73 100755 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ # HiGHmed Data Sharing Framework (HiGHmed DSF) -[![Build Status](https://travis-ci.org/highmed/highmed-dsf.svg?branch=master)](https://travis-ci.org/highmed/highmed-dsf) +[![Java CI with Maven status](https://github.com/highmed/highmed-dsf/workflows/Java%20CI%20with%20Maven/badge.svg)](https://github.com/highmed/highmed-dsf/actions?query=workflow%3A"Java+CI+with+Maven") The HiGHmed Data Sharing Framework (HiGHmed DSF) implements a distributed process engine based on the BPMN 2.0 and FHIR R4 standards. Within the HiGHmed medical informatics consortium, the DSF is used to support biomedical research with routine data. Every participating site runs a FHIR endpoint (dsf-fhir) accessible by other sites and a business process engine (dsf-bpe) in the local secured network. Authentication between sites is handled using X.509 client/server certificates. The process engines execute BPMN processes in order to coordinate local and remote steps necessary to enable cross-site data sharing and feasibility analyses. This includes access to local data repositories, use-and-access-committee decision support, consent filtering, and privacy preserving record-linkage and pseudonymization. -## Introduction -An introduction to the HiGHmed data sharing architecture can be found on [YouTube](http://www.youtube.com/watch?v=YPcryul5occ) (German). +## Development +Branching follows the git-flow model, for the latest development version see branch [develop](https://github.com/highmed/highmed-dsf/tree/develop). + +## License +All code from the HiGHmed Data Sharing Framework is published under the [Apache-2.0 License](LICENSE). ## Wiki -The Wiki with the full documentation can be found [here](https://github.com/highmed/highmed-dsf/wiki). +A full documentation can be found in the [Wiki](https://github.com/highmed/highmed-dsf/wiki). ## Manual Integration Testing (local with Docker) -Prerequisite: Java 11, Maven 3.6, Docker 18 +Prerequisite: Java 11, Maven >= 3.6, Docker >= 18 * Build the entire project from the root directory of this repository ``` diff --git a/dsf-bpe/dsf-bpe-process-base/pom.xml b/dsf-bpe/dsf-bpe-process-base/pom.xml index 33d120a20..a5b67a2d8 100755 --- a/dsf-bpe/dsf-bpe-process-base/pom.xml +++ b/dsf-bpe/dsf-bpe-process-base/pom.xml @@ -1,5 +1,5 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 dsf-bpe-process-base @@ -7,7 +7,7 @@ org.highmed.dsf dsf-bpe-pom - 0.1.0 + 0.2.0 @@ -28,5 +28,11 @@ org.camunda.bpm camunda-engine + + + de.hs-heilbronn.mi + log4j2-utils + test + \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/bpe/Constants.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/bpe/Constants.java index a723033c2..945287256 100755 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/bpe/Constants.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/bpe/Constants.java @@ -12,11 +12,14 @@ public interface Constants // String VARIABLE_CORRELATION_KEY = "correlationKey"; String VARIABLE_MULTI_INSTANCE_TARGET = "multiInstanceTarget"; String VARIABLE_MULTI_INSTANCE_TARGETS = "multiInstanceTargets"; + String VARIABLE_BLOOM_FILTER_CONFIG = "bloomFilterConfig"; String VARIABLE_QUERY_RESULTS = "queryResults"; + String VARIABLE_FINAL_QUERY_RESULTS = "finalQueryResults"; String VARIABLE_TASK = "task"; String VARIABLE_LEADING_TASK = "leadingTask"; String VARIABLE_RESEARCH_STUDY = "researchStudy"; String VARIABLE_COHORTS = "cohorts"; + String VARIABLE_TTP_IDENTIFIER = "ttp"; String VARIABLE_QUERIES = "queries"; String VARIABLE_QUERY_PARAMETERS = "queryParameters"; String VARIABLE_BUNDLE_ID = "bundleId"; @@ -24,14 +27,8 @@ public interface Constants String VARIABLE_NEEDS_RECORD_LINKAGE = "needsRecordLinkage"; /** - * Stores a List<{@link org.highmed.dsf.bpe.variables.FinalSimpleFeasibilityResult}> of the final results of - * a multi medic simple cohort size query. Do not override, only add new entries to the list. - */ - String VARIABLE_SIMPLE_COHORT_SIZE_QUERY_FINAL_RESULT = "simpleCohortSizeQueryFinalResult"; - - /** - * Stores a List<{@link org.highmed.dsf.fhir.variables.Outputs}> of outputs that have to be written to a - * task resource after the process terminates. Do not override, only add new entries to the list. + * Stores a List<{@link org.highmed.dsf.fhir.variables.Outputs}> of outputs that have to be written to a task + * resource after the process terminates. Do not override, only add new entries to the list. */ String VARIABLE_PROCESS_OUTPUTS = "outputs"; @@ -54,13 +51,16 @@ public interface Constants String CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_PARTICIPATING_MEDIC_CORRELATION_KEY = "medic-correlation-key"; String CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_NEEDS_CONSENT_CHECK = "needs-consent-check"; String CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_NEEDS_RECORD_LINKAGE = "needs-record-linkage"; + String CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_BLOOM_FILTER_CONFIG = "bloom-filter-configuration"; String CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_SINGLE_MEDIC_RESULT = "single-medic-result"; + String CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_SINGLE_MEDIC_RESULT_REFERENCE = "single-medic-result-reference"; String CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_PARTICIPATING_MEDICS_COUNT = "participating-medics"; + String CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_NOT_ENOUGH_PARTICIPATION = "not-enough-participation"; String CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_MULTI_MEDIC_RESULT = "multi-medic-result"; String CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_RESEARCH_STUDY_REFERENCE = "research-study-reference"; String CODESYSTEM_HIGHMED_UPDATE_WHITELIST = "http://highmed.org/fhir/CodeSystem/update-whitelist"; - String CODESYSTEM_HIGHMED_UPDATE_WHITELIST_VALUE_WHITE_LIST = "HiGHmed_white_list"; + String CODESYSTEM_HIGHMED_UPDATE_WHITELIST_VALUE_WHITE_LIST = "highmed_whitelist"; String PROCESS_URI_BASE = "http://highmed.org/bpe/Process/"; @@ -69,6 +69,7 @@ public interface Constants String ENDPOINT_IDENTIFIER_SYSTEM = "http://highmed.org/fhir/NamingSystem/endpoint-identifier"; String EXTENSION_PARTICIPATING_MEDIC_URI = "http://highmed.org/fhir/StructureDefinition/participating-medic"; + String EXTENSION_PARTICIPATING_TTP_URI = "http://highmed.org/fhir/StructureDefinition/participating-ttp"; String EXTENSION_QUERY_URI = "http://highmed.org/fhir/StructureDefinition/query"; String EXTENSION_GROUP_ID_URI = "http://highmed.org/fhir/StructureDefinition/group-id"; @@ -81,4 +82,6 @@ public interface Constants CodeType AQL_QUERY_TYPE = new CodeType("application/x-aql-query") .setSystem("http://highmed.org/fhir/CodeSystem/query-type"); + + String OPENEHR_MIMETYPE_JSON = "application/json"; } diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/bpe/delegate/AbstractServiceDelegate.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/bpe/delegate/AbstractServiceDelegate.java index b04f378b6..16654602d 100755 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/bpe/delegate/AbstractServiceDelegate.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/bpe/delegate/AbstractServiceDelegate.java @@ -73,7 +73,7 @@ public final void execute(DelegateExecution execution) throws Exception task = taskHelper.addOutputs(task, outputs); task.setStatus(Task.TaskStatus.FAILED); - webserviceClient.update(task); + webserviceClient.withMinimalReturn().update(task); execution.getProcessEngine().getRuntimeService() .deleteProcessInstance(execution.getProcessInstanceId(), exception.getMessage()); diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/task/AbstractTaskMessageSend.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/task/AbstractTaskMessageSend.java index b1f72cd19..bdd591856 100755 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/task/AbstractTaskMessageSend.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/task/AbstractTaskMessageSend.java @@ -74,12 +74,12 @@ public void doExecute(DelegateExecution execution) throws Exception } catch (Exception e) { - String errorMessage = - "Error while sending Task (process: " + processDefinitionKey + ", version: " + versionTag - + ", message-name: " + messageName + ", business-key: " + businessKey - + ", correlation-key: " + target.getCorrelationKey() + ") to organization with identifier " - + target.getTargetOrganizationIdentifierValue() + ": " + e.getMessage(); + String errorMessage = "Error while sending Task (process: " + processDefinitionKey + ", version: " + + versionTag + ", message-name: " + messageName + ", business-key: " + businessKey + + ", correlation-key: " + target.getCorrelationKey() + ") to organization with identifier " + + target.getTargetOrganizationIdentifierValue() + ": " + e.getMessage(); logger.warn(errorMessage); + logger.debug("Error while sending Task", e); Outputs outputs = (Outputs) execution.getVariable(Constants.VARIABLE_PROCESS_OUTPUTS); outputs.addErrorOutput(errorMessage); @@ -96,7 +96,8 @@ public void doExecute(DelegateExecution execution) throws Exception * Override this method to set a different multiinstance target then the one defined in the process variable * {@link Constants#VARIABLE_MULTI_INSTANCE_TARGET} * - * @param execution the delegate execution of this process instance + * @param execution + * the delegate execution of this process instance * @return {@link MultiInstanceTarget} that should receive the message */ protected MultiInstanceTarget getMultiInstanceTarget(DelegateExecution execution) @@ -136,26 +137,26 @@ protected void sendTask(String targetOrganizationIdentifierValue, String process // http://highmed.org/bpe/Process/processDefinitionKey // http://highmed.org/bpe/Process/processDefinitionKey/versionTag - String instantiatesUri = - Constants.PROCESS_URI_BASE + processDefinitionKey + (versionTag != null && !versionTag.isEmpty() ? - ("/" + versionTag) : - ""); + String instantiatesUri = Constants.PROCESS_URI_BASE + processDefinitionKey + + (versionTag != null && !versionTag.isEmpty() ? ("/" + versionTag) : ""); task.setInstantiatesUri(instantiatesUri); - ParameterComponent messageNameInput = new ParameterComponent(new CodeableConcept( - new Coding(Constants.CODESYSTEM_HIGHMED_BPMN, Constants.CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME, - null)), new StringType(messageName)); + ParameterComponent messageNameInput = new ParameterComponent( + new CodeableConcept(new Coding(Constants.CODESYSTEM_HIGHMED_BPMN, + Constants.CODESYSTEM_HIGHMED_BPMN_VALUE_MESSAGE_NAME, null)), + new StringType(messageName)); task.getInput().add(messageNameInput); - ParameterComponent businessKeyInput = new ParameterComponent(new CodeableConcept( - new Coding(Constants.CODESYSTEM_HIGHMED_BPMN, Constants.CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY, - null)), new StringType(businessKey)); + ParameterComponent businessKeyInput = new ParameterComponent( + new CodeableConcept(new Coding(Constants.CODESYSTEM_HIGHMED_BPMN, + Constants.CODESYSTEM_HIGHMED_BPMN_VALUE_BUSINESS_KEY, null)), + new StringType(businessKey)); task.getInput().add(businessKeyInput); if (correlationKey != null) { - ParameterComponent correlationKeyInput = new ParameterComponent(new CodeableConcept( - new Coding(Constants.CODESYSTEM_HIGHMED_BPMN, + ParameterComponent correlationKeyInput = new ParameterComponent( + new CodeableConcept(new Coding(Constants.CODESYSTEM_HIGHMED_BPMN, Constants.CODESYSTEM_HIGHMED_BPMN_VALUE_CORRELATION_KEY, null)), new StringType(correlationKey)); task.getInput().add(correlationKeyInput); @@ -170,7 +171,7 @@ protected void sendTask(String targetOrganizationIdentifierValue, String process client.getBaseUrl()); logger.trace("Task resource to send: {}", fhirContext.newJsonParser().encodeResourceToString(task)); - client.create(task); + client.withMinimalReturn().create(task); } private FhirWebserviceClient getFhirClient(Task task, String targetOrganizationIdentifierValue) @@ -183,9 +184,8 @@ private FhirWebserviceClient getFhirClient(Task task, String targetOrganizationI else { logger.trace("Using remote webservice client"); - return getFhirWebserviceClientProvider() - .getRemoteWebserviceClient(organizationProvider.getDefaultIdentifierSystem(), - targetOrganizationIdentifierValue); + return getFhirWebserviceClientProvider().getRemoteWebserviceClient( + organizationProvider.getDefaultIdentifierSystem(), targetOrganizationIdentifierValue); } } diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/task/TaskHelper.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/task/TaskHelper.java index 62c263301..aa307ac93 100755 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/task/TaskHelper.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/task/TaskHelper.java @@ -6,6 +6,8 @@ import org.highmed.dsf.fhir.variables.Outputs; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.ParameterComponent; +import org.hl7.fhir.r4.model.Task.TaskOutputComponent; import org.hl7.fhir.r4.model.UrlType; public interface TaskHelper @@ -24,17 +26,27 @@ public interface TaskHelper Optional getFirstInputParameterUrlValue(Task task, String system, String code); - Stream getInputParameterWithExtension(Task task, String system, String code, String url); - Stream getInputParameterUrlValues(Task task, String system, String code); - Task.ParameterComponent createInput(String system, String code, String value); + Optional getFirstInputParameterByteValue(Task task, String system, String code); + + Stream getInputParameterWithExtension(Task task, String system, String code, String url); + + ParameterComponent createInput(String system, String code, String value); + + ParameterComponent createInput(String system, String code, boolean value); + + ParameterComponent createInput(String system, String code, Reference reference); + + ParameterComponent createInput(String system, String code, byte[] bytes); + + ParameterComponent createInputUnsignedInt(String system, String code, int value); - Task.ParameterComponent createInput(String system, String code, boolean value); + ParameterComponent createInput(String system, String code, int value); - Task.ParameterComponent createInput(String system, String code, Reference reference); + TaskOutputComponent createOutput(String system, String code, String value); - Task.TaskOutputComponent createOutput(String system, String code, String value); + TaskOutputComponent createOutputUnsignedInt(String system, String code, int value); Task addOutputs(Task task, Outputs outputs); } diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/BloomFilterConfig.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/BloomFilterConfig.java new file mode 100644 index 000000000..051677144 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/BloomFilterConfig.java @@ -0,0 +1,103 @@ +package org.highmed.dsf.fhir.variables; + +import java.security.Key; + +import javax.crypto.spec.SecretKeySpec; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +public class BloomFilterConfig +{ + private static final int SEED_LENGTH = 8; + private static final int HMAC_SHA2_KEY_LENGTH = 32; + private static final int HMAC_SHA3_KEY_LENGTH = 32; + + private final long permutationSeed; + + @JsonDeserialize(using = KeyDeserializer.class) + @JsonSerialize(using = KeySerializer.class) + private final Key hmacSha2Key; + + @JsonDeserialize(using = KeyDeserializer.class) + @JsonSerialize(using = KeySerializer.class) + private final Key hmacSha3Key; + + public static BloomFilterConfig fromBytes(byte[] bytes) + { + if (bytes.length != SEED_LENGTH + HMAC_SHA2_KEY_LENGTH + HMAC_SHA3_KEY_LENGTH) + throw new IllegalArgumentException( + "bytes.length = " + (SEED_LENGTH + HMAC_SHA2_KEY_LENGTH + HMAC_SHA3_KEY_LENGTH) + + " expected, but got " + bytes.length); + + byte[] seed = new byte[SEED_LENGTH]; + byte[] key1 = new byte[HMAC_SHA2_KEY_LENGTH]; + byte[] key2 = new byte[HMAC_SHA3_KEY_LENGTH]; + + System.arraycopy(bytes, 0, seed, 0, seed.length); + System.arraycopy(bytes, seed.length, key1, 0, key1.length); + System.arraycopy(bytes, seed.length + key1.length, key2, 0, key2.length); + + long permutationSeed = bigEndianToLong(seed); + Key hmacSha2Key = new SecretKeySpec(key1, "HmacSHA256"); + Key hmacSha3Key = new SecretKeySpec(key2, "HmacSHA3-256"); + + return new BloomFilterConfig(permutationSeed, hmacSha2Key, hmacSha3Key); + } + + @JsonCreator + public BloomFilterConfig(@JsonProperty("permutationSeed") long permutationSeed, + @JsonProperty("hmacSha2Key") Key hmacSha2Key, @JsonProperty("hmacSha3Key") Key hmacSha3Key) + { + this.permutationSeed = permutationSeed; + this.hmacSha2Key = hmacSha2Key; + this.hmacSha3Key = hmacSha3Key; + } + + public long getPermutationSeed() + { + return permutationSeed; + } + + public Key getHmacSha2Key() + { + return hmacSha2Key; + } + + public Key getHmacSha3Key() + { + return hmacSha3Key; + } + + @JsonIgnore + public byte[] toBytes() + { + byte[] bytes = new byte[SEED_LENGTH + HMAC_SHA2_KEY_LENGTH + HMAC_SHA3_KEY_LENGTH]; + + byte[] seed = longToBigEndian(permutationSeed); + byte[] key1 = hmacSha2Key.getEncoded(); + byte[] key2 = hmacSha3Key.getEncoded(); + + System.arraycopy(seed, 0, bytes, 0, seed.length); + System.arraycopy(key1, 0, bytes, SEED_LENGTH, key1.length); + System.arraycopy(key2, 0, bytes, SEED_LENGTH + HMAC_SHA2_KEY_LENGTH, key2.length); + + return bytes; + } + + private static byte[] longToBigEndian(long l) + { + return new byte[] { (byte) (l >>> 56), (byte) (l >>> 48), (byte) (l >>> 40), (byte) (l >>> 32), + (byte) (l >>> 24), (byte) (l >>> 16), (byte) (l >>> 8), (byte) (l >>> 0) }; + } + + private static long bigEndianToLong(byte[] b) + { + return (((long) b[0] << 56) + ((long) (b[1] & 255) << 48) + ((long) (b[2] & 255) << 40) + + ((long) (b[3] & 255) << 32) + ((long) (b[4] & 255) << 24) + ((b[5] & 255) << 16) + ((b[6] & 255) << 8) + + ((b[7] & 255) << 0)); + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/BloomFilterConfigSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/BloomFilterConfigSerializer.java new file mode 100644 index 000000000..372d24c25 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/BloomFilterConfigSerializer.java @@ -0,0 +1,70 @@ +package org.highmed.dsf.fhir.variables; + +import java.io.IOException; +import java.util.Objects; + +import org.camunda.bpm.engine.impl.variable.serializer.PrimitiveValueSerializer; +import org.camunda.bpm.engine.impl.variable.serializer.ValueFields; +import org.camunda.bpm.engine.variable.impl.value.UntypedValueImpl; +import org.highmed.dsf.fhir.variables.BloomFilterConfigValues.BloomFilterConfigValue; +import org.springframework.beans.factory.InitializingBean; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class BloomFilterConfigSerializer extends PrimitiveValueSerializer + implements InitializingBean +{ + private final ObjectMapper objectMapper; + + public BloomFilterConfigSerializer(ObjectMapper objectMapper) + { + super(BloomFilterConfigValues.VALUE_TYPE); + + this.objectMapper = objectMapper; + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(objectMapper, "objectMapper"); + } + + @Override + public void writeValue(BloomFilterConfigValue value, ValueFields valueFields) + { + BloomFilterConfig target = value.getValue(); + try + { + if (target != null) + valueFields.setByteArrayValue(objectMapper.writeValueAsBytes(target)); + } + catch (JsonProcessingException e) + { + throw new RuntimeException(e); + } + } + + @Override + public BloomFilterConfigValue convertToTypedValue(UntypedValueImpl untypedValue) + { + return BloomFilterConfigValues.create((BloomFilterConfig) untypedValue.getValue()); + } + + @Override + public BloomFilterConfigValue readValue(ValueFields valueFields, boolean asTransientValue) + { + byte[] bytes = valueFields.getByteArrayValue(); + + try + { + BloomFilterConfig target = (bytes == null || bytes.length <= 0) ? null + : objectMapper.readValue(bytes, BloomFilterConfig.class); + return BloomFilterConfigValues.create(target); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/BloomFilterConfigValues.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/BloomFilterConfigValues.java new file mode 100644 index 000000000..a38d71162 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/BloomFilterConfigValues.java @@ -0,0 +1,54 @@ +package org.highmed.dsf.fhir.variables; + +import java.util.Map; + +import org.camunda.bpm.engine.variable.impl.type.PrimitiveValueTypeImpl; +import org.camunda.bpm.engine.variable.impl.value.PrimitiveTypeValueImpl; +import org.camunda.bpm.engine.variable.type.PrimitiveValueType; +import org.camunda.bpm.engine.variable.value.PrimitiveValue; +import org.camunda.bpm.engine.variable.value.TypedValue; + +public class BloomFilterConfigValues +{ + public static interface BloomFilterConfigValue extends PrimitiveValue + { + } + + private static class BloomFilterConfigValueImpl extends PrimitiveTypeValueImpl + implements BloomFilterConfigValues.BloomFilterConfigValue + { + private static final long serialVersionUID = 1L; + + public BloomFilterConfigValueImpl(BloomFilterConfig value, PrimitiveValueType type) + { + super(value, type); + } + } + + public static class BloomFilterConfigValueTypeImpl extends PrimitiveValueTypeImpl + { + private static final long serialVersionUID = 1L; + + private BloomFilterConfigValueTypeImpl() + { + super(BloomFilterConfig.class); + } + + @Override + public TypedValue createValue(Object value, Map valueInfo) + { + return new BloomFilterConfigValues.BloomFilterConfigValueImpl((BloomFilterConfig) value, VALUE_TYPE); + } + } + + public static final PrimitiveValueType VALUE_TYPE = new BloomFilterConfigValues.BloomFilterConfigValueTypeImpl(); + + private BloomFilterConfigValues() + { + } + + public static BloomFilterConfigValues.BloomFilterConfigValue create(BloomFilterConfig value) + { + return new BloomFilterConfigValues.BloomFilterConfigValueImpl(value, VALUE_TYPE); + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResult.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResult.java index eca10b8e4..5558a7680 100755 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResult.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResult.java @@ -1,6 +1,9 @@ package org.highmed.dsf.fhir.variables; +import org.highmed.openehr.model.structure.ResultSet; + import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; public class FeasibilityQueryResult @@ -8,16 +11,37 @@ public class FeasibilityQueryResult private final String organizationIdentifier; private final String cohortId; private final int cohortSize; + private final ResultSet resultSet; + private final String resultSetUrl; + + public static FeasibilityQueryResult countResult(String organizationIdentifier, String cohortId, int cohortSize) + { + if (cohortSize < 0) + throw new IllegalArgumentException("cohortSize >= 0 expected"); + + return new FeasibilityQueryResult(organizationIdentifier, cohortId, cohortSize, null, null); + } + + public static FeasibilityQueryResult idResult(String organizationIdentifier, String cohortId, ResultSet resultSet) + { + return new FeasibilityQueryResult(organizationIdentifier, cohortId, -1, resultSet, null); + } + + public static FeasibilityQueryResult idResult(String organizationIdentifier, String cohortId, String resultSetUrl) + { + return new FeasibilityQueryResult(organizationIdentifier, cohortId, -1, null, resultSetUrl); + } @JsonCreator - public FeasibilityQueryResult( - @JsonProperty("organizationIdentifier") String organizationIdentifier, - @JsonProperty("groupId") String groupId, - @JsonProperty("groupSize") int groupSize) + public FeasibilityQueryResult(@JsonProperty("organizationIdentifier") String organizationIdentifier, + @JsonProperty("cohortId") String cohortId, @JsonProperty("cohortSize") int cohortSize, + @JsonProperty("resultSet") ResultSet resultSet, @JsonProperty("resultSetUrl") String resultSetUrl) { this.organizationIdentifier = organizationIdentifier; - this.cohortId = groupId; - this.cohortSize = groupSize; + this.cohortId = cohortId; + this.cohortSize = cohortSize; + this.resultSet = resultSet; + this.resultSetUrl = resultSetUrl; } public String getOrganizationIdentifier() @@ -34,4 +58,32 @@ public int getCohortSize() { return cohortSize; } + + public ResultSet getResultSet() + { + return resultSet; + } + + public String getResultSetUrl() + { + return resultSetUrl; + } + + @JsonIgnore + public boolean isCohortSizeResult() + { + return resultSet == null && resultSetUrl == null; + } + + @JsonIgnore + public boolean isIdResultSetResult() + { + return resultSet != null && resultSetUrl == null; + } + + @JsonIgnore + public boolean isIdResultSetUrlResult() + { + return resultSet == null && resultSetUrl != null; + } } diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResultSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResultSerializer.java index 1d139ce93..591946001 100644 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResultSerializer.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResultSerializer.java @@ -33,11 +33,11 @@ public void afterPropertiesSet() throws Exception @Override public void writeValue(FeasibilityQueryResultValue value, ValueFields valueFields) { - FeasibilityQueryResult target = value.getValue(); + FeasibilityQueryResult result = value.getValue(); try { - if (target != null) - valueFields.setByteArrayValue(objectMapper.writeValueAsBytes(target)); + if (result != null) + valueFields.setByteArrayValue(objectMapper.writeValueAsBytes(result)); } catch (JsonProcessingException e) { @@ -52,15 +52,15 @@ public FeasibilityQueryResultValue convertToTypedValue(UntypedValueImpl untypedV } @Override - public FeasibilityQueryResultValue readValue(ValueFields valueFields) + public FeasibilityQueryResultValue readValue(ValueFields valueFields, boolean asTransientValue) { byte[] bytes = valueFields.getByteArrayValue(); try { - FeasibilityQueryResult target = (bytes == null || bytes.length <= 0) ? null + FeasibilityQueryResult result = (bytes == null || bytes.length <= 0) ? null : objectMapper.readValue(bytes, FeasibilityQueryResult.class); - return FeasibilityQueryResultValues.create(target); + return FeasibilityQueryResultValues.create(result); } catch (IOException e) { diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResultsSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResultsSerializer.java index 347d814a0..d7b8afe31 100644 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResultsSerializer.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FeasibilityQueryResultsSerializer.java @@ -33,11 +33,11 @@ public void afterPropertiesSet() throws Exception @Override public void writeValue(FeasibilityQueryResultsValue value, ValueFields valueFields) { - FeasibilityQueryResults targets = value.getValue(); + FeasibilityQueryResults results = value.getValue(); try { - if (targets != null) - valueFields.setByteArrayValue(objectMapper.writeValueAsBytes(targets)); + if (results != null) + valueFields.setByteArrayValue(objectMapper.writeValueAsBytes(results)); } catch (JsonProcessingException e) { @@ -52,15 +52,15 @@ public FeasibilityQueryResultsValue convertToTypedValue(UntypedValueImpl untyped } @Override - public FeasibilityQueryResultsValue readValue(ValueFields valueFields) + public FeasibilityQueryResultsValue readValue(ValueFields valueFields, boolean asTransientValue) { byte[] bytes = valueFields.getByteArrayValue(); try { - FeasibilityQueryResults targets = (bytes == null || bytes.length <= 0) ? null + FeasibilityQueryResults results = (bytes == null || bytes.length <= 0) ? null : objectMapper.readValue(bytes, FeasibilityQueryResults.class); - return FeasibilityQueryResultsValues.create(targets); + return FeasibilityQueryResultsValues.create(results); } catch (IOException e) { diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirResourceSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirResourceSerializer.java index 04e187b85..bdc7c8241 100644 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirResourceSerializer.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirResourceSerializer.java @@ -66,7 +66,7 @@ public FhirResourceValue convertToTypedValue(UntypedValueImpl untypedValue) } @Override - public FhirResourceValue readValue(ValueFields valueFields) + public FhirResourceValue readValue(ValueFields valueFields, boolean asTransientValue) { String className = valueFields.getTextValue(); byte[] bytes = valueFields.getByteArrayValue(); diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirResourcesListSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirResourcesListSerializer.java index bf430e970..3298df9a7 100644 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirResourcesListSerializer.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirResourcesListSerializer.java @@ -58,7 +58,7 @@ public FhirResourcesListValue convertToTypedValue(UntypedValueImpl untypedValue) } @Override - public FhirResourcesListValue readValue(ValueFields valueFields) + public FhirResourcesListValue readValue(ValueFields valueFields, boolean asTransientValue) { String className = valueFields.getTextValue(); byte[] bytes = valueFields.getByteArrayValue(); diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResult.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResult.java new file mode 100644 index 000000000..6e19c49b1 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResult.java @@ -0,0 +1,35 @@ +package org.highmed.dsf.fhir.variables; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class FinalFeasibilityQueryResult +{ + private final String cohortId; + private final int participatingMedics; + private final int cohortSize; + + @JsonCreator + public FinalFeasibilityQueryResult(@JsonProperty("cohortId") String cohortId, + @JsonProperty("participatingMedics") int participatingMedics, @JsonProperty("cohortSize") int cohortSize) + { + this.cohortId = cohortId; + this.participatingMedics = participatingMedics; + this.cohortSize = cohortSize; + } + + public String getCohortId() + { + return cohortId; + } + + public int getParticipatingMedics() + { + return participatingMedics; + } + + public int getCohortSize() + { + return cohortSize; + } +} \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultSerializer.java new file mode 100644 index 000000000..c67dcd212 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultSerializer.java @@ -0,0 +1,70 @@ +package org.highmed.dsf.fhir.variables; + +import java.io.IOException; +import java.util.Objects; + +import org.camunda.bpm.engine.impl.variable.serializer.PrimitiveValueSerializer; +import org.camunda.bpm.engine.impl.variable.serializer.ValueFields; +import org.camunda.bpm.engine.variable.impl.value.UntypedValueImpl; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResultValues.FinalFeasibilityQueryResultValue; +import org.springframework.beans.factory.InitializingBean; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class FinalFeasibilityQueryResultSerializer extends PrimitiveValueSerializer + implements InitializingBean +{ + private final ObjectMapper objectMapper; + + public FinalFeasibilityQueryResultSerializer(ObjectMapper objectMapper) + { + super(FinalFeasibilityQueryResultValues.VALUE_TYPE); + + this.objectMapper = objectMapper; + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(objectMapper, "objectMapper"); + } + + @Override + public void writeValue(FinalFeasibilityQueryResultValue value, ValueFields valueFields) + { + FinalFeasibilityQueryResult result = value.getValue(); + try + { + if (result != null) + valueFields.setByteArrayValue(objectMapper.writeValueAsBytes(result)); + } + catch (JsonProcessingException e) + { + throw new RuntimeException(e); + } + } + + @Override + public FinalFeasibilityQueryResultValue convertToTypedValue(UntypedValueImpl untypedValue) + { + return FinalFeasibilityQueryResultValues.create((FinalFeasibilityQueryResult) untypedValue.getValue()); + } + + @Override + public FinalFeasibilityQueryResultValue readValue(ValueFields valueFields, boolean asTransientValue) + { + byte[] bytes = valueFields.getByteArrayValue(); + + try + { + FinalFeasibilityQueryResult result = (bytes == null || bytes.length <= 0) ? null + : objectMapper.readValue(bytes, FinalFeasibilityQueryResult.class); + return FinalFeasibilityQueryResultValues.create(result); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultValues.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultValues.java new file mode 100644 index 000000000..8c29c6a51 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultValues.java @@ -0,0 +1,57 @@ +package org.highmed.dsf.fhir.variables; + +import java.util.Map; + +import org.camunda.bpm.engine.variable.impl.type.PrimitiveValueTypeImpl; +import org.camunda.bpm.engine.variable.impl.value.PrimitiveTypeValueImpl; +import org.camunda.bpm.engine.variable.type.PrimitiveValueType; +import org.camunda.bpm.engine.variable.value.PrimitiveValue; +import org.camunda.bpm.engine.variable.value.TypedValue; + +public class FinalFeasibilityQueryResultValues +{ + public static interface FinalFeasibilityQueryResultValue extends PrimitiveValue + { + } + + private static class FinalFeasibilityQueryResultValueImpl + extends PrimitiveTypeValueImpl + implements FinalFeasibilityQueryResultValues.FinalFeasibilityQueryResultValue + { + private static final long serialVersionUID = 1L; + + public FinalFeasibilityQueryResultValueImpl(FinalFeasibilityQueryResult value, PrimitiveValueType type) + { + super(value, type); + } + } + + public static class FinalFeasibilityQueryResultValueTypeImpl extends PrimitiveValueTypeImpl + { + private static final long serialVersionUID = 1L; + + private FinalFeasibilityQueryResultValueTypeImpl() + { + super(FinalFeasibilityQueryResult.class); + } + + @Override + public TypedValue createValue(Object value, Map valueInfo) + { + return new FinalFeasibilityQueryResultValues.FinalFeasibilityQueryResultValueImpl( + (FinalFeasibilityQueryResult) value, VALUE_TYPE); + } + } + + public static final PrimitiveValueType VALUE_TYPE = new FinalFeasibilityQueryResultValues.FinalFeasibilityQueryResultValueTypeImpl(); + + private FinalFeasibilityQueryResultValues() + { + } + + public static FinalFeasibilityQueryResultValues.FinalFeasibilityQueryResultValue create( + FinalFeasibilityQueryResult value) + { + return new FinalFeasibilityQueryResultValues.FinalFeasibilityQueryResultValueImpl(value, VALUE_TYPE); + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResults.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResults.java new file mode 100644 index 000000000..16fd822f8 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResults.java @@ -0,0 +1,38 @@ +package org.highmed.dsf.fhir.variables; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class FinalFeasibilityQueryResults +{ + private final List results = new ArrayList<>(); + + @JsonCreator + public FinalFeasibilityQueryResults(@JsonProperty("results") Collection results) + { + if (results != null) + this.results.addAll(results); + } + + public void add(FinalFeasibilityQueryResult newResult) + { + if (newResult != null) + results.add(newResult); + } + + public void addAll(Collection results) + { + if (results != null) + this.results.addAll(results); + } + + public List getResults() + { + return Collections.unmodifiableList(results); + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultsSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultsSerializer.java new file mode 100644 index 000000000..ba0eee54b --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultsSerializer.java @@ -0,0 +1,70 @@ +package org.highmed.dsf.fhir.variables; + +import java.io.IOException; +import java.util.Objects; + +import org.camunda.bpm.engine.impl.variable.serializer.PrimitiveValueSerializer; +import org.camunda.bpm.engine.impl.variable.serializer.ValueFields; +import org.camunda.bpm.engine.variable.impl.value.UntypedValueImpl; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResultsValues.FinalFeasibilityQueryResultsValue; +import org.springframework.beans.factory.InitializingBean; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class FinalFeasibilityQueryResultsSerializer extends PrimitiveValueSerializer + implements InitializingBean +{ + private final ObjectMapper objectMapper; + + public FinalFeasibilityQueryResultsSerializer(ObjectMapper objectMapper) + { + super(FinalFeasibilityQueryResultsValues.VALUE_TYPE); + + this.objectMapper = objectMapper; + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(objectMapper, "objectMapper"); + } + + @Override + public void writeValue(FinalFeasibilityQueryResultsValue value, ValueFields valueFields) + { + FinalFeasibilityQueryResults results = value.getValue(); + try + { + if (results != null) + valueFields.setByteArrayValue(objectMapper.writeValueAsBytes(results)); + } + catch (JsonProcessingException e) + { + throw new RuntimeException(e); + } + } + + @Override + public FinalFeasibilityQueryResultsValue convertToTypedValue(UntypedValueImpl untypedValue) + { + return FinalFeasibilityQueryResultsValues.create((FinalFeasibilityQueryResults) untypedValue.getValue()); + } + + @Override + public FinalFeasibilityQueryResultsValue readValue(ValueFields valueFields, boolean asTransientValue) + { + byte[] bytes = valueFields.getByteArrayValue(); + + try + { + FinalFeasibilityQueryResults results = (bytes == null || bytes.length <= 0) ? null + : objectMapper.readValue(bytes, FinalFeasibilityQueryResults.class); + return FinalFeasibilityQueryResultsValues.create(results); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultsValues.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultsValues.java new file mode 100644 index 000000000..ac6b1eae8 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalFeasibilityQueryResultsValues.java @@ -0,0 +1,57 @@ +package org.highmed.dsf.fhir.variables; + +import java.util.Map; + +import org.camunda.bpm.engine.variable.impl.type.PrimitiveValueTypeImpl; +import org.camunda.bpm.engine.variable.impl.value.PrimitiveTypeValueImpl; +import org.camunda.bpm.engine.variable.type.PrimitiveValueType; +import org.camunda.bpm.engine.variable.value.PrimitiveValue; +import org.camunda.bpm.engine.variable.value.TypedValue; + +public class FinalFeasibilityQueryResultsValues +{ + public static interface FinalFeasibilityQueryResultsValue extends PrimitiveValue + { + } + + private static class FinalFeasibilityQueryResultsValueImpl + extends PrimitiveTypeValueImpl + implements FinalFeasibilityQueryResultsValues.FinalFeasibilityQueryResultsValue + { + private static final long serialVersionUID = 1L; + + public FinalFeasibilityQueryResultsValueImpl(FinalFeasibilityQueryResults value, PrimitiveValueType type) + { + super(value, type); + } + } + + public static class FinalFeasibilityQueryResultsValueTypeImpl extends PrimitiveValueTypeImpl + { + private static final long serialVersionUID = 1L; + + private FinalFeasibilityQueryResultsValueTypeImpl() + { + super(FinalFeasibilityQueryResults.class); + } + + @Override + public TypedValue createValue(Object value, Map valueInfo) + { + return new FinalFeasibilityQueryResultsValues.FinalFeasibilityQueryResultsValueImpl( + (FinalFeasibilityQueryResults) value, VALUE_TYPE); + } + } + + public static final PrimitiveValueType VALUE_TYPE = new FinalFeasibilityQueryResultsValues.FinalFeasibilityQueryResultsValueTypeImpl(); + + private FinalFeasibilityQueryResultsValues() + { + } + + public static FinalFeasibilityQueryResultsValues.FinalFeasibilityQueryResultsValue create( + FinalFeasibilityQueryResults value) + { + return new FinalFeasibilityQueryResultsValues.FinalFeasibilityQueryResultsValueImpl(value, VALUE_TYPE); + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalSimpleFeasibilityResult.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalSimpleFeasibilityResult.java deleted file mode 100644 index 40b369d6c..000000000 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FinalSimpleFeasibilityResult.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.highmed.dsf.fhir.variables; - -public class FinalSimpleFeasibilityResult -{ - private final String cohortId; - private final long participatingMedics; - private final long cohortSize; - - public FinalSimpleFeasibilityResult(String cohortId, long participatingMedics, long cohortSize) - { - this.cohortId = cohortId; - this.participatingMedics = participatingMedics; - this.cohortSize = cohortSize; - } - - public String getCohortId() - { - return cohortId; - } - - public long getParticipatingMedics() - { - return participatingMedics; - } - - public long getCohortSize() - { - return cohortSize; - } -} \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/KeyDeserializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/KeyDeserializer.java new file mode 100644 index 000000000..8961869a4 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/KeyDeserializer.java @@ -0,0 +1,27 @@ +package org.highmed.dsf.fhir.variables; + +import java.io.IOException; +import java.security.Key; + +import javax.crypto.spec.SecretKeySpec; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.node.TextNode; + +public class KeyDeserializer extends JsonDeserializer +{ + @Override + public Key deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException + { + TreeNode node = p.getCodec().readTree(p); + + String algorithm = ((TextNode) node.get("algorithm")).textValue(); + byte[] value = ((TextNode) node.get("value")).binaryValue(); + + return new SecretKeySpec(value, algorithm); + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/KeySerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/KeySerializer.java new file mode 100644 index 000000000..9b104277a --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/KeySerializer.java @@ -0,0 +1,24 @@ +package org.highmed.dsf.fhir.variables; + +import java.io.IOException; +import java.security.Key; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +public class KeySerializer extends JsonSerializer +{ + @Override + public void serialize(Key value, JsonGenerator jgen, SerializerProvider provider) + throws IOException, JsonGenerationException + { + jgen.writeStartObject(); + jgen.writeFieldName("algorithm"); + jgen.writeString(value.getAlgorithm()); + jgen.writeFieldName("value"); + jgen.writeBinary(value.getEncoded()); + jgen.writeEndObject(); + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/MultiInstanceTargetSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/MultiInstanceTargetSerializer.java index 48934830d..7993c0ed0 100755 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/MultiInstanceTargetSerializer.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/MultiInstanceTargetSerializer.java @@ -52,7 +52,7 @@ public MultiInstanceTargetValue convertToTypedValue(UntypedValueImpl untypedValu } @Override - public MultiInstanceTargetValue readValue(ValueFields valueFields) + public MultiInstanceTargetValue readValue(ValueFields valueFields, boolean asTransientValue) { byte[] bytes = valueFields.getByteArrayValue(); diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/MultiInstanceTargetsSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/MultiInstanceTargetsSerializer.java index c7493ddaf..add2f433f 100755 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/MultiInstanceTargetsSerializer.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/MultiInstanceTargetsSerializer.java @@ -52,7 +52,7 @@ public MultiInstanceTargetsValue convertToTypedValue(UntypedValueImpl untypedVal } @Override - public MultiInstanceTargetsValue readValue(ValueFields valueFields) + public MultiInstanceTargetsValue readValue(ValueFields valueFields, boolean asTransientValue) { byte[] bytes = valueFields.getByteArrayValue(); diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/OutputSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/OutputSerializer.java index e1a0d5aa2..de5034b6c 100755 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/OutputSerializer.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/OutputSerializer.java @@ -51,7 +51,7 @@ public OutputValue convertToTypedValue(UntypedValueImpl untypedValue) } @Override - public OutputValue readValue(ValueFields valueFields) + public OutputValue readValue(ValueFields valueFields, boolean asTransientValue) { byte[] bytes = valueFields.getByteArrayValue(); diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/OutputsSerializer.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/OutputsSerializer.java index 196854ea4..24fa29cb0 100755 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/OutputsSerializer.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/OutputsSerializer.java @@ -51,7 +51,7 @@ public OutputsValue convertToTypedValue(UntypedValueImpl untypedValue) } @Override - public OutputsValue readValue(ValueFields valueFields) + public OutputsValue readValue(ValueFields valueFields, boolean asTransientValue) { byte[] bytes = valueFields.getByteArrayValue(); diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirPlugin.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/SerializerPlugin.java old mode 100755 new mode 100644 similarity index 71% rename from dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirPlugin.java rename to dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/SerializerPlugin.java index 55950dda5..ead6dfb0b --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/FhirPlugin.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/fhir/variables/SerializerPlugin.java @@ -8,22 +8,26 @@ import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin; import org.camunda.bpm.engine.impl.variable.serializer.TypedValueSerializer; -public class FhirPlugin implements ProcessEnginePlugin +public class SerializerPlugin implements ProcessEnginePlugin { @SuppressWarnings("rawtypes") private final List serializer; - public FhirPlugin(FhirResourceSerializer fhirResourceSerializer, + public SerializerPlugin(FhirResourceSerializer fhirResourceSerializer, FhirResourcesListSerializer fhirResourcesListSerializer, MultiInstanceTargetSerializer multiInstanceTargetSerializer, MultiInstanceTargetsSerializer multiInstanceTargetsSerializer, FeasibilityQueryResultSerializer feasibilityQueryResultSerializer, - FeasibilityQueryResultsSerializer feasibilityQueryResultsSerializer, OutputSerializer outputSerializer, + FeasibilityQueryResultsSerializer feasibilityQueryResultsSerializer, + FinalFeasibilityQueryResultSerializer finalFeasibilityQueryResultSerializer, + FinalFeasibilityQueryResultsSerializer finalFeasibilityQueryResultsSerializer, + BloomFilterConfigSerializer bloomFilterConfigSerializer, OutputSerializer outputSerializer, OutputsSerializer outputsSerializer) { serializer = Arrays.asList(fhirResourceSerializer, fhirResourcesListSerializer, multiInstanceTargetSerializer, multiInstanceTargetsSerializer, feasibilityQueryResultSerializer, feasibilityQueryResultsSerializer, - outputSerializer, outputsSerializer); + finalFeasibilityQueryResultSerializer, finalFeasibilityQueryResultsSerializer, + bloomFilterConfigSerializer, outputSerializer, outputsSerializer); } @Override diff --git a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/openehr/client/OpenEhrWebserviceClientProvider.java b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/openehr/client/OpenEhrWebserviceClientProvider.java index fdf7b7ed1..9757924da 100755 --- a/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/openehr/client/OpenEhrWebserviceClientProvider.java +++ b/dsf-bpe/dsf-bpe-process-base/src/main/java/org/highmed/dsf/openehr/client/OpenEhrWebserviceClientProvider.java @@ -1,10 +1,10 @@ package org.highmed.dsf.openehr.client; -import org.highmed.openehr.client.OpenehrWebserviceClient; +import org.highmed.openehr.client.OpenEhrWebserviceClient; public interface OpenEhrWebserviceClientProvider { String getBaseUrl(); - OpenehrWebserviceClient getWebserviceClient(); + OpenEhrWebserviceClient getWebserviceClient(); } diff --git a/dsf-bpe/dsf-bpe-process-base/src/test/java/org/highmed/dsf/fhir/variables/BloomFilterConfigTest.java b/dsf-bpe/dsf-bpe-process-base/src/test/java/org/highmed/dsf/fhir/variables/BloomFilterConfigTest.java new file mode 100644 index 000000000..a7a6d141d --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/test/java/org/highmed/dsf/fhir/variables/BloomFilterConfigTest.java @@ -0,0 +1,61 @@ +package org.highmed.dsf.fhir.variables; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Base64; + +import javax.crypto.spec.SecretKeySpec; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class BloomFilterConfigTest +{ + private static final Logger logger = LoggerFactory.getLogger(BloomFilterConfigTest.class); + + private static final byte[] b1 = Base64.getDecoder().decode("KLhuuy3lDSmo8A/mcYBBZJ+Xu+ok30qDGM4L0magwyY="); + private static final byte[] b2 = Base64.getDecoder().decode("VALdwRisuEsUBIXaqJ01L9lk0jJUSGm5ZBE+Ha5bm8c="); + private static final long l = -9139328758761390867L; + + @Test + public void testReadWriteJson() throws Exception + { + ObjectMapper objectMapper = new ObjectMapper(); + + BloomFilterConfig bfc = new BloomFilterConfig(l, new SecretKeySpec(b1, "HmacSHA256"), + new SecretKeySpec(b2, "HmacSHA3-256")); + + String value = objectMapper.writeValueAsString(bfc); + + logger.debug("BloomFilterConfig: {}", value); + + BloomFilterConfig readBfc = objectMapper.readValue(value, BloomFilterConfig.class); + + assertNotNull(readBfc); + assertEquals(bfc.getPermutationSeed(), readBfc.getPermutationSeed()); + assertEquals(bfc.getHmacSha2Key(), readBfc.getHmacSha2Key()); + assertEquals(bfc.getHmacSha3Key(), readBfc.getHmacSha3Key()); + } + + @Test + public void testReadWriteBytes() throws Exception + { + BloomFilterConfig bfc = new BloomFilterConfig(l, new SecretKeySpec(b1, "HmacSHA256"), + new SecretKeySpec(b2, "HmacSHA3-256")); + + byte[] bytes = bfc.toBytes(); + + logger.debug("BloomFilterConfig: {}", Base64.getEncoder().encodeToString(bytes)); + + BloomFilterConfig fromBytes = BloomFilterConfig.fromBytes(bytes); + + assertNotNull(fromBytes); + assertEquals(bfc.getPermutationSeed(), fromBytes.getPermutationSeed()); + assertEquals(bfc.getHmacSha2Key(), fromBytes.getHmacSha2Key()); + assertEquals(bfc.getHmacSha3Key(), fromBytes.getHmacSha3Key()); + } +} diff --git a/dsf-bpe/dsf-bpe-process-base/src/test/resources/log4j2.xml b/dsf-bpe/dsf-bpe-process-base/src/test/resources/log4j2.xml new file mode 100644 index 000000000..f1afe81dc --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-base/src/test/resources/log4j2.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-process-feasibility/pom.xml b/dsf-bpe/dsf-bpe-process-feasibility/pom.xml index e3d119997..3e9caa823 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/pom.xml +++ b/dsf-bpe/dsf-bpe-process-feasibility/pom.xml @@ -1,6 +1,6 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 dsf-bpe-process-feasibility @@ -8,7 +8,7 @@ dsf-bpe-pom org.highmed.dsf - 0.1.0 + 0.2.0 @@ -16,6 +16,20 @@ org.highmed.dsf dsf-bpe-process-base + + org.highmed.dsf + dsf-pseudonymization-medic + + + org.highmed.dsf + dsf-pseudonymization-ttp + + + + org.highmed.dsf + dsf-mpi-client + + de.hs-heilbronn.mi log4j2-utils diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendMedicRequest.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendMedicRequest.java index 3e93d09de..131ef178e 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendMedicRequest.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendMedicRequest.java @@ -8,10 +8,11 @@ import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.AbstractTaskMessageSend; import org.highmed.dsf.fhir.task.TaskHelper; +import org.highmed.dsf.fhir.variables.BloomFilterConfig; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.ResearchStudy; -import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.ParameterComponent; import ca.uhn.fhir.context.FhirContext; @@ -24,26 +25,39 @@ public SendMedicRequest(FhirWebserviceClientProvider clientProvider, TaskHelper } @Override - protected Stream getAdditionalInputParameters(DelegateExecution execution) + protected Stream getAdditionalInputParameters(DelegateExecution execution) { ResearchStudy researchStudy = (ResearchStudy) execution.getVariable(Constants.VARIABLE_RESEARCH_STUDY); - IdType type = new IdType(getFhirWebserviceClientProvider().getLocalBaseUrl() + "/" + researchStudy.getId()); + IdType researchStudyId = new IdType( + getFhirWebserviceClientProvider().getLocalBaseUrl() + "/" + researchStudy.getId()); - Task.ParameterComponent inputResearchStudyReference = getTaskHelper() - .createInput(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, - Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_RESEARCH_STUDY_REFERENCE, - new Reference().setReference(type.getValueAsString())); + ParameterComponent inputResearchStudyReference = getTaskHelper().createInput( + Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_RESEARCH_STUDY_REFERENCE, + new Reference().setReference(researchStudyId.toVersionless().getValueAsString())); boolean needsConsentCheck = (boolean) execution.getVariable(Constants.VARIABLE_NEEDS_CONSENT_CHECK); - Task.ParameterComponent inputNeedsConsentCheck = getTaskHelper() - .createInput(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, - Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_NEEDS_CONSENT_CHECK, needsConsentCheck); + ParameterComponent inputNeedsConsentCheck = getTaskHelper().createInput( + Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_NEEDS_CONSENT_CHECK, needsConsentCheck); boolean needsRecordLinkage = (boolean) execution.getVariable(Constants.VARIABLE_NEEDS_RECORD_LINKAGE); - Task.ParameterComponent inputNeedsRecordLinkage = getTaskHelper() - .createInput(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, - Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_NEEDS_RECORD_LINKAGE, needsRecordLinkage); - - return Stream.of(inputResearchStudyReference, inputNeedsConsentCheck, inputNeedsRecordLinkage); + ParameterComponent inputNeedsRecordLinkage = getTaskHelper().createInput( + Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_NEEDS_RECORD_LINKAGE, needsRecordLinkage); + + if (needsRecordLinkage) + { + BloomFilterConfig bloomFilterConfig = (BloomFilterConfig) execution + .getVariable(Constants.VARIABLE_BLOOM_FILTER_CONFIG); + ParameterComponent inputBloomFilterConfig = getTaskHelper().createInput( + Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_BLOOM_FILTER_CONFIG, bloomFilterConfig.toBytes()); + + return Stream.of(inputResearchStudyReference, inputNeedsConsentCheck, inputNeedsRecordLinkage, + inputBloomFilterConfig); + } + else + return Stream.of(inputResearchStudyReference, inputNeedsConsentCheck, inputNeedsRecordLinkage); } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendMultiMedicResults.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendMultiMedicResults.java index a236c53f3..244ceb7c8 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendMultiMedicResults.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendMultiMedicResults.java @@ -8,10 +8,11 @@ import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.AbstractTaskMessageSend; import org.highmed.dsf.fhir.task.TaskHelper; -import org.highmed.dsf.fhir.variables.Outputs; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResult; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResults; import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.Reference; -import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.ParameterComponent; import ca.uhn.fhir.context.FhirContext; @@ -24,19 +25,30 @@ public SendMultiMedicResults(FhirWebserviceClientProvider clientProvider, TaskHe } @Override - protected Stream getAdditionalInputParameters(DelegateExecution execution) + protected Stream getAdditionalInputParameters(DelegateExecution execution) { - Outputs outputs = (Outputs) execution.getVariable(Constants.VARIABLE_PROCESS_OUTPUTS); + FinalFeasibilityQueryResults results = (FinalFeasibilityQueryResults) execution + .getVariable(Constants.VARIABLE_FINAL_QUERY_RESULTS); - return outputs.getOutputs().stream().map(output -> { - Task.ParameterComponent component = getTaskHelper() - .createInput(output.getSystem(), output.getCode(), output.getValue()); + return results.getResults().stream().flatMap(this::toInputs); + } + + private Stream toInputs(FinalFeasibilityQueryResult result) + { + ParameterComponent input1 = getTaskHelper().createInputUnsignedInt(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_MULTI_MEDIC_RESULT, result.getCohortSize()); + input1.addExtension(createCohortIdExtension(result.getCohortId())); - if (output.hasExtension()) - component.addExtension( - new Extension(output.getExtensionUrl(), new Reference(output.getExtensionValue()))); + ParameterComponent input2 = getTaskHelper().createInputUnsignedInt(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_PARTICIPATING_MEDICS_COUNT, + result.getParticipatingMedics()); + input2.addExtension(createCohortIdExtension(result.getCohortId())); - return component; - }); + return Stream.of(input1, input2); + } + + private Extension createCohortIdExtension(String cohortId) + { + return new Extension(Constants.EXTENSION_GROUP_ID_URI, new Reference(cohortId)); } -} +} \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendSingleMedicResults.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendSingleMedicResults.java index 9d49413bd..78ac4f00a 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendSingleMedicResults.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendSingleMedicResults.java @@ -8,15 +8,21 @@ import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.AbstractTaskMessageSend; import org.highmed.dsf.fhir.task.TaskHelper; -import org.highmed.dsf.fhir.variables.Outputs; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResult; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResults; import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.ParameterComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import ca.uhn.fhir.context.FhirContext; public class SendSingleMedicResults extends AbstractTaskMessageSend { + private static final Logger logger = LoggerFactory.getLogger(SendSingleMedicResults.class); + public SendSingleMedicResults(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, OrganizationProvider organizationProvider, FhirContext fhirContext) { @@ -26,14 +32,41 @@ public SendSingleMedicResults(FhirWebserviceClientProvider clientProvider, TaskH @Override protected Stream getAdditionalInputParameters(DelegateExecution execution) { - Outputs outputs = (Outputs) execution.getVariable(Constants.VARIABLE_PROCESS_OUTPUTS); - return outputs.getOutputs().stream().map(o -> { - Task.ParameterComponent component = getTaskHelper().createInput(o.getSystem(), o.getCode(), o.getValue()); + FeasibilityQueryResults results = (FeasibilityQueryResults) execution + .getVariable(Constants.VARIABLE_QUERY_RESULTS); + + return results.getResults().stream().map(result -> toInput(result)); + } - if (o.hasExtension()) - component.addExtension(new Extension(o.getExtensionUrl(), new Reference(o.getExtensionValue()))); + private Task.ParameterComponent toInput(FeasibilityQueryResult result) + { + if (result.isCohortSizeResult()) + { + ParameterComponent input = getTaskHelper().createInputUnsignedInt(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_SINGLE_MEDIC_RESULT, result.getCohortSize()); + input.addExtension(createCohortIdExtension(result.getCohortId())); + return input; + } + else if (result.isIdResultSetUrlResult()) + { + ParameterComponent input = getTaskHelper().createInput(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_SINGLE_MEDIC_RESULT_REFERENCE, + new Reference(result.getResultSetUrl())); + input.addExtension(createCohortIdExtension(result.getCohortId())); + return input; + } + else + { + logger.warn("Unexpected result (not a cohort-size or ResultSet URL result) for cohort with ID " + + result.getCohortId()); + throw new RuntimeException( + "Unexpected result (not a cohort-size or ResultSet URL result) for cohort with ID " + + result.getCohortId()); + } + } - return component; - }); + private Extension createCohortIdExtension(String cohortId) + { + return new Extension(Constants.EXTENSION_GROUP_ID_URI, new Reference(cohortId)); } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendTtpRequest.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendTtpRequest.java index f0828ce7c..1ac5d42ba 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendTtpRequest.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/message/SendTtpRequest.java @@ -32,16 +32,11 @@ protected Stream getAdditionalInputParameters(DelegateE Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_PARTICIPATING_MEDIC_CORRELATION_KEY, target.getCorrelationKey())); - boolean needsConsentCheck = (boolean) execution.getVariable(Constants.VARIABLE_NEEDS_CONSENT_CHECK); - Task.ParameterComponent inputNeedsConsentCheck = getTaskHelper() - .createInput(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, - Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_NEEDS_CONSENT_CHECK, needsConsentCheck); - boolean needsRecordLinkage = (boolean) execution.getVariable(Constants.VARIABLE_NEEDS_RECORD_LINKAGE); Task.ParameterComponent inputNeedsRecordLinkage = getTaskHelper() .createInput(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_NEEDS_RECORD_LINKAGE , needsRecordLinkage); - return Stream.concat(inputTargets, Stream.of(inputNeedsConsentCheck, inputNeedsRecordLinkage)); + return Stream.concat(inputTargets, Stream.of(inputNeedsRecordLinkage)); } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CalculateMultiMedicResults.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CalculateMultiMedicResults.java index 249fbd0ce..24acc480b 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CalculateMultiMedicResults.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CalculateMultiMedicResults.java @@ -1,6 +1,7 @@ package org.highmed.dsf.bpe.service; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import org.camunda.bpm.engine.delegate.DelegateExecution; @@ -10,8 +11,9 @@ import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.fhir.variables.FeasibilityQueryResult; import org.highmed.dsf.fhir.variables.FeasibilityQueryResults; -import org.highmed.dsf.fhir.variables.FinalSimpleFeasibilityResult; -import org.highmed.dsf.fhir.variables.Outputs; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResult; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResults; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResultsValues; public class CalculateMultiMedicResults extends AbstractServiceDelegate { @@ -21,44 +23,35 @@ public CalculateMultiMedicResults(FhirWebserviceClientProvider clientProvider, T } @Override - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { - - List locationBasedResults = ((FeasibilityQueryResults) execution + List results = ((FeasibilityQueryResults) execution .getVariable(Constants.VARIABLE_QUERY_RESULTS)).getResults(); - List finalResults = calculateResults(locationBasedResults); // TODO: add percentage filter over result + List finalResults = calculateResults(results); - Outputs outputs = (Outputs) execution.getVariable(Constants.VARIABLE_PROCESS_OUTPUTS); - addResultsToOutput(outputs, finalResults); - - execution.setVariable(Constants.VARIABLE_PROCESS_OUTPUTS, outputs); + execution.setVariable(Constants.VARIABLE_FINAL_QUERY_RESULTS, + FinalFeasibilityQueryResultsValues.create(new FinalFeasibilityQueryResults(finalResults))); } - private List calculateResults(List results) + private List calculateResults(List results) { - return results.stream().map(FeasibilityQueryResult::getCohortId).distinct().map(groupId -> { - long participatingMedics = results.stream().filter(resultEntry -> resultEntry.getCohortId().equals(groupId)) - .count(); - long result = results.stream().filter(resultEntry -> resultEntry.getCohortId().equals(groupId)) - .mapToInt(FeasibilityQueryResult::getCohortSize).sum(); - return new FinalSimpleFeasibilityResult(groupId, participatingMedics, result); - }).collect(Collectors.toUnmodifiableList()); + Map> byCohortId = results.stream() + .collect(Collectors.groupingBy(FeasibilityQueryResult::getCohortId)); + + return byCohortId.entrySet().stream() + .map(e -> new FinalFeasibilityQueryResult(e.getKey(), + toInt(e.getValue().stream().filter(r -> r.getCohortSize() > 0).count()), + toInt(e.getValue().stream().mapToLong(FeasibilityQueryResult::getCohortSize).sum()))) + .collect(Collectors.toList()); } - private void addResultsToOutput(Outputs outputs, List finalResults) + private int toInt(long l) { - finalResults.forEach(result -> { - outputs.add(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, - Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_MULTI_MEDIC_RESULT, - String.valueOf(result.getCohortSize()), Constants.EXTENSION_GROUP_ID_URI, result.getCohortId()); - ; - - outputs.add(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, - Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_PARTICIPATING_MEDICS_COUNT, - String.valueOf(result.getParticipatingMedics()), Constants.EXTENSION_GROUP_ID_URI, - result.getCohortId()); - }); + if (l > Integer.MAX_VALUE) + throw new IllegalArgumentException("long > " + Integer.MAX_VALUE); + else + return (int) l; } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckFeasibilityResources.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckFeasibilityResources.java index 2bd78ebad..2ff059c82 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckFeasibilityResources.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckFeasibilityResources.java @@ -23,7 +23,7 @@ public CheckFeasibilityResources(FhirWebserviceClientProvider clientProvider, Ta } @Override - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { ResearchStudy researchStudy = (ResearchStudy) execution.getVariable(Constants.VARIABLE_RESEARCH_STUDY); @@ -31,28 +31,39 @@ public void doExecute(DelegateExecution execution) throws Exception .getResourcesAndCast(); checkNumberOfParticipatingMedics(researchStudy); + checkFullyQualifiedCohortIds(cohorts); checkNumberOfCohortDefinitions(cohorts); } private void checkNumberOfParticipatingMedics(ResearchStudy researchStudy) { - long medics = researchStudy.getExtension().stream() - .filter(e -> e.getUrl().equals(Constants.EXTENSION_PARTICIPATING_MEDIC_URI)) - .map(extension -> ((Reference) extension.getValue()).getReference()).distinct().count(); + long medics = researchStudy.getExtensionsByUrl(Constants.EXTENSION_PARTICIPATING_MEDIC_URI).stream() + .filter(e -> e.getValue() instanceof Reference).map(e -> (Reference) e.getValue()) + .map(r -> r.getIdentifier()) + .filter(i -> "http://highmed.org/fhir/NamingSystem/organization-identifier".equals(i.getSystem())) + .map(i -> i.getValue()).distinct().count(); if (medics < MIN_PARTICIPATING_MEDICS) { - throw new IllegalStateException( + throw new RuntimeException( "Number of distinct participanting MeDICs is < " + MIN_PARTICIPATING_MEDICS + ", got " + medics); } } + private void checkFullyQualifiedCohortIds(List cohorts) + { + if (cohorts.stream().anyMatch(g -> !g.getIdElement().hasBaseUrl())) + { + throw new RuntimeException("Not all cohorts have fully qualified ids (containing server base url)"); + } + } + private void checkNumberOfCohortDefinitions(List cohorts) { int size = cohorts.size(); if (size < MIN_COHORT_DEFINITIONS) { - throw new IllegalStateException( + throw new RuntimeException( "Number of defined cohorts is < " + MIN_COHORT_DEFINITIONS + ", got " + cohorts.size()); } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckMultiMedicResults.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckMultiMedicResults.java index e15c0e97b..44c2c8f7e 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckMultiMedicResults.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckMultiMedicResults.java @@ -1,13 +1,21 @@ package org.highmed.dsf.bpe.service; +import java.util.List; +import java.util.stream.Collectors; + import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.task.TaskHelper; -import org.highmed.dsf.fhir.variables.Outputs; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResult; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResults; +import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.ParameterComponent; +import org.hl7.fhir.r4.model.Task.TaskOutputComponent; +import org.hl7.fhir.r4.model.UnsignedIntType; public class CheckMultiMedicResults extends AbstractServiceDelegate { @@ -17,27 +25,77 @@ public CheckMultiMedicResults(FhirWebserviceClientProvider clientProvider, TaskH } @Override - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { Task task = (Task) execution.getVariable(Constants.VARIABLE_TASK); - Outputs outputs = (Outputs) execution.getVariable(Constants.VARIABLE_PROCESS_OUTPUTS); + // Outputs outputs = (Outputs) execution.getVariable(Constants.VARIABLE_PROCESS_OUTPUTS); + + FinalFeasibilityQueryResults results = readFinalFeasibilityQueryResults(task); + results = checkResults(results); + + Task leadingTask = (Task) execution.getVariable(Constants.VARIABLE_LEADING_TASK); + addOutputs(leadingTask, results); + } + + private FinalFeasibilityQueryResults readFinalFeasibilityQueryResults(Task task) + { + List results = task.getInput().stream() + .filter(in -> in.hasType() && in.getType().hasCoding() + && Constants.CODESYSTEM_HIGHMED_FEASIBILITY.equals(in.getType().getCodingFirstRep().getSystem()) + && Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_MULTI_MEDIC_RESULT + .equals(in.getType().getCodingFirstRep().getCode())) + .map(in -> toResult(task, in)).collect(Collectors.toList()); + return new FinalFeasibilityQueryResults(results); + } + + private FinalFeasibilityQueryResult toResult(Task task, ParameterComponent in) + { + String cohortId = ((Reference) in.getExtensionByUrl(Constants.EXTENSION_GROUP_ID_URI).getValue()) + .getReference(); + int participatingMedics = getParticipatingMedicsCountByCohortId(task, cohortId); + int cohortSize = ((UnsignedIntType) in.getValue()).getValue(); + return new FinalFeasibilityQueryResult(cohortId, participatingMedics, cohortSize); + } - // TODO implement check for results with filter - // - check resulting cohort sizes is not an exact number - // - check participating medics is > 3 - // - other criterias tbd + private int getParticipatingMedicsCountByCohortId(Task task, String cohortId) + { + return task.getInput().stream().filter(in -> in.hasType() && in.getType().hasCoding() + && Constants.CODESYSTEM_HIGHMED_FEASIBILITY.equals(in.getType().getCodingFirstRep().getSystem()) + && Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_PARTICIPATING_MEDICS_COUNT + .equals(in.getType().getCodingFirstRep().getCode()) + && cohortId.equals( + ((Reference) in.getExtensionByUrl(Constants.EXTENSION_GROUP_ID_URI).getValue()).getReference())) + .mapToInt(in -> ((UnsignedIntType) in.getValue()).getValue()).findFirst().getAsInt(); + } + + protected FinalFeasibilityQueryResults checkResults(FinalFeasibilityQueryResults results) + { + // TODO implement check for results + // - criterias tbd + return results; + } + + private void addOutputs(Task leadingTask, FinalFeasibilityQueryResults results) + { + results.getResults().forEach(result -> addOutput(leadingTask, result)); + } + + private void addOutput(Task leadingTask, FinalFeasibilityQueryResult result) + { + TaskOutputComponent output1 = getTaskHelper().createOutputUnsignedInt(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_MULTI_MEDIC_RESULT, result.getCohortSize()); + output1.addExtension(createCohortIdExtension(result.getCohortId())); + leadingTask.addOutput(output1); - transformAndAddToTaskOutput(outputs, task, Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_MULTI_MEDIC_RESULT); - transformAndAddToTaskOutput(outputs, task, - Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_PARTICIPATING_MEDICS_COUNT); + TaskOutputComponent output2 = getTaskHelper().createOutputUnsignedInt(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_PARTICIPATING_MEDICS_COUNT, + result.getParticipatingMedics()); + output2.addExtension(createCohortIdExtension(result.getCohortId())); + leadingTask.addOutput(output2); } - private void transformAndAddToTaskOutput(Outputs outputs, Task task, String code) + private Extension createCohortIdExtension(String cohortId) { - getTaskHelper().getInputParameterWithExtension(task, Constants.CODESYSTEM_HIGHMED_FEASIBILITY, code, - Constants.EXTENSION_GROUP_ID_URI).forEach(result -> outputs - .add(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, code, result.getValue().primitiveValue(), - Constants.EXTENSION_GROUP_ID_URI, - ((Reference) result.getExtension().get(0).getValue()).getReference())); + return new Extension(Constants.EXTENSION_GROUP_ID_URI, new Reference(cohortId)); } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckQueries.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckQueries.java index 6b8fd1fda..3816011c7 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckQueries.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckQueries.java @@ -42,7 +42,7 @@ public void afterPropertiesSet() throws Exception } @Override - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { Outputs outputs = (Outputs) execution.getVariable(Constants.VARIABLE_PROCESS_OUTPUTS); List cohorts = ((FhirResourcesList) execution.getVariable(Constants.VARIABLE_COHORTS)) @@ -50,17 +50,17 @@ public void doExecute(DelegateExecution execution) throws Exception Map queries = new HashMap<>(); - cohorts.forEach(group -> - { + cohorts.forEach(group -> { String aqlQuery = groupHelper.extractAqlQuery(group).toLowerCase(); String groupId = group.getId(); if (!aqlQuery.startsWith(SIMPLE_FEASIBILITY_QUERY_PREFIX)) { - String errorMessage = "Initial single medic feasibility query check failed, wrong format for query of group with id '" - + groupId + "', expected query to start with '" + SIMPLE_FEASIBILITY_QUERY_PREFIX - + "' but got '" + aqlQuery + "'"; + String errorMessage = + "Initial single medic feasibility query check failed, wrong format for query of group with id '" + + groupId + "', expected query to start with '" + SIMPLE_FEASIBILITY_QUERY_PREFIX + + "' but got '" + aqlQuery + "'"; logger.info(errorMessage); outputs.addErrorOutput(errorMessage); diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckSingleMedicResults.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckSingleMedicResults.java index 5632c4958..51dcfaa4e 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckSingleMedicResults.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/CheckSingleMedicResults.java @@ -1,8 +1,8 @@ package org.highmed.dsf.bpe.service; +import java.util.ArrayList; import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Stream; +import java.util.Optional; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.Constants; @@ -11,8 +11,8 @@ import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.fhir.variables.FeasibilityQueryResult; import org.highmed.dsf.fhir.variables.FeasibilityQueryResults; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResultsValues; import org.highmed.dsf.fhir.variables.Outputs; -import org.highmed.dsf.fhir.variables.OutputsValues; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,63 +26,48 @@ public CheckSingleMedicResults(FhirWebserviceClientProvider clientProvider, Task } @Override - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { Outputs outputs = (Outputs) execution.getVariable(Constants.VARIABLE_PROCESS_OUTPUTS); - List results = ((FeasibilityQueryResults) execution - .getVariable(Constants.VARIABLE_QUERY_RESULTS)).getResults(); + FeasibilityQueryResults results = (FeasibilityQueryResults) execution + .getVariable(Constants.VARIABLE_QUERY_RESULTS); - Stream positiveResults = checkQueryResults(results, getFilter()); - Stream negativeResults = checkQueryResults(results, getNegativeFilter()); + List filteredResults = filterErronesResultsAndAddErrorsToOutput(results, outputs); - addSuccessfulResultsToOutputs(positiveResults, outputs); - addErroneousResultsToOutputs(negativeResults, outputs); - - execution.setVariable(Constants.VARIABLE_PROCESS_OUTPUTS, OutputsValues.create(outputs)); + execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, + FeasibilityQueryResultsValues.create(new FeasibilityQueryResults(filteredResults))); } - private Stream checkQueryResults(List queryResults, - Predicate filter) + private List filterErronesResultsAndAddErrorsToOutput(FeasibilityQueryResults results, + Outputs outputs) { - return queryResults.stream().filter(filter); + List filteredResults = new ArrayList<>(); + for (FeasibilityQueryResult result : results.getResults()) + { + Optional errorReason = testResultAndReturnErrorReason(result); + if (errorReason.isPresent()) + addError(outputs, result.getCohortId(), errorReason.get()); + else + filteredResults.add(result); + } + + return filteredResults; } - private Predicate getFilter() + protected Optional testResultAndReturnErrorReason(FeasibilityQueryResult result) { // TODO: implement check - // cohort size > 0 - // other filter criteria tbd - - return result -> true; - } - - private Predicate getNegativeFilter() - { - // TODO: implement check, should match the opposite criteria of getFilter() - - return result -> false; + // cohort size > 0 + // other filter criteria tbd + return Optional.empty(); } - private void addErroneousResultsToOutputs(Stream erroneousResults, Outputs outputs) + private void addError(Outputs outputs, String cohortId, String error) { - erroneousResults.forEach(result -> { - String errorMessage = - "Final single medic feasibility query result check failed for group with id '" + result - .getCohortId() + "', reason unknown"; - - logger.info(errorMessage); - outputs.addErrorOutput(errorMessage); - }); + String errorMessage = "Feasibility query result check failed for group with id '" + cohortId + "': " + error; - } - - private void addSuccessfulResultsToOutputs(Stream successfulResults, Outputs outputs) - { - successfulResults.forEach(result -> { - outputs.add(Constants.CODESYSTEM_HIGHMED_FEASIBILITY, - Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_SINGLE_MEDIC_RESULT, - String.valueOf(result.getCohortSize()), Constants.EXTENSION_GROUP_ID_URI, result.getCohortId()); - }); + logger.info(errorMessage); + outputs.addErrorOutput(errorMessage); } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadFeasibilityResources.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadFeasibilityResources.java index e8044c1ce..8a4f1f94a 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadFeasibilityResources.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadFeasibilityResources.java @@ -1,22 +1,24 @@ package org.highmed.dsf.bpe.service; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; -import javax.ws.rs.WebApplicationException; - import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; +import org.highmed.dsf.fhir.variables.BloomFilterConfig; +import org.highmed.dsf.fhir.variables.BloomFilterConfigValues; +import org.highmed.dsf.fhir.variables.FhirResourceValues; import org.highmed.dsf.fhir.variables.FhirResourcesListValues; -import org.highmed.dsf.fhir.variables.Outputs; -import org.highmed.dsf.fhir.variables.OutputsValues; import org.highmed.fhir.client.FhirWebserviceClient; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.Group; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Reference; @@ -26,8 +28,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; -import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; - public class DownloadFeasibilityResources extends AbstractServiceDelegate implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(DownloadFeasibilityResources.class); @@ -49,26 +49,35 @@ public void afterPropertiesSet() throws Exception } @Override - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { Task task = (Task) execution.getVariable(Constants.VARIABLE_TASK); IdType researchStudyId = getResearchStudyId(task); FhirWebserviceClient client = getWebserviceClient(researchStudyId); - ResearchStudy researchStudy = getResearchStudy(researchStudyId, client); - execution.setVariable(Constants.VARIABLE_RESEARCH_STUDY, researchStudy); + Bundle bundle = getResearchStudyAndCohortDefinitions(researchStudyId, client); - Outputs outputs = (Outputs) execution.getVariable(Constants.VARIABLE_PROCESS_OUTPUTS); + ResearchStudy researchStudy = (ResearchStudy) bundle.getEntryFirstRep().getResource(); + execution.setVariable(Constants.VARIABLE_RESEARCH_STUDY, FhirResourceValues.create(researchStudy)); - List cohortDefinitions = getCohortDefinitions(researchStudy, outputs, client); + List cohortDefinitions = getCohortDefinitions(bundle, client.getBaseUrl()); execution.setVariable(Constants.VARIABLE_COHORTS, FhirResourcesListValues.create(cohortDefinitions)); - execution.setVariable(Constants.VARIABLE_PROCESS_OUTPUTS, OutputsValues.create(outputs)); + + String ttpIdentifier = getTtpIdentifier(researchStudy, client); + execution.setVariable(Constants.VARIABLE_TTP_IDENTIFIER, ttpIdentifier); boolean needsConsentCheck = getNeedsConsentCheck(task); execution.setVariable(Constants.VARIABLE_NEEDS_CONSENT_CHECK, needsConsentCheck); boolean needsRecordLinkage = getNeedsRecordLinkageCheck(task); execution.setVariable(Constants.VARIABLE_NEEDS_RECORD_LINKAGE, needsRecordLinkage); + + if (needsRecordLinkage) + { + BloomFilterConfig bloomFilterConfig = getBloomFilterConfig(task); + execution.setVariable(Constants.VARIABLE_BLOOM_FILTER_CONFIG, + BloomFilterConfigValues.create(bloomFilterConfig)); + } } private IdType getResearchStudyId(Task task) @@ -76,7 +85,7 @@ private IdType getResearchStudyId(Task task) Reference researchStudyReference = getTaskHelper() .getInputParameterReferenceValues(task, Constants.CODESYSTEM_HIGHMED_FEASIBILITY, Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_RESEARCH_STUDY_REFERENCE) - .collect(Collectors.toList()).get(0); + .findFirst().get(); return new IdType(researchStudyReference.getReference()); } @@ -94,47 +103,57 @@ private FhirWebserviceClient getWebserviceClient(IdType researchStudyId) } } - private ResearchStudy getResearchStudy(IdType researchStudyid, FhirWebserviceClient client) + private Bundle getResearchStudyAndCohortDefinitions(IdType researchStudyId, FhirWebserviceClient client) { try { - return client.read(ResearchStudy.class, researchStudyid.getIdPart()); + Bundle bundle = client.searchWithStrictHandling(ResearchStudy.class, + Map.of("_id", Collections.singletonList(researchStudyId.getIdPart()), "_include", + Collections.singletonList("ResearchStudy:enrollment"))); + + if (bundle.getEntry().size() < 2) + { + throw new RuntimeException("Returned search-set contained less then two entries"); + } + else if (!bundle.getEntryFirstRep().hasResource() + || !(bundle.getEntryFirstRep().getResource() instanceof ResearchStudy)) + { + throw new RuntimeException("Returned search-set did not contain ResearchStudy at index == 0"); + } + else if (bundle.getEntry().stream().skip(1).map(c -> c.hasResource() && c.getResource() instanceof Group) + .filter(b -> !b).findAny().isPresent()) + { + throw new RuntimeException("Returned search-set contained unexpected resource at index >= 1"); + } + + return bundle; } - catch (WebApplicationException e) + catch (Exception e) { - throw new ResourceNotFoundException("Error while reading ResearchStudy with id " - + researchStudyid.getIdPart() + " from " + client.getBaseUrl()); + logger.warn("Error while reading ResearchStudy with id {} including Groups from {}: {}", + researchStudyId.getIdPart(), client.getBaseUrl(), e.getMessage()); + throw e; } } - private List getCohortDefinitions(ResearchStudy researchStudy, Outputs outputs, FhirWebserviceClient client) + private List getCohortDefinitions(Bundle bundle, String baseUrl) { - List cohortDefinitions = new ArrayList<>(); - List cohortDefinitionReferences = researchStudy.getEnrollment(); - - cohortDefinitionReferences.forEach(reference -> + return bundle.getEntry().stream().skip(1).map(e -> { - try - { - IdType type = new IdType(reference.getReference()); - Group group = client.read(Group.class, type.getIdPart()); - - IdType groupId = new IdType(group.getId()); - group.setId(client.getBaseUrl() + groupId.getResourceType() + "/" + groupId.getIdPart()); - - cohortDefinitions.add(group); - } - catch (WebApplicationException e) - { - String errorMessage = "Error while reading cohort definition with id " + reference.getReference() - + " from " + client.getBaseUrl(); - - logger.info(errorMessage); - outputs.addErrorOutput(errorMessage); - } - }); + Group group = (Group) e.getResource(); + IdType oldId = group.getIdElement(); + group.setIdElement( + new IdType(baseUrl, oldId.getResourceType(), oldId.getIdPart(), oldId.getVersionIdPart())); + return group; + }).collect(Collectors.toList()); + } - return cohortDefinitions; + private String getTtpIdentifier(ResearchStudy researchStudy, FhirWebserviceClient client) + { + Extension ext = researchStudy + .getExtensionByUrl("http://highmed.org/fhir/StructureDefinition/participating-ttp"); + Reference ref = (Reference) ext.getValue(); + return ref.getIdentifier().getValue(); } private boolean getNeedsConsentCheck(Task task) @@ -155,4 +174,13 @@ private boolean getNeedsRecordLinkageCheck(Task task) () -> new IllegalArgumentException("NeedsRecordLinkage boolean is not set in task with id='" + task.getId() + "', this error should " + "have been caught by resource validation")); } + + private BloomFilterConfig getBloomFilterConfig(Task task) + { + return BloomFilterConfig.fromBytes(getTaskHelper() + .getFirstInputParameterByteValue(task, Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_BLOOM_FILTER_CONFIG) + .orElseThrow(() -> new IllegalArgumentException("BloomFilterConfig byte[] is not set in task with id='" + + task.getId() + "', this error should " + "have been caught by resource validation"))); + } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadResearchStudyResource.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadResearchStudyResource.java index 7217585e6..cd182f022 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadResearchStudyResource.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadResearchStudyResource.java @@ -1,43 +1,55 @@ package org.highmed.dsf.bpe.service; -import javax.ws.rs.WebApplicationException; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; +import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.fhir.client.FhirWebserviceClient; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.ResearchStudy; import org.hl7.fhir.r4.model.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; -import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; - public class DownloadResearchStudyResource extends AbstractServiceDelegate implements InitializingBean { - public DownloadResearchStudyResource(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper) + private static final Logger logger = LoggerFactory.getLogger(DownloadResearchStudyResource.class); + + private final OrganizationProvider organizationProvider; + + public DownloadResearchStudyResource(OrganizationProvider organizationProvider, + FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper) { super(clientProvider, taskHelper); + + this.organizationProvider = organizationProvider; } @Override public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); + + Objects.requireNonNull(organizationProvider, "organizationProvider"); } @Override - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { Task task = (Task) execution.getVariable(Constants.VARIABLE_TASK); IdType researchStudyId = getResearchStudyId(task); FhirWebserviceClient client = getFhirWebserviceClientProvider().getLocalWebserviceClient(); ResearchStudy researchStudy = getResearchStudy(researchStudyId, client); - + researchStudy = addMissingOrganizations(researchStudy, client); execution.setVariable(Constants.VARIABLE_RESEARCH_STUDY, researchStudy); boolean needsConsentCheck = getNeedsConsentCheck(task); @@ -45,12 +57,6 @@ public void doExecute(DelegateExecution execution) throws Exception boolean needsRecordLinkage = getNeedsRecordLinkageCheck(task); execution.setVariable(Constants.VARIABLE_NEEDS_RECORD_LINKAGE, needsRecordLinkage); - - // TODO: remove when implemented - if (needsConsentCheck || needsRecordLinkage) - { - throw new UnsupportedOperationException("Consent Check and Record Linkage not yet supported."); - } } private IdType getResearchStudyId(Task task) @@ -71,10 +77,50 @@ private ResearchStudy getResearchStudy(IdType researchStudyid, FhirWebserviceCli { return client.read(ResearchStudy.class, researchStudyid.getIdPart()); } - catch (WebApplicationException e) + catch (Exception e) + { + logger.warn("Error while reading ResearchStudy with id {} from {}", researchStudyid.getIdPart(), + client.getBaseUrl()); + throw e; + } + } + + private ResearchStudy addMissingOrganizations(ResearchStudy researchStudy, FhirWebserviceClient client) + { + List identifiers = organizationProvider.getOrganizationsByType("MeDIC") + .flatMap(o -> o.getIdentifier().stream()) + .filter(i -> "http://highmed.org/fhir/NamingSystem/organization-identifier".equals(i.getSystem())) + .map(i -> i.getValue()).collect(Collectors.toList()); + + List existingIdentifiers = researchStudy.getExtensionsByUrl(Constants.EXTENSION_PARTICIPATING_MEDIC_URI) + .stream().filter(e -> e.getValue() instanceof Reference).map(e -> (Reference) e.getValue()) + .map(r -> r.getIdentifier().getValue()).collect(Collectors.toList()); + + identifiers.removeAll(existingIdentifiers); + + if (!identifiers.isEmpty()) + { + identifiers.forEach(identifier -> researchStudy.addExtension(Constants.EXTENSION_PARTICIPATING_MEDIC_URI, + new Reference().getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue(identifier))); + + return update(researchStudy, client); + } + else + return researchStudy; + } + + private ResearchStudy update(ResearchStudy researchStudy, FhirWebserviceClient client) + { + try + { + return client.update(researchStudy); + } + catch (Exception e) { - throw new ResourceNotFoundException("Error while reading ResearchStudy with id " - + researchStudyid.getIdPart() + " from " + client.getBaseUrl()); + logger.warn("Error while updating ResearchStudy resoruce: " + e.getMessage(), e); + throw e; } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadResultSets.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadResultSets.java new file mode 100644 index 000000000..5a698117f --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/DownloadResultSets.java @@ -0,0 +1,103 @@ +package org.highmed.dsf.bpe.service; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.ws.rs.core.MediaType; + +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.highmed.dsf.bpe.Constants; +import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; +import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; +import org.highmed.dsf.fhir.task.TaskHelper; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResult; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResults; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResultsValues; +import org.highmed.fhir.client.FhirWebserviceClient; +import org.highmed.openehr.model.structure.ResultSet; +import org.hl7.fhir.r4.model.IdType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class DownloadResultSets extends AbstractServiceDelegate +{ + private static final Logger logger = LoggerFactory.getLogger(DownloadResultSets.class); + + private final ObjectMapper openEhrObjectMapper; + + public DownloadResultSets(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, + ObjectMapper openEhrObjectMapper) + { + super(clientProvider, taskHelper); + + this.openEhrObjectMapper = openEhrObjectMapper; + } + + @Override + public void afterPropertiesSet() throws Exception + { + super.afterPropertiesSet(); + + Objects.requireNonNull(openEhrObjectMapper, "openEhrObjectMapper"); + } + + @Override + protected void doExecute(DelegateExecution execution) throws Exception + { + FeasibilityQueryResults results = (FeasibilityQueryResults) execution + .getVariable(Constants.VARIABLE_QUERY_RESULTS); + + List resultsWithResultSets = download(results); + + execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, + FeasibilityQueryResultsValues.create(new FeasibilityQueryResults(resultsWithResultSets))); + } + + private List download(FeasibilityQueryResults results) + { + return results.getResults().stream().map(r -> download(r)).collect(Collectors.toList()); + } + + private FeasibilityQueryResult download(FeasibilityQueryResult result) + { + IdType id = new IdType(result.getResultSetUrl()); + FhirWebserviceClient client = getFhirWebserviceClientProvider().getRemoteWebserviceClient(id.getBaseUrl()); + + InputStream binary = readBinaryResource(client, id.getIdPart()); + ResultSet resultSet = deserializeResultSet(binary); + + return FeasibilityQueryResult.idResult(result.getOrganizationIdentifier(), result.getCohortId(), resultSet); + } + + private InputStream readBinaryResource(FhirWebserviceClient client, String id) + { + try + { + logger.info("Reading binary from {} with id {}", client.getBaseUrl(), id); + return client.readBinary(id, MediaType.valueOf(Constants.OPENEHR_MIMETYPE_JSON)); + } + catch (Exception e) + { + logger.warn("Error while reading Binary resoruce: " + e.getMessage(), e); + throw e; + } + } + + private ResultSet deserializeResultSet(InputStream content) + { + try (content) + { + return openEhrObjectMapper.readValue(content, ResultSet.class); + } + catch (IOException e) + { + logger.warn("Error while deserializing ResultSet: " + e.getMessage(), e); + throw new RuntimeException(e); + } + } +} diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ExecuteEpiLink.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ExecuteEpiLink.java deleted file mode 100644 index 77778a046..000000000 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ExecuteEpiLink.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.highmed.dsf.bpe.service; - -import org.camunda.bpm.engine.delegate.DelegateExecution; -import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; -import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; -import org.highmed.dsf.fhir.task.TaskHelper; - -public class ExecuteEpiLink extends AbstractServiceDelegate -{ - public ExecuteEpiLink(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper) - { - super(clientProvider, taskHelper); - } - - @Override - protected void doExecute(DelegateExecution execution) throws Exception - { - // TODO: implement - } -} diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ExecuteQueries.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ExecuteQueries.java index fce9046cd..1354255c2 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ExecuteQueries.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ExecuteQueries.java @@ -1,63 +1,94 @@ package org.highmed.dsf.bpe.service; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; +import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.fhir.variables.FeasibilityQueryResult; import org.highmed.dsf.fhir.variables.FeasibilityQueryResults; -import org.highmed.openehr.client.OpenehrWebserviceClient; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResultsValues; +import org.highmed.openehr.client.OpenEhrWebserviceClient; +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; import org.springframework.beans.factory.InitializingBean; public class ExecuteQueries extends AbstractServiceDelegate implements InitializingBean { - private final OpenehrWebserviceClient openehrWebserviceClient; + private final OpenEhrWebserviceClient openehrWebserviceClient; + private final OrganizationProvider organizationProvider; - public ExecuteQueries(FhirWebserviceClientProvider clientProvider, OpenehrWebserviceClient openehrWebserviceClient, - TaskHelper taskHelper) + public ExecuteQueries(FhirWebserviceClientProvider clientProvider, OpenEhrWebserviceClient openehrWebserviceClient, + TaskHelper taskHelper, OrganizationProvider organizationProvider) { super(clientProvider, taskHelper); + this.openehrWebserviceClient = openehrWebserviceClient; + this.organizationProvider = organizationProvider; } @Override public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); + Objects.requireNonNull(openehrWebserviceClient, "openehrWebserviceClient"); + Objects.requireNonNull(organizationProvider, "organizationProvider"); } @Override - @SuppressWarnings("unchecked") - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { // + @SuppressWarnings("unchecked") Map queries = (Map) execution.getVariable(Constants.VARIABLE_QUERIES); - List results = queries.entrySet().stream().map(entry -> { - int result = executeQuery(entry.getValue()); - return new FeasibilityQueryResult(null, entry.getKey(), result); - }).collect(Collectors.toList()); + Boolean needsConsentCheck = (Boolean) execution.getVariable(Constants.VARIABLE_NEEDS_CONSENT_CHECK); + Boolean needsRecordLinkage = (Boolean) execution.getVariable(Constants.VARIABLE_NEEDS_RECORD_LINKAGE); + boolean idQuery = Boolean.TRUE.equals(needsConsentCheck) || Boolean.TRUE.equals(needsRecordLinkage); + + List results = queries.entrySet().stream() + .map(entry -> executeQuery(entry.getKey(), entry.getValue(), idQuery)).collect(Collectors.toList()); - execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, new FeasibilityQueryResults(results)); + execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, + FeasibilityQueryResultsValues.create(new FeasibilityQueryResults(results))); } - private int executeQuery(String query) + private FeasibilityQueryResult executeQuery(String cohortId, String cohortQuery, boolean idQuery) { // TODO We might want to introduce a more complex result type to represent a count, - // errors and possible meta-data. + // errors and possible meta-data. - // ResultSet result = openehrWebserviceClient.query(query, null); - // int count = ((DvCount) result.getRow(0).get(0)).getValue(); + // ResultSet result = openehrWebserviceClient.query(query, null); + // int count = ((DvCount) result.getRow(0).get(0)).getValue(); // TODO: remove dummy result - return 15; - } + if (idQuery) + { + List> rows = IntStream.range(0, 15) + .mapToObj(id -> Collections. singletonList(new StringRowElement(String.valueOf(id)))) + .collect(Collectors.toList()); + ResultSet resultSet = new ResultSet(null, null, cohortQuery, + Collections.singleton(new Column("EHRID", "/ehr_id/value")), rows); + + // returns ResultSet with EHRIDs 0, 1, ..., 14 + return FeasibilityQueryResult.idResult(organizationProvider.getLocalIdentifierValue(), cohortId, resultSet); + } + else + { + // returns 15 + return FeasibilityQueryResult.countResult(organizationProvider.getLocalIdentifierValue(), cohortId, 15); + } + } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ExecuteRecordLink.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ExecuteRecordLink.java new file mode 100644 index 000000000..d5aea4513 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ExecuteRecordLink.java @@ -0,0 +1,98 @@ +package org.highmed.dsf.bpe.service; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.highmed.dsf.bpe.Constants; +import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; +import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; +import org.highmed.dsf.fhir.task.TaskHelper; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResult; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResults; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResult; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResults; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResultsValues; +import org.highmed.pseudonymization.domain.PersonWithMdat; +import org.highmed.pseudonymization.domain.impl.MatchedPersonImpl; +import org.highmed.pseudonymization.recordlinkage.FederatedMatcherImpl; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.translation.ResultSetTranslatorFromMedicRbfOnly; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExecuteRecordLink extends AbstractServiceDelegate +{ + private static final Logger logger = LoggerFactory.getLogger(ExecuteRecordLink.class); + + private final ResultSetTranslatorFromMedicRbfOnly translator; + + public ExecuteRecordLink(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, + ResultSetTranslatorFromMedicRbfOnly translator) + { + super(clientProvider, taskHelper); + + this.translator = translator; + } + + @Override + public void afterPropertiesSet() throws Exception + { + super.afterPropertiesSet(); + + Objects.requireNonNull(translator, "translator"); + } + + @Override + protected void doExecute(DelegateExecution execution) throws Exception + { + FeasibilityQueryResults results = (FeasibilityQueryResults) execution + .getVariable(Constants.VARIABLE_QUERY_RESULTS); + + Map> byCohortId = results.getResults().stream() + .collect(Collectors.groupingBy(FeasibilityQueryResult::getCohortId)); + + FederatedMatcherImpl matcher = createMatcher(); + + List matchedResults = byCohortId.entrySet().stream() + .map(e -> match(matcher, e.getKey(), e.getValue())).collect(Collectors.toList()); + + execution.setVariable(Constants.VARIABLE_FINAL_QUERY_RESULTS, + FinalFeasibilityQueryResultsValues.create(new FinalFeasibilityQueryResults(matchedResults))); + } + + private FinalFeasibilityQueryResult match(FederatedMatcherImpl matcher, String cohortId, + List results) + { + logger.debug("Matching results for cohort {}", cohortId); + + List> persons = results.stream().map(this::translate).collect(Collectors.toList()); + + Set> matchedPersons = matcher.matchPersons(persons); + + return new FinalFeasibilityQueryResult(cohortId, + toInt(persons.stream().mapToInt(r -> r.size()).filter(cohortSize -> cohortSize > 0).count()), + toInt(matchedPersons.size())); + } + + private List translate(FeasibilityQueryResult result) + { + return translator.translate(result.getOrganizationIdentifier(), result.getResultSet()); + } + + protected FederatedMatcherImpl createMatcher() + { + return new FederatedMatcherImpl<>(MatchedPersonImpl::new); + } + + private int toInt(long l) + { + if (l > Integer.MAX_VALUE) + throw new IllegalArgumentException("long > " + Integer.MAX_VALUE); + else + return (int) l; + } +} diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/FilterQueryResultsByConsent.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/FilterQueryResultsByConsent.java index 09f7c1d9e..56e92380e 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/FilterQueryResultsByConsent.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/FilterQueryResultsByConsent.java @@ -1,9 +1,17 @@ package org.highmed.dsf.bpe.service; +import java.util.List; +import java.util.stream.Collectors; + import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.task.TaskHelper; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResult; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResults; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResultsValues; +import org.highmed.openehr.model.structure.ResultSet; public class FilterQueryResultsByConsent extends AbstractServiceDelegate { @@ -15,6 +23,30 @@ public FilterQueryResultsByConsent(FhirWebserviceClientProvider clientProvider, @Override protected void doExecute(DelegateExecution execution) throws Exception { - // TODO: implement + FeasibilityQueryResults results = (FeasibilityQueryResults) execution + .getVariable(Constants.VARIABLE_QUERY_RESULTS); + + List filteredResults = filterResults(results.getResults()); + + execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, + FeasibilityQueryResultsValues.create(new FeasibilityQueryResults(filteredResults))); + } + + private List filterResults(List results) + { + return results.stream().map(this::filterResult).collect(Collectors.toList()); + } + + protected FeasibilityQueryResult filterResult(FeasibilityQueryResult result) + { + return FeasibilityQueryResult.idResult(result.getOrganizationIdentifier(), result.getCohortId(), + filterResultSet(result.getResultSet())); + } + + private ResultSet filterResultSet(ResultSet resultSet) + { + // TODO implement + + return resultSet; } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/GenerateBloomFilters.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/GenerateBloomFilters.java index acaa8b233..4a9f4e4b2 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/GenerateBloomFilters.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/GenerateBloomFilters.java @@ -1,20 +1,171 @@ package org.highmed.dsf.bpe.service; +import java.security.Key; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.task.TaskHelper; +import org.highmed.dsf.fhir.variables.BloomFilterConfig; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResult; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResults; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResultsValues; +import org.highmed.mpi.client.MasterPatientIndexClient; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.pseudonymization.bloomfilter.BloomFilterGenerator; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGenerator; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGeneratorImpl; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGeneratorImpl.FieldBloomFilterLengths; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGeneratorImpl.FieldWeights; +import org.highmed.pseudonymization.translation.ResultSetTranslatorToTtpRbfOnly; +import org.highmed.pseudonymization.translation.ResultSetTranslatorToTtpRbfOnlyImpl; +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import ca.uhn.fhir.context.FhirContext; public class GenerateBloomFilters extends AbstractServiceDelegate { - public GenerateBloomFilters(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper) + private static final Logger logger = LoggerFactory.getLogger(GenerateBloomFilters.class); + + private static final int RBF_LENGTH = 3000; + private static final FieldWeights FBF_WEIGHTS = new FieldWeights(0.1, 0.1, 0.1, 0.2, 0.05, 0.1, 0.05, 0.2, 0.1); + private static final FieldBloomFilterLengths FBF_LENGTHS = new FieldBloomFilterLengths(500, 500, 250, 50, 500, 250, + 500, 500, 500); + + private final MasterPatientIndexClient masterPatientIndexClient; + private final ObjectMapper openEhrObjectMapper; + private final BouncyCastleProvider bouncyCastleProvider; + + public GenerateBloomFilters(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, + MasterPatientIndexClient masterPatientIndexClient, ObjectMapper openEhrObjectMapper, + BouncyCastleProvider bouncyCastleProvider) { super(clientProvider, taskHelper); + + this.masterPatientIndexClient = masterPatientIndexClient; + this.openEhrObjectMapper = openEhrObjectMapper; + this.bouncyCastleProvider = bouncyCastleProvider; + } + + @Override + public void afterPropertiesSet() throws Exception + { + super.afterPropertiesSet(); + + Objects.requireNonNull(masterPatientIndexClient, "masterPatientIndexClient"); + Objects.requireNonNull(openEhrObjectMapper, "openEhrObjectMapper"); + Objects.requireNonNull(bouncyCastleProvider, "bouncyCastleProvider"); } @Override protected void doExecute(DelegateExecution execution) throws Exception { - // TODO: implement + FeasibilityQueryResults results = (FeasibilityQueryResults) execution + .getVariable(Constants.VARIABLE_QUERY_RESULTS); + + String ttpIdentifier = (String) execution.getVariable(Constants.VARIABLE_TTP_IDENTIFIER); + + BloomFilterConfig bloomFilterConfig = (BloomFilterConfig) execution + .getVariable(Constants.VARIABLE_BLOOM_FILTER_CONFIG); + + ResultSetTranslatorToTtpRbfOnly resultSetTranslator = createResultSetTranslator(bloomFilterConfig); + + List translatedResults = results.getResults().stream() + .map(result -> translateAndCreateBinary(resultSetTranslator, result, ttpIdentifier)) + .collect(Collectors.toList()); + + execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, + FeasibilityQueryResultsValues.create(new FeasibilityQueryResults(translatedResults))); + } + + protected ResultSetTranslatorToTtpRbfOnly createResultSetTranslator(BloomFilterConfig bloomFilterConfig) + { + return new ResultSetTranslatorToTtpRbfOnlyImpl( + createRecordBloomFilterGenerator(bloomFilterConfig.getPermutationSeed(), + bloomFilterConfig.getHmacSha2Key(), bloomFilterConfig.getHmacSha3Key()), + masterPatientIndexClient); + } + + protected RecordBloomFilterGenerator createRecordBloomFilterGenerator(long permutationSeed, Key hmacSha2Key, + Key hmacSha3Key) + { + return new RecordBloomFilterGeneratorImpl(RBF_LENGTH, permutationSeed, FBF_WEIGHTS, FBF_LENGTHS, + () -> new BloomFilterGenerator.HmacSha2HmacSha3BiGramHasher(hmacSha2Key, hmacSha3Key, + bouncyCastleProvider)); + } + + private FeasibilityQueryResult translateAndCreateBinary(ResultSetTranslatorToTtpRbfOnly resultSetTranslator, + FeasibilityQueryResult result, String ttpIdentifier) + { + ResultSet translatedResultSet = translate(resultSetTranslator, result.getResultSet()); + String resultSetUrl = saveResultSetAsBinaryForTtp(translatedResultSet, ttpIdentifier); + + return FeasibilityQueryResult.idResult(result.getOrganizationIdentifier(), result.getCohortId(), resultSetUrl); + } + + private ResultSet translate(ResultSetTranslatorToTtpRbfOnly resultSetTranslator, ResultSet resultSet) + { + try + { + return resultSetTranslator.translate(resultSet); + } + catch (Exception e) + { + logger.warn("Error while translating ResultSet: " + e.getMessage(), e); + throw e; + } + } + + protected String saveResultSetAsBinaryForTtp(ResultSet resultSet, String ttpIdentifier) + { + byte[] content = serializeResultSet(resultSet); + Reference securityContext = new Reference(); + securityContext.setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue(ttpIdentifier); + Binary binary = new Binary().setContentType(Constants.OPENEHR_MIMETYPE_JSON).setSecurityContext(securityContext) + .setData(content); + + IdType created = createBinaryResource(binary); + return new IdType(getFhirWebserviceClientProvider().getLocalBaseUrl(), "Binary", created.getIdPart(), + created.getVersionIdPart()).getValue(); + } + + private byte[] serializeResultSet(ResultSet resultSet) + { + try + { + return openEhrObjectMapper.writeValueAsBytes(resultSet); + } + catch (JsonProcessingException e) + { + logger.warn("Error while serializing ResultSet: " + e.getMessage(), e); + throw new RuntimeException(e); + } + } + + private IdType createBinaryResource(Binary binary) + { + try + { + return getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn().create(binary); + } + catch (Exception e) + { + logger.debug("Binary to create {}", FhirContext.forR4().newJsonParser().encodeResourceToString(binary)); + logger.warn("Error while creating Binary resoruce: " + e.getMessage(), e); + throw e; + } } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/GenerateCountFromIds.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/GenerateCountFromIds.java index 3cbb3c780..ca7e8b7d6 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/GenerateCountFromIds.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/GenerateCountFromIds.java @@ -1,9 +1,16 @@ package org.highmed.dsf.bpe.service; +import java.util.List; +import java.util.stream.Collectors; + import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.task.TaskHelper; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResult; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResults; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResultsValues; public class GenerateCountFromIds extends AbstractServiceDelegate { @@ -15,6 +22,23 @@ public GenerateCountFromIds(FhirWebserviceClientProvider clientProvider, TaskHel @Override protected void doExecute(DelegateExecution execution) throws Exception { - // TODO: implement + FeasibilityQueryResults results = (FeasibilityQueryResults) execution + .getVariable(Constants.VARIABLE_QUERY_RESULTS); + + List filteredResults = count(results.getResults()); + + execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, + FeasibilityQueryResultsValues.create(new FeasibilityQueryResults(filteredResults))); + } + + private List count(List results) + { + return results.stream().map(this::count).collect(Collectors.toList()); + } + + protected FeasibilityQueryResult count(FeasibilityQueryResult result) + { + return FeasibilityQueryResult.countResult(result.getOrganizationIdentifier(), result.getCohortId(), + result.getResultSet().getRows().size()); } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ModifyQueries.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ModifyQueries.java index 44b7b331d..0d56cfd42 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ModifyQueries.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/ModifyQueries.java @@ -1,6 +1,11 @@ package org.highmed.dsf.bpe.service; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.task.TaskHelper; @@ -15,6 +20,33 @@ public ModifyQueries(FhirWebserviceClientProvider clientProvider, TaskHelper tas @Override protected void doExecute(DelegateExecution execution) throws Exception { - // TODO: implement + Boolean needsConsentCheck = (Boolean) execution.getVariable(Constants.VARIABLE_NEEDS_CONSENT_CHECK); + Boolean needsRecordLinkage = (Boolean) execution.getVariable(Constants.VARIABLE_NEEDS_RECORD_LINKAGE); + boolean idQuery = Boolean.TRUE.equals(needsConsentCheck) || Boolean.TRUE.equals(needsRecordLinkage); + + if (idQuery) + { + // + @SuppressWarnings("unchecked") + Map queries = (Map) execution.getVariable(Constants.VARIABLE_QUERIES); + Map modifiedQueries = modifyQueries(queries); + execution.setVariable(Constants.VARIABLE_QUERIES, modifiedQueries); + } + } + + private Map modifyQueries(Map queries) + { + Map modifiedQueries = new HashMap<>(); + + for (Entry entry : queries.entrySet()) + modifiedQueries.put(entry.getKey(), replaceSelectCountWithSelectMpiId(entry.getValue())); + + return modifiedQueries; + } + + protected String replaceSelectCountWithSelectMpiId(String value) + { + // TODO Implement correct replacement for default id query + return value.replace("SELECT COUNT(e)", "SELECT e/ehr_id/value as EHRID"); } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectRequestTargets.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectRequestTargets.java index 9d1cd27dc..82ed1a3c7 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectRequestTargets.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectRequestTargets.java @@ -1,35 +1,56 @@ package org.highmed.dsf.bpe.service; +import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.Objects; +import java.util.Random; import java.util.UUID; import java.util.stream.Collectors; +import javax.crypto.KeyGenerator; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; +import org.highmed.dsf.fhir.variables.BloomFilterConfig; +import org.highmed.dsf.fhir.variables.BloomFilterConfigValues; import org.highmed.dsf.fhir.variables.MultiInstanceTarget; import org.highmed.dsf.fhir.variables.MultiInstanceTargetValues; import org.highmed.dsf.fhir.variables.MultiInstanceTargets; import org.highmed.dsf.fhir.variables.MultiInstanceTargetsValues; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Identifier; -import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.ResearchStudy; public class SelectRequestTargets extends AbstractServiceDelegate { + private static final Random random = new Random(); + private final OrganizationProvider organizationProvider; + private final KeyGenerator hmacSha2Generator; + private final KeyGenerator hmacSha3Generator; public SelectRequestTargets(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, - OrganizationProvider organizationProvider) + OrganizationProvider organizationProvider, BouncyCastleProvider bouncyCastleProvider) { super(clientProvider, taskHelper); + this.organizationProvider = organizationProvider; + + try + { + Objects.requireNonNull(bouncyCastleProvider, "bouncyCastleProvider"); + + hmacSha2Generator = KeyGenerator.getInstance("HmacSHA256", bouncyCastleProvider); + hmacSha3Generator = KeyGenerator.getInstance("HmacSHA3-256", bouncyCastleProvider); + } + catch (NoSuchAlgorithmException e) + { + throw new RuntimeException(e); + } } @Override @@ -40,42 +61,46 @@ public void afterPropertiesSet() throws Exception } @Override - public void doExecute(DelegateExecution execution) throws Exception - { - setMedicTargets(execution); - setTtpTarget(execution); - } - - private void setMedicTargets(DelegateExecution execution) + protected void doExecute(DelegateExecution execution) throws Exception { ResearchStudy researchStudy = (ResearchStudy) execution.getVariable(Constants.VARIABLE_RESEARCH_STUDY); - List targetReferences = researchStudy.getExtension().stream() - .filter(extension -> extension.getUrl().equals(Constants.EXTENSION_PARTICIPATING_MEDIC_URI)) - .map(extension -> ((Reference) extension.getValue()).getReference()).collect(Collectors.toList()); + execution.setVariable(Constants.VARIABLE_MULTI_INSTANCE_TARGETS, + MultiInstanceTargetsValues.create(getMedicTargets(researchStudy))); - List targets = targetReferences.stream() - .flatMap(reference -> organizationProvider.getIdentifier(new IdType(reference)).stream()) - .map(identifier -> new MultiInstanceTarget(identifier.getValue(), UUID.randomUUID().toString())) - .collect(Collectors.toList()); + execution.setVariable(Constants.VARIABLE_MULTI_INSTANCE_TARGET, + MultiInstanceTargetValues.create(getTtpTarget(researchStudy))); - execution.setVariable(Constants.VARIABLE_MULTI_INSTANCE_TARGETS, - MultiInstanceTargetsValues.create(new MultiInstanceTargets(targets))); + Boolean needsRecordLinkage = (Boolean) execution.getVariable(Constants.VARIABLE_NEEDS_RECORD_LINKAGE); + if (Boolean.TRUE.equals(needsRecordLinkage)) + { + execution.setVariable(Constants.VARIABLE_BLOOM_FILTER_CONFIG, + BloomFilterConfigValues.create(createBloomFilterConfig())); + } } - private void setTtpTarget(DelegateExecution execution) + private BloomFilterConfig createBloomFilterConfig() { - // TODO implement ttp selection strategy, if there are multiple TTPs available + return new BloomFilterConfig(random.nextLong(), hmacSha2Generator.generateKey(), + hmacSha3Generator.generateKey()); + } - Organization ttp = organizationProvider.getOrganizationsByType("TTP").findFirst().orElseThrow( - () -> new IllegalArgumentException("No organization of type TTP could be found, aborting request")); + private MultiInstanceTargets getMedicTargets(ResearchStudy researchStudy) + { + List targets = researchStudy + .getExtensionsByUrl(Constants.EXTENSION_PARTICIPATING_MEDIC_URI).stream() + .filter(e -> e.getValue() instanceof Reference).map(e -> (Reference) e.getValue()) + .map(r -> new MultiInstanceTarget(r.getIdentifier().getValue(), UUID.randomUUID().toString())) + .collect(Collectors.toList()); - Identifier ttpIdentifier = ttp.getIdentifier().stream() - .filter(identifier -> identifier.getSystem().equals(Constants.ORGANIZATION_IDENTIFIER_SYSTEM)) - .findFirst().orElseThrow(() -> new IllegalArgumentException( - "No organization identifier of type TTP could be found, aborting request")); + return new MultiInstanceTargets(targets); + } - MultiInstanceTarget ttpTarget = new MultiInstanceTarget(ttpIdentifier.getValue(), UUID.randomUUID().toString()); - execution.setVariable(Constants.VARIABLE_MULTI_INSTANCE_TARGET, MultiInstanceTargetValues.create(ttpTarget)); + private MultiInstanceTarget getTtpTarget(ResearchStudy researchStudy) + { + return researchStudy.getExtensionsByUrl(Constants.EXTENSION_PARTICIPATING_TTP_URI).stream() + .filter(e -> e.getValue() instanceof Reference).map(e -> (Reference) e.getValue()) + .map(r -> new MultiInstanceTarget(r.getIdentifier().getValue(), UUID.randomUUID().toString())) + .findFirst().get(); } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectResponseTargetMedic.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectResponseTargetMedic.java index 547c5a963..06dc58c07 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectResponseTargetMedic.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectResponseTargetMedic.java @@ -10,8 +10,6 @@ import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.fhir.variables.MultiInstanceTarget; import org.highmed.dsf.fhir.variables.MultiInstanceTargetValues; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Task; import org.springframework.beans.factory.InitializingBean; @@ -36,21 +34,18 @@ public void afterPropertiesSet() throws Exception } @Override - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { Task task = (Task) execution.getVariable(Constants.VARIABLE_LEADING_TASK); String correlationKey = getTaskHelper() .getFirstInputParameterStringValue(task, Constants.CODESYSTEM_HIGHMED_BPMN, - Constants.CODESYSTEM_HIGHMED_BPMN_VALUE_CORRELATION_KEY).orElseThrow( - () -> new IllegalStateException( - "No correlation key found, this error should have been caught by resource validation")); - - Identifier medicIdentifier = organizationProvider.getIdentifier(new IdType(task.getRequester().getReference())) + Constants.CODESYSTEM_HIGHMED_BPMN_VALUE_CORRELATION_KEY) .orElseThrow(() -> new IllegalStateException( - "Organization with id " + task.getRequester().getReference() + " not found")); + "No correlation key found, this error should have been caught by resource validation")); - MultiInstanceTarget medicTarget = new MultiInstanceTarget(medicIdentifier.getValue(), correlationKey); + MultiInstanceTarget medicTarget = new MultiInstanceTarget(task.getRequester().getIdentifier().getValue(), + correlationKey); execution.setVariable(Constants.VARIABLE_MULTI_INSTANCE_TARGET, MultiInstanceTargetValues.create(medicTarget)); } } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectResponseTargetTtp.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectResponseTargetTtp.java index 31bcf1095..68528df24 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectResponseTargetTtp.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/SelectResponseTargetTtp.java @@ -10,8 +10,6 @@ import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.fhir.variables.MultiInstanceTarget; import org.highmed.dsf.fhir.variables.MultiInstanceTargetValues; -import org.hl7.fhir.r4.model.Identifier; -import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Task; import org.springframework.beans.factory.InitializingBean; @@ -23,7 +21,6 @@ public SelectResponseTargetTtp(FhirWebserviceClientProvider clientProvider, Task OrganizationProvider organizationProvider) { super(clientProvider, taskHelper); - this.organizationProvider = organizationProvider; } @@ -31,42 +28,27 @@ public SelectResponseTargetTtp(FhirWebserviceClientProvider clientProvider, Task public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); - Objects.requireNonNull(organizationProvider, "organizationProvider"); } @Override - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { - Identifier ttpIdentifier = getTtpIdentifier(execution); + String ttpIdentifier = (String) execution.getVariable(Constants.VARIABLE_TTP_IDENTIFIER); String correlationKey = getCorrelationKey(execution); - MultiInstanceTarget ttpTarget = new MultiInstanceTarget(ttpIdentifier.getValue(), correlationKey); + MultiInstanceTarget ttpTarget = new MultiInstanceTarget(ttpIdentifier, correlationKey); execution.setVariable(Constants.VARIABLE_MULTI_INSTANCE_TARGET, MultiInstanceTargetValues.create(ttpTarget)); } - private Identifier getTtpIdentifier(DelegateExecution execution) - { - // TODO implement ttp selection strategy, if there are multiple TTPs available - // has to mach the selection strategy from the service SelectRequestTarget, - // because this sends the Query results for record linkage to the TTP - - Organization ttp = organizationProvider.getOrganizationsByType("TTP").findFirst().orElseThrow( - () -> new IllegalArgumentException("No organization of type TTP could be found, aborting request")); - - return ttp.getIdentifier().stream() - .filter(identifier -> identifier.getSystem().equals(Constants.ORGANIZATION_IDENTIFIER_SYSTEM)) - .findFirst().orElseThrow(() -> new IllegalArgumentException( - "No organization identifier of type TTP could be found, aborting request")); - } - private String getCorrelationKey(DelegateExecution execution) { Task task = (Task) execution.getVariable(Constants.VARIABLE_TASK); - return getTaskHelper().getFirstInputParameterStringValue(task, Constants.CODESYSTEM_HIGHMED_BPMN, - Constants.CODESYSTEM_HIGHMED_BPMN_VALUE_CORRELATION_KEY).orElseThrow(() -> new IllegalStateException( - "No correlation key found, this error should have been caught by resource validation")); + return getTaskHelper() + .getFirstInputParameterStringValue(task, Constants.CODESYSTEM_HIGHMED_BPMN, + Constants.CODESYSTEM_HIGHMED_BPMN_VALUE_CORRELATION_KEY) + .orElseThrow(() -> new IllegalStateException( + "No correlation key found, this error should have been caught by resource validation")); } - } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/StoreCorrelationKeys.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/StoreCorrelationKeys.java index 1ba17e01c..5263de7fb 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/StoreCorrelationKeys.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/StoreCorrelationKeys.java @@ -35,22 +35,11 @@ protected void doExecute(DelegateExecution execution) throws Exception execution.setVariable(Constants.VARIABLE_MULTI_INSTANCE_TARGETS, MultiInstanceTargetsValues.create(new MultiInstanceTargets(targets))); - boolean needsConsentCheck = getNeedsConsentCheck(task); - execution.setVariable(Constants.VARIABLE_NEEDS_CONSENT_CHECK, needsConsentCheck); - boolean needsRecordLinkage = getNeedsRecordLinkageCheck(task); execution.setVariable(Constants.VARIABLE_NEEDS_RECORD_LINKAGE, needsRecordLinkage); - execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, FeasibilityQueryResultsValues.create(new FeasibilityQueryResults(null))); - } - - private boolean getNeedsConsentCheck(Task task) - { - return getTaskHelper().getFirstInputParameterBooleanValue(task, Constants.CODESYSTEM_HIGHMED_FEASIBILITY, - Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_NEEDS_CONSENT_CHECK).orElseThrow( - () -> new IllegalArgumentException( - "NeedsConsentCheck boolean is not set in task with id='" + task.getId() - + "', this error should " + "have been caught by resource validation")); + execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, + FeasibilityQueryResultsValues.create(new FeasibilityQueryResults(null))); } private boolean getNeedsRecordLinkageCheck(Task task) @@ -61,5 +50,4 @@ private boolean getNeedsRecordLinkageCheck(Task task) "NeedsRecordLinkage boolean is not set in task with id='" + task.getId() + "', this error should " + "have been caught by resource validation")); } - } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/StoreResults.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/StoreResults.java index 1e6c1af5e..1ab36d60a 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/StoreResults.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/service/StoreResults.java @@ -1,5 +1,6 @@ package org.highmed.dsf.bpe.service; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -12,8 +13,10 @@ import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.fhir.variables.FeasibilityQueryResult; import org.highmed.dsf.fhir.variables.FeasibilityQueryResults; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResultsValues; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.UnsignedIntType; import org.springframework.beans.factory.InitializingBean; public class StoreResults extends AbstractServiceDelegate implements InitializingBean @@ -32,30 +35,60 @@ public StoreResults(FhirWebserviceClientProvider clientProvider, TaskHelper task public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); + Objects.requireNonNull(organizationProvider, "organizationProvider"); } @Override - public void doExecute(DelegateExecution execution) throws Exception + protected void doExecute(DelegateExecution execution) throws Exception { FeasibilityQueryResults results = (FeasibilityQueryResults) execution .getVariable(Constants.VARIABLE_QUERY_RESULTS); + boolean needsRecordLinkage = Boolean.TRUE + .equals((Boolean) execution.getVariable(Constants.VARIABLE_NEEDS_RECORD_LINKAGE)); + Task task = (Task) execution.getVariable(Constants.VARIABLE_TASK); - String requester = task.getRequester().getReference(); - List resultInputs = getTaskHelper() - .getInputParameterWithExtension(task, Constants.CODESYSTEM_HIGHMED_FEASIBILITY, - Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_SINGLE_MEDIC_RESULT, - Constants.EXTENSION_GROUP_ID_URI).map(input -> { - String groupId = ((Reference) input.getExtension().get(0).getValue()).getReference(); - int groupSize = Integer.parseInt(input.getValue().primitiveValue()); - return new FeasibilityQueryResult(requester, groupId, groupSize); - }).collect(Collectors.toList()); + List extendedResults = new ArrayList<>(); + extendedResults.addAll(results.getResults()); + extendedResults.addAll(getResults(task, needsRecordLinkage)); + + execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, + FeasibilityQueryResultsValues.create(new FeasibilityQueryResults(extendedResults))); + } + + private List getResults(Task task, boolean needsRecordLinkage) + { + TaskHelper taskHelper = getTaskHelper(); + Reference requester = task.getRequester(); + + if (needsRecordLinkage) + { + return taskHelper.getInputParameterWithExtension(task, Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_SINGLE_MEDIC_RESULT_REFERENCE, + Constants.EXTENSION_GROUP_ID_URI).map(input -> + { + String cohortId = ((Reference) input.getExtension().get(0).getValue()).getReference(); + String resultSetUrl = ((Reference) input.getValue()).getReference(); - results.addAll(resultInputs); + return FeasibilityQueryResult.idResult(requester.getIdentifier().getValue(), cohortId, + resultSetUrl); + }).collect(Collectors.toList()); + } + else + { + return taskHelper.getInputParameterWithExtension(task, Constants.CODESYSTEM_HIGHMED_FEASIBILITY, + Constants.CODESYSTEM_HIGHMED_FEASIBILITY_VALUE_SINGLE_MEDIC_RESULT, + Constants.EXTENSION_GROUP_ID_URI).map(input -> + { + String cohortId = ((Reference) input.getExtension().get(0).getValue()).getReference(); + int cohortSize = ((UnsignedIntType) input.getValue()).getValue(); - // race conditions are not possible, since tasks are received sequentially over the websocket connection - execution.setVariable(Constants.VARIABLE_QUERY_RESULTS, results); + return FeasibilityQueryResult.countResult(requester.getIdentifier().getValue(), cohortId, + cohortSize); + }).collect(Collectors.toList()); + } } + } diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/spring/config/FeasibilityConfig.java b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/spring/config/FeasibilityConfig.java index 4e860416c..e5c376d99 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/spring/config/FeasibilityConfig.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/java/org/highmed/dsf/bpe/spring/config/FeasibilityConfig.java @@ -1,5 +1,6 @@ package org.highmed.dsf.bpe.spring.config; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin; import org.highmed.dsf.bpe.message.SendMedicRequest; import org.highmed.dsf.bpe.message.SendMultiMedicResults; @@ -13,8 +14,9 @@ import org.highmed.dsf.bpe.service.CheckSingleMedicResults; import org.highmed.dsf.bpe.service.DownloadFeasibilityResources; import org.highmed.dsf.bpe.service.DownloadResearchStudyResource; -import org.highmed.dsf.bpe.service.ExecuteEpiLink; +import org.highmed.dsf.bpe.service.DownloadResultSets; import org.highmed.dsf.bpe.service.ExecuteQueries; +import org.highmed.dsf.bpe.service.ExecuteRecordLink; import org.highmed.dsf.bpe.service.FilterQueryResultsByConsent; import org.highmed.dsf.bpe.service.GenerateBloomFilters; import org.highmed.dsf.bpe.service.GenerateCountFromIds; @@ -29,9 +31,16 @@ import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.openehr.client.OpenEhrWebserviceClientProvider; +import org.highmed.mpi.client.MasterPatientIndexClient; +import org.highmed.mpi.client.MasterPatientIndexClientFactory; +import org.highmed.pseudonymization.translation.ResultSetTranslatorFromMedicRbfOnly; +import org.highmed.pseudonymization.translation.ResultSetTranslatorFromMedicRbfOnlyImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +import com.fasterxml.jackson.databind.ObjectMapper; import ca.uhn.fhir.context.FhirContext; @@ -44,6 +53,9 @@ public class FeasibilityConfig @Autowired private OpenEhrWebserviceClientProvider openehrClientProvider; + @Autowired + private MasterPatientIndexClientFactory masterPatientIndexClientFactory; + @Autowired private OrganizationProvider organizationProvider; @@ -56,6 +68,12 @@ public class FeasibilityConfig @Autowired private FhirContext fhirContext; + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private Environment environment; + @Bean public ProcessEnginePlugin feasibilityPlugin() { @@ -69,13 +87,13 @@ public ProcessEnginePlugin feasibilityPlugin() @Bean public DownloadResearchStudyResource downloadResearchStudyResource() { - return new DownloadResearchStudyResource(fhirClientProvider, taskHelper); + return new DownloadResearchStudyResource(organizationProvider, fhirClientProvider, taskHelper); } @Bean public SelectRequestTargets selectRequestTargets() { - return new SelectRequestTargets(fhirClientProvider, taskHelper, organizationProvider); + return new SelectRequestTargets(fhirClientProvider, taskHelper, organizationProvider, bouncyCastleProvider()); } @Bean @@ -127,7 +145,8 @@ public ModifyQueries modifyQueries() @Bean public ExecuteQueries executeQueries() { - return new ExecuteQueries(fhirClientProvider, openehrClientProvider.getWebserviceClient(), taskHelper); + return new ExecuteQueries(fhirClientProvider, openehrClientProvider.getWebserviceClient(), taskHelper, + organizationProvider); } @Bean @@ -136,16 +155,29 @@ public FilterQueryResultsByConsent filterQueryResultsByConsent() return new FilterQueryResultsByConsent(fhirClientProvider, taskHelper); } + @Bean + public GenerateCountFromIds generateCountFromIds() + { + return new GenerateCountFromIds(fhirClientProvider, taskHelper); + } + + @Bean + public MasterPatientIndexClient masterPatientIndexClient() + { + return masterPatientIndexClientFactory.createClient(environment::getProperty); + } + @Bean public GenerateBloomFilters generateBloomFilters() { - return new GenerateBloomFilters(fhirClientProvider, taskHelper); + return new GenerateBloomFilters(fhirClientProvider, taskHelper, masterPatientIndexClient(), objectMapper, + bouncyCastleProvider()); } @Bean - public GenerateCountFromIds generateCountFromIds() + public BouncyCastleProvider bouncyCastleProvider() { - return new GenerateCountFromIds(fhirClientProvider, taskHelper); + return new BouncyCastleProvider(); } @Bean @@ -183,9 +215,21 @@ public StoreResults storeResults() } @Bean - public ExecuteEpiLink executeEpiLink() + public DownloadResultSets downloadResultSets() + { + return new DownloadResultSets(fhirClientProvider, taskHelper, objectMapper); + } + + @Bean + public ResultSetTranslatorFromMedicRbfOnly resultSetTranslatorFromMedicRbfOnly() + { + return new ResultSetTranslatorFromMedicRbfOnlyImpl(); + } + + @Bean + public ExecuteRecordLink executeRecordLink() { - return new ExecuteEpiLink(fhirClientProvider, taskHelper); + return new ExecuteRecordLink(fhirClientProvider, taskHelper, resultSetTranslatorFromMedicRbfOnly()); } @Bean diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/computeSimpleFeasibility.bpmn b/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/computeSimpleFeasibility.bpmn index 8d9ce9c61..fbd448eb5 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/computeSimpleFeasibility.bpmn +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/computeSimpleFeasibility.bpmn @@ -1,6 +1,6 @@ - + SequenceFlow_1lfe4wr SequenceFlow_0xxpamp @@ -29,8 +29,8 @@ - SequenceFlow_1lu3gr1 - SequenceFlow_0ru8qx9 + SequenceFlow_0t4lx4v + SequenceFlow_155t66x SequenceFlow_0h3to47 @@ -46,15 +46,14 @@ requestSimpleFeasibility - http://highmed.org/fhir/StructureDefinition/highmed-task-result-multi-medic-simple-feasibility - 0.1.0 + http://highmed.org/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility + 0.2.0 resultMultiMedicSimpleFeasibilityMessage SequenceFlow_0brvdlv - @@ -65,37 +64,38 @@ - + ${needsRecordLinkage == false} - + ${needsRecordLinkage == true} - - SequenceFlow_0calilw + + SequenceFlow_0zp76kj SequenceFlow_02zmrer - - - SequenceFlow_02zmrer - SequenceFlow_1sevjlz - + - SequenceFlow_0t4lx4v - SequenceFlow_1sevjlz + SequenceFlow_02zmrer + SequenceFlow_155t66x SequenceFlow_1lu3gr1 - - + SequenceFlow_01pjftq SequenceFlow_1lfe4wr - SequenceFlow_0ru8qx9 + SequenceFlow_1lu3gr1 SequenceFlow_0brvdlv + + + SequenceFlow_0calilw + SequenceFlow_0zp76kj + + @@ -106,7 +106,7 @@ - + @@ -145,15 +145,11 @@ - + - + - - - - @@ -176,50 +172,54 @@ - + - + - + - + - - + + - - + + - - - - + - - - - - - + + - - + + - + + + + + + + + + + + + diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/executeSimpleFeasibility.bpmn b/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/executeSimpleFeasibility.bpmn index 826722289..b69df3fcc 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/executeSimpleFeasibility.bpmn +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/executeSimpleFeasibility.bpmn @@ -1,6 +1,6 @@ - + SequenceFlow_0q803rh SequenceFlow_04ouilq @@ -25,9 +25,9 @@ resultSingleMedicSimpleFeasibilityMessage - 0.1.0 + 0.2.0 computeSimpleFeasibility - http://highmed.org/fhir/StructureDefinition/highmed-task-result-single-medic-simple-feasibility + http://highmed.org/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility SequenceFlow_0ascyjc diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/requestSimpleFeasibility.bpmn b/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/requestSimpleFeasibility.bpmn index 9a78de695..386c043ad 100755 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/requestSimpleFeasibility.bpmn +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/main/resources/requestSimpleFeasibility.bpmn @@ -1,6 +1,6 @@ - + SequenceFlow_11k77gx @@ -13,7 +13,7 @@ executeSimpleFeasibility - 0.1.0 + 0.2.0 executeSimpleFeasibilityMessage http://highmed.org/fhir/StructureDefinition/highmed-task-execute-simple-feasibility @@ -42,7 +42,7 @@ computeSimpleFeasibility - 0.1.0 + 0.2.0 computeSimpleFeasibilityMessage http://highmed.org/fhir/StructureDefinition/highmed-task-compute-simple-feasibility diff --git a/dsf-bpe/dsf-bpe-process-feasibility/src/test/java/org/highmed/dsf/bpe/start/RequestSimpleFeasibilityFromMedicsViaMedic1ExampleStarter.java b/dsf-bpe/dsf-bpe-process-feasibility/src/test/java/org/highmed/dsf/bpe/start/RequestSimpleFeasibilityFromMedicsViaMedic1ExampleStarter.java index 70c5e175a..2526b6349 100644 --- a/dsf-bpe/dsf-bpe-process-feasibility/src/test/java/org/highmed/dsf/bpe/start/RequestSimpleFeasibilityFromMedicsViaMedic1ExampleStarter.java +++ b/dsf-bpe/dsf-bpe-process-feasibility/src/test/java/org/highmed/dsf/bpe/start/RequestSimpleFeasibilityFromMedicsViaMedic1ExampleStarter.java @@ -12,7 +12,8 @@ import javax.ws.rs.WebApplicationException; import org.highmed.dsf.bpe.Constants; -import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.ReferenceCleanerImpl; import org.highmed.dsf.fhir.service.ReferenceExtractorImpl; import org.highmed.fhir.client.FhirWebserviceClient; import org.highmed.fhir.client.FhirWebserviceClientJersey; @@ -27,8 +28,6 @@ import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Narrative; import org.hl7.fhir.r4.model.OperationOutcome; -import org.hl7.fhir.r4.model.Practitioner; -import org.hl7.fhir.r4.model.PractitionerRole; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.ResearchStudy; import org.hl7.fhir.r4.model.ResearchStudy.ResearchStudyStatus; @@ -53,18 +52,16 @@ public static void main(String[] args) KeyStore trustStore = CertificateHelper.extractTrust(keyStore); FhirContext context = FhirContext.forR4(); - ReferenceExtractor referenceExtractor = new ReferenceExtractorImpl(); + ReferenceCleaner referenceCleaner = new ReferenceCleanerImpl(new ReferenceExtractorImpl()); FhirWebserviceClient client = new FhirWebserviceClientJersey("https://medic1/fhir/", trustStore, keyStore, - keyStorePassword, null, null, null, 0, 0, null, context, referenceExtractor); + keyStorePassword, null, null, null, 0, 0, null, context, referenceCleaner); try { Group group1 = createGroup("Group 1"); Group group2 = createGroup("Group 2"); - Practitioner practitioner = createPractitioner(); - PractitionerRole practitionerRole = createPractitionerRole(practitioner); - ResearchStudy researchStudy = createResearchStudy(group1, group2, practitioner); - Task task = createTask(practitioner, researchStudy); + ResearchStudy researchStudy = createResearchStudy(group1, group2); + Task task = createTask(researchStudy); Bundle bundle = new Bundle(); bundle.setType(BundleType.TRANSACTION); @@ -72,16 +69,12 @@ public static void main(String[] args) .setMethod(HTTPVerb.POST).setUrl("Group"); bundle.addEntry().setResource(group2).setFullUrl(group2.getIdElement().getIdPart()).getRequest() .setMethod(HTTPVerb.POST).setUrl("Group"); - bundle.addEntry().setResource(practitioner).setFullUrl(practitioner.getIdElement().getIdPart()).getRequest() - .setMethod(HTTPVerb.POST).setUrl("Practitioner"); - bundle.addEntry().setResource(practitionerRole).setFullUrl(practitionerRole.getIdElement().getIdPart()) - .getRequest().setMethod(HTTPVerb.POST).setUrl("PractitionerRole"); bundle.addEntry().setResource(researchStudy).setFullUrl(researchStudy.getIdElement().getIdPart()) .getRequest().setMethod(HTTPVerb.POST).setUrl("ResearchStudy"); bundle.addEntry().setResource(task).setFullUrl(task.getIdElement().getIdPart()).getRequest() .setMethod(HTTPVerb.POST).setUrl("Task"); - client.postBundle(bundle); + client.withMinimalReturn().postBundle(bundle); } catch (WebApplicationException e) { @@ -105,7 +98,7 @@ private static Group createGroup(String name) group.getText().getDiv().addText("This is the description"); group.getText().setStatus(Narrative.NarrativeStatus.ADDITIONAL); group.setType(GroupType.PERSON); - group.setActual(true); + group.setActual(false); group.setActive(true); group.addExtension().setUrl("http://highmed.org/fhir/StructureDefinition/query").setValue(new Expression() .setLanguageElement(Constants.AQL_QUERY_TYPE).setExpression("SELECT COUNT(e) FROM EHR e")); @@ -114,72 +107,51 @@ private static Group createGroup(String name) return group; } - private static Practitioner createPractitioner() - { - Practitioner practitioner = new Practitioner(); - practitioner.setIdElement(new IdType("urn:uuid:" + UUID.randomUUID().toString())); - practitioner.setActive(true); - - practitioner.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-practitioner"); - practitioner.getNameFirstRep().setFamily("HiGHmed").addGiven("Test"); - - return practitioner; - } - - private static PractitionerRole createPractitionerRole(Practitioner practitioner) - { - PractitionerRole practitionerRole = new PractitionerRole(); - practitionerRole.setIdElement(new IdType("urn:uuid:" + UUID.randomUUID().toString())); - practitionerRole.setActive(true); - - practitioner.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-practitioner-role"); - practitionerRole.getPractitioner().setReference(practitioner.getIdElement().getIdPart()); - practitionerRole.getOrganization().setType("Organization").getIdentifier() - .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); - - return practitionerRole; - } - - private static ResearchStudy createResearchStudy(Group group1, Group group2, Practitioner practitioner) + private static ResearchStudy createResearchStudy(Group group1, Group group2) { ResearchStudy researchStudy = new ResearchStudy(); researchStudy.setIdElement(new IdType("urn:uuid:" + UUID.randomUUID().toString())); - researchStudy.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-research-study"); + researchStudy.getMeta() + .addProfile("http://highmed.org/fhir/StructureDefinition/highmed-research-study-feasibility"); researchStudy.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/research-study-identifier") .setValue(UUID.randomUUID().toString()); - researchStudy.setTitle("Research Study Test"); researchStudy.setStatus(ResearchStudyStatus.ACTIVE); - researchStudy.setDescription( - "This is a test research study based on the highmed profile. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua."); researchStudy.addEnrollment().setReference(group1.getIdElement().getIdPart()); researchStudy.addEnrollment().setReference(group2.getIdElement().getIdPart()); - researchStudy.getPrincipalInvestigator().setReference(practitioner.getIdElement().getIdPart()); researchStudy.addExtension().setUrl("http://highmed.org/fhir/StructureDefinition/participating-medic") - .setValue(new Reference().setType("Organization").setIdentifier(new Identifier() - .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"))); + .setValue(new Reference().setType("Organization") + .setIdentifier(new Identifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_MeDIC_1"))); researchStudy.addExtension().setUrl("http://highmed.org/fhir/StructureDefinition/participating-medic") - .setValue(new Reference().setType("Organization").setIdentifier(new Identifier() - .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_2"))); + .setValue(new Reference().setType("Organization") + .setIdentifier(new Identifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_MeDIC_2"))); researchStudy.addExtension().setUrl("http://highmed.org/fhir/StructureDefinition/participating-medic") - .setValue(new Reference().setType("Organization").setIdentifier(new Identifier() - .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_3"))); + .setValue(new Reference().setType("Organization") + .setIdentifier(new Identifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_MeDIC_3"))); researchStudy.addExtension().setUrl("http://highmed.org/fhir/StructureDefinition/participating-ttp") - .setValue(new Reference().setType("Organization").setIdentifier(new Identifier() - .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"))); + .setValue(new Reference().setType("Organization") + .setIdentifier(new Identifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_TTP"))); return researchStudy; } - private static Task createTask(Practitioner practitioner, ResearchStudy researchStudy) + private static Task createTask(ResearchStudy researchStudy) { Task task = new Task(); task.setIdElement(new IdType("urn:uuid:" + UUID.randomUUID().toString())); task.getMeta() .addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-request-simple-feasibility"); - task.setInstantiatesUri("http://highmed.org/bpe/Process/requestSimpleFeasibility/0.1.0"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/requestSimpleFeasibility/0.2.0"); task.setStatus(TaskStatus.REQUESTED); task.setIntent(TaskIntent.ORDER); task.setAuthoredOn(new Date()); @@ -195,9 +167,9 @@ private static Task createTask(Practitioner practitioner, ResearchStudy research new Reference().setReference(researchStudy.getIdElement().getIdPart()).setType("ResearchStudy")) .getType().addCoding().setSystem("http://highmed.org/fhir/CodeSystem/feasibility") .setCode("research-study-reference"); - task.addInput().setValue(new BooleanType(false)).getType().addCoding() + task.addInput().setValue(new BooleanType(true)).getType().addCoding() .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("needs-record-linkage"); - task.addInput().setValue(new BooleanType(false)).getType().addCoding() + task.addInput().setValue(new BooleanType(true)).getType().addCoding() .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("needs-consent-check"); return task; diff --git a/dsf-bpe/dsf-bpe-process-ping/pom.xml b/dsf-bpe/dsf-bpe-process-ping/pom.xml index 83eff334b..87cd08048 100755 --- a/dsf-bpe/dsf-bpe-process-ping/pom.xml +++ b/dsf-bpe/dsf-bpe-process-ping/pom.xml @@ -7,7 +7,7 @@ org.highmed.dsf dsf-bpe-pom - 0.1.0 + 0.2.0 diff --git a/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/LogPing.java b/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/LogPing.java index 98e1ac565..3adfaf1ae 100755 --- a/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/LogPing.java +++ b/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/LogPing.java @@ -1,15 +1,10 @@ package org.highmed.dsf.bpe.service; -import java.util.Objects; - import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; -import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,22 +13,9 @@ public class LogPing extends AbstractServiceDelegate { private static final Logger logger = LoggerFactory.getLogger(LogPing.class); - private final OrganizationProvider organizationProvider; - - public LogPing(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, - OrganizationProvider organizationProvider) + public LogPing(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper) { super(clientProvider, taskHelper); - - this.organizationProvider = organizationProvider; - } - - @Override - public void afterPropertiesSet() throws Exception - { - super.afterPropertiesSet(); - - Objects.requireNonNull(organizationProvider, "organizationProvider"); } @Override @@ -45,9 +27,6 @@ public void doExecute(DelegateExecution execution) throws Exception Task task = (Task) execution.getVariable(Constants.VARIABLE_TASK); - String organization = organizationProvider.getIdentifier(new IdType(task.getRequester().getReference())) - .map(Identifier::getValue).orElse(task.getRequester().getReference()); - - logger.info("PING from {}", organization); + logger.info("PING from {}", task.getRequester().getIdentifier().getValue()); } } diff --git a/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/LogPong.java b/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/LogPong.java index 7430e24d2..fcf49ee58 100755 --- a/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/LogPong.java +++ b/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/LogPong.java @@ -1,15 +1,10 @@ package org.highmed.dsf.bpe.service; -import java.util.Objects; - import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; -import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,22 +13,9 @@ public class LogPong extends AbstractServiceDelegate { private static final Logger logger = LoggerFactory.getLogger(LogPong.class); - private final OrganizationProvider organizationProvider; - - public LogPong(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, - OrganizationProvider organizationProvider) + public LogPong(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper) { super(clientProvider, taskHelper); - - this.organizationProvider = organizationProvider; - } - - @Override - public void afterPropertiesSet() throws Exception - { - super.afterPropertiesSet(); - - Objects.requireNonNull(organizationProvider, "organizationProvider"); } @Override @@ -45,9 +27,6 @@ public void doExecute(DelegateExecution execution) throws Exception Task task = (Task) execution.getVariable(Constants.VARIABLE_TASK); - String organization = organizationProvider.getIdentifier(new IdType(task.getRequester().getReference())) - .map(Identifier::getValue).orElse(task.getRequester().getReference()); - - logger.info("PONG from {}", organization); + logger.info("PONG from {}", task.getRequester().getIdentifier().getValue()); } } diff --git a/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/SelectPongTarget.java b/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/SelectPongTarget.java index ec9060a02..b7dbaa96e 100755 --- a/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/SelectPongTarget.java +++ b/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/service/SelectPongTarget.java @@ -1,16 +1,12 @@ package org.highmed.dsf.bpe.service; -import java.util.Objects; - import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.Constants; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; -import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.fhir.variables.MultiInstanceTarget; import org.highmed.dsf.fhir.variables.MultiInstanceTargetValues; -import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Task; import org.slf4j.Logger; @@ -21,22 +17,9 @@ public class SelectPongTarget extends AbstractServiceDelegate implements Initial { private static final Logger logger = LoggerFactory.getLogger(SelectPingTargets.class); - private final OrganizationProvider organizationProvider; - - public SelectPongTarget(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, - OrganizationProvider organizationProvider) + public SelectPongTarget(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper) { super(clientProvider, taskHelper); - - this.organizationProvider = organizationProvider; - } - - @Override - public void afterPropertiesSet() throws Exception - { - super.afterPropertiesSet(); - - Objects.requireNonNull(organizationProvider, "organizationProvider"); } @Override @@ -50,11 +33,7 @@ public void doExecute(DelegateExecution execution) throws Exception String correlationKey = getTaskHelper().getFirstInputParameterStringValue(task, Constants.CODESYSTEM_HIGHMED_BPMN, Constants.CODESYSTEM_HIGHMED_BPMN_VALUE_CORRELATION_KEY).get(); - - Identifier targetOrganizationIdentifier = organizationProvider - .getIdentifier(new IdType(task.getRequester().getReference())) - .orElseThrow(() -> new IllegalStateException( - "Organization with id " + task.getRequester().getReference() + " not found")); + Identifier targetOrganizationIdentifier = task.getRequester().getIdentifier(); execution.setVariable(Constants.VARIABLE_MULTI_INSTANCE_TARGET, MultiInstanceTargetValues .create(new MultiInstanceTarget(targetOrganizationIdentifier.getValue(), correlationKey))); diff --git a/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/spring/config/PingConfig.java b/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/spring/config/PingConfig.java index 79de26b42..932fbdfe6 100755 --- a/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/spring/config/PingConfig.java +++ b/dsf-bpe/dsf-bpe-process-ping/src/main/java/org/highmed/dsf/bpe/spring/config/PingConfig.java @@ -53,13 +53,13 @@ public SendPong sendPong() @Bean public LogPing logPing() { - return new LogPing(clientProvider, taskHelper, organizationProvider); + return new LogPing(clientProvider, taskHelper); } @Bean public LogPong logPong() { - return new LogPong(clientProvider, taskHelper, organizationProvider); + return new LogPong(clientProvider, taskHelper); } @Bean @@ -71,6 +71,6 @@ public SelectPingTargets selectPingTargets() @Bean public SelectPongTarget selectPongTarget() { - return new SelectPongTarget(clientProvider, taskHelper, organizationProvider); + return new SelectPongTarget(clientProvider, taskHelper); } } diff --git a/dsf-bpe/dsf-bpe-process-ping/src/main/resources/ping.bpmn b/dsf-bpe/dsf-bpe-process-ping/src/main/resources/ping.bpmn index 4b064775d..a68c15eb4 100755 --- a/dsf-bpe/dsf-bpe-process-ping/src/main/resources/ping.bpmn +++ b/dsf-bpe/dsf-bpe-process-ping/src/main/resources/ping.bpmn @@ -1,6 +1,6 @@ - + @@ -11,7 +11,7 @@ pong - 0.1.0 + 0.2.0 pingMessage http://highmed.org/fhir/StructureDefinition/highmed-task-ping @@ -50,7 +50,7 @@ SequenceFlow_01v9yzp - PT5S + PT5M @@ -66,17 +66,30 @@ - + - - - + + + + + + + + + + + + + + + + @@ -86,52 +99,39 @@ - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + diff --git a/dsf-bpe/dsf-bpe-process-ping/src/main/resources/pong.bpmn b/dsf-bpe/dsf-bpe-process-ping/src/main/resources/pong.bpmn index d13a47ae0..5af4b7e5a 100755 --- a/dsf-bpe/dsf-bpe-process-ping/src/main/resources/pong.bpmn +++ b/dsf-bpe/dsf-bpe-process-ping/src/main/resources/pong.bpmn @@ -1,6 +1,6 @@ - + SequenceFlow_07w11cw @@ -10,7 +10,7 @@ pongMessage - 0.1.0 + 0.2.0 ping http://highmed.org/fhir/StructureDefinition/highmed-task-pong diff --git a/dsf-bpe/dsf-bpe-process-ping/src/test/java/org/highmed/dsf/bpe/start/Ping3MedicFromTtpExampleStarter.java b/dsf-bpe/dsf-bpe-process-ping/src/test/java/org/highmed/dsf/bpe/start/Ping3MedicFromTtpExampleStarter.java index 182ffc78c..3896bc12d 100644 --- a/dsf-bpe/dsf-bpe-process-ping/src/test/java/org/highmed/dsf/bpe/start/Ping3MedicFromTtpExampleStarter.java +++ b/dsf-bpe/dsf-bpe-process-ping/src/test/java/org/highmed/dsf/bpe/start/Ping3MedicFromTtpExampleStarter.java @@ -8,7 +8,8 @@ import java.security.cert.CertificateException; import java.util.Date; -import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.ReferenceCleanerImpl; import org.highmed.dsf.fhir.service.ReferenceExtractorImpl; import org.highmed.fhir.client.FhirWebserviceClient; import org.highmed.fhir.client.FhirWebserviceClientJersey; @@ -33,13 +34,13 @@ public static void main(String[] args) KeyStore trustStore = CertificateHelper.extractTrust(keyStore); FhirContext context = FhirContext.forR4(); - ReferenceExtractor referenceExtractor = new ReferenceExtractorImpl(); + ReferenceCleaner referenceCleaner = new ReferenceCleanerImpl(new ReferenceExtractorImpl()); FhirWebserviceClient client = new FhirWebserviceClientJersey("https://ttp/fhir/", trustStore, keyStore, - keyStorePassword, null, null, null, 0, 0, null, context, referenceExtractor); + keyStorePassword, null, null, null, 0, 0, null, context, referenceCleaner); Task task = new Task(); - task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - task.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); task.setStatus(TaskStatus.REQUESTED); task.setIntent(TaskIntent.ORDER); task.setAuthoredOn(new Date()); @@ -48,9 +49,9 @@ public static void main(String[] args) task.getRestriction().addRecipient().setType("Organization").getIdentifier() .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); - task.addInput().setValue(new StringType("startProcessMessage")).getType().addCoding() + task.addInput().setValue(new StringType("startPingProcessMessage")).getType().addCoding() .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); - client.create(task); + client.withMinimalReturn().create(task); } } diff --git a/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-child/pom.xml b/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-child/pom.xml index 800f31492..0efeac384 100644 --- a/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-child/pom.xml +++ b/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-child/pom.xml @@ -8,7 +8,7 @@ dsf-bpe-process-plugin-example org.highmed.dsf - 0.1.0 + 0.2.0 diff --git a/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-parent/pom.xml b/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-parent/pom.xml index d5e911885..9cc236e41 100644 --- a/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-parent/pom.xml +++ b/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-parent/pom.xml @@ -8,7 +8,7 @@ dsf-bpe-process-plugin-example org.highmed.dsf - 0.1.0 + 0.2.0 diff --git a/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-parent/src/test/java/org/highmed/dsf/bpe/start/PluginSubprocessExampleStarter.java b/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-parent/src/test/java/org/highmed/dsf/bpe/start/PluginSubprocessExampleStarter.java new file mode 100644 index 000000000..57d63e481 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-parent/src/test/java/org/highmed/dsf/bpe/start/PluginSubprocessExampleStarter.java @@ -0,0 +1,58 @@ +package org.highmed.dsf.bpe.start; + +import java.io.IOException; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.Date; + +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.ReferenceCleanerImpl; +import org.highmed.dsf.fhir.service.ReferenceExtractorImpl; +import org.highmed.fhir.client.FhirWebserviceClient; +import org.highmed.fhir.client.FhirWebserviceClientJersey; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.TaskIntent; +import org.hl7.fhir.r4.model.Task.TaskStatus; + +import ca.uhn.fhir.context.FhirContext; + +import de.rwh.utils.crypto.CertificateHelper; +import de.rwh.utils.crypto.io.CertificateReader; + +public class PluginSubprocessExampleStarter +{ + public static void main(String[] args) + throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException + { + char[] keyStorePassword = "password".toCharArray(); + KeyStore keyStore = CertificateReader.fromPkcs12(Paths.get( + "../../dsf-tools/dsf-tools-test-data-generator/cert/Webbrowser_Test_User/Webbrowser_Test_User_certificate.p12"), + keyStorePassword); + KeyStore trustStore = CertificateHelper.extractTrust(keyStore); + + FhirContext context = FhirContext.forR4(); + ReferenceCleaner referenceCleaner = new ReferenceCleanerImpl(new ReferenceExtractorImpl()); + FhirWebserviceClient client = new FhirWebserviceClientJersey("https://medic1/fhir/", trustStore, keyStore, + keyStorePassword, null, null, null, 0, 0, null, context, referenceCleaner); + + Task task = new Task(); + task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-parent-plugin"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/parentPlugin/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); + + task.addInput().setValue(new StringType("parentPluginMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + + client.create(task); + } +} diff --git a/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-service-overwrite/pom.xml b/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-service-overwrite/pom.xml index 5e8693cba..595307b8f 100644 --- a/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-service-overwrite/pom.xml +++ b/dsf-bpe/dsf-bpe-process-plugin-example/dsf-bpe-process-service-overwrite/pom.xml @@ -8,7 +8,7 @@ dsf-bpe-process-plugin-example org.highmed.dsf - 0.1.0 + 0.2.0 diff --git a/dsf-bpe/dsf-bpe-process-plugin-example/pom.xml b/dsf-bpe/dsf-bpe-process-plugin-example/pom.xml index c9a65ec6a..23eda8da5 100644 --- a/dsf-bpe/dsf-bpe-process-plugin-example/pom.xml +++ b/dsf-bpe/dsf-bpe-process-plugin-example/pom.xml @@ -7,7 +7,7 @@ dsf-bpe-pom org.highmed.dsf - 0.1.0 + 0.2.0 dsf-bpe-process-plugin-example diff --git a/dsf-bpe/dsf-bpe-process-update-resources/pom.xml b/dsf-bpe/dsf-bpe-process-update-resources/pom.xml index 4b58e1d19..e7ca984d9 100755 --- a/dsf-bpe/dsf-bpe-process-update-resources/pom.xml +++ b/dsf-bpe/dsf-bpe-process-update-resources/pom.xml @@ -7,7 +7,7 @@ org.highmed.dsf dsf-bpe-pom - 0.1.0 + 0.2.0 diff --git a/dsf-bpe/dsf-bpe-process-update-resources/src/main/java/org/highmed/dsf/bpe/service/UpdateResources.java b/dsf-bpe/dsf-bpe-process-update-resources/src/main/java/org/highmed/dsf/bpe/service/UpdateResources.java index 57757af39..8705695fb 100755 --- a/dsf-bpe/dsf-bpe-process-update-resources/src/main/java/org/highmed/dsf/bpe/service/UpdateResources.java +++ b/dsf-bpe/dsf-bpe-process-update-resources/src/main/java/org/highmed/dsf/bpe/service/UpdateResources.java @@ -58,14 +58,17 @@ public void doExecute(DelegateExecution execution) throws Exception Bundle bundle; try { - bundle = requesterClient.read(Bundle.class, bundleId.getIdPart()); + if (bundleId.hasVersionIdPart()) + bundle = requesterClient.read(Bundle.class, bundleId.getIdPart(), bundleId.getVersionIdPart()); + else + bundle = requesterClient.read(Bundle.class, bundleId.getIdPart()); } catch (WebApplicationException e) { - logger.error("Error while reading Bundle with id {} from organization {}", bundleId.getValue(), - task.getRequester().getReference()); + logger.error("Error while reading Bundle with id {} from organization {}: {}", bundleId.getValue(), + task.getRequester().getReference(), e.getMessage()); throw new RuntimeException("Error while reading Bundle with id " + bundleId.getValue() - + " from organization " + task.getRequester().getReference(), e); + + " from organization " + task.getRequester().getReference() + ", " + e.getMessage(), e); } if (!EnumSet.of(BundleType.TRANSACTION, BundleType.BATCH).contains(bundle.getType())) @@ -77,14 +80,14 @@ public void doExecute(DelegateExecution execution) throws Exception try { logger.debug("Posting bundle to local endpoint: {}", context.newXmlParser().encodeResourceToString(bundle)); - getFhirWebserviceClientProvider().getLocalWebserviceClient().postBundle(bundle); + getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn().postBundle(bundle); } catch (Exception e) { - logger.error("Error while executing read Bundle with id {} from organization {} locally", - bundleId.getValue(), task.getRequester().getReference()); - throw new RuntimeException("Error while executing read Bundle with id " + bundleId.getValue() - + " from organization " + task.getRequester().getReference() + " locally", e); + logger.error("Error while executing Bundle with id {} from organization {} locally: {}", + bundleId.getValue(), task.getRequester().getReference(), e.getMessage()); + throw new RuntimeException("Error while executing Bundle with id " + bundleId.getValue() + + " from organization " + task.getRequester().getReference() + " locally, " + e.getMessage(), e); } } diff --git a/dsf-bpe/dsf-bpe-process-update-resources/src/main/resources/executeUpdateResources.bpmn b/dsf-bpe/dsf-bpe-process-update-resources/src/main/resources/executeUpdateResources.bpmn index 7b323f8d6..a9ae8427a 100755 --- a/dsf-bpe/dsf-bpe-process-update-resources/src/main/resources/executeUpdateResources.bpmn +++ b/dsf-bpe/dsf-bpe-process-update-resources/src/main/resources/executeUpdateResources.bpmn @@ -1,6 +1,6 @@ - + SequenceFlow_0djh0eg @@ -28,7 +28,7 @@ - + @@ -41,11 +41,11 @@ - + - + diff --git a/dsf-bpe/dsf-bpe-process-update-resources/src/main/resources/requestUpdateResources.bpmn b/dsf-bpe/dsf-bpe-process-update-resources/src/main/resources/requestUpdateResources.bpmn index 5fe0830b9..c4a320cc6 100755 --- a/dsf-bpe/dsf-bpe-process-update-resources/src/main/resources/requestUpdateResources.bpmn +++ b/dsf-bpe/dsf-bpe-process-update-resources/src/main/resources/requestUpdateResources.bpmn @@ -1,6 +1,6 @@ - + @@ -11,7 +11,7 @@ executeUpdateResources - 0.1.0 + 0.2.0 executeUpdateResourcesMessage http://highmed.org/fhir/StructureDefinition/highmed-task-execute-update-resources diff --git a/dsf-bpe/dsf-bpe-process-update-resources/src/test/java/org/highmed/dsf/bpe/start/UpdateResource3MedicTtpExampleStarter.java b/dsf-bpe/dsf-bpe-process-update-resources/src/test/java/org/highmed/dsf/bpe/start/UpdateResource3MedicTtpExampleStarter.java index 3b9f4c732..57c4bb701 100644 --- a/dsf-bpe/dsf-bpe-process-update-resources/src/test/java/org/highmed/dsf/bpe/start/UpdateResource3MedicTtpExampleStarter.java +++ b/dsf-bpe/dsf-bpe-process-update-resources/src/test/java/org/highmed/dsf/bpe/start/UpdateResource3MedicTtpExampleStarter.java @@ -10,11 +10,13 @@ import java.util.Date; import java.util.Map; -import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.ReferenceCleanerImpl; import org.highmed.dsf.fhir.service.ReferenceExtractorImpl; import org.highmed.fhir.client.FhirWebserviceClient; import org.highmed.fhir.client.FhirWebserviceClientJersey; import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.Task; @@ -37,19 +39,21 @@ public static void main(String[] args) KeyStore trustStore = CertificateHelper.extractTrust(keyStore); FhirContext context = FhirContext.forR4(); - ReferenceExtractor referenceExtractor = new ReferenceExtractorImpl(); + ReferenceCleaner referenceCleaner = new ReferenceCleanerImpl(new ReferenceExtractorImpl()); FhirWebserviceClient client = new FhirWebserviceClientJersey("https://ttp/fhir/", trustStore, keyStore, - keyStorePassword, null, null, null, 0, 0, null, context, referenceExtractor); + keyStorePassword, null, null, null, 0, 0, null, context, referenceCleaner); - Bundle searchResult = client.search(Bundle.class, Map.of("identifier", - Collections.singletonList("http://highmed.org/fhir/CodeSystem/update-whitelist|HiGHmed_white_list"))); + Bundle searchResult = client.searchWithStrictHandling(Bundle.class, Map.of("identifier", + Collections.singletonList("http://highmed.org/fhir/CodeSystem/update-whitelist|highmed_whitelist"))); if (searchResult.getTotal() != 1 && searchResult.getEntryFirstRep().getResource() instanceof Bundle) throw new IllegalStateException("Expected a single White-List Bundle"); Bundle whiteList = (Bundle) searchResult.getEntryFirstRep().getResource(); + System.out.println(context.newXmlParser().encodeResourceToString(whiteList)); + Task task = new Task(); task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-request-update-resources"); - task.setInstantiatesUri("http://highmed.org/bpe/Process/requestUpdateResources/0.1.0"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/requestUpdateResources/0.2.0"); task.setStatus(TaskStatus.REQUESTED); task.setIntent(TaskIntent.ORDER); task.setAuthoredOn(new Date()); @@ -61,13 +65,16 @@ public static void main(String[] args) task.addInput().setValue(new StringType("requestUpdateResourcesMessage")).getType().addCoding() .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); - task.addInput().setValue(new Reference("Bundle/" + whiteList.getIdElement().getIdPart())).getType().addCoding() - .setSystem("http://highmed.org/fhir/CodeSystem/update-resources").setCode("bundle-reference"); + task.addInput() + .setValue(new Reference(new IdType("Bundle", whiteList.getIdElement().getIdPart(), + whiteList.getIdElement().getVersionIdPart()))) + .getType().addCoding().setSystem("http://highmed.org/fhir/CodeSystem/update-resources") + .setCode("bundle-reference"); - task.addInput().setValue(new StringType("http://highmed.org/fhir/NamingSystem/organization-identifier|")).getType() - .addCoding().setSystem("http://highmed.org/fhir/CodeSystem/update-resources") + task.addInput().setValue(new StringType("http://highmed.org/fhir/NamingSystem/organization-identifier|")) + .getType().addCoding().setSystem("http://highmed.org/fhir/CodeSystem/update-resources") .setCode("organization-identifier-search-parameter"); - client.create(task); + client.withMinimalReturn().create(task); } } diff --git a/dsf-bpe/dsf-bpe-process-update-whitelist/pom.xml b/dsf-bpe/dsf-bpe-process-update-whitelist/pom.xml index dc67e38e0..c985297f5 100755 --- a/dsf-bpe/dsf-bpe-process-update-whitelist/pom.xml +++ b/dsf-bpe/dsf-bpe-process-update-whitelist/pom.xml @@ -7,7 +7,7 @@ org.highmed.dsf dsf-bpe-pom - 0.1.0 + 0.2.0 diff --git a/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/plugin/UpdateWhiteListPlugin.java b/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/plugin/UpdateWhitelistPlugin.java similarity index 53% rename from dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/plugin/UpdateWhiteListPlugin.java rename to dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/plugin/UpdateWhitelistPlugin.java index 4a5d317ec..46e2ecdce 100755 --- a/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/plugin/UpdateWhiteListPlugin.java +++ b/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/plugin/UpdateWhitelistPlugin.java @@ -3,14 +3,14 @@ import org.camunda.bpm.engine.ProcessEngine; import org.camunda.bpm.model.bpmn.BpmnModelInstance; -public class UpdateWhiteListPlugin extends AbstractProcessEnginePlugin +public class UpdateWhitelistPlugin extends AbstractProcessEnginePlugin { - private static final String UPDATE_WHITE_LISTE_FILE = "updateWhiteListe.bpmn"; + private static final String UPDATE_WHITELIST_FILE = "updateWhitelist.bpmn"; @Override public void postProcessEngineBuild(ProcessEngine processEngine) { - BpmnModelInstance updateWhiteListeProcess = readAndValidateModel("/" + UPDATE_WHITE_LISTE_FILE); - deploy(processEngine, UPDATE_WHITE_LISTE_FILE, updateWhiteListeProcess); + BpmnModelInstance updateWhiteListeProcess = readAndValidateModel("/" + UPDATE_WHITELIST_FILE); + deploy(processEngine, UPDATE_WHITELIST_FILE, updateWhiteListeProcess); } } diff --git a/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/service/UpdateWhiteList.java b/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/service/UpdateWhitelist.java old mode 100755 new mode 100644 similarity index 84% rename from dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/service/UpdateWhiteList.java rename to dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/service/UpdateWhitelist.java index e366732f9..b5756b2c2 --- a/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/service/UpdateWhiteList.java +++ b/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/service/UpdateWhitelist.java @@ -15,8 +15,6 @@ import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; -import org.highmed.dsf.fhir.variables.Outputs; -import org.highmed.dsf.fhir.variables.OutputsValues; import org.highmed.fhir.client.FhirWebserviceClient; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; @@ -28,16 +26,24 @@ import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; -public class UpdateWhiteList extends AbstractServiceDelegate implements InitializingBean +import ca.uhn.fhir.context.FhirContext; + +public class UpdateWhitelist extends AbstractServiceDelegate implements InitializingBean { + private static final Logger logger = LoggerFactory.getLogger(UpdateWhitelist.class); + private final OrganizationProvider organizationProvider; - public UpdateWhiteList(OrganizationProvider organizationProvider, FhirWebserviceClientProvider clientProvider, + public UpdateWhitelist(OrganizationProvider organizationProvider, FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper) { super(clientProvider, taskHelper); + this.organizationProvider = organizationProvider; } @@ -45,6 +51,7 @@ public UpdateWhiteList(OrganizationProvider organizationProvider, FhirWebservice public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); + Objects.requireNonNull(organizationProvider, "organizationProvider"); } @@ -53,7 +60,7 @@ public void doExecute(DelegateExecution execution) throws Exception { FhirWebserviceClient client = getFhirWebserviceClientProvider().getLocalWebserviceClient(); - Bundle searchSet = client.search(Organization.class, + Bundle searchSet = client.searchWithStrictHandling(Organization.class, Map.of("active", Collections.singletonList("true"), "identifier", Collections.singletonList(organizationProvider.getDefaultIdentifierSystem() + "|"), "_include", Collections.singletonList("Organization:endpoint"))); @@ -68,11 +75,17 @@ public void doExecute(DelegateExecution execution) throws Exception && e.getResource() instanceof Organization) .map(e -> (Organization) e.getResource()).forEach(addWhiteListEntry(transaction, searchSet)); - Bundle result = client.updateConditionaly(transaction, + logger.debug("Uploading new white-list transaction bundle: {}", + FhirContext.forR4().newJsonParser().encodeResourceToString(transaction)); + + IdType result = client.withMinimalReturn().updateConditionaly(transaction, Map.of("identifier", Collections.singletonList(Constants.CODESYSTEM_HIGHMED_UPDATE_WHITELIST + "|" + Constants.CODESYSTEM_HIGHMED_UPDATE_WHITELIST_VALUE_WHITE_LIST))); - setTaskOutput(result, execution); + Task task = (Task) execution.getVariable(Constants.VARIABLE_LEADING_TASK); + task.addOutput().setValue(new Reference(new IdType("Bundle", result.getIdPart(), result.getVersionIdPart()))) + .getType().addCoding().setSystem(Constants.CODESYSTEM_HIGHMED_UPDATE_WHITELIST) + .setCode(Constants.CODESYSTEM_HIGHMED_UPDATE_WHITELIST_VALUE_WHITE_LIST); } private Consumer addWhiteListEntry(Bundle transaction, Bundle searchSet) @@ -138,14 +151,4 @@ private Optional getEndpoint(Reference endpoint, Bundle searchSet) && e.getFullUrl().endsWith(endpoint.getReference())) .map(e -> (Endpoint) e.getResource()).findFirst(); } - - private void setTaskOutput(Bundle result, DelegateExecution execution) - { - Outputs outputs = (Outputs) execution.getVariable(Constants.VARIABLE_PROCESS_OUTPUTS); - - outputs.add(Constants.CODESYSTEM_HIGHMED_UPDATE_WHITELIST, - Constants.CODESYSTEM_HIGHMED_UPDATE_WHITELIST_VALUE_WHITE_LIST, new IdType(result.getId()).getIdPart()); - - execution.setVariable(Constants.VARIABLE_PROCESS_OUTPUTS, OutputsValues.create(outputs)); - } } diff --git a/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/spring/config/UpdateWhiteListConfig.java b/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/spring/config/UpdateWhitelistConfig.java similarity index 72% rename from dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/spring/config/UpdateWhiteListConfig.java rename to dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/spring/config/UpdateWhitelistConfig.java index 5db3aa588..e0efe0d4b 100755 --- a/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/spring/config/UpdateWhiteListConfig.java +++ b/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/java/org/highmed/dsf/bpe/spring/config/UpdateWhitelistConfig.java @@ -1,8 +1,8 @@ package org.highmed.dsf.bpe.spring.config; import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin; -import org.highmed.dsf.bpe.plugin.UpdateWhiteListPlugin; -import org.highmed.dsf.bpe.service.UpdateWhiteList; +import org.highmed.dsf.bpe.plugin.UpdateWhitelistPlugin; +import org.highmed.dsf.bpe.service.UpdateWhitelist; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; @@ -11,7 +11,7 @@ import org.springframework.context.annotation.Configuration; @Configuration -public class UpdateWhiteListConfig +public class UpdateWhitelistConfig { @Autowired private FhirWebserviceClientProvider clientProvider; @@ -25,12 +25,12 @@ public class UpdateWhiteListConfig @Bean public ProcessEnginePlugin updateWhiteListPlugin() { - return new UpdateWhiteListPlugin(); + return new UpdateWhitelistPlugin(); } @Bean - public UpdateWhiteList updateWhiteList() + public UpdateWhitelist updateWhiteList() { - return new UpdateWhiteList(organizationProvider, clientProvider, taskHelper); + return new UpdateWhitelist(organizationProvider, clientProvider, taskHelper); } } diff --git a/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/resources/updateWhiteListe.bpmn b/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/resources/updateWhitelist.bpmn similarity index 81% rename from dsf-bpe/dsf-bpe-process-update-whitelist/src/main/resources/updateWhiteListe.bpmn rename to dsf-bpe/dsf-bpe-process-update-whitelist/src/main/resources/updateWhitelist.bpmn index 96ee697b9..13a84df30 100755 --- a/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/resources/updateWhiteListe.bpmn +++ b/dsf-bpe/dsf-bpe-process-update-whitelist/src/main/resources/updateWhitelist.bpmn @@ -1,12 +1,12 @@ - - + + SequenceFlow_0oyvmcd - - + + SequenceFlow_0bbhq2r SequenceFlow_0oyvmcd @@ -15,9 +15,9 @@ - + - + @@ -29,7 +29,7 @@ - + diff --git a/dsf-bpe/dsf-bpe-process-update-whitelist/src/test/java/org/highmed/dsf/bpe/start/UpdateWhiteList3MedicTtpExampleStarter.java b/dsf-bpe/dsf-bpe-process-update-whitelist/src/test/java/org/highmed/dsf/bpe/start/UpdateWhitelist3MedicTtpExampleStarter.java similarity index 87% rename from dsf-bpe/dsf-bpe-process-update-whitelist/src/test/java/org/highmed/dsf/bpe/start/UpdateWhiteList3MedicTtpExampleStarter.java rename to dsf-bpe/dsf-bpe-process-update-whitelist/src/test/java/org/highmed/dsf/bpe/start/UpdateWhitelist3MedicTtpExampleStarter.java index def693de8..7d609a9f1 100644 --- a/dsf-bpe/dsf-bpe-process-update-whitelist/src/test/java/org/highmed/dsf/bpe/start/UpdateWhiteList3MedicTtpExampleStarter.java +++ b/dsf-bpe/dsf-bpe-process-update-whitelist/src/test/java/org/highmed/dsf/bpe/start/UpdateWhitelist3MedicTtpExampleStarter.java @@ -8,7 +8,8 @@ import java.security.cert.CertificateException; import java.util.Date; -import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.ReferenceCleanerImpl; import org.highmed.dsf.fhir.service.ReferenceExtractorImpl; import org.highmed.fhir.client.FhirWebserviceClient; import org.highmed.fhir.client.FhirWebserviceClientJersey; @@ -21,7 +22,7 @@ import de.rwh.utils.crypto.CertificateHelper; import de.rwh.utils.crypto.io.CertificateReader; -public class UpdateWhiteList3MedicTtpExampleStarter +public class UpdateWhitelist3MedicTtpExampleStarter { public static void main(String[] args) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException @@ -33,13 +34,13 @@ public static void main(String[] args) KeyStore trustStore = CertificateHelper.extractTrust(keyStore); FhirContext context = FhirContext.forR4(); - ReferenceExtractor referenceExtractor = new ReferenceExtractorImpl(); + ReferenceCleaner referenceCleaner = new ReferenceCleanerImpl(new ReferenceExtractorImpl()); FhirWebserviceClient client = new FhirWebserviceClientJersey("https://ttp/fhir/", trustStore, keyStore, - keyStorePassword, null, null, null, 0, 0, null, context, referenceExtractor); + keyStorePassword, null, null, null, 0, 0, null, context, referenceCleaner); Task task = new Task(); task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-update-whitelist"); - task.setInstantiatesUri("http://highmed.org/bpe/Process/updateWhiteList/0.1.0"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/updateWhitelist/0.2.0"); task.setStatus(TaskStatus.REQUESTED); task.setIntent(TaskIntent.ORDER); task.setAuthoredOn(new Date()); @@ -51,6 +52,6 @@ public static void main(String[] args) task.addInput().setValue(new StringType("updateWhitelistMessage")).getType().addCoding() .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); - client.create(task); + client.withMinimalReturn().create(task); } } diff --git a/dsf-bpe/dsf-bpe-server-jetty/conf/config.properties b/dsf-bpe/dsf-bpe-server-jetty/conf/config.properties index 654ff5654..05d2e3a34 100755 --- a/dsf-bpe/dsf-bpe-server-jetty/conf/config.properties +++ b/dsf-bpe/dsf-bpe-server-jetty/conf/config.properties @@ -1,42 +1,56 @@ -org.highmed.dsf.bpe.fhir.organization.identifier.localValue=Test_Organization - -org.highmed.dsf.bpe.fhir.local.webservice.baseUrl=https://localhost:8001/fhir -org.highmed.dsf.bpe.fhir.local.webservice.keystore.p12file=target/test-client_certificate.p12 -org.highmed.dsf.bpe.fhir.local.webservice.keystore.password=password -org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=1500 -org.highmed.dsf.bpe.fhir.local.webservice.connectTimeout=500 - -org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=2500 -org.highmed.dsf.bpe.fhir.remote.webservice.connectTimeout=1500 -#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.password= -#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.username= -#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.schemeHostPort= - -org.highmed.dsf.bpe.fhir.local.websocket.url=wss://localhost:8001/fhir/ws -org.highmed.dsf.bpe.fhir.local.websocket.keystore.p12file=target/test-client_certificate.p12 -org.highmed.dsf.bpe.fhir.local.websocket.keystore.password=password - -org.highmed.dsf.bpe.fhir.task.subscription.searchParameter=?criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson -org.highmed.dsf.bpe.fhir.task.subscription.lastEventTimeFile=target/last_event_time_file.txt - -org.highmed.dsf.bpe.db.driver=org.postgresql.Driver -org.highmed.dsf.bpe.db.url=jdbc:postgresql://localhost/bpe -org.highmed.dsf.bpe.db.liquibase_user=liquibase_user -org.highmed.dsf.bpe.db.liquibase_user_password=fLp6ZSd5QrMAkGZMjxqXjmcWrTfa3Dn8fA57h92Y - -org.highmed.dsf.bpe.db.server_users_group=bpe_users -org.highmed.dsf.bpe.db.server_user=bpe_server_user -org.highmed.dsf.bpe.db.server_user_password=as2hm56BPcaJKtG25JEx - -org.highmed.dsf.bpe.db.camunda_users_group=camunda_users -org.highmed.dsf.bpe.db.camunda_user=camunda_server_user -org.highmed.dsf.bpe.db.camunda_user_password=arpJ2FgJuYvUJhbxeuh7 - -org.highmed.dsf.bpe.openehr.webservice.baseUrl=http://localhost:8003/rest/openehr/v1 -org.highmed.dsf.bpe.openehr.webservice.basicAuthUsername=username -org.highmed.dsf.bpe.openehr.webservice.basicAuthPassword=password -org.highmed.dsf.bpe.openehr.webservice.connectionTimeout=1500 -org.highmed.dsf.bpe.openehr.webservice.readTimeout=2500 - -org.highmed.dsf.bpe.cors.origins= - +org.highmed.dsf.bpe.fhir.organization.identifier.localValue=Test_Organization + +org.highmed.dsf.bpe.fhir.local.webservice.baseUrl=https://localhost:8001/fhir +org.highmed.dsf.bpe.fhir.local.webservice.keystore.p12file=target/test-client_certificate.p12 +org.highmed.dsf.bpe.fhir.local.webservice.keystore.password=password +org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=1500 +org.highmed.dsf.bpe.fhir.local.webservice.connectTimeout=500 + +org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=2500 +org.highmed.dsf.bpe.fhir.remote.webservice.connectTimeout=1500 +#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.password= +#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.username= +#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.schemeHostPort= + +org.highmed.dsf.bpe.fhir.local.websocket.url=wss://localhost:8001/fhir/ws +org.highmed.dsf.bpe.fhir.local.websocket.keystore.p12file=target/test-client_certificate.p12 +org.highmed.dsf.bpe.fhir.local.websocket.keystore.password=password + +org.highmed.dsf.bpe.fhir.task.subscription.searchParameter=?criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson +org.highmed.dsf.bpe.fhir.task.subscription.lastEventTimeFile=target/last_event_time_file.txt +#org.highmed.dsf.bpe.fhir.task.subscription.retrySleepMillis=5000 +#org.highmed.dsf.bpe.fhir.task.subscription.maxRetries=-1 + +org.highmed.dsf.bpe.db.driver=org.postgresql.Driver +org.highmed.dsf.bpe.db.url=jdbc:postgresql://localhost/bpe +org.highmed.dsf.bpe.db.liquibase_user=liquibase_user +org.highmed.dsf.bpe.db.liquibase_user_password=fLp6ZSd5QrMAkGZMjxqXjmcWrTfa3Dn8fA57h92Y + +org.highmed.dsf.bpe.db.server_users_group=bpe_users +org.highmed.dsf.bpe.db.server_user=bpe_server_user +org.highmed.dsf.bpe.db.server_user_password=as2hm56BPcaJKtG25JEx + +org.highmed.dsf.bpe.db.camunda_users_group=camunda_users +org.highmed.dsf.bpe.db.camunda_user=camunda_server_user +org.highmed.dsf.bpe.db.camunda_user_password=arpJ2FgJuYvUJhbxeuh7 + +org.highmed.dsf.bpe.openehr.webservice.baseUrl=http://localhost:8003/rest/openehr/v1 +org.highmed.dsf.bpe.openehr.webservice.basicAuthUsername=username +org.highmed.dsf.bpe.openehr.webservice.basicAuthPassword=password +org.highmed.dsf.bpe.openehr.webservice.connectionTimeout=1500 +org.highmed.dsf.bpe.openehr.webservice.readTimeout=2500 + +#org.highmed.dsf.bpe.mpi.webservice.factory.class=org.highmed.mpi.client.pdq.MasterPatientIndexClientPdqFactory +#org.highmed.dsf.bpe.mpi.pdq.webservice.host= +#org.highmed.dsf.bpe.mpi.pdq.webservice.port= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.path= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.password= +#org.highmed.dsf.bpe.mpi.pdq.sender.application= +#org.highmed.dsf.bpe.mpi.pdq.sender.facility= +#org.highmed.dsf.bpe.mpi.pdq.receiver.application= +#org.highmed.dsf.bpe.mpi.pdq.receiver.facility= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.namespaceId= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.universalId= + +org.highmed.dsf.bpe.cors.origins= + diff --git a/dsf-bpe/dsf-bpe-server-jetty/docker/.dockerignore b/dsf-bpe/dsf-bpe-server-jetty/docker/.dockerignore index 5c60d5a7e..847795777 100755 --- a/dsf-bpe/dsf-bpe-server-jetty/docker/.dockerignore +++ b/dsf-bpe/dsf-bpe-server-jetty/docker/.dockerignore @@ -1,6 +1,7 @@ -.dockerignore -Dockerfile -conf/README.md -last_event/README.md -lib/.gitignore +.dockerignore +.gitignore +Dockerfile +conf/README.md +last_event/README.md +lib/.gitignore log/README.md \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-server-jetty/docker/.gitignore b/dsf-bpe/dsf-bpe-server-jetty/docker/.gitignore index 088235a8a..c295afe8d 100755 --- a/dsf-bpe/dsf-bpe-server-jetty/docker/.gitignore +++ b/dsf-bpe/dsf-bpe-server-jetty/docker/.gitignore @@ -1 +1,2 @@ /dsf_bpe.jar +/plugin/mpi_client_stub.jar diff --git a/dsf-bpe/dsf-bpe-server-jetty/docker/Dockerfile b/dsf-bpe/dsf-bpe-server-jetty/docker/Dockerfile index c578fdaba..6f9c238f7 100755 --- a/dsf-bpe/dsf-bpe-server-jetty/docker/Dockerfile +++ b/dsf-bpe/dsf-bpe-server-jetty/docker/Dockerfile @@ -1,12 +1,21 @@ +FROM debian:buster-slim AS builder +RUN adduser --system --no-create-home --group --uid 2202 java +WORKDIR /opt/bpe +COPY --chown=root:java ./ ./ +RUN chown root:java ./ && \ + chmod 750 ./ ./lib ./plugin ./dsf_bpe_start.sh && \ + chmod 640 ./dsf_bpe.jar ./lib/*.jar && \ + chmod 1775 ./log ./last_event + + FROM openjdk:11-slim -MAINTAINER Hauke Hund +LABEL maintainer="hauke.hund@hs-heilbronn.de" EXPOSE 8080 RUN adduser --system --no-create-home --group --uid 2202 java WORKDIR /opt/bpe -COPY --chown=root:java ./ ./ -RUN chown root:java ./ && chmod 750 ./ ./lib ./plugin ./dsf_bpe_start.sh && chmod 640 ./dsf_bpe.jar ./lib/*.jar && chmod 1775 ./log ./last_event +COPY --from=builder /opt/bpe ./ USER java ENTRYPOINT ["./dsf_bpe_start.sh"] diff --git a/dsf-bpe/dsf-bpe-server-jetty/pom.xml b/dsf-bpe/dsf-bpe-server-jetty/pom.xml index 3b2f54624..ddb1217d4 100755 --- a/dsf-bpe/dsf-bpe-server-jetty/pom.xml +++ b/dsf-bpe/dsf-bpe-server-jetty/pom.xml @@ -7,7 +7,7 @@ org.highmed.dsf dsf-bpe-pom - 0.1.0 + 0.2.0 @@ -34,7 +34,6 @@ javax.mail mail - 1.4.7 diff --git a/dsf-bpe/dsf-bpe-server/pom.xml b/dsf-bpe/dsf-bpe-server/pom.xml index aa65fc907..c95b43274 100755 --- a/dsf-bpe/dsf-bpe-server/pom.xml +++ b/dsf-bpe/dsf-bpe-server/pom.xml @@ -7,7 +7,7 @@ org.highmed.dsf dsf-bpe-pom - 0.1.0 + 0.2.0 @@ -49,6 +49,14 @@ org.highmed.dsf dsf-openehr-model + + org.highmed.dsf + dsf-mpi-client + + + org.highmed.dsf + dsf-mpi-client-stub + org.highmed.dsf dsf-tools-build-info-reader diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/listener/EndListener.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/listener/EndListener.java index 00687b4d2..76e4b3676 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/listener/EndListener.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/listener/EndListener.java @@ -54,7 +54,7 @@ public void notify(DelegateExecution execution) throws Exception } task.setStatus(Task.TaskStatus.COMPLETED); - webserviceClient.update(task); + webserviceClient.withMinimalReturn().update(task); } else { diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/FhirConfig.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/FhirConfig.java index d2e8cdab8..688357e6b 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/FhirConfig.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/FhirConfig.java @@ -10,43 +10,29 @@ import java.security.cert.CertificateException; import org.camunda.bpm.engine.ProcessEngine; -import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin; import org.highmed.dsf.fhir.client.FhirClientProviderImpl; import org.highmed.dsf.fhir.client.FhirWebsocketClientProvider; import org.highmed.dsf.fhir.group.GroupHelper; import org.highmed.dsf.fhir.group.GroupHelperImpl; import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.organization.OrganizationProviderImpl; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.ReferenceCleanerImpl; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceExtractorImpl; import org.highmed.dsf.fhir.task.TaskHandler; import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.fhir.task.TaskHelperImpl; -import org.highmed.dsf.fhir.variables.FeasibilityQueryResultSerializer; -import org.highmed.dsf.fhir.variables.FeasibilityQueryResultsSerializer; -import org.highmed.dsf.fhir.variables.FhirPlugin; -import org.highmed.dsf.fhir.variables.FhirResourceJacksonDeserializer; -import org.highmed.dsf.fhir.variables.FhirResourceJacksonSerializer; -import org.highmed.dsf.fhir.variables.FhirResourceSerializer; -import org.highmed.dsf.fhir.variables.FhirResourcesListSerializer; -import org.highmed.dsf.fhir.variables.MultiInstanceTargetSerializer; -import org.highmed.dsf.fhir.variables.MultiInstanceTargetsSerializer; -import org.highmed.dsf.fhir.variables.OutputSerializer; -import org.highmed.dsf.fhir.variables.OutputsSerializer; import org.highmed.dsf.fhir.websocket.FhirConnector; +import org.highmed.dsf.fhir.websocket.FhirConnectorImpl; import org.highmed.dsf.fhir.websocket.LastEventTimeIo; -import org.hl7.fhir.r4.model.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; - -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; import ca.uhn.fhir.context.FhirContext; import de.rwh.utils.crypto.CertificateHelper; @@ -103,31 +89,16 @@ public class FhirConfig @Value("${org.highmed.dsf.bpe.fhir.task.subscription.lastEventTimeFile}") private String lastEventTimeFile; + @Value("${org.highmed.dsf.bpe.fhir.task.subscription.retrySleepMillis:5000}") + private long websocketRetrySleepMillis; + + @Value("${org.highmed.dsf.bpe.fhir.task.subscription.maxRetries:-1}") + private int websocketMaxRetries; + @Autowired @Lazy private ProcessEngine processEngine; - @Bean - public ObjectMapper fhirObjectMapper() - { - ObjectMapper mapper = new ObjectMapper(); - - mapper.getFactory().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET); - mapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION); - mapper.setSerializationInclusion(Include.NON_NULL); - mapper.setSerializationInclusion(Include.NON_EMPTY); - - // mapper.enable(SerializationFeature.INDENT_OUTPUT); - - SimpleModule module = new SimpleModule(); - module.addSerializer(Resource.class, new FhirResourceJacksonSerializer(fhirContext())); - module.addDeserializer(Resource.class, new FhirResourceJacksonDeserializer(fhirContext())); - - mapper.registerModule(module); - - return mapper; - } - @Bean public FhirContext fhirContext() { @@ -135,65 +106,15 @@ public FhirContext fhirContext() } @Bean - public ReferenceExtractor referenceExtractor() - { - return new ReferenceExtractorImpl(); - } - - @Bean - public ProcessEnginePlugin fhirPlugin() - { - return new FhirPlugin(fhirResourceSerializer(), fhirResourcesListSerializer(), multiInstanceTargetSerializer(), - multiInstanceTargetsSerializer(), feasibilityQueryResultSerializer(), - feasibilityQueryResultsSerializer(), outputSerializer(), outputsSerializer()); - } - - @Bean - public FhirResourceSerializer fhirResourceSerializer() - { - return new FhirResourceSerializer(fhirContext()); - } - - @Bean - public FhirResourcesListSerializer fhirResourcesListSerializer() + public ReferenceCleaner referenceCleaner() { - return new FhirResourcesListSerializer(fhirObjectMapper()); + return new ReferenceCleanerImpl(referenceExtractor()); } @Bean - public MultiInstanceTargetSerializer multiInstanceTargetSerializer() - { - return new MultiInstanceTargetSerializer(fhirObjectMapper()); - } - - @Bean - public MultiInstanceTargetsSerializer multiInstanceTargetsSerializer() - { - return new MultiInstanceTargetsSerializer(fhirObjectMapper()); - } - - @Bean - public OutputSerializer outputSerializer() - { - return new OutputSerializer(fhirObjectMapper()); - } - - @Bean - public OutputsSerializer outputsSerializer() - { - return new OutputsSerializer(fhirObjectMapper()); - } - - @Bean - public FeasibilityQueryResultSerializer feasibilityQueryResultSerializer() - { - return new FeasibilityQueryResultSerializer(fhirObjectMapper()); - } - - @Bean - public FeasibilityQueryResultsSerializer feasibilityQueryResultsSerializer() + public ReferenceExtractor referenceExtractor() { - return new FeasibilityQueryResultsSerializer(fhirObjectMapper()); + return new ReferenceExtractorImpl(); } @Bean @@ -233,7 +154,7 @@ public FhirWebsocketClientProvider clientProvider() localWebsocketKeyStorePassword); KeyStore localWebsocketTrustStore = CertificateHelper.extractTrust(localWebsocketKeyStore); - return new FhirClientProviderImpl(fhirContext(), referenceExtractor(), localWebserviceBaseUrl, + return new FhirClientProviderImpl(fhirContext(), referenceCleaner(), localWebserviceBaseUrl, localReadTimeout, localConnectTimeout, localWebserviceTrustStore, localWebserviceKeyStore, webserviceKeyStorePassword, remoteReadTimeout, remoteConnectTimeout, remoteProxyPassword, remoteProxyUsername, remoteProxySchemeHostPort, localWebsocketUrl, localWebsocketTrustStore, @@ -254,8 +175,14 @@ public OrganizationProvider organizationProvider() @Bean public FhirConnector fhirConnector() { - return new FhirConnector(clientProvider(), taskHandler(), lastEventTimeIo(), fhirContext(), - subscriptionSearchParameter); + return new FhirConnectorImpl(clientProvider(), taskHandler(), lastEventTimeIo(), fhirContext(), + subscriptionSearchParameter, websocketRetrySleepMillis, websocketMaxRetries); + } + + @EventListener({ ContextRefreshedEvent.class }) + public void onContextRefreshedEvent(ContextRefreshedEvent event) + { + fhirConnector().connect(); } @Bean diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/MasterPatientIndexConfig.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/MasterPatientIndexConfig.java new file mode 100644 index 000000000..bbe402089 --- /dev/null +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/MasterPatientIndexConfig.java @@ -0,0 +1,43 @@ +package org.highmed.dsf.bpe.spring.config; + +import java.util.NoSuchElementException; + +import org.highmed.mpi.client.MasterPatientIndexClientFactory; +import org.highmed.mpi.client.MasterPatientIndexClientServiceLoader; +import org.highmed.mpi.client.stub.MasterPatientIndexClientStubFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MasterPatientIndexConfig +{ + private static final Logger logger = LoggerFactory.getLogger(MasterPatientIndexConfig.class); + + @Value("${org.highmed.dsf.bpe.mpi.webservice.factory.class:org.highmed.mpi.client.stub.MasterPatientIndexClientStubFactory}") + private String masterPatientIndexClientFactoryClass; + + @Bean + public MasterPatientIndexClientServiceLoader masterPatientIndexClientServiceLoader() + { + return new MasterPatientIndexClientServiceLoader(); + } + + @Bean + public MasterPatientIndexClientFactory masterPatientIndexClientFactory() + { + MasterPatientIndexClientFactory factory = masterPatientIndexClientServiceLoader() + .getMasterPatientIndexClientFactory(masterPatientIndexClientFactoryClass) + .orElseThrow(() -> new NoSuchElementException("Master patient index client factory with classname='" + + masterPatientIndexClientFactoryClass + "' not found")); + + if(factory instanceof MasterPatientIndexClientStubFactory) + logger.warn("Using {} as MPI client factory", factory.getClass().getName()); + else + logger.info("Using {} as MPI client factory", factory.getClass().getName()); + + return factory; + } +} diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/OpenEhrConfig.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/OpenEhrConfig.java index 63a734ff5..b2bb2e3c5 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/OpenEhrConfig.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/OpenEhrConfig.java @@ -2,18 +2,12 @@ import org.highmed.dsf.openehr.client.OpenEhrClientProviderImpl; import org.highmed.dsf.openehr.client.OpenEhrWebserviceClientProvider; - -import org.highmed.openehr.deserializer.RowElementDeserializer; -import org.highmed.openehr.model.structure.RowElement; +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; @Configuration public class OpenEhrConfig @@ -36,25 +30,7 @@ public class OpenEhrConfig @Bean public ObjectMapper openEhrObjectMapper() { - ObjectMapper mapper = new ObjectMapper(); - - mapper.getFactory().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET); - mapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); - - SimpleModule module = new SimpleModule(); - module.addDeserializer(RowElement.class, rowElementDeserializer()); - - mapper.registerModule(module); - - return mapper; - } - - @Bean - public RowElementDeserializer rowElementDeserializer() - { - return new RowElementDeserializer(); + return OpenEhrObjectMapperFactory.createObjectMapper(); } @Bean diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/SerializerConfig.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/SerializerConfig.java new file mode 100644 index 000000000..8c0fa5d1f --- /dev/null +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/bpe/spring/config/SerializerConfig.java @@ -0,0 +1,129 @@ +package org.highmed.dsf.bpe.spring.config; + +import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin; +import org.highmed.dsf.fhir.variables.BloomFilterConfigSerializer; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResultSerializer; +import org.highmed.dsf.fhir.variables.FeasibilityQueryResultsSerializer; +import org.highmed.dsf.fhir.variables.FhirResourceJacksonDeserializer; +import org.highmed.dsf.fhir.variables.FhirResourceJacksonSerializer; +import org.highmed.dsf.fhir.variables.FhirResourceSerializer; +import org.highmed.dsf.fhir.variables.FhirResourcesListSerializer; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResultSerializer; +import org.highmed.dsf.fhir.variables.FinalFeasibilityQueryResultsSerializer; +import org.highmed.dsf.fhir.variables.MultiInstanceTargetSerializer; +import org.highmed.dsf.fhir.variables.MultiInstanceTargetsSerializer; +import org.highmed.dsf.fhir.variables.OutputSerializer; +import org.highmed.dsf.fhir.variables.OutputsSerializer; +import org.highmed.dsf.fhir.variables.SerializerPlugin; +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; +import org.hl7.fhir.r4.model.Resource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; + +import ca.uhn.fhir.context.FhirContext; + +@Configuration +public class SerializerConfig +{ + @Autowired + private FhirContext fhirContext; + + @Bean + public ObjectMapper objectMapper() + { + ObjectMapper mapper = new ObjectMapper(); + + mapper.setSerializationInclusion(Include.NON_NULL); + mapper.setSerializationInclusion(Include.NON_EMPTY); + + SimpleModule module = new SimpleModule(); + module.addSerializer(Resource.class, new FhirResourceJacksonSerializer(fhirContext)); + module.addDeserializer(Resource.class, new FhirResourceJacksonDeserializer(fhirContext)); + + mapper.registerModule(module); + mapper.registerModule(OpenEhrObjectMapperFactory.openEhrModule()); + + return mapper; + } + + @Bean + public FhirResourceSerializer fhirResourceSerializer() + { + return new FhirResourceSerializer(fhirContext); + } + + @Bean + public FhirResourcesListSerializer fhirResourcesListSerializer() + { + return new FhirResourcesListSerializer(objectMapper()); + } + + @Bean + public MultiInstanceTargetSerializer multiInstanceTargetSerializer() + { + return new MultiInstanceTargetSerializer(objectMapper()); + } + + @Bean + public MultiInstanceTargetsSerializer multiInstanceTargetsSerializer() + { + return new MultiInstanceTargetsSerializer(objectMapper()); + } + + @Bean + public OutputSerializer outputSerializer() + { + return new OutputSerializer(objectMapper()); + } + + @Bean + public OutputsSerializer outputsSerializer() + { + return new OutputsSerializer(objectMapper()); + } + + @Bean + public FeasibilityQueryResultSerializer feasibilityQueryResultSerializer() + { + return new FeasibilityQueryResultSerializer(objectMapper()); + } + + @Bean + public FeasibilityQueryResultsSerializer feasibilityQueryResultsSerializer() + { + return new FeasibilityQueryResultsSerializer(objectMapper()); + } + + @Bean + public FinalFeasibilityQueryResultSerializer finalFeasibilityQueryResultSerializer() + { + return new FinalFeasibilityQueryResultSerializer(objectMapper()); + } + + @Bean + public FinalFeasibilityQueryResultsSerializer finalFeasibilityQueryResultsSerializer() + { + return new FinalFeasibilityQueryResultsSerializer(objectMapper()); + } + + @Bean + public BloomFilterConfigSerializer bloomFilterConfigSerializer() + { + return new BloomFilterConfigSerializer(objectMapper()); + } + + @Bean + public ProcessEnginePlugin serializerPlugin() + { + return new SerializerPlugin(fhirResourceSerializer(), fhirResourcesListSerializer(), + multiInstanceTargetSerializer(), multiInstanceTargetsSerializer(), feasibilityQueryResultSerializer(), + feasibilityQueryResultsSerializer(), finalFeasibilityQueryResultSerializer(), + finalFeasibilityQueryResultsSerializer(), bloomFilterConfigSerializer(), outputSerializer(), + outputsSerializer()); + } +} diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/client/FhirClientProviderImpl.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/client/FhirClientProviderImpl.java index 8552722db..f201270de 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/client/FhirClientProviderImpl.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/client/FhirClientProviderImpl.java @@ -8,7 +8,7 @@ import java.util.Objects; import java.util.stream.Collectors; -import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.fhir.client.FhirWebserviceClient; import org.highmed.fhir.client.FhirWebserviceClientJersey; import org.highmed.fhir.client.WebsocketClient; @@ -32,7 +32,7 @@ public class FhirClientProviderImpl private final Map websocketClientsBySubscriptionId = new HashMap<>(); private final FhirContext fhirContext; - private final ReferenceExtractor referenceExtractor; + private final ReferenceCleaner referenceCleaner; private final String localBaseUrl; private final int localReadTimeout; @@ -53,7 +53,7 @@ public class FhirClientProviderImpl private final KeyStore localWebsocketKeyStore; private final char[] localWebsocketKeyStorePassword; - public FhirClientProviderImpl(FhirContext fhirContext, ReferenceExtractor referenceExtractor, String localBaseUrl, + public FhirClientProviderImpl(FhirContext fhirContext, ReferenceCleaner referenceCleaner, String localBaseUrl, int localReadTimeout, int localConnectTimeout, KeyStore webserviceTrustStore, KeyStore webserviceKeyStore, char[] webserviceKeyStorePassword, int remoteReadTimeout, int remoteConnectTimeout, char[] remoteProxyPassword, String remoteProxyUsername, String remoteProxySchemeHostPort, @@ -61,7 +61,7 @@ public FhirClientProviderImpl(FhirContext fhirContext, ReferenceExtractor refere char[] localWebsocketKeyStorePassword) { this.fhirContext = fhirContext; - this.referenceExtractor = referenceExtractor; + this.referenceCleaner = referenceCleaner; this.localBaseUrl = localBaseUrl; this.localReadTimeout = localReadTimeout; this.localConnectTimeout = localConnectTimeout; @@ -124,12 +124,12 @@ private FhirWebserviceClient getClient(String webserviceUrl) if (localBaseUrl.equals(webserviceUrl)) client = new FhirWebserviceClientJersey(webserviceUrl, webserviceTrustStore, webserviceKeyStore, webserviceKeyStorePassword, null, null, null, localConnectTimeout, localReadTimeout, null, - fhirContext, referenceExtractor); + fhirContext, referenceCleaner); else client = new FhirWebserviceClientJersey(webserviceUrl, webserviceTrustStore, webserviceKeyStore, webserviceKeyStorePassword, remoteProxySchemeHostPort, remoteProxyUsername, remoteProxyPassword, remoteConnectTimeout, remoteReadTimeout, null, fhirContext, - referenceExtractor); + referenceCleaner); webserviceClientsByUrl.put(webserviceUrl, client); return client; @@ -172,7 +172,7 @@ public FhirWebserviceClient getRemoteWebserviceClient(IdType organizationReferen private Endpoint searchForEndpoint(String searchParameter, String searchParameterValue) { - Bundle resultSet = getLocalWebserviceClient().search(Organization.class, + Bundle resultSet = getLocalWebserviceClient().searchWithStrictHandling(Organization.class, Map.of(searchParameter, Collections.singletonList(searchParameterValue), "_include", Collections.singletonList("Organization:endpoint"))); @@ -210,12 +210,11 @@ public FhirWebserviceClient getRemoteWebserviceClient(String organizationIdentif } @Override - public WebsocketClient getLocalWebsocketClient(String subscriptionId) + public WebsocketClient getLocalWebsocketClient(Runnable reconnector, String subscriptionId) { if (!websocketClientsBySubscriptionId.containsKey(subscriptionId)) { - WebsocketClientTyrus client = new WebsocketClientTyrus(URI.create(localWebsocketUrl), - localWebsocketTrustStore, localWebsocketKeyStore, localWebsocketKeyStorePassword, subscriptionId); + WebsocketClientTyrus client = createWebsocketClient(reconnector, subscriptionId); websocketClientsBySubscriptionId.put(subscriptionId, client); return client; @@ -224,6 +223,12 @@ public WebsocketClient getLocalWebsocketClient(String subscriptionId) return websocketClientsBySubscriptionId.get(subscriptionId); } + protected WebsocketClientTyrus createWebsocketClient(Runnable reconnector, String subscriptionId) + { + return new WebsocketClientTyrus(reconnector, URI.create(localWebsocketUrl), localWebsocketTrustStore, + localWebsocketKeyStore, localWebsocketKeyStorePassword, subscriptionId); + } + @Override public void disconnectAll() { diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/client/FhirWebsocketClientProvider.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/client/FhirWebsocketClientProvider.java index 09793ee58..db733c528 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/client/FhirWebsocketClientProvider.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/client/FhirWebsocketClientProvider.java @@ -4,7 +4,7 @@ public interface FhirWebsocketClientProvider extends FhirWebserviceClientProvider { - WebsocketClient getLocalWebsocketClient(String subscriptionId); + WebsocketClient getLocalWebsocketClient(Runnable reconnector, String subscriptionId); void disconnectAll(); } diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/organization/OrganizationProviderImpl.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/organization/OrganizationProviderImpl.java index 2d2ad2582..fef4262f4 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/organization/OrganizationProviderImpl.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/organization/OrganizationProviderImpl.java @@ -75,7 +75,7 @@ private Stream searchForOrganizations(String system, String identi private Stream searchForOrganizations(String identifierValue) { - Bundle resultSet = clientProvider.getLocalWebserviceClient().search(Organization.class, + Bundle resultSet = clientProvider.getLocalWebserviceClient().searchWithStrictHandling(Organization.class, Map.of("active", Collections.singletonList("true"), "identifier", Collections.singletonList(identifierValue))); @@ -112,7 +112,7 @@ public List getRemoteOrganizations() @Override public Stream getOrganizationsByType(String type) { - Bundle resultSet = clientProvider.getLocalWebserviceClient().search(Organization.class, + Bundle resultSet = clientProvider.getLocalWebserviceClient().searchWithStrictHandling(Organization.class, Map.of("active", Collections.singletonList("true"), "type", Collections.singletonList(getDefaultTypeSystem() + "|" + type))); diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/task/TaskHelperImpl.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/task/TaskHelperImpl.java index ec6079fa7..e9694d6aa 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/task/TaskHelperImpl.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/task/TaskHelperImpl.java @@ -4,14 +4,19 @@ import java.util.stream.Stream; import org.highmed.dsf.fhir.variables.Outputs; +import org.hl7.fhir.r4.model.Base64BinaryType; import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Extension; +import org.hl7.fhir.r4.model.IntegerType; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.ParameterComponent; +import org.hl7.fhir.r4.model.Task.TaskOutputComponent; import org.hl7.fhir.r4.model.Type; +import org.hl7.fhir.r4.model.UnsignedIntType; import org.hl7.fhir.r4.model.UrlType; public class TaskHelperImpl implements TaskHelper @@ -64,6 +69,22 @@ public Stream getInputParameterUrlValues(Task task, String system, Stri return getInputParameterValues(task, system, code, UrlType.class); } + @Override + public Optional getFirstInputParameterByteValue(Task task, String system, String code) + { + return getInputParameterValues(task, system, code, Base64BinaryType.class).map(Base64BinaryType::getValue) + .findFirst(); + } + + @Override + public Stream getInputParameterWithExtension(Task task, String system, String code, String url) + { + return task.getInput().stream() + .filter(input -> input.getType().getCoding().stream() + .anyMatch(coding -> coding.getSystem().equals(system) && coding.getCode().equals(code))) + .filter(input -> input.getExtension().stream().anyMatch(extension -> extension.getUrl().equals(url))); + } + private Stream getInputParameterValues(Task task, String system, String code, Class type) { return task.getInput().stream().filter(c -> type.isInstance(c.getValue())) @@ -73,43 +94,59 @@ private Stream getInputParameterValues(Task task, String sys } @Override - public Stream getInputParameterWithExtension(Task task, String system, String code, - String url) + public ParameterComponent createInput(String system, String code, String value) { - return task.getInput().stream().filter(input -> input.getType().getCoding().stream() - .anyMatch(coding -> coding.getSystem().equals(system) && coding.getCode().equals(code))) - .filter(input -> input.getExtension().stream().anyMatch(extension -> extension.getUrl().equals(url))); + return new ParameterComponent(new CodeableConcept(new Coding(system, code, null)), new StringType(value)); + } + + @Override + public ParameterComponent createInput(String system, String code, boolean value) + { + return new ParameterComponent(new CodeableConcept(new Coding(system, code, null)), new BooleanType(value)); + } + + @Override + public ParameterComponent createInput(String system, String code, Reference reference) + { + return new ParameterComponent(new CodeableConcept(new Coding(system, code, null)), reference); + } + + @Override + public ParameterComponent createInput(String system, String code, byte[] bytes) + { + return new ParameterComponent(new CodeableConcept(new Coding(system, code, null)), new Base64BinaryType(bytes)); } @Override - public Task.ParameterComponent createInput(String system, String code, String value) + public ParameterComponent createInputUnsignedInt(String system, String code, int value) { - return new Task.ParameterComponent(new CodeableConcept(new Coding(system, code, null)), new StringType(value)); + return new ParameterComponent(new CodeableConcept(new Coding(system, code, null)), new UnsignedIntType(value)); } @Override - public Task.ParameterComponent createInput(String system, String code, boolean value) + public ParameterComponent createInput(String system, String code, int value) { - return new Task.ParameterComponent(new CodeableConcept(new Coding(system, code, null)), new BooleanType(value)); + return new ParameterComponent(new CodeableConcept(new Coding(system, code, null)), new IntegerType(value)); } @Override - public Task.ParameterComponent createInput(String system, String code, Reference reference) + public TaskOutputComponent createOutput(String system, String code, String value) { - return new Task.ParameterComponent(new CodeableConcept(new Coding(system, code, null)), reference); + return new TaskOutputComponent(new CodeableConcept(new Coding(system, code, null)), new StringType(value)); } @Override - public Task.TaskOutputComponent createOutput(String system, String code, String value) + public TaskOutputComponent createOutputUnsignedInt(String system, String code, int value) { - return new Task.TaskOutputComponent(new CodeableConcept(new Coding(system, code, null)), new StringType(value)); + return new TaskOutputComponent(new CodeableConcept(new Coding(system, code, null)), new UnsignedIntType(value)); } @Override public Task addOutputs(Task task, Outputs outputs) { - outputs.getOutputs().forEach(output -> { - Task.TaskOutputComponent component = createOutput(output.getSystem(), output.getCode(), output.getValue()); + outputs.getOutputs().forEach(output -> + { + TaskOutputComponent component = createOutput(output.getSystem(), output.getCode(), output.getValue()); if (output.hasExtension()) component.addExtension( diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/ExistingTaskLoader.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/ExistingTaskLoader.java new file mode 100644 index 000000000..2a5b5eb70 --- /dev/null +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/ExistingTaskLoader.java @@ -0,0 +1,88 @@ +package org.highmed.dsf.fhir.websocket; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.ws.rs.core.UriBuilder; + +import org.highmed.dsf.fhir.task.TaskHandler; +import org.highmed.fhir.client.FhirWebserviceClient; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.r4.model.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExistingTaskLoader +{ + private static final Logger logger = LoggerFactory.getLogger(ExistingTaskLoader.class); + + private static final String PARAM_LAST_UPDATED = "_lastUpdated"; + private static final String PARAM_COUNT = "_count"; + private static final String PARAM_PAGE = "_page"; + private static final String PARAM_SORT = "_sort"; + private static final int RESULT_PAGE_COUNT = 20; + + private final LastEventTimeIo lastEventTimeIo; + private final FhirWebserviceClient webserviceClient; + private final TaskHandler taskHandler; + + public ExistingTaskLoader(LastEventTimeIo lastEventTimeIo, TaskHandler taskHandler, + FhirWebserviceClient webserviceClient) + { + this.lastEventTimeIo = lastEventTimeIo; + this.taskHandler = taskHandler; + this.webserviceClient = webserviceClient; + } + + public void readExistingTasks(Map> searchCriteriaQueryParameters) + { + // executing search until call results in no more found tasks + while (doReadExistingTasks(searchCriteriaQueryParameters)) + ; + } + + private boolean doReadExistingTasks(Map> searchCriteriaQueryParameters) + { + Map> queryParams = new HashMap<>(searchCriteriaQueryParameters); + Optional readLastEventTime = lastEventTimeIo.readLastEventTime(); + + readLastEventTime.ifPresent(lastEventTime -> queryParams.put(PARAM_LAST_UPDATED, + Collections.singletonList("gt" + lastEventTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)))); + + queryParams.put(PARAM_COUNT, Collections.singletonList(String.valueOf(RESULT_PAGE_COUNT))); + queryParams.put(PARAM_PAGE, Collections.singletonList("1")); + queryParams.put(PARAM_SORT, Collections.singletonList(PARAM_LAST_UPDATED)); + + UriBuilder builder = UriBuilder.fromPath("Task"); + queryParams.forEach((k, v) -> builder.replaceQueryParam(k, v.toArray())); + + logger.debug("Executing search {}", builder.toString()); + Bundle bundle = webserviceClient.searchWithStrictHandling(Task.class, queryParams); + + if (bundle.getTotal() <= 0) + { + logger.debug("Result bundle.total <= 0"); + return false; + } + + for (BundleEntryComponent entry : bundle.getEntry()) + { + if (entry.getResource() instanceof Task) + { + Task task = (Task) entry.getResource(); + taskHandler.onTask(task); + lastEventTimeIo.writeLastEventTime(task.getAuthoredOn()); + } + else + logger.warn("Ignoring resource of type {}"); + } + + return true; + } +} diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/FhirConnector.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/FhirConnector.java old mode 100755 new mode 100644 index 4c9e74bb4..0d2d6378e --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/FhirConnector.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/FhirConnector.java @@ -1,189 +1,6 @@ package org.highmed.dsf.fhir.websocket; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Supplier; - -import org.highmed.dsf.fhir.client.FhirWebsocketClientProvider; -import org.highmed.dsf.fhir.task.TaskHandler; -import org.highmed.fhir.client.WebsocketClient; -import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Bundle.BundleType; -import org.hl7.fhir.r4.model.Subscription; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.event.ContextClosedEvent; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.context.event.EventListener; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.parser.IParser; -import ca.uhn.fhir.rest.api.Constants; - -public class FhirConnector implements InitializingBean +public interface FhirConnector { - private static final Logger logger = LoggerFactory.getLogger(FhirConnector.class); - - private final FhirWebsocketClientProvider clientProvider; - private final TaskHandler taskHandler; - private final LastEventTimeIo lastEventTimeIo; - private final FhirContext fhirContext; - - private final Map> subscriptionSearchParameter; - - public FhirConnector(FhirWebsocketClientProvider clientProvider, TaskHandler taskHandler, - LastEventTimeIo lastEventTimeIo, FhirContext fhirContext, String subscriptionSearchParameter) - { - this.clientProvider = clientProvider; - this.taskHandler = taskHandler; - this.lastEventTimeIo = lastEventTimeIo; - this.fhirContext = fhirContext; - this.subscriptionSearchParameter = parse(subscriptionSearchParameter, null); - } - - private static Map> parse(String queryParameters, String expectedPath) - { - if (expectedPath != null && !expectedPath.isBlank()) - { - UriComponents components = UriComponentsBuilder.fromUriString(queryParameters).build(); - if (!expectedPath.equals(components.getPath())) - throw new RuntimeException("Unexpected query parameters format '" + queryParameters + "'"); - else - return components.getQueryParams(); - } - else - { - UriComponents componentes = UriComponentsBuilder - .fromUriString(queryParameters.startsWith("?") ? queryParameters : "?" + queryParameters).build(); - - return componentes.getQueryParams(); - } - } - - @Override - public void afterPropertiesSet() throws Exception - { - Objects.requireNonNull(clientProvider, "clientProvider"); - Objects.requireNonNull(taskHandler, "taskHandler"); - Objects.requireNonNull(lastEventTimeIo, "lastEventTimeIo"); - Objects.requireNonNull(fhirContext, "fhirContext"); - } - - @EventListener({ ContextRefreshedEvent.class }) - public void onContextRefreshedEvent(ContextRefreshedEvent event) - { - Subscription subscription = retrieveWebsocketSubscription(); - - WebsocketClient client = clientProvider.getLocalWebsocketClient(subscription.getIdElement().getIdPart()); - - EventType eventType = toEventType(subscription.getChannel().getPayload()); - if (EventType.PING.equals(eventType)) - { - Map> subscriptionCriteria = parse(subscription.getCriteria(), "Task"); - setPingEventHandler(client, subscription.getIdElement().getIdPart(), subscriptionCriteria); - } - else - setResourceEventHandler(client, eventType); - - try - { - logger.info("Connecting websocket to loal FHIR server with subscription id {} ...", - subscription.getIdElement().getIdPart()); - client.connect(); - } - catch (Exception e) - { - logger.warn("Error while connecting websocket to local FHIR server", e); - throw e; - } - } - - private Subscription retrieveWebsocketSubscription() - { - try - { - Bundle bundle = clientProvider.getLocalWebserviceClient().search(Subscription.class, - subscriptionSearchParameter); - - if (!BundleType.SEARCHSET.equals(bundle.getType())) - throw new RuntimeException("Could not retrieve searchset for subscription search query " - + subscriptionSearchParameter + ", but got " + bundle.getType()); - if (bundle.getTotal() != 1) - throw new RuntimeException("Could not retrieve exactly one result for subscription search query " - + subscriptionSearchParameter); - if (!(bundle.getEntryFirstRep().getResource() instanceof Subscription)) - throw new RuntimeException("Could not retrieve exactly one Subscription for subscription search query " - + subscriptionSearchParameter + ", but got " - + bundle.getEntryFirstRep().getResource().getResourceType()); - - return (Subscription) bundle.getEntryFirstRep().getResource(); - } - catch (Exception e) - { - logger.warn("Error while retrieving websocket subscription from local FHIR server", e); - throw e; - } - } - - private EventType toEventType(String payload) - { - if (payload == null) - return EventType.PING; - - switch (payload) - { - case Constants.CT_FHIR_JSON: - case Constants.CT_FHIR_JSON_NEW: - return EventType.JSON; - case Constants.CT_FHIR_XML: - case Constants.CT_FHIR_XML_NEW: - return EventType.XML; - default: - throw new RuntimeException("Unsupportet subscription.payload " + payload); - } - } - - @EventListener({ ContextClosedEvent.class }) - public void onContextClosedEvent(ContextClosedEvent event) - { - clientProvider.disconnectAll(); - } - - private void setPingEventHandler(WebsocketClient client, String subscriptionIdPart, - Map> searchCriteriaQueryParameters) - { - PingEventHandler handler = new PingEventHandler(lastEventTimeIo, taskHandler, - clientProvider.getLocalWebserviceClient()); - client.setPingHandler(ping -> handler.onPing(ping, subscriptionIdPart, searchCriteriaQueryParameters)); - } - - private void setResourceEventHandler(WebsocketClient client, EventType eventType) - { - ResourceEventHandler handler = new ResourceEventHandler(taskHandler); - client.setDomainResourceHandler(handler::onResource, createParserFactory(eventType, fhirContext)); - } - - private Supplier createParserFactory(EventType eventType, FhirContext fhirContext) - { - switch (eventType) - { - case XML: - return () -> configureParser(fhirContext.newXmlParser()); - case JSON: - return () -> configureParser(fhirContext.newJsonParser()); - default: - throw new RuntimeException("EventType " + eventType + " not supported"); - } - } - - private IParser configureParser(IParser p) - { - p.setStripVersionsFromReferences(false); - p.setOverrideResourceIdWithBundleEntryFullUrl(false); - return p; - } -} + void connect(); +} \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/FhirConnectorImpl.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/FhirConnectorImpl.java new file mode 100755 index 000000000..f892ef168 --- /dev/null +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/FhirConnectorImpl.java @@ -0,0 +1,285 @@ +package org.highmed.dsf.fhir.websocket; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.function.Supplier; + +import org.highmed.dsf.fhir.client.FhirWebsocketClientProvider; +import org.highmed.dsf.fhir.task.TaskHandler; +import org.highmed.fhir.client.FhirWebserviceClient; +import org.highmed.fhir.client.WebsocketClient; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleType; +import org.hl7.fhir.r4.model.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; +import ca.uhn.fhir.rest.api.Constants; + +public class FhirConnectorImpl implements InitializingBean, FhirConnector +{ + private static final Logger logger = LoggerFactory.getLogger(FhirConnectorImpl.class); + + private final FhirWebsocketClientProvider clientProvider; + private final TaskHandler taskHandler; + private final LastEventTimeIo lastEventTimeIo; + private final FhirContext fhirContext; + + private final long retrySleepMillis; + private final int maxRetries; + private final Map> subscriptionSearchParameter; + + public FhirConnectorImpl(FhirWebsocketClientProvider clientProvider, TaskHandler taskHandler, + LastEventTimeIo lastEventTimeIo, FhirContext fhirContext, String subscriptionSearchParameter, + long retrySleepMillis, int maxRetries) + { + this.clientProvider = clientProvider; + this.taskHandler = taskHandler; + this.lastEventTimeIo = lastEventTimeIo; + this.fhirContext = fhirContext; + this.subscriptionSearchParameter = parse(subscriptionSearchParameter, null); + this.retrySleepMillis = retrySleepMillis; + this.maxRetries = maxRetries; + } + + private static Map> parse(String queryParameters, String expectedPath) + { + if (expectedPath != null && !expectedPath.isBlank()) + { + UriComponents components = UriComponentsBuilder.fromUriString(queryParameters).build(); + if (!expectedPath.equals(components.getPath())) + throw new RuntimeException("Unexpected query parameters format '" + queryParameters + "'"); + else + return components.getQueryParams(); + } + else + { + UriComponents componentes = UriComponentsBuilder + .fromUriString(queryParameters.startsWith("?") ? queryParameters : "?" + queryParameters).build(); + + return componentes.getQueryParams(); + } + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(clientProvider, "clientProvider"); + Objects.requireNonNull(taskHandler, "taskHandler"); + Objects.requireNonNull(lastEventTimeIo, "lastEventTimeIo"); + Objects.requireNonNull(fhirContext, "fhirContext"); + } + + @Override + public void connect() + { + logger.debug("Retrieving Subscription and connecting to websocket"); + + CompletableFuture.supplyAsync(this::retrieveWebsocketSubscription, Executors.newSingleThreadExecutor()) + .thenApply(this::loadExistingTasks).thenAccept(this::connectWebsocket).exceptionally(this::onError); + } + + private Subscription retrieveWebsocketSubscription() + { + if (maxRetries >= 0) + return retry(() -> doRetrieveWebsocketSubscription()); + else + return retryForever(() -> doRetrieveWebsocketSubscription()); + } + + private Subscription retry(Supplier supplier) + { + RuntimeException lastException = null; + for (int retryCounter = 0; retryCounter <= maxRetries; retryCounter++) + { + try + { + return supplier.get(); + } + catch (RuntimeException e) + { + if (retryCounter < maxRetries) + { + logger.warn( + "Error while retrieving websocket subscription ({}), trying again in {} ms (retry {} of {})", + e.getMessage(), retrySleepMillis, retryCounter + 1, maxRetries); + try + { + Thread.sleep(retrySleepMillis); + } + catch (InterruptedException e1) + { + } + } + + lastException = e; + } + } + + logger.error("Error while retrieving websocket subscription ({}), giving up", lastException.getMessage()); + throw lastException; + } + + private Subscription retryForever(Supplier supplier) + { + for (int retryCounter = 1; true; retryCounter++) + { + try + { + return supplier.get(); + } + catch (RuntimeException e) + { + logger.warn("Error while retrieving websocket subscription ({}), trying again in {} ms (retry {})", + e.getMessage(), retrySleepMillis, retryCounter); + try + { + Thread.sleep(retrySleepMillis); + } + catch (InterruptedException e1) + { + } + } + } + } + + private Subscription doRetrieveWebsocketSubscription() + { + logger.debug("Retrieving websocket subscription"); + + Bundle bundle = clientProvider.getLocalWebserviceClient().searchWithStrictHandling(Subscription.class, + subscriptionSearchParameter); + + if (!BundleType.SEARCHSET.equals(bundle.getType())) + throw new RuntimeException("Could not retrieve searchset for subscription search query " + + subscriptionSearchParameter + ", but got " + bundle.getType()); + if (bundle.getTotal() != 1) + throw new RuntimeException("Could not retrieve exactly one result for subscription search query " + + subscriptionSearchParameter); + if (!(bundle.getEntryFirstRep().getResource() instanceof Subscription)) + throw new RuntimeException("Could not retrieve exactly one Subscription for subscription search query " + + subscriptionSearchParameter + ", but got " + + bundle.getEntryFirstRep().getResource().getResourceType()); + + Subscription subscription = (Subscription) bundle.getEntryFirstRep().getResource(); + logger.debug("Subscription with id {} found", subscription.getIdElement().getIdPart()); + + return subscription; + } + + private Subscription loadExistingTasks(Subscription subscription) + { + logger.debug("Downloading existing Task resources"); + + FhirWebserviceClient webserviceClient = clientProvider.getLocalWebserviceClient(); + ExistingTaskLoader existingTaskLoader = new ExistingTaskLoader(lastEventTimeIo, taskHandler, webserviceClient); + Map> subscriptionCriteria = parse(subscription.getCriteria(), "Task"); + existingTaskLoader.readExistingTasks(subscriptionCriteria); + + return subscription; + } + + private void connectWebsocket(Subscription subscription) + { + logger.debug("Connecting to websocket"); + + WebsocketClient client = clientProvider.getLocalWebsocketClient(() -> connect(), + subscription.getIdElement().getIdPart()); + + EventType eventType = toEventType(subscription.getChannel().getPayload()); + if (EventType.PING.equals(eventType)) + { + Map> subscriptionCriteria = parse(subscription.getCriteria(), "Task"); + setPingEventHandler(client, subscription.getIdElement().getIdPart(), subscriptionCriteria); + } + else + setResourceEventHandler(client, eventType); + + try + { + logger.info("Connecting websocket to local FHIR server with subscription id {}", + subscription.getIdElement().getIdPart()); + client.connect(); + } + catch (Exception e) + { + logger.warn("Error while connecting websocket to local FHIR server", e); + throw e; + } + } + + private Void onError(Throwable t) + { + logger.error("Error while connecting to websocket", t); + return null; + } + + private EventType toEventType(String payload) + { + if (payload == null) + return EventType.PING; + + switch (payload) + { + case Constants.CT_FHIR_JSON: + case Constants.CT_FHIR_JSON_NEW: + return EventType.JSON; + case Constants.CT_FHIR_XML: + case Constants.CT_FHIR_XML_NEW: + return EventType.XML; + default: + throw new RuntimeException("Unsupportet subscription.payload " + payload); + } + } + + @EventListener({ ContextClosedEvent.class }) + public void onContextClosedEvent(ContextClosedEvent event) + { + clientProvider.disconnectAll(); + } + + protected void setPingEventHandler(WebsocketClient client, String subscriptionIdPart, + Map> searchCriteriaQueryParameters) + { + FhirWebserviceClient webserviceClient = clientProvider.getLocalWebserviceClient(); + PingEventHandler handler = new PingEventHandler( + new ExistingTaskLoader(lastEventTimeIo, taskHandler, webserviceClient)); + client.setPingHandler(ping -> handler.onPing(ping, subscriptionIdPart, searchCriteriaQueryParameters)); + } + + protected void setResourceEventHandler(WebsocketClient client, EventType eventType) + { + ResourceEventHandler handler = new ResourceEventHandler(lastEventTimeIo, taskHandler); + client.setDomainResourceHandler(handler::onResource, createParserFactory(eventType, fhirContext)); + } + + private Supplier createParserFactory(EventType eventType, FhirContext fhirContext) + { + switch (eventType) + { + case XML: + return () -> configureParser(fhirContext.newXmlParser()); + case JSON: + return () -> configureParser(fhirContext.newJsonParser()); + default: + throw new RuntimeException("EventType " + eventType + " not supported"); + } + } + + private IParser configureParser(IParser p) + { + p.setStripVersionsFromReferences(false); + p.setOverrideResourceIdWithBundleEntryFullUrl(false); + return p; + } +} diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/LastEventTimeIo.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/LastEventTimeIo.java index 6352f936a..b88a1da1f 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/LastEventTimeIo.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/LastEventTimeIo.java @@ -5,7 +5,10 @@ import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.time.LocalDateTime; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Date; import java.util.Objects; import java.util.Optional; @@ -16,6 +19,7 @@ public class LastEventTimeIo implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(LastEventTimeIo.class); + private static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ISO_LOCAL_DATE_TIME; private final Path lastEventTimeFile; @@ -32,37 +36,53 @@ public void afterPropertiesSet() throws Exception if (Files.exists(lastEventTimeFile) && !Files.isWritable(lastEventTimeFile)) throw new IOException("Last event time file at " + lastEventTimeFile.toString() + " not writable"); else if (!Files.isWritable(lastEventTimeFile.getParent())) - throw new IOException( - "Last event time file at " + lastEventTimeFile.toString() + " not existing and parent not writable"); + throw new IOException("Last event time file at " + lastEventTimeFile.toString() + + " not existing and parent not writable"); } public Optional readLastEventTime() { try { - return Optional.of( - LocalDateTime.parse(Files.readString(lastEventTimeFile), DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + Optional value = Optional + .of(LocalDateTime.parse(Files.readString(lastEventTimeFile), DATE_TIME_FORMAT)); + + logger.debug("Read {} from {}", value.get(), lastEventTimeFile); + return value; + } + catch (DateTimeParseException e) + { + logger.warn("Error while reading last event time file: {} {}", e.getClass().getName(), e.getMessage()); + return Optional.empty(); } catch (IOException e) { - logger.warn("Error while reading last event time file: {}", e.getMessage()); + logger.warn("Error while reading last event time file: {} {}", e.getClass().getName(), e.getMessage()); return Optional.empty(); } } - public LocalDateTime writeLastEventTime(LocalDateTime time) + public LocalDateTime writeLastEventTime(LocalDateTime localDateTime) { try { - Files.writeString(lastEventTimeFile, time.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME), - StandardOpenOption.TRUNCATE_EXISTING); + String value = localDateTime.format(DATE_TIME_FORMAT); + logger.debug("Writing {} to {}", value, lastEventTimeFile); + Files.writeString(lastEventTimeFile, value, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); } catch (IOException e) { - logger.warn("Error while writing last event time file: {}", e.getMessage()); + logger.warn("Error while writing last event time file: {} {}", e.getClass().getName(), e.getMessage()); } - return time; + return localDateTime; + } + + public void writeLastEventTime(Date authoredOn) + { + LocalDateTime localDateTime = LocalDateTime.ofInstant(authoredOn.toInstant(), ZoneId.systemDefault()); + writeLastEventTime(localDateTime); } } diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/PingEventHandler.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/PingEventHandler.java index 27527c5f4..391254912 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/PingEventHandler.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/PingEventHandler.java @@ -1,51 +1,20 @@ package org.highmed.dsf.fhir.websocket; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import org.highmed.dsf.fhir.task.TaskHandler; -import org.highmed.fhir.client.FhirWebserviceClient; -import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; -import org.hl7.fhir.r4.model.Task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -public class PingEventHandler implements InitializingBean +public class PingEventHandler { private static final Logger logger = LoggerFactory.getLogger(PingEventHandler.class); - private static final String PARAM_LAST_UPDATE = "_lastUpdated"; - private static final String PARAM_COUNT = "_count"; - private static final String PARAM_PAGE = "_page"; - private static final String PARAM_SORT = "_sort"; - private static final int RESULT_PAGE_COUNT = 20; + private final ExistingTaskLoader taskLoader; - private final LastEventTimeIo lastEventTimeIo; - private final TaskHandler taskHandler; - private final FhirWebserviceClient webserviceClient; - - public PingEventHandler(LastEventTimeIo lastEventTimeIo, TaskHandler taskHandler, FhirWebserviceClient webserviceClient) - { - this.lastEventTimeIo = lastEventTimeIo; - this.taskHandler = taskHandler; - this.webserviceClient = webserviceClient; - } - - @Override - public void afterPropertiesSet() throws Exception + public PingEventHandler(ExistingTaskLoader taskLoader) { - Objects.requireNonNull(lastEventTimeIo, "lastEventTimeIo"); - Objects.requireNonNull(taskHandler, "taskHandler"); - Objects.requireNonNull(webserviceClient, "webserviceClient"); + this.taskLoader = taskLoader; } public void onPing(String ping, String subscriptionIdPart, Map> searchCriteriaQueryParameters) @@ -58,48 +27,6 @@ public void onPing(String ping, String subscriptionIdPart, Map readLastEventTime = lastEventTimeIo.readLastEventTime(); - - Map> queryParams = new HashMap<>(searchCriteriaQueryParameters); - if (readLastEventTime.isPresent()) - { - queryParams.put(PARAM_LAST_UPDATE, - Arrays.asList("gt" + readLastEventTime.get().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME))); - queryParams.put(PARAM_COUNT, Arrays.asList(String.valueOf(RESULT_PAGE_COUNT))); - } - else - { - queryParams.put(PARAM_COUNT, Arrays.asList(String.valueOf(Integer.MAX_VALUE))); - } - queryParams.put(PARAM_PAGE, Arrays.asList("1")); - queryParams.put(PARAM_SORT, Arrays.asList(PARAM_LAST_UPDATE)); - - Bundle bundle = webserviceClient.search(Task.class, queryParams); - lastEventTimeIo.writeLastEventTime(LocalDateTime.now()); - - if (bundle.getTotal() <= 0) - { - logger.warn("Result bundle.total <= 0, ignoring ping"); - return; - } - - for (BundleEntryComponent entry : bundle.getEntry()) - { - if (entry.getResource() instanceof Task) - { - Task task = (Task) entry.getResource(); - taskHandler.onTask(task); - - lastEventTimeIo.writeLastEventTime(LocalDateTime.ofInstant(task.getMeta().getLastUpdated().toInstant(), ZoneId.systemDefault())); - } - else - logger.warn("Ignoring resource of type {}"); - } - - if (bundle.getTotal() > RESULT_PAGE_COUNT) - { - logger.warn("Result bundle.total > {}, calling onPing again", RESULT_PAGE_COUNT); - onPing(ping, subscriptionIdPart, searchCriteriaQueryParameters); - } + taskLoader.readExistingTasks(searchCriteriaQueryParameters); } } diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/ResourceEventHandler.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/ResourceEventHandler.java index c38858504..cdc033f01 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/ResourceEventHandler.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/fhir/websocket/ResourceEventHandler.java @@ -1,39 +1,36 @@ package org.highmed.dsf.fhir.websocket; -import java.util.Objects; - import org.highmed.dsf.fhir.task.TaskHandler; import org.hl7.fhir.r4.model.DomainResource; import org.hl7.fhir.r4.model.Task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; import ca.uhn.fhir.model.api.annotation.ResourceDef; -public class ResourceEventHandler implements InitializingBean +public class ResourceEventHandler { private static final Logger logger = LoggerFactory.getLogger(ResourceEventHandler.class); private final TaskHandler taskHandler; + private final LastEventTimeIo lastEventTimeIo; - public ResourceEventHandler(TaskHandler taskHandler) + public ResourceEventHandler(LastEventTimeIo lastEventTimeIo, TaskHandler taskHandler) { + this.lastEventTimeIo = lastEventTimeIo; this.taskHandler = taskHandler; } - @Override - public void afterPropertiesSet() throws Exception - { - Objects.requireNonNull(taskHandler, "taskHandler"); - } - public void onResource(DomainResource resource) { logger.trace("Resource of type {} received", resource.getClass().getAnnotation(ResourceDef.class).name()); if (resource instanceof Task) - taskHandler.onTask((Task) resource); + { + Task task = (Task) resource; + taskHandler.onTask(task); + lastEventTimeIo.writeLastEventTime(task.getAuthoredOn()); + } else logger.warn("Ignoring resource of type {}"); } diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/openehr/client/OpenEhrClientProviderImpl.java b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/openehr/client/OpenEhrClientProviderImpl.java index 99c302cbd..2549f533e 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/openehr/client/OpenEhrClientProviderImpl.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/org/highmed/dsf/openehr/client/OpenEhrClientProviderImpl.java @@ -2,8 +2,8 @@ import java.util.Objects; -import org.highmed.openehr.client.OpenehrWebserviceClient; -import org.highmed.openehr.client.OpenehrWebserviceClientJersey; +import org.highmed.openehr.client.OpenEhrWebserviceClient; +import org.highmed.openehr.client.OpenEhrWebserviceClientJersey; import org.springframework.beans.factory.InitializingBean; import com.fasterxml.jackson.databind.ObjectMapper; @@ -46,9 +46,9 @@ public void afterPropertiesSet() throws Exception } @Override - public OpenehrWebserviceClient getWebserviceClient() + public OpenEhrWebserviceClient getWebserviceClient() { - return new OpenehrWebserviceClientJersey(baseUrl, basicAuthUsername, basicAuthPassword, connectionTimeout, + return new OpenEhrWebserviceClientJersey(baseUrl, basicAuthUsername, basicAuthPassword, connectionTimeout, readTimeout, objectMapper); } diff --git a/dsf-bpe/dsf-bpe-server/src/main/resources/db/camunda/postgres_engine_7.12_to_7.13.sql b/dsf-bpe/dsf-bpe-server/src/main/resources/db/camunda/postgres_engine_7.12_to_7.13.sql new file mode 100644 index 000000000..2625534b3 --- /dev/null +++ b/dsf-bpe/dsf-bpe-server/src/main/resources/db/camunda/postgres_engine_7.12_to_7.13.sql @@ -0,0 +1,63 @@ +-- +-- Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH +-- under one or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information regarding copyright +-- ownership. Camunda licenses this file to you under the Apache License, +-- Version 2.0; you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +insert into ACT_GE_SCHEMA_LOG +values ('200', CURRENT_TIMESTAMP, '7.13.0'); + +-- https://jira.camunda.com/browse/CAM-10953 +create index ACT_IDX_HI_VAR_PI_NAME_TYPE on ACT_HI_VARINST(PROC_INST_ID_, NAME_, VAR_TYPE_); + + +-- https://app.camunda.com/jira/browse/CAM-10784 +ALTER TABLE ACT_HI_JOB_LOG + ADD HOSTNAME_ varchar(255) default null; + +-- https://jira.camunda.com/browse/CAM-10378 +ALTER TABLE ACT_RU_JOB + ADD FAILED_ACT_ID_ varchar(255); + +ALTER TABLE ACT_HI_JOB_LOG + ADD FAILED_ACT_ID_ varchar(255); + +ALTER TABLE ACT_RU_INCIDENT + ADD FAILED_ACTIVITY_ID_ varchar(255); + +ALTER TABLE ACT_HI_INCIDENT + ADD FAILED_ACTIVITY_ID_ varchar(255); + +-- https://jira.camunda.com/browse/CAM-11616 +ALTER TABLE ACT_RU_AUTHORIZATION + ADD REMOVAL_TIME_ timestamp; +create index ACT_IDX_AUTH_RM_TIME on ACT_RU_AUTHORIZATION(REMOVAL_TIME_); + +-- https://jira.camunda.com/browse/CAM-11616 +ALTER TABLE ACT_RU_AUTHORIZATION + ADD ROOT_PROC_INST_ID_ varchar(64); +create index ACT_IDX_AUTH_ROOT_PI on ACT_RU_AUTHORIZATION(ROOT_PROC_INST_ID_); + +-- https://jira.camunda.com/browse/CAM-11188 +ALTER TABLE ACT_RU_JOBDEF + ADD DEPLOYMENT_ID_ varchar(64); + + +-- https://jira.camunda.com/browse/CAM-10978 + +ALTER TABLE ACT_RU_VARIABLE + ADD PROC_DEF_ID_ varchar(64); + +ALTER TABLE ACT_HI_DETAIL + ADD INITIAL_ boolean; diff --git a/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.camunda_engine.changelog-0.2.0.xml b/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.camunda_engine.changelog-0.2.0.xml new file mode 100644 index 000000000..ebbdd131f --- /dev/null +++ b/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.camunda_engine.changelog-0.2.0.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.changelog.xml b/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.changelog.xml index 6295cdbe4..2e32ed8f3 100644 --- a/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.changelog.xml +++ b/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.changelog.xml @@ -9,4 +9,6 @@ + + \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-server/src/test/java/org/highmed/dsf/fhir/websocket/LastEventTimeIoTest.java b/dsf-bpe/dsf-bpe-server/src/test/java/org/highmed/dsf/fhir/websocket/LastEventTimeIoTest.java new file mode 100644 index 000000000..0a1ecc6ec --- /dev/null +++ b/dsf-bpe/dsf-bpe-server/src/test/java/org/highmed/dsf/fhir/websocket/LastEventTimeIoTest.java @@ -0,0 +1,57 @@ +package org.highmed.dsf.fhir.websocket; + +import static org.junit.Assert.*; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.UUID; + +import org.junit.Test; + +public class LastEventTimeIoTest +{ + @Test + public void testWriteRead() throws Exception + { + Path lastEventTimeFile = Paths.get("target", UUID.randomUUID().toString()); + try + { + LastEventTimeIo io = new LastEventTimeIo(lastEventTimeFile); + + LocalDateTime written = io.writeLastEventTime(LocalDateTime.now()); + assertNotNull(written); + + Optional read = io.readLastEventTime(); + assertTrue(read.isPresent()); + + assertEquals(written, read.get()); + } + finally + { + Files.deleteIfExists(lastEventTimeFile); + } + } + + @Test + public void testReadNotExistingFile() throws Exception + { + Path lastEventTimeFile = Paths.get("target", UUID.randomUUID().toString()); + LastEventTimeIo io = new LastEventTimeIo(lastEventTimeFile); + + assertFalse(io.readLastEventTime().isPresent()); + } + + @Test + public void testReadEmptyFile() throws Exception + { + Path lastEventTimeFile = Paths.get("target", UUID.randomUUID().toString()); + Files.createFile(lastEventTimeFile); + + LastEventTimeIo io = new LastEventTimeIo(lastEventTimeFile); + + assertFalse(io.readLastEventTime().isPresent()); + } +} diff --git a/dsf-bpe/dsf-bpe-webservice-client/pom.xml b/dsf-bpe/dsf-bpe-webservice-client/pom.xml index 602a5f81d..c6be59b0b 100755 --- a/dsf-bpe/dsf-bpe-webservice-client/pom.xml +++ b/dsf-bpe/dsf-bpe-webservice-client/pom.xml @@ -7,7 +7,7 @@ org.highmed.dsf dsf-bpe-pom - 0.1.0 + 0.2.0 diff --git a/dsf-bpe/pom.xml b/dsf-bpe/pom.xml index 24082212d..3d3c97297 100755 --- a/dsf-bpe/pom.xml +++ b/dsf-bpe/pom.xml @@ -8,7 +8,7 @@ org.highmed.dsf dsf-pom - 0.1.0 + 0.2.0 @@ -25,7 +25,7 @@ - 7.12.0 + 7.13.0 @@ -120,6 +120,7 @@ dsf-fhir-webservice-client ${project.version} + org.highmed.dsf dsf-openehr-model @@ -142,6 +143,33 @@ ${project.version} + + org.highmed.dsf + dsf-pseudonymization-medic + ${project.version} + + + org.highmed.dsf + dsf-pseudonymization-ttp + ${project.version} + + + + org.highmed.dsf + dsf-mpi-client + ${project.version} + + + org.highmed.dsf + dsf-mpi-client-pdq + ${project.version} + + + org.highmed.dsf + dsf-mpi-client-stub + ${project.version} + + org.camunda.bpm camunda-bom @@ -149,11 +177,6 @@ import pom - - org.mybatis - mybatis - 3.5.3 - \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/docker-build-tag-push.bat b/dsf-docker-test-setup-3medic-ttp/docker-build-tag-push.bat index 5a0047cf3..a8b18d83d 100755 --- a/dsf-docker-test-setup-3medic-ttp/docker-build-tag-push.bat +++ b/dsf-docker-test-setup-3medic-ttp/docker-build-tag-push.bat @@ -4,21 +4,21 @@ REM For installing / starting local registry at registry:5000 see test_setup.txt REM See https://docs.docker.com/registry/insecure/ for infos on pushing to / pulling from a local insecure registry echo highmed/bpe ... -docker build -t highmed/bpe ..\dsf-bpe\dsf-bpe-server-jetty\docker +docker build --pull -t highmed/bpe ..\dsf-bpe\dsf-bpe-server-jetty\docker docker tag highmed/bpe:latest registry:5000/highmed/bpe:latest docker push registry:5000/highmed/bpe echo highmed/bpe_proxy ... -docker build -t highmed/bpe_proxy ..\dsf-docker\bpe_proxy +docker build --pull -t highmed/bpe_proxy ..\dsf-docker\bpe_proxy docker tag highmed/bpe_proxy:latest registry:5000/highmed/bpe_proxy:latest docker push registry:5000/highmed/bpe_proxy echo highmed/fhir ... -docker build -t highmed/fhir ..\dsf-fhir\dsf-fhir-server-jetty\docker +docker build --pull -t highmed/fhir ..\dsf-fhir\dsf-fhir-server-jetty\docker docker tag highmed/fhir:latest registry:5000/highmed/fhir:latest docker push registry:5000/highmed/fhir echo highmed/fhir_proxy ... -docker build -t highmed/fhir_proxy ..\dsf-docker\fhir_proxy +docker build --pull -t highmed/fhir_proxy ..\dsf-docker\fhir_proxy docker tag highmed/fhir_proxy:latest registry:5000/highmed/fhir_proxy:latest docker push registry:5000/highmed/fhir_proxy diff --git a/dsf-docker-test-setup-3medic-ttp/docker-build-tag-push.sh b/dsf-docker-test-setup-3medic-ttp/docker-build-tag-push.sh index 23e8d0a33..c28d4b296 100755 --- a/dsf-docker-test-setup-3medic-ttp/docker-build-tag-push.sh +++ b/dsf-docker-test-setup-3medic-ttp/docker-build-tag-push.sh @@ -4,21 +4,21 @@ # See https://docs.docker.com/registry/insecure/ for infos on pushing to / pulling from a local insecure registry echo highmed/bpe ... -docker build -t highmed/bpe ../dsf-bpe/dsf-bpe-server-jetty/docker +docker build --pull -t highmed/bpe ../dsf-bpe/dsf-bpe-server-jetty/docker docker tag highmed/bpe:latest registry:5000/highmed/bpe:latest docker push registry:5000/highmed/bpe echo highmed/bpe_proxy ... -docker build -t highmed/bpe_proxy ../dsf-docker/bpe_proxy +docker build --pull -t highmed/bpe_proxy ../dsf-docker/bpe_proxy docker tag highmed/bpe_proxy:latest registry:5000/highmed/bpe_proxy:latest docker push registry:5000/highmed/bpe_proxy echo highmed/fhir ... -docker build -t highmed/fhir ../dsf-fhir/dsf-fhir-server-jetty/docker +docker build --pull -t highmed/fhir ../dsf-fhir/dsf-fhir-server-jetty/docker docker tag highmed/fhir:latest registry:5000/highmed/fhir:latest docker push registry:5000/highmed/fhir echo highmed/fhir_proxy ... -docker build -t highmed/fhir_proxy ../dsf-docker/fhir_proxy +docker build --pull -t highmed/fhir_proxy ../dsf-docker/fhir_proxy docker tag highmed/fhir_proxy:latest registry:5000/highmed/fhir_proxy:latest docker push registry:5000/highmed/fhir_proxy diff --git a/dsf-docker-test-setup-3medic-ttp/highmed.yml b/dsf-docker-test-setup-3medic-ttp/highmed.yml index 7e6a554bb..fd671aa04 100755 --- a/dsf-docker-test-setup-3medic-ttp/highmed.yml +++ b/dsf-docker-test-setup-3medic-ttp/highmed.yml @@ -67,9 +67,9 @@ append: true - name: Download docker-compose get_url: - url: https://github.com/docker/compose/releases/download/1.25.4/docker-compose-Linux-x86_64 + url: https://github.com/docker/compose/releases/download/1.26.0/docker-compose-Linux-x86_64 dest: /usr/local/bin/docker-compose - checksum: sha256:542e93b1d5106d2769b325f60ba9a0ba087bb96e30dc2c1cb026f0cb642e9aed + checksum: sha256:ff6816932a57eab448798105926adbe4363b82f217802b105ade2edad95706cb mode: '777' - name: update /etc/hosts file blockinfile: diff --git a/dsf-docker-test-setup-3medic-ttp/medic1/bpe/.rsync-filter b/dsf-docker-test-setup-3medic-ttp/medic1/bpe/.rsync-filter index 716786e6e..a87a3a1cd 100644 --- a/dsf-docker-test-setup-3medic-ttp/medic1/bpe/.rsync-filter +++ b/dsf-docker-test-setup-3medic-ttp/medic1/bpe/.rsync-filter @@ -1,5 +1,6 @@ - .rsync-filter - app/conf/.gitignore +- app/last_event/README.md - app/log/README.md - app/plugin/.gitignore - proxy/ssl/.gitignore \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/conf/config.properties b/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/conf/config.properties index a7ae8f282..d0d88c5ab 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/conf/config.properties +++ b/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/conf/config.properties @@ -16,10 +16,10 @@ org.highmed.dsf.bpe.fhir.organization.identifier.localValue=Test_MeDIC_1 org.highmed.dsf.bpe.fhir.local.webservice.baseUrl=https://medic1/fhir org.highmed.dsf.bpe.fhir.local.webservice.keystore.p12file=conf/medic1-client_certificate.p12 org.highmed.dsf.bpe.fhir.local.webservice.keystore.password=password -org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=2000 +org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=10000 org.highmed.dsf.bpe.fhir.local.webservice.connectTimeout=500 -org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=5000 +org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=10000 org.highmed.dsf.bpe.fhir.remote.webservice.connectTimeout=2000 #org.highmed.dsf.bpe.fhir.remote.webservice.proxy.password= #org.highmed.dsf.bpe.fhir.remote.webservice.proxy.username= @@ -31,6 +31,8 @@ org.highmed.dsf.bpe.fhir.local.websocket.keystore.password=password org.highmed.dsf.bpe.fhir.task.subscription.searchParameter=?criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson org.highmed.dsf.bpe.fhir.task.subscription.lastEventTimeFile=last_event/time.file +#org.highmed.dsf.bpe.fhir.task.subscription.retrySleepMillis=5000 +#org.highmed.dsf.bpe.fhir.task.subscription.maxRetries=-1 org.highmed.dsf.bpe.openehr.webservice.baseUrl=https://openehr/rest/openehr/v1 org.highmed.dsf.bpe.openehr.webservice.basicAuthUsername=username @@ -38,4 +40,16 @@ org.highmed.dsf.bpe.openehr.webservice.basicAuthPassword=password org.highmed.dsf.bpe.openehr.webservice.connectionTimeout=1500 org.highmed.dsf.bpe.openehr.webservice.readTimeout=2500 +#org.highmed.dsf.bpe.mpi.webservice.factory.class=org.highmed.mpi.client.pdq.MasterPatientIndexClientPdqFactory +#org.highmed.dsf.bpe.mpi.pdq.webservice.host= +#org.highmed.dsf.bpe.mpi.pdq.webservice.port= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.path= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.password= +#org.highmed.dsf.bpe.mpi.pdq.sender.application= +#org.highmed.dsf.bpe.mpi.pdq.sender.facility= +#org.highmed.dsf.bpe.mpi.pdq.receiver.application= +#org.highmed.dsf.bpe.mpi.pdq.receiver.facility= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.namespaceId= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.universalId= + org.highmed.dsf.bpe.cors.origins= \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/conf/log4j2.xml b/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/conf/log4j2.xml index 7006f1aaf..016d8e200 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/conf/log4j2.xml +++ b/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/conf/log4j2.xml @@ -34,15 +34,8 @@ - - - - - + - - - diff --git a/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/last_event/README.md b/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/last_event/README.md new file mode 100644 index 000000000..12fefbfaa --- /dev/null +++ b/dsf-docker-test-setup-3medic-ttp/medic1/bpe/app/last_event/README.md @@ -0,0 +1 @@ +empty directory for last-event time.file \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/medic1/bpe/docker-compose.yml b/dsf-docker-test-setup-3medic-ttp/medic1/bpe/docker-compose.yml index 97bf3acd5..f11a6c301 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic1/bpe/docker-compose.yml +++ b/dsf-docker-test-setup-3medic-ttp/medic1/bpe/docker-compose.yml @@ -35,6 +35,9 @@ services: - type: bind source: ./app/log target: /opt/bpe/log + - type: bind + source: ./app/last_event + target: /opt/bpe/last_event environment: TZ: Europe/Berlin networks: diff --git a/dsf-docker-test-setup-3medic-ttp/medic1/fhir/app/conf/log4j2.xml b/dsf-docker-test-setup-3medic-ttp/medic1/fhir/app/conf/log4j2.xml index 61f365c4c..33426c0b6 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic1/fhir/app/conf/log4j2.xml +++ b/dsf-docker-test-setup-3medic-ttp/medic1/fhir/app/conf/log4j2.xml @@ -49,15 +49,8 @@ - - - - - + - - - diff --git a/dsf-docker-test-setup-3medic-ttp/medic1/upload.yml b/dsf-docker-test-setup-3medic-ttp/medic1/upload.yml index 42ed3bae3..35b6b9641 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic1/upload.yml +++ b/dsf-docker-test-setup-3medic-ttp/medic1/upload.yml @@ -30,6 +30,13 @@ group: '2202' mode: '2775' become: true + - name: Set bpe/app/last_event permissions + file: + path: /opt/highmed/bpe/app/last_event + owner: '{{ user }}' + group: '2202' + mode: '2775' + become: true - name: Set fhir/app/log permissions file: path: /opt/highmed/fhir/app/log diff --git a/dsf-docker-test-setup-3medic-ttp/medic2/bpe/.rsync-filter b/dsf-docker-test-setup-3medic-ttp/medic2/bpe/.rsync-filter index 716786e6e..a87a3a1cd 100644 --- a/dsf-docker-test-setup-3medic-ttp/medic2/bpe/.rsync-filter +++ b/dsf-docker-test-setup-3medic-ttp/medic2/bpe/.rsync-filter @@ -1,5 +1,6 @@ - .rsync-filter - app/conf/.gitignore +- app/last_event/README.md - app/log/README.md - app/plugin/.gitignore - proxy/ssl/.gitignore \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/conf/config.properties b/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/conf/config.properties index 5922d5d4b..4e16c97d7 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/conf/config.properties +++ b/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/conf/config.properties @@ -16,10 +16,10 @@ org.highmed.dsf.bpe.fhir.organization.identifier.localValue=Test_MeDIC_2 org.highmed.dsf.bpe.fhir.local.webservice.baseUrl=https://medic2/fhir org.highmed.dsf.bpe.fhir.local.webservice.keystore.p12file=conf/medic2-client_certificate.p12 org.highmed.dsf.bpe.fhir.local.webservice.keystore.password=password -org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=2000 +org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=10000 org.highmed.dsf.bpe.fhir.local.webservice.connectTimeout=500 -org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=5000 +org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=10000 org.highmed.dsf.bpe.fhir.remote.webservice.connectTimeout=2000 #org.highmed.dsf.bpe.fhir.remote.webservice.proxy.password= #org.highmed.dsf.bpe.fhir.remote.webservice.proxy.username= @@ -31,6 +31,8 @@ org.highmed.dsf.bpe.fhir.local.websocket.keystore.password=password org.highmed.dsf.bpe.fhir.task.subscription.searchParameter=?criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson org.highmed.dsf.bpe.fhir.task.subscription.lastEventTimeFile=last_event/time.file +#org.highmed.dsf.bpe.fhir.task.subscription.retrySleepMillis=5000 +#org.highmed.dsf.bpe.fhir.task.subscription.maxRetries=-1 org.highmed.dsf.bpe.openehr.webservice.baseUrl=https://openehr/rest/openehr/v1 org.highmed.dsf.bpe.openehr.webservice.basicAuthUsername=username @@ -38,4 +40,16 @@ org.highmed.dsf.bpe.openehr.webservice.basicAuthPassword=password org.highmed.dsf.bpe.openehr.webservice.connectionTimeout=1500 org.highmed.dsf.bpe.openehr.webservice.readTimeout=2500 +#org.highmed.dsf.bpe.mpi.webservice.factory.class=org.highmed.mpi.client.pdq.MasterPatientIndexClientPdqFactory +#org.highmed.dsf.bpe.mpi.pdq.webservice.host= +#org.highmed.dsf.bpe.mpi.pdq.webservice.port= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.path= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.password= +#org.highmed.dsf.bpe.mpi.pdq.sender.application= +#org.highmed.dsf.bpe.mpi.pdq.sender.facility= +#org.highmed.dsf.bpe.mpi.pdq.receiver.application= +#org.highmed.dsf.bpe.mpi.pdq.receiver.facility= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.namespaceId= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.universalId= + org.highmed.dsf.bpe.cors.origins= \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/conf/log4j2.xml b/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/conf/log4j2.xml index 7006f1aaf..016d8e200 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/conf/log4j2.xml +++ b/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/conf/log4j2.xml @@ -34,15 +34,8 @@ - - - - - + - - - diff --git a/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/last_event/README.md b/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/last_event/README.md new file mode 100644 index 000000000..12fefbfaa --- /dev/null +++ b/dsf-docker-test-setup-3medic-ttp/medic2/bpe/app/last_event/README.md @@ -0,0 +1 @@ +empty directory for last-event time.file \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/medic2/bpe/docker-compose.yml b/dsf-docker-test-setup-3medic-ttp/medic2/bpe/docker-compose.yml index 1fe67af8c..84ad9f325 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic2/bpe/docker-compose.yml +++ b/dsf-docker-test-setup-3medic-ttp/medic2/bpe/docker-compose.yml @@ -35,6 +35,9 @@ services: - type: bind source: ./app/log target: /opt/bpe/log + - type: bind + source: ./app/last_event + target: /opt/bpe/last_event environment: TZ: Europe/Berlin networks: diff --git a/dsf-docker-test-setup-3medic-ttp/medic2/fhir/app/conf/log4j2.xml b/dsf-docker-test-setup-3medic-ttp/medic2/fhir/app/conf/log4j2.xml index 61f365c4c..33426c0b6 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic2/fhir/app/conf/log4j2.xml +++ b/dsf-docker-test-setup-3medic-ttp/medic2/fhir/app/conf/log4j2.xml @@ -49,15 +49,8 @@ - - - - - + - - - diff --git a/dsf-docker-test-setup-3medic-ttp/medic2/upload.yml b/dsf-docker-test-setup-3medic-ttp/medic2/upload.yml index 9b7e283ba..ef642cf97 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic2/upload.yml +++ b/dsf-docker-test-setup-3medic-ttp/medic2/upload.yml @@ -30,6 +30,13 @@ group: '2202' mode: '2775' become: true + - name: Set bpe/app/last_event permissions + file: + path: /opt/highmed/bpe/app/last_event + owner: '{{ user }}' + group: '2202' + mode: '2775' + become: true - name: Set fhir/app/log permissions file: path: /opt/highmed/fhir/app/log diff --git a/dsf-docker-test-setup-3medic-ttp/medic3/bpe/.rsync-filter b/dsf-docker-test-setup-3medic-ttp/medic3/bpe/.rsync-filter index 716786e6e..a87a3a1cd 100644 --- a/dsf-docker-test-setup-3medic-ttp/medic3/bpe/.rsync-filter +++ b/dsf-docker-test-setup-3medic-ttp/medic3/bpe/.rsync-filter @@ -1,5 +1,6 @@ - .rsync-filter - app/conf/.gitignore +- app/last_event/README.md - app/log/README.md - app/plugin/.gitignore - proxy/ssl/.gitignore \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/conf/config.properties b/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/conf/config.properties index c8614100f..443abe2c6 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/conf/config.properties +++ b/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/conf/config.properties @@ -16,10 +16,10 @@ org.highmed.dsf.bpe.fhir.organization.identifier.localValue=Test_MeDIC_3 org.highmed.dsf.bpe.fhir.local.webservice.baseUrl=https://medic3/fhir org.highmed.dsf.bpe.fhir.local.webservice.keystore.p12file=conf/medic3-client_certificate.p12 org.highmed.dsf.bpe.fhir.local.webservice.keystore.password=password -org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=2000 +org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=10000 org.highmed.dsf.bpe.fhir.local.webservice.connectTimeout=500 -org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=5000 +org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=10000 org.highmed.dsf.bpe.fhir.remote.webservice.connectTimeout=2000 #org.highmed.dsf.bpe.fhir.remote.webservice.proxy.password= #org.highmed.dsf.bpe.fhir.remote.webservice.proxy.username= @@ -31,6 +31,8 @@ org.highmed.dsf.bpe.fhir.local.websocket.keystore.password=password org.highmed.dsf.bpe.fhir.task.subscription.searchParameter=?criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson org.highmed.dsf.bpe.fhir.task.subscription.lastEventTimeFile=last_event/time.file +#org.highmed.dsf.bpe.fhir.task.subscription.retrySleepMillis=5000 +#org.highmed.dsf.bpe.fhir.task.subscription.maxRetries=-1 org.highmed.dsf.bpe.openehr.webservice.baseUrl=https://openehr/rest/openehr/v1 org.highmed.dsf.bpe.openehr.webservice.basicAuthUsername=username @@ -38,4 +40,16 @@ org.highmed.dsf.bpe.openehr.webservice.basicAuthPassword=password org.highmed.dsf.bpe.openehr.webservice.connectionTimeout=1500 org.highmed.dsf.bpe.openehr.webservice.readTimeout=2500 +#org.highmed.dsf.bpe.mpi.webservice.factory.class=org.highmed.mpi.client.pdq.MasterPatientIndexClientPdqFactory +#org.highmed.dsf.bpe.mpi.pdq.webservice.host= +#org.highmed.dsf.bpe.mpi.pdq.webservice.port= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.path= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.password= +#org.highmed.dsf.bpe.mpi.pdq.sender.application= +#org.highmed.dsf.bpe.mpi.pdq.sender.facility= +#org.highmed.dsf.bpe.mpi.pdq.receiver.application= +#org.highmed.dsf.bpe.mpi.pdq.receiver.facility= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.namespaceId= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.universalId= + org.highmed.dsf.bpe.cors.origins= \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/conf/log4j2.xml b/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/conf/log4j2.xml index 7006f1aaf..016d8e200 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/conf/log4j2.xml +++ b/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/conf/log4j2.xml @@ -34,15 +34,8 @@ - - - - - + - - - diff --git a/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/last_event/README.md b/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/last_event/README.md new file mode 100644 index 000000000..12fefbfaa --- /dev/null +++ b/dsf-docker-test-setup-3medic-ttp/medic3/bpe/app/last_event/README.md @@ -0,0 +1 @@ +empty directory for last-event time.file \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/medic3/bpe/docker-compose.yml b/dsf-docker-test-setup-3medic-ttp/medic3/bpe/docker-compose.yml index 36c48de8a..477ff9f39 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic3/bpe/docker-compose.yml +++ b/dsf-docker-test-setup-3medic-ttp/medic3/bpe/docker-compose.yml @@ -35,6 +35,9 @@ services: - type: bind source: ./app/log target: /opt/bpe/log + - type: bind + source: ./app/last_event + target: /opt/bpe/last_event environment: TZ: Europe/Berlin networks: diff --git a/dsf-docker-test-setup-3medic-ttp/medic3/fhir/app/conf/log4j2.xml b/dsf-docker-test-setup-3medic-ttp/medic3/fhir/app/conf/log4j2.xml index 61f365c4c..33426c0b6 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic3/fhir/app/conf/log4j2.xml +++ b/dsf-docker-test-setup-3medic-ttp/medic3/fhir/app/conf/log4j2.xml @@ -49,15 +49,8 @@ - - - - - + - - - diff --git a/dsf-docker-test-setup-3medic-ttp/medic3/upload.yml b/dsf-docker-test-setup-3medic-ttp/medic3/upload.yml index a05d5077b..be50b483f 100755 --- a/dsf-docker-test-setup-3medic-ttp/medic3/upload.yml +++ b/dsf-docker-test-setup-3medic-ttp/medic3/upload.yml @@ -30,6 +30,13 @@ group: '2202' mode: '2775' become: true + - name: Set bpe/app/last_event permissions + file: + path: /opt/highmed/bpe/app/last_event + owner: '{{ user }}' + group: '2202' + mode: '2775' + become: true - name: Set fhir/app/log permissions file: path: /opt/highmed/fhir/app/log diff --git a/dsf-docker-test-setup-3medic-ttp/ttp/bpe/.rsync-filter b/dsf-docker-test-setup-3medic-ttp/ttp/bpe/.rsync-filter index 716786e6e..a87a3a1cd 100644 --- a/dsf-docker-test-setup-3medic-ttp/ttp/bpe/.rsync-filter +++ b/dsf-docker-test-setup-3medic-ttp/ttp/bpe/.rsync-filter @@ -1,5 +1,6 @@ - .rsync-filter - app/conf/.gitignore +- app/last_event/README.md - app/log/README.md - app/plugin/.gitignore - proxy/ssl/.gitignore \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/conf/config.properties b/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/conf/config.properties index e1c20401c..980d281b6 100755 --- a/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/conf/config.properties +++ b/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/conf/config.properties @@ -16,10 +16,10 @@ org.highmed.dsf.bpe.fhir.organization.identifier.localValue=Test_TTP org.highmed.dsf.bpe.fhir.local.webservice.baseUrl=https://ttp/fhir org.highmed.dsf.bpe.fhir.local.webservice.keystore.p12file=conf/ttp-client_certificate.p12 org.highmed.dsf.bpe.fhir.local.webservice.keystore.password=password -org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=2000 +org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=10000 org.highmed.dsf.bpe.fhir.local.webservice.connectTimeout=500 -org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=5000 +org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=10000 org.highmed.dsf.bpe.fhir.remote.webservice.connectTimeout=2000 #org.highmed.dsf.bpe.fhir.remote.webservice.proxy.password= #org.highmed.dsf.bpe.fhir.remote.webservice.proxy.username= @@ -31,6 +31,8 @@ org.highmed.dsf.bpe.fhir.local.websocket.keystore.password=password org.highmed.dsf.bpe.fhir.task.subscription.searchParameter=?criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson org.highmed.dsf.bpe.fhir.task.subscription.lastEventTimeFile=last_event/time.file +#org.highmed.dsf.bpe.fhir.task.subscription.retrySleepMillis=5000 +#org.highmed.dsf.bpe.fhir.task.subscription.maxRetries=-1 org.highmed.dsf.bpe.openehr.webservice.baseUrl=https://openehr/rest/openehr/v1 org.highmed.dsf.bpe.openehr.webservice.basicAuthUsername=username @@ -38,4 +40,16 @@ org.highmed.dsf.bpe.openehr.webservice.basicAuthPassword=password org.highmed.dsf.bpe.openehr.webservice.connectionTimeout=1500 org.highmed.dsf.bpe.openehr.webservice.readTimeout=2500 +#org.highmed.dsf.bpe.mpi.webservice.factory.class=org.highmed.mpi.client.pdq.MasterPatientIndexClientPdqFactory +#org.highmed.dsf.bpe.mpi.pdq.webservice.host= +#org.highmed.dsf.bpe.mpi.pdq.webservice.port= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.path= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.password= +#org.highmed.dsf.bpe.mpi.pdq.sender.application= +#org.highmed.dsf.bpe.mpi.pdq.sender.facility= +#org.highmed.dsf.bpe.mpi.pdq.receiver.application= +#org.highmed.dsf.bpe.mpi.pdq.receiver.facility= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.namespaceId= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.universalId= + org.highmed.dsf.bpe.cors.origins= \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/conf/log4j2.xml b/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/conf/log4j2.xml index 7006f1aaf..016d8e200 100755 --- a/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/conf/log4j2.xml +++ b/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/conf/log4j2.xml @@ -34,15 +34,8 @@ - - - - - + - - - diff --git a/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/last_event/README.md b/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/last_event/README.md new file mode 100644 index 000000000..12fefbfaa --- /dev/null +++ b/dsf-docker-test-setup-3medic-ttp/ttp/bpe/app/last_event/README.md @@ -0,0 +1 @@ +empty directory for last-event time.file \ No newline at end of file diff --git a/dsf-docker-test-setup-3medic-ttp/ttp/bpe/docker-compose.yml b/dsf-docker-test-setup-3medic-ttp/ttp/bpe/docker-compose.yml index 818383aed..e9fa6db5b 100755 --- a/dsf-docker-test-setup-3medic-ttp/ttp/bpe/docker-compose.yml +++ b/dsf-docker-test-setup-3medic-ttp/ttp/bpe/docker-compose.yml @@ -35,6 +35,9 @@ services: - type: bind source: ./app/log target: /opt/bpe/log + - type: bind + source: ./app/last_event + target: /opt/bpe/last_event environment: TZ: Europe/Berlin networks: diff --git a/dsf-docker-test-setup-3medic-ttp/ttp/fhir/app/conf/log4j2.xml b/dsf-docker-test-setup-3medic-ttp/ttp/fhir/app/conf/log4j2.xml index 61f365c4c..33426c0b6 100755 --- a/dsf-docker-test-setup-3medic-ttp/ttp/fhir/app/conf/log4j2.xml +++ b/dsf-docker-test-setup-3medic-ttp/ttp/fhir/app/conf/log4j2.xml @@ -49,15 +49,8 @@ - - - - - + - - - diff --git a/dsf-docker-test-setup-3medic-ttp/ttp/upload.yml b/dsf-docker-test-setup-3medic-ttp/ttp/upload.yml index cf93585eb..25a1e966a 100755 --- a/dsf-docker-test-setup-3medic-ttp/ttp/upload.yml +++ b/dsf-docker-test-setup-3medic-ttp/ttp/upload.yml @@ -30,6 +30,13 @@ group: '2202' mode: '2775' become: true + - name: Set bpe/app/last_event permissions + file: + path: /opt/highmed/bpe/app/last_event + owner: '{{ user }}' + group: '2202' + mode: '2775' + become: true - name: Set fhir/app/log permissions file: path: /opt/highmed/fhir/app/log diff --git a/dsf-docker-test-setup/bpe/app/conf/config.properties b/dsf-docker-test-setup/bpe/app/conf/config.properties index 6da6fcf8e..e74fb3b7d 100755 --- a/dsf-docker-test-setup/bpe/app/conf/config.properties +++ b/dsf-docker-test-setup/bpe/app/conf/config.properties @@ -1,41 +1,55 @@ -org.highmed.dsf.bpe.db.driver=org.postgresql.Driver -org.highmed.dsf.bpe.db.url=jdbc:postgresql://db/bpe -org.highmed.dsf.bpe.db.liquibase_user=liquibase_user -org.highmed.dsf.bpe.db.liquibase_user_password=PW99vXYyTbBTGzemQbCnVb4Bce7xuzcU77W5BUCVjYTjbwleVfpTXkQWtGFHYrT8 - -org.highmed.dsf.bpe.db.server_users_group=bpe_users -org.highmed.dsf.bpe.db.server_user=bpe_server_user -org.highmed.dsf.bpe.db.server_user_password=8s4cGYqY41mrWqTmwhZ3beVQcz6wc3Yr - -org.highmed.dsf.bpe.db.camunda_users_group=camunda_users -org.highmed.dsf.bpe.db.camunda_user=camunda_server_user -org.highmed.dsf.bpe.db.camunda_user_password=dcPa7a9wTCaTxFk7BdjmCuQp8k29e2eL - -org.highmed.dsf.bpe.fhir.organization.identifier.localValue=Test_Organization - -org.highmed.dsf.bpe.fhir.local.webservice.baseUrl=https://fhir/fhir -org.highmed.dsf.bpe.fhir.local.webservice.keystore.p12file=conf/test-client_certificate.p12 -org.highmed.dsf.bpe.fhir.local.webservice.keystore.password=password -org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=1500 -org.highmed.dsf.bpe.fhir.local.webservice.connectTimeout=500 - -org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=2500 -org.highmed.dsf.bpe.fhir.remote.webservice.connectTimeout=1500 -#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.password= -#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.username= -#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.schemeHostPort= - -org.highmed.dsf.bpe.fhir.local.websocket.url=wss://fhir/fhir/ws -org.highmed.dsf.bpe.fhir.local.websocket.keystore.p12file=conf/test-client_certificate.p12 -org.highmed.dsf.bpe.fhir.local.websocket.keystore.password=password - -org.highmed.dsf.bpe.fhir.task.subscription.searchParameter=?criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson -org.highmed.dsf.bpe.fhir.task.subscription.lastEventTimeFile=last_event/time.file - -org.highmed.dsf.bpe.openehr.webservice.baseUrl=https://openehr/rest/openehr/v1 -org.highmed.dsf.bpe.openehr.webservice.basicAuthUsername=username -org.highmed.dsf.bpe.openehr.webservice.basicAuthPassword=password -org.highmed.dsf.bpe.openehr.webservice.connectionTimeout=1500 -org.highmed.dsf.bpe.openehr.webservice.readTimeout=2500 - -org.highmed.dsf.bpe.cors.origins= +org.highmed.dsf.bpe.db.driver=org.postgresql.Driver +org.highmed.dsf.bpe.db.url=jdbc:postgresql://db/bpe +org.highmed.dsf.bpe.db.liquibase_user=liquibase_user +org.highmed.dsf.bpe.db.liquibase_user_password=PW99vXYyTbBTGzemQbCnVb4Bce7xuzcU77W5BUCVjYTjbwleVfpTXkQWtGFHYrT8 + +org.highmed.dsf.bpe.db.server_users_group=bpe_users +org.highmed.dsf.bpe.db.server_user=bpe_server_user +org.highmed.dsf.bpe.db.server_user_password=8s4cGYqY41mrWqTmwhZ3beVQcz6wc3Yr + +org.highmed.dsf.bpe.db.camunda_users_group=camunda_users +org.highmed.dsf.bpe.db.camunda_user=camunda_server_user +org.highmed.dsf.bpe.db.camunda_user_password=dcPa7a9wTCaTxFk7BdjmCuQp8k29e2eL + +org.highmed.dsf.bpe.fhir.organization.identifier.localValue=Test_Organization + +org.highmed.dsf.bpe.fhir.local.webservice.baseUrl=https://fhir/fhir +org.highmed.dsf.bpe.fhir.local.webservice.keystore.p12file=conf/test-client_certificate.p12 +org.highmed.dsf.bpe.fhir.local.webservice.keystore.password=password +org.highmed.dsf.bpe.fhir.local.webservice.readTimeout=1500 +org.highmed.dsf.bpe.fhir.local.webservice.connectTimeout=500 + +org.highmed.dsf.bpe.fhir.remote.webservice.readTimeout=2500 +org.highmed.dsf.bpe.fhir.remote.webservice.connectTimeout=1500 +#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.password= +#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.username= +#org.highmed.dsf.bpe.fhir.remote.webservice.proxy.schemeHostPort= + +org.highmed.dsf.bpe.fhir.local.websocket.url=wss://fhir/fhir/ws +org.highmed.dsf.bpe.fhir.local.websocket.keystore.p12file=conf/test-client_certificate.p12 +org.highmed.dsf.bpe.fhir.local.websocket.keystore.password=password + +org.highmed.dsf.bpe.fhir.task.subscription.searchParameter=?criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson +org.highmed.dsf.bpe.fhir.task.subscription.lastEventTimeFile=last_event/time.file +#org.highmed.dsf.bpe.fhir.task.subscription.retrySleepMillis=5000 +#org.highmed.dsf.bpe.fhir.task.subscription.maxRetries=-1 + +org.highmed.dsf.bpe.openehr.webservice.baseUrl=https://openehr/rest/openehr/v1 +org.highmed.dsf.bpe.openehr.webservice.basicAuthUsername=username +org.highmed.dsf.bpe.openehr.webservice.basicAuthPassword=password +org.highmed.dsf.bpe.openehr.webservice.connectionTimeout=1500 +org.highmed.dsf.bpe.openehr.webservice.readTimeout=2500 + +#org.highmed.dsf.bpe.mpi.webservice.factory.class=org.highmed.mpi.client.pdq.MasterPatientIndexClientPdqFactory +#org.highmed.dsf.bpe.mpi.pdq.webservice.host= +#org.highmed.dsf.bpe.mpi.pdq.webservice.port= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.path= +#org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.password= +#org.highmed.dsf.bpe.mpi.pdq.sender.application= +#org.highmed.dsf.bpe.mpi.pdq.sender.facility= +#org.highmed.dsf.bpe.mpi.pdq.receiver.application= +#org.highmed.dsf.bpe.mpi.pdq.receiver.facility= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.namespaceId= +#org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.universalId= + +org.highmed.dsf.bpe.cors.origins= diff --git a/dsf-docker-test-setup/bpe/app/last_event/.gitignore b/dsf-docker-test-setup/bpe/app/last_event/.gitignore new file mode 100644 index 000000000..9a81fe812 --- /dev/null +++ b/dsf-docker-test-setup/bpe/app/last_event/.gitignore @@ -0,0 +1 @@ +/time.file \ No newline at end of file diff --git a/dsf-docker-test-setup/bpe/docker-compose.yml b/dsf-docker-test-setup/bpe/docker-compose.yml index e0f8b521b..4ef7969f5 100755 --- a/dsf-docker-test-setup/bpe/docker-compose.yml +++ b/dsf-docker-test-setup/bpe/docker-compose.yml @@ -25,12 +25,17 @@ services: - type: bind source: ./app/conf target: /opt/bpe/conf + read_only: true - type: bind source: ./app/plugin target: /opt/bpe/plugin + read_only: true - type: bind source: ./app/log target: /opt/bpe/log + - type: bind + source: ./app/last_event + target: /opt/bpe/last_event environment: TZ: Europe/Berlin networks: diff --git a/dsf-docker-test-setup/docker-build.bat b/dsf-docker-test-setup/docker-build.bat index ecfe317b5..0cc134768 100755 --- a/dsf-docker-test-setup/docker-build.bat +++ b/dsf-docker-test-setup/docker-build.bat @@ -1,13 +1,13 @@ @echo off echo highmed/bpe ... -docker build -t highmed/bpe ..\dsf-bpe\dsf-bpe-server-jetty\docker +docker build --pull -t highmed/bpe ..\dsf-bpe\dsf-bpe-server-jetty\docker echo highmed/bpe_proxy ... -docker build -t highmed/bpe_proxy ..\dsf-docker\bpe_proxy +docker build --pull -t highmed/bpe_proxy ..\dsf-docker\bpe_proxy echo highmed/fhir ... -docker build -t highmed/fhir ..\dsf-fhir\dsf-fhir-server-jetty\docker +docker build --pull -t highmed/fhir ..\dsf-fhir\dsf-fhir-server-jetty\docker echo highmed/fhir_proxy ... -docker build -t highmed/fhir_proxy ..\dsf-docker\fhir_proxy +docker build --pull -t highmed/fhir_proxy ..\dsf-docker\fhir_proxy diff --git a/dsf-docker-test-setup/docker-build.sh b/dsf-docker-test-setup/docker-build.sh index d26697a6c..7b9bb25c2 100755 --- a/dsf-docker-test-setup/docker-build.sh +++ b/dsf-docker-test-setup/docker-build.sh @@ -1,13 +1,13 @@ #!/bin/bash echo highmed/bpe ... -docker build -t highmed/bpe ../dsf-bpe/dsf-bpe-server-jetty/docker +docker build --pull -t highmed/bpe ../dsf-bpe/dsf-bpe-server-jetty/docker echo highmed/bpe_proxy ... -docker build -t highmed/bpe_proxy ../dsf-docker/bpe_proxy +docker build --pull -t highmed/bpe_proxy ../dsf-docker/bpe_proxy echo highmed/fhir ... -docker build -t highmed/fhir ../dsf-fhir/dsf-fhir-server-jetty/docker +docker build --pull -t highmed/fhir ../dsf-fhir/dsf-fhir-server-jetty/docker echo highmed/fhir_proxy ... -docker build -t highmed/fhir_proxy ../dsf-docker/fhir_proxy +docker build --pull -t highmed/fhir_proxy ../dsf-docker/fhir_proxy diff --git a/dsf-fhir/dsf-fhir-rest-adapter/pom.xml b/dsf-fhir/dsf-fhir-rest-adapter/pom.xml index 43f059f2d..9c1e9143e 100755 --- a/dsf-fhir/dsf-fhir-rest-adapter/pom.xml +++ b/dsf-fhir/dsf-fhir-rest-adapter/pom.xml @@ -1,5 +1,5 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 dsf-fhir-rest-adapter @@ -7,7 +7,7 @@ org.highmed.dsf dsf-fhir-pom - 0.1.0 + 0.2.0 @@ -20,5 +20,11 @@ javax.ws.rs-api provided + + + de.hs-heilbronn.mi + log4j2-utils + test + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/AbstractFhirAdapter.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/AbstractFhirAdapter.java index 32c1ac6f4..62864dbf4 100755 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/AbstractFhirAdapter.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/AbstractFhirAdapter.java @@ -81,6 +81,11 @@ public T readFrom(Class type, Type genericType, Annotation[] annotations, Med MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { - return getParser(null).parseResource(type, new InputStreamReader(entityStream)); + return fixResource(getParser(null).parseResource(type, new InputStreamReader(entityStream))); + } + + protected T fixResource(T resource) + { + return resource; } } diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BinaryJsonFhirAdapter.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BinaryJsonFhirAdapter.java index 300705af1..37cd7ef87 100755 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BinaryJsonFhirAdapter.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BinaryJsonFhirAdapter.java @@ -3,6 +3,7 @@ import javax.ws.rs.ext.Provider; import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.IdType; import ca.uhn.fhir.context.FhirContext; @@ -13,4 +14,20 @@ public BinaryJsonFhirAdapter(FhirContext fhirContext) { super(fhirContext, Binary.class); } + + @Override + protected Binary fixResource(Binary resource) + { + if (resource.hasIdElement() && resource.getIdElement().hasIdPart() + && !resource.getIdElement().hasVersionIdPart() && resource.hasMeta() + && resource.getMeta().hasVersionId()) + { + // TODO Bugfix HAPI is removing version information from binary.id + IdType fixedId = new IdType(resource.getResourceType().name(), resource.getIdElement().getIdPart(), + resource.getMeta().getVersionId()); + resource.setIdElement(fixedId); + } + + return resource; + } } diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BinaryXmlFhirAdapter.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BinaryXmlFhirAdapter.java index bb31a9285..e4ae6e0b7 100755 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BinaryXmlFhirAdapter.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BinaryXmlFhirAdapter.java @@ -3,6 +3,7 @@ import javax.ws.rs.ext.Provider; import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.IdType; import ca.uhn.fhir.context.FhirContext; @@ -13,4 +14,20 @@ public BinaryXmlFhirAdapter(FhirContext fhirContext) { super(fhirContext, Binary.class); } + + @Override + protected Binary fixResource(Binary resource) + { + if (resource.hasIdElement() && resource.getIdElement().hasIdPart() + && !resource.getIdElement().hasVersionIdPart() && resource.hasMeta() + && resource.getMeta().hasVersionId()) + { + // TODO Bugfix HAPI is removing version information from binary.id + IdType fixedId = new IdType(resource.getResourceType().name(), resource.getIdElement().getIdPart(), + resource.getMeta().getVersionId()); + resource.setIdElement(fixedId); + } + + return resource; + } } diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BundleJsonFhirAdapter.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BundleJsonFhirAdapter.java index 99da67c01..5e2e5c331 100755 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BundleJsonFhirAdapter.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BundleJsonFhirAdapter.java @@ -3,6 +3,7 @@ import javax.ws.rs.ext.Provider; import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.IdType; import ca.uhn.fhir.context.FhirContext; @@ -13,4 +14,20 @@ public BundleJsonFhirAdapter(FhirContext fhirContext) { super(fhirContext, Bundle.class); } + + @Override + protected Bundle fixResource(Bundle resource) + { + if (resource.hasIdElement() && resource.getIdElement().hasIdPart() + && !resource.getIdElement().hasVersionIdPart() && resource.hasMeta() + && resource.getMeta().hasVersionId()) + { + // TODO Bugfix HAPI is removing version information from bundle.id + IdType fixedId = new IdType(resource.getResourceType().name(), resource.getIdElement().getIdPart(), + resource.getMeta().getVersionId()); + resource.setIdElement(fixedId); + } + + return resource; + } } diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BundleXmlFhirAdapter.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BundleXmlFhirAdapter.java index 27b256b1c..cd848c816 100755 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BundleXmlFhirAdapter.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/BundleXmlFhirAdapter.java @@ -3,6 +3,7 @@ import javax.ws.rs.ext.Provider; import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.IdType; import ca.uhn.fhir.context.FhirContext; @@ -13,4 +14,20 @@ public BundleXmlFhirAdapter(FhirContext fhirContext) { super(fhirContext, Bundle.class); } + + @Override + protected Bundle fixResource(Bundle resource) + { + if (resource.hasIdElement() && resource.getIdElement().hasIdPart() + && !resource.getIdElement().hasVersionIdPart() && resource.hasMeta() + && resource.getMeta().hasVersionId()) + { + // TODO Bugfix HAPI is removing version information from bundle.id + IdType fixedId = new IdType(resource.getResourceType().name(), resource.getIdElement().getIdPart(), + resource.getMeta().getVersionId()); + resource.setIdElement(fixedId); + } + + return resource; + } } diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/HtmlFhirAdapter.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/HtmlFhirAdapter.java index ba7ed8d23..61687be45 100644 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/HtmlFhirAdapter.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/adapter/HtmlFhirAdapter.java @@ -23,6 +23,7 @@ import org.hl7.fhir.r4.model.BaseResource; import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Resource; import ca.uhn.fhir.context.FhirContext; @@ -177,8 +178,13 @@ private Optional getResourceUrl(T t) throws MalformedURLException else if (t instanceof Resource && t.getIdElement().getResourceType() != null && t.getIdElement().getIdPart() != null) { - return Optional.of(String.format("%s/%s/%s", serverBaseProvider.getServerBase(), - t.getIdElement().getResourceType(), t.getIdElement().getIdPart())); + if (!uriInfo.getPath().contains("_history")) + return Optional.of(String.format("%s/%s/%s", serverBaseProvider.getServerBase(), + t.getIdElement().getResourceType(), t.getIdElement().getIdPart())); + else + return Optional.of(String.format("%s/%s/%s/_history/%s", serverBaseProvider.getServerBase(), + t.getIdElement().getResourceType(), t.getIdElement().getIdPart(), + t.getIdElement().getVersionIdPart())); } else return Optional.empty(); @@ -239,8 +245,19 @@ private void writeJson(T t, OutputStreamWriter out) throws IOException private Optional getResourceName(T t, String uuid) { if (t instanceof Bundle) - return ((Bundle) t).getEntry().stream().filter(c -> uuid.equals(c.getResource().getIdElement().getIdPart())) - .map(c -> c.getResource().getClass().getAnnotation(ResourceDef.class).name()).findFirst(); + return ((Bundle) t).getEntry().stream().filter(c -> + { + if (c.hasResource()) + return uuid.equals(c.getResource().getIdElement().getIdPart()); + else + return uuid.equals(new IdType(c.getResponse().getLocation()).getIdPart()); + }).map(c -> + { + if (c.hasResource()) + return c.getResource().getClass().getAnnotation(ResourceDef.class).name(); + else + return new IdType(c.getResponse().getLocation()).getResourceType(); + }).findFirst(); else if (t instanceof Resource) return Optional.of(t.getClass().getAnnotation(ResourceDef.class).name()); else diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/prefer/PreferHandlingType.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/prefer/PreferHandlingType.java new file mode 100644 index 000000000..c1da6e8df --- /dev/null +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/prefer/PreferHandlingType.java @@ -0,0 +1,33 @@ +package org.highmed.dsf.fhir.prefer; + +public enum PreferHandlingType +{ + STRICT("handling=strict"), LENIENT("handling=lenient"); + + private final String headerValue; + + private PreferHandlingType(String headerValue) + { + this.headerValue = headerValue; + } + + public static PreferHandlingType fromString(String prefer) + { + if (prefer == null) + return LENIENT; + + switch (prefer) + { + case "handling=strict": + return STRICT; + case "handling=lenient": + default: + return LENIENT; + } + } + + public String getHeaderValue() + { + return headerValue; + } +} diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/prefer/PreferReturnType.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/prefer/PreferReturnType.java new file mode 100644 index 000000000..d6bafb0b8 --- /dev/null +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/prefer/PreferReturnType.java @@ -0,0 +1,35 @@ +package org.highmed.dsf.fhir.prefer; + +public enum PreferReturnType +{ + MINIMAL("return=minimal"), REPRESENTATION("return=representation"), OPERATION_OUTCOME("return=OperationOutcome"); + + private final String headerValue; + + private PreferReturnType(String headerValue) + { + this.headerValue = headerValue; + } + + public static PreferReturnType fromString(String prefer) + { + if (prefer == null) + return REPRESENTATION; + + switch (prefer) + { + case "return=minimal": + return MINIMAL; + case "return=OperationOutcome": + return OPERATION_OUTCOME; + case "return=representation": + default: + return REPRESENTATION; + } + } + + public String getHeaderValue() + { + return headerValue; + } +} diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceCleaner.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceCleaner.java new file mode 100644 index 000000000..dc1fe9d9f --- /dev/null +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceCleaner.java @@ -0,0 +1,24 @@ +package org.highmed.dsf.fhir.service; + +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Resource; + +public interface ReferenceCleaner +{ + /** + * Removes literal references, if a conditional reference is also set + * + * @param resource + * @return null if given resource is null, cleaned up resource (same instance) + */ + R cleanLiteralReferences(R resource); + + /** + * Removes embedded resources from references within {@link Bundle} entries + * + * @param + * @param resource + * @return null if given resource is null, cleaned up resource (same instance) + */ + R cleanReferenceResourcesIfBundle(R resource); +} diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceCleanerImpl.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceCleanerImpl.java new file mode 100644 index 000000000..901fcee70 --- /dev/null +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceCleanerImpl.java @@ -0,0 +1,66 @@ +package org.highmed.dsf.fhir.service; + +import java.util.Objects; +import java.util.stream.Stream; + +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.Resource; + +public class ReferenceCleanerImpl implements ReferenceCleaner +{ + private ReferenceExtractor referenceExtractor; + + public ReferenceCleanerImpl(ReferenceExtractor referenceExtractor) + { + this.referenceExtractor = Objects.requireNonNull(referenceExtractor, "referenceExtractor"); + } + + @Override + public R cleanLiteralReferences(R resource) + { + if (resource == null) + return null; + + Stream references = referenceExtractor.getReferences(resource); + references.forEach(this::cleanupReference); + + return resource; + } + + private void cleanupReference(ResourceReference resourceReference) + { + Reference ref = resourceReference.getReference(); + if (ref.hasIdentifier() && ref.hasReference()) + ref.setReferenceElement((IdType) null); + } + + @Override + public R cleanReferenceResourcesIfBundle(R resource) + { + if (resource == null) + return null; + + if (resource instanceof Bundle) + { + Bundle bundle = (Bundle) resource; + bundle.getEntry().stream().map(e -> e.getResource()).forEach(this::fixBundleEntry); + } + + return resource; + } + + private void fixBundleEntry(Resource resource) + { + if (resource instanceof Bundle) + { + cleanReferenceResourcesIfBundle(resource); + } + else + { + Stream references = referenceExtractor.getReferences(resource); + references.forEach(r -> r.getReference().setResource(null)); + } + } +} diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceExtractor.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceExtractor.java index 88c69827b..67031ca5c 100644 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceExtractor.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceExtractor.java @@ -3,10 +3,13 @@ import java.util.stream.Stream; import org.hl7.fhir.r4.model.ActivityDefinition; +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.Endpoint; import org.hl7.fhir.r4.model.Group; import org.hl7.fhir.r4.model.HealthcareService; import org.hl7.fhir.r4.model.Location; +import org.hl7.fhir.r4.model.NamingSystem; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Practitioner; @@ -14,7 +17,10 @@ import org.hl7.fhir.r4.model.Provenance; import org.hl7.fhir.r4.model.ResearchStudy; import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.Subscription; import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.ValueSet; public interface ReferenceExtractor { @@ -22,6 +28,13 @@ public interface ReferenceExtractor Stream getReferences(ActivityDefinition resource); + Stream getReferences(Binary resource); + + // Not implemented yet, special rules apply for tmp ids + // Stream getReferences(Bundle bundle); + + Stream getReferences(CodeSystem resource); + Stream getReferences(Endpoint resource); Stream getReferences(Group group); @@ -30,6 +43,8 @@ public interface ReferenceExtractor Stream getReferences(Location resource); + Stream getReferences(NamingSystem resource); + Stream getReferences(Organization resource); Stream getReferences(Patient resource); @@ -42,5 +57,11 @@ public interface ReferenceExtractor Stream getReferences(ResearchStudy resource); + Stream getReferences(StructureDefinition resource); + + Stream getReferences(Subscription resource); + Stream getReferences(Task resource); + + Stream getReferences(ValueSet resource); } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceExtractorImpl.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceExtractorImpl.java index 2cb4fb2c2..dc0513fa8 100644 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceExtractorImpl.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ReferenceExtractorImpl.java @@ -8,17 +8,21 @@ import org.hl7.fhir.r4.model.ActivityDefinition; import org.hl7.fhir.r4.model.BackboneElement; +import org.hl7.fhir.r4.model.Binary; import org.hl7.fhir.r4.model.CareTeam; import org.hl7.fhir.r4.model.ClaimResponse; +import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.Coverage; import org.hl7.fhir.r4.model.Device; import org.hl7.fhir.r4.model.DomainResource; import org.hl7.fhir.r4.model.Encounter; import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.Group; import org.hl7.fhir.r4.model.HealthcareService; import org.hl7.fhir.r4.model.Location; import org.hl7.fhir.r4.model.Medication; +import org.hl7.fhir.r4.model.NamingSystem; import org.hl7.fhir.r4.model.ObservationDefinition; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Patient; @@ -36,8 +40,11 @@ import org.hl7.fhir.r4.model.ResearchStudy; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.SpecimenDefinition; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.Subscription; import org.hl7.fhir.r4.model.Substance; import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.ValueSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -142,9 +149,38 @@ private Stream getReferences(E ba private Stream getExtensionReferences(DomainResource resource) { - return resource.getExtension().stream().filter(e -> e.getValue() instanceof Reference) - .map(e -> (Reference) e.getValue()) + Stream extensions = resource.getExtension().stream() + .filter(e -> e.getValue() instanceof Reference).map(e -> (Reference) e.getValue()) .map(toResourceReference(resource.getResourceType().name() + ".extension")); + + Stream extensionExtensions = resource.getExtension().stream() + .flatMap(e -> getExtensionReferences(resource.getResourceType().name() + ".extension", e)); + + return Stream.concat(extensions, extensionExtensions); + } + + private Stream getExtensionReferences(String baseElementName, BackboneElement resource) + { + Stream extensions = resource.getExtension().stream() + .filter(e -> e.getValue() instanceof Reference).map(e -> (Reference) e.getValue()) + .map(toResourceReference(baseElementName + ".extension")); + + Stream extensionExtensions = resource.getExtension().stream() + .flatMap(e -> getExtensionReferences(baseElementName + ".extension", e)); + + return Stream.concat(extensions, extensionExtensions); + } + + private Stream getExtensionReferences(String baseElementName, Extension resource) + { + Stream extensions = resource.getExtension().stream() + .filter(e -> e.getValue() instanceof Reference).map(e -> (Reference) e.getValue()) + .map(toResourceReference(baseElementName + ".extension")); + + Stream extensionExtensions = resource.getExtension().stream() + .flatMap(e -> getExtensionReferences(baseElementName + ".extension", e)); + + return Stream.concat(extensions, extensionExtensions); } @SafeVarargs @@ -166,7 +202,16 @@ public Stream getReferences(Resource resource) if (resource == null) return Stream.empty(); - if (resource instanceof Endpoint) + if (resource instanceof ActivityDefinition) + return getReferences((ActivityDefinition) resource); + // not implemented yet, special rules apply for tmp ids + // else if (resource instanceof Bundle) + // return getReferences((Bundle) resource); + else if (resource instanceof Binary) + return getReferences((Binary) resource); + else if (resource instanceof CodeSystem) + return getReferences((CodeSystem) resource); + else if (resource instanceof Endpoint) return getReferences((Endpoint) resource); else if (resource instanceof Group) return getReferences((Group) resource); @@ -174,6 +219,8 @@ else if (resource instanceof HealthcareService) return getReferences((HealthcareService) resource); else if (resource instanceof Location) return getReferences((Location) resource); + else if (resource instanceof NamingSystem) + return getReferences((NamingSystem) resource); else if (resource instanceof Organization) return getReferences((Organization) resource); else if (resource instanceof Patient) @@ -186,8 +233,14 @@ else if (resource instanceof Provenance) return getReferences((Provenance) resource); else if (resource instanceof ResearchStudy) return getReferences((ResearchStudy) resource); + else if (resource instanceof StructureDefinition) + return getReferences((StructureDefinition) resource); + else if (resource instanceof Subscription) + return getReferences((Subscription) resource); else if (resource instanceof Task) return getReferences((Task) resource); + else if (resource instanceof ValueSet) + return getReferences((ValueSet) resource); else if (resource instanceof DomainResource) { logger.debug("DomainResource of type {} not supported, returning extension references only", @@ -231,6 +284,29 @@ public Stream getReferences(ActivityDefinition resource) observationResultRequirement, extensionReferences); } + @Override + public Stream getReferences(Binary resource) + { + if (resource == null) + return Stream.empty(); + + var securityContext = getReference(resource, Binary::hasSecurityContext, Binary::getSecurityContext, + "Binary.securityContext"); + + return securityContext; + } + + @Override + public Stream getReferences(CodeSystem resource) + { + if (resource == null) + return Stream.empty(); + + var extensionReferences = getExtensionReferences(resource); + + return extensionReferences; + } + @Override public Stream getReferences(Endpoint resource) { @@ -288,6 +364,9 @@ public Stream getReferences(HealthcareService resource) @Override public Stream getReferences(Location resource) { + if (resource == null) + return Stream.empty(); + var managingOrganization = getReference(resource, Location::hasManagingOrganization, Location::getManagingOrganization, "Location.managingOrganization", Organization.class); var partOf = getReference(resource, Location::hasPartOf, Location::getPartOf, "Location.partOf", @@ -300,9 +379,23 @@ public Stream getReferences(Location resource) return concat(managingOrganization, partOf, endpoints, extensionReferences); } + @Override + public Stream getReferences(NamingSystem resource) + { + if (resource == null) + return Stream.empty(); + + var extensionReferences = getExtensionReferences(resource); + + return extensionReferences; + } + @Override public Stream getReferences(Organization resource) { + if (resource == null) + return Stream.empty(); + var partOf = getReference(resource, Organization::hasPartOf, Organization::getPartOf, "Organization.partOf", Organization.class); var endpoints = getReferences(resource, Organization::hasEndpoint, Organization::getEndpoint, @@ -316,6 +409,9 @@ public Stream getReferences(Organization resource) @Override public Stream getReferences(Patient resource) { + if (resource == null) + return Stream.empty(); + var contactsOrganization = getBackboneElementsReference(resource, Patient::hasContact, Patient::getContact, ContactComponent::hasOrganization, ContactComponent::getOrganization, "Patient.contact.organization", Organization.class); @@ -337,6 +433,9 @@ public Stream getReferences(Patient resource) @Override public Stream getReferences(Practitioner resource) { + if (resource == null) + return Stream.empty(); + var qualificationsIssuer = getBackboneElementsReference(resource, Practitioner::hasQualification, Practitioner::getQualification, PractitionerQualificationComponent::hasIssuer, PractitionerQualificationComponent::getIssuer, "Practitioner.qualification.issuer", Organization.class); @@ -349,6 +448,9 @@ public Stream getReferences(Practitioner resource) @Override public Stream getReferences(PractitionerRole resource) { + if (resource == null) + return Stream.empty(); + var practitioner = getReference(resource, PractitionerRole::hasPractitioner, PractitionerRole::getPractitioner, "PractitionerRole.practitioner", Practitioner.class); var organization = getReference(resource, PractitionerRole::hasOrganization, PractitionerRole::getOrganization, @@ -368,6 +470,9 @@ public Stream getReferences(PractitionerRole resource) @Override public Stream getReferences(Provenance resource) { + if (resource == null) + return Stream.empty(); + var targets = getReferences(resource, Provenance::hasTarget, Provenance::getTarget, "Provenance.target"); var location = getReference(resource, Provenance::hasLocation, Provenance::getLocation, "Provenance.location", Location.class); @@ -390,6 +495,9 @@ public Stream getReferences(Provenance resource) @Override public Stream getReferences(ResearchStudy resource) { + if (resource == null) + return Stream.empty(); + var protocols = getReferences(resource, ResearchStudy::hasProtocol, ResearchStudy::getProtocol, "ResearchStudy.protocol", PlanDefinition.class); var partOfs = getReferences(resource, ResearchStudy::hasPartOf, ResearchStudy::getPartOf, @@ -409,9 +517,34 @@ public Stream getReferences(ResearchStudy resource) return concat(protocols, partOfs, enrollments, sponsor, principalInvestigator, sites, extensionReferences); } + @Override + public Stream getReferences(StructureDefinition resource) + { + if (resource == null) + return Stream.empty(); + + var extensionReferences = getExtensionReferences(resource); + + return extensionReferences; + } + + @Override + public Stream getReferences(Subscription resource) + { + if (resource == null) + return Stream.empty(); + + var extensionReferences = getExtensionReferences(resource); + + return extensionReferences; + } + @Override public Stream getReferences(Task resource) { + if (resource == null) + return Stream.empty(); + var basedOns = getReferences(resource, Task::hasBasedOn, Task::getBasedOn, "Task.basedOn"); var partOfs = getReferences(resource, Task::hasPartOf, Task::getPartOf, "Task.partOf", Task.class); var focus = getReference(resource, Task::hasFocus, Task::getFocus, "Task.focus"); @@ -439,21 +572,49 @@ public Stream getReferences(Task resource) var outputReferences = getOutputReferences(resource); var extensionReferences = getExtensionReferences(resource); - return concat(basedOns, partOfs, focus, forRef, encounter, requester, owner, location, reasonReference, insurance, - relevanteHistories, restrictionRecipiets, inputReferences, outputReferences, extensionReferences); + return concat(basedOns, partOfs, focus, forRef, encounter, requester, owner, location, reasonReference, + insurance, relevanteHistories, restrictionRecipiets, inputReferences, outputReferences, + extensionReferences); } private Stream getInputReferences(Task resource) { - return resource.getInput().stream().filter(in -> in.getValue() instanceof Reference) - .map(in -> (Reference) in.getValue()) + if (resource == null) + return Stream.empty(); + + Stream inputReferences = resource.getInput().stream() + .filter(in -> in.getValue() instanceof Reference).map(in -> (Reference) in.getValue()) .map(toResourceReference(resource.getResourceType().name() + ".input")); + + Stream inputExtensionReferences = resource.getInput().stream() + .flatMap(in -> getExtensionReferences(resource.getResourceType().name() + ".input", in)); + + return Stream.concat(inputReferences, inputExtensionReferences); } private Stream getOutputReferences(Task resource) { - return resource.getOutput().stream().filter(out -> out.getValue() instanceof Reference) - .map(out -> (Reference) out.getValue()) + if (resource == null) + return Stream.empty(); + + Stream outputReferences = resource.getOutput().stream() + .filter(out -> out.getValue() instanceof Reference).map(in -> (Reference) in.getValue()) .map(toResourceReference(resource.getResourceType().name() + ".output")); + + Stream outputExtensionReferences = resource.getOutput().stream() + .flatMap(out -> getExtensionReferences(resource.getResourceType().name() + ".output", out)); + + return Stream.concat(outputReferences, outputExtensionReferences); + } + + @Override + public Stream getReferences(ValueSet resource) + { + if (resource == null) + return Stream.empty(); + + var extensionReferences = getExtensionReferences(resource); + + return extensionReferences; } } diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ResourceReference.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ResourceReference.java index 3a871fb86..da5913c63 100644 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ResourceReference.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/org/highmed/dsf/fhir/service/ResourceReference.java @@ -135,9 +135,14 @@ public boolean supportsType(Class type) } /** + * Determines the {@link ReferenceType} based {@link Reference#getReference()} first and then looks at + * {@link Reference#getIdentifier()} + * * @param localServerBase * not null - * @return + * @return one of this priority list: {@link ReferenceType#TEMPORARY}, {@link ReferenceType#LITERAL_INTERNAL}, + * {@link ReferenceType#LITERAL_EXTERNAL}, {@link ReferenceType#CONDITIONAL}, {@link ReferenceType#LOGICAL}, + * {@link ReferenceType#UNKNOWN} */ public ReferenceType getType(String localServerBase) { diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/test/java/org/highmed/dsf/fhir/service/ReferenceExtractorTest.java b/dsf-fhir/dsf-fhir-rest-adapter/src/test/java/org/highmed/dsf/fhir/service/ReferenceExtractorTest.java new file mode 100644 index 000000000..3ddd2cd56 --- /dev/null +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/test/java/org/highmed/dsf/fhir/service/ReferenceExtractorTest.java @@ -0,0 +1,54 @@ +package org.highmed.dsf.fhir.service; + +import static org.junit.Assert.*; + +import java.util.List; +import java.util.stream.Collectors; + +import org.hl7.fhir.r4.model.Extension; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.Task; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ReferenceExtractorTest +{ + private static final Logger logger = LoggerFactory.getLogger(ReferenceExtractorTest.class); + + private ReferenceExtractor referenceExtractor; + + @Before + public void before() throws Exception + { + referenceExtractor = new ReferenceExtractorImpl(); + } + + @Test + public void testExtractTaskReferences() throws Exception + { + Extension e0 = new Extension("url0", new Reference("task.ref")); + Extension e1 = new Extension("url1", new Reference("task.input.extension.ref")); + Extension e2 = new Extension("url2", new StringType("value")); + Extension e3 = new Extension("url3", new Reference("task.input.extension.extension.extension.ref")); + e1.addExtension(e2); + e2.addExtension(e3); + + Task t = new Task(); + t.addExtension(e0); + t.addInput().setValue(new Reference("task.input.ref")).addExtension(e1); + + List refs = referenceExtractor.getReferences(t).collect(Collectors.toList()); + + logger.debug("refs: {}", refs.stream().map(r -> r.getReferenceLocation()).collect(Collectors.toList())); + + assertNotNull(refs); + assertEquals(4, refs.size()); + assertEquals("task.input.ref", refs.get(0).getReference().getReference()); + assertEquals("task.input.extension.ref", refs.get(1).getReference().getReference()); + assertEquals("task.input.extension.extension.extension.ref", refs.get(2).getReference().getReference()); + assertEquals("task.ref", refs.get(3).getReference().getReference()); + } +} diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/test/resources/log4j2.xml b/dsf-fhir/dsf-fhir-rest-adapter/src/test/resources/log4j2.xml new file mode 100644 index 000000000..9999bb653 --- /dev/null +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/test/resources/log4j2.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server-jetty/docker/.dockerignore b/dsf-fhir/dsf-fhir-server-jetty/docker/.dockerignore index 91816beee..6024446f9 100755 --- a/dsf-fhir/dsf-fhir-server-jetty/docker/.dockerignore +++ b/dsf-fhir/dsf-fhir-server-jetty/docker/.dockerignore @@ -1,5 +1,6 @@ -.dockerignore -Dockerfile -conf/README.md -lib/.gitignore +.dockerignore +.gitignore +Dockerfile +conf/README.md +lib/.gitignore log/README.md \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server-jetty/docker/Dockerfile b/dsf-fhir/dsf-fhir-server-jetty/docker/Dockerfile index 823d2cc14..0eedb083c 100755 --- a/dsf-fhir/dsf-fhir-server-jetty/docker/Dockerfile +++ b/dsf-fhir/dsf-fhir-server-jetty/docker/Dockerfile @@ -1,12 +1,21 @@ +FROM debian:buster-slim AS builder +RUN adduser --system --no-create-home --group --uid 2101 java +WORKDIR /opt/fhir +COPY --chown=root:java ./ ./ +RUN chown root:java ./ && \ + chmod 750 ./ ./lib ./dsf_fhir_start.sh && \ + chmod 640 ./dsf_fhir.jar ./lib/*.jar && \ + chmod 1775 ./log + + FROM openjdk:11-slim -MAINTAINER Hauke Hund +LABEL maintainer="hauke.hund@hs-heilbronn.de" EXPOSE 8080 RUN adduser --system --no-create-home --group --uid 2101 java WORKDIR /opt/fhir -COPY --chown=root:java ./ ./ -RUN chown root:java ./ && chmod 750 ./ ./lib ./dsf_fhir_start.sh && chmod 640 ./dsf_fhir.jar ./lib/*.jar && chmod 1775 ./log +COPY --from=builder /opt/fhir ./ USER java ENTRYPOINT ["./dsf_fhir_start.sh"] diff --git a/dsf-fhir/dsf-fhir-server-jetty/pom.xml b/dsf-fhir/dsf-fhir-server-jetty/pom.xml index 89cb065e5..bc0708572 100755 --- a/dsf-fhir/dsf-fhir-server-jetty/pom.xml +++ b/dsf-fhir/dsf-fhir-server-jetty/pom.xml @@ -7,7 +7,7 @@ org.highmed.dsf dsf-fhir-pom - 0.1.0 + 0.2.0 @@ -46,7 +46,6 @@ javax.mail mail - 1.4.7 diff --git a/dsf-fhir/dsf-fhir-server/pom.xml b/dsf-fhir/dsf-fhir-server/pom.xml index fe3647577..a215c4927 100755 --- a/dsf-fhir/dsf-fhir-server/pom.xml +++ b/dsf-fhir/dsf-fhir-server/pom.xml @@ -7,7 +7,7 @@ org.highmed.dsf dsf-fhir-pom - 0.1.0 + 0.2.0 @@ -79,6 +79,10 @@ ca.uhn.hapi.fhir hapi-fhir-structures-r4 + + ca.uhn.hapi.fhir + hapi-fhir-structures-r5 + ca.uhn.hapi.fhir hapi-fhir-validation @@ -88,18 +92,8 @@ hapi-fhir-validation-resources-r4 - com.helger - ph-schematron - - - org.glassfish.jaxb - jaxb-core - - - com.helger - ph-jaxb-pom - - + ca.uhn.hapi.fhir + hapi-fhir-validation-resources-r5 @@ -141,11 +135,12 @@ javax-websocket-server-impl test - + + org.mockito mockito-core @@ -157,6 +152,19 @@ org.highmed.dsf dsf-tools-bundle-generator + runtime + + + de.hs-heilbronn.mi + log4j2-utils + runtime + + + + + com.lmax + disruptor + test @@ -209,6 +217,7 @@ ${project.basedir}/src/main/resources/fhir ${project.basedir} + false @@ -216,7 +225,7 @@ - diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AbstractAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AbstractAuthorizationRule.java index 69f0711db..b7bdfcc71 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AbstractAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AbstractAuthorizationRule.java @@ -118,20 +118,6 @@ public final Optional reasonDeleteAllowed(User user, R oldResource) } } - @Override - public final Optional reasonSearchAllowed(User user) - { - try (Connection connection = daoProvider.newReadOnlyAutoCommitTransaction()) - { - return reasonSearchAllowed(connection, user); - } - catch (SQLException e) - { - logger.warn("Error while accessing database", e); - throw new RuntimeException(e); - } - } - protected final boolean isLocalUser(User user) { return user != null && UserRole.LOCAL.equals(user.getRole()); @@ -201,11 +187,11 @@ protected final boolean isCurrentUserPartOfReferencedOrganization(Connection con { ResourceReference resReference = new ResourceReference(referenceLocation, reference, Organization.class); - if (!EnumSet.of(ReferenceType.LITERAL_INTERNAL, ReferenceType.LOGICAL) - .contains(resReference.getType(serverBase))) + ReferenceType type = resReference.getType(serverBase); + if (!EnumSet.of(ReferenceType.LITERAL_INTERNAL, ReferenceType.LOGICAL).contains(type)) { logger.warn("Reference of type {} not supported while checking if user part of referenced organization", - resReference.getType(serverBase)); + type); return false; } @@ -247,7 +233,8 @@ protected final Optional createIfLiteralInternalOrLogicalRefe Reference reference, Class... referenceTypes) { ResourceReference r = new ResourceReference(referenceLocation, reference, referenceTypes); - if (EnumSet.of(ReferenceType.LITERAL_INTERNAL, ReferenceType.LOGICAL).contains(r.getType(serverBase))) + ReferenceType type = r.getType(serverBase); + if (EnumSet.of(ReferenceType.LITERAL_INTERNAL, ReferenceType.LOGICAL).contains(type)) return Optional.of(r); else return Optional.empty(); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ActivityDefinitionAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ActivityDefinitionAuthorizationRule.java index cbe5a5d92..a2c9a3314 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ActivityDefinitionAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ActivityDefinitionAuthorizationRule.java @@ -224,10 +224,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Ac } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of ActivityDefinition authorized for {} user '{}', will be fitered by user role", user.getRole(), user.getName()); return Optional.of("Allowed for all, filtered by user role"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of ActivityDefinition authorized for {} user '{}', will be fitered by user role", + user.getRole(), user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRule.java index 24064cb1c..8d8b54d42 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRule.java @@ -124,5 +124,5 @@ public interface AuthorizationRule * not null * @return Reason as String in {@link Optional#of(Object)} if delete allowed */ - Optional reasonSearchAllowed(Connection connection, User user); + Optional reasonHistoryAllowed(User user); } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRuleProvider.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRuleProvider.java index d966d7525..0af345947 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRuleProvider.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRuleProvider.java @@ -2,45 +2,65 @@ import java.util.Optional; +import org.hl7.fhir.r4.model.ActivityDefinition; +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.Group; +import org.hl7.fhir.r4.model.HealthcareService; +import org.hl7.fhir.r4.model.Location; +import org.hl7.fhir.r4.model.NamingSystem; +import org.hl7.fhir.r4.model.Organization; +import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Practitioner; +import org.hl7.fhir.r4.model.PractitionerRole; +import org.hl7.fhir.r4.model.Provenance; +import org.hl7.fhir.r4.model.ResearchStudy; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.Subscription; +import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.ValueSet; + public interface AuthorizationRuleProvider { - ActivityDefinitionAuthorizationRule getActivityDefinitionAuthorizationRule(); + AuthorizationRule getActivityDefinitionAuthorizationRule(); - BinaryAuthorizationRule getBinaryAuthorizationRule(); + AuthorizationRule getBinaryAuthorizationRule(); - BundleAuthorizationRule getBundleAuthorizationRule(); + AuthorizationRule getBundleAuthorizationRule(); - CodeSystemAuthorizationRule getCodeSystemAuthorizationRule(); + AuthorizationRule getCodeSystemAuthorizationRule(); - EndpointAuthorizationRule getEndpointAuthorizationRule(); + AuthorizationRule getEndpointAuthorizationRule(); - GroupAuthorizationRule getGroupAuthorizationRule(); + AuthorizationRule getGroupAuthorizationRule(); - HealthcareServiceAuthorizationRule getHealthcareServiceAuthorizationRule(); + AuthorizationRule getHealthcareServiceAuthorizationRule(); - LocationAuthorizationRule getLocationAuthorizationRule(); + AuthorizationRule getLocationAuthorizationRule(); - NamingSystemAuthorizationRule getNamingSystemAuthorizationRule(); + AuthorizationRule getNamingSystemAuthorizationRule(); - OrganizationAuthorizationRule getOrganizationAuthorizationRule(); + AuthorizationRule getOrganizationAuthorizationRule(); - PatientAuthorizationRule getPatientAuthorizationRule(); + AuthorizationRule getPatientAuthorizationRule(); - PractitionerAuthorizationRule getPractitionerAuthorizationRule(); + AuthorizationRule getPractitionerAuthorizationRule(); - PractitionerRoleAuthorizationRule getPractitionerRoleAuthorizationRule(); + AuthorizationRule getPractitionerRoleAuthorizationRule(); - ProvenanceAuthorizationRule getProvenanceAuthorizationRule(); + AuthorizationRule getProvenanceAuthorizationRule(); - ResearchStudyAuthorizationRule getResearchStudyAuthorizationRule(); + AuthorizationRule getResearchStudyAuthorizationRule(); - StructureDefinitionAuthorizationRule getStructureDefinitionAuthorizationRule(); + AuthorizationRule getStructureDefinitionAuthorizationRule(); - SubscriptionAuthorizationRule getSubscriptionAuthorizationRule(); + AuthorizationRule getSubscriptionAuthorizationRule(); - TaskAuthorizationRule getTaskAuthorizationRule(); + AuthorizationRule getTaskAuthorizationRule(); - ValueSetAuthorizationRule getValueSetAuthorizationRule(); + AuthorizationRule getValueSetAuthorizationRule(); Optional> getAuthorizationRule(Class resourceClass); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRuleProviderImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRuleProviderImpl.java index 4af4770e5..6310cfee5 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRuleProviderImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/AuthorizationRuleProviderImpl.java @@ -29,45 +29,45 @@ public class AuthorizationRuleProviderImpl implements AuthorizationRuleProvider { - private final ActivityDefinitionAuthorizationRule activityDefinitionAuthorizationRule; - private final BinaryAuthorizationRule binaryAuthorizationRule; - private final BundleAuthorizationRule bundleAuthorizationRule; - private final CodeSystemAuthorizationRule codeSystemAuthorizationRule; - private final EndpointAuthorizationRule endpointAuthorizationRule; - private final GroupAuthorizationRule groupAuthorizationRule; - private final HealthcareServiceAuthorizationRule healthcareServiceAuthorizationRule; - private final LocationAuthorizationRule locationAuthorizationRule; - private final NamingSystemAuthorizationRule namingSystemAuthorizationRule; - private final OrganizationAuthorizationRule organizationAuthorizationRule; - private final PatientAuthorizationRule patientAuthorizationRule; - private final PractitionerAuthorizationRule practitionerAuthorizationRule; - private final PractitionerRoleAuthorizationRule practitionerRoleAuthorizationRule; - private final ProvenanceAuthorizationRule provenanceAuthorizationRule; - private final ResearchStudyAuthorizationRule researchStudyAuthorizationRule; - private final StructureDefinitionAuthorizationRule structureDefinitionAuthorizationRule; - private final SubscriptionAuthorizationRule subscriptionAuthorizationRule; - private final TaskAuthorizationRule taskAuthorizationRule; - private final ValueSetAuthorizationRule valueSetAuthorizationRule; + private final AuthorizationRule activityDefinitionAuthorizationRule; + private final AuthorizationRule binaryAuthorizationRule; + private final AuthorizationRule bundleAuthorizationRule; + private final AuthorizationRule codeSystemAuthorizationRule; + private final AuthorizationRule endpointAuthorizationRule; + private final AuthorizationRule groupAuthorizationRule; + private final AuthorizationRule healthcareServiceAuthorizationRule; + private final AuthorizationRule locationAuthorizationRule; + private final AuthorizationRule namingSystemAuthorizationRule; + private final AuthorizationRule organizationAuthorizationRule; + private final AuthorizationRule patientAuthorizationRule; + private final AuthorizationRule practitionerAuthorizationRule; + private final AuthorizationRule practitionerRoleAuthorizationRule; + private final AuthorizationRule provenanceAuthorizationRule; + private final AuthorizationRule researchStudyAuthorizationRule; + private final AuthorizationRule structureDefinitionAuthorizationRule; + private final AuthorizationRule subscriptionAuthorizationRule; + private final AuthorizationRule taskAuthorizationRule; + private final AuthorizationRule valueSetAuthorizationRule; private final Map, AuthorizationRule> authorizationRulesByResourecClass = new HashMap<>(); private final Map> authorizationRulesByResourceTypeName = new HashMap<>(); - public AuthorizationRuleProviderImpl(ActivityDefinitionAuthorizationRule activityDefinitionAuthorizationRule, - BinaryAuthorizationRule binaryAuthorizationRule, BundleAuthorizationRule bundleAuthorizationRule, - CodeSystemAuthorizationRule codeSystemAuthorizationRule, - EndpointAuthorizationRule endpointAuthorizationRule, GroupAuthorizationRule groupAuthorizationRule, - HealthcareServiceAuthorizationRule healthcareServiceAuthorizationRule, - LocationAuthorizationRule locationAuthorizationRule, - NamingSystemAuthorizationRule namingSystemAuthorizationRule, - OrganizationAuthorizationRule organizationAuthorizationRule, - PatientAuthorizationRule patientAuthorizationRule, - PractitionerAuthorizationRule practitionerAuthorizationRule, - PractitionerRoleAuthorizationRule practitionerRoleAuthorizationRule, - ProvenanceAuthorizationRule provenanceAuthorizationRule, - ResearchStudyAuthorizationRule researchStudyAuthorizationRule, - StructureDefinitionAuthorizationRule structureDefinitionAuthorizationRule, - SubscriptionAuthorizationRule subscriptionAuthorizationRule, TaskAuthorizationRule taskAuthorizationRule, - ValueSetAuthorizationRule valueSetAuthorizationRule) + public AuthorizationRuleProviderImpl(AuthorizationRule activityDefinitionAuthorizationRule, + AuthorizationRule binaryAuthorizationRule, AuthorizationRule bundleAuthorizationRule, + AuthorizationRule codeSystemAuthorizationRule, + AuthorizationRule endpointAuthorizationRule, AuthorizationRule groupAuthorizationRule, + AuthorizationRule healthcareServiceAuthorizationRule, + AuthorizationRule locationAuthorizationRule, + AuthorizationRule namingSystemAuthorizationRule, + AuthorizationRule organizationAuthorizationRule, + AuthorizationRule patientAuthorizationRule, + AuthorizationRule practitionerAuthorizationRule, + AuthorizationRule practitionerRoleAuthorizationRule, + AuthorizationRule provenanceAuthorizationRule, + AuthorizationRule researchStudyAuthorizationRule, + AuthorizationRule structureDefinitionAuthorizationRule, + AuthorizationRule subscriptionAuthorizationRule, + AuthorizationRule taskAuthorizationRule, AuthorizationRule valueSetAuthorizationRule) { this.activityDefinitionAuthorizationRule = activityDefinitionAuthorizationRule; this.binaryAuthorizationRule = binaryAuthorizationRule; @@ -114,115 +114,115 @@ public AuthorizationRuleProviderImpl(ActivityDefinitionAuthorizationRule activit } @Override - public ActivityDefinitionAuthorizationRule getActivityDefinitionAuthorizationRule() + public AuthorizationRule getActivityDefinitionAuthorizationRule() { return activityDefinitionAuthorizationRule; } @Override - public BinaryAuthorizationRule getBinaryAuthorizationRule() + public AuthorizationRule getBinaryAuthorizationRule() { return binaryAuthorizationRule; } @Override - public BundleAuthorizationRule getBundleAuthorizationRule() + public AuthorizationRule getBundleAuthorizationRule() { return bundleAuthorizationRule; } @Override - public CodeSystemAuthorizationRule getCodeSystemAuthorizationRule() + public AuthorizationRule getCodeSystemAuthorizationRule() { return codeSystemAuthorizationRule; } @Override - public EndpointAuthorizationRule getEndpointAuthorizationRule() + public AuthorizationRule getEndpointAuthorizationRule() { return endpointAuthorizationRule; } @Override - public GroupAuthorizationRule getGroupAuthorizationRule() + public AuthorizationRule getGroupAuthorizationRule() { return groupAuthorizationRule; } @Override - public HealthcareServiceAuthorizationRule getHealthcareServiceAuthorizationRule() + public AuthorizationRule getHealthcareServiceAuthorizationRule() { return healthcareServiceAuthorizationRule; } @Override - public LocationAuthorizationRule getLocationAuthorizationRule() + public AuthorizationRule getLocationAuthorizationRule() { return locationAuthorizationRule; } @Override - public NamingSystemAuthorizationRule getNamingSystemAuthorizationRule() + public AuthorizationRule getNamingSystemAuthorizationRule() { return namingSystemAuthorizationRule; } @Override - public OrganizationAuthorizationRule getOrganizationAuthorizationRule() + public AuthorizationRule getOrganizationAuthorizationRule() { return organizationAuthorizationRule; } @Override - public PatientAuthorizationRule getPatientAuthorizationRule() + public AuthorizationRule getPatientAuthorizationRule() { return patientAuthorizationRule; } @Override - public PractitionerAuthorizationRule getPractitionerAuthorizationRule() + public AuthorizationRule getPractitionerAuthorizationRule() { return practitionerAuthorizationRule; } @Override - public PractitionerRoleAuthorizationRule getPractitionerRoleAuthorizationRule() + public AuthorizationRule getPractitionerRoleAuthorizationRule() { return practitionerRoleAuthorizationRule; } @Override - public ProvenanceAuthorizationRule getProvenanceAuthorizationRule() + public AuthorizationRule getProvenanceAuthorizationRule() { return provenanceAuthorizationRule; } @Override - public ResearchStudyAuthorizationRule getResearchStudyAuthorizationRule() + public AuthorizationRule getResearchStudyAuthorizationRule() { return researchStudyAuthorizationRule; } @Override - public StructureDefinitionAuthorizationRule getStructureDefinitionAuthorizationRule() + public AuthorizationRule getStructureDefinitionAuthorizationRule() { return structureDefinitionAuthorizationRule; } @Override - public SubscriptionAuthorizationRule getSubscriptionAuthorizationRule() + public AuthorizationRule getSubscriptionAuthorizationRule() { return subscriptionAuthorizationRule; } @Override - public TaskAuthorizationRule getTaskAuthorizationRule() + public AuthorizationRule getTaskAuthorizationRule() { return taskAuthorizationRule; } @Override - public ValueSetAuthorizationRule getValueSetAuthorizationRule() + public AuthorizationRule getValueSetAuthorizationRule() { return valueSetAuthorizationRule; } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/BinaryAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/BinaryAuthorizationRule.java index f7012ba20..fa6380629 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/BinaryAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/BinaryAuthorizationRule.java @@ -119,10 +119,11 @@ public Optional reasonUpdateAllowed(Connection connection, User user, Bi oldResource.getSecurityContext(), Organization.class); ResourceReference newReference = new ResourceReference("Binary.SecurityContext", newResource.getSecurityContext(), Organization.class); - if (EnumSet.of(ReferenceType.LITERAL_INTERNAL, ReferenceType.LOGICAL) - .contains(oldReference.getType(serverBase)) - && EnumSet.of(ReferenceType.LITERAL_INTERNAL, ReferenceType.LOGICAL) - .contains(newReference.getType(serverBase))) + ReferenceType oldType = oldReference.getType(serverBase); + ReferenceType newType = newReference.getType(serverBase); + + if (EnumSet.of(ReferenceType.LITERAL_INTERNAL, ReferenceType.LOGICAL).contains(oldType) + && EnumSet.of(ReferenceType.LITERAL_INTERNAL, ReferenceType.LOGICAL).contains(newType)) { Optional oldSecurityContext = referenceResolver.resolveReference(user, oldReference, connection); @@ -188,10 +189,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Bi } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of Binary authorized for {} user '{}', will be fitered by users organization {}", user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); return Optional.of("Allowed for all, filtered by users organization"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Binary authorized for {} user '{}', will be fitered by users organization {}", + user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); + return Optional.of("Allowed for all, filtered by users organization"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/BundleAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/BundleAuthorizationRule.java index b6e9e599e..94b3ee0f2 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/BundleAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/BundleAuthorizationRule.java @@ -67,7 +67,7 @@ private Optional newResourceOk(Bundle newResource) @Override public Optional reasonReadAllowed(Connection connection, User user, Bundle existingResource) { - if (isLocalUser(user) && hasLocalAuthorizationRole(existingResource)) + if (isLocalUser(user) && hasLocalOrRemoteAuthorizationRole(existingResource)) { logger.info("Read of Bundle authorized for local user '{}', Bundle has local or remote authorization role", user.getName()); @@ -127,10 +127,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Bu } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of Bundle authorized for {} user '{}', will be fitered by user role", user.getRole(), user.getName()); return Optional.of("Allowed for all, filtered by user role"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Bundle authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/CodeSystemAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/CodeSystemAuthorizationRule.java index a6c6f9cf5..73267f41d 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/CodeSystemAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/CodeSystemAuthorizationRule.java @@ -145,10 +145,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Co } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of CodeSystem authorized for {} user '{}', will be fitered by user role", user.getRole(), user.getName()); return Optional.of("Allowed for all, filtered by user role"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of CodeSystem authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/EndpointAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/EndpointAuthorizationRule.java index 14967c401..4ecd8c04f 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/EndpointAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/EndpointAuthorizationRule.java @@ -132,7 +132,7 @@ private boolean endpointWithAddressExists(Connection connection, String address) try { PartialResult result = dao.searchWithTransaction(connection, query); - return result.getOverallCount() >= 1; + return result.getTotal() >= 1; } catch (SQLException e) { @@ -154,7 +154,7 @@ private boolean endpointWithIdentifierExists(Connection connection, String ident try { PartialResult result = dao.searchWithTransaction(connection, query); - return result.getOverallCount() >= 1; + return result.getTotal() >= 1; } catch (SQLException e) { @@ -257,10 +257,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, En } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of Endpoint authorized for {} user '{}', will be fitered by user role", user.getRole(), user.getName()); return Optional.of("Allowed for all, filtered by user role"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Endpoint authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/GroupAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/GroupAuthorizationRule.java index 91f527cdb..c8db841a2 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/GroupAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/GroupAuthorizationRule.java @@ -118,10 +118,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Gr } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of Group authorized for {} user '{}', will be fitered by users organization {}", user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); return Optional.of("Allowed for all, filtered by users organization"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Group authorized for {} user '{}', will be fitered by users organization {}", + user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); + return Optional.of("Allowed for all, filtered by users organization"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/HealthcareServiceAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/HealthcareServiceAuthorizationRule.java index bd3fdb272..05e531c70 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/HealthcareServiceAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/HealthcareServiceAuthorizationRule.java @@ -96,10 +96,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, He } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { - logger.info("Search of HealthcareService authorized for {} user '{}', will be fitered by users organization {}", - user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); - return Optional.of("Allowed for all, filtered by users organization"); + logger.info("Search of HealthcareService authorized for {} user '{}', will be fitered by user role", + user.getRole(), user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of HealthcareService authorized for {} user '{}', will be fitered by user role", + user.getRole(), user.getName()); + return Optional.of("Allowed for all, filtered by user role"); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/LocationAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/LocationAuthorizationRule.java index 38a3aa8bc..c84936d35 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/LocationAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/LocationAuthorizationRule.java @@ -93,10 +93,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Lo } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { - logger.info("Search of Location authorized for {} user '{}', will be fitered by users organization {}", - user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); - return Optional.of("Allowed for all, filtered by users organization"); + logger.info("Search of Location authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Location authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/NamingSystemAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/NamingSystemAuthorizationRule.java index 1c59a5ffb..d363c5580 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/NamingSystemAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/NamingSystemAuthorizationRule.java @@ -143,10 +143,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Na } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of NamingSystem authorized for {} user '{}', will be fitered by user role", user.getRole(), user.getName()); return Optional.of("Allowed for all, filtered by user role"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of NamingSystem authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/OrganizationAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/OrganizationAuthorizationRule.java index fbf4c241d..34b232381 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/OrganizationAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/OrganizationAuthorizationRule.java @@ -160,7 +160,7 @@ private boolean organizationWithIdentifierExists(Connection connection, String i try { PartialResult result = dao.searchWithTransaction(connection, query); - return result.getOverallCount() >= 1; + return result.getTotal() >= 1; } catch (SQLException e) { @@ -272,10 +272,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Or } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of Organization authorized for {} user '{}', will be fitered by user role", user.getRole(), user.getName()); return Optional.of("Allowed for all, filtered by user role"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Organization authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PatientAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PatientAuthorizationRule.java index 235657d8a..5e57e11c5 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PatientAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PatientAuthorizationRule.java @@ -85,10 +85,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Pa } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { - logger.info("Search of Patient authorized for {} user '{}', will be fitered by users organization {}", - user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); - return Optional.of("Allowed for all, filtered by users organization"); + logger.info("Search of Patient authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Patient authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PractitionerAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PractitionerAuthorizationRule.java index 4349b2f55..b581ad926 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PractitionerAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PractitionerAuthorizationRule.java @@ -120,7 +120,7 @@ private boolean practitionerRoleWithPractitionerAndUsersOrganizationExists(Conne try { PartialResult result = dao.searchWithTransaction(connection, query); - return result.getOverallCount() > 0; + return result.getTotal() > 0; } catch (SQLException e) { @@ -162,10 +162,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Pr } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { - logger.info("Search of Practitioner authorized for {} user '{}', will be fitered by users organization {}", - user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); - return Optional.of("Allowed for all, filtered by users organization"); + logger.info("Search of Practitioner authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Practitioner authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PractitionerRoleAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PractitionerRoleAuthorizationRule.java index e4cbec732..5f52d2b59 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PractitionerRoleAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/PractitionerRoleAuthorizationRule.java @@ -223,10 +223,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Pr } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of PractitionerRole authorized for {} user '{}', will be fitered by users organization {}", user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); return Optional.of("Allowed for all, filtered by users organization"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of PractitionerRole authorized for {} user '{}', will be fitered by users organization {}", + user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); + return Optional.of("Allowed for all, filtered by users organization"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ProvenanceAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ProvenanceAuthorizationRule.java index cbf41e9d2..a061cd939 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ProvenanceAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ProvenanceAuthorizationRule.java @@ -85,10 +85,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Pr } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of Provenance authorized for {} user '{}', will be fitered by users organization {}", user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); return Optional.of("Allowed for all, filtered by users organization"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Provenance authorized for {} user '{}', will be fitered by users organization {}", + user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); + return Optional.of("Allowed for all, filtered by users organization"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ResearchStudyAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ResearchStudyAuthorizationRule.java index 92fe9c4c7..d786f57a2 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ResearchStudyAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ResearchStudyAuthorizationRule.java @@ -145,6 +145,8 @@ private Optional newResourceOk(Connection connection, User user, Researc errors.add("ResearchStudy.enrollment one or more Group references missing"); } + // TODO: hasPrincipalInvestigator check is only optional for Feasability Requests. For full Data Sharing + // processes, the field is mandatory and should lead to a validation error if not supplied. if (newResource.hasPrincipalInvestigator()) { Optional practitioner = resolvePractitioner(connection, user, @@ -164,10 +166,6 @@ private Optional newResourceOk(Connection connection, User user, Researc "ResearchStudy.principalInvestigator not resolved or not instance of Practitioner or not active"); } } - else - { - errors.add("ResearchStudy.principalInvestigator missing"); - } if (errors.isEmpty()) return Optional.empty(); @@ -221,7 +219,7 @@ private boolean practitionerRoleExists(Connection connection, User user, IdType try { - return dao.searchWithTransaction(connection, query).getOverallCount() == 1; + return dao.searchWithTransaction(connection, query).getTotal() == 1; } catch (SQLException e) { @@ -253,7 +251,7 @@ private boolean researchStudyWithIdentifierExists(Connection connection, String try { PartialResult result = dao.searchWithTransaction(connection, query); - return result.getOverallCount() >= 1; + return result.getTotal() >= 1; } catch (SQLException e) { @@ -400,10 +398,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Re } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of ResearchStudy authorized for {} user '{}', will be fitered by users organization {}", user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); return Optional.of("Allowed for all, filtered by users organization"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of ResearchStudy authorized for {} user '{}', will be fitered by users organization {}", + user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); + return Optional.of("Allowed for all, filtered by users organization"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/RootAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/RootAuthorizationRule.java new file mode 100644 index 000000000..ad75c176a --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/RootAuthorizationRule.java @@ -0,0 +1,77 @@ +package org.highmed.dsf.fhir.authorization; + +import java.sql.Connection; +import java.util.Optional; + +import org.highmed.dsf.fhir.authentication.User; +import org.hl7.fhir.r4.model.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RootAuthorizationRule implements AuthorizationRule +{ + private static final Logger logger = LoggerFactory.getLogger(RootAuthorizationRule.class); + + @Override + public Optional reasonCreateAllowed(User user, Resource newResource) + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional reasonCreateAllowed(Connection connection, User user, Resource newResource) + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional reasonReadAllowed(User user, Resource existingResource) + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional reasonReadAllowed(Connection connection, User user, Resource existingResource) + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional reasonUpdateAllowed(User user, Resource oldResource, Resource newResource) + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional reasonUpdateAllowed(Connection connection, User user, Resource oldResource, + Resource newResource) + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional reasonDeleteAllowed(User user, Resource oldResource) + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional reasonDeleteAllowed(Connection connection, User user, Resource oldResource) + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional reasonSearchAllowed(User user) + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("Root History authorized for {} user '{}', will be fitered by user role or users organization {}", + user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); + return Optional.of("Allowed for all, filtered by user role or users organization"); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/StructureDefinitionAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/StructureDefinitionAuthorizationRule.java index 717d5da37..cbcbf7097 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/StructureDefinitionAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/StructureDefinitionAuthorizationRule.java @@ -153,14 +153,15 @@ public Optional reasonUpdateAllowed(Connection connection, User user, St if (isSame(oldResource, newResource) && statusOk(oldResource, newResource)) { logger.info( - "Update of StructureDefinition authorized for local user '{}', criteria, type and payload same as existing StructureDefinition", - user.getName()); - return Optional.of("local user; criteria, type and payload same as existing StructureDefinition"); + "Update of StructureDefinition authorized for local user '{}', url and version same as existing StructureDefinition, status change {} -> {} ok", + user.getName(), oldResource.getStatus(), newResource.getStatus()); + return Optional.of("local user; url and version same as existing StructureDefinition"); } else { logger.warn( - "Update of StructureDefinition unauthorized, other StructureDefinition with criteria, type and payload already exists"); + "Update of StructureDefinition unauthorized, other StructureDefinition with same url and version exists, illegal status change {} -> {}", + oldResource.getStatus(), newResource.getStatus()); return Optional.empty(); } } @@ -212,10 +213,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, St } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of StructureDefinition authorized for {} user '{}', will be fitered by user role", user.getRole(), user.getName()); return Optional.of("Allowed for all, filtered by user role"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of StructureDefinition authorized for {} user '{}', will be fitered by user role", + user.getRole(), user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/SubscriptionAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/SubscriptionAuthorizationRule.java index 0acc6d1f9..21ed6fa30 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/SubscriptionAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/SubscriptionAuthorizationRule.java @@ -158,7 +158,7 @@ private boolean resourceExists(Connection connection, Subscription newResource) try { PartialResult result = dao.searchWithTransaction(connection, query); - return result.getOverallCount() >= 1; + return result.getTotal() >= 1; } catch (SQLException e) { @@ -261,10 +261,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Su } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of Subscription authorized for {} user '{}', will be fitered by user role", user.getRole(), user.getName()); return Optional.of("Allowed for all, filtered by user role"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Subscription authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/TaskAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/TaskAuthorizationRule.java index 1bd3ce9c6..c952f4e8b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/TaskAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/TaskAuthorizationRule.java @@ -394,10 +394,18 @@ && isCurrentUserPartOfReferencedOrganization(connection, user, "task.restriction } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of Task authorized for {} user '{}', will be fitered by users organization {}", user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); return Optional.of("Allowed for all, filtered by users organization"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of Task authorized for {} user '{}', will be fitered by users organization {}", + user.getRole(), user.getName(), user.getOrganization().getIdElement().getValueAsString()); + return Optional.of("Allowed for all, filtered by users organization"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ValueSetAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ValueSetAuthorizationRule.java index 98ef2713a..436aa8e73 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ValueSetAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/authorization/ValueSetAuthorizationRule.java @@ -144,10 +144,18 @@ public Optional reasonDeleteAllowed(Connection connection, User user, Va } @Override - public Optional reasonSearchAllowed(Connection connection, User user) + public Optional reasonSearchAllowed(User user) { logger.info("Search of ValueSet authorized for {} user '{}', will be fitered by user role", user.getRole(), user.getName()); return Optional.of("Allowed for all, filtered by user role"); } + + @Override + public Optional reasonHistoryAllowed(User user) + { + logger.info("History of ValueSet authorized for {} user '{}', will be fitered by user role", user.getRole(), + user.getName()); + return Optional.of("Allowed for all, filtered by user role"); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/client/ClientProviderImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/client/ClientProviderImpl.java index 6f9e2aee8..addfbc845 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/client/ClientProviderImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/client/ClientProviderImpl.java @@ -6,7 +6,7 @@ import org.highmed.dsf.fhir.dao.EndpointDao; import org.highmed.dsf.fhir.help.ExceptionHandler; -import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.fhir.client.FhirWebserviceClient; import org.highmed.fhir.client.FhirWebserviceClientJersey; import org.slf4j.Logger; @@ -29,14 +29,14 @@ public class ClientProviderImpl implements ClientProvider, InitializingBean private final String remoteProxyUsername; private final String remoteProxySchemeHostPort; private final FhirContext fhirContext; - private final ReferenceExtractor referenceExtractor; + private final ReferenceCleaner referenceCleaner; private final EndpointDao endpointDao; private final ExceptionHandler exceptionHandler; public ClientProviderImpl(KeyStore webserviceTrustStore, KeyStore webserviceKeyStore, char[] webserviceKeyStorePassword, int remoteReadTimeout, int remoteConnectTimeout, char[] remoteProxyPassword, String remoteProxyUsername, String remoteProxySchemeHostPort, - FhirContext fhirContext, ReferenceExtractor referenceExtractor, EndpointDao endpointDao, + FhirContext fhirContext, ReferenceCleaner referenceCleaner, EndpointDao endpointDao, ExceptionHandler exceptionHandler) { this.webserviceTrustStore = webserviceTrustStore; @@ -48,7 +48,7 @@ public ClientProviderImpl(KeyStore webserviceTrustStore, KeyStore webserviceKeyS this.remoteProxyUsername = remoteProxyUsername; this.remoteProxySchemeHostPort = remoteProxySchemeHostPort; this.fhirContext = fhirContext; - this.referenceExtractor = referenceExtractor; + this.referenceCleaner = referenceCleaner; this.endpointDao = endpointDao; this.exceptionHandler = exceptionHandler; } @@ -61,7 +61,7 @@ public void afterPropertiesSet() throws Exception Objects.requireNonNull(webserviceKeyStorePassword, "webserviceKeyStorePassword"); Objects.requireNonNull(fhirContext, "fhirContext"); - Objects.requireNonNull(referenceExtractor, "referenceExtractor"); + Objects.requireNonNull(referenceCleaner, "referenceCleaner"); Objects.requireNonNull(endpointDao, "endpointDao"); Objects.requireNonNull(exceptionHandler, "exceptionHandler"); } @@ -76,8 +76,7 @@ public Optional getClient(String serverBase) { FhirWebserviceClient client = new FhirWebserviceClientJersey(serverBase, webserviceTrustStore, webserviceKeyStore, webserviceKeyStorePassword, remoteProxySchemeHostPort, remoteProxyUsername, - remoteProxyPassword, remoteConnectTimeout, remoteReadTimeout, null, fhirContext, - referenceExtractor); + remoteProxyPassword, remoteConnectTimeout, remoteReadTimeout, null, fhirContext, referenceCleaner); return Optional.of(client); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/HistoryDao.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/HistoryDao.java new file mode 100644 index 000000000..0370c8031 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/HistoryDao.java @@ -0,0 +1,24 @@ +package org.highmed.dsf.fhir.dao; + +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +import org.highmed.dsf.fhir.history.AtParameter; +import org.highmed.dsf.fhir.history.History; +import org.highmed.dsf.fhir.history.SinceParameter; +import org.highmed.dsf.fhir.history.user.HistoryUserFilter; +import org.highmed.dsf.fhir.search.PageAndCount; +import org.hl7.fhir.r4.model.Resource; + +public interface HistoryDao +{ + History readHistory(List filters, PageAndCount pageAndCount, AtParameter atParameter, + SinceParameter sinceParameter) throws SQLException; + + History readHistory(HistoryUserFilter filter, PageAndCount pageAndCount, AtParameter atParameter, + SinceParameter sinceParameter, Class resource) throws SQLException; + + History readHistory(HistoryUserFilter filter, PageAndCount pageAndCount, AtParameter atParameter, + SinceParameter sinceParameter, Class resource, UUID id) throws SQLException; +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/OrganizationDao.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/OrganizationDao.java index fcf286a59..b29f0c089 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/OrganizationDao.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/OrganizationDao.java @@ -10,6 +10,13 @@ public interface OrganizationDao extends ResourceDao { Optional readActiveNotDeletedByThumbprint(String thumbprintHex) throws SQLException; + /** + * Uses http://highmed.org/fhir/NamingSystem/organization-identifier as identifier system + * + * @param identifierValue + * @return {@link Optional#empty()} if param identifierValue is null or {@link String#isBlank()} + * @throws SQLException + */ Optional readActiveNotDeletedByIdentifier(String identifierValue) throws SQLException; boolean existsNotDeletedByThumbprintWithTransaction(Connection connection, String thumbprintHex) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/ReadByUrlDao.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/ReadByUrlDao.java index 96f2d5868..45d818d33 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/ReadByUrlDao.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/ReadByUrlDao.java @@ -12,6 +12,8 @@ public interface ReadByUrlDao Optional readByUrlAndVersion(String url, String version) throws SQLException; + Optional readByUrlAndVersionWithTransaction(Connection connection, String urlAndVersion) throws SQLException; + Optional readByUrlAndVersionWithTransaction(Connection connection, String url, String version) throws SQLException; } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/ResourceDao.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/ResourceDao.java index 4c2c80bb7..7adf96b2f 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/ResourceDao.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/ResourceDao.java @@ -2,6 +2,7 @@ import java.sql.Connection; import java.sql.SQLException; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -90,8 +91,10 @@ public interface ResourceDao * @return {@link Optional#empty()} if the given uuid is null, the given version is less then * {@value #FIRST_VERSION} or no resource could be found for the given uuid and version * @throws SQLException + * @throws ResourceDeletedException + * if a resource with the given uuid and version could be found, but is the delete history entry */ - Optional readVersion(UUID uuid, long version) throws SQLException; + Optional readVersion(UUID uuid, long version) throws SQLException, ResourceDeletedException; /** * @param connection @@ -103,8 +106,11 @@ public interface ResourceDao * @return {@link Optional#empty()} if the given uuid is null, the given version is less then * {@value #FIRST_VERSION} or no resource could be found for the given uuid and version * @throws SQLException + * @throws ResourceDeletedException + * if a resource with the given uuid and version could be found, but is the delete history entry */ - Optional readVersionWithTransaction(Connection connection, UUID uuid, long version) throws SQLException; + Optional readVersionWithTransaction(Connection connection, UUID uuid, long version) + throws SQLException, ResourceDeletedException; /** * @param uuid @@ -126,6 +132,16 @@ public interface ResourceDao */ Optional readIncludingDeletedWithTransaction(Connection connection, UUID uuid) throws SQLException; + List readAll() throws SQLException; + + /** + * @param connection + * not null + * @return + * @throws SQLException + */ + List readAllWithTransaction(Connection connection) throws SQLException; + /** * @param id * not null @@ -150,6 +166,34 @@ public interface ResourceDao */ boolean existsNotDeletedWithTransaction(Connection connection, String id, String version) throws SQLException; + /** + * Sets the version of the stored resource to latest version from DB plus 1. + * + * Does not check the latest version in DB before storing the update. + * + * Resurrects all old versions (removes deleted flag) if the latest version in DB is marked as deleted. + * + * @param resource + * not null + * @return the stored resource, not the same object as the given resource (defensive copy) + * @throws SQLException + * @throws ResourceNotFoundException + * if the given resource could not be found + * @see ResourceDao#update(Resource, Long) + */ + default R update(R resource) throws SQLException, ResourceNotFoundException + { + try + { + return update(resource, null); + } + catch (ResourceVersionNoMatchException e) + { + // should never be thrown if update is called with a null expectedVersion + throw new RuntimeException(e); + } + } + /** * Sets the version of the stored resource to latest version from DB plus 1. * @@ -173,6 +217,41 @@ public interface ResourceDao R update(R resource, Long expectedVersion) throws SQLException, ResourceNotFoundException, ResourceVersionNoMatchException; + /** + * Sets the version of the stored resource to latest version from DB plus 1. + * + * Does not check the latest version in DB before storing the update. + * + * Resurrects all old versions (removes deleted flag) if the latest version in DB is marked as deleted. + * + * @param connection + * not null, not {@link Connection#isReadOnly()} and not {@link Connection#getAutoCommit()} + * and {@link Connection#getTransactionIsolation()} one of {@link Connection#TRANSACTION_REPEATABLE_READ} + * or {@link Connection#TRANSACTION_SERIALIZABLE} + * @param resource + * not null + * @return + * @throws SQLException + * @throws ResourceNotFoundException + * if the given resource could not be found + * @throws IllegalArgumentException + * if the given connection is {@link Connection#isReadOnly()} or is {@link Connection#getAutoCommit()} + * or {@link Connection#getTransactionIsolation()} is not one of + * {@link Connection#TRANSACTION_REPEATABLE_READ} or {@link Connection#TRANSACTION_SERIALIZABLE} + */ + default R updateWithTransaction(Connection connection, R resource) throws SQLException, ResourceNotFoundException + { + try + { + return updateWithTransaction(connection, resource, null); + } + catch (ResourceVersionNoMatchException e) + { + // should never be thrown if update is called with a null expectedVersion + throw new RuntimeException(e); + } + } + /** * Sets the version of the stored resource to latest version from DB plus 1. * diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/StructureDefinitionDao.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/StructureDefinitionDao.java index bdb56892c..01263abd1 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/StructureDefinitionDao.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/StructureDefinitionDao.java @@ -1,5 +1,7 @@ package org.highmed.dsf.fhir.dao; -public interface StructureDefinitionDao extends StructureDefinitionDaoBase +import org.hl7.fhir.r4.model.StructureDefinition; + +public interface StructureDefinitionDao extends ResourceDao, ReadByUrlDao { } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/StructureDefinitionDaoBase.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/StructureDefinitionDaoBase.java deleted file mode 100755 index d5139388d..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/StructureDefinitionDaoBase.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.highmed.dsf.fhir.dao; - -import java.sql.SQLException; -import java.util.List; - -import org.hl7.fhir.r4.model.StructureDefinition; - -public interface StructureDefinitionDaoBase - extends ResourceDao, ReadByUrlDao -{ - List readAll() throws SQLException; -} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/StructureDefinitionSnapshotDao.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/StructureDefinitionSnapshotDao.java deleted file mode 100755 index aaeab502f..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/StructureDefinitionSnapshotDao.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.highmed.dsf.fhir.dao; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.UUID; - -import org.highmed.dsf.fhir.dao.exception.ResourceNotFoundException; -import org.highmed.dsf.fhir.service.SnapshotInfo; -import org.hl7.fhir.r4.model.StructureDefinition; - -public interface StructureDefinitionSnapshotDao extends StructureDefinitionDaoBase -{ - StructureDefinition create(UUID uuid, StructureDefinition resource, SnapshotInfo info) throws SQLException; - - StructureDefinition createWithTransaction(Connection connection, UUID uuid, StructureDefinition resource, - SnapshotInfo info) throws SQLException; - - StructureDefinition update(StructureDefinition resource, SnapshotInfo info) - throws SQLException, ResourceNotFoundException; - - StructureDefinition updateWithTransaction(Connection connection, StructureDefinition resource, SnapshotInfo info) - throws SQLException, ResourceNotFoundException; - - void deleteAllByDependency(String url) throws SQLException; - - void deleteAllByDependencyWithTransaction(Connection connection, String url) throws SQLException; -} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AbstractCommand.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AbstractCommand.java index 3d02ba199..26c22367b 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AbstractCommand.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AbstractCommand.java @@ -1,6 +1,7 @@ package org.highmed.dsf.fhir.dao.command; import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.prefer.PreferReturnType; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.slf4j.Logger; @@ -15,6 +16,7 @@ public abstract class AbstractCommand implements Command protected final int index; protected final User user; + protected final PreferReturnType returnType; protected final Bundle bundle; protected final BundleEntryComponent entry; @@ -22,14 +24,15 @@ public abstract class AbstractCommand implements Command protected final AuthorizationHelper authorizationHelper; - public AbstractCommand(int transactionPriority, int index, User user, Bundle bundle, BundleEntryComponent entry, - String serverBase, AuthorizationHelper authorizationHelper) + public AbstractCommand(int transactionPriority, int index, User user, PreferReturnType returnType, Bundle bundle, + BundleEntryComponent entry, String serverBase, AuthorizationHelper authorizationHelper) { this.transactionPriority = transactionPriority; this.index = index; this.user = user; + this.returnType = returnType; this.bundle = bundle; this.entry = entry; this.serverBase = serverBase; diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AbstractCommandWithResource.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AbstractCommandWithResource.java index db2551838..bb582920b 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AbstractCommandWithResource.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AbstractCommandWithResource.java @@ -4,6 +4,10 @@ import org.highmed.dsf.fhir.dao.ResourceDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; +import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.prefer.PreferReturnType; +import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceResolver; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Resource; @@ -15,16 +19,30 @@ public abstract class AbstractCommandWithResource referencesHelper; - public AbstractCommandWithResource(int transactionPriority, int index, User user, Bundle bundle, - BundleEntryComponent entry, String serverBase, AuthorizationHelper authorizationHelper, - R resource, D dao, ExceptionHandler exceptionHandler, ParameterConverter parameterConverter) + public AbstractCommandWithResource(int transactionPriority, int index, User user, PreferReturnType returnType, + Bundle bundle, BundleEntryComponent entry, String serverBase, AuthorizationHelper authorizationHelper, + R resource, D dao, ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + ResponseGenerator responseGenerator, ReferenceExtractor referenceExtractor, + ReferenceResolver referenceResolver) { - super(transactionPriority, index, user, bundle, entry, serverBase, authorizationHelper); + super(transactionPriority, index, user, returnType, bundle, entry, serverBase, authorizationHelper); this.resource = resource; this.dao = dao; this.exceptionHandler = exceptionHandler; this.parameterConverter = parameterConverter; + + referencesHelper = createReferencesHelper(index, user, serverBase, resource, responseGenerator, + referenceExtractor, referenceResolver); + } + + protected ReferencesHelper createReferencesHelper(int index, User user, String serverBase, R resource, + ResponseGenerator responseGenerator, ReferenceExtractor referenceExtractor, + ReferenceResolver referenceResolver) + { + return new ReferencesHelperImpl(index, user, resource, serverBase, referenceExtractor, referenceResolver, + responseGenerator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AuthorizationHelper.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AuthorizationHelper.java index 3199a2c9e..aecea1aa3 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AuthorizationHelper.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AuthorizationHelper.java @@ -16,7 +16,7 @@ public interface AuthorizationHelper void checkDeleteAllowed(Connection connection, User user, Resource oldResource); - void checkSearchAllowed(Connection connection, User user, String resourceTypeName); + void checkSearchAllowed(User user, String resourceTypeName); void filterIncludeResults(Connection connection, User user, Bundle multipleResult); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AuthorizationHelperImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AuthorizationHelperImpl.java index 2792823f8..46cf7fd72 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AuthorizationHelperImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/AuthorizationHelperImpl.java @@ -12,9 +12,9 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.help.ResponseGenerator; import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.SearchEntryMode; +import org.hl7.fhir.r4.model.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -120,10 +120,10 @@ public void checkDeleteAllowed(Connection connection, User user, Resource oldRes } @Override - public void checkSearchAllowed(Connection connection, User user, String resourceTypeName) + public void checkSearchAllowed(User user, String resourceTypeName) { Optional> optRule = getAuthorizationRule(resourceTypeName); - optRule.flatMap(rule -> rule.reasonSearchAllowed(connection, user)).ifPresentOrElse(reason -> + optRule.flatMap(rule -> rule.reasonSearchAllowed(user)).ifPresentOrElse(reason -> { audit.info("Search of resource {} allowed for user '{}', reason: {}", resourceTypeName, user.getName(), reason); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/BatchCommandList.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/BatchCommandList.java index d0d99eccd..3a70ca417 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/BatchCommandList.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/BatchCommandList.java @@ -15,7 +15,9 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; +import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleType; @@ -30,13 +32,20 @@ public class BatchCommandList implements CommandList private final DataSource dataSource; private final ExceptionHandler exceptionHandler; + private final ValidationHelper validationHelper; + private final SnapshotGenerator snapshotGenerator; + private final EventHandler eventHandler; private final List commands = new ArrayList<>(); - public BatchCommandList(DataSource dataSource, ExceptionHandler exceptionHandler, List commands) + public BatchCommandList(DataSource dataSource, ExceptionHandler exceptionHandler, ValidationHelper validationHelper, + SnapshotGenerator snapshotGenerator, EventHandler eventHandler, List commands) { this.dataSource = dataSource; this.exceptionHandler = exceptionHandler; + this.validationHelper = validationHelper; + this.snapshotGenerator = snapshotGenerator; + this.eventHandler = eventHandler; if (commands != null) this.commands.addAll(commands); @@ -65,8 +74,6 @@ public Bundle execute() throws WebApplicationException (int) (commands.size() / 0.75) + 1); Map idTranslationTable = new HashMap<>(); - commands.forEach(preExecute(idTranslationTable, caughtExceptions)); - if (hasModifyingCommands()) { logger.debug( @@ -78,6 +85,8 @@ public Bundle execute() throws WebApplicationException connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); } + commands.forEach(preExecute(idTranslationTable, connection, caughtExceptions)); + commands.forEach(execute(idTranslationTable, connection, caughtExceptions)); if (hasModifyingCommands()) @@ -150,7 +159,7 @@ private BundleEntryComponent toEntry(Exception exception) return entry; } - private Consumer preExecute(Map idTranslationTable, + private Consumer preExecute(Map idTranslationTable, Connection connection, Map caughtExceptions) { return command -> @@ -161,7 +170,7 @@ private Consumer preExecute(Map idTranslationTable, { logger.debug("Running pre-execute of command {} for entry at index {}", command.getClass().getName(), command.getIndex()); - command.preExecute(idTranslationTable); + command.preExecute(idTranslationTable, connection, validationHelper, snapshotGenerator); } else { @@ -191,7 +200,7 @@ private Consumer execute(Map idTranslationTable, Connec { logger.debug("Running execute of command {} for entry at index {}", command.getClass().getName(), command.getIndex()); - command.execute(idTranslationTable, connection); + command.execute(idTranslationTable, connection, validationHelper, snapshotGenerator); } else { @@ -239,7 +248,7 @@ private Consumer postExecute(Connection connection, Map optResult = command.postExecute(connection); + Optional optResult = command.postExecute(connection, eventHandler); optResult.ifPresent(result -> results.put(command.getIndex(), result)); } else diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CheckReferencesCommand.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CheckReferencesCommand.java new file mode 100644 index 000000000..68495c207 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CheckReferencesCommand.java @@ -0,0 +1,43 @@ +package org.highmed.dsf.fhir.dao.command; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; + +import javax.ws.rs.WebApplicationException; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.dao.ResourceDao; +import org.highmed.dsf.fhir.help.ExceptionHandler; +import org.highmed.dsf.fhir.help.ParameterConverter; +import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.prefer.PreferReturnType; +import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.SnapshotGenerator; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Resource; + +public class CheckReferencesCommand> + extends AbstractCommandWithResource implements Command +{ + public CheckReferencesCommand(int index, User user, PreferReturnType returnType, Bundle bundle, + BundleEntryComponent entry, String serverBase, AuthorizationHelper authorizationHelper, R resource, D dao, + ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + ResponseGenerator responseGenerator, ReferenceExtractor referenceExtractor, + ReferenceResolver referenceResolver) + { + super(4, index, user, returnType, bundle, entry, serverBase, authorizationHelper, resource, dao, + exceptionHandler, parameterConverter, responseGenerator, referenceExtractor, referenceResolver); + } + + @Override + public void execute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) + throws SQLException, WebApplicationException + { + referencesHelper.checkReferences(idTranslationTable, connection); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/Command.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/Command.java index 14b35c685..eea130294 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/Command.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/Command.java @@ -7,6 +7,8 @@ import javax.ws.rs.WebApplicationException; +import org.highmed.dsf.fhir.event.EventHandler; +import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.IdType; @@ -18,10 +20,17 @@ public interface Command int getTransactionPriority(); - void preExecute(Map idTranslationTable); + default void preExecute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) - void execute(Map idTranslationTable, Connection connection) - throws SQLException, WebApplicationException; + { + } - Optional postExecute(Connection connection); + void execute(Map idTranslationTable, Connection connection, ValidationHelper validationHelper, + SnapshotGenerator snapshotGenerator) throws SQLException, WebApplicationException; + + default Optional postExecute(Connection connection, EventHandler eventHandler) + { + return Optional.empty(); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CommandFactory.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CommandFactory.java index 882ea77ef..413fc69f4 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CommandFactory.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CommandFactory.java @@ -2,6 +2,8 @@ import org.highmed.dsf.fhir.authentication.User; import org.highmed.dsf.fhir.dao.exception.BadBundleException; +import org.highmed.dsf.fhir.prefer.PreferHandlingType; +import org.highmed.dsf.fhir.prefer.PreferReturnType; import org.hl7.fhir.r4.model.Bundle; public interface CommandFactory @@ -11,8 +13,14 @@ public interface CommandFactory * not null * @param user * not null + * @param returnType + * not null + * @param handlingType + * not null + * * @return * @throws BadBundleException */ - CommandList createCommands(Bundle bundle, User user) throws BadBundleException; + CommandList createCommands(Bundle bundle, User user, PreferReturnType returnType, PreferHandlingType handlingType) + throws BadBundleException; } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CommandFactoryImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CommandFactoryImpl.java index 3b5b31273..b2f070444 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CommandFactoryImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CommandFactoryImpl.java @@ -1,5 +1,6 @@ package org.highmed.dsf.fhir.dao.command; +import java.sql.Connection; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -16,17 +17,18 @@ import org.highmed.dsf.fhir.dao.exception.BadBundleException; import org.highmed.dsf.fhir.dao.provider.DaoProvider; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.prefer.PreferHandlingType; +import org.highmed.dsf.fhir.prefer.PreferReturnType; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; -import org.highmed.dsf.fhir.service.SnapshotDependencyAnalyzer; import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; -import org.hl7.fhir.r4.model.Bundle.BundleType; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.StructureDefinition; import org.springframework.beans.factory.InitializingBean; @@ -39,21 +41,23 @@ public class CommandFactoryImpl implements InitializingBean, CommandFactory private final DaoProvider daoProvider; private final ReferenceExtractor referenceExtractor; private final ReferenceResolver referenceResolver; + private final ReferenceCleaner referenceCleaner; private final ResponseGenerator responseGenerator; private final ExceptionHandler exceptionHandler; - private final EventManager eventManager; - private final EventGenerator eventGenerator; - private final SnapshotGenerator snapshotGenerator; - private final SnapshotDependencyAnalyzer snapshotDependencyAnalyzer; private final ParameterConverter parameterConverter; + private final EventHandler eventHandler; + private final EventGenerator eventGenerator; private final AuthorizationHelper authorizationHelper; + private final ValidationHelper validationHelper; + private final SnapshotGenerator snapshotGenerator; + private final Function transactionResourcesFactory; public CommandFactoryImpl(String serverBase, int defaultPageCount, DataSource dataSource, DaoProvider daoProvider, ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - ResponseGenerator responseGenerator, ExceptionHandler exceptionHandler, EventManager eventManager, - EventGenerator eventGenerator, SnapshotGenerator snapshotGenerator, - SnapshotDependencyAnalyzer snapshotDependencyAnalyzer, ParameterConverter parameterConverter, - AuthorizationHelper authorizationHelper) + ReferenceCleaner referenceCleaner, ResponseGenerator responseGenerator, ExceptionHandler exceptionHandler, + ParameterConverter parameterConverter, EventHandler eventHandler, EventGenerator eventGenerator, + AuthorizationHelper authorizationHelper, ValidationHelper validationHelper, + SnapshotGenerator snapshotGenerator, Function transactionResourcesFactory) { this.serverBase = serverBase; this.defaultPageCount = defaultPageCount; @@ -61,43 +65,50 @@ public CommandFactoryImpl(String serverBase, int defaultPageCount, DataSource da this.daoProvider = daoProvider; this.referenceExtractor = referenceExtractor; this.referenceResolver = referenceResolver; + this.referenceCleaner = referenceCleaner; this.responseGenerator = responseGenerator; this.exceptionHandler = exceptionHandler; - this.eventManager = eventManager; - this.eventGenerator = eventGenerator; - this.snapshotGenerator = snapshotGenerator; - this.snapshotDependencyAnalyzer = snapshotDependencyAnalyzer; this.parameterConverter = parameterConverter; + this.eventHandler = eventHandler; + this.eventGenerator = eventGenerator; this.authorizationHelper = authorizationHelper; + this.validationHelper = validationHelper; + this.snapshotGenerator = snapshotGenerator; + this.transactionResourcesFactory = transactionResourcesFactory; } @Override public void afterPropertiesSet() throws Exception { Objects.requireNonNull(serverBase, "serverBase"); + Objects.requireNonNull(dataSource, "dataSource"); Objects.requireNonNull(daoProvider, "daoProvider"); Objects.requireNonNull(referenceExtractor, "referenceExtractor"); Objects.requireNonNull(referenceResolver, "referenceResolver"); + Objects.requireNonNull(referenceCleaner, "referenceCleaner"); Objects.requireNonNull(responseGenerator, "responseGenerator"); Objects.requireNonNull(exceptionHandler, "exceptionHandler"); - Objects.requireNonNull(eventManager, "eventManager"); - Objects.requireNonNull(eventGenerator, "eventGenerator"); - Objects.requireNonNull(snapshotGenerator, "snapshotGenerator"); - Objects.requireNonNull(snapshotDependencyAnalyzer, "snapshotDependencyAnalyzer"); Objects.requireNonNull(parameterConverter, "parameterConverter"); + Objects.requireNonNull(eventHandler, "eventHandler"); + Objects.requireNonNull(eventGenerator, "eventGenerator"); Objects.requireNonNull(authorizationHelper, "authorizationHelper"); + Objects.requireNonNull(validationHelper, "validationHelper"); + Objects.requireNonNull(snapshotGenerator, "snapshotGenerator"); + Objects.requireNonNull(transactionResourcesFactory, "transactionResourcesFactory"); } // read, vread - private Command get(int index, User user, Bundle bundle, BundleEntryComponent entry) + private Command get(int index, User user, PreferReturnType returnType, Bundle bundle, BundleEntryComponent entry, + PreferHandlingType handlingType) { - return new ReadCommand(index, user, bundle, entry, serverBase, authorizationHelper, defaultPageCount, - daoProvider, parameterConverter, responseGenerator, exceptionHandler); + return new ReadCommand(index, user, returnType, bundle, entry, serverBase, authorizationHelper, + defaultPageCount, daoProvider, parameterConverter, responseGenerator, exceptionHandler, + referenceCleaner, handlingType); } // create, conditional create - private Command post(int index, User user, Bundle bundle, BundleEntryComponent entry, - EventManager eventManager, R resource) + private Command post(int index, User user, PreferReturnType returnType, Bundle bundle, + BundleEntryComponent entry, R resource) { if (resource.getResourceType().name().equals(entry.getRequest().getUrl())) { @@ -106,16 +117,14 @@ private Command post(int index, User user, Bundle bundle, B .getDao(resource.getClass()); if (resource instanceof StructureDefinition) - return new CreateStructureDefinitionCommand(index, user, bundle, entry, serverBase, authorizationHelper, - (StructureDefinition) resource, (StructureDefinitionDao) dao.get(), exceptionHandler, - parameterConverter, responseGenerator, referenceExtractor, referenceResolver, eventManager, - eventGenerator, daoProvider.getStructureDefinitionSnapshotDao(), snapshotGenerator, - snapshotDependencyAnalyzer); + return new CreateStructureDefinitionCommand(index, user, returnType, bundle, entry, serverBase, + authorizationHelper, (StructureDefinition) resource, (StructureDefinitionDao) dao.get(), + exceptionHandler, parameterConverter, responseGenerator, referenceExtractor, referenceResolver, + referenceCleaner, eventGenerator, daoProvider.getStructureDefinitionSnapshotDao()); else - return dao - .map(d -> new CreateCommand>(index, user, bundle, entry, serverBase, - authorizationHelper, resource, d, exceptionHandler, parameterConverter, - responseGenerator, referenceExtractor, referenceResolver, eventManager, eventGenerator)) + return dao.map(d -> new CreateCommand>(index, user, returnType, bundle, entry, + serverBase, authorizationHelper, resource, d, exceptionHandler, parameterConverter, + responseGenerator, referenceExtractor, referenceResolver, referenceCleaner, eventGenerator)) .orElseThrow(() -> new IllegalStateException( "Resource of type " + resource.getClass().getName() + " not supported")); } @@ -125,8 +134,8 @@ private Command post(int index, User user, Bundle bundle, B } // update, conditional update - private Command put(int index, User user, Bundle bundle, BundleEntryComponent entry, - EventManager eventManager, R resource) + private Command put(int index, User user, PreferReturnType returnType, Bundle bundle, + BundleEntryComponent entry, R resource) { if (entry.getRequest().getUrl() != null && !entry.getRequest().getUrl().isBlank() && entry.getRequest().getUrl().startsWith(resource.getResourceType().name())) @@ -136,16 +145,14 @@ private Command put(int index, User user, Bundle bundle, Bu .getDao(resource.getClass()); if (resource instanceof StructureDefinition) - return new UpdateStructureDefinitionCommand(index, user, bundle, entry, serverBase, authorizationHelper, - (StructureDefinition) resource, (StructureDefinitionDao) dao.get(), exceptionHandler, - parameterConverter, responseGenerator, referenceExtractor, referenceResolver, eventManager, - eventGenerator, daoProvider.getStructureDefinitionSnapshotDao(), snapshotGenerator, - snapshotDependencyAnalyzer); + return new UpdateStructureDefinitionCommand(index, user, returnType, bundle, entry, serverBase, + authorizationHelper, (StructureDefinition) resource, (StructureDefinitionDao) dao.get(), + exceptionHandler, parameterConverter, responseGenerator, referenceExtractor, referenceResolver, + referenceCleaner, eventGenerator, daoProvider.getStructureDefinitionSnapshotDao()); else - return dao - .map(d -> new UpdateCommand>(index, user, bundle, entry, serverBase, - authorizationHelper, resource, d, exceptionHandler, parameterConverter, - responseGenerator, referenceExtractor, referenceResolver, eventManager, eventGenerator)) + return dao.map(d -> new UpdateCommand>(index, user, returnType, bundle, entry, + serverBase, authorizationHelper, resource, d, exceptionHandler, parameterConverter, + responseGenerator, referenceExtractor, referenceResolver, referenceCleaner, eventGenerator)) .orElseThrow(() -> new IllegalStateException( "Resource of type " + resource.getClass().getName() + " not supported")); } @@ -155,43 +162,39 @@ private Command put(int index, User user, Bundle bundle, Bu } // delete, conditional delete - private Command delete(int index, User user, Bundle bundle, BundleEntryComponent entry, EventManager eventManager) + private Command delete(int index, User user, PreferReturnType returnType, Bundle bundle, BundleEntryComponent entry) { if (entry.getRequest().getUrl() != null && !entry.getRequest().getUrl().isBlank()) - { - return new DeleteCommand(index, user, bundle, entry, serverBase, authorizationHelper, responseGenerator, - daoProvider, exceptionHandler, parameterConverter, eventManager, eventGenerator); - } + return new DeleteCommand(index, user, returnType, bundle, entry, serverBase, authorizationHelper, + responseGenerator, daoProvider, exceptionHandler, parameterConverter, eventGenerator); else throw new BadBundleException( "Request url " + entry.getRequest().getUrl() + " for method DELETE not supported"); } @Override - public CommandList createCommands(Bundle bundle, User user) throws BadBundleException + public CommandList createCommands(Bundle bundle, User user, PreferReturnType returnType, + PreferHandlingType handlingType) throws BadBundleException { Objects.requireNonNull(bundle, "bundle"); Objects.requireNonNull(user, "user"); + Objects.requireNonNull(returnType, "returnType"); + Objects.requireNonNull(handlingType, "handlingType"); if (bundle.getType() != null) { - EventManager eventManager; - if (BundleType.TRANSACTION.equals(bundle.getType())) - eventManager = new TransactionEventManager(this.eventManager); - else - eventManager = this.eventManager; - - List commands = IntStream.range(0, bundle.getEntry().size()) - .mapToObj(index -> createCommand(index, bundle, user, bundle.getEntry().get(index), eventManager)) + List commands = IntStream.range(0, bundle.getEntry().size()).mapToObj( + index -> createCommand(index, user, returnType, handlingType, bundle, bundle.getEntry().get(index))) .flatMap(Function.identity()).collect(Collectors.toList()); switch (bundle.getType()) { case BATCH: - return new BatchCommandList(dataSource, exceptionHandler, commands); + return new BatchCommandList(dataSource, exceptionHandler, validationHelper, snapshotGenerator, + eventHandler, commands); case TRANSACTION: - return new TransactionCommandList(dataSource, exceptionHandler, commands, - (TransactionEventManager) eventManager); + return new TransactionCommandList(dataSource, exceptionHandler, transactionResourcesFactory, + commands); default: throw new BadBundleException("Unsupported bundle type " + bundle.getType()); } @@ -200,8 +203,8 @@ public CommandList createCommands(Bundle bundle, User user) throws BadBundleExce throw new BadBundleException("Missing bundle type"); } - protected Stream createCommand(int index, Bundle bundle, User user, BundleEntryComponent entry, - EventManager eventManager) + protected Stream createCommand(int index, User user, PreferReturnType returnType, + PreferHandlingType handlingType, Bundle bundle, BundleEntryComponent entry) { if (entry.hasRequest() && entry.getRequest().hasMethod()) { @@ -210,9 +213,9 @@ protected Stream createCommand(int index, Bundle bundle, User user, Bun switch (entry.getRequest().getMethod()) { case GET: // read - return Stream.of(get(index, user, bundle, entry)); + return Stream.of(get(index, user, returnType, bundle, entry, handlingType)); case DELETE: // delete - return Stream.of(delete(index, user, bundle, entry, eventManager)); + return Stream.of(delete(index, user, returnType, bundle, entry)); default: throw new BadBundleException("Request method " + entry.getRequest().getMethod() + " at index " + index + " not supported without resource"); @@ -223,11 +226,13 @@ protected Stream createCommand(int index, Bundle bundle, User user, Bun switch (entry.getRequest().getMethod()) { case POST: // create - Command post = post(index, user, bundle, entry, eventManager, (Resource) entry.getResource()); - return resolveReferences(post, index, user, bundle, entry, (Resource) entry.getResource()); + Command post = post(index, user, returnType, bundle, entry, (Resource) entry.getResource()); + return resolveReferences(post, index, user, returnType, bundle, entry, + (Resource) entry.getResource()); case PUT: // update - Command put = put(index, user, bundle, entry, eventManager, (Resource) entry.getResource()); - return resolveReferences(put, index, user, bundle, entry, (Resource) entry.getResource()); + Command put = put(index, user, returnType, bundle, entry, (Resource) entry.getResource()); + return resolveReferences(put, index, user, returnType, bundle, entry, + (Resource) entry.getResource()); default: throw new BadBundleException("Request method " + entry.getRequest().getMethod() + " at index " + index + " not supported with resource"); @@ -238,8 +243,8 @@ protected Stream createCommand(int index, Bundle bundle, User user, Bun throw new BadBundleException("BundleEntry at index " + index + " has no request or request has no method"); } - private Stream resolveReferences(Command cmd, int index, User user, Bundle bundle, - BundleEntryComponent entry, R resource) + private Stream resolveReferences(Command cmd, int index, User user, + PreferReturnType returnType, Bundle bundle, BundleEntryComponent entry, R resource) { @SuppressWarnings("unchecked") Optional> dao = (Optional>) daoProvider @@ -249,8 +254,8 @@ private Stream resolveReferences(Command cmd, int { return dao .map(d -> Stream.of(cmd, - new ResolveReferencesCommand>(index, user, bundle, entry, serverBase, - authorizationHelper, resource, d, exceptionHandler, parameterConverter, + new CheckReferencesCommand>(index, user, returnType, bundle, entry, + serverBase, authorizationHelper, resource, d, exceptionHandler, parameterConverter, responseGenerator, referenceExtractor, referenceResolver))) .orElseThrow(() -> new IllegalStateException( "Resource of type " + resource.getClass().getName() + " not supported")); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CreateCommand.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CreateCommand.java index b7abadc48..c22a2e56d 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CreateCommand.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CreateCommand.java @@ -17,21 +17,26 @@ import org.highmed.dsf.fhir.authentication.User; import org.highmed.dsf.fhir.dao.ResourceDao; +import org.highmed.dsf.fhir.dao.exception.ResourceDeletedException; import org.highmed.dsf.fhir.dao.exception.ResourceNotFoundException; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.prefer.PreferReturnType; import org.highmed.dsf.fhir.search.PartialResult; import org.highmed.dsf.fhir.search.SearchQuery; import org.highmed.dsf.fhir.search.SearchQueryParameterError; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleEntryResponseComponent; import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.ResourceType; import org.slf4j.Logger; @@ -40,44 +45,43 @@ import org.springframework.web.util.UriComponentsBuilder; import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.validation.ValidationResult; public class CreateCommand> extends AbstractCommandWithResource implements Command { private static final Logger logger = LoggerFactory.getLogger(CreateCommand.class); - private final ResponseGenerator responseGenerator; - private final ResolveReferencesHelper resolveReferencesHelper; - - protected final EventManager eventManager; + protected final ResponseGenerator responseGenerator; + protected final ReferenceCleaner referenceCleaner; protected final EventGenerator eventGenerator; protected R createdResource; protected Response responseResult; + protected ValidationResult validationResult; - public CreateCommand(int index, User user, Bundle bundle, BundleEntryComponent entry, String serverBase, - AuthorizationHelper authorizationHelper, R resource, D dao, ExceptionHandler exceptionHandler, - ParameterConverter parameterConverter, ResponseGenerator responseGenerator, - ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, EventManager eventManager, - EventGenerator eventGenerator) + public CreateCommand(int index, User user, PreferReturnType returnType, Bundle bundle, BundleEntryComponent entry, + String serverBase, AuthorizationHelper authorizationHelper, R resource, D dao, + ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + ResponseGenerator responseGenerator, ReferenceExtractor referenceExtractor, + ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, EventGenerator eventGenerator) { - super(2, index, user, bundle, entry, serverBase, authorizationHelper, resource, dao, exceptionHandler, - parameterConverter); + super(2, index, user, returnType, bundle, entry, serverBase, authorizationHelper, resource, dao, + exceptionHandler, parameterConverter, responseGenerator, referenceExtractor, referenceResolver); this.responseGenerator = responseGenerator; - resolveReferencesHelper = new ResolveReferencesHelper(index, user, serverBase, referenceExtractor, - referenceResolver, responseGenerator); + this.referenceCleaner = referenceCleaner; - this.eventManager = eventManager; this.eventGenerator = eventGenerator; } @Override - public void preExecute(Map idTranslationTable) + public void preExecute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) { UriComponents eruComponentes = UriComponentsBuilder.fromUriString(entry.getRequest().getUrl()).build(); - // check standard update request url: Patient + // check standard create request url: e.g. Patient if (eruComponentes.getPathSegments().size() == 1 && eruComponentes.getQueryParams().isEmpty()) { if (!entry.getFullUrl().startsWith(URL_UUID_PREFIX)) @@ -89,6 +93,9 @@ else if (resource.hasIdElement() && !resource.getIdElement().getValue().startsWi else if (resource.hasIdElement() && !entry.getFullUrl().equals(resource.getIdElement().getValue())) throw new WebApplicationException(responseGenerator.badBundleEntryFullUrlVsResourceId(index, entry.getFullUrl(), resource.getIdElement().getValue())); + + // add new or existing id to the id translation table + addToIdTranslationTable(idTranslationTable, connection); } // all other request urls @@ -97,23 +104,15 @@ else if (resource.hasIdElement() && !entry.getFullUrl().equals(resource.getIdEle responseGenerator.badCreateRequestUrl(index, entry.getRequest().getUrl())); } - @Override - public void execute(Map idTranslationTable, Connection connection) - throws SQLException, WebApplicationException + private void addToIdTranslationTable(Map idTranslationTable, Connection connection) { - resolveReferencesHelper.resolveReferencesIgnoreAndLogExceptions(idTranslationTable, connection, resource); - - authorizationHelper.checkCreateAllowed(connection, user, resource); - Optional exists = checkAlreadyExists(connection, entry.getRequest().getIfNoneExist(), resource.getResourceType()); - if (exists.isEmpty()) { UUID id = UUID.randomUUID(); idTranslationTable.put(entry.getFullUrl(), new IdType(resource.getResourceType().toString(), id.toString())); - createdResource = dao.createWithTransactionAndId(connection, resource, id); } else { @@ -124,6 +123,45 @@ public void execute(Map idTranslationTable, Connection connectio } } + @Override + public void execute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) + throws SQLException, WebApplicationException + { + // always resolve temp and conditional references, necessary if conditional create and resource exists + referencesHelper.resolveTemporaryAndConditionalReferences(idTranslationTable, connection); + // TODO maybe check again if resource exists, could be that a previous command created it + + if (responseResult == null) + { + validationResult = validationHelper.checkResourceValidForCreate(user, resource); + + referencesHelper.resolveLogicalReferences(connection); + + authorizationHelper.checkCreateAllowed(connection, user, resource); + + createdResource = createWithTransactionAndId(connection, resource, getId(idTranslationTable)); + } + } + + protected R createWithTransactionAndId(Connection connection, R resource, UUID uuid) throws SQLException + { + return dao.createWithTransactionAndId(connection, resource, uuid); + } + + private UUID getId(Map idTranslationTable) + { + IdType idType = idTranslationTable.get(entry.getFullUrl()); + if (idType != null) + { + Optional uuid = parameterConverter.toUuid(idType.getIdPart()); + if (uuid.isPresent()) + return uuid.get(); + } + + throw new RuntimeException("Error while retrieving id from id translation table"); + } + private Optional checkAlreadyExists(Connection connection, String ifNoneExist, ResourceType resourceType) throws WebApplicationException { @@ -165,40 +203,54 @@ private Optional checkAlreadyExists(Connection connection, String ifNo PartialResult result = exceptionHandler .handleSqlException(() -> dao.searchWithTransaction(connection, query)); - if (result.getOverallCount() == 1) + if (result.getTotal() == 1) return Optional.of(result.getPartialResult().get(0)); - else if (result.getOverallCount() > 1) + else if (result.getTotal() > 1) throw new WebApplicationException(responseGenerator.multipleExists(resourceType.name(), ifNoneExist)); return Optional.empty(); } @Override - public Optional postExecute(Connection connection) + public Optional postExecute(Connection connection, EventHandler eventHandler) { if (responseResult == null) { + // retrieving the latest resource from db to include updated references + Resource createdResourceWithResolvedReferences = latestOrErrorIfDeletedOrNotFound(connection, + createdResource); try { - // retrieving the latest resource from db to include updated references - Resource createdResourceWithResolvedReferences = latestOrErrorIfDeletedOrNotFound(connection, - createdResource); - eventManager.handleEvent(eventGenerator.newResourceCreatedEvent(createdResourceWithResolvedReferences)); + referenceCleaner.cleanLiteralReferences(createdResourceWithResolvedReferences); + eventHandler.handleEvent(eventGenerator.newResourceCreatedEvent(createdResourceWithResolvedReferences)); } catch (Exception e) { logger.warn("Error while handling resource created event", e); } + IdType location = createdResourceWithResolvedReferences.getIdElement().withServerBase(serverBase, + createdResourceWithResolvedReferences.getResourceType().name()); + BundleEntryComponent resultEntry = new BundleEntryComponent(); - resultEntry.setFullUrl(new IdType(serverBase, createdResource.getResourceType().name(), - createdResource.getIdElement().getIdPart(), null).getValue()); + resultEntry.setFullUrl(location.toVersionless().toString()); + + if (PreferReturnType.REPRESENTATION.equals(returnType)) + resultEntry.setResource(createdResourceWithResolvedReferences); + else if (PreferReturnType.OPERATION_OUTCOME.equals(returnType)) + { + OperationOutcome outcome = responseGenerator.created(location.toString(), + createdResourceWithResolvedReferences); + validationResult.populateOperationOutcome(outcome); + resultEntry.getResponse().setOutcome(outcome); + } + BundleEntryResponseComponent response = resultEntry.getResponse(); response.setStatus(Status.CREATED.getStatusCode() + " " + Status.CREATED.getReasonPhrase()); - response.setLocation(createdResource.getIdElement() - .withServerBase(serverBase, createdResource.getResourceType().name()).getValue()); - response.setEtag(new EntityTag(createdResource.getMeta().getVersionId(), true).toString()); - response.setLastModified(createdResource.getMeta().getLastUpdated()); + response.setLocation(location.getValue()); + response.setEtag( + new EntityTag(createdResourceWithResolvedReferences.getMeta().getVersionId(), true).toString()); + response.setLastModified(createdResourceWithResolvedReferences.getMeta().getLastUpdated()); return Optional.of(resultEntry); } @@ -220,12 +272,20 @@ public Optional postExecute(Connection connection) } } - private R latestOrErrorIfDeletedOrNotFound(Connection connection, Resource resource) throws Exception + private R latestOrErrorIfDeletedOrNotFound(Connection connection, Resource resource) { - return dao - .readWithTransaction(connection, - parameterConverter.toUuid(resource.getResourceType().name(), - resource.getIdElement().getIdPart())) - .orElseThrow(() -> new ResourceNotFoundException(resource.getIdElement().getIdPart())); + try + { + return dao + .readWithTransaction(connection, + parameterConverter.toUuid(resource.getResourceType().name(), + resource.getIdElement().getIdPart())) + .orElseThrow(() -> new ResourceNotFoundException(resource.getIdElement().getIdPart())); + } + catch (ResourceNotFoundException | SQLException | ResourceDeletedException e) + { + logger.warn("Error while reading resource from db", e); + throw new RuntimeException(e); + } } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CreateStructureDefinitionCommand.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CreateStructureDefinitionCommand.java index a622476f5..02aed5a5f 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CreateStructureDefinitionCommand.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/CreateStructureDefinitionCommand.java @@ -1,29 +1,29 @@ package org.highmed.dsf.fhir.dao.command; import java.sql.Connection; +import java.sql.SQLException; import java.util.Map; -import java.util.Optional; +import java.util.UUID; + +import javax.ws.rs.WebApplicationException; import org.highmed.dsf.fhir.authentication.User; import org.highmed.dsf.fhir.dao.StructureDefinitionDao; -import org.highmed.dsf.fhir.dao.StructureDefinitionSnapshotDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; -import org.highmed.dsf.fhir.function.ConsumerWithSqlAndResourceNotFoundException; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.prefer.PreferReturnType; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; -import org.highmed.dsf.fhir.service.SnapshotDependencies; -import org.highmed.dsf.fhir.service.SnapshotDependencyAnalyzer; import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.highmed.dsf.fhir.service.SnapshotGenerator.SnapshotWithValidationMessages; -import org.highmed.dsf.fhir.service.SnapshotInfo; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,80 +31,69 @@ public class CreateStructureDefinitionCommand extends CreateCommand idTranslationTable) + public void preExecute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) { - resourceWithSnapshot = resource.hasSnapshot() ? resource.copy() : null; + resourceWithSnapshot = resource.hasSnapshot() ? resource.copy() + : generateSnapshot(snapshotGenerator, resource.copy()); resource.setSnapshot(null); - super.preExecute(idTranslationTable); + super.preExecute(idTranslationTable, connection, validationHelper, snapshotGenerator); } - @Override - public Optional postExecute(Connection connection) + private StructureDefinition generateSnapshot(SnapshotGenerator snapshotGenerator, StructureDefinition resource) { - if (responseResult != null) - return super.postExecute(connection); + logger.debug("Generating snapshot for bundle entry at index {}", index); + SnapshotWithValidationMessages s = snapshotGenerator.generateSnapshot(resource); - if (resourceWithSnapshot != null) + if (s.getMessages().stream() + .anyMatch(m -> IssueSeverity.FATAL.equals(m.getLevel()) || IssueSeverity.ERROR.equals(m.getLevel()))) { - handleSnapshot(resourceWithSnapshot, - info -> snapshotDao.create(parameterConverter.toUuid(resourceWithSnapshot.getResourceType().name(), - createdResource.getIdElement().getIdPart()), resourceWithSnapshot, info)); + throw new WebApplicationException( + responseGenerator.unableToGenerateSnapshot(resource, index, s.getMessages())); } - else if (createdResource != null) + + return s.getSnapshot(); + } + + @Override + protected StructureDefinition createWithTransactionAndId(Connection connection, StructureDefinition resource, + UUID uuid) throws SQLException + { + StructureDefinition created = super.createWithTransactionAndId(connection, resource, uuid); + + if (resourceWithSnapshot != null) { try { - SnapshotWithValidationMessages s = snapshotGenerator.generateSnapshot(createdResource); - - if (s != null && s.getSnapshot() != null && s.getMessages().isEmpty()) - handleSnapshot(s.getSnapshot(), - info -> snapshotDao - .create(parameterConverter.toUuid(createdResource.getResourceType().name(), - createdResource.getIdElement().getIdPart()), createdResource, info)); + snapshotDao.createWithTransactionAndId(connection, resourceWithSnapshot, uuid); } - catch (Exception e) + catch (SQLException e) { - logger.warn("Error while generating snapshot for StructureDefinition with id " - + createdResource.getIdElement().getIdPart(), e); + logger.warn("Error while creating StructureDefinition snapshot: " + e.getMessage(), e); + throw e; } } - return super.postExecute(connection); - } - - private void handleSnapshot(StructureDefinition snapshot, - ConsumerWithSqlAndResourceNotFoundException dbOp) - { - SnapshotDependencies dependencies = snapshotDependencyAnalyzer.analyzeSnapshotDependencies(snapshot); - - exceptionHandler.catchAndLogSqlException(() -> snapshotDao.deleteAllByDependency(snapshot.getUrl())); - - exceptionHandler.catchAndLogSqlAndResourceNotFoundException(resource.getResourceType().name(), - () -> dbOp.accept(new SnapshotInfo(dependencies))); + return created; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/DeleteCommand.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/DeleteCommand.java index 8179e2a56..3389bacfa 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/DeleteCommand.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/DeleteCommand.java @@ -17,13 +17,15 @@ import org.highmed.dsf.fhir.dao.ResourceDao; import org.highmed.dsf.fhir.dao.provider.DaoProvider; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.prefer.PreferReturnType; import org.highmed.dsf.fhir.search.PartialResult; import org.highmed.dsf.fhir.search.SearchQuery; import org.highmed.dsf.fhir.search.SearchQueryParameterError; +import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleEntryResponseComponent; @@ -43,7 +45,6 @@ public class DeleteCommand extends AbstractCommand implements Command private final DaoProvider daoProvider; private final ExceptionHandler exceptionHandler; private final ParameterConverter parameterConverter; - private final EventManager eventManager; private final EventGenerator eventGenerator; private boolean deleted; @@ -51,28 +52,29 @@ public class DeleteCommand extends AbstractCommand implements Command private Class resourceType; private String id; - public DeleteCommand(int index, User user, Bundle bundle, BundleEntryComponent entry, String serverBase, - AuthorizationHelper authorizationHelper, ResponseGenerator responseGenerator, + public DeleteCommand(int index, User user, PreferReturnType returnType, Bundle bundle, BundleEntryComponent entry, + String serverBase, AuthorizationHelper authorizationHelper, ResponseGenerator responseGenerator, DaoProvider daoProvider, ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, - EventManager eventManager, EventGenerator eventGenerator) + EventGenerator eventGenerator) { - super(1, index, user, bundle, entry, serverBase, authorizationHelper); + super(1, index, user, returnType, bundle, entry, serverBase, authorizationHelper); this.responseGenerator = responseGenerator; this.daoProvider = daoProvider; this.exceptionHandler = exceptionHandler; this.parameterConverter = parameterConverter; - this.eventManager = eventManager; this.eventGenerator = eventGenerator; } @Override - public void preExecute(Map idTranslationTable) + public void preExecute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) { } @Override - public void execute(Map idTranslationTable, Connection connection) + public void execute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) throws SQLException, WebApplicationException { UriComponents componentes = UriComponentsBuilder.fromUriString(entry.getRequest().getUrl()).build(); @@ -104,8 +106,7 @@ private void deleteById(Connection connection, String resourceTypeName, String i Optional dbResource = exceptionHandler .handleSqlException(() -> dao.readIncludingDeletedWithTransaction(connection, uuid)); - dbResource.ifPresent( - oldResource -> authorizationHelper.checkDeleteAllowed(connection, user, oldResource)); + dbResource.ifPresent(oldResource -> authorizationHelper.checkDeleteAllowed(connection, user, oldResource)); deleted = exceptionHandler.handleSqlAndResourceNotFoundException(resourceTypeName, () -> dao.deleteWithTransaction(connection, uuid)); @@ -171,11 +172,11 @@ private Optional search(Connection connection, ResourceDao dao, PartialResult result = exceptionHandler .handleSqlException(() -> dao.searchWithTransaction(connection, query)); - if (result.getOverallCount() <= 0) + if (result.getTotal() <= 0) { return Optional.empty(); } - else if (result.getOverallCount() == 1) + else if (result.getTotal() == 1) { return Optional.of(result.getPartialResult().get(0)); } @@ -188,12 +189,12 @@ else if (result.getOverallCount() == 1) } @Override - public Optional postExecute(Connection connection) + public Optional postExecute(Connection connection, EventHandler eventHandler) { try { if (deleted) - eventManager.handleEvent(eventGenerator.newResourceDeletedEvent(resourceType, id)); + eventHandler.handleEvent(eventGenerator.newResourceDeletedEvent(resourceType, id)); } catch (Exception e) { diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ReadCommand.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ReadCommand.java index ff4a4d104..f9234a77f 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ReadCommand.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ReadCommand.java @@ -10,6 +10,7 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.EntityTag; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriBuilder; @@ -17,12 +18,17 @@ import org.highmed.dsf.fhir.authentication.User; import org.highmed.dsf.fhir.dao.ResourceDao; import org.highmed.dsf.fhir.dao.provider.DaoProvider; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.prefer.PreferHandlingType; +import org.highmed.dsf.fhir.prefer.PreferReturnType; import org.highmed.dsf.fhir.search.PartialResult; import org.highmed.dsf.fhir.search.SearchQuery; import org.highmed.dsf.fhir.search.SearchQueryParameterError; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleEntryResponseComponent; @@ -47,18 +53,20 @@ public class ReadCommand extends AbstractCommand implements Command private final ParameterConverter parameterConverter; private final ResponseGenerator responseGenerator; private final ExceptionHandler exceptionHandler; + private final ReferenceCleaner referenceCleaner; + private final PreferHandlingType handlingType; private Bundle multipleResult; private Resource singleResult; private OperationOutcome singleResultSearchWarning; private Response responseResult; - public ReadCommand(int index, User user, Bundle bundle, BundleEntryComponent entry, String serverBase, - AuthorizationHelper authorizationHelper, int defaultPageCount, DaoProvider daoProvider, + public ReadCommand(int index, User user, PreferReturnType returnType, Bundle bundle, BundleEntryComponent entry, + String serverBase, AuthorizationHelper authorizationHelper, int defaultPageCount, DaoProvider daoProvider, ParameterConverter parameterConverter, ResponseGenerator responseGenerator, - ExceptionHandler exceptionHandler) + ExceptionHandler exceptionHandler, ReferenceCleaner referenceCleaner, PreferHandlingType handlingType) { - super(5, index, user, bundle, entry, serverBase, authorizationHelper); + super(5, index, user, returnType, bundle, entry, serverBase, authorizationHelper); this.defaultPageCount = defaultPageCount; @@ -66,15 +74,19 @@ public ReadCommand(int index, User user, Bundle bundle, BundleEntryComponent ent this.parameterConverter = parameterConverter; this.responseGenerator = responseGenerator; this.exceptionHandler = exceptionHandler; + this.referenceCleaner = referenceCleaner; + this.handlingType = handlingType; } @Override - public void preExecute(Map idTranslationTable) + public void preExecute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) { } @Override - public void execute(Map idTranslationTable, Connection connection) + public void execute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) throws SQLException, WebApplicationException { String requestUrl = entry.getRequest().getUrl(); @@ -107,7 +119,7 @@ private void readById(Connection connection, String resourceTypeName, String id) responseResult = Response.status(Status.NOT_FOUND).build(); ResourceDao dao = optDao.get(); - Optional read = exceptionHandler.handleSqlAndResourceDeletedException(resourceTypeName, + Optional read = exceptionHandler.handleSqlAndResourceDeletedException(serverBase, resourceTypeName, () -> dao.readWithTransaction(connection, parameterConverter.toUuid(resourceTypeName, id))); if (read.isEmpty()) responseResult = Response.status(Status.NOT_FOUND).build(); @@ -136,7 +148,7 @@ private void readByIdAndVersion(Connection connection, String resourceTypeName, responseResult = Response.status(Status.NOT_FOUND).build(); ResourceDao dao = optDao.get(); - Optional read = exceptionHandler.handleSqlAndResourceDeletedException(resourceTypeName, + Optional read = exceptionHandler.handleSqlAndResourceDeletedException(serverBase, resourceTypeName, () -> dao.readVersionWithTransaction(connection, parameterConverter.toUuid(resourceTypeName, id), longVersion.get())); if (read.isEmpty()) @@ -174,7 +186,10 @@ private void readByCondition(Connection connection, String resourceTypeName, SearchQuery query = optDao.get().createSearchQuery(user, effectivePage, effectiveCount); query.configureParameters(cleanQueryParameters); List errors = query.getUnsupportedQueryParameters(cleanQueryParameters); - // TODO throw error if strict param handling is configured, include warning else + + if (!errors.isEmpty() && PreferHandlingType.STRICT.equals(handlingType)) + throw new WebApplicationException(responseGenerator.response(Status.BAD_REQUEST, + responseGenerator.toOperationOutcomeError(errors), MediaType.APPLICATION_XML_TYPE).build()); PartialResult result = exceptionHandler .handleSqlException(() -> optDao.get().searchWithTransaction(connection, query)); @@ -213,16 +228,18 @@ else if (multipleResult != null && multipleResult.getEntry().size() == 2 } else { - authorizationHelper.checkSearchAllowed(connection, user, resourceTypeName); + authorizationHelper.checkSearchAllowed(user, resourceTypeName); authorizationHelper.filterIncludeResults(connection, user, multipleResult); } } @Override - public Optional postExecute(Connection connection) + public Optional postExecute(Connection connection, EventHandler eventHandler) { if (singleResult != null) { + referenceCleaner.cleanLiteralReferences(singleResult); + BundleEntryComponent resultEntry = new BundleEntryComponent(); resultEntry.setFullUrl(new IdType(serverBase, singleResult.getResourceType().name(), singleResult.getIdElement().getIdPart(), null).getValue()); @@ -241,6 +258,10 @@ public Optional postExecute(Connection connection) } else if (multipleResult != null) { + // clean literal references from bundle entries + multipleResult.getEntry().stream().filter(BundleEntryComponent::hasResource) + .map(BundleEntryComponent::getResource).forEach(referenceCleaner::cleanLiteralReferences); + BundleEntryComponent resultEntry = new BundleEntryComponent(); resultEntry.setFullUrl(URL_UUID_PREFIX + UUID.randomUUID().toString()); BundleEntryResponseComponent response = resultEntry.getResponse(); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ReferencesHelper.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ReferencesHelper.java new file mode 100644 index 000000000..97b9bc10c --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ReferencesHelper.java @@ -0,0 +1,19 @@ +package org.highmed.dsf.fhir.dao.command; + +import java.sql.Connection; +import java.util.Map; + +import javax.ws.rs.WebApplicationException; + +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Resource; + +public interface ReferencesHelper +{ + void resolveTemporaryAndConditionalReferences(Map idTranslationTable, Connection connection) + throws WebApplicationException; + + void resolveLogicalReferences(Connection connection) throws WebApplicationException; + + void checkReferences(Map idTranslationTable, Connection connection) throws WebApplicationException; +} \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ReferencesHelperImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ReferencesHelperImpl.java new file mode 100644 index 000000000..e838f79f9 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ReferencesHelperImpl.java @@ -0,0 +1,167 @@ +package org.highmed.dsf.fhir.dao.command; + +import java.sql.Connection; +import java.util.Map; +import java.util.Optional; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceReference; +import org.highmed.dsf.fhir.service.ResourceReference.ReferenceType; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.OperationOutcome; +import org.hl7.fhir.r4.model.Resource; + +public final class ReferencesHelperImpl implements ReferencesHelper +{ + private final int index; + private final User user; + private final R resource; + private final String serverBase; + private final ReferenceExtractor referenceExtractor; + private final ReferenceResolver referenceResolver; + private final ResponseGenerator responseGenerator; + + public ReferencesHelperImpl(int index, User user, R resource, String serverBase, + ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, + ResponseGenerator responseGenerator) + { + this.index = index; + this.user = user; + this.resource = resource; + this.serverBase = serverBase; + this.referenceExtractor = referenceExtractor; + this.referenceResolver = referenceResolver; + this.responseGenerator = responseGenerator; + } + + @Override + public void resolveTemporaryAndConditionalReferences(Map idTranslationTable, Connection connection) + throws WebApplicationException + { + referenceExtractor.getReferences(resource).forEach(ref -> + { + Optional outcome = resolveTemporaryOrConditionalReference(ref, idTranslationTable, + connection); + if (outcome.isPresent()) + { + Response response = Response.status(Status.FORBIDDEN).entity(outcome.get()).build(); + throw new WebApplicationException(response); + } + }); + } + + private Optional resolveTemporaryOrConditionalReference(ResourceReference reference, + Map idTranslationTable, Connection connection) + { + ReferenceType type = reference.getType(serverBase); + switch (type) + { + case TEMPORARY: + return resolveTemporaryReference(reference, idTranslationTable); + case CONDITIONAL: + return resolveConditionalReference(reference, connection); + default: + return Optional.empty(); + } + } + + private Optional resolveTemporaryReference(ResourceReference reference, + Map idTranslationTable) + { + IdType newId = idTranslationTable.get(reference.getReference().getReference()); + if (newId != null) + { + reference.getReference().setReferenceElement(newId); + + return Optional.empty(); + } + else + return Optional.of(responseGenerator.unknownReference(resource, reference, index)); + } + + private Optional resolveConditionalReference(ResourceReference reference, Connection connection) + { + Optional resolvedResource = referenceResolver.resolveReference(user, reference, connection); + if (resolvedResource.isPresent()) + { + Resource target = resolvedResource.get(); + reference.getReference().setReferenceElement( + new IdType(target.getResourceType().name(), target.getIdElement().getIdPart())); + + return Optional.empty(); + } + else + return Optional.of(responseGenerator.referenceTargetNotFoundLocallyByCondition(index, resource, reference)); + } + + @Override + public void resolveLogicalReferences(Connection connection) throws WebApplicationException + { + referenceExtractor.getReferences(resource).filter(ref -> ReferenceType.LOGICAL.equals(ref.getType(serverBase))) + .forEach(ref -> + { + Optional outcome = resolveLogicalReference(ref, connection); + if (outcome.isPresent()) + { + Response response = Response.status(Status.FORBIDDEN).entity(outcome.get()).build(); + throw new WebApplicationException(response); + } + }); + } + + private Optional resolveLogicalReference(ResourceReference reference, Connection connection) + { + Optional resolvedResource = referenceResolver.resolveReference(user, reference, connection); + if (resolvedResource.isPresent()) + { + Resource target = resolvedResource.get(); + reference.getReference().setReferenceElement( + new IdType(target.getResourceType().name(), target.getIdElement().getIdPart())); + + return Optional.empty(); + } + else + return Optional + .of(responseGenerator.referenceTargetNotFoundLocallyByIdentifier(index, resource, reference)); + } + + @Override + public void checkReferences(Map idTranslationTable, Connection connection) + throws WebApplicationException + { + referenceExtractor.getReferences(resource).forEach(ref -> + { + Optional outcome = checkReference(idTranslationTable, connection, ref); + if (outcome.isPresent()) + { + Response response = Response.status(Status.FORBIDDEN).entity(outcome.get()).build(); + throw new WebApplicationException(response); + } + }); + } + + private Optional checkReference(Map idTranslationTable, Connection connection, + ResourceReference reference) throws WebApplicationException + { + ReferenceType type = reference.getType(serverBase); + switch (type) + { + case LITERAL_INTERNAL: + return referenceResolver.checkLiteralInternalReference(resource, reference, connection, index); + case LITERAL_EXTERNAL: + return referenceResolver.checkLiteralExternalReference(resource, reference, index); + case LOGICAL: + return referenceResolver.checkLogicalReference(user, resource, reference, connection, index); + case UNKNOWN: + default: + return Optional.of(responseGenerator.unknownReference(resource, reference, index)); + } + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ResolveReferencesCommand.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ResolveReferencesCommand.java deleted file mode 100755 index aa9dc4d55..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ResolveReferencesCommand.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.highmed.dsf.fhir.dao.command; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Map; -import java.util.Optional; - -import javax.ws.rs.WebApplicationException; - -import org.highmed.dsf.fhir.authentication.User; -import org.highmed.dsf.fhir.dao.ResourceDao; -import org.highmed.dsf.fhir.dao.exception.ResourceDeletedException; -import org.highmed.dsf.fhir.dao.exception.ResourceNotFoundException; -import org.highmed.dsf.fhir.help.ExceptionHandler; -import org.highmed.dsf.fhir.help.ParameterConverter; -import org.highmed.dsf.fhir.help.ResponseGenerator; -import org.highmed.dsf.fhir.service.ReferenceExtractor; -import org.highmed.dsf.fhir.service.ReferenceResolver; -import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Resource; - -public class ResolveReferencesCommand> - extends AbstractCommandWithResource implements Command -{ - private final ResolveReferencesHelper resolveReferencesHelper; - - public ResolveReferencesCommand(int index, User user, Bundle bundle, BundleEntryComponent entry, String serverBase, - AuthorizationHelper authorizationHelper, R resource, D dao, ExceptionHandler exceptionHandler, - ParameterConverter parameterConverter, ResponseGenerator responseGenerator, - ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver) - { - super(4, index, user, bundle, entry, serverBase, authorizationHelper, resource, dao, exceptionHandler, - parameterConverter); - - resolveReferencesHelper = new ResolveReferencesHelper(index, user, serverBase, referenceExtractor, - referenceResolver, responseGenerator); - } - - @Override - public void preExecute(Map idTranslationTable) - { - } - - @Override - public void execute(Map idTranslationTable, Connection connection) - throws SQLException, WebApplicationException - { - R latest = latestOrErrorIfDeletedOrNotFound(idTranslationTable, connection); - - boolean resourceNeedsUpdated = resolveReferencesHelper.resolveReferences(idTranslationTable, connection, - latest); - if (resourceNeedsUpdated) - { - try - { - dao.updateSameRowWithTransaction(connection, latest); - } - catch (ResourceNotFoundException e) - { - throw exceptionHandler.internalServerError(e); - } - } - } - - private R latestOrErrorIfDeletedOrNotFound(Map idTranslationTable, Connection connection) - throws SQLException - { - try - { - String id = idTranslationTable.getOrDefault(entry.getFullUrl(), resource.getIdElement()).getIdPart(); - return dao.readWithTransaction(connection, parameterConverter.toUuid(resource.getResourceType().name(), id)) - .orElseThrow(() -> exceptionHandler.internalServerError(new ResourceNotFoundException(id))); - } - catch (ResourceDeletedException e) - { - throw exceptionHandler.internalServerError(e); - } - } - - @Override - public Optional postExecute(Connection connection) - { - return Optional.empty(); - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ResolveReferencesHelper.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ResolveReferencesHelper.java deleted file mode 100644 index 443b1f8e9..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ResolveReferencesHelper.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.highmed.dsf.fhir.dao.command; - -import java.sql.Connection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import javax.ws.rs.WebApplicationException; - -import org.highmed.dsf.fhir.authentication.User; -import org.highmed.dsf.fhir.help.ResponseGenerator; -import org.highmed.dsf.fhir.service.ReferenceExtractor; -import org.highmed.dsf.fhir.service.ReferenceResolver; -import org.highmed.dsf.fhir.service.ResourceReference; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Resource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class ResolveReferencesHelper -{ - private static final Logger logger = LoggerFactory.getLogger(ResolveReferencesHelper.class); - - private final int index; - private final User user; - private final String serverBase; - private final ReferenceExtractor referenceExtractor; - private final ReferenceResolver referenceResolver; - private final ResponseGenerator responseGenerator; - - public ResolveReferencesHelper(int index, User user, String serverBase, ReferenceExtractor referenceExtractor, - ReferenceResolver referenceResolver, ResponseGenerator responseGenerator) - { - this.index = index; - this.user = user; - this.serverBase = serverBase; - this.referenceExtractor = referenceExtractor; - this.referenceResolver = referenceResolver; - this.responseGenerator = responseGenerator; - } - - public boolean resolveReferences(Map idTranslationTable, Connection connection, R resource) - throws WebApplicationException - { - boolean resourceNeedsUpdated = false; - List references = referenceExtractor.getReferences(resource).collect(Collectors.toList()); - // Don't use stream.map(...).anyMatch(b -> b), anyMatch is a shortcut operation stopping after first match - for (ResourceReference ref : references) - { - boolean needsUpdate = resolveReference(idTranslationTable, connection, resource, ref); - if (needsUpdate) - resourceNeedsUpdated = true; - } - return resourceNeedsUpdated; - } - - public void resolveReferencesIgnoreAndLogExceptions(Map idTranslationTable, Connection connection, - R resource) throws WebApplicationException - { - List references = referenceExtractor.getReferences(resource).collect(Collectors.toList()); - // Don't use stream.map(...).anyMatch(b -> b), anyMatch is a shortcut operation stopping after first match - for (ResourceReference ref : references) - { - try - { - resolveReference(idTranslationTable, connection, resource, ref); - } - catch (WebApplicationException e) - { - logger.warn("Error while resolving reference {}", e.getMessage()); - } - } - } - - private boolean resolveReference(Map idTranslationTable, Connection connection, R resource, - ResourceReference resourceReference) throws WebApplicationException - { - switch (resourceReference.getType(serverBase)) - { - case TEMPORARY: - return resolveTemporaryReference(resourceReference, idTranslationTable, resource); - case LITERAL_INTERNAL: - return referenceResolver.resolveLiteralInternalReference(resource, index, resourceReference, - connection); - case LITERAL_EXTERNAL: - return referenceResolver.resolveLiteralExternalReference(resource, index, resourceReference); - case CONDITIONAL: - return referenceResolver.resolveConditionalReference(user, resource, index, resourceReference, - connection); - case LOGICAL: - return referenceResolver.resolveLogicalReference(user, resource, index, resourceReference, connection); - case UNKNOWN: - default: - throw new WebApplicationException( - responseGenerator.unknownReference(index, resource, resourceReference)); - } - } - - private boolean resolveTemporaryReference(ResourceReference resourceReference, - Map idTranslationTable, R resource) - { - IdType newId = idTranslationTable.get(resourceReference.getReference().getReference()); - if (newId == null) - throw new WebApplicationException(responseGenerator.unknownReference(index, resource, resourceReference)); - else - resourceReference.getReference().setReferenceElement(newId); - - return true; // throws exception if reference could not be resolved - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionCommandList.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionCommandList.java index dcd025704..aa27e5284 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionCommandList.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionCommandList.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import java.util.function.Function; import javax.sql.DataSource; import javax.ws.rs.WebApplicationException; @@ -16,6 +17,7 @@ import javax.ws.rs.core.Response.Status; import org.highmed.dsf.fhir.help.ExceptionHandler; +import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleType; @@ -29,24 +31,22 @@ public class TransactionCommandList implements CommandList private final DataSource dataSource; private final ExceptionHandler exceptionHandler; - private final TransactionEventManager eventManager; + private final Function transactionResourceFactory; private final List commands = new ArrayList<>(); private final boolean hasModifyingCommand; - public TransactionCommandList(DataSource dataSource, ExceptionHandler exceptionHandler, List commands, - TransactionEventManager eventManager) + public TransactionCommandList(DataSource dataSource, ExceptionHandler exceptionHandler, + Function transactionResourceFactory, List commands) { this.dataSource = dataSource; this.exceptionHandler = exceptionHandler; - this.eventManager = eventManager; + this.transactionResourceFactory = transactionResourceFactory; if (commands != null) this.commands.addAll(commands); - Collections.sort(this.commands, Comparator.comparing(Command::getTransactionPriority).thenComparing(Command::getIndex)); - hasModifyingCommand = commands.stream() .anyMatch(c -> c instanceof CreateCommand || c instanceof UpdateCommand || c instanceof DeleteCommand); } @@ -57,24 +57,7 @@ public Bundle execute() throws WebApplicationException Map results = new HashMap<>((int) ((commands.size() / 0.75) + 1)); try { - Map idTranslationTable = new HashMap<>(); - for (Command c : commands) - { - try - { - logger.debug("Running pre-execute of command {} for entry at index {}", c.getClass().getName(), - c.getIndex()); - c.preExecute(idTranslationTable); - } - catch (Exception e) - { - logger.warn("Error while running pre-execute of command " + c.getClass().getSimpleName() - + " for entry at index " + c.getIndex() + ", abborting transaction", e); - - throw e; - } - } - + TransactionEventHandler transactionEventHandler; try (Connection connection = dataSource.getConnection()) { if (hasModifyingCommand) @@ -84,13 +67,36 @@ public Bundle execute() throws WebApplicationException connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); } + TransactionResources transactionResources = transactionResourceFactory.apply(connection); + transactionEventHandler = transactionResources.getTransactionEventHandler(); + ValidationHelper validationHelper = transactionResources.getValidationHelper(); + SnapshotGenerator snapshotGenerator = transactionResources.getSnapshotGenerator(); + + Map idTranslationTable = new HashMap<>(); + for (Command c : commands) + { + try + { + logger.debug("Running pre-execute of command {} for entry at index {}", c.getClass().getName(), + c.getIndex()); + c.preExecute(idTranslationTable, connection, validationHelper, snapshotGenerator); + } + catch (Exception e) + { + logger.warn("Error while running pre-execute of command " + c.getClass().getSimpleName() + + " for entry at index " + c.getIndex() + ", abborting transaction", e); + + throw e; + } + } + for (Command c : commands) { try { logger.debug("Running execute of command {} for entry at index {}", c.getClass().getName(), c.getIndex()); - c.execute(idTranslationTable, connection); + c.execute(idTranslationTable, connection, validationHelper, snapshotGenerator); } catch (Exception e) { @@ -113,7 +119,7 @@ public Bundle execute() throws WebApplicationException { logger.debug("Running post-execute of command {} for entry at index {}", c.getClass().getName(), c.getIndex()); - Optional optResult = c.postExecute(connection); + Optional optResult = c.postExecute(connection, transactionEventHandler); optResult.ifPresent(result -> results.putIfAbsent(c.getIndex(), result)); } catch (Exception e) @@ -141,7 +147,7 @@ public Bundle execute() throws WebApplicationException try { logger.debug("Commiting events"); - eventManager.commitEvents(); + transactionEventHandler.commitEvents(); } catch (Exception e) { diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionEventHandler.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionEventHandler.java new file mode 100755 index 000000000..913314e9b --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionEventHandler.java @@ -0,0 +1,44 @@ +package org.highmed.dsf.fhir.dao.command; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.highmed.dsf.fhir.event.Event; +import org.highmed.dsf.fhir.event.EventHandler; + +public class TransactionEventHandler implements EventHandler +{ + private final List cachedEvents = new ArrayList<>(); + private final EventHandler commitDelegate; + private final EventHandler delegate; + + public TransactionEventHandler(EventHandler commitDelegate, EventHandler delegate) + { + this.commitDelegate = Objects.requireNonNull(commitDelegate, "commitDelegate"); + this.delegate = delegate; // may be null + } + + @Override + public void handleEvent(Event event) + { + cachedEvents.add(event); + + if (delegate != null) + delegate.handleEvent(event); + } + + @Override + public void handleEvents(List events) + { + cachedEvents.addAll(events); + + if (delegate != null) + delegate.handleEvents(events); + } + + public void commitEvents() + { + commitDelegate.handleEvents(cachedEvents); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionEventManager.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionEventManager.java deleted file mode 100755 index c1ec37d4e..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionEventManager.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.highmed.dsf.fhir.dao.command; - -import java.util.ArrayList; -import java.util.List; - -import javax.websocket.RemoteEndpoint.Async; - -import org.highmed.dsf.fhir.authentication.User; -import org.highmed.dsf.fhir.event.Event; -import org.highmed.dsf.fhir.event.EventManager; - -public class TransactionEventManager implements EventManager -{ - private final List cachedEvents = new ArrayList<>(); - private final EventManager delegate; - - public TransactionEventManager(EventManager delegate) - { - this.delegate = delegate; - } - - @Override - public void handleEvent(Event event) - { - cachedEvents.add(event); - } - - @Override - public void handleEvents(List events) - { - this.cachedEvents.addAll(events); - } - - public void commitEvents() - { - delegate.handleEvents(cachedEvents); - } - - @Override - public void bind(User user, String sessionId, Async asyncRemote, String subscriptionIdPart) - { - delegate.bind(user, sessionId, asyncRemote, subscriptionIdPart); - } - - @Override - public void close(String sessionId) - { - delegate.close(sessionId); - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionResources.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionResources.java new file mode 100644 index 000000000..c69fef5aa --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/TransactionResources.java @@ -0,0 +1,33 @@ +package org.highmed.dsf.fhir.dao.command; + +import org.highmed.dsf.fhir.service.SnapshotGenerator; + +public class TransactionResources +{ + private final ValidationHelper validationHelper; + private final SnapshotGenerator snapshotGenerator; + private final TransactionEventHandler transactionEventHandler; + + public TransactionResources(ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator, + TransactionEventHandler transactionEventHandler) + { + this.validationHelper = validationHelper; + this.snapshotGenerator = snapshotGenerator; + this.transactionEventHandler = transactionEventHandler; + } + + public ValidationHelper getValidationHelper() + { + return validationHelper; + } + + public SnapshotGenerator getSnapshotGenerator() + { + return snapshotGenerator; + } + + public TransactionEventHandler getTransactionEventHandler() + { + return transactionEventHandler; + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/UpdateCommand.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/UpdateCommand.java index bb96cd75f..6a0974363 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/UpdateCommand.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/UpdateCommand.java @@ -17,21 +17,27 @@ import org.highmed.dsf.fhir.authentication.User; import org.highmed.dsf.fhir.dao.ResourceDao; +import org.highmed.dsf.fhir.dao.exception.ResourceDeletedException; import org.highmed.dsf.fhir.dao.exception.ResourceNotFoundException; +import org.highmed.dsf.fhir.dao.exception.ResourceVersionNoMatchException; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.prefer.PreferReturnType; import org.highmed.dsf.fhir.search.PartialResult; import org.highmed.dsf.fhir.search.SearchQuery; import org.highmed.dsf.fhir.search.SearchQueryParameterError; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleEntryResponseComponent; import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,43 +45,43 @@ import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; +import ca.uhn.fhir.validation.ValidationResult; + public class UpdateCommand> extends AbstractCommandWithResource implements Command { private static final Logger logger = LoggerFactory.getLogger(UpdateCommand.class); - private final ResponseGenerator responseGenerator; - private final ResolveReferencesHelper resolveReferencesHelper; - - protected final EventManager eventManager; + protected final ResponseGenerator responseGenerator; + protected final ReferenceCleaner referenceCleaner; protected final EventGenerator eventGenerator; - protected UUID id; + protected Boolean foundByCondition; protected R updatedResource; + protected ValidationResult validationResult; - public UpdateCommand(int index, User user, Bundle bundle, BundleEntryComponent entry, String serverBase, - AuthorizationHelper authorizationHelper, R resource, D dao, ExceptionHandler exceptionHandler, - ParameterConverter parameterConverter, ResponseGenerator responseGenerator, - ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, EventManager eventManager, - EventGenerator eventGenerator) + public UpdateCommand(int index, User user, PreferReturnType returnType, Bundle bundle, BundleEntryComponent entry, + String serverBase, AuthorizationHelper authorizationHelper, R resource, D dao, + ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + ResponseGenerator responseGenerator, ReferenceExtractor referenceExtractor, + ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, EventGenerator eventGenerator) { - super(3, index, user, bundle, entry, serverBase, authorizationHelper, resource, dao, exceptionHandler, - parameterConverter); + super(3, index, user, returnType, bundle, entry, serverBase, authorizationHelper, resource, dao, + exceptionHandler, parameterConverter, responseGenerator, referenceExtractor, referenceResolver); this.responseGenerator = responseGenerator; - resolveReferencesHelper = new ResolveReferencesHelper(index, user, serverBase, referenceExtractor, - referenceResolver, responseGenerator); + this.referenceCleaner = referenceCleaner; - this.eventManager = eventManager; this.eventGenerator = eventGenerator; } @Override - public void preExecute(Map idTranslationTable) + public void preExecute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) { UriComponents eruComponentes = UriComponentsBuilder.fromUriString(entry.getRequest().getUrl()).build(); - // check standard update request url: Patient/123 + // check standard update request url: e.g. Patient/123 if (eruComponentes.getPathSegments().size() == 2 && eruComponentes.getQueryParams().isEmpty()) { if (entry.getFullUrl().startsWith(URL_UUID_PREFIX)) @@ -101,7 +107,7 @@ else if (!expectedResourceTypeName.equals(eruComponentes.getPathSegments().get(0 responseGenerator.badUpdateRequestUrl(index, entry.getRequest().getUrl())); } - // check conditional update request url: Patient?... + // check conditional update request url: e.g. Patient?... else if (eruComponentes.getPathSegments().size() == 1 && !eruComponentes.getQueryParams().isEmpty()) { if (!entry.getFullUrl().startsWith(URL_UUID_PREFIX)) @@ -113,6 +119,9 @@ else if (resource.hasIdElement() && !resource.getIdElement().getValue().startsWi else if (resource.hasIdElement() && !entry.getFullUrl().equals(resource.getIdElement().getValue())) throw new WebApplicationException(responseGenerator.badBundleEntryFullUrlVsResourceId(index, entry.getFullUrl(), resource.getIdElement().getValue())); + + // add new or existing id to the id translation table + addToIdTranslationTable(idTranslationTable, connection); } // all other request urls @@ -121,76 +130,13 @@ else if (resource.hasIdElement() && !entry.getFullUrl().equals(resource.getIdEle responseGenerator.badUpdateRequestUrl(index, entry.getRequest().getUrl())); } - @Override - public void execute(Map idTranslationTable, Connection connection) - throws SQLException, WebApplicationException + private void addToIdTranslationTable(Map idTranslationTable, Connection connection) { UriComponents componentes = UriComponentsBuilder.fromUriString(entry.getRequest().getUrl()).build(); + String resourceTypeName = componentes.getPathSegments().get(0); + Map> queryParameters = parameterConverter + .urlDecodeQueryParameters(componentes.getQueryParams()); - if (componentes.getPathSegments().size() == 2 && componentes.getQueryParams().isEmpty()) - updateById(idTranslationTable, connection, componentes.getPathSegments().get(0), - componentes.getPathSegments().get(1)); - else if (componentes.getPathSegments().size() == 1 && !componentes.getQueryParams().isEmpty()) - updateByCondition(idTranslationTable, connection, componentes.getPathSegments().get(0), - parameterConverter.urlDecodeQueryParameters(componentes.getQueryParams())); - else - throw new WebApplicationException( - responseGenerator.badUpdateRequestUrl(index, entry.getRequest().getUrl())); - } - - private void updateById(Map idTranslationTable, Connection connection, String resourceTypeName, - String pathId) throws SQLException - { - IdType resourceId = resource.getIdElement(); - - if (!Objects.equals(pathId, resourceId.getIdPart())) - throw new WebApplicationException( - responseGenerator.pathVsElementIdInBundle(index, resourceTypeName, pathId, resourceId)); - if (resourceId.getBaseUrl() != null && !serverBase.equals(resourceId.getBaseUrl())) - throw new WebApplicationException( - responseGenerator.invalidBaseUrlInBundle(index, resourceTypeName, resourceId)); - - if (!Objects.equals(resourceTypeName, resource.getResourceType().name())) - throw new WebApplicationException(responseGenerator.nonMatchingResourceTypeAndRequestUrlInBundle(index, - resourceTypeName, entry.getRequest().getUrl())); - - checkUpdateAllowed(idTranslationTable, connection, user, resource); - - Optional ifMatch = Optional.ofNullable(entry.getRequest().getIfMatch()) - .flatMap(parameterConverter::toEntityTag).flatMap(parameterConverter::toVersion); - - updatedResource = exceptionHandler.handleSqlExAndResourceNotFoundExAndResouceVersionNonMatchEx(resourceTypeName, - () -> dao.updateWithTransaction(connection, resource, ifMatch.orElse(null))); - } - - private void checkUpdateAllowed(Map idTranslationTable, Connection connection, User user, - R newResource) - { - String resourceTypeName = newResource.getResourceType().name(); - String id = newResource.getIdElement().getIdPart(); - - Optional dbResource = exceptionHandler.handleSqlAndResourceDeletedException(resourceTypeName, - () -> dao.readWithTransaction(connection, parameterConverter.toUuid(resourceTypeName, id))); - - if (dbResource.isEmpty()) - { - audit.info("Create as Update of non existing resource {} denied for user '{}'", resourceTypeName + "/" + id, - user.getName()); - throw new WebApplicationException( - responseGenerator.updateAsCreateNotAllowed(resourceTypeName, resourceTypeName + "/" + id)); - } - else - { - resolveReferencesHelper.resolveReferencesIgnoreAndLogExceptions(idTranslationTable, connection, resource); - - R oldResource = dbResource.get(); - authorizationHelper.checkUpdateAllowed(connection, user, oldResource, newResource); - } - } - - private void updateByCondition(Map idTranslationTable, Connection connection, - String resourceTypeName, Map> queryParameters) throws SQLException - { if (Arrays.stream(SearchQuery.STANDARD_PARAMETERS).anyMatch(queryParameters::containsKey)) { logger.warn( @@ -216,29 +162,26 @@ private void updateByCondition(Map idTranslationTable, Connectio .handleSqlException(() -> dao.searchWithTransaction(connection, query)); // No matches and no id provided or temp id: The server creates the resource. - if (result.getOverallCount() <= 0 + if (result.getTotal() <= 0 && (!resource.hasId() || resource.getIdElement().getValue().startsWith(URL_UUID_PREFIX))) { - resolveReferencesHelper.resolveReferencesIgnoreAndLogExceptions(idTranslationTable, connection, resource); - - authorizationHelper.checkCreateAllowed(connection, user, resource); - - id = UUID.randomUUID(); + UUID id = UUID.randomUUID(); idTranslationTable.put(entry.getFullUrl(), new IdType(resource.getResourceType().toString(), id.toString())); - updatedResource = dao.createWithTransactionAndId(connection, resource, id); + + foundByCondition = false; } // No matches, id provided: The server treats the interaction as an Update as Create interaction (or rejects it, // if it does not support Update as Create) -> reject - else if (result.getOverallCount() <= 0 && resource.hasId()) + else if (result.getTotal() <= 0 && resource.hasId()) // TODO bundle specific error throw new WebApplicationException( responseGenerator.updateAsCreateNotAllowed(resourceTypeName, resource.getId())); // One Match, no resource id provided OR (resource id provided and it matches the found resource): // The server performs the update against the matching resource - else if (result.getOverallCount() == 1) + else if (result.getTotal() == 1) { R dbResource = result.getPartialResult().get(0); IdType dbResourceId = dbResource.getIdElement(); @@ -246,13 +189,10 @@ else if (result.getOverallCount() == 1) // update: resource has no id or resource has temporary id if (!resource.hasId() || resource.getIdElement().getValue().startsWith(URL_UUID_PREFIX)) { - resource.setIdElement(dbResourceId); - - // more security checks and audit log in update method - updateById(idTranslationTable, connection, resourceTypeName, resource.getIdElement().getIdPart()); - idTranslationTable.put(entry.getFullUrl(), new IdType(resource.getResourceType().toString(), dbResource.getIdElement().getIdPart())); + + foundByCondition = true; } // update: resource has same id else if (resource.hasId() @@ -262,8 +202,10 @@ else if (resource.hasId() || resourceTypeName.equals(resource.getIdElement().getResourceType())) && (dbResourceId.getIdPart().equals(resource.getIdElement().getIdPart()))) { - // more security checks and audit log in update method - updateById(idTranslationTable, connection, resourceTypeName, resource.getIdElement().getIdPart()); + idTranslationTable.put(entry.getFullUrl(), + new IdType(resource.getResourceType().toString(), dbResource.getIdElement().getIdPart())); + + foundByCondition = true; } else // TODO bundle specific error @@ -281,39 +223,190 @@ else if (resource.hasId() } @Override - public Optional postExecute(Connection connection) + public void execute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) + throws SQLException, WebApplicationException + { + UriComponents componentes = UriComponentsBuilder.fromUriString(entry.getRequest().getUrl()).build(); + + if (componentes.getPathSegments().size() == 2 && componentes.getQueryParams().isEmpty()) + updateById(idTranslationTable, connection, validationHelper, componentes.getPathSegments().get(0), + componentes.getPathSegments().get(1)); + else if (componentes.getPathSegments().size() == 1 && !componentes.getQueryParams().isEmpty()) + updateByCondition(idTranslationTable, connection, validationHelper, componentes.getPathSegments().get(0), + parameterConverter.urlDecodeQueryParameters(componentes.getQueryParams())); + else + throw new WebApplicationException( + responseGenerator.badUpdateRequestUrl(index, entry.getRequest().getUrl())); + } + + private void updateById(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, String resourceTypeName, String pathId) throws SQLException + { + IdType resourceId = resource.getIdElement(); + + if (!Objects.equals(pathId, resourceId.getIdPart())) + throw new WebApplicationException( + responseGenerator.pathVsElementIdInBundle(index, resourceTypeName, pathId, resourceId)); + if (resourceId.getBaseUrl() != null && !serverBase.equals(resourceId.getBaseUrl())) + throw new WebApplicationException( + responseGenerator.invalidBaseUrlInBundle(index, resourceTypeName, resourceId)); + + if (!Objects.equals(resourceTypeName, resource.getResourceType().name())) + throw new WebApplicationException(responseGenerator.nonMatchingResourceTypeAndRequestUrlInBundle(index, + resourceTypeName, entry.getRequest().getUrl())); + + @SuppressWarnings("unchecked") + R copy = (R) resource.copy(); + checkUpdateAllowed(idTranslationTable, connection, validationHelper, user, copy); + + Optional ifMatch = Optional.ofNullable(entry.getRequest().getIfMatch()) + .flatMap(parameterConverter::toEntityTag).flatMap(parameterConverter::toVersion); + + updatedResource = exceptionHandler.handleSqlExAndResourceNotFoundExAndResouceVersionNonMatchEx(resourceTypeName, + () -> updateWithTransaction(connection, resource, ifMatch.orElse(null))); + } + + protected R updateWithTransaction(Connection connection, R resource, Long expectedVersion) + throws SQLException, ResourceNotFoundException, ResourceVersionNoMatchException + { + return dao.updateWithTransaction(connection, resource, expectedVersion); + } + + private void checkUpdateAllowed(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, User user, R newResource) + { + String resourceTypeName = newResource.getResourceType().name(); + String id = newResource.getIdElement().getIdPart(); + + Optional dbResource = exceptionHandler.handleSqlAndResourceDeletedException(serverBase, resourceTypeName, + () -> dao.readWithTransaction(connection, parameterConverter.toUuid(resourceTypeName, id))); + + if (dbResource.isEmpty()) + { + audit.info("Create as Update of non existing resource {} denied for user '{}'", resourceTypeName + "/" + id, + user.getName()); + throw new WebApplicationException( + responseGenerator.updateAsCreateNotAllowed(resourceTypeName, resourceTypeName + "/" + id)); + } + else + { + referencesHelper.resolveTemporaryAndConditionalReferences(idTranslationTable, connection); + + validationResult = validationHelper.checkResourceValidForUpdate(user, resource); + + referencesHelper.resolveLogicalReferences(connection); + + authorizationHelper.checkUpdateAllowed(connection, user, dbResource.get(), resource); + } + } + + private void updateByCondition(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, String resourceTypeName, Map> queryParameters) + throws SQLException + { + if (Boolean.FALSE.equals(foundByCondition)) + { + referencesHelper.resolveTemporaryAndConditionalReferences(idTranslationTable, connection); + + validationResult = validationHelper.checkResourceValidForCreate(user, resource); + + referencesHelper.resolveLogicalReferences(connection); + + authorizationHelper.checkCreateAllowed(connection, user, resource); + + updatedResource = createWithTransactionAndId(connection, resource, getUuid(idTranslationTable)); + } + else if (Boolean.TRUE.equals(foundByCondition)) + { + resource.setIdElement(getId(idTranslationTable)); + + updateById(idTranslationTable, connection, validationHelper, resourceTypeName, + resource.getIdElement().getIdPart()); + } + // else errors thrown by preExecute + } + + protected R createWithTransactionAndId(Connection connection, R resource, UUID uuid) throws SQLException + { + return dao.createWithTransactionAndId(connection, resource, uuid); + } + + private IdType getId(Map idTranslationTable) + { + IdType idType = idTranslationTable.get(entry.getFullUrl()); + if (idType != null) + { + return idType; + } + + throw new RuntimeException("Error while retrieving id from id translation table"); + } + + private UUID getUuid(Map idTranslationTable) + { + Optional uuid = parameterConverter.toUuid(getId(idTranslationTable).getIdPart()); + if (uuid.isPresent()) + return uuid.get(); + + throw new RuntimeException("Error while retrieving id from id translation table"); + } + + @Override + public Optional postExecute(Connection connection, EventHandler eventHandler) { + // retrieving the latest resource from db to include updated references + Resource updatedResourceWithResolvedReferences = latestOrErrorIfDeletedOrNotFound(connection, updatedResource); try { - // retrieving the latest resource from db to include updated references - Resource updatedResourceWithResolvedReferences = latestOrErrorIfDeletedOrNotFound(connection, - updatedResource); - eventManager.handleEvent(eventGenerator.newResourceUpdatedEvent(updatedResourceWithResolvedReferences)); + referenceCleaner.cleanLiteralReferences(updatedResourceWithResolvedReferences); + eventHandler.handleEvent(eventGenerator.newResourceUpdatedEvent(updatedResourceWithResolvedReferences)); } catch (Exception e) { logger.warn("Error while handling resource updated event", e); } + IdType location = updatedResourceWithResolvedReferences.getIdElement().withServerBase(serverBase, + updatedResourceWithResolvedReferences.getResourceType().name()); + BundleEntryComponent resultEntry = new BundleEntryComponent(); - resultEntry.setFullUrl(new IdType(serverBase, updatedResource.getResourceType().name(), - updatedResource.getIdElement().getIdPart(), null).getValue()); + resultEntry.setFullUrl(location.toVersionless().toString()); + + if (PreferReturnType.REPRESENTATION.equals(returnType)) + resultEntry.setResource(updatedResourceWithResolvedReferences); + else if (PreferReturnType.OPERATION_OUTCOME.equals(returnType)) + { + OperationOutcome outcome = responseGenerator.updated(location.toString(), + updatedResourceWithResolvedReferences); + validationResult.populateOperationOutcome(outcome); + resultEntry.getResponse().setOutcome(outcome); + } + BundleEntryResponseComponent response = resultEntry.getResponse(); response.setStatus(Status.OK.getStatusCode() + " " + Status.OK.getReasonPhrase()); - response.setLocation(updatedResource.getIdElement() - .withServerBase(serverBase, updatedResource.getResourceType().name()).getValue()); - response.setEtag(new EntityTag(updatedResource.getMeta().getVersionId(), true).toString()); - response.setLastModified(updatedResource.getMeta().getLastUpdated()); + response.setLocation(location.getValue()); + response.setEtag( + new EntityTag(updatedResourceWithResolvedReferences.getMeta().getVersionId(), true).toString()); + response.setLastModified(updatedResourceWithResolvedReferences.getMeta().getLastUpdated()); return Optional.of(resultEntry); } - private R latestOrErrorIfDeletedOrNotFound(Connection connection, Resource resource) throws Exception + private R latestOrErrorIfDeletedOrNotFound(Connection connection, Resource resource) { - return dao - .readWithTransaction(connection, - parameterConverter.toUuid(resource.getResourceType().name(), - resource.getIdElement().getIdPart())) - .orElseThrow(() -> new ResourceNotFoundException(resource.getIdElement().getIdPart())); + try + { + return dao + .readWithTransaction(connection, + parameterConverter.toUuid(resource.getResourceType().name(), + resource.getIdElement().getIdPart())) + .orElseThrow(() -> new ResourceNotFoundException(resource.getIdElement().getIdPart())); + } + catch (ResourceNotFoundException | SQLException | ResourceDeletedException e) + { + logger.warn("Error while reading resource from db", e); + throw new RuntimeException(e); + } } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/UpdateStructureDefinitionCommand.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/UpdateStructureDefinitionCommand.java index 49c01f01e..b03b8f6c7 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/UpdateStructureDefinitionCommand.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/UpdateStructureDefinitionCommand.java @@ -1,29 +1,31 @@ package org.highmed.dsf.fhir.dao.command; import java.sql.Connection; +import java.sql.SQLException; import java.util.Map; -import java.util.Optional; +import java.util.UUID; + +import javax.ws.rs.WebApplicationException; import org.highmed.dsf.fhir.authentication.User; import org.highmed.dsf.fhir.dao.StructureDefinitionDao; -import org.highmed.dsf.fhir.dao.StructureDefinitionSnapshotDao; +import org.highmed.dsf.fhir.dao.exception.ResourceNotFoundException; +import org.highmed.dsf.fhir.dao.exception.ResourceVersionNoMatchException; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; -import org.highmed.dsf.fhir.function.ConsumerWithSqlAndResourceNotFoundException; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.prefer.PreferReturnType; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; -import org.highmed.dsf.fhir.service.SnapshotDependencies; -import org.highmed.dsf.fhir.service.SnapshotDependencyAnalyzer; import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.highmed.dsf.fhir.service.SnapshotGenerator.SnapshotWithValidationMessages; -import org.highmed.dsf.fhir.service.SnapshotInfo; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,75 +34,94 @@ public class UpdateStructureDefinitionCommand extends UpdateCommand idTranslationTable) + public void preExecute(Map idTranslationTable, Connection connection, + ValidationHelper validationHelper, SnapshotGenerator snapshotGenerator) { - resourceWithSnapshot = resource.hasSnapshot() ? resource.copy() : null; + resourceWithSnapshot = resource.hasSnapshot() ? resource.copy() + : generateSnapshot(snapshotGenerator, resource.copy()); resource.setSnapshot(null); - super.preExecute(idTranslationTable); + super.preExecute(idTranslationTable, connection, validationHelper, snapshotGenerator); } - @Override - public Optional postExecute(Connection connection) + private StructureDefinition generateSnapshot(SnapshotGenerator snapshotGenerator, StructureDefinition resource) { - if (resourceWithSnapshot != null) + logger.debug("Generating snapshot for bundle entry at index {}", index); + SnapshotWithValidationMessages s = snapshotGenerator.generateSnapshot(resource); + + if (s.getMessages().stream() + .anyMatch(m -> IssueSeverity.FATAL.equals(m.getLevel()) || IssueSeverity.ERROR.equals(m.getLevel()))) { - handleSnapshot(connection, resourceWithSnapshot, - info -> snapshotDao.updateWithTransaction(connection, resourceWithSnapshot, info)); + throw new WebApplicationException( + responseGenerator.unableToGenerateSnapshot(resource, index, s.getMessages())); } - else if (updatedResource != null) + + return s.getSnapshot(); + } + + @Override + protected StructureDefinition createWithTransactionAndId(Connection connection, StructureDefinition resource, + UUID uuid) throws SQLException + { + StructureDefinition created = super.createWithTransactionAndId(connection, resource, uuid); + + if (resourceWithSnapshot != null) { try { - SnapshotWithValidationMessages s = snapshotGenerator.generateSnapshot(updatedResource); - - if (s != null && s.getSnapshot() != null && s.getMessages().isEmpty()) - handleSnapshot(connection, s.getSnapshot(), - info -> snapshotDao.updateWithTransaction(connection, s.getSnapshot(), info)); + snapshotDao.createWithTransactionAndId(connection, resourceWithSnapshot, uuid); } - catch (Exception e) + catch (SQLException e) { - logger.warn("Error while generating snapshot for StructureDefinition with id " - + updatedResource.getIdElement().getIdPart(), e); + logger.warn("Error while creating StructureDefinition snapshot: " + e.getMessage(), e); + throw e; } } - return super.postExecute(connection); + return created; } - private void handleSnapshot(Connection connection, StructureDefinition snapshot, - ConsumerWithSqlAndResourceNotFoundException dbOp) + @Override + protected StructureDefinition updateWithTransaction(Connection connection, StructureDefinition resource, + Long expectedVersion) throws SQLException, ResourceNotFoundException, ResourceVersionNoMatchException { - SnapshotDependencies dependencies = snapshotDependencyAnalyzer.analyzeSnapshotDependencies(snapshot); + StructureDefinition updated = super.updateWithTransaction(connection, resource, expectedVersion); + + if (resourceWithSnapshot != null) + { + if (!resourceWithSnapshot.hasId() && resource.hasId()) + resourceWithSnapshot.setIdElement(resource.getIdElement().copy()); - exceptionHandler.catchAndLogSqlException( - () -> snapshotDao.deleteAllByDependencyWithTransaction(connection, snapshot.getUrl())); + try + { + snapshotDao.updateWithTransaction(connection, resourceWithSnapshot, expectedVersion); + } + catch (SQLException | ResourceNotFoundException | ResourceVersionNoMatchException e) + { + logger.warn("Error while updating StructureDefinition snapshot: " + e.getMessage(), e); + throw e; + } + } - exceptionHandler.catchAndLogSqlAndResourceNotFoundException(resource.getResourceType().name(), - () -> dbOp.accept(new SnapshotInfo(dependencies))); + return updated; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ValidationHelper.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ValidationHelper.java new file mode 100644 index 000000000..23242598d --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ValidationHelper.java @@ -0,0 +1,13 @@ +package org.highmed.dsf.fhir.dao.command; + +import org.highmed.dsf.fhir.authentication.User; +import org.hl7.fhir.r4.model.Resource; + +import ca.uhn.fhir.validation.ValidationResult; + +public interface ValidationHelper +{ + ValidationResult checkResourceValidForCreate(User user, Resource resource); + + ValidationResult checkResourceValidForUpdate(User user, Resource resource); +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ValidationHelperImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ValidationHelperImpl.java new file mode 100644 index 000000000..520919ee7 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/command/ValidationHelperImpl.java @@ -0,0 +1,69 @@ +package org.highmed.dsf.fhir.dao.command; + +import java.util.stream.Collectors; + +import javax.ws.rs.WebApplicationException; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ResourceValidator; +import org.hl7.fhir.r4.model.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.validation.ResultSeverityEnum; +import ca.uhn.fhir.validation.ValidationResult; + +public class ValidationHelperImpl implements ValidationHelper +{ + private static final Logger logger = LoggerFactory.getLogger(ValidationHelperImpl.class); + + private final ResourceValidator resourceValidator; + private final ResponseGenerator responseGenerator; + + public ValidationHelperImpl(ResourceValidator resourceValidator, ResponseGenerator responseGenerator) + { + this.resourceValidator = resourceValidator; + this.responseGenerator = responseGenerator; + } + + @Override + public ValidationResult checkResourceValidForCreate(User user, Resource resource) + { + return checkResourceValid(user, resource, "Create"); + } + + @Override + public ValidationResult checkResourceValidForUpdate(User user, Resource resource) + { + return checkResourceValid(user, resource, "Update"); + } + + private ValidationResult checkResourceValid(User user, Resource resource, String method) + { + ValidationResult validationResult = resourceValidator.validate(resource); + + if (validationResult.getMessages().stream().anyMatch(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity()))) + { + logger.warn("{} of {} unauthorized, resource not valid: {}", method, resource.fhirType(), + toValidationLogMessage(validationResult)); + + throw new WebApplicationException( + responseGenerator.forbiddenNotValid(method, user, resource.fhirType(), validationResult)); + } + else if (!validationResult.getMessages().isEmpty()) + logger.info("Resource {} validated with messages: {}", resource.fhirType(), + toValidationLogMessage(validationResult)); + + return validationResult; + } + + private String toValidationLogMessage(ValidationResult validationResult) + { + return validationResult + .getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" + + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()) + .collect(Collectors.joining(", ", "[", "]")); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/converter/SnapshotInfoConverter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/converter/SnapshotInfoConverter.java deleted file mode 100755 index 077802549..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/converter/SnapshotInfoConverter.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.highmed.dsf.fhir.dao.converter; - -import java.io.IOException; -import java.sql.SQLException; -import java.util.Objects; - -import org.highmed.dsf.fhir.service.SnapshotInfo; -import org.postgresql.util.PGobject; -import org.springframework.beans.factory.InitializingBean; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -public class SnapshotInfoConverter implements InitializingBean -{ - private final ObjectMapper objectMapper; - - public SnapshotInfoConverter(ObjectMapper objectMapper) - { - this.objectMapper = objectMapper; - } - - @Override - public void afterPropertiesSet() throws Exception - { - Objects.requireNonNull(objectMapper, "objectMapper"); - } - - public SnapshotInfo fromDb(String json) - { - if (json == null) - return null; - - try - { - return objectMapper.reader().forType(SnapshotInfo.class).readValue(json); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - - public PGobject toDb(SnapshotInfo info) - { - if (info == null) - return null; - - try - { - PGobject o = new PGobject(); - o.setType("JSONB"); - - o.setValue(objectMapper.writer().forType(SnapshotInfo.class).writeValueAsString(info)); - - return o; - } - catch (JsonProcessingException | SQLException e) - { - throw new RuntimeException(e); - } - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/exception/ResourceDeletedException.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/exception/ResourceDeletedException.java index a8bd03963..3554e5ec7 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/exception/ResourceDeletedException.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/exception/ResourceDeletedException.java @@ -1,20 +1,29 @@ package org.highmed.dsf.fhir.dao.exception; +import java.time.LocalDateTime; + import org.hl7.fhir.r4.model.IdType; public class ResourceDeletedException extends Exception { private static final long serialVersionUID = 1L; - + private final IdType id; + private final LocalDateTime deleted; - public ResourceDeletedException(IdType id) + public ResourceDeletedException(IdType id, LocalDateTime deleted) { this.id = id; + this.deleted = deleted; } - + public IdType getId() { return id; } + + public LocalDateTime getDeleted() + { + return deleted; + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/AbstractResourceDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/AbstractResourceDaoJdbc.java index 61f9c94bd..04d531130 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/AbstractResourceDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/AbstractResourceDaoJdbc.java @@ -5,6 +5,8 @@ import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; +import java.sql.Timestamp; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; @@ -282,25 +284,6 @@ protected R getResource(ResultSet result, int index) throws SQLException return preparedStatementFactory.getJsonParser().parseResource(resourceType, json); } - /* caution: only works because we set all versions as deleted or not deleted in method markDeleted */ - public final boolean hasNonDeletedResource(Connection connection, UUID uuid) throws SQLException - { - if (uuid == null) - return false; - - try (PreparedStatement statement = connection.prepareStatement( - "SELECT count(*) FROM " + resourceTable + " WHERE " + resourceIdColumn + " = ? AND NOT deleted")) - { - statement.setObject(1, preparedStatementFactory.uuidToPgObject(uuid)); - - logger.trace("Executing query '{}'", statement); - try (ResultSet result = statement.executeQuery()) - { - return result.next() && result.getInt(1) > 0; - } - } - } - @Override public final Optional read(UUID uuid) throws SQLException, ResourceDeletedException { @@ -330,10 +313,12 @@ public Optional readWithTransaction(Connection connection, UUID uuid) { if (result.next()) { - if (preparedStatementFactory.isReadByIdDeleted(result)) + LocalDateTime deleted = preparedStatementFactory.getReadByIdDeleted(result); + if (deleted != null) { + long version = preparedStatementFactory.getReadByIdVersion(result); logger.debug("{} with IdPart {} found, but marked as deleted", resourceTypeName, uuid); - throw new ResourceDeletedException(new IdType(resourceTypeName, uuid.toString())); + throw newResourceDeletedException(uuid, deleted, version); } else { @@ -350,8 +335,14 @@ public Optional readWithTransaction(Connection connection, UUID uuid) } } + private ResourceDeletedException newResourceDeletedException(UUID uuid, LocalDateTime deleted, long version) + { + return new ResourceDeletedException(new IdType(resourceTypeName, uuid.toString(), String.valueOf(version + 1)), + deleted); + } + @Override - public final Optional readVersion(UUID uuid, long version) throws SQLException + public final Optional readVersion(UUID uuid, long version) throws SQLException, ResourceDeletedException { if (uuid == null || version < FIRST_VERSION) return Optional.empty(); @@ -363,7 +354,8 @@ public final Optional readVersion(UUID uuid, long version) throws SQLExceptio } @Override - public Optional readVersionWithTransaction(Connection connection, UUID uuid, long version) throws SQLException + public Optional readVersionWithTransaction(Connection connection, UUID uuid, long version) + throws SQLException, ResourceDeletedException { Objects.requireNonNull(connection, "connection"); if (uuid == null || version < FIRST_VERSION) @@ -379,6 +371,16 @@ public Optional readVersionWithTransaction(Connection connection, UUID uuid, { if (result.next()) { + LocalDateTime deleted = preparedStatementFactory.getReadByIdVersionDeleted(result); + long lastVersion = preparedStatementFactory.getReadByIdVersionVersion(result); + if (lastVersion + 1 == version) + { + logger.debug( + "{} with IdPart {} and Version {} found, but marked as deleted (delete history entry)", + resourceTypeName, uuid, version); + throw newResourceDeletedException(uuid, deleted, lastVersion); + } + logger.debug("{} with IdPart {} and Version {} found", resourceTypeName, uuid, version); return Optional.of(preparedStatementFactory.getReadByIdAndVersionResource(result)); } @@ -419,7 +421,7 @@ public Optional readIncludingDeletedWithTransaction(Connection connection, UU { if (result.next()) { - if (preparedStatementFactory.isReadByIdDeleted(result)) + if (preparedStatementFactory.getReadByIdDeleted(result) != null) logger.warn("{} with IdPart {} found, but marked as deleted", resourceTypeName, uuid); else logger.debug("{} with IdPart {} found", resourceTypeName, uuid); @@ -435,6 +437,36 @@ public Optional readIncludingDeletedWithTransaction(Connection connection, UU } } + @Override + public List readAll() throws SQLException + { + try (Connection connection = getDataSource().getConnection()) + { + return readAllWithTransaction(connection); + } + } + + @Override + public List readAllWithTransaction(Connection connection) throws SQLException + { + Objects.requireNonNull(connection, "connection"); + + try (PreparedStatement statement = connection + .prepareStatement("SELECT " + getResourceColumn() + " FROM current_" + getResourceTable())) + { + logger.trace("Executing query '{}'", statement); + try (ResultSet result = statement.executeQuery()) + { + List all = new ArrayList<>(); + + while (result.next()) + all.add(getResource(result, 1)); + + return all; + } + } + } + @Override public boolean existsNotDeleted(String idString, String versionString) throws SQLException { @@ -453,15 +485,27 @@ public boolean existsNotDeletedWithTransaction(Connection connection, String idS return false; if (versionString == null || versionString.isBlank()) - return hasNonDeletedResource(connection, uuid); + { + try (PreparedStatement statement = connection.prepareStatement("SELECT deleted IS NOT NULL FROM " + + resourceTable + " WHERE " + resourceIdColumn + " = ? ORDER BY version DESC LIMIT 1")) + { + statement.setObject(1, preparedStatementFactory.uuidToPgObject(uuid)); + + logger.trace("Executing query '{}'", statement); + try (ResultSet result = statement.executeQuery()) + { + return result.next() && !result.getBoolean(1); + } + } + } else { Long version = toLong(versionString); if (version == null || version < FIRST_VERSION) return false; - try (PreparedStatement statement = connection.prepareStatement("SELECT count(*) FROM " + resourceTable - + " WHERE " + resourceIdColumn + " = ? AND version = ? AND NOT deleted")) + try (PreparedStatement statement = connection.prepareStatement("SELECT deleted IS NOT NULL FROM " + + resourceTable + " WHERE " + resourceIdColumn + " = ? AND version = ?")) { statement.setObject(1, preparedStatementFactory.uuidToPgObject(uuid)); statement.setLong(2, version); @@ -469,7 +513,7 @@ public boolean existsNotDeletedWithTransaction(Connection connection, String idS logger.trace("Executing query '{}'", statement); try (ResultSet result = statement.executeQuery()) { - return result.next() && result.getInt(1) > 0; + return result.next() && !result.getBoolean(1); } } } @@ -530,11 +574,10 @@ public R updateWithTransaction(Connection connection, R resource, Long expectedV latestVersion.version); } + // latestVersion gives stored latest version +1 if resource is deleted long newVersion = latestVersion.version + 1; R updated = update(connection, resource, newVersion); - if (latestVersion.deleted) // TODO check if resurrection needs undelete for old versions - markDeleted(connection, toUuid(updated.getIdElement().getIdPart()), false); logger.debug("{} with IdPart {} updated, new version {}", resourceTypeName, updated.getIdElement().getIdPart(), newVersion); @@ -652,7 +695,7 @@ protected static class LatestVersion LatestVersion(long version, boolean deleted) { - this.version = version; + this.version = version + (deleted ? 1 : 0); this.deleted = deleted; } } @@ -667,16 +710,6 @@ protected final LatestVersion getLatestVersion(R resource, Connection connection return getLatestVersion(uuid, connection); } - protected final Optional getLatestVersionIfExists(R resource, Connection connection) - throws SQLException, ResourceNotFoundException - { - UUID uuid = toUuid(resource.getIdElement().getIdPart()); - if (uuid == null) - throw new ResourceNotFoundException(resource.getId() != null ? resource.getId() : "'null'"); - - return getLatestVersionIfExists(uuid, connection); - } - protected final LatestVersion getLatestVersion(UUID uuid, Connection connection) throws SQLException, ResourceNotFoundException { @@ -693,8 +726,8 @@ protected final Optional getLatestVersionIfExists(UUID uuid, Conn if (uuid == null) return Optional.empty(); - try (PreparedStatement statement = connection.prepareStatement("SELECT version, deleted FROM " + resourceTable - + " WHERE " + resourceIdColumn + " = ? ORDER BY version DESC LIMIT 1")) + try (PreparedStatement statement = connection.prepareStatement("SELECT version, deleted IS NOT NULL FROM " + + resourceTable + " WHERE " + resourceIdColumn + " = ? ORDER BY version DESC LIMIT 1")) { statement.setObject(1, preparedStatementFactory.uuidToPgObject(uuid)); @@ -743,15 +776,10 @@ public boolean deleteWithTransaction(Connection connection, UUID uuid) if (connection.isReadOnly()) throw new IllegalStateException("Connection is read-only"); - return markDeleted(connection, uuid, true); + return markDeleted(connection, uuid); } - /* - * caution: implementation of method hasNonDeletedResource only works because we set all versions as deleted or not - * deleted here - */ - protected final boolean markDeleted(Connection connection, UUID uuid, boolean deleted) - throws SQLException, ResourceNotFoundException + protected final boolean markDeleted(Connection connection, UUID uuid) throws SQLException, ResourceNotFoundException { if (uuid == null) throw new ResourceNotFoundException("'null'"); @@ -761,11 +789,13 @@ protected final boolean markDeleted(Connection connection, UUID uuid, boolean de if (latestVersion.deleted) return false; - try (PreparedStatement statement = connection - .prepareStatement("UPDATE " + resourceTable + " SET deleted = ? WHERE " + resourceIdColumn + " = ?")) + try (PreparedStatement statement = connection.prepareStatement("UPDATE " + resourceTable + + " SET deleted = ? WHERE " + resourceIdColumn + " = ? AND version = (SELECT MAX(version) FROM " + + resourceTable + " WHERE " + resourceIdColumn + " = ?)")) { - statement.setBoolean(1, deleted); + statement.setTimestamp(1, Timestamp.valueOf(LocalDateTime.now())); statement.setObject(2, preparedStatementFactory.uuidToPgObject(uuid)); + statement.setObject(3, preparedStatementFactory.uuidToPgObject(uuid)); logger.trace("Executing query '{}'", statement); statement.execute(); @@ -792,7 +822,7 @@ public PartialResult searchWithTransaction(Connection connection, DbSearchQue Objects.requireNonNull(connection, "connection"); Objects.requireNonNull(query, "query"); - int overallCount = 0; + int total = 0; try (PreparedStatement statement = connection.prepareStatement(query.getCountSql())) { query.modifyStatement(statement, connection::createArrayOf); @@ -801,14 +831,14 @@ public PartialResult searchWithTransaction(Connection connection, DbSearchQue try (ResultSet result = statement.executeQuery()) { if (result.next()) - overallCount = result.getInt(1); + total = result.getInt(1); } } List partialResult = new ArrayList<>(); List includes = new ArrayList<>(); - if (!query.isCountOnly(overallCount)) // TODO ask db if count 0 + if (!query.getPageAndCount().isCountOnly(total)) { try (PreparedStatement statement = connection.prepareStatement(query.getSearchSql())) { @@ -835,8 +865,7 @@ public PartialResult searchWithTransaction(Connection connection, DbSearchQue includes = includes.stream().map(r -> new ResourceDistinctById(r.getIdElement(), r)).distinct() .map(ResourceDistinctById::getResource).collect(Collectors.toList()); - return new PartialResult<>(overallCount, query.getPageAndCount(), partialResult, includes, - query.isCountOnly(overallCount)); + return new PartialResult<>(total, query.getPageAndCount(), partialResult, includes); } /** diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/AbstractStructureDefinitionDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/AbstractStructureDefinitionDaoJdbc.java index eed0fe1b2..2cc9af3b4 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/AbstractStructureDefinitionDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/AbstractStructureDefinitionDaoJdbc.java @@ -1,33 +1,25 @@ package org.highmed.dsf.fhir.dao.jdbc; import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; import java.util.Optional; import java.util.function.Function; import org.apache.commons.dbcp2.BasicDataSource; import org.highmed.dsf.fhir.authentication.User; -import org.highmed.dsf.fhir.dao.StructureDefinitionDaoBase; +import org.highmed.dsf.fhir.dao.StructureDefinitionDao; import org.highmed.dsf.fhir.search.SearchQueryUserFilter; import org.highmed.dsf.fhir.search.parameters.StructureDefinitionIdentifier; import org.highmed.dsf.fhir.search.parameters.StructureDefinitionStatus; import org.highmed.dsf.fhir.search.parameters.StructureDefinitionUrl; import org.highmed.dsf.fhir.search.parameters.StructureDefinitionVersion; import org.hl7.fhir.r4.model.StructureDefinition; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import ca.uhn.fhir.context.FhirContext; abstract class AbstractStructureDefinitionDaoJdbc extends AbstractResourceDaoJdbc - implements StructureDefinitionDaoBase + implements StructureDefinitionDao { - private static final Logger logger = LoggerFactory.getLogger(AbstractStructureDefinitionDaoJdbc.class); - private final ReadByUrlDaoJdbc readByUrl; public AbstractStructureDefinitionDaoJdbc(BasicDataSource dataSource, FhirContext fhirContext, String resourceTable, @@ -42,34 +34,20 @@ public AbstractStructureDefinitionDaoJdbc(BasicDataSource dataSource, FhirContex with()); readByUrl = new ReadByUrlDaoJdbc(this::getDataSource, this::getResource, resourceTable, - resourceColumn, resourceIdColumn); + resourceColumn); } @Override - public List readAll() throws SQLException + public Optional readByUrlAndVersion(String urlAndVersion) throws SQLException { - try (Connection connection = getDataSource().getConnection(); - PreparedStatement statement = connection.prepareStatement("SELECT DISTINCT ON(" + getResourceIdColumn() - + ") " + getResourceColumn() + " FROM " + getResourceTable() + " WHERE NOT deleted ORDER BY " - + getResourceIdColumn() + ", version")) - { - logger.trace("Executing query '{}'", statement); - try (ResultSet result = statement.executeQuery()) - { - List all = new ArrayList<>(); - - while (result.next()) - all.add(getResource(result, 1)); - - return all; - } - } + return readByUrl.readByUrlAndVersion(urlAndVersion); } @Override - public Optional readByUrlAndVersion(String urlAndVersion) throws SQLException + public Optional readByUrlAndVersionWithTransaction(Connection connection, String urlAndVersion) + throws SQLException { - return readByUrl.readByUrlAndVersion(urlAndVersion); + return readByUrl.readByUrlAndVersionWithTransaction(connection, urlAndVersion); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ActivityDefinitionDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ActivityDefinitionDaoJdbc.java index 5be6d907d..e7dc66ae4 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ActivityDefinitionDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ActivityDefinitionDaoJdbc.java @@ -39,7 +39,7 @@ public ActivityDefinitionDaoJdbc(BasicDataSource dataSource, FhirContext fhirCon with()); readByUrl = new ReadByUrlDaoJdbc(this::getDataSource, this::getResource, getResourceTable(), - getResourceColumn(), getResourceIdColumn()); + getResourceColumn()); } @Override @@ -54,6 +54,13 @@ public Optional readByUrlAndVersion(String urlAndVersion) th return readByUrl.readByUrlAndVersion(urlAndVersion); } + @Override + public Optional readByUrlAndVersionWithTransaction(Connection connection, String urlAndVersion) + throws SQLException + { + return readByUrl.readByUrlAndVersionWithTransaction(connection, urlAndVersion); + } + @Override public Optional readByUrlAndVersion(String url, String version) throws SQLException { diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/BinaryDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/BinaryDaoJdbc.java index 96dc8ae52..f6588250f 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/BinaryDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/BinaryDaoJdbc.java @@ -33,7 +33,7 @@ protected Binary copy(Binary resource) @Override protected Binary getResource(ResultSet result, int index) throws SQLException { - // TODO Bugfix HAPI is removing version information from bundle.id + // TODO Bugfix HAPI is removing version information from binary.id Binary binary = super.getResource(result, index); IdType fixedId = new IdType(binary.getResourceType().name(), binary.getIdElement().getIdPart(), binary.getMeta().getVersionId()); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/CodeSystemDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/CodeSystemDaoJdbc.java index d6b78552d..62b7a46df 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/CodeSystemDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/CodeSystemDaoJdbc.java @@ -27,7 +27,7 @@ public CodeSystemDaoJdbc(BasicDataSource dataSource, FhirContext fhirContext) with()); readByUrl = new ReadByUrlDaoJdbc<>(this::getDataSource, this::getResource, getResourceTable(), - getResourceColumn(), getResourceIdColumn()); + getResourceColumn()); } @Override @@ -42,6 +42,13 @@ public Optional readByUrlAndVersion(String urlAndVersion) throws SQL return readByUrl.readByUrlAndVersion(urlAndVersion); } + @Override + public Optional readByUrlAndVersionWithTransaction(Connection connection, String urlAndVersion) + throws SQLException + { + return readByUrl.readByUrlAndVersionWithTransaction(connection, urlAndVersion); + } + @Override public Optional readByUrlAndVersion(String url, String version) throws SQLException { diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/EndpointDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/EndpointDaoJdbc.java index 96ba71015..2e9ce32a5 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/EndpointDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/EndpointDaoJdbc.java @@ -45,9 +45,8 @@ public boolean existsActiveNotDeletedByAddress(String address) throws SQLExcepti return false; try (Connection connection = getDataSource().getConnection(); - PreparedStatement statement = connection.prepareStatement("SELECT count(*) FROM " + getResourceTable() - + " WHERE " + getResourceColumn() + "->>'address' = ? AND " + getResourceColumn() - + "->>'status' = 'active' AND NOT deleted")) + PreparedStatement statement = connection.prepareStatement( + "SELECT count(*) FROM current_endpoints WHERE endpoint->>'address' = ? AND endpoint->>'status' = 'active'")) { statement.setString(1, address); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/HistroyDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/HistroyDaoJdbc.java new file mode 100644 index 000000000..f0ac4084b --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/HistroyDaoJdbc.java @@ -0,0 +1,271 @@ +package org.highmed.dsf.fhir.dao.jdbc; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.sql.DataSource; + +import org.highmed.dsf.fhir.dao.HistoryDao; +import org.highmed.dsf.fhir.history.AtParameter; +import org.highmed.dsf.fhir.history.History; +import org.highmed.dsf.fhir.history.HistoryEntry; +import org.highmed.dsf.fhir.history.SinceParameter; +import org.highmed.dsf.fhir.history.user.HistoryUserFilter; +import org.highmed.dsf.fhir.search.PageAndCount; +import org.highmed.dsf.fhir.search.SearchQueryParameter; +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.DomainResource; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Resource; +import org.postgresql.util.PGobject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.annotation.ResourceDef; +import ca.uhn.fhir.parser.DataFormatException; +import ca.uhn.fhir.parser.IParser; + +public class HistroyDaoJdbc implements HistoryDao, InitializingBean +{ + private static final Logger logger = LoggerFactory.getLogger(HistroyDaoJdbc.class); + + private final DataSource dataSource; + private final FhirContext fhirContext; + private final BinaryDaoJdbc binaryDao; + + public HistroyDaoJdbc(DataSource dataSource, FhirContext fhirContext, BinaryDaoJdbc binaryDao) + { + this.dataSource = dataSource; + this.fhirContext = fhirContext; + this.binaryDao = binaryDao; + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(dataSource, "dataSource"); + Objects.requireNonNull(fhirContext, "fhirContext"); + Objects.requireNonNull(binaryDao, "binaryDao"); + } + + @Override + public History readHistory(List filters, PageAndCount pageAndCount, AtParameter atParameter, + SinceParameter sinceParameter) throws SQLException + { + Objects.requireNonNull(filters, "filters"); + Objects.requireNonNull(pageAndCount, "pageAndCount"); + Objects.requireNonNull(atParameter, "atParameter"); + Objects.requireNonNull(sinceParameter, "sinceParameter"); + + return readHistory(filters, pageAndCount, atParameter, sinceParameter, null, null); + } + + @Override + public History readHistory(HistoryUserFilter filter, PageAndCount pageAndCount, AtParameter atParameter, + SinceParameter sinceParameter, Class resource) throws SQLException + { + Objects.requireNonNull(filter, "filter"); + Objects.requireNonNull(pageAndCount, "pageAndCount"); + Objects.requireNonNull(atParameter, "atParameter"); + Objects.requireNonNull(sinceParameter, "sinceParameter"); + Objects.requireNonNull(resource, "resource"); + + return readHistory(Collections.singletonList(filter), pageAndCount, atParameter, sinceParameter, resource, + null); + } + + @Override + public History readHistory(HistoryUserFilter filter, PageAndCount pageAndCount, AtParameter atParameter, + SinceParameter sinceParameter, Class resource, UUID id) throws SQLException + { + Objects.requireNonNull(filter, "filter"); + Objects.requireNonNull(pageAndCount, "pageAndCount"); + Objects.requireNonNull(atParameter, "atParameter"); + Objects.requireNonNull(sinceParameter, "sinceParameter"); + Objects.requireNonNull(resource, "resource"); + Objects.requireNonNull(id, "id"); + + return readHistory(Collections.singletonList(filter), pageAndCount, atParameter, sinceParameter, resource, id); + } + + private History readHistory(List filter, PageAndCount pageAndCount, AtParameter atParameter, + SinceParameter sinceParameter, Class resource, UUID id) throws SQLException + { + try (Connection connection = dataSource.getConnection()) + { + int total = 0; + try (PreparedStatement statement = connection.prepareStatement( + createCountSql(id != null, resource != null, filter, atParameter, sinceParameter))) + { + configureStatement(statement, id, resource, filter, atParameter, sinceParameter); + + logger.trace("Executing count query '{}'", statement); + try (ResultSet result = statement.executeQuery()) + { + if (result.next()) + total = result.getInt(1); + } + } + + List entries = new ArrayList<>(); + if (!pageAndCount.isCountOnly(total)) + { + try (PreparedStatement statement = connection.prepareStatement( + createReadSql(id != null, resource != null, filter, atParameter, sinceParameter, pageAndCount))) + { + configureStatement(statement, id, resource, filter, atParameter, sinceParameter); + + logger.trace("Executing read query '{}'", statement); + try (ResultSet result = statement.executeQuery()) + { + while (result.next()) + { + UUID entryId = result.getObject(1, UUID.class); + long version = result.getLong(2); + String resourceType = result.getString(3); + String method = result.getString(4); + Timestamp lastUpdated = result.getTimestamp(5); + Resource entryResource = jsonToResource(result.getString(6), resource); + modifyResource(entryResource, connection); + + HistoryEntry entry = new HistoryEntry(entryId, String.valueOf(version), resourceType, + method, lastUpdated == null ? null : lastUpdated.toLocalDateTime(), entryResource); + entries.add(entry); + } + + } + } + } + + return new History(total, pageAndCount, entries); + } + } + + private void modifyResource(Resource resource, Connection connection) throws SQLException + { + if (resource instanceof Binary) + binaryDao.modifySearchResultResource((Binary) resource, connection); + } + + private PGobject uuidToPgObject(UUID uuid) + { + if (uuid == null) + return null; + + try + { + PGobject o = new PGobject(); + o.setType("UUID"); + o.setValue(uuid.toString()); + return o; + } + catch (DataFormatException | SQLException e) + { + throw new RuntimeException(e); + } + } + + public IParser getJsonParser() + { + IParser p = fhirContext.newJsonParser(); + p.setStripVersionsFromReferences(false); + return p; + } + + private Resource jsonToResource(String json, Class resourceType) + { + if (json == null) + return null; + + Resource resource; + if (resourceType != null) + resource = getJsonParser().parseResource(resourceType, json); + else + resource = (Resource) getJsonParser().parseResource(json); + + // TODO Bugfix HAPI is not setting version information from bundle.id while parsing non DomainResource + if (!(resource instanceof DomainResource)) + { + IdType fixedId = new IdType(resource.getResourceType().name(), resource.getIdElement().getIdPart(), + resource.getMeta().getVersionId()); + resource.setIdElement(fixedId); + } + + return resource; + } + + private String createCountSql(boolean forId, boolean forResource, List filter, + AtParameter atParameter, SinceParameter sinceParameter) + { + String selectSql = "SELECT count(*) FROM history WHERE "; + + return createSql(forId, forResource, filter, atParameter, sinceParameter, selectSql, ""); + } + + private String createReadSql(boolean forId, boolean forResource, List filter, + AtParameter atParameter, SinceParameter sinceParameter, PageAndCount pageAndCount) + { + String selectSql = "SELECT id, version, type, method, last_updated, resource FROM history WHERE "; + + return createSql(forId, forResource, filter, atParameter, sinceParameter, selectSql, pageAndCount.getSql()); + } + + private String createSql(boolean forId, boolean forResource, List filter, + AtParameter atParameter, SinceParameter sinceParameter, String selectSql, String limitOffsetSql) + { + String idSql = forId ? "id = ?" : null; + String typeSql = forResource ? "type = ?" : null; + String filterSql = filter.stream().filter(HistoryUserFilter::isDefined).map(f -> f.getFilterQuery()) + .collect(Collectors.joining(" OR ", "(", ")")); + filterSql = "()".equals(filterSql) ? null : filterSql; + + Stream params = Stream.of(atParameter, sinceParameter).filter(SearchQueryParameter::isDefined) + .map(SearchQueryParameter::getFilterQuery); + + return Stream.concat(Stream.of(idSql, typeSql, filterSql).filter(s -> s != null), params) + .collect(Collectors.joining(" AND ", selectSql, limitOffsetSql)); + } + + private void configureStatement(PreparedStatement statement, UUID id, Class resource, + List filter, AtParameter atParameter, SinceParameter sinceParameter) throws SQLException + { + int parameterIndex = 1; + if (id != null) + statement.setObject(parameterIndex++, uuidToPgObject(id)); + if (resource != null) + statement.setString(parameterIndex++, resource.getAnnotation(ResourceDef.class).name()); + + for (HistoryUserFilter f : filter) + { + if (f.isDefined()) + { + for (int i = 1; i <= f.getSqlParameterCount(); i++) + f.modifyStatement(parameterIndex++, i, statement); + } + } + + if (atParameter.isDefined()) + { + for (int i = 1; i <= atParameter.getSqlParameterCount(); i++) + atParameter.modifyStatement(parameterIndex++, i, statement, null); + } + + if (sinceParameter.isDefined()) + { + for (int i = 1; i <= sinceParameter.getSqlParameterCount(); i++) + sinceParameter.modifyStatement(parameterIndex++, i, statement, null); + } + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/OrganizationDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/OrganizationDaoJdbc.java index 0749a6958..61b167c16 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/OrganizationDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/OrganizationDaoJdbc.java @@ -157,5 +157,4 @@ public boolean existsNotDeletedByThumbprintWithTransaction(Connection connection } } } - } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactory.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactory.java index 851185e73..45e7ebac6 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactory.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactory.java @@ -3,6 +3,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.time.LocalDateTime; import java.util.UUID; import org.hl7.fhir.r4.model.Resource; @@ -26,7 +27,9 @@ interface PreparedStatementFactory void configureReadByIdStatement(PreparedStatement statement, UUID uuid) throws SQLException; - boolean isReadByIdDeleted(ResultSet result) throws SQLException; + LocalDateTime getReadByIdDeleted(ResultSet result) throws SQLException; + + long getReadByIdVersion(ResultSet result) throws SQLException; R getReadByIdResource(ResultSet result) throws SQLException; @@ -34,6 +37,10 @@ interface PreparedStatementFactory void configureReadByIdAndVersionStatement(PreparedStatement statement, UUID uuid, long version) throws SQLException; + LocalDateTime getReadByIdVersionDeleted(ResultSet result) throws SQLException; + + long getReadByIdVersionVersion(ResultSet result) throws SQLException; + R getReadByIdAndVersionResource(ResultSet result) throws SQLException; String getUpdateNewRowSql(); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactoryBinary.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactoryBinary.java index 485a16de3..bdbfa603d 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactoryBinary.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactoryBinary.java @@ -4,7 +4,9 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Timestamp; import java.sql.Types; +import java.time.LocalDateTime; import java.util.UUID; import org.hl7.fhir.r4.model.Binary; @@ -14,8 +16,8 @@ class PreparedStatementFactoryBinary extends AbstractPreparedStatementFactory { private static final String createSql = "INSERT INTO binaries (binary_id, binary_json, binary_data) VALUES (?, ?, ?)"; - private static final String readByIdSql = "SELECT deleted, binary_json, binary_data FROM binaries WHERE binary_id = ? ORDER BY version DESC LIMIT 1"; - private static final String readByIdAndVersionSql = "SELECT binary_json, binary_data FROM binaries WHERE binary_id = ? AND version = ?"; + private static final String readByIdSql = "SELECT deleted, version, binary_json, binary_data FROM binaries WHERE binary_id = ? ORDER BY version DESC LIMIT 1"; + private static final String readByIdAndVersionSql = "SELECT deleted, version, binary_json, binary_data FROM binaries WHERE binary_id = ? AND (version = ? OR version = ?) ORDER BY version DESC LIMIT 1"; private static final String updateNewRowSql = "INSERT INTO binaries (binary_id, version, binary_json, binary_data) VALUES (?, ?, ?, ?)"; private static final String updateSameRowSql = "UPDATE binaries SET binary_json = ?, binary_data = ? WHERE binary_id = ? AND version = ?"; @@ -49,16 +51,23 @@ public void configureReadByIdStatement(PreparedStatement statement, UUID uuid) t } @Override - public boolean isReadByIdDeleted(ResultSet result) throws SQLException + public LocalDateTime getReadByIdDeleted(ResultSet result) throws SQLException { - return result.getBoolean(1); + Timestamp deleted = result.getTimestamp(1); + return deleted == null ? null : deleted.toLocalDateTime(); + } + + @Override + public long getReadByIdVersion(ResultSet result) throws SQLException + { + return result.getLong(2); } @Override public Binary getReadByIdResource(ResultSet result) throws SQLException { - String json = result.getString(2); - byte[] data = result.getBytes(3); + String json = result.getString(3); + byte[] data = result.getBytes(4); return jsonToResource(json).setData(data); } @@ -69,13 +78,27 @@ public void configureReadByIdAndVersionStatement(PreparedStatement statement, UU { statement.setObject(1, uuidToPgObject(uuid)); statement.setLong(2, version); + statement.setLong(3, version - 1); + } + + @Override + public LocalDateTime getReadByIdVersionDeleted(ResultSet result) throws SQLException + { + Timestamp deleted = result.getTimestamp(1); + return deleted == null ? null : deleted.toLocalDateTime(); + } + + @Override + public long getReadByIdVersionVersion(ResultSet result) throws SQLException + { + return result.getLong(2); } @Override public Binary getReadByIdAndVersionResource(ResultSet result) throws SQLException { - String json = result.getString(1); - byte[] data = result.getBytes(2); + String json = result.getString(3); + byte[] data = result.getBytes(4); return jsonToResource(json).setData(data); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactoryDefault.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactoryDefault.java index c48e34532..e46adc930 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactoryDefault.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/PreparedStatementFactoryDefault.java @@ -3,6 +3,8 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Timestamp; +import java.time.LocalDateTime; import java.util.UUID; import org.hl7.fhir.r4.model.Resource; @@ -28,14 +30,14 @@ private static String createSql(String resourceTable, String resourceIdColumn, S private static String readByIdSql(String resourceTable, String resourceIdColumn, String resourceColumn) { - return "SELECT deleted, " + resourceColumn + " FROM " + resourceTable + " WHERE " + resourceIdColumn + return "SELECT deleted, version, " + resourceColumn + " FROM " + resourceTable + " WHERE " + resourceIdColumn + " = ? ORDER BY version DESC LIMIT 1"; } private static String readByIdAndVersionSql(String resourceTable, String resourceIdColumn, String resourceColumn) { - return "SELECT " + resourceColumn + " FROM " + resourceTable + " WHERE " + resourceIdColumn - + " = ? AND version = ?"; + return "SELECT deleted, version," + resourceColumn + " FROM " + resourceTable + " WHERE " + resourceIdColumn + + " = ? AND (version = ? OR version = ?) ORDER BY version DESC LIMIT 1"; } private static String updateNewRowSql(String resourceTable, String resourceIdColumn, String resourceColumn) @@ -64,15 +66,22 @@ public void configureReadByIdStatement(PreparedStatement statement, UUID uuid) t } @Override - public boolean isReadByIdDeleted(ResultSet result) throws SQLException + public LocalDateTime getReadByIdDeleted(ResultSet result) throws SQLException { - return result.getBoolean(1); + Timestamp deleted = result.getTimestamp(1); + return deleted == null ? null : deleted.toLocalDateTime(); + } + + @Override + public long getReadByIdVersion(ResultSet result) throws SQLException + { + return result.getLong(2); } @Override public R getReadByIdResource(ResultSet result) throws SQLException { - String json = result.getString(2); + String json = result.getString(3); return jsonToResource(json); } @@ -83,12 +92,26 @@ public void configureReadByIdAndVersionStatement(PreparedStatement statement, UU { statement.setObject(1, uuidToPgObject(uuid)); statement.setLong(2, version); + statement.setLong(3, version - 1); + } + + @Override + public LocalDateTime getReadByIdVersionDeleted(ResultSet result) throws SQLException + { + Timestamp deleted = result.getTimestamp(1); + return deleted == null ? null : deleted.toLocalDateTime(); + } + + @Override + public long getReadByIdVersionVersion(ResultSet result) throws SQLException + { + return result.getLong(2); } @Override public R getReadByIdAndVersionResource(ResultSet result) throws SQLException { - String json = result.getString(1); + String json = result.getString(3); return jsonToResource(json); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ReadByUrlDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ReadByUrlDaoJdbc.java index ae06e9e6d..d3a4b1110 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ReadByUrlDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ReadByUrlDaoJdbc.java @@ -24,17 +24,15 @@ class ReadByUrlDaoJdbc private final String resourceTable; private final String resourceColumn; - private final String resourceIdColumn; ReadByUrlDaoJdbc(Supplier dataSourceSupplier, BiFunctionWithSqlException resourceExtractor, String resourceTable, - String resourceColumn, String resourceIdColumn) + String resourceColumn) { this.dataSourceSupplier = dataSourceSupplier; this.resourceExtractor = resourceExtractor; this.resourceTable = resourceTable; this.resourceColumn = resourceColumn; - this.resourceIdColumn = resourceIdColumn; } /** @@ -45,6 +43,24 @@ class ReadByUrlDaoJdbc */ Optional readByUrlAndVersion(String urlAndVersion) throws SQLException { + try (Connection connection = dataSourceSupplier.get().getConnection()) + { + return readByUrlAndVersionWithTransaction(connection, urlAndVersion); + } + } + + /** + * @param connection + * not null + * @param urlAndVersion + * not null, url|version + * @return {@link Optional#empty()} if param urlAndVersion is null or {@link String#isBlank()} + * @throws SQLException + */ + public Optional readByUrlAndVersionWithTransaction(Connection connection, String urlAndVersion) + throws SQLException + { + Objects.requireNonNull(connection, "connection"); if (urlAndVersion == null || urlAndVersion.isBlank()) return Optional.empty(); @@ -52,7 +68,7 @@ Optional readByUrlAndVersion(String urlAndVersion) throws SQLException if (split.length < 1 || split.length > 2) return Optional.empty(); - return readByUrlAndVersion(split[0], split.length == 2 ? split[1] : null); + return readByUrlAndVersionWithTransaction(connection, split[0], split.length == 2 ? split[1] : null); } /** @@ -88,15 +104,14 @@ Optional readByUrlAndVersionWithTransaction(Connection connection, String url if (url == null || url.isBlank()) return Optional.empty(); - String versionSql = version == null || version.isBlank() ? ("AND " + resourceColumn + "->>'version' = ? ") : ""; - String sql = "SELECT DISTINCT ON(" + resourceIdColumn + ") " + resourceColumn + " FROM " + resourceTable - + " WHERE NOT deleted AND " + resourceColumn + "->>'url' = ? " + versionSql + "ORDER BY " - + resourceIdColumn + ", version LIMIT 1"; + String versionSql = version != null && !version.isBlank() ? "AND " + resourceColumn + "->>'version' = ? " : ""; + String sql = "SELECT " + resourceColumn + " FROM current_" + resourceTable + " WHERE " + resourceColumn + + "->>'url' = ? " + versionSql; try (PreparedStatement statement = connection.prepareStatement(sql)) { statement.setString(1, url); - if (version == null || version.isBlank()) + if (version != null && !version.isBlank()) statement.setString(2, version); logger.trace("Executing query '{}'", statement); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/StructureDefinitionDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/StructureDefinitionDaoJdbc.java index b3db5b0ba..0b2ca2461 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/StructureDefinitionDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/StructureDefinitionDaoJdbc.java @@ -1,13 +1,12 @@ package org.highmed.dsf.fhir.dao.jdbc; import org.apache.commons.dbcp2.BasicDataSource; -import org.highmed.dsf.fhir.dao.StructureDefinitionDao; import org.highmed.dsf.fhir.search.parameters.user.StructureDefinitionUserFilter; import org.hl7.fhir.r4.model.StructureDefinition; import ca.uhn.fhir.context.FhirContext; -public class StructureDefinitionDaoJdbc extends AbstractStructureDefinitionDaoJdbc implements StructureDefinitionDao +public class StructureDefinitionDaoJdbc extends AbstractStructureDefinitionDaoJdbc { public StructureDefinitionDaoJdbc(BasicDataSource dataSource, FhirContext fhirContext) { diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/StructureDefinitionSnapshotDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/StructureDefinitionSnapshotDaoJdbc.java index 7492c5482..8d388a038 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/StructureDefinitionSnapshotDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/StructureDefinitionSnapshotDaoJdbc.java @@ -1,47 +1,17 @@ package org.highmed.dsf.fhir.dao.jdbc; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.Date; -import java.util.Objects; -import java.util.UUID; - import org.apache.commons.dbcp2.BasicDataSource; -import org.highmed.dsf.fhir.dao.StructureDefinitionSnapshotDao; -import org.highmed.dsf.fhir.dao.converter.SnapshotInfoConverter; -import org.highmed.dsf.fhir.dao.exception.ResourceNotFoundException; import org.highmed.dsf.fhir.search.parameters.user.StructureDefinitionSnapshotUserFilter; -import org.highmed.dsf.fhir.service.SnapshotInfo; -import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.StructureDefinition; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import ca.uhn.fhir.context.FhirContext; public class StructureDefinitionSnapshotDaoJdbc extends AbstractStructureDefinitionDaoJdbc - implements StructureDefinitionSnapshotDao { - private static final Logger logger = LoggerFactory.getLogger(StructureDefinitionSnapshotDaoJdbc.class); - - private final SnapshotInfoConverter converter; - - public StructureDefinitionSnapshotDaoJdbc(BasicDataSource dataSource, FhirContext fhirContext, - SnapshotInfoConverter converter) + public StructureDefinitionSnapshotDaoJdbc(BasicDataSource dataSource, FhirContext fhirContext) { super(dataSource, fhirContext, "structure_definition_snapshots", "structure_definition_snapshot", "structure_definition_snapshot_id", StructureDefinitionSnapshotUserFilter::new); - - this.converter = converter; - } - - @Override - public void afterPropertiesSet() throws Exception - { - super.afterPropertiesSet(); - - Objects.requireNonNull(converter, "converter"); } @Override @@ -49,164 +19,4 @@ protected StructureDefinition copy(StructureDefinition resource) { return resource.copy(); } - - @Override - public StructureDefinition create(UUID uuid, StructureDefinition resource, SnapshotInfo info) throws SQLException - { - Objects.requireNonNull(uuid, "uuid"); - Objects.requireNonNull(resource, "resource"); - Objects.requireNonNull(info, "info"); - - try (Connection connection = getDataSource().getConnection()) - { - connection.setReadOnly(false); - - StructureDefinition inserted = createWithTransaction(connection, uuid, resource, info); - - logger.debug("{} with ID {} created", getResourceTypeName(), inserted.getId()); - return inserted; - } - } - - @Override - public StructureDefinition createWithTransaction(Connection connection, UUID uuid, StructureDefinition resource, - SnapshotInfo info) throws SQLException - { - Objects.requireNonNull(connection, "connection"); - Objects.requireNonNull(uuid, "uuid"); - Objects.requireNonNull(resource, "resource"); - Objects.requireNonNull(info, "info"); - - resource = copy(resource); - resource.setIdElement(new IdType(getResourceTypeName(), uuid.toString(), "1")); - resource.getMeta().setVersionId("1"); - resource.getMeta().setLastUpdated(new Date()); - - // db version set by default value - try (PreparedStatement statement = connection - .prepareStatement("INSERT INTO " + getResourceTable() + " (" + getResourceIdColumn() + ", " - + getResourceColumn() + ", structure_definition_snapshot_info) VALUES (?, ?, ?)")) - { - statement.setObject(1, getPreparedStatementFactory().uuidToPgObject(uuid)); - statement.setObject(2, getPreparedStatementFactory().resourceToPgObject(resource)); - statement.setObject(3, converter.toDb(info)); - - logger.trace("Executing query '{}'", statement); - statement.execute(); - } - - return resource; - } - - @Override - public StructureDefinition update(StructureDefinition resource, SnapshotInfo info) - throws SQLException, ResourceNotFoundException - { - Objects.requireNonNull(resource, "resource"); - Objects.requireNonNull(info, "info"); - - try (Connection connection = getDataSource().getConnection()) - { - connection.setReadOnly(false); - connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); - connection.setAutoCommit(false); - - try - { - StructureDefinition updated = updateWithTransaction(connection, resource, info); - - connection.commit(); - - return updated; - } - catch (Exception e) - { - connection.rollback(); - throw e; - } - } - } - - @Override - public StructureDefinition updateWithTransaction(Connection connection, StructureDefinition resource, - SnapshotInfo info) throws SQLException, ResourceNotFoundException - { - Objects.requireNonNull(resource, "resource"); - Objects.requireNonNull(info, "info"); - - LatestVersion latestVersion = getLatestVersionIfExists(resource, connection) - .orElse(new LatestVersion(0, false)); - long newVersion = latestVersion.version + 1; - - StructureDefinition updated = update(connection, resource, info, newVersion); - if (latestVersion.deleted) - markDeleted(connection, toUuid(updated.getIdElement().getIdPart()), false); - - logger.debug("{} with IdPart {} updated, new version {}.", getResourceTypeName(), - updated.getIdElement().getIdPart(), newVersion); - return updated; - } - - private StructureDefinition update(Connection connection, StructureDefinition resource, SnapshotInfo info, - long newVersion) throws SQLException - { - UUID uuid = toUuid(resource.getIdElement().getIdPart()); - if (uuid == null) - throw new IllegalArgumentException("resource.id is not a UUID"); - - String newVersionAsString = String.valueOf(newVersion); - IdType newId = new IdType(getResourceTypeName(), resource.getIdElement().getIdPart(), newVersionAsString); - - resource = copy(resource); - resource.setIdElement(newId); - resource.getMeta().setVersionId(newVersionAsString); - resource.getMeta().setLastUpdated(new Date()); - - try (PreparedStatement statement = connection - .prepareStatement("INSERT INTO " + getResourceTable() + " (" + getResourceIdColumn() + ", version, " - + getResourceColumn() + ", structure_definition_snapshot_info) VALUES (?, ?, ?, ?)")) - { - statement.setObject(1, getPreparedStatementFactory().uuidToPgObject(uuid)); - statement.setLong(2, newVersion); - statement.setObject(3, getPreparedStatementFactory().resourceToPgObject(resource)); - statement.setObject(4, converter.toDb(info)); - - logger.trace("Executing query '{}'", statement); - statement.execute(); - } - - return resource; - } - - @Override - public void deleteAllByDependency(String url) throws SQLException - { - Objects.requireNonNull(url, "url"); - - try (Connection connection = getDataSource().getConnection()) - { - connection.setReadOnly(false); - - deleteAllByDependencyWithTransaction(connection, url); - } - } - - @Override - public void deleteAllByDependencyWithTransaction(Connection connection, String url) throws SQLException - { - Objects.requireNonNull(connection, "connection"); - Objects.requireNonNull(url, "url"); - - try (PreparedStatement statement = connection.prepareStatement("UPDATE " + getResourceTable() - + " SET deleted = TRUE WHERE structure_definition_snapshot_info->'dependencies'->'profiles' ?? ?")) - { - statement.setString(1, url); - - logger.trace("Executing query '{}'", statement); - int count = statement.executeUpdate(); - - logger.debug("{} {} snapshot{} with dependency url {} marked as deleted", count, getResourceTypeName(), - count != 1 ? "s" : "", url); - } - } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/SubscriptionDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/SubscriptionDaoJdbc.java index 6604d846a..ed4b07980 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/SubscriptionDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/SubscriptionDaoJdbc.java @@ -47,11 +47,8 @@ public List readByStatus(org.hl7.fhir.r4.model.Subscription.Subscr return Collections.emptyList(); try (Connection connection = getDataSource().getConnection(); - PreparedStatement statement = connection - .prepareStatement("SELECT " + getResourceColumn() + " FROM (SELECT DISTINCT ON (" - + getResourceIdColumn() + ") " + getResourceColumn() + " FROM " + getResourceTable() - + " WHERE NOT deleted ORDER BY " + getResourceIdColumn() + ", version DESC) AS current_" - + getResourceTable() + " WHERE " + getResourceColumn() + "->>'status' = ?")) + PreparedStatement statement = connection.prepareStatement( + "SELECT subscription FROM current_subscriptions WHERE subscription->>'status' = ?")) { statement.setString(1, status.toCode()); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/TaskDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/TaskDaoJdbc.java index 09aeee935..cfd194aa1 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/TaskDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/TaskDaoJdbc.java @@ -2,7 +2,9 @@ import org.apache.commons.dbcp2.BasicDataSource; import org.highmed.dsf.fhir.dao.TaskDao; +import org.highmed.dsf.fhir.search.parameters.TaskAuthoredOn; import org.highmed.dsf.fhir.search.parameters.TaskIdentifier; +import org.highmed.dsf.fhir.search.parameters.TaskModified; import org.highmed.dsf.fhir.search.parameters.TaskRequester; import org.highmed.dsf.fhir.search.parameters.TaskStatus; import org.highmed.dsf.fhir.search.parameters.user.TaskUserFilter; @@ -15,7 +17,8 @@ public class TaskDaoJdbc extends AbstractResourceDaoJdbc implements TaskDa public TaskDaoJdbc(BasicDataSource dataSource, FhirContext fhirContext) { super(dataSource, fhirContext, Task.class, "tasks", "task", "task_id", TaskUserFilter::new, - with(TaskIdentifier::new, TaskRequester::new, TaskStatus::new), with()); + with(TaskAuthoredOn::new, TaskIdentifier::new, TaskModified::new, TaskRequester::new, TaskStatus::new), + with()); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ValueSetDaoJdbc.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ValueSetDaoJdbc.java index b51fd2800..e35ea1127 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ValueSetDaoJdbc.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/jdbc/ValueSetDaoJdbc.java @@ -26,7 +26,7 @@ public ValueSetDaoJdbc(BasicDataSource dataSource, FhirContext fhirContext) with(ValueSetIdentifier::new, ValueSetStatus::new, ValueSetUrl::new, ValueSetVersion::new), with()); readByUrl = new ReadByUrlDaoJdbc<>(this::getDataSource, this::getResource, getResourceTable(), - getResourceColumn(), getResourceIdColumn()); + getResourceColumn()); } @Override @@ -41,6 +41,13 @@ public Optional readByUrlAndVersion(String urlAndVersion) throws SQLEx return readByUrl.readByUrlAndVersion(urlAndVersion); } + @Override + public Optional readByUrlAndVersionWithTransaction(Connection connection, String urlAndVersion) + throws SQLException + { + return readByUrl.readByUrlAndVersionWithTransaction(connection, urlAndVersion); + } + @Override public Optional readByUrlAndVersion(String url, String version) throws SQLException { diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/provider/DaoProvider.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/provider/DaoProvider.java index 1fd482577..e857e6fc9 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/provider/DaoProvider.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/provider/DaoProvider.java @@ -21,7 +21,6 @@ import org.highmed.dsf.fhir.dao.ResearchStudyDao; import org.highmed.dsf.fhir.dao.ResourceDao; import org.highmed.dsf.fhir.dao.StructureDefinitionDao; -import org.highmed.dsf.fhir.dao.StructureDefinitionSnapshotDao; import org.highmed.dsf.fhir.dao.SubscriptionDao; import org.highmed.dsf.fhir.dao.TaskDao; import org.highmed.dsf.fhir.dao.ValueSetDao; @@ -65,7 +64,7 @@ public interface DaoProvider StructureDefinitionDao getStructureDefinitionDao(); - StructureDefinitionSnapshotDao getStructureDefinitionSnapshotDao(); + StructureDefinitionDao getStructureDefinitionSnapshotDao(); SubscriptionDao getSubscriptionDao(); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/provider/DaoProviderImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/provider/DaoProviderImpl.java index 2d20adce6..669926df1 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/provider/DaoProviderImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/dao/provider/DaoProviderImpl.java @@ -26,7 +26,6 @@ import org.highmed.dsf.fhir.dao.ResearchStudyDao; import org.highmed.dsf.fhir.dao.ResourceDao; import org.highmed.dsf.fhir.dao.StructureDefinitionDao; -import org.highmed.dsf.fhir.dao.StructureDefinitionSnapshotDao; import org.highmed.dsf.fhir.dao.SubscriptionDao; import org.highmed.dsf.fhir.dao.TaskDao; import org.highmed.dsf.fhir.dao.ValueSetDao; @@ -73,7 +72,7 @@ public class DaoProviderImpl implements DaoProvider, InitializingBean private final ProvenanceDao provenanceDao; private final ResearchStudyDao researchStudyDao; private final StructureDefinitionDao structureDefinitionDao; - private final StructureDefinitionSnapshotDao structureDefinitionSnapshotDao; + private final StructureDefinitionDao structureDefinitionSnapshotDao; private final SubscriptionDao subscriptionDao; private final TaskDao taskDao; private final ValueSetDao valueSetDao; @@ -86,9 +85,8 @@ public DaoProviderImpl(DataSource dataSource, ActivityDefinitionDao activityDefi HealthcareServiceDao healthcareServiceDao, LocationDao locationDao, NamingSystemDao namingSystemDao, OrganizationDao organizationDao, PatientDao patientDao, PractitionerDao practitionerDao, PractitionerRoleDao practitionerRoleDao, ProvenanceDao provenanceDao, ResearchStudyDao researchStudyDao, - StructureDefinitionDao structureDefinitionDao, - StructureDefinitionSnapshotDao structureDefinitionSnapshotDao, SubscriptionDao subscriptionDao, - TaskDao taskDao, ValueSetDao valueSetDao) + StructureDefinitionDao structureDefinitionDao, StructureDefinitionDao structureDefinitionSnapshotDao, + SubscriptionDao subscriptionDao, TaskDao taskDao, ValueSetDao valueSetDao) { this.dataSource = dataSource; this.activityDefinitionDao = activityDefinitionDao; @@ -279,7 +277,7 @@ public StructureDefinitionDao getStructureDefinitionDao() } @Override - public StructureDefinitionSnapshotDao getStructureDefinitionSnapshotDao() + public StructureDefinitionDao getStructureDefinitionSnapshotDao() { return structureDefinitionSnapshotDao; } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventHandler.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventHandler.java new file mode 100644 index 000000000..e321bfe79 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventHandler.java @@ -0,0 +1,13 @@ +package org.highmed.dsf.fhir.event; + +import java.util.List; + +public interface EventHandler +{ + void handleEvent(Event event); + + default void handleEvents(List events) + { + events.stream().forEach(this::handleEvent); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventManager.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventManager.java old mode 100755 new mode 100644 index c476c735c..876f331d2 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventManager.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventManager.java @@ -1,18 +1,17 @@ package org.highmed.dsf.fhir.event; -import java.util.List; - -import javax.websocket.RemoteEndpoint.Async; - -import org.highmed.dsf.fhir.authentication.User; - -public interface EventManager +public interface EventManager extends EventHandler { - void handleEvent(Event event); - - void handleEvents(List events); - - void bind(User user, String sessionId, Async asyncRemote, String subscriptionIdPart); + /** + * @param eventHandler + * not null + * @return handler remover, calls {@link EventManager#removeHandler(EventHandler)} + */ + Runnable addHandler(EventHandler eventHandler); - void close(String sessionId); + /** + * @param eventHandler + * not null + */ + void removeHandler(EventHandler eventHandler); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventManagerImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventManagerImpl.java old mode 100755 new mode 100644 index 764087987..7500756fd --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventManagerImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/EventManagerImpl.java @@ -1,391 +1,83 @@ package org.highmed.dsf.fhir.event; -import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Function; -import java.util.stream.Collectors; +import java.util.function.Consumer; -import javax.websocket.RemoteEndpoint.Async; - -import org.highmed.dsf.fhir.authentication.User; -import org.highmed.dsf.fhir.authorization.AuthorizationRule; -import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; -import org.highmed.dsf.fhir.dao.SubscriptionDao; -import org.highmed.dsf.fhir.dao.provider.DaoProvider; -import org.highmed.dsf.fhir.help.ExceptionHandler; -import org.highmed.dsf.fhir.search.Matcher; -import org.hl7.fhir.r4.model.Resource; -import org.hl7.fhir.r4.model.Subscription; -import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.model.api.annotation.ResourceDef; -import ca.uhn.fhir.parser.IParser; -import ca.uhn.fhir.rest.api.Constants; -public class EventManagerImpl implements EventManager, InitializingBean, DisposableBean +public class EventManagerImpl implements EventManager { private static final Logger logger = LoggerFactory.getLogger(EventManagerImpl.class); - private static class SubscriptionAndMatcher - { - final Subscription subscription; - final Matcher matcher; - - SubscriptionAndMatcher(Subscription subscription, Matcher matcher) - { - this.subscription = subscription; - this.matcher = matcher; - } - - boolean matches(Resource resource, DaoProvider daoProvider) - { - try - { - matcher.resloveReferencesForMatching(resource, daoProvider); - } - catch (SQLException e) - { - throw new RuntimeException(e); - } + private final List eventHandlers = Collections.synchronizedList(new ArrayList<>()); - return matcher.matches(resource); - } - } - - private static class SessionIdAndRemoteAsync + public EventManagerImpl(Collection eventHandlers) { - final User user; - final String sessionId; - final Async remoteAsync; - - SessionIdAndRemoteAsync(User user, String sessionId, Async remoteAsync) - { - this.user = user; - this.sessionId = sessionId; - this.remoteAsync = remoteAsync; - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((sessionId == null) ? 0 : sessionId.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - SessionIdAndRemoteAsync other = (SessionIdAndRemoteAsync) obj; - if (sessionId == null) - { - if (other.sessionId != null) - return false; - } - else if (!sessionId.equals(other.sessionId)) - return false; - return true; - } - } - - private final ExecutorService executor = Executors.newCachedThreadPool(); - - private final DaoProvider daoProvider; - private final SubscriptionDao subscriptionDao; - private final ExceptionHandler exceptionHandler; - private final MatcherFactory matcherFactory; - private final FhirContext fhirContext; - private final AuthorizationRuleProvider authorizationRuleProvider; - - private final AtomicBoolean firstCall = new AtomicBoolean(true); - private final ReadWriteMap subscriptionsByIdPart = new ReadWriteMap<>(); - private final ReadWriteMap, List> matchersByResource = new ReadWriteMap<>(); - private final ReadWriteMap> asyncRemotesBySubscriptionIdPart = new ReadWriteMap<>(); - - public EventManagerImpl(DaoProvider daoProvider, ExceptionHandler exceptionHandler, MatcherFactory matcherFactory, - FhirContext fhirContext, AuthorizationRuleProvider authorizationRuleProvider) - { - this.daoProvider = daoProvider; - this.subscriptionDao = daoProvider.getSubscriptionDao(); - this.exceptionHandler = exceptionHandler; - this.matcherFactory = matcherFactory; - this.fhirContext = fhirContext; - this.authorizationRuleProvider = authorizationRuleProvider; + if (eventHandlers != null) + this.eventHandlers.addAll(eventHandlers); } @Override - public void afterPropertiesSet() throws Exception + public void handleEvent(Event event) { - Objects.requireNonNull(daoProvider, "daoProvider"); - Objects.requireNonNull(subscriptionDao, "subscriptionDao"); - Objects.requireNonNull(exceptionHandler, "exceptionHandler"); - Objects.requireNonNull(matcherFactory, "matcherFactory"); - Objects.requireNonNull(fhirContext, "fhirContext"); - Objects.requireNonNull(authorizationRuleProvider, "authorizationRuleProvider"); + if (event != null) + eventHandlers.forEach(doHandleEvent(event)); } - private void refreshMatchers() + private Consumer doHandleEvent(Event event) { - logger.info("Refreshing subscriptions"); - firstCall.set(false); - - try + return e -> { - List subscriptions = subscriptionDao.readByStatus(SubscriptionStatus.ACTIVE); - Map, List> matchers = new HashMap<>(); - for (Subscription subscription : subscriptions) + try { - Optional matcher = matcherFactory.createMatcher(subscription.getCriteria()); - if (matcher.isPresent()) - { - if (matchers.containsKey(matcher.get().getResourceType())) - { - matchers.get(matcher.get().getResourceType()) - .add(new SubscriptionAndMatcher(subscription, matcher.get())); - } - else - { - matchers.put(matcher.get().getResourceType(), new ArrayList<>( - Collections.singletonList(new SubscriptionAndMatcher(subscription, matcher.get())))); - } - } + e.handleEvent(event); } - matchersByResource.replaceAll(matchers); - subscriptionsByIdPart.replaceAll(subscriptions.stream() - .collect(Collectors.toMap(s -> s.getIdElement().getIdPart(), Function.identity()))); - - logger.debug("Current active subscription-ids (after refreshing): {}", subscriptionsByIdPart.getAllKeys()); - } - catch (SQLException e) - { - logger.error("Error while accessing DB", e); - } - } - - @Override - public void destroy() throws Exception - { - executor.shutdown(); - try - { - if (!executor.awaitTermination(60, TimeUnit.SECONDS)) + catch (Exception ex) { - executor.shutdownNow(); - if (!executor.awaitTermination(60, TimeUnit.SECONDS)) - logger.warn("EventManager executor did not terminate"); + logger.warn("Error while handling {} with {}", event.getClass().getSimpleName(), + e.getClass().getName()); } - } - catch (InterruptedException ie) - { - executor.shutdownNow(); - Thread.currentThread().interrupt(); - } + }; } @Override public void handleEvents(List events) { - executor.execute(() -> doHandleEventsAndRefreshMatchers(events)); + if (events != null) + eventHandlers.forEach(doHandleEvents(events)); } - private void doHandleEventsAndRefreshMatchers(List events) - { - if (events.stream().anyMatch(e -> e.getResource() instanceof Subscription || firstCall.get())) - refreshMatchers(); - - events.stream().forEach(this::doHandleEvent); - } - - @Override - public void handleEvent(Event event) + private Consumer doHandleEvents(List events) { - executor.execute(() -> doHandleEventAndRefreshMatchers(event)); - } - - private void doHandleEventAndRefreshMatchers(Event event) - { - if (event.getResource() instanceof Subscription || firstCall.get()) - refreshMatchers(); - - doHandleEvent(event); - } - - private void doHandleEvent(Event event) - { - logger.debug("handling event {} for resource of type {} with id {}", event.getClass().getName(), - event.getResourceType().getAnnotation(ResourceDef.class).name(), event.getId()); - - Optional> optMatchers = matchersByResource.get(event.getResourceType()); - if (optMatchers.isEmpty()) - { - logger.debug("No subscriptions for event {} for resource of type {} with id {}", event.getClass().getName(), - event.getResourceType().getAnnotation(ResourceDef.class).name(), event.getId()); - return; - } - - List matchingSubscriptions = optMatchers.get().stream() - .filter(sAndM -> sAndM.matches(event.getResource(), daoProvider)).collect(Collectors.toList()); - - if (matchingSubscriptions.isEmpty()) - { - logger.debug("No matching subscriptions for event {} for resource of type {} with id {}", - event.getClass().getName(), event.getResourceType().getAnnotation(ResourceDef.class).name(), - event.getId()); - return; - } - - matchingSubscriptions.forEach(sAndM -> doHandleEventWithSubscription(sAndM.subscription, event)); - } - - private void doHandleEventWithSubscription(Subscription s, Event event) - { - Optional> optRemotes = asyncRemotesBySubscriptionIdPart - .get(s.getIdElement().getIdPart()); - - if (optRemotes.isEmpty()) - { - logger.debug("No remotes connected to subscription with id {}", s.getIdElement().getIdPart()); - return; - } - - final String text; - if (Constants.CT_FHIR_JSON_NEW.equals(s.getChannel().getPayload())) - text = newJsonParser().encodeResourceToString(event.getResource()); - else if (Constants.CT_FHIR_XML_NEW.contentEquals(s.getChannel().getPayload())) - text = newXmlParser().encodeResourceToString(event.getResource()); - else - text = "ping " + s.getIdElement().getIdPart(); - - logger.debug("Calling {} remote{} connected to subscription with id {}", optRemotes.get().size(), - optRemotes.get().size() != 1 ? "s" : "", s.getIdElement().getIdPart()); - - // defensive copy because list could be changed by other threads while we are reading - List remotes = new ArrayList<>(optRemotes.get()); - remotes.stream().filter(r -> userHasReadAccess(r, event)).forEach(r -> send(r, text)); - } - - private IParser newXmlParser() - { - return configureParser(fhirContext.newXmlParser()); - } - - private IParser newJsonParser() - { - return configureParser(fhirContext.newJsonParser()); - } - - private IParser configureParser(IParser p) - { - p.setStripVersionsFromReferences(false); - p.setOverrideResourceIdWithBundleEntryFullUrl(false); - return p; - } - - private boolean userHasReadAccess(SessionIdAndRemoteAsync sessionAndRemote, Event event) - { - Optional> optRule = authorizationRuleProvider - .getAuthorizationRule(event.getResourceType()); - if (optRule.isPresent()) + return e -> { - @SuppressWarnings("unchecked") - AuthorizationRule rule = (AuthorizationRule) optRule.get(); - Optional optReason = rule.reasonReadAllowed(sessionAndRemote.user, event.getResource()); - - if (optReason.isPresent()) + try { - logger.info("Sending event {} to user {}, read of {} allowed {}", event.getClass().getSimpleName(), - sessionAndRemote.user.getName(), event.getResourceType().getSimpleName(), optReason.get()); - return true; + e.handleEvents(events); } - else + catch (Exception ex) { - logger.warn("Skipping event {} for user {}, read of {} not allowed", event.getClass().getSimpleName(), - sessionAndRemote.user.getName(), event.getResourceType().getSimpleName()); - return false; + logger.warn("Error while handling {} event{} with {}", events.size(), events.size() != 1 ? "s" : "", + e.getClass().getName()); } - } - else - { - logger.warn("Skipping event {} for user {}, no authorization rule for resource of type {} found", - event.getClass().getSimpleName(), sessionAndRemote.user.getName(), - event.getResourceType().getSimpleName()); - return false; - } - } - - private void send(SessionIdAndRemoteAsync sessionAndRemote, String text) - { - try - { - sessionAndRemote.remoteAsync.sendText(text); - } - catch (Exception e) - { - logger.warn("Error while sending event to remote with session id {}", sessionAndRemote.sessionId); - } + }; } @Override - public void bind(User user, String sessionId, Async asyncRemote, String subscriptionIdPart) + public Runnable addHandler(EventHandler eventHandler) { - if (firstCall.get()) - refreshMatchers(); + eventHandlers.add(eventHandler); - if (subscriptionsByIdPart.containsKey(subscriptionIdPart)) - { - logger.debug("Binding websocket session {} to subscription {}", sessionId, subscriptionIdPart); - asyncRemotesBySubscriptionIdPart.replace(subscriptionIdPart, list -> - { - if (list == null) - { - List newList = new ArrayList<>(); - newList.add(new SessionIdAndRemoteAsync(user, sessionId, asyncRemote)); - return newList; - } - else - { - list.add(new SessionIdAndRemoteAsync(user, sessionId, asyncRemote)); - return list; - } - }); - asyncRemote.sendText("bound " + subscriptionIdPart); - } - else - { - logger.warn("Could not bind websocket session {} to subscription {}, subscription not found", sessionId, - subscriptionIdPart); - logger.debug("Current active subscription-ids: {}", subscriptionsByIdPart.getAllKeys()); - asyncRemote.sendText("not-found " + subscriptionIdPart); // TODO not part of FHIR specification - } + return () -> removeHandler(eventHandler); } @Override - public void close(String sessionId) + public void removeHandler(EventHandler eventHandler) { - logger.debug("Removing websocket session {}", sessionId); - asyncRemotesBySubscriptionIdPart.removeWhereValueMatches(list -> list.isEmpty(), - list -> list.remove(new SessionIdAndRemoteAsync(null, sessionId, null))); + eventHandlers.remove(eventHandler); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ExceptionHandler.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ExceptionHandler.java index 1fec6e6a6..2e569d570 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ExceptionHandler.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ExceptionHandler.java @@ -1,9 +1,14 @@ package org.highmed.dsf.fhir.help; +import java.net.URI; +import java.net.URISyntaxException; import java.sql.SQLException; +import java.time.ZoneId; +import java.util.Date; import java.util.function.Supplier; import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.EntityTag; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; @@ -18,6 +23,7 @@ import org.highmed.dsf.fhir.function.SupplierWithSqlAndResourceNotFoundAndResouceVersionNoMatchException; import org.highmed.dsf.fhir.function.SupplierWithSqlAndResourceNotFoundException; import org.highmed.dsf.fhir.function.SupplierWithSqlException; +import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.r4.model.OperationOutcome.IssueType; @@ -154,7 +160,7 @@ public WebApplicationException notFound(String resourceTypeName, ResourceNotFoun return new WebApplicationException(Response.status(Status.NOT_FOUND).entity(outcome).build()); } - public T handleSqlAndResourceDeletedException(String resourceTypeName, + public T handleSqlAndResourceDeletedException(String serverBase, String resourceTypeName, SupplierWithSqlAndResourceDeletedException s) { try @@ -163,7 +169,7 @@ public T handleSqlAndResourceDeletedException(String resourceTypeName, } catch (ResourceDeletedException e) { - throw gone(resourceTypeName, e); + throw gone(serverBase, resourceTypeName, e); } catch (SQLException e) { @@ -188,13 +194,29 @@ public T handleSqlAndResourceNotFoundException(String resourceTypeName, } } - public WebApplicationException gone(String resourceTypeName, ResourceDeletedException e) + public WebApplicationException gone(String serverBase, String resourceTypeName, ResourceDeletedException e) { logger.error("{} with id {} is marked as deleted", resourceTypeName, e.getId()); OperationOutcome outcome = responseGenerator.createOutcome(IssueSeverity.ERROR, IssueType.DELETED, "Resource with id " + e.getId() + " is marked as deleted."); - return new WebApplicationException(Response.status(Status.GONE).entity(outcome).build()); + EntityTag tag = new EntityTag(e.getId().getVersionIdPart(), true); + URI location = toUri(serverBase, resourceTypeName, e.getId()); + Date lastModified = Date.from(e.getDeleted().atZone(ZoneId.systemDefault()).toInstant()); + return new WebApplicationException(Response.status(Status.GONE).tag(tag).location(location) + .lastModified(lastModified).entity(outcome).build()); + } + + private URI toUri(String serverBase, String resourceTypeName, IdType id) + { + try + { + return new URI(id.withServerBase(serverBase, resourceTypeName).getValue()); + } + catch (URISyntaxException e) + { + throw new RuntimeException(e); + } } public T catchAndLogSqlExceptionAndIfReturn(SupplierWithSqlException s, Supplier onSqlException) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ParameterConverter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ParameterConverter.java index b414bce09..a8a3a2b70 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ParameterConverter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ParameterConverter.java @@ -20,6 +20,8 @@ import javax.ws.rs.core.UriInfo; import org.highmed.dsf.fhir.adapter.AbstractFhirAdapter; +import org.highmed.dsf.fhir.prefer.PreferHandlingType; +import org.highmed.dsf.fhir.prefer.PreferReturnType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -79,7 +81,16 @@ public Optional toUuid(String id) } } - public MediaType getMediaType(UriInfo uri, HttpHeaders headers) + public MediaType getMediaTypeThrowIfNotSupported(UriInfo uri, HttpHeaders headers) throws WebApplicationException + { + return getMediaTypeIfSupported(uri, headers).orElseThrow(() -> + { + logger.warn("Media type not supported"); + return new WebApplicationException(Status.UNSUPPORTED_MEDIA_TYPE); + }); + } + + public Optional getMediaTypeIfSupported(UriInfo uri, HttpHeaders headers) { String format = uri.getQueryParameters().getFirst("_format"); boolean pretty = "true".equals(uri.getQueryParameters().getFirst("_pretty")); @@ -87,41 +98,39 @@ public MediaType getMediaType(UriInfo uri, HttpHeaders headers) if (format == null || format.isBlank()) return getMediaType(accept, pretty); + else if (XML_FORMATS.contains(format) || JSON_FORMATS.contains(format) || MediaType.TEXT_HTML.equals(format)) return getMediaType(format, pretty); else if (XML_FORMAT.equals(format)) - return mediaType("application", "fhir+xml", pretty); + return Optional.of(mediaType("application", "fhir+xml", pretty)); else if (JSON_FORMAT.equals(format)) - return mediaType("application", "fhir+json", pretty); + return Optional.of(mediaType("application", "fhir+json", pretty)); else if (HTML_FORMAT.equals(format)) - return mediaType("text", "html", pretty); + return Optional.of(mediaType("text", "html", pretty)); else - throw new WebApplicationException(Status.UNSUPPORTED_MEDIA_TYPE); + return Optional.empty(); } - private MediaType getMediaType(String mediaType, boolean pretty) + private Optional getMediaType(String mediaType, boolean pretty) { if (mediaType.contains(MediaType.TEXT_HTML)) - return mediaType("text", "html", pretty); + return Optional.of(mediaType("text", "html", pretty)); else if (mediaType.contains(Constants.CT_FHIR_JSON_NEW)) - return mediaType("application", "fhir+json", pretty); + return Optional.of(mediaType("application", "fhir+json", pretty)); else if (mediaType.contains(Constants.CT_FHIR_JSON)) - return mediaType("application", "json+fhir", pretty); + return Optional.of(mediaType("application", "json+fhir", pretty)); else if (mediaType.contains(MediaType.APPLICATION_JSON)) - return mediaType("application", "json", pretty); + return Optional.of(mediaType("application", "json", pretty)); else if (mediaType.contains(Constants.CT_FHIR_XML_NEW)) - return mediaType("application", "fhir+xml", pretty); + return Optional.of(mediaType("application", "fhir+xml", pretty)); else if (mediaType.contains(Constants.CT_FHIR_XML)) - return mediaType("application", "xml+fhir", pretty); + return Optional.of(mediaType("application", "xml+fhir", pretty)); else if (mediaType.contains(MediaType.APPLICATION_XML)) - return mediaType("application", "xml", pretty); + return Optional.of(mediaType("application", "xml", pretty)); else if (mediaType.contains(MediaType.TEXT_XML)) - return mediaType("text", "xml", pretty); + return Optional.of(mediaType("text", "xml", pretty)); else - { - logger.error("Media type '{}' not supported", mediaType); - throw new WebApplicationException(Status.UNSUPPORTED_MEDIA_TYPE); - } + return Optional.empty(); } private MediaType mediaType(String type, String subtype, boolean pretty) @@ -130,6 +139,28 @@ private MediaType mediaType(String type, String subtype, boolean pretty) !pretty ? null : Map.of(AbstractFhirAdapter.PRETTY, String.valueOf(pretty))); } + public PreferReturnType getPreferReturn(HttpHeaders headers) + { + List preferHeaders = headers.getRequestHeader(Constants.HEADER_PREFER); + + if (preferHeaders == null) + return PreferReturnType.REPRESENTATION; + else + return preferHeaders.stream().map(PreferReturnType::fromString).findFirst() + .orElse(PreferReturnType.REPRESENTATION); + } + + public PreferHandlingType getPreferHandling(HttpHeaders headers) + { + List preferHeaders = headers.getRequestHeader(Constants.HEADER_PREFER); + + if (preferHeaders == null) + return PreferHandlingType.LENIENT; + else + return preferHeaders.stream().map(PreferHandlingType::fromString).findFirst() + .orElse(PreferHandlingType.LENIENT); + } + public Integer getFirstInt(Map> queryParameters, String key) { List listForKey = queryParameters.getOrDefault(key, Collections.emptyList()); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ResponseGenerator.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ResponseGenerator.java index f90b7dd54..9cc471635 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ResponseGenerator.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/help/ResponseGenerator.java @@ -2,9 +2,11 @@ import java.net.URI; import java.nio.charset.StandardCharsets; +import java.time.ZoneId; import java.util.Date; import java.util.List; import java.util.Objects; +import java.util.function.Supplier; import java.util.stream.Collectors; import javax.ws.rs.core.EntityTag; @@ -15,23 +17,32 @@ import javax.ws.rs.core.UriBuilder; import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.history.History; +import org.highmed.dsf.fhir.history.HistoryEntry; +import org.highmed.dsf.fhir.prefer.PreferReturnType; +import org.highmed.dsf.fhir.search.PageAndCount; import org.highmed.dsf.fhir.search.PartialResult; import org.highmed.dsf.fhir.search.SearchQueryParameterError; import org.highmed.dsf.fhir.service.ResourceReference; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.r4.model.Bundle.BundleEntryResponseComponent; import org.hl7.fhir.r4.model.Bundle.BundleType; +import org.hl7.fhir.r4.model.Bundle.HTTPVerb; import org.hl7.fhir.r4.model.Bundle.SearchEntryMode; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity; import org.hl7.fhir.r4.model.OperationOutcome.IssueType; import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.StructureDefinition; import org.hl7.fhir.r4.model.UriType; +import org.hl7.fhir.utilities.validation.ValidationMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.validation.ValidationResult; public class ResponseGenerator { @@ -60,11 +71,32 @@ public OperationOutcome resourceDeleted(String resourceTypeName, String id) } public ResponseBuilder response(Status status, Resource resource, MediaType mediaType) + { + return response(status, resource, mediaType, PreferReturnType.REPRESENTATION, null); + } + + public ResponseBuilder response(Status status, Resource resource, MediaType mediaType, PreferReturnType prefer, + Supplier operationOutcomeCreator) { Objects.requireNonNull(status, "status"); Objects.requireNonNull(resource, "resource"); - ResponseBuilder b = Response.status(status).entity(resource); + ResponseBuilder b = Response.status(status); + + switch (prefer) + { + case REPRESENTATION: + b = b.entity(resource); + break; + case OPERATION_OUTCOME: + b = b.entity(operationOutcomeCreator.get()); + break; + case MINIMAL: + // do nothing, headers only + break; + default: + throw new RuntimeException(PreferReturnType.class.getName() + " value " + prefer + " not supported"); + } if (mediaType != null) b = b.type(mediaType.withCharset(StandardCharsets.UTF_8.displayName())); @@ -79,14 +111,26 @@ public ResponseBuilder response(Status status, Resource resource, MediaType medi return b; } - public BundleEntryComponent toBundleEntryComponent(Resource resource, SearchEntryMode mode) + public OperationOutcome created(URI location, Resource resource) { - BundleEntryComponent entry = new BundleEntryComponent(); - entry.getSearch().setMode(mode); - entry.setResource(resource); - entry.setFullUrlElement(new IdType(serverBase, resource.getIdElement().getResourceType(), - resource.getIdElement().getIdPart(), null)); - return entry; + return created(location.toString(), resource); + } + + public OperationOutcome created(String location, Resource resource) + { + String message = String.format("%s created at location %s", resource.getResourceType().name(), location); + return createOutcome(IssueSeverity.INFORMATION, IssueType.INFORMATIONAL, message); + } + + public OperationOutcome updated(URI location, Resource resource) + { + return updated(location.toString(), resource); + } + + public OperationOutcome updated(String location, Resource resource) + { + String message = String.format("%s updated at location %s", resource.getResourceType().name(), location); + return createOutcome(IssueSeverity.INFORMATION, IssueType.INFORMATIONAL, message); } /** @@ -113,57 +157,141 @@ public Bundle createSearchSet(PartialResult result, List toBundleEntryComponent(r, SearchEntryMode.INCLUDE)) .forEach(bundle::addEntry); if (!errors.isEmpty()) - bundle.addEntry(toBundleEntryComponent(toOperationOutcome(errors), SearchEntryMode.OUTCOME)); + bundle.addEntry(toBundleEntryComponent(toOperationOutcomeWarning(errors), SearchEntryMode.OUTCOME)); + + bundle.setTotal(result.getTotal()); + + setLinks(result.getPageAndCount(), bundleUri, format, pretty, bundle, result.getPartialResult().isEmpty(), + result.getTotal()); - bundle.setTotal(result.getOverallCount()); + return bundle; + } + public BundleEntryComponent toBundleEntryComponent(Resource resource, SearchEntryMode mode) + { + BundleEntryComponent entry = new BundleEntryComponent(); + entry.getSearch().setMode(mode); + entry.setResource(resource); + entry.setFullUrlElement(new IdType(serverBase, resource.getIdElement().getResourceType(), + resource.getIdElement().getIdPart(), null)); + return entry; + } + + public Bundle createHistoryBundle(History history, List errors, UriBuilder bundleUri, + String format, String pretty) + { + Bundle bundle = new Bundle(); + bundle.setTimestamp(new Date()); + bundle.setType(BundleType.HISTORY); + history.getEntries().stream().map(e -> toBundleEntryComponent(e)).forEach(bundle::addEntry); + + if (!errors.isEmpty()) + bundle.addEntry(toBundleEntryComponent(toOperationOutcomeWarning(errors), SearchEntryMode.OUTCOME)); + + bundle.setTotal(history.getTotal()); + + setLinks(history.getPageAndCount(), bundleUri, format, pretty, bundle, history.getEntries().isEmpty(), + history.getTotal()); + + return bundle; + } + + public BundleEntryComponent toBundleEntryComponent(HistoryEntry historyEntry) + { + BundleEntryComponent entry = new BundleEntryComponent(); + entry.getRequest().setMethod(HTTPVerb.fromCode(historyEntry.getMethod())) + .setUrl(historyEntry.getResourceType() + (historyEntry.getResource() == null + ? "/" + historyEntry.getId().toString() + "/_history/" + historyEntry.getVersion() + : "")); + entry.setResource(historyEntry.getResource()); + BundleEntryResponseComponent response = entry.getResponse(); + + response.setStatus(toStatus(historyEntry.getMethod())); + response.setLocation( + toLocation(historyEntry.getResourceType(), historyEntry.getId().toString(), historyEntry.getVersion())); + response.setEtag(new EntityTag(historyEntry.getVersion(), true).toString()); + response.setLastModified(Date.from(historyEntry.getLastUpdated().atZone(ZoneId.systemDefault()).toInstant())); + + return entry; + } + + private String toStatus(String method) + { + switch (method) + { + case "POST": + return "201 Created"; + case "PUT": + return "200 OK"; + case "DELETE": + return "200 OK"; + default: + throw new RuntimeException("Method " + method + " not supported"); + } + } + + private String toLocation(String resourceType, String id, String version) + { + return new IdType(serverBase, resourceType, id, version).getValue(); + } + + private void setLinks(PageAndCount pageAndCount, UriBuilder bundleUri, String format, String pretty, Bundle bundle, + boolean isEmpty, int total) + { if (format != null) bundleUri = bundleUri.replaceQueryParam("_format", format); if (pretty != null) bundleUri = bundleUri.replaceQueryParam("_pretty", pretty); - if (result.getPageAndCount().getCount() > 0) + if (pageAndCount.getCount() > 0) { - bundleUri = bundleUri.replaceQueryParam("_count", result.getPageAndCount().getCount()); - bundleUri = bundleUri.replaceQueryParam("_page", - result.getPartialResult().isEmpty() ? 1 : result.getPageAndCount().getPage()); + bundleUri = bundleUri.replaceQueryParam("_count", pageAndCount.getCount()); + bundleUri = bundleUri.replaceQueryParam("_page", isEmpty ? 1 : pageAndCount.getPage()); } else bundleUri = bundleUri.replaceQueryParam("_count", "0"); bundle.addLink().setRelation("self").setUrlElement(new UriType(bundleUri.build())); - if (result.getPageAndCount().getCount() > 0 && !result.getPartialResult().isEmpty()) + if (pageAndCount.getCount() > 0 && !isEmpty) { bundleUri = bundleUri.replaceQueryParam("_page", 1); - bundleUri = bundleUri.replaceQueryParam("_count", result.getPageAndCount().getCount()); + bundleUri = bundleUri.replaceQueryParam("_count", pageAndCount.getCount()); bundle.addLink().setRelation("first").setUrlElement(new UriType(bundleUri.build())); - if (result.getPageAndCount().getPage() > 1) + if (pageAndCount.getPage() > 1) { - bundleUri = bundleUri.replaceQueryParam("_page", result.getPageAndCount().getPage() - 1); - bundleUri = bundleUri.replaceQueryParam("_count", result.getPageAndCount().getCount()); + bundleUri = bundleUri.replaceQueryParam("_page", pageAndCount.getPage() - 1); + bundleUri = bundleUri.replaceQueryParam("_count", pageAndCount.getCount()); bundle.addLink().setRelation("previous").setUrlElement(new UriType(bundleUri.build())); } - if (!result.isLastPage()) + if (!pageAndCount.isLastPage(total)) { - bundleUri = bundleUri.replaceQueryParam("_page", result.getPageAndCount().getPage() + 1); - bundleUri = bundleUri.replaceQueryParam("_count", result.getPageAndCount().getCount()); + bundleUri = bundleUri.replaceQueryParam("_page", pageAndCount.getPage() + 1); + bundleUri = bundleUri.replaceQueryParam("_count", pageAndCount.getCount()); bundle.addLink().setRelation("next").setUrlElement(new UriType(bundleUri.build())); } - bundleUri = bundleUri.replaceQueryParam("_page", result.getLastPage()); - bundleUri = bundleUri.replaceQueryParam("_count", result.getPageAndCount().getCount()); + bundleUri = bundleUri.replaceQueryParam("_page", pageAndCount.getLastPage(total)); + bundleUri = bundleUri.replaceQueryParam("_count", pageAndCount.getCount()); bundle.addLink().setRelation("last").setUrlElement(new UriType(bundleUri.build())); } + } - return bundle; + public OperationOutcome toOperationOutcomeWarning(List errors) + { + return toOperationOutcome(errors, IssueSeverity.WARNING); + } + + public OperationOutcome toOperationOutcomeError(List errors) + { + return toOperationOutcome(errors, IssueSeverity.ERROR); } - public OperationOutcome toOperationOutcome(List errors) + private OperationOutcome toOperationOutcome(List errors, IssueSeverity severity) { String diagnostics = errors.stream().map(SearchQueryParameterError::toString).collect(Collectors.joining("; ")); - return createOutcome(IssueSeverity.WARNING, IssueType.PROCESSING, diagnostics); + return createOutcome(severity, IssueType.PROCESSING, diagnostics); } public Response pathVsElementId(String resourceTypeName, String id, IdType resourceId) @@ -251,7 +379,7 @@ public Response badIfNoneExistHeaderValue(String ifNoneExistsHeaderValue, public Response oneExists(Resource resource, String ifNoneExistsHeaderValue) { - logger.info("{} with criteria {} exists", resource, ifNoneExistsHeaderValue); + logger.info("{} with criteria {} exists", resource.getResourceType().name(), ifNoneExistsHeaderValue); OperationOutcome outcome = createOutcome(IssueSeverity.INFORMATION, IssueType.DUPLICATE, "Resource with criteria '" + ifNoneExistsHeaderValue + "' exists"); @@ -265,12 +393,13 @@ public Response oneExists(Resource resource, String ifNoneExistsHeaderValue) .tag(new EntityTag(resource.getMeta().getVersionId(), true)).build(); } - public Response unknownReference(Resource resource, ResourceReference resourceReference) + public OperationOutcome unknownReference(Resource resource, ResourceReference resourceReference) { - return unknownReference(null, resource, resourceReference); + return unknownReference(resource, resourceReference, null); } - public Response unknownReference(Integer bundleIndex, Resource resource, ResourceReference resourceReference) + public OperationOutcome unknownReference(Resource resource, ResourceReference resourceReference, + Integer bundleIndex) { if (bundleIndex == null) logger.warn("Unknown reference at {} in resource of type {} with id {}", @@ -280,14 +409,13 @@ public Response unknownReference(Integer bundleIndex, Resource resource, Resourc resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), bundleIndex); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, "Unknown reference at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex)); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response referenceTargetTypeNotSupportedByImplementation(Integer bundleIndex, Resource resource, + public OperationOutcome referenceTargetTypeNotSupportedByImplementation(Integer bundleIndex, Resource resource, ResourceReference resourceReference) { if (bundleIndex == null) @@ -300,15 +428,14 @@ public Response referenceTargetTypeNotSupportedByImplementation(Integer bundleIn resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), bundleIndex); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, "Reference target type of reference at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " not supported by this implementation"); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response referenceTargetTypeNotSupportedByResource(Integer bundleIndex, Resource resource, + public OperationOutcome referenceTargetTypeNotSupportedByResource(Integer bundleIndex, Resource resource, ResourceReference resourceReference) { if (bundleIndex == null) @@ -320,14 +447,13 @@ public Response referenceTargetTypeNotSupportedByResource(Integer bundleIndex, R resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), bundleIndex); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, "Reference target type of reference at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " not supported"); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response referenceTargetNotFoundLocally(Integer bundleIndex, Resource resource, + public OperationOutcome referenceTargetNotFoundLocally(Integer bundleIndex, Resource resource, ResourceReference resourceReference) { if (bundleIndex == null) @@ -340,15 +466,14 @@ public Response referenceTargetNotFoundLocally(Integer bundleIndex, Resource res resourceReference.getReference().getReference(), resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), bundleIndex); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, "Reference target " + resourceReference.getReference().getReference() + " of reference at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " not found"); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response referenceTargetNotFoundRemote(Integer bundleIndex, Resource resource, + public OperationOutcome referenceTargetNotFoundRemote(Integer bundleIndex, Resource resource, ResourceReference resourceReference, String serverBase) { if (bundleIndex == null) @@ -362,16 +487,15 @@ public Response referenceTargetNotFoundRemote(Integer bundleIndex, Resource reso resourceReference.getReference().getReference(), resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), bundleIndex, serverBase); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, "Reference target " + resourceReference.getReference().getReference() + " of reference at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " not found on server " + serverBase); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response noEndpointFoundForLiteralExternalReference(Integer bundleIndex, Resource resource, + public OperationOutcome noEndpointFoundForLiteralExternalReference(Integer bundleIndex, Resource resource, ResourceReference resourceReference) { if (bundleIndex == null) @@ -385,15 +509,14 @@ public Response noEndpointFoundForLiteralExternalReference(Integer bundleIndex, resourceReference.getReference().getReference(), resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), bundleIndex); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, "No Endpoint found for reference target " + resourceReference.getReference().getReference() + " of reference at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " not found"); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response badReference(boolean logicalNotConditional, Integer bundleIndex, Resource resource, + public OperationOutcome badReference(boolean logicalNotConditional, Integer bundleIndex, Resource resource, ResourceReference resourceReference, String queryParameters, List unsupportedQueryParameters) { @@ -413,17 +536,22 @@ public Response badReference(boolean logicalNotConditional, Integer bundleIndex, resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), bundleIndex, unsupportedQueryParameters.size() != 1 ? "s" : "", unsupportedQueryParametersString); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, (logicalNotConditional ? "Logical" : "Conditional") + " reference " + queryParameters + " at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " contains unsupported queryparameter" + (unsupportedQueryParameters.size() != 1 ? "s" : "") + " " + unsupportedQueryParametersString); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response referenceTargetNotFoundLocallyByIdentifier(Integer bundleIndex, Resource resource, + public OperationOutcome referenceTargetNotFoundLocallyByIdentifier(Resource resource, + ResourceReference resourceReference) + { + return referenceTargetNotFoundLocallyByIdentifier(null, resource, resourceReference); + } + + public OperationOutcome referenceTargetNotFoundLocallyByIdentifier(Integer bundleIndex, Resource resource, ResourceReference resourceReference) { if (bundleIndex == null) @@ -440,16 +568,15 @@ public Response referenceTargetNotFoundLocallyByIdentifier(Integer bundleIndex, resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), bundleIndex); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, "Reference target by identifier '" + resourceReference.getReference().getIdentifier().getSystem() + "|" + resourceReference.getReference().getIdentifier().getValue() + "' of reference at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " not found"); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response referenceTargetMultipleMatchesLocallyByIdentifier(Integer bundleIndex, Resource resource, + public OperationOutcome referenceTargetMultipleMatchesLocallyByIdentifier(Integer bundleIndex, Resource resource, ResourceReference resourceReference, int overallCount) { if (bundleIndex == null) @@ -466,65 +593,60 @@ public Response referenceTargetMultipleMatchesLocallyByIdentifier(Integer bundle resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), bundleIndex); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, "Found " + overallCount + " matches for reference target by identifier '" + resourceReference.getReference().getIdentifier().getSystem() + "|" + resourceReference.getReference().getIdentifier().getValue() + "' of reference at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " not found"); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response referenceTargetNotFoundLocallyByCondition(Integer bundleIndex, Resource resource, - ResourceReference resourceReference, String queryParameters) + public OperationOutcome referenceTargetNotFoundLocallyByCondition(Integer bundleIndex, Resource resource, + ResourceReference resourceReference) { if (bundleIndex == null) logger.warn( - "Reference target by identifier '{}|{}' of reference at {} in resource of type {} with id {} not found", - resourceReference.getReference().getIdentifier().getSystem(), - resourceReference.getReference().getIdentifier().getValue(), - resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId()); + "Reference target by condition '{}' of reference at {} in resource of type {} with id {} not found", + resourceReference.getReference().getReference(), resourceReference.getReferenceLocation(), + resource.getResourceType().name(), resource.getId()); else logger.warn( - "Reference target by identifier '{}|{}' of reference at {} in resource of type {} with id {} at bundle index {} not found", - resourceReference.getReference().getIdentifier().getSystem(), - resourceReference.getReference().getIdentifier().getValue(), - resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), - bundleIndex); + "Reference target by condition '{}' of reference at {} in resource of type {} with id {} at bundle index {} not found", + resourceReference.getReference().getReference(), resourceReference.getReferenceLocation(), + resource.getResourceType().name(), resource.getId(), bundleIndex); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, - "Reference target by identifier '" + resourceReference.getReference().getIdentifier().getSystem() + "|" - + resourceReference.getReference().getIdentifier().getValue() + "' of reference at " - + resourceReference.getReferenceLocation() + " in resource of type " + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + "Reference target by condition '" + resourceReference.getReference().getReference() + + "' of reference at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " not found"); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response referenceTargetMultipleMatchesLocallyByCondition(Integer bundleIndex, Resource resource, - ResourceReference resourceReference, int overallCount, String queryParameters) + public OperationOutcome referenceTargetMultipleMatchesLocallyByCondition(Integer bundleIndex, Resource resource, + ResourceReference resourceReference, int overallCount) { if (bundleIndex == null) logger.warn( "Found {} matches for reference target by condition '{}' of reference at {} in resource of type {} with id {}", - overallCount, queryParameters, resourceReference.getReferenceLocation(), - resource.getResourceType().name(), resource.getId()); + overallCount, resourceReference.getReference().getReference(), + resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId()); else logger.warn( "Found {} matches for reference target by condition '{}' of reference at {} in resource of type {} with id {} at bundle index {}", - overallCount, queryParameters, resourceReference.getReferenceLocation(), - resource.getResourceType().name(), resource.getId(), bundleIndex); + overallCount, resourceReference.getReference().getReference(), + resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), + bundleIndex); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, - "Found " + overallCount + " matches for reference target by condition '" + queryParameters - + "' of reference at " + resourceReference.getReferenceLocation() + " in resource of type " + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + "Found " + overallCount + " matches for reference target by condition '" + + resourceReference.getReference().getReference() + "' of reference at " + + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " not found"); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } - public Response referenceTargetBadCondition(Integer bundleIndex, Resource resource, + public OperationOutcome referenceTargetBadCondition(Integer bundleIndex, Resource resource, ResourceReference resourceReference) { if (bundleIndex == null) @@ -537,12 +659,11 @@ public Response referenceTargetBadCondition(Integer bundleIndex, Resource resour resourceReference.getReference().getReference(), resourceReference.getReferenceLocation(), resource.getResourceType().name(), resource.getId(), bundleIndex); - OperationOutcome outcome = createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, + return createOutcome(IssueSeverity.ERROR, IssueType.PROCESSING, "Bad conditional reference target '" + resourceReference.getReference().getReference() + "' of reference at " + resourceReference.getReferenceLocation() + " in resource of type " + resource.getResourceType().name() + " with id " + resource.getId() + (bundleIndex == null ? "" : " at bundle index " + bundleIndex) + " not found"); - return Response.status(Status.BAD_REQUEST).entity(outcome).build(); } public Response badDeleteRequestUrl(int bundleIndex, String url) @@ -734,4 +855,129 @@ public Response notFound(String id, String resourceTypeName) resourceTypeName + " with id " + id + " not found"); return Response.status(Status.NOT_FOUND).entity(outcome).build(); } + + public Response forbiddenNotValid(String operation, User user, String resourceType, + ValidationResult validationResult) + { + OperationOutcome outcome = new OperationOutcome(); + validationResult.populateOperationOutcome(outcome); + + logger.warn("Operation {} forbidden, {} resource not valid for user '{}'", operation, resourceType, + user.getName()); + + return Response.status(Status.FORBIDDEN).entity(outcome).build(); + } + + public Response unableToGenerateSnapshot(StructureDefinition resource, Integer bundleIndex, + List messages) + { + if (bundleIndex == null) + logger.warn( + "Unable to generate StructureDefinition snapshot for profile with url {}, version {} and id {}: {}", + resource.getUrl(), resource.getVersion(), resource.getId()); + else + logger.warn( + "Unable to generate StructureDefinition snapshot for profile with url {}, version {} and id {} at bundle index {}: {}", + resource.getUrl(), resource.getVersion(), resource.getId(), bundleIndex); + + OperationOutcome outcome = new OperationOutcome(); + + messages.forEach(m -> outcome.addIssue().setSeverity(convert(m.getLevel())).setCode(convert(m.getType())) + .setDiagnostics(m.summary())); + + return Response.status(Status.BAD_REQUEST).entity(outcome).build(); + } + + private IssueSeverity convert(org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity severity) + { + switch (severity) + { + case FATAL: + return IssueSeverity.FATAL; + case ERROR: + return IssueSeverity.ERROR; + case WARNING: + return IssueSeverity.WARNING; + case INFORMATION: + return IssueSeverity.INFORMATION; + case NULL: + return IssueSeverity.NULL; + default: + throw new RuntimeException("IssueSeverity " + severity + " not supported"); + } + } + + private IssueType convert(org.hl7.fhir.utilities.validation.ValidationMessage.IssueType type) + { + switch (type) + { + case INVALID: + return IssueType.INVALID; + case STRUCTURE: + return IssueType.STRUCTURE; + case REQUIRED: + return IssueType.REQUIRED; + case VALUE: + return IssueType.VALUE; + case INVARIANT: + return IssueType.INVARIANT; + case SECURITY: + return IssueType.SECURITY; + case LOGIN: + return IssueType.LOGIN; + case UNKNOWN: + return IssueType.UNKNOWN; + case EXPIRED: + return IssueType.EXPIRED; + case FORBIDDEN: + return IssueType.FORBIDDEN; + case SUPPRESSED: + return IssueType.SUPPRESSED; + case PROCESSING: + return IssueType.PROCESSING; + case NOTSUPPORTED: + return IssueType.NOTSUPPORTED; + case DUPLICATE: + return IssueType.DUPLICATE; + case MULTIPLEMATCHES: + return IssueType.MULTIPLEMATCHES; + case NOTFOUND: + return IssueType.NOTFOUND; + case DELETED: + return IssueType.DELETED; + case TOOLONG: + return IssueType.TOOLONG; + case CODEINVALID: + return IssueType.CODEINVALID; + case EXTENSION: + return IssueType.EXTENSION; + case TOOCOSTLY: + return IssueType.TOOCOSTLY; + case BUSINESSRULE: + return IssueType.BUSINESSRULE; + case CONFLICT: + return IssueType.CONFLICT; + case TRANSIENT: + return IssueType.TRANSIENT; + case LOCKERROR: + return IssueType.LOCKERROR; + case NOSTORE: + return IssueType.NOSTORE; + case EXCEPTION: + return IssueType.EXCEPTION; + case TIMEOUT: + return IssueType.TIMEOUT; + case INCOMPLETE: + return IssueType.INCOMPLETE; + case THROTTLED: + return IssueType.THROTTLED; + case INFORMATIONAL: + return IssueType.INFORMATIONAL; + case NULL: + return IssueType.NULL; + + default: + throw new RuntimeException("IssueType " + type + " not supported"); + } + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/AtParameter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/AtParameter.java new file mode 100644 index 000000000..46fd9a902 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/AtParameter.java @@ -0,0 +1,30 @@ +package org.highmed.dsf.fhir.history; + +import org.highmed.dsf.fhir.search.parameters.basic.AbstractDateTimeParameter; +import org.hl7.fhir.r4.model.DomainResource; +import org.hl7.fhir.r4.model.Resource; + +public class AtParameter extends AbstractDateTimeParameter +{ + private static final String PARAMETER_NAME = "_at"; + private static final String COLUMN_NAME = "last_updated"; + + public AtParameter() + { + super(PARAMETER_NAME, COLUMN_NAME); + } + + @Override + public boolean matches(Resource resource) + { + // Not implemented for history + throw new UnsupportedOperationException(); + } + + @Override + protected String getSortSql(String sortDirectionWithSpacePrefix) + { + // Not implemented for history + throw new UnsupportedOperationException(); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/History.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/History.java new file mode 100644 index 000000000..1661ac7c9 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/History.java @@ -0,0 +1,39 @@ +package org.highmed.dsf.fhir.history; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.highmed.dsf.fhir.search.PageAndCount; + +public class History +{ + private final int total; + private final PageAndCount pageAndCount; + private final List entries = new ArrayList<>(); + + public History(int total, PageAndCount pageAndCount, Collection entries) + { + this.total = total; + this.pageAndCount = pageAndCount; + if (entries != null) + this.entries.addAll(entries); + } + + public int getTotal() + { + return total; + } + + public PageAndCount getPageAndCount() + { + return pageAndCount; + } + + public List getEntries() + { + return Collections.unmodifiableList(entries); + } + +} \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/HistoryEntry.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/HistoryEntry.java new file mode 100644 index 000000000..664906eb0 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/HistoryEntry.java @@ -0,0 +1,57 @@ +package org.highmed.dsf.fhir.history; + +import java.time.LocalDateTime; +import java.util.UUID; + +import org.hl7.fhir.r4.model.Resource; + +public class HistoryEntry +{ + private final UUID id; + private final String version; + private final String resourceType; + private final String method; + private final LocalDateTime lastUpdated; + private final Resource resource; + + public HistoryEntry(UUID id, String version, String resourceType, String method, LocalDateTime lastUpdated, + Resource resource) + { + this.id = id; + this.version = version; + this.resourceType = resourceType; + this.method = method; + this.lastUpdated = lastUpdated; + this.resource = resource; + } + + public UUID getId() + { + return id; + } + + public String getVersion() + { + return version; + } + + public String getResourceType() + { + return resourceType; + } + + public String getMethod() + { + return method; + } + + public LocalDateTime getLastUpdated() + { + return lastUpdated; + } + + public Resource getResource() + { + return resource; + } +} \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/HistoryService.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/HistoryService.java new file mode 100644 index 000000000..08ee61a08 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/HistoryService.java @@ -0,0 +1,17 @@ +package org.highmed.dsf.fhir.history; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; + +import org.highmed.dsf.fhir.authentication.User; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Resource; + +public interface HistoryService +{ + Bundle getHistory(User user, UriInfo uri, HttpHeaders headers); + + Bundle getHistory(User user, UriInfo uri, HttpHeaders headers, Class resource); + + Bundle getHistory(User user, UriInfo uri, HttpHeaders headers, Class resource, String id); +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/HistoryServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/HistoryServiceImpl.java new file mode 100644 index 000000000..e83c1f034 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/HistoryServiceImpl.java @@ -0,0 +1,149 @@ +package org.highmed.dsf.fhir.history; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.core.UriInfo; +import javax.ws.rs.core.Response.Status; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.dao.HistoryDao; +import org.highmed.dsf.fhir.help.ExceptionHandler; +import org.highmed.dsf.fhir.help.ParameterConverter; +import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.user.HistoryUserFilterFactory; +import org.highmed.dsf.fhir.prefer.PreferHandlingType; +import org.highmed.dsf.fhir.search.PageAndCount; +import org.highmed.dsf.fhir.search.SearchQuery; +import org.highmed.dsf.fhir.search.SearchQueryParameterError; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Resource; +import org.springframework.beans.factory.InitializingBean; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class HistoryServiceImpl implements HistoryService, InitializingBean +{ + private final String serverBase; + private final int defaultPageCount; + private final ParameterConverter parameterConverter; + private final ExceptionHandler exceptionHandler; + private final ResponseGenerator responseGenerator; + private final HistoryDao historyDao; + private final HistoryUserFilterFactory historyUserFilterFactory; + + public HistoryServiceImpl(String serverBase, int defaultPageCount, ParameterConverter parameterConverter, + ExceptionHandler exceptionHandler, ResponseGenerator responseGenerator, HistoryDao historyDao, + HistoryUserFilterFactory historyUserFilterFactory) + { + this.serverBase = serverBase; + this.defaultPageCount = defaultPageCount; + this.parameterConverter = parameterConverter; + this.exceptionHandler = exceptionHandler; + this.responseGenerator = responseGenerator; + this.historyDao = historyDao; + this.historyUserFilterFactory = historyUserFilterFactory; + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(serverBase, "serverBase"); + Objects.requireNonNull(parameterConverter, "parameterConverter"); + Objects.requireNonNull(exceptionHandler, "exceptionHandler"); + Objects.requireNonNull(responseGenerator, "responseGenerator"); + Objects.requireNonNull(historyDao, "historyDao"); + Objects.requireNonNull(historyUserFilterFactory, "historyUserFilterFactory"); + } + + @Override + public Bundle getHistory(User user, UriInfo uri, HttpHeaders headers) + { + return getHistory(user, uri, headers, null, null); + } + + @Override + public Bundle getHistory(User user, UriInfo uri, HttpHeaders headers, Class resource) + { + return getHistory(user, uri, headers, resource, null); + } + + @Override + public Bundle getHistory(User user, UriInfo uri, HttpHeaders headers, Class resource, String id) + { + MultivaluedMap queryParameters = uri.getQueryParameters(); + + Integer page = parameterConverter.getFirstInt(queryParameters, SearchQuery.PARAMETER_PAGE); + int effectivePage = page == null ? 1 : page; + + Integer count = parameterConverter.getFirstInt(queryParameters, SearchQuery.PARAMETER_COUNT); + int effectiveCount = (count == null || count < 0) ? defaultPageCount : count; + + PageAndCount pageAndCount = new PageAndCount(effectivePage, effectiveCount); + + AtParameter atParameter = new AtParameter(); + atParameter.configure(queryParameters); + SinceParameter sinceParameter = new SinceParameter(); + sinceParameter.configure(queryParameters); + + String path = null; + History history; + if (resource == null && id == null) + history = exceptionHandler + .handleSqlException(() -> historyDao.readHistory(historyUserFilterFactory.getUserFilters(user), + pageAndCount, atParameter, sinceParameter)); + else if (resource != null && id != null) + { + history = exceptionHandler.handleSqlException(() -> historyDao.readHistory( + historyUserFilterFactory.getUserFilter(user, resource), pageAndCount, atParameter, sinceParameter, + resource, parameterConverter.toUuid(getResourceTypeName(resource), id))); + path = resource.getAnnotation(ResourceDef.class).name(); + } + else if (resource != null) + { + history = exceptionHandler.handleSqlException( + () -> historyDao.readHistory(historyUserFilterFactory.getUserFilter(user, resource), pageAndCount, + atParameter, sinceParameter, resource)); + path = resource.getAnnotation(ResourceDef.class).name(); + } + else + throw new WebApplicationException(); + + List errors = new ArrayList<>(); + errors.addAll(atParameter.getErrors()); + errors.addAll(sinceParameter.getErrors()); + + if (!errors.isEmpty() && PreferHandlingType.STRICT.equals(parameterConverter.getPreferHandling(headers))) + throw new WebApplicationException( + responseGenerator.response(Status.BAD_REQUEST, responseGenerator.toOperationOutcomeError(errors), + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build()); + + String format = queryParameters.getFirst(SearchQuery.PARAMETER_FORMAT); + String pretty = queryParameters.getFirst(SearchQuery.PARAMETER_PRETTY); + + UriBuilder bundleUri = UriBuilder.fromPath(serverBase); + if (path != null) + bundleUri = bundleUri.path(path); + if (path != null && id != null) + bundleUri = bundleUri.path(id); + + bundleUri = bundleUri.path("_history"); + atParameter.modifyBundleUri(bundleUri); + sinceParameter.modifyBundleUri(bundleUri); + + return responseGenerator.createHistoryBundle(history, errors, bundleUri, format, pretty); + } + + private String getResourceTypeName(Class resource) + { + if (resource == null) + return null; + else + return resource.getAnnotation(ResourceDef.class).name(); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/SinceParameter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/SinceParameter.java new file mode 100644 index 000000000..ba578093f --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/SinceParameter.java @@ -0,0 +1,69 @@ +package org.highmed.dsf.fhir.history; + +import java.util.Collections; +import java.util.List; + +import org.highmed.dsf.fhir.search.SearchQueryParameterError; +import org.highmed.dsf.fhir.search.SearchQueryParameterError.SearchQueryParameterErrorType; +import org.highmed.dsf.fhir.search.parameters.basic.AbstractDateTimeParameter; +import org.hl7.fhir.r4.model.DomainResource; +import org.hl7.fhir.r4.model.Resource; + +public class SinceParameter extends AbstractDateTimeParameter +{ + private static final String PARAMETER_NAME = "_since"; + private static final String COLUMN_NAME = "last_updated"; + + public SinceParameter() + { + super(PARAMETER_NAME, COLUMN_NAME); + } + + @Override + protected void checkParameters(List parameters) + { + List superValuesAndTypes = super.getValuesAndTypes(); + + if (superValuesAndTypes.size() > 1) + addError(new SearchQueryParameterError(SearchQueryParameterErrorType.UNSUPPORTED_NUMBER_OF_VALUES, + parameterName, parameters, "More than one " + parameterName + " values")); + + if (superValuesAndTypes.size() == 1) + { + DateTimeValueAndTypeAndSearchType vT = superValuesAndTypes.get(0); + if (!DateTimeSearchType.EQ.equals(vT.searchType) || !DateTimeType.ZONED_DATE_TIME.equals(vT.type)) + addError(new SearchQueryParameterError(SearchQueryParameterErrorType.UNPARSABLE_VALUE, parameterName, + parameters, "Not instant")); + } + } + + @Override + public List getValuesAndTypes() + { + List superValuesAndTypes = super.getValuesAndTypes(); + + if (superValuesAndTypes.size() == 1) + { + DateTimeValueAndTypeAndSearchType vT = superValuesAndTypes.get(0); + if (DateTimeSearchType.EQ.equals(vT.searchType) && DateTimeType.ZONED_DATE_TIME.equals(vT.type)) + return Collections + .singletonList(new DateTimeValueAndTypeAndSearchType(vT.value, vT.type, DateTimeSearchType.GE)); + } + + return superValuesAndTypes; + } + + @Override + public boolean matches(Resource resource) + { + // Not implemented for history + throw new UnsupportedOperationException(); + } + + @Override + protected String getSortSql(String sortDirectionWithSpacePrefix) + { + // Not implemented for history + throw new UnsupportedOperationException(); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ActivityDefinitionHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ActivityDefinitionHistoryUserFilter.java new file mode 100644 index 000000000..ff20d74d6 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ActivityDefinitionHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.ActivityDefinitionUserFilter; +import org.hl7.fhir.r4.model.ActivityDefinition; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class ActivityDefinitionHistoryUserFilter extends ActivityDefinitionUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = ActivityDefinition.class.getAnnotation(ResourceDef.class).name(); + + public ActivityDefinitionHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/BinaryHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/BinaryHistoryUserFilter.java new file mode 100644 index 000000000..3f39a7714 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/BinaryHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.BinaryUserFilter; +import org.hl7.fhir.r4.model.Binary; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class BinaryHistoryUserFilter extends BinaryUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Binary.class.getAnnotation(ResourceDef.class).name(); + + public BinaryHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/BundleHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/BundleHistoryUserFilter.java new file mode 100644 index 000000000..e8c162b40 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/BundleHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.BundleUserFilter; +import org.hl7.fhir.r4.model.Bundle; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class BundleHistoryUserFilter extends BundleUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Bundle.class.getAnnotation(ResourceDef.class).name(); + + public BundleHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/CodeSystemHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/CodeSystemHistoryUserFilter.java new file mode 100644 index 000000000..104bf58b9 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/CodeSystemHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.CodeSystemUserFilter; +import org.hl7.fhir.r4.model.CodeSystem; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class CodeSystemHistoryUserFilter extends CodeSystemUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = CodeSystem.class.getAnnotation(ResourceDef.class).name(); + + public CodeSystemHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/EndpointHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/EndpointHistoryUserFilter.java new file mode 100644 index 000000000..4e38bf400 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/EndpointHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.EndpointUserFilter; +import org.hl7.fhir.r4.model.Endpoint; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class EndpointHistoryUserFilter extends EndpointUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Endpoint.class.getAnnotation(ResourceDef.class).name(); + + public EndpointHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/GroupHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/GroupHistoryUserFilter.java new file mode 100644 index 000000000..1c5f4db74 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/GroupHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.GroupUserFilter; +import org.hl7.fhir.r4.model.Group; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class GroupHistoryUserFilter extends GroupUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Group.class.getAnnotation(ResourceDef.class).name(); + + public GroupHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HealthcareServiceHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HealthcareServiceHistoryUserFilter.java new file mode 100644 index 000000000..102f4afac --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HealthcareServiceHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.HealthcareServiceUserFilter; +import org.hl7.fhir.r4.model.HealthcareService; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class HealthcareServiceHistoryUserFilter extends HealthcareServiceUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = HealthcareService.class.getAnnotation(ResourceDef.class).name(); + + public HealthcareServiceHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HistoryUserFilter.java new file mode 100644 index 000000000..e0e968dca --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HistoryUserFilter.java @@ -0,0 +1,22 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.search.SearchQueryUserFilter; + +public interface HistoryUserFilter extends SearchQueryUserFilter +{ + String RESOURCE_COLUMN = "resource"; + + static String getFilterQuery(String resourceType, String filterQuery) + { + if (filterQuery == null || filterQuery.isBlank()) + return "(type = '" + resourceType + "')"; + else + return "(type = '" + resourceType + "' AND " + filterQuery + ")"; + } + + default boolean isDefined() + { + String filterQuery = getFilterQuery(); + return filterQuery != null && !filterQuery.isBlank(); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HistoryUserFilterFactory.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HistoryUserFilterFactory.java new file mode 100644 index 000000000..781133671 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HistoryUserFilterFactory.java @@ -0,0 +1,13 @@ +package org.highmed.dsf.fhir.history.user; + +import java.util.List; + +import org.highmed.dsf.fhir.authentication.User; +import org.hl7.fhir.r4.model.Resource; + +public interface HistoryUserFilterFactory +{ + HistoryUserFilter getUserFilter(User user, Class resourceType); + + List getUserFilters(User user); +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HistoryUserFilterFactoryImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HistoryUserFilterFactoryImpl.java new file mode 100644 index 000000000..1bae9e430 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/HistoryUserFilterFactoryImpl.java @@ -0,0 +1,74 @@ +package org.highmed.dsf.fhir.history.user; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.highmed.dsf.fhir.authentication.User; +import org.hl7.fhir.r4.model.ActivityDefinition; +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.Group; +import org.hl7.fhir.r4.model.HealthcareService; +import org.hl7.fhir.r4.model.Location; +import org.hl7.fhir.r4.model.NamingSystem; +import org.hl7.fhir.r4.model.Organization; +import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Practitioner; +import org.hl7.fhir.r4.model.PractitionerRole; +import org.hl7.fhir.r4.model.Provenance; +import org.hl7.fhir.r4.model.ResearchStudy; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.Subscription; +import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.ValueSet; + +public class HistoryUserFilterFactoryImpl implements HistoryUserFilterFactory +{ + private final Map, Function> filtersByResource = new HashMap<>(); + + public HistoryUserFilterFactoryImpl() + { + filtersByResource.put(ActivityDefinition.class, ActivityDefinitionHistoryUserFilter::new); + filtersByResource.put(Binary.class, BinaryHistoryUserFilter::new); + filtersByResource.put(Bundle.class, BundleHistoryUserFilter::new); + filtersByResource.put(CodeSystem.class, CodeSystemHistoryUserFilter::new); + filtersByResource.put(Endpoint.class, EndpointHistoryUserFilter::new); + filtersByResource.put(Group.class, GroupHistoryUserFilter::new); + filtersByResource.put(HealthcareService.class, HealthcareServiceHistoryUserFilter::new); + filtersByResource.put(Location.class, LocationHistoryUserFilter::new); + filtersByResource.put(NamingSystem.class, NamingSystemHistoryUserFilter::new); + filtersByResource.put(Organization.class, OrganizationHistoryUserFilter::new); + filtersByResource.put(Patient.class, PatientHistoryUserFilter::new); + filtersByResource.put(Practitioner.class, PractitionerHistoryUserFilter::new); + filtersByResource.put(PractitionerRole.class, PractitionerRoleHistoryUserFilter::new); + filtersByResource.put(Provenance.class, ProvenanceHistoryUserFilter::new); + filtersByResource.put(ResearchStudy.class, ResearchStudyHistoryUserFilter::new); + filtersByResource.put(StructureDefinition.class, StructureDefinitionHistoryUserFilter::new); + filtersByResource.put(Subscription.class, SubscriptionHistoryUserFilter::new); + filtersByResource.put(Task.class, TaskHistoryUserFilter::new); + filtersByResource.put(ValueSet.class, ValueSetHistoryUserFilter::new); + } + + @Override + public HistoryUserFilter getUserFilter(User user, Class resourceType) + { + Function factory = filtersByResource.get(resourceType); + if (factory == null) + throw new IllegalArgumentException(HistoryUserFilter.class.getSimpleName() + " for " + + resourceType.getClass().getName() + " not found"); + else + return factory.apply(user); + } + + @Override + public List getUserFilters(User user) + { + return filtersByResource.values().stream().map(f -> f.apply(user)).collect(Collectors.toList()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/LocationHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/LocationHistoryUserFilter.java new file mode 100644 index 000000000..13e612dd7 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/LocationHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.LocationUserFilter; +import org.hl7.fhir.r4.model.Location; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class LocationHistoryUserFilter extends LocationUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Location.class.getAnnotation(ResourceDef.class).name(); + + public LocationHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/NamingSystemHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/NamingSystemHistoryUserFilter.java new file mode 100644 index 000000000..b42ed0b87 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/NamingSystemHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.NamingSystemUserFilter; +import org.hl7.fhir.r4.model.NamingSystem; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class NamingSystemHistoryUserFilter extends NamingSystemUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = NamingSystem.class.getAnnotation(ResourceDef.class).name(); + + public NamingSystemHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/OrganizationHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/OrganizationHistoryUserFilter.java new file mode 100644 index 000000000..d24ed0d1e --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/OrganizationHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.OrganizationUserFilter; +import org.hl7.fhir.r4.model.Organization; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class OrganizationHistoryUserFilter extends OrganizationUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Organization.class.getAnnotation(ResourceDef.class).name(); + + public OrganizationHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/PatientHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/PatientHistoryUserFilter.java new file mode 100644 index 000000000..345bfc0fe --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/PatientHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.PatientUserFilter; +import org.hl7.fhir.r4.model.Patient; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class PatientHistoryUserFilter extends PatientUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Patient.class.getAnnotation(ResourceDef.class).name(); + + public PatientHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/PractitionerHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/PractitionerHistoryUserFilter.java new file mode 100644 index 000000000..080e185e6 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/PractitionerHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.PractitionerUserFilter; +import org.hl7.fhir.r4.model.Practitioner; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class PractitionerHistoryUserFilter extends PractitionerUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Practitioner.class.getAnnotation(ResourceDef.class).name(); + + public PractitionerHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/PractitionerRoleHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/PractitionerRoleHistoryUserFilter.java new file mode 100644 index 000000000..9e93acb70 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/PractitionerRoleHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.PractitionerRoleUserFilter; +import org.hl7.fhir.r4.model.PractitionerRole; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class PractitionerRoleHistoryUserFilter extends PractitionerRoleUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = PractitionerRole.class.getAnnotation(ResourceDef.class).name(); + + public PractitionerRoleHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ProvenanceHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ProvenanceHistoryUserFilter.java new file mode 100644 index 000000000..45c48f58c --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ProvenanceHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.ProvenanceUserFilter; +import org.hl7.fhir.r4.model.Provenance; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class ProvenanceHistoryUserFilter extends ProvenanceUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Provenance.class.getAnnotation(ResourceDef.class).name(); + + public ProvenanceHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ResearchStudyHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ResearchStudyHistoryUserFilter.java new file mode 100644 index 000000000..3515e5135 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ResearchStudyHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.ResearchStudyUserFilter; +import org.hl7.fhir.r4.model.ResearchStudy; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class ResearchStudyHistoryUserFilter extends ResearchStudyUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = ResearchStudy.class.getAnnotation(ResourceDef.class).name(); + + public ResearchStudyHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/StructureDefinitionHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/StructureDefinitionHistoryUserFilter.java new file mode 100644 index 000000000..151613985 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/StructureDefinitionHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.StructureDefinitionUserFilter; +import org.hl7.fhir.r4.model.StructureDefinition; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class StructureDefinitionHistoryUserFilter extends StructureDefinitionUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = StructureDefinition.class.getAnnotation(ResourceDef.class).name(); + + public StructureDefinitionHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/SubscriptionHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/SubscriptionHistoryUserFilter.java new file mode 100644 index 000000000..1cc6de5a6 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/SubscriptionHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.SubscriptionUserFilter; +import org.hl7.fhir.r4.model.Subscription; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class SubscriptionHistoryUserFilter extends SubscriptionUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Subscription.class.getAnnotation(ResourceDef.class).name(); + + public SubscriptionHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/TaskHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/TaskHistoryUserFilter.java new file mode 100644 index 000000000..211a6e1d0 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/TaskHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.TaskUserFilter; +import org.hl7.fhir.r4.model.Task; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class TaskHistoryUserFilter extends TaskUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = Task.class.getAnnotation(ResourceDef.class).name(); + + public TaskHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ValueSetHistoryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ValueSetHistoryUserFilter.java new file mode 100644 index 000000000..197a49e17 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/history/user/ValueSetHistoryUserFilter.java @@ -0,0 +1,23 @@ +package org.highmed.dsf.fhir.history.user; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.search.parameters.user.ValueSetUserFilter; +import org.hl7.fhir.r4.model.ValueSet; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +public class ValueSetHistoryUserFilter extends ValueSetUserFilter implements HistoryUserFilter +{ + private static final String RESOURCE_TYPE = ValueSet.class.getAnnotation(ResourceDef.class).name(); + + public ValueSetHistoryUserFilter(User user) + { + super(user, HistoryUserFilter.RESOURCE_COLUMN); + } + + @Override + public String getFilterQuery() + { + return HistoryUserFilter.getFilterQuery(RESOURCE_TYPE, super.getFilterQuery()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/DbSearchQuery.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/DbSearchQuery.java index 3c3b4d7d3..c356ddd80 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/DbSearchQuery.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/DbSearchQuery.java @@ -10,8 +10,6 @@ public interface DbSearchQuery { - boolean isCountOnly(int overallCount); - String getCountSql(); String getSearchSql(); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/IncludeParameterDefinition.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/IncludeParameterDefinition.java new file mode 100644 index 000000000..db450afde --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/IncludeParameterDefinition.java @@ -0,0 +1,21 @@ +package org.highmed.dsf.fhir.search; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.hl7.fhir.r4.model.Resource; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface IncludeParameterDefinition +{ + Class resourceType(); + + String parameterName(); + + Class[] targetResourceTypes(); +} \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/PageAndCount.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/PageAndCount.java index de6238cfb..cf5e67a6c 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/PageAndCount.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/PageAndCount.java @@ -11,11 +11,16 @@ public PageAndCount(int page, int count) this.count = count; } - protected String sql() + public String getSql() { return " LIMIT " + count + (page > 1 ? (" OFFSET " + ((page - 1) * count)) : ""); } + public boolean isCountOnly(int total) + { + return page < 1 || count < 1 || getPageStart() > total; + } + public int getPage() { return page; @@ -41,4 +46,14 @@ public int getPageEnd() return getPageStart() - 1 + count; } + + public boolean isLastPage(int total) + { + return page >= getLastPage(total); + } + + public int getLastPage(int total) + { + return (int) Math.ceil((double) total / count); + } } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/PartialResult.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/PartialResult.java index 96032ff39..9a33eb498 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/PartialResult.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/PartialResult.java @@ -7,25 +7,22 @@ public class PartialResult { - private final int overallCount; + private final int total; private final PageAndCount pageAndCount; private final List partialResult; private final List includes; - private final boolean countOnly; - public PartialResult(int overallCount, PageAndCount pageAndCount, List partialResult, List includes, - boolean countOnly) + public PartialResult(int total, PageAndCount pageAndCount, List partialResult, List includes) { - this.overallCount = overallCount; + this.total = total; this.pageAndCount = pageAndCount; this.partialResult = partialResult; this.includes = includes; - this.countOnly = countOnly; } - public int getOverallCount() + public int getTotal() { - return overallCount; + return total; } public PageAndCount getPageAndCount() @@ -42,19 +39,4 @@ public List getIncludes() { return Collections.unmodifiableList(includes); } - - public boolean isLastPage() - { - return pageAndCount.getPage() >= getLastPage(); - } - - public int getLastPage() - { - return (int) Math.ceil((double) overallCount / pageAndCount.getCount()); - } - - public boolean isCountOnly() - { - return countOnly; - } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQuery.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQuery.java index d01b7b3df..c923f3add 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQuery.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQuery.java @@ -196,9 +196,15 @@ public List getUnsupportedQueryParameters(Map p.getErrors().stream()).forEach(errors::add); revIncludeParameterFactories.stream().flatMap(p -> p.getErrors().stream()).forEach(errors::add); + List includeParameterValues = queryParameters.getOrDefault(PARAMETER_INCLUDE, Collections.emptyList()); + includeParameters.stream().map(SearchQueryIncludeParameter::getBundleUriQueryParameterValues) + .forEach(v -> includeParameterValues.remove(v)); + if (!includeParameterValues.isEmpty()) + errors.add(new SearchQueryParameterError(SearchQueryParameterErrorType.UNSUPPORTED_PARAMETER, + PARAMETER_INCLUDE, includeParameterValues)); + List revIncludeParameterValues = new ArrayList<>( queryParameters.getOrDefault(PARAMETER_REVINCLUDE, Collections.emptyList())); - revIncludeParameters.stream().map(SearchQueryIncludeParameter::getBundleUriQueryParameterValues) .forEach(v -> revIncludeParameterValues.remove(v)); if (!revIncludeParameterValues.isEmpty()) @@ -301,7 +307,7 @@ public String getSearchSql() + resourceTable; return searchQueryMain + (!filterQuery.isEmpty() ? (" WHERE " + filterQuery) : "") + sortSql - + pageAndCount.sql(); + + pageAndCount.getSql(); } @Override @@ -315,8 +321,13 @@ public void modifyStatement(PreparedStatement statement, int index = 0; if (userFilter != null) + { while (index < userFilter.getSqlParameterCount()) - userFilter.modifyStatement(++index, statement); + { + int i = ++index; + userFilter.modifyStatement(i, i, statement); + } + } for (SearchQueryParameter q : filtered) for (int i = 0; i < q.getSqlParameterCount(); i++) @@ -335,12 +346,6 @@ public PageAndCount getPageAndCount() return pageAndCount; } - @Override - public boolean isCountOnly(int overallCount) - { - return pageAndCount.getPage() < 1 || pageAndCount.getCount() < 1 || pageAndCount.getPageStart() > overallCount; - } - public UriBuilder configureBundleUri(UriBuilder bundleUri) { Objects.requireNonNull(bundleUri, "bundleUri"); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQueryRevIncludeParameterFactory.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQueryRevIncludeParameterFactory.java index 0f85bcadb..ec64fd450 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQueryRevIncludeParameterFactory.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQueryRevIncludeParameterFactory.java @@ -1,28 +1,9 @@ package org.highmed.dsf.fhir.search; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; import java.util.List; -import org.hl7.fhir.r4.model.Resource; - public interface SearchQueryRevIncludeParameterFactory { - @Target(ElementType.TYPE) - @Retention(RetentionPolicy.RUNTIME) - @Documented - public @interface RevIncludeDefinition - { - Class resourceType(); - - String parameterName(); - - Class[] targetResourceTypes(); - } - void configure(List revIncludeParameterValues); List getErrors(); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQueryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQueryUserFilter.java index 007159f8b..f6e77ae6d 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQueryUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/SearchQueryUserFilter.java @@ -19,5 +19,6 @@ public interface SearchQueryUserFilter */ int getSqlParameterCount(); - void modifyStatement(int parameterIndex, PreparedStatement statement) throws SQLException; + void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) + throws SQLException; } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ActivityDefinitionName.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ActivityDefinitionName.java index 74f01d8f4..3b76a5ec4 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ActivityDefinitionName.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ActivityDefinitionName.java @@ -88,15 +88,6 @@ public boolean matches(Resource resource) @Override protected String getSortSql(String sortDirectionWithSpacePrefix) { - switch (valueAndType.type) - { - case STARTS_WITH: - case CONTAINS: - return "lower(activity_definition->>'name')" + sortDirectionWithSpacePrefix; - case EXACT: - return "activity_definition->>'name'" + sortDirectionWithSpacePrefix; - default: - return ""; - } + return "activity_definition->>'name'" + sortDirectionWithSpacePrefix; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/EndpointName.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/EndpointName.java index a6b46951e..0c9adabfb 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/EndpointName.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/EndpointName.java @@ -88,15 +88,6 @@ public boolean matches(Resource resource) @Override protected String getSortSql(String sortDirectionWithSpacePrefix) { - switch (valueAndType.type) - { - case STARTS_WITH: - case CONTAINS: - return "lower(endpoint->>'name')" + sortDirectionWithSpacePrefix; - case EXACT: - return "endpoint->>'name'" + sortDirectionWithSpacePrefix; - default: - return ""; - } + return "endpoint->>'name'" + sortDirectionWithSpacePrefix; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/EndpointOrganization.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/EndpointOrganization.java index 37faa148c..34785be2b 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/EndpointOrganization.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/EndpointOrganization.java @@ -10,6 +10,7 @@ import org.highmed.dsf.fhir.dao.exception.ResourceDeletedException; import org.highmed.dsf.fhir.dao.provider.DaoProvider; import org.highmed.dsf.fhir.function.BiFunctionWithSqlException; +import org.highmed.dsf.fhir.search.IncludeParameterDefinition; import org.highmed.dsf.fhir.search.IncludeParts; import org.highmed.dsf.fhir.search.SearchQueryParameter.SearchParameterDefinition; import org.highmed.dsf.fhir.search.parameters.basic.AbstractIdentifierParameter; @@ -21,6 +22,7 @@ import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; +@IncludeParameterDefinition(resourceType = Endpoint.class, parameterName = EndpointOrganization.PARAMETER_NAME, targetResourceTypes = Organization.class) @SearchParameterDefinition(name = EndpointOrganization.PARAMETER_NAME, definition = "http://hl7.org/fhir/SearchParameter/Endpoint-organization", type = SearchParamType.REFERENCE, documentation = "The organization that is managing the endpoint") public class EndpointOrganization extends AbstractReferenceParameter { @@ -115,21 +117,17 @@ protected void doResolveReferencesForMatching(Endpoint resource, DaoProvider dao Reference reference = resource.getManagingOrganization(); IIdType idType = reference.getReferenceElement(); - if (idType.hasVersionIdPart()) + try { - dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) - .ifPresent(reference::setResource); + if (idType.hasVersionIdPart()) + dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) + .ifPresent(reference::setResource); + else + dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); } - else + catch (ResourceDeletedException e) { - try - { - dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); - } - catch (ResourceDeletedException e) - { - // ignore while matching, will result in a non match if this would have been the matching resource - } + // ignore while matching, will result in a non match if this would have been the matching resource } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/NamingSystemName.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/NamingSystemName.java index 42e9f04db..169583667 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/NamingSystemName.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/NamingSystemName.java @@ -89,15 +89,6 @@ public boolean matches(Resource resource) @Override protected String getSortSql(String sortDirectionWithSpacePrefix) { - switch (valueAndType.type) - { - case STARTS_WITH: - case CONTAINS: - return "lower(naming_system->>'name')" + sortDirectionWithSpacePrefix; - case EXACT: - return "naming_system->>'name'" + sortDirectionWithSpacePrefix; - default: - return ""; - } + return "naming_system->>'name'" + sortDirectionWithSpacePrefix; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/OrganizationEndpoint.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/OrganizationEndpoint.java index 5add3d3bf..11ef7c89e 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/OrganizationEndpoint.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/OrganizationEndpoint.java @@ -10,6 +10,7 @@ import org.highmed.dsf.fhir.dao.exception.ResourceDeletedException; import org.highmed.dsf.fhir.dao.provider.DaoProvider; import org.highmed.dsf.fhir.function.BiFunctionWithSqlException; +import org.highmed.dsf.fhir.search.IncludeParameterDefinition; import org.highmed.dsf.fhir.search.IncludeParts; import org.highmed.dsf.fhir.search.SearchQueryParameter.SearchParameterDefinition; import org.highmed.dsf.fhir.search.parameters.basic.AbstractIdentifierParameter; @@ -21,6 +22,7 @@ import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; +@IncludeParameterDefinition(resourceType = Organization.class, parameterName = OrganizationEndpoint.PARAMETER_NAME, targetResourceTypes = Endpoint.class) @SearchParameterDefinition(name = OrganizationEndpoint.PARAMETER_NAME, definition = "http://hl7.org/fhir/SearchParameter/Organization-endpoint", type = SearchParamType.REFERENCE, documentation = "Technical endpoints providing access to services operated for the organization") public class OrganizationEndpoint extends AbstractReferenceParameter { @@ -116,21 +118,17 @@ protected void doResolveReferencesForMatching(Organization resource, DaoProvider { IIdType idType = reference.getReferenceElement(); - if (idType.hasVersionIdPart()) + try { - dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) - .ifPresent(reference::setResource); + if (idType.hasVersionIdPart()) + dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) + .ifPresent(reference::setResource); + else + dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); } - else + catch (ResourceDeletedException e) { - try - { - dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); - } - catch (ResourceDeletedException e) - { - // ignore while matching, will result in a non match if this would have been the matching resource - } + // ignore while matching, will result in a non match if this would have been the matching resource } } } @@ -148,7 +146,7 @@ public boolean matches(Resource resource) if (ReferenceSearchType.IDENTIFIER.equals(valueAndType.type)) { - return o.getEndpoint().stream().map(e -> e.getResource()).filter(r -> r instanceof Endpoint) + return o.getEndpoint().stream().map(Reference::getResource).filter(r -> r instanceof Endpoint) .flatMap(r -> ((Endpoint) r).getIdentifier().stream()) .anyMatch(i -> AbstractIdentifierParameter.identifierMatches(valueAndType.identifier, i)); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/OrganizationName.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/OrganizationName.java index 171e870df..9402c7a93 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/OrganizationName.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/OrganizationName.java @@ -93,17 +93,7 @@ public boolean matches(Resource resource) @Override protected String getSortSql(String sortDirectionWithSpacePrefix) { - switch (valueAndType.type) - { - case STARTS_WITH: - case CONTAINS: - return "lower(organization->>'name')" + sortDirectionWithSpacePrefix + ", lower(organization->>'alias')" - + sortDirectionWithSpacePrefix; - case EXACT: - return "organization->>'name'" + sortDirectionWithSpacePrefix + ", organization->>'alias'" - + sortDirectionWithSpacePrefix; - default: - return ""; - } + return "organization->>'name'" + sortDirectionWithSpacePrefix + ", organization->>'alias'" + + sortDirectionWithSpacePrefix; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/PractitionerRoleOrganization.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/PractitionerRoleOrganization.java index 1cab775c0..866da92a9 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/PractitionerRoleOrganization.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/PractitionerRoleOrganization.java @@ -10,6 +10,7 @@ import org.highmed.dsf.fhir.dao.exception.ResourceDeletedException; import org.highmed.dsf.fhir.dao.provider.DaoProvider; import org.highmed.dsf.fhir.function.BiFunctionWithSqlException; +import org.highmed.dsf.fhir.search.IncludeParameterDefinition; import org.highmed.dsf.fhir.search.IncludeParts; import org.highmed.dsf.fhir.search.SearchQueryParameter.SearchParameterDefinition; import org.highmed.dsf.fhir.search.parameters.basic.AbstractIdentifierParameter; @@ -21,6 +22,7 @@ import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; +@IncludeParameterDefinition(resourceType = PractitionerRole.class, parameterName = PractitionerRoleOrganization.PARAMETER_NAME, targetResourceTypes = Organization.class) @SearchParameterDefinition(name = PractitionerRoleOrganization.PARAMETER_NAME, definition = "http://hl7.org/fhir/SearchParameter/PractitionerRole-organization", type = SearchParamType.REFERENCE, documentation = "The identity of the organization the practitioner represents / acts on behalf of") public class PractitionerRoleOrganization extends AbstractReferenceParameter { @@ -116,21 +118,17 @@ protected void doResolveReferencesForMatching(PractitionerRole resource, DaoProv Reference reference = resource.getOrganization(); IIdType idType = reference.getReferenceElement(); - if (idType.hasVersionIdPart()) + try { - dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) - .ifPresent(reference::setResource); + if (idType.hasVersionIdPart()) + dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) + .ifPresent(reference::setResource); + else + dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); } - else + catch (ResourceDeletedException e) { - try - { - dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); - } - catch (ResourceDeletedException e) - { - // ignore while matching, will result in a non match if this would have been the matching resource - } + // ignore while matching, will result in a non match if this would have been the matching resource } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/PractitionerRolePractitioner.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/PractitionerRolePractitioner.java index 468fa775a..50ae46cf0 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/PractitionerRolePractitioner.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/PractitionerRolePractitioner.java @@ -10,6 +10,7 @@ import org.highmed.dsf.fhir.dao.exception.ResourceDeletedException; import org.highmed.dsf.fhir.dao.provider.DaoProvider; import org.highmed.dsf.fhir.function.BiFunctionWithSqlException; +import org.highmed.dsf.fhir.search.IncludeParameterDefinition; import org.highmed.dsf.fhir.search.IncludeParts; import org.highmed.dsf.fhir.search.SearchQueryParameter.SearchParameterDefinition; import org.highmed.dsf.fhir.search.parameters.basic.AbstractIdentifierParameter; @@ -21,6 +22,7 @@ import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; +@IncludeParameterDefinition(resourceType = PractitionerRole.class, parameterName = PractitionerRolePractitioner.PARAMETER_NAME, targetResourceTypes = Practitioner.class) @SearchParameterDefinition(name = PractitionerRolePractitioner.PARAMETER_NAME, definition = "http://hl7.org/fhir/SearchParameter/PractitionerRole-practitioner", type = SearchParamType.REFERENCE, documentation = "Practitioner that is able to provide the defined services for the organization") public class PractitionerRolePractitioner extends AbstractReferenceParameter { @@ -116,21 +118,17 @@ protected void doResolveReferencesForMatching(PractitionerRole resource, DaoProv Reference reference = resource.getPractitioner(); IIdType idType = reference.getReferenceElement(); - if (idType.hasVersionIdPart()) + try { - dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) - .ifPresent(reference::setResource); + if (idType.hasVersionIdPart()) + dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) + .ifPresent(reference::setResource); + else + dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); } - else + catch (ResourceDeletedException e) { - try - { - dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); - } - catch (ResourceDeletedException e) - { - // ignore while matching, will result in a non match if this would have been the matching resource - } + // ignore while matching, will result in a non match if this would have been the matching resource } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResearchStudyEnrollment.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResearchStudyEnrollment.java index db91aeec8..36d2a151c 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResearchStudyEnrollment.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResearchStudyEnrollment.java @@ -10,18 +10,20 @@ import org.highmed.dsf.fhir.dao.exception.ResourceDeletedException; import org.highmed.dsf.fhir.dao.provider.DaoProvider; import org.highmed.dsf.fhir.function.BiFunctionWithSqlException; +import org.highmed.dsf.fhir.search.IncludeParameterDefinition; import org.highmed.dsf.fhir.search.IncludeParts; -import org.highmed.dsf.fhir.search.SearchQueryParameter; +import org.highmed.dsf.fhir.search.SearchQueryParameter.SearchParameterDefinition; import org.highmed.dsf.fhir.search.parameters.basic.AbstractIdentifierParameter; import org.highmed.dsf.fhir.search.parameters.basic.AbstractReferenceParameter; import org.hl7.fhir.instance.model.api.IIdType; -import org.hl7.fhir.r4.model.Enumerations; +import org.hl7.fhir.r4.model.Enumerations.SearchParamType; import org.hl7.fhir.r4.model.Group; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.ResearchStudy; import org.hl7.fhir.r4.model.Resource; -@SearchQueryParameter.SearchParameterDefinition(name = ResearchStudyEnrollment.PARAMETER_NAME, definition = "http://highmed.org/fhir/SearchParameter/ResearchStudy-enrollment", type = Enumerations.SearchParamType.REFERENCE, documentation = "Search by research study enrollment") +@IncludeParameterDefinition(resourceType = ResearchStudy.class, parameterName = ResearchStudyEnrollment.PARAMETER_NAME, targetResourceTypes = Group.class) +@SearchParameterDefinition(name = ResearchStudyEnrollment.PARAMETER_NAME, definition = "http://highmed.org/fhir/SearchParameter/ResearchStudy-enrollment", type = SearchParamType.REFERENCE, documentation = "Search by research study enrollment") public class ResearchStudyEnrollment extends AbstractReferenceParameter { private static final String RESOURCE_TYPE_NAME = "ResearchStudy"; @@ -116,21 +118,17 @@ protected void doResolveReferencesForMatching(ResearchStudy resource, DaoProvide { IIdType idType = reference.getReferenceElement(); - if (idType.hasVersionIdPart()) + try { - dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) - .ifPresent(reference::setResource); + if (idType.hasVersionIdPart()) + dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) + .ifPresent(reference::setResource); + else + dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); } - else + catch (ResourceDeletedException e) { - try - { - dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); - } - catch (ResourceDeletedException e) - { - // ignore while matching, will result in a non match if this would have been the matching resource - } + // ignore while matching, will result in a non match if this would have been the matching resource } } } @@ -181,9 +179,7 @@ protected String getSortSql(String sortDirectionWithSpacePrefix) protected String getIncludeSql(IncludeParts includeParts) { if (includeParts.matches(RESOURCE_TYPE_NAME, PARAMETER_NAME, TARGET_RESOURCE_TYPE_NAME)) - return "(SELECT jsonb_agg(group_json) FROM current_groups" - + " WHERE concat('Group/', group_json->>'id') IN (SELECT reference->>'reference' FROM jsonb_array_elements(research_study->'enrollment') AS reference)" - + ") AS groups"; + return "(SELECT jsonb_agg(group_json) FROM current_groups WHERE concat('Group/', group_json->>'id') IN (SELECT reference->>'reference' FROM jsonb_array_elements(research_study->'enrollment') AS reference)) AS groups"; else return null; } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResearchStudyPrincipalInvestigator.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResearchStudyPrincipalInvestigator.java index a9a5c109d..9a4ccbb73 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResearchStudyPrincipalInvestigator.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResearchStudyPrincipalInvestigator.java @@ -11,6 +11,7 @@ import org.highmed.dsf.fhir.dao.exception.ResourceDeletedException; import org.highmed.dsf.fhir.dao.provider.DaoProvider; import org.highmed.dsf.fhir.function.BiFunctionWithSqlException; +import org.highmed.dsf.fhir.search.IncludeParameterDefinition; import org.highmed.dsf.fhir.search.IncludeParts; import org.highmed.dsf.fhir.search.SearchQueryParameter.SearchParameterDefinition; import org.highmed.dsf.fhir.search.parameters.basic.AbstractIdentifierParameter; @@ -23,6 +24,8 @@ import org.hl7.fhir.r4.model.ResearchStudy; import org.hl7.fhir.r4.model.Resource; +@IncludeParameterDefinition(resourceType = ResearchStudy.class, parameterName = ResearchStudyPrincipalInvestigator.PARAMETER_NAME, targetResourceTypes = { + Practitioner.class, PractitionerRole.class }) @SearchParameterDefinition(name = ResearchStudyPrincipalInvestigator.PARAMETER_NAME, definition = "http://hl7.org/fhir/SearchParameter/ResearchStudy-principalinvestigator", type = SearchParamType.REFERENCE, documentation = "Researcher who oversees multiple aspects of the study") public class ResearchStudyPrincipalInvestigator extends AbstractReferenceParameter { @@ -130,21 +133,17 @@ else if ("PractitionerRole".equals(idType.getResourceType())) private void setResource(Reference reference, IIdType idType, ResourceDao dao) throws SQLException { - if (idType.hasVersionIdPart()) + try { - dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) - .ifPresent(reference::setResource); + if (idType.hasVersionIdPart()) + dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) + .ifPresent(reference::setResource); + else + dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); } - else + catch (ResourceDeletedException e) { - try - { - dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); - } - catch (ResourceDeletedException e) - { - // ignore while matching, will result in a non match if this would have been the matching resource - } + // ignore while matching, will result in a non match if this would have been the matching resource } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResourceLastUpdated.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResourceLastUpdated.java index 4b6d482e2..c6a7ae5cc 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResourceLastUpdated.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/ResourceLastUpdated.java @@ -1,190 +1,22 @@ package org.highmed.dsf.fhir.search.parameters; -import java.sql.Array; -import java.sql.Date; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.time.LocalDate; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import org.highmed.dsf.fhir.function.BiFunctionWithSqlException; import org.highmed.dsf.fhir.search.SearchQueryParameter.SearchParameterDefinition; import org.highmed.dsf.fhir.search.parameters.basic.AbstractDateTimeParameter; import org.hl7.fhir.r4.model.DomainResource; import org.hl7.fhir.r4.model.Enumerations.SearchParamType; -import org.hl7.fhir.r4.model.Resource; @SearchParameterDefinition(name = ResourceLastUpdated.PARAMETER_NAME, definition = "http://hl7.org/fhir/SearchParameter/Resource-lastUpdated", type = SearchParamType.DATE, documentation = "When the resource version last changed") public class ResourceLastUpdated extends AbstractDateTimeParameter { public static final String PARAMETER_NAME = "_lastUpdated"; - private static String toJsonProperty(String resourceColumn) + private static String toColumn(String resourceColumn) { return "(" + resourceColumn + "->'meta'->>'lastUpdated')"; } - private final String jsonProperty; - private List values = new ArrayList<>(); - public ResourceLastUpdated(String resourceColumn) { - super(PARAMETER_NAME); - - jsonProperty = toJsonProperty(resourceColumn); - } - - @Override - public String getFilterQuery() - { - return getValuesAndTypes().stream().map(this::getSubquery).collect(Collectors.joining(" AND ")); - } - - private String getSubquery(DateTimeValueAndTypeAndSearchType value) - { - switch (value.type) - { - case ZONED_DATE_TIME: - return getSubquery((ZonedDateTime) value.value, value.searchType); - case LOCAL_DATE: - return getSubquery((LocalDate) value.value, value.searchType); - case YEAR_MONTH_PERIOD: - case YEAR_PERIOD: - return getSubquery((LocalDatePair) value.value); - default: - return ""; - } - } - - private String getSubquery(ZonedDateTime value, DateTimeSearchType searchType) - { - values.add(value); - - return jsonProperty + "::timestamp " + searchType.operator + " ?"; - } - - private String getSubquery(LocalDate value, DateTimeSearchType searchType) - { - values.add(value); - - return jsonProperty + "::date " + searchType.operator + " ?"; - } - - private String getSubquery(LocalDatePair value) - { - return getSubquery(value.startInclusive, DateTimeSearchType.GE) + " AND " - + getSubquery(value.endExclusive, DateTimeSearchType.LT); - } - - @Override - public int getSqlParameterCount() - { - return values.size(); - } - - @Override - public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement, - BiFunctionWithSqlException arrayCreator) throws SQLException - { - Object value = values.get(subqueryParameterIndex - 1); - - if (value instanceof ZonedDateTime) - statement.setTimestamp(parameterIndex, Timestamp - .valueOf(((ZonedDateTime) value).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime())); - else if (value instanceof LocalDate) - statement.setDate(parameterIndex, Date.valueOf((LocalDate) value)); - } - - @Override - public boolean matches(Resource resource) - { - if (!isDefined()) - throw notDefined(); - - ZonedDateTime lastUpdated = toZonedDateTime(resource.getMeta().getLastUpdated()); - return lastUpdated != null && getValuesAndTypes().stream().allMatch(value -> matches(lastUpdated, value)); - } - - private ZonedDateTime toZonedDateTime(java.util.Date date) - { - if (date == null) - return null; - - return ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); - } - - private boolean matches(ZonedDateTime lastUpdated, DateTimeValueAndTypeAndSearchType value) - { - switch (value.type) - { - case ZONED_DATE_TIME: - return matches(lastUpdated, (ZonedDateTime) value.value, value.searchType); - case LOCAL_DATE: - return matches(lastUpdated.toLocalDate(), (LocalDate) value.value, value.searchType); - case YEAR_MONTH_PERIOD: - case YEAR_PERIOD: - return matches(lastUpdated.toLocalDate(), (LocalDatePair) value.value); - default: - throw notDefined(); - } - } - - private boolean matches(ZonedDateTime lastUpdated, ZonedDateTime value, DateTimeSearchType type) - { - switch (type) - { - case EQ: - return lastUpdated.equals(value); - case GT: - return lastUpdated.isAfter(value); - case GE: - return lastUpdated.isAfter(value) || lastUpdated.equals(value); - case LT: - return lastUpdated.isBefore(value); - case LE: - return lastUpdated.isBefore(value) || lastUpdated.equals(value); - case NE: - return !lastUpdated.isEqual(value); - default: - throw notDefined(); - } - } - - private boolean matches(LocalDate lastUpdated, LocalDate value, DateTimeSearchType type) - { - switch (type) - { - case EQ: - return lastUpdated.equals(value); - case GT: - return lastUpdated.isAfter(value); - case GE: - return lastUpdated.isAfter(value) || lastUpdated.equals(value); - case LT: - return lastUpdated.isBefore(value); - case LE: - return lastUpdated.isBefore(value) || lastUpdated.equals(value); - case NE: - return !lastUpdated.isEqual(value); - default: - throw notDefined(); - } - } - - private boolean matches(LocalDate lastUpdated, LocalDatePair value) - { - return (lastUpdated.isAfter(value.startInclusive) || lastUpdated.isEqual(value.startInclusive)) - && lastUpdated.isBefore(value.endExclusive); - } - - @Override - protected String getSortSql(String sortDirectionWithSpacePrefix) - { - return jsonProperty + "::timestamp" + sortDirectionWithSpacePrefix; + super(PARAMETER_NAME, toColumn(resourceColumn)); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/TaskAuthoredOn.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/TaskAuthoredOn.java new file mode 100644 index 000000000..07b4348d0 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/TaskAuthoredOn.java @@ -0,0 +1,18 @@ +package org.highmed.dsf.fhir.search.parameters; + +import org.highmed.dsf.fhir.search.SearchQueryParameter.SearchParameterDefinition; +import org.highmed.dsf.fhir.search.parameters.basic.AbstractDateTimeParameter; +import org.hl7.fhir.r4.model.Enumerations.SearchParamType; +import org.hl7.fhir.r4.model.Task; + +@SearchParameterDefinition(name = TaskAuthoredOn.PARAMETER_NAME, definition = "http://hl7.org/fhir/SearchParameter/Task-authored-on", type = SearchParamType.DATE, documentation = "Search by creation date") +public class TaskAuthoredOn extends AbstractDateTimeParameter +{ + public static final String PARAMETER_NAME = "authored-on"; + private static final String PROPERTY = "(task->>'authoredOn')";; + + public TaskAuthoredOn() + { + super(PARAMETER_NAME, PROPERTY); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/TaskModified.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/TaskModified.java new file mode 100644 index 000000000..6182b7365 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/TaskModified.java @@ -0,0 +1,18 @@ +package org.highmed.dsf.fhir.search.parameters; + +import org.highmed.dsf.fhir.search.SearchQueryParameter.SearchParameterDefinition; +import org.highmed.dsf.fhir.search.parameters.basic.AbstractDateTimeParameter; +import org.hl7.fhir.r4.model.Enumerations.SearchParamType; +import org.hl7.fhir.r4.model.Task; + +@SearchParameterDefinition(name = TaskModified.PARAMETER_NAME, definition = "http://hl7.org/fhir/SearchParameter/Task-modified", type = SearchParamType.DATE, documentation = "Search by last modification date") +public class TaskModified extends AbstractDateTimeParameter +{ + public static final String PARAMETER_NAME = "modified"; + private static final String PROPERTY = "(task->>'lastModified')";; + + public TaskModified() + { + super(PARAMETER_NAME, PROPERTY); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/TaskRequester.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/TaskRequester.java index a2ea2caab..cfc6f151e 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/TaskRequester.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/TaskRequester.java @@ -11,6 +11,7 @@ import org.highmed.dsf.fhir.dao.exception.ResourceDeletedException; import org.highmed.dsf.fhir.dao.provider.DaoProvider; import org.highmed.dsf.fhir.function.BiFunctionWithSqlException; +import org.highmed.dsf.fhir.search.IncludeParameterDefinition; import org.highmed.dsf.fhir.search.IncludeParts; import org.highmed.dsf.fhir.search.SearchQueryParameter.SearchParameterDefinition; import org.highmed.dsf.fhir.search.parameters.basic.AbstractIdentifierParameter; @@ -26,6 +27,8 @@ import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.Task; +@IncludeParameterDefinition(resourceType = Task.class, parameterName = TaskRequester.PARAMETER_NAME, targetResourceTypes = { + Practitioner.class, Organization.class, Patient.class, PractitionerRole.class }) @SearchParameterDefinition(name = TaskRequester.PARAMETER_NAME, definition = "http://hl7.org/fhir/SearchParameter/Task-requester", type = SearchParamType.REFERENCE, documentation = "Search by task requester") public class TaskRequester extends AbstractReferenceParameter { @@ -145,21 +148,17 @@ else if ("PractitionerRole".equals(idType.getResourceType())) private void setResource(Reference reference, IIdType idType, ResourceDao dao) throws SQLException { - if (idType.hasVersionIdPart()) + try { - dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) - .ifPresent(reference::setResource); + if (idType.hasVersionIdPart()) + dao.readVersion(UUID.fromString(idType.getIdPart()), idType.getVersionIdPartAsLong()) + .ifPresent(reference::setResource); + else + dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); } - else + catch (ResourceDeletedException e) { - try - { - dao.read(UUID.fromString(idType.getIdPart())).ifPresent(reference::setResource); - } - catch (ResourceDeletedException e) - { - // ignore while matching, will result in a non match if this would have been the matching resource - } + // ignore while matching, will result in a non match if this would have been the matching resource } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/basic/AbstractDateTimeParameter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/basic/AbstractDateTimeParameter.java index 6d3b5e980..d07cf6834 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/basic/AbstractDateTimeParameter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/basic/AbstractDateTimeParameter.java @@ -1,5 +1,10 @@ package org.highmed.dsf.fhir.search.parameters.basic; +import java.sql.Array; +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Timestamp; import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -17,9 +22,11 @@ import javax.ws.rs.core.UriBuilder; +import org.highmed.dsf.fhir.function.BiFunctionWithSqlException; import org.highmed.dsf.fhir.search.SearchQueryParameterError; import org.highmed.dsf.fhir.search.SearchQueryParameterError.SearchQueryParameterErrorType; import org.hl7.fhir.r4.model.DomainResource; +import org.hl7.fhir.r4.model.Resource; public abstract class AbstractDateTimeParameter extends AbstractSearchParameter { @@ -48,7 +55,7 @@ protected static class DateTimeValueAndTypeAndSearchType public final DateTimeType type; public final DateTimeSearchType searchType; - private DateTimeValueAndTypeAndSearchType(Object value, DateTimeType type, DateTimeSearchType searchType) + public DateTimeValueAndTypeAndSearchType(Object value, DateTimeType type, DateTimeSearchType searchType) { this.value = value; this.type = type; @@ -84,9 +91,14 @@ public String toString() private List valuesAndTypes = new ArrayList<>(); - public AbstractDateTimeParameter(String parameterName) + private final String timestampColumn; + private final List values = new ArrayList<>(); + + public AbstractDateTimeParameter(String parameterName, String timestampColumn) { super(parameterName); + + this.timestampColumn = timestampColumn; } @Override @@ -124,6 +136,18 @@ else if (valuesAndTypes.size() == 2) valuesAndTypes.clear(); valuesAndTypes.add(first); } + + checkParameters(parameters); + } + + /** + * Override to perform additional parameter checks + * + * @param parameters + * @see #addError(SearchQueryParameterError) + */ + protected void checkParameters(List parameters) + { } private DateTimeValueAndTypeAndSearchType parse(String parameterValue, List parameterValues) @@ -244,4 +268,155 @@ private String toUrlValue(DateTimeValueAndTypeAndSearchType value) return ""; } } + + @Override + public String getFilterQuery() + { + values.clear(); + + return getValuesAndTypes().stream().map(this::getSubquery).collect(Collectors.joining(" AND ")); + } + + private String getSubquery(DateTimeValueAndTypeAndSearchType value) + { + switch (value.type) + { + case ZONED_DATE_TIME: + return getSubquery((ZonedDateTime) value.value, value.searchType); + case LOCAL_DATE: + return getSubquery((LocalDate) value.value, value.searchType); + case YEAR_MONTH_PERIOD: + case YEAR_PERIOD: + return getSubquery((LocalDatePair) value.value); + default: + return ""; + } + } + + private String getSubquery(ZonedDateTime value, DateTimeSearchType searchType) + { + values.add(value); + + return timestampColumn + "::timestamp " + searchType.operator + " ?"; + } + + private String getSubquery(LocalDate value, DateTimeSearchType searchType) + { + values.add(value); + + return timestampColumn + "::date " + searchType.operator + " ?"; + } + + private String getSubquery(LocalDatePair value) + { + return getSubquery(value.startInclusive, DateTimeSearchType.GE) + " AND " + + getSubquery(value.endExclusive, DateTimeSearchType.LT); + } + + @Override + public int getSqlParameterCount() + { + return values.size(); + } + + @Override + public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement, + BiFunctionWithSqlException arrayCreator) throws SQLException + { + Object value = values.get(subqueryParameterIndex - 1); + + if (value instanceof ZonedDateTime) + statement.setTimestamp(parameterIndex, Timestamp + .valueOf(((ZonedDateTime) value).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime())); + else if (value instanceof LocalDate) + statement.setDate(parameterIndex, Date.valueOf((LocalDate) value)); + } + + @Override + public boolean matches(Resource resource) + { + if (!isDefined()) + throw notDefined(); + + ZonedDateTime lastUpdated = toZonedDateTime(resource.getMeta().getLastUpdated()); + return lastUpdated != null && getValuesAndTypes().stream().allMatch(value -> matches(lastUpdated, value)); + } + + private ZonedDateTime toZonedDateTime(java.util.Date date) + { + if (date == null) + return null; + + return ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); + } + + private boolean matches(ZonedDateTime lastUpdated, DateTimeValueAndTypeAndSearchType value) + { + switch (value.type) + { + case ZONED_DATE_TIME: + return matches(lastUpdated, (ZonedDateTime) value.value, value.searchType); + case LOCAL_DATE: + return matches(lastUpdated.toLocalDate(), (LocalDate) value.value, value.searchType); + case YEAR_MONTH_PERIOD: + case YEAR_PERIOD: + return matches(lastUpdated.toLocalDate(), (LocalDatePair) value.value); + default: + throw notDefined(); + } + } + + private boolean matches(ZonedDateTime lastUpdated, ZonedDateTime value, DateTimeSearchType type) + { + switch (type) + { + case EQ: + return lastUpdated.equals(value); + case GT: + return lastUpdated.isAfter(value); + case GE: + return lastUpdated.isAfter(value) || lastUpdated.equals(value); + case LT: + return lastUpdated.isBefore(value); + case LE: + return lastUpdated.isBefore(value) || lastUpdated.equals(value); + case NE: + return !lastUpdated.isEqual(value); + default: + throw notDefined(); + } + } + + private boolean matches(LocalDate lastUpdated, LocalDate value, DateTimeSearchType type) + { + switch (type) + { + case EQ: + return lastUpdated.equals(value); + case GT: + return lastUpdated.isAfter(value); + case GE: + return lastUpdated.isAfter(value) || lastUpdated.equals(value); + case LT: + return lastUpdated.isBefore(value); + case LE: + return lastUpdated.isBefore(value) || lastUpdated.equals(value); + case NE: + return !lastUpdated.isEqual(value); + default: + throw notDefined(); + } + } + + private boolean matches(LocalDate lastUpdated, LocalDatePair value) + { + return (lastUpdated.isAfter(value.startInclusive) || lastUpdated.isEqual(value.startInclusive)) + && lastUpdated.isBefore(value.endExclusive); + } + + @Override + protected String getSortSql(String sortDirectionWithSpacePrefix) + { + return timestampColumn + "::timestamp" + sortDirectionWithSpacePrefix; + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/basic/AbstractReferenceParameter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/basic/AbstractReferenceParameter.java index 9e57f08bf..50ff2a0e2 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/basic/AbstractReferenceParameter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/basic/AbstractReferenceParameter.java @@ -170,18 +170,6 @@ private List getIncludeParts(Map> queryParame List includeParameterValues = queryParameters.getOrDefault(SearchQuery.PARAMETER_INCLUDE, Collections.emptyList()); - List nonMatchingIncludeParameters = includeParameterValues.stream().map(IncludeParts::fromString) - .filter(p -> !resourceTypeName.equals(p.getSourceResourceTypeName()) - || !parameterName.equals(p.getSearchParameterName()) - || !((targetResourceTypeNames.size() == 1 && p.getTargetResourceTypeName() == null) - || targetResourceTypeNames.contains(p.getTargetResourceTypeName()))) - .map(IncludeParts::toString).collect(Collectors.toList()); - - if (!nonMatchingIncludeParameters.isEmpty()) - addError(new SearchQueryParameterError(SearchQueryParameterErrorType.UNPARSABLE_VALUE, - SearchQuery.PARAMETER_INCLUDE, includeParameterValues, "Non matching include parameter" - + (nonMatchingIncludeParameters.size() != 1 ? "s " : " ") + nonMatchingIncludeParameters)); - List includeParts = includeParameterValues.stream().map(IncludeParts::fromString) .filter(p -> resourceTypeName.equals(p.getSourceResourceTypeName()) && parameterName.equals(p.getSearchParameterName()) @@ -269,6 +257,5 @@ public void resolveReferencesForMatching(Resource resource, DaoProvider daoProvi * @param connection * not null */ - protected abstract void modifyIncludeResource(IncludeParts includeParts, Resource resource, - Connection connection); + protected abstract void modifyIncludeResource(IncludeParts includeParts, Resource resource, Connection connection); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/EndpointOrganizationRevInclude.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/EndpointOrganizationRevInclude.java index bb250af31..499bca062 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/EndpointOrganizationRevInclude.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/EndpointOrganizationRevInclude.java @@ -3,13 +3,12 @@ import java.sql.Connection; import org.highmed.dsf.fhir.search.IncludeParts; -import org.highmed.dsf.fhir.search.SearchQueryRevIncludeParameterFactory.RevIncludeDefinition; +import org.highmed.dsf.fhir.search.IncludeParameterDefinition; import org.hl7.fhir.r4.model.Endpoint; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Resource; -@RevIncludeDefinition(resourceType = Endpoint.class, parameterName = "organization", targetResourceTypes = { - Organization.class }) +@IncludeParameterDefinition(resourceType = Endpoint.class, parameterName = "organization", targetResourceTypes = Organization.class) public class EndpointOrganizationRevInclude extends AbstractRevIncludeParameterFactory { public EndpointOrganizationRevInclude() diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/OrganizationEndpointRevInclude.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/OrganizationEndpointRevInclude.java index fb6221937..9dd58242b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/OrganizationEndpointRevInclude.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/OrganizationEndpointRevInclude.java @@ -3,13 +3,12 @@ import java.sql.Connection; import org.highmed.dsf.fhir.search.IncludeParts; -import org.highmed.dsf.fhir.search.SearchQueryRevIncludeParameterFactory.RevIncludeDefinition; +import org.highmed.dsf.fhir.search.IncludeParameterDefinition; import org.hl7.fhir.r4.model.Endpoint; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Resource; -@RevIncludeDefinition(resourceType = Organization.class, parameterName = "endpoint", targetResourceTypes = { - Endpoint.class }) +@IncludeParameterDefinition(resourceType = Organization.class, parameterName = "endpoint", targetResourceTypes = Endpoint.class) public class OrganizationEndpointRevInclude extends AbstractRevIncludeParameterFactory { public OrganizationEndpointRevInclude() diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/ResearchStudyEnrollmentRevInclude.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/ResearchStudyEnrollmentRevInclude.java index 607447458..798382a0e 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/ResearchStudyEnrollmentRevInclude.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/rev/include/ResearchStudyEnrollmentRevInclude.java @@ -3,13 +3,12 @@ import java.sql.Connection; import org.highmed.dsf.fhir.search.IncludeParts; -import org.highmed.dsf.fhir.search.SearchQueryRevIncludeParameterFactory.RevIncludeDefinition; +import org.highmed.dsf.fhir.search.IncludeParameterDefinition; import org.hl7.fhir.r4.model.Group; import org.hl7.fhir.r4.model.ResearchStudy; import org.hl7.fhir.r4.model.Resource; -@RevIncludeDefinition(resourceType = ResearchStudy.class, parameterName = "enrollment", targetResourceTypes = { - Group.class }) +@IncludeParameterDefinition(resourceType = ResearchStudy.class, parameterName = "enrollment", targetResourceTypes = Group.class) public class ResearchStudyEnrollmentRevInclude extends AbstractRevIncludeParameterFactory { public ResearchStudyEnrollmentRevInclude() diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/AbstractMetaTagAuthorizationRoleUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/AbstractMetaTagAuthorizationRoleUserFilter.java index 6ac54aae5..7cae0e61e 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/AbstractMetaTagAuthorizationRoleUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/AbstractMetaTagAuthorizationRoleUserFilter.java @@ -8,13 +8,9 @@ abstract class AbstractMetaTagAuthorizationRoleUserFilter extends AbstractUserFilter { - private final String resourceColumn; - public AbstractMetaTagAuthorizationRoleUserFilter(User user, String resourceColumn) { - super(user); - - this.resourceColumn = resourceColumn; + super(user, resourceColumn); } @Override @@ -53,12 +49,13 @@ public int getSqlParameterCount() } @Override - public void modifyStatement(int parameterIndex, PreparedStatement statement) throws SQLException + public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) + throws SQLException { - if (parameterIndex == 1) + if (subqueryParameterIndex == 1) statement.setString(parameterIndex, "[{\"code\": \"" + AUTHORIZATION_ROLE_VALUE_REMOTE + "\", \"system\": \"" + AUTHORIZATION_ROLE_SYSTEM + "\"}]"); - else if (parameterIndex == 2) + else if (subqueryParameterIndex == 2) statement.setString(parameterIndex, "[{\"code\": \"" + AUTHORIZATION_ROLE_VALUE_LOCAL + "\", \"system\": \"" + AUTHORIZATION_ROLE_SYSTEM + "\"}]"); else diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/AbstractUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/AbstractUserFilter.java index ab4215213..4d1bafa4b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/AbstractUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/AbstractUserFilter.java @@ -6,9 +6,11 @@ abstract class AbstractUserFilter implements SearchQueryUserFilter { protected final User user; + protected final String resourceColumn; - public AbstractUserFilter(User user) + public AbstractUserFilter(User user, String resourceColumn) { this.user = user; + this.resourceColumn = resourceColumn; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ActivityDefinitionUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ActivityDefinitionUserFilter.java index 56edb6a47..396430055 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ActivityDefinitionUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ActivityDefinitionUserFilter.java @@ -4,8 +4,15 @@ public class ActivityDefinitionUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "activity_definition"; + public ActivityDefinitionUserFilter(User user) { - super(user, "activity_definition"); + super(user, RESOURCE_COLUMN); + } + + public ActivityDefinitionUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/BinaryUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/BinaryUserFilter.java index 291e80dbf..7613fbf1b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/BinaryUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/BinaryUserFilter.java @@ -8,9 +8,16 @@ public class BinaryUserFilter extends AbstractUserFilter { + private static final String RESOURCE_COLUMN = "binary_json"; + public BinaryUserFilter(User user) { - super(user); + super(user, RESOURCE_COLUMN); + } + + public BinaryUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } @Override @@ -19,7 +26,8 @@ public String getFilterQuery() if (UserRole.LOCAL.equals(user.getRole())) return ""; else - return "(binary_json->'securityContext'->>'reference' = ? OR binary_json->'securityContext'->>'reference' = ?)"; + return "(" + resourceColumn + "->'securityContext'->>'reference' = ? OR " + resourceColumn + + "->'securityContext'->>'reference' = ?)"; } @Override @@ -29,13 +37,14 @@ public int getSqlParameterCount() } @Override - public void modifyStatement(int parameterIndex, PreparedStatement statement) throws SQLException + public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) + throws SQLException { if (!UserRole.LOCAL.equals(user.getRole())) { - if (parameterIndex == 1) + if (subqueryParameterIndex == 1) statement.setString(parameterIndex, user.getOrganization().getIdElement().getValue()); - else if (parameterIndex == 2) + else if (subqueryParameterIndex == 2) statement.setString(parameterIndex, user.getOrganization().getIdElement().toVersionless().getValue()); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/BundleUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/BundleUserFilter.java index c01578f97..b7eb3f2fc 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/BundleUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/BundleUserFilter.java @@ -4,8 +4,15 @@ public class BundleUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "bundle"; + public BundleUserFilter(User user) { - super(user, "bundle"); + super(user, RESOURCE_COLUMN); + } + + public BundleUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/CodeSystemUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/CodeSystemUserFilter.java index 82693757d..7c91b33f8 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/CodeSystemUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/CodeSystemUserFilter.java @@ -4,8 +4,15 @@ public class CodeSystemUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "code_system"; + public CodeSystemUserFilter(User user) { - super(user, "code_system"); + super(user, RESOURCE_COLUMN); + } + + public CodeSystemUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/EndpointUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/EndpointUserFilter.java index 074f8e40b..87603fa80 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/EndpointUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/EndpointUserFilter.java @@ -4,8 +4,15 @@ public class EndpointUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "endpoint"; + public EndpointUserFilter(User user) { - super(user, "endpoint"); + super(user, RESOURCE_COLUMN); + } + + public EndpointUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/GroupUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/GroupUserFilter.java index 32c16e539..33a411147 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/GroupUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/GroupUserFilter.java @@ -8,9 +8,16 @@ public class GroupUserFilter extends AbstractUserFilter { + private static final String RESOURCE_COLUMN = "group"; + public GroupUserFilter(User user) { - super(user); + super(user, RESOURCE_COLUMN); + } + + public GroupUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } @Override @@ -19,7 +26,7 @@ public String getFilterQuery() if (UserRole.LOCAL.equals(user.getRole())) return ""; else - return "(concat('Group/', group->>'id') IN " + return "(concat('Group/', " + resourceColumn + "->>'id') IN " + "(SELECT enrollment->>'reference' FROM (SELECT jsonb_array_elements(research_study->'enrollment') AS enrollment FROM current_research_studies " + "WHERE research_study->'extension' @> ?::jsonb OR research_study->'extension' @> ?::jsonb) AS enrollments))"; } @@ -31,38 +38,39 @@ public int getSqlParameterCount() } @Override - public void modifyStatement(int parameterIndex, PreparedStatement statement) throws SQLException + public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) + throws SQLException { if (!UserRole.LOCAL.equals(user.getRole())) { switch (user.getOrganizationType()) { case MeDIC: - if (parameterIndex == 1) + if (subqueryParameterIndex == 1) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-medic\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().getValue() + "\"}}]"); - else if (parameterIndex == 2) + else if (subqueryParameterIndex == 2) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-medic\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().toVersionless().getValue() + "\"}}]"); break; case TTP: - if (parameterIndex == 1) + if (subqueryParameterIndex == 1) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-ttp\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().getValue() + "\"}}]"); - else if (parameterIndex == 2) + else if (subqueryParameterIndex == 2) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-ttp\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().toVersionless().getValue() + "\"}}]"); break; } - if (parameterIndex == 3) + if (subqueryParameterIndex == 3) statement.setString(parameterIndex, user.getOrganization().getIdElement().getValue()); - else if (parameterIndex == 4) + else if (subqueryParameterIndex == 4) statement.setString(parameterIndex, user.getOrganization().getIdElement().toVersionless().getValue()); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/HealthcareServiceUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/HealthcareServiceUserFilter.java index 0e012319c..5616979d1 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/HealthcareServiceUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/HealthcareServiceUserFilter.java @@ -4,8 +4,15 @@ public class HealthcareServiceUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "healthcare_service"; + public HealthcareServiceUserFilter(User user) { - super(user, "healthcare_service"); + super(user, RESOURCE_COLUMN); + } + + public HealthcareServiceUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/LocationUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/LocationUserFilter.java index b174f9230..c5e6c9a01 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/LocationUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/LocationUserFilter.java @@ -4,8 +4,15 @@ public class LocationUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "location"; + public LocationUserFilter(User user) { - super(user, "location"); + super(user, RESOURCE_COLUMN); + } + + public LocationUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/NamingSystemUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/NamingSystemUserFilter.java index b3d186bf9..f706132ba 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/NamingSystemUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/NamingSystemUserFilter.java @@ -4,8 +4,15 @@ public class NamingSystemUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "naming_system"; + public NamingSystemUserFilter(User user) { - super(user, "naming_system"); + super(user, RESOURCE_COLUMN); + } + + public NamingSystemUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/OrganizationUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/OrganizationUserFilter.java index e09d1b9ab..d4036eee5 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/OrganizationUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/OrganizationUserFilter.java @@ -4,8 +4,15 @@ public class OrganizationUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "organization"; + public OrganizationUserFilter(User user) { - super(user, "organization"); + super(user, RESOURCE_COLUMN); + } + + public OrganizationUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PatientUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PatientUserFilter.java index 2b87ac849..3d32fd22c 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PatientUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PatientUserFilter.java @@ -8,9 +8,16 @@ public class PatientUserFilter extends AbstractUserFilter { + private static final String RESOURCE_COLUMN = "patient"; + public PatientUserFilter(User user) { - super(user); + super(user, RESOURCE_COLUMN); + } + + public PatientUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } @Override @@ -29,7 +36,8 @@ public int getSqlParameterCount() } @Override - public void modifyStatement(int parameterIndex, PreparedStatement statement) throws SQLException + public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) + throws SQLException { // nothing to do } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PractitionerRoleUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PractitionerRoleUserFilter.java index fb2e03dc0..192d34db6 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PractitionerRoleUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PractitionerRoleUserFilter.java @@ -8,9 +8,16 @@ public class PractitionerRoleUserFilter extends AbstractUserFilter { + private static String RESOURCE_COLUMN = "practitioner_role"; + public PractitionerRoleUserFilter(User user) { - super(user); + super(user, RESOURCE_COLUMN); + } + + public PractitionerRoleUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } @Override @@ -22,8 +29,9 @@ public String getFilterQuery() // user part of PractitionerRoles Organization or // PractitionerRoles Practitioner part of ResearchStudy as principal investigator and // users Organization part of ResearchStudy - return "(practitioner_role->'organization'->>'reference' = ? OR practitioner_role->'organization'->>'reference' = ? OR " - + "practitioner_role->'practitioner'->>'reference' IN (SELECT research_study->'principalInvestigator'->>'reference' FROM " + return "(" + resourceColumn + "->'organization'->>'reference' = ? OR " + resourceColumn + + "->'organization'->>'reference' = ? OR " + resourceColumn + + "->'practitioner'->>'reference' IN (SELECT research_study->'principalInvestigator'->>'reference' FROM " + "current_research_studies WHERE current_research_studies WHERE research_study->'extension' @> ?::jsonb OR research_study->'extension' @> ?::jsonb))"; } @@ -34,34 +42,35 @@ public int getSqlParameterCount() } @Override - public void modifyStatement(int parameterIndex, PreparedStatement statement) throws SQLException + public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) + throws SQLException { if (!UserRole.LOCAL.equals(user.getRole())) { - if (parameterIndex == 1) + if (subqueryParameterIndex == 1) statement.setString(parameterIndex, user.getOrganization().getIdElement().getValue()); - else if (parameterIndex == 2) + else if (subqueryParameterIndex == 2) statement.setString(parameterIndex, user.getOrganization().getIdElement().toVersionless().getValue()); switch (user.getOrganizationType()) { case MeDIC: - if (parameterIndex == 3) + if (subqueryParameterIndex == 3) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-medic\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().getValue() + "\"}}]"); - else if (parameterIndex == 4) + else if (subqueryParameterIndex == 4) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-medic\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().toVersionless().getValue() + "\"}}]"); break; - + case TTP: - if (parameterIndex == 3) + if (subqueryParameterIndex == 3) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-ttp\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().getValue() + "\"}}]"); - else if (parameterIndex == 4) + else if (subqueryParameterIndex == 4) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-ttp\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().toVersionless().getValue() + "\"}}]"); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PractitionerUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PractitionerUserFilter.java index 1402f74a1..ac08aecb3 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PractitionerUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/PractitionerUserFilter.java @@ -8,9 +8,16 @@ public class PractitionerUserFilter extends AbstractUserFilter { + private static final String RESOURCE_COLUMN = "practitioner"; + public PractitionerUserFilter(User user) { - super(user); + super(user, RESOURCE_COLUMN); + } + + public PractitionerUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } @Override @@ -21,12 +28,12 @@ public String getFilterQuery() else // Practitioner part of ResearchStudy as principal investigator and users Organization part of same // ResearchStudy or - return "(concat('Practitioner/', practitioner->>'id') IN (" + return "(concat('Practitioner/', " + resourceColumn + "->>'id') IN (" + "SELECT research_study->'principalInvestigator'->>'reference' FROM current_research_studies WHERE " + "research_study->'extension' @> ?::jsonb OR research_study->'extension' @> ?::jsonb) OR " // Practitioner part of PractitionerRole and users Organization part of same PractitionerRole - + "concat('Practitioner/', practitioner->>'id') IN (" + + "concat('Practitioner/', " + resourceColumn + "->>'id') IN (" + "SELECT practitioner_role->'practitioner'->>'reference' FROM current_practitioner_roles WHERE " + "practitioner_role->'organization'->>'reference' = ? OR practitioner_role->'organization'->>'reference' = ?))"; } @@ -38,38 +45,39 @@ public int getSqlParameterCount() } @Override - public void modifyStatement(int parameterIndex, PreparedStatement statement) throws SQLException + public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) + throws SQLException { if (!UserRole.LOCAL.equals(user.getRole())) { switch (user.getOrganizationType()) { case MeDIC: - if (parameterIndex == 1) + if (subqueryParameterIndex == 1) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-medic\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().getValue() + "\"}}]"); - else if (parameterIndex == 2) + else if (subqueryParameterIndex == 2) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-medic\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().toVersionless().getValue() + "\"}}]"); break; case TTP: - if (parameterIndex == 1) + if (subqueryParameterIndex == 1) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-ttp\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().getValue() + "\"}}]"); - else if (parameterIndex == 2) + else if (subqueryParameterIndex == 2) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-ttp\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().toVersionless().getValue() + "\"}}]"); break; } - if (parameterIndex == 3) + if (subqueryParameterIndex == 3) statement.setString(parameterIndex, user.getOrganization().getIdElement().getValue()); - else if (parameterIndex == 4) + else if (subqueryParameterIndex == 4) statement.setString(parameterIndex, user.getOrganization().getIdElement().toVersionless().getValue()); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ProvenanceUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ProvenanceUserFilter.java index a8c02b680..27449f55b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ProvenanceUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ProvenanceUserFilter.java @@ -8,9 +8,16 @@ public class ProvenanceUserFilter extends AbstractUserFilter { + private static final String RESOURCE_COLUMN = "provenance"; + public ProvenanceUserFilter(User user) { - super(user); + super(user, RESOURCE_COLUMN); + } + + public ProvenanceUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } @Override @@ -29,7 +36,8 @@ public int getSqlParameterCount() } @Override - public void modifyStatement(int parameterIndex, PreparedStatement statement) throws SQLException + public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) + throws SQLException { // nothing to do } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ResearchStudyUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ResearchStudyUserFilter.java index 90683814d..1e884ca53 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ResearchStudyUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ResearchStudyUserFilter.java @@ -8,9 +8,16 @@ public class ResearchStudyUserFilter extends AbstractUserFilter { + private static final String RESOURCE_COLUMN = "research_study"; + public ResearchStudyUserFilter(User user) { - super(user); + super(user, RESOURCE_COLUMN); + } + + public ResearchStudyUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } @Override @@ -19,7 +26,8 @@ public String getFilterQuery() if (UserRole.LOCAL.equals(user.getRole())) return ""; else - return "(research_study->'extension' @> ?::jsonb OR research_study->'extension' @> ?::jsonb)"; + return "(" + resourceColumn + "->'extension' @> ?::jsonb OR " + resourceColumn + + "->'extension' @> ?::jsonb)"; } @Override @@ -29,29 +37,30 @@ public int getSqlParameterCount() } @Override - public void modifyStatement(int parameterIndex, PreparedStatement statement) throws SQLException + public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) + throws SQLException { if (!UserRole.LOCAL.equals(user.getRole())) { switch (user.getOrganizationType()) { case MeDIC: - if (parameterIndex == 1) + if (subqueryParameterIndex == 1) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-medic\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().getValue() + "\"}}]"); - else if (parameterIndex == 2) + else if (subqueryParameterIndex == 2) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-medic\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().toVersionless().getValue() + "\"}}]"); break; - + case TTP: - if (parameterIndex == 1) + if (subqueryParameterIndex == 1) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-ttp\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().getValue() + "\"}}]"); - else if (parameterIndex == 2) + else if (subqueryParameterIndex == 2) statement.setString(parameterIndex, "[{\"url\":\"http://highmed.org/fhir/StructureDefinition/participating-ttp\",\"valueReference\":{\"reference\":\"" + user.getOrganization().getIdElement().toVersionless().getValue() + "\"}}]"); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/StructureDefinitionSnapshotUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/StructureDefinitionSnapshotUserFilter.java index 96f0dc08a..5745a18e1 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/StructureDefinitionSnapshotUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/StructureDefinitionSnapshotUserFilter.java @@ -4,8 +4,15 @@ public class StructureDefinitionSnapshotUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "structure_definition_snapshot"; + public StructureDefinitionSnapshotUserFilter(User user) { - super(user, "structure_definition_snapshot"); + super(user, RESOURCE_COLUMN); + } + + public StructureDefinitionSnapshotUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/StructureDefinitionUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/StructureDefinitionUserFilter.java index 90820fc98..3ea8bc31c 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/StructureDefinitionUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/StructureDefinitionUserFilter.java @@ -4,8 +4,15 @@ public class StructureDefinitionUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "structure_definition"; + public StructureDefinitionUserFilter(User user) { - super(user, "structure_definition"); + super(user, RESOURCE_COLUMN); + } + + public StructureDefinitionUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/SubscriptionUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/SubscriptionUserFilter.java index 1277f0f3f..99d07dc2a 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/SubscriptionUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/SubscriptionUserFilter.java @@ -4,8 +4,15 @@ public class SubscriptionUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "subscription"; + public SubscriptionUserFilter(User user) { - super(user, "subscription"); + super(user, RESOURCE_COLUMN); + } + + public SubscriptionUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/TaskUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/TaskUserFilter.java index 5faf6ccaf..290ce8125 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/TaskUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/TaskUserFilter.java @@ -7,16 +7,26 @@ public class TaskUserFilter extends AbstractUserFilter { + private static final String RESOURCE_COLUMN = "task"; + public TaskUserFilter(User user) { - super(user); + super(user, RESOURCE_COLUMN); + } + + public TaskUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } @Override public String getFilterQuery() { - return "(task->'requester'->>'reference' = ? OR task->'requester'->>'reference' = ? OR" - + " task->'restriction'->'recipient' @> ?::jsonb OR task->'restriction'->'recipient' @> ?::jsonb)"; + // TODO modify for requester = Practitioner or PractitionerRole + return "(" + resourceColumn + "->'requester'->>'reference' = ? OR " + resourceColumn + + "->'requester'->>'reference' = ? OR " + resourceColumn + + "->'restriction'->'recipient' @> ?::jsonb OR " + resourceColumn + + "->'restriction'->'recipient' @> ?::jsonb)"; } @Override @@ -26,16 +36,17 @@ public int getSqlParameterCount() } @Override - public void modifyStatement(int parameterIndex, PreparedStatement statement) throws SQLException + public void modifyStatement(int parameterIndex, int subqueryParameterIndex, PreparedStatement statement) + throws SQLException { - if (parameterIndex == 1) + if (subqueryParameterIndex == 1) statement.setString(parameterIndex, user.getOrganization().getIdElement().getValue()); - else if (parameterIndex == 2) + else if (subqueryParameterIndex == 2) statement.setString(parameterIndex, user.getOrganization().getIdElement().toVersionless().getValue()); - else if (parameterIndex == 3) + else if (subqueryParameterIndex == 3) statement.setString(parameterIndex, "[{\"reference\": \"" + user.getOrganization().getIdElement().getValue() + "\"}]"); - else if (parameterIndex == 4) + else if (subqueryParameterIndex == 4) statement.setString(parameterIndex, "[{\"reference\": \"" + user.getOrganization().getIdElement().toVersionless().getValue() + "\"}]"); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ValueSetUserFilter.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ValueSetUserFilter.java index 4b047365c..901d82052 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ValueSetUserFilter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/search/parameters/user/ValueSetUserFilter.java @@ -4,8 +4,15 @@ public class ValueSetUserFilter extends AbstractMetaTagAuthorizationRoleUserFilter { + private static final String RESOURCE_COLUMN = "value_set"; + public ValueSetUserFilter(User user) { - super(user, "value_set"); + super(user, RESOURCE_COLUMN); + } + + public ValueSetUserFilter(User user, String resourceColumn) + { + super(user, resourceColumn); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/DefaultProfileValidationSupportWithCustomResources.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/DefaultProfileValidationSupportWithCustomResources.java deleted file mode 100755 index 045c470a4..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/DefaultProfileValidationSupportWithCustomResources.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.highmed.dsf.fhir.service; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport; -import org.hl7.fhir.r4.model.CodeSystem; -import org.hl7.fhir.r4.model.StructureDefinition; -import org.hl7.fhir.r4.model.ValueSet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import ca.uhn.fhir.context.FhirContext; - -public class DefaultProfileValidationSupportWithCustomResources extends DefaultProfileValidationSupport -{ - private static final Logger logger = LoggerFactory - .getLogger(DefaultProfileValidationSupportWithCustomResources.class); - - private final Map structureDefinitionsByUrl = new HashMap<>(); - private final Map codeSystemsByUrl = new HashMap<>(); - private final Map valueSetsByUrl = new HashMap<>(); - - public DefaultProfileValidationSupportWithCustomResources() - { - } - - public DefaultProfileValidationSupportWithCustomResources( - Collection structureDefinitions, - Collection codeSystems, Collection valueSets) - { - structureDefinitions.forEach(s -> structureDefinitionsByUrl.put(s.getUrl(), s)); - codeSystems.forEach(s -> codeSystemsByUrl.put(s.getUrl(), s)); - valueSets.forEach(s -> valueSetsByUrl.put(s.getUrl(), s)); - } - - @Override - public List fetchAllStructureDefinitions(FhirContext context) - { - logger.trace("Fetching all StructureDefinitions"); - - var sD = new ArrayList<>(structureDefinitionsByUrl.values()); - sD.addAll(super.fetchAllStructureDefinitions(context)); - return sD; - } - - @Override - public StructureDefinition fetchStructureDefinition(FhirContext context, String url) - { - logger.trace("Fetching StructureDefinition by url: {}", url); - - var sD = structureDefinitionsByUrl.getOrDefault(url, null); - - if (sD != null) - return sD; - else - return super.fetchStructureDefinition(context, url); - } - - public void addOrReplaceStructureDefinition(StructureDefinition s) - { - structureDefinitionsByUrl.put(s.getUrl(), s); - } - - @Override - public CodeSystem fetchCodeSystem(FhirContext context, String url) - { - logger.trace("Fetching CodeSystem by url: {}", url); - - var cS = codeSystemsByUrl.getOrDefault(url, null); - - if (cS != null) - return cS; - else - return super.fetchCodeSystem(context, url); - } - - public void addOrReplaceCodeSystem(CodeSystem s) - { - codeSystemsByUrl.put(s.getUrl(), s); - } - - @Override - public ValueSet fetchValueSet(FhirContext context, String url) - { - logger.trace("Fetching ValueSet by url: {}", url); - - var vS = valueSetsByUrl.getOrDefault(url, null); - - if (vS != null) - return vS; - else - return super.fetchValueSet(context, url); - } - - public void addOrReplaceValueSet(ValueSet s) - { - valueSetsByUrl.put(s.getUrl(), s); - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/InitialDataLoaderImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/InitialDataLoaderImpl.java index 40c127294..759cb1c27 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/InitialDataLoaderImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/InitialDataLoaderImpl.java @@ -6,6 +6,8 @@ import org.highmed.dsf.fhir.authentication.UserRole; import org.highmed.dsf.fhir.dao.command.CommandFactory; import org.highmed.dsf.fhir.dao.command.CommandList; +import org.highmed.dsf.fhir.prefer.PreferHandlingType; +import org.highmed.dsf.fhir.prefer.PreferReturnType; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Organization; @@ -45,7 +47,8 @@ public void load(Bundle bundle) } CommandList commands = commandFactory.createCommands(bundle, - new User(new Organization().setName("Initial Data Loader"), UserRole.LOCAL)); + new User(new Organization().setName("Initial Data Loader"), UserRole.LOCAL), PreferReturnType.MINIMAL, + PreferHandlingType.STRICT); logger.debug("Executing command list for bundle with {} entries", bundle.getEntry().size()); Bundle result = commands.execute(); result.getEntry().forEach(this::logResult); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ReferenceResolver.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ReferenceResolver.java index 48372a377..c0bc9e7d6 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ReferenceResolver.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ReferenceResolver.java @@ -1,48 +1,14 @@ package org.highmed.dsf.fhir.service; import java.sql.Connection; -import java.util.List; import java.util.Optional; -import javax.ws.rs.WebApplicationException; - import org.highmed.dsf.fhir.authentication.User; -import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.Resource; public interface ReferenceResolver { - /** - * @param user - * not null - * @param referenceLocation - * @param reference - * not null - * @param referenceTypes - * @return {@link Optional#empty()} if the reference could not be resolved - * @throws IllegalArgumentException - * if the reference is not of type {@link ResourceReference.ReferenceType#LITERAL_INTERNAL}, - * {@link ResourceReference.ReferenceType#LITERAL_EXTERNAL}, - * {@link ResourceReference.ReferenceType#CONDITIONAL} or - * {@link ResourceReference.ReferenceType#LOGICAL} - */ - Optional resolveReference(User user, String referenceLocation, Reference reference, - List> referenceTypes); - - /** - * @param user - * not null - * @param reference - * not null - * @return {@link Optional#empty()} if the reference could not be resolved - * @throws IllegalArgumentException - * if the reference is not of type {@link ResourceReference.ReferenceType#LITERAL_INTERNAL}, - * {@link ResourceReference.ReferenceType#LITERAL_EXTERNAL}, - * {@link ResourceReference.ReferenceType#CONDITIONAL} or - * {@link ResourceReference.ReferenceType#LOGICAL} - */ - Optional resolveReference(User user, ResourceReference reference); - /** * @param user * not null @@ -60,51 +26,19 @@ Optional resolveReference(User user, String referenceLocation, Referen Optional resolveReference(User user, ResourceReference reference, Connection connection); /** - * @param user - * not null * @param resource * not null * @param resourceReference * not null * @param connection * not null - * @return true if the resource was changed by resolving the reference (always returns - * false for literal references) - * @throws WebApplicationException - * if the reference could not be resolved + * @return {@link Optional#empty()} if the reference could be resolved * @throws IllegalArgumentException - * if the reference is not of type {@link ResourceReference.ReferenceType#LITERAL_INTERNAL}, - * {@link ResourceReference.ReferenceType#LITERAL_EXTERNAL}, - * {@link ResourceReference.ReferenceType#CONDITIONAL} or - * {@link ResourceReference.ReferenceType#LOGICAL} - * @see ResourceReference#getType(String) - */ - boolean resolveReference(User user, Resource resource, ResourceReference resourceReference, Connection connection); - - /** - * @param user - * not null - * @param resource - * not null - * @param bundleIndex - * may be null - * @param resourceReference - * not null - * @param connection - * not null - * @return true if the resource was changed by resolving the reference (always returns - * false for literal references) - * @throws WebApplicationException - * if the reference could not be resolved - * @throws IllegalArgumentException - * if the reference is not of type {@link ResourceReference.ReferenceType#LITERAL_INTERNAL}, - * {@link ResourceReference.ReferenceType#LITERAL_EXTERNAL}, - * {@link ResourceReference.ReferenceType#CONDITIONAL} or - * {@link ResourceReference.ReferenceType#LOGICAL} + * if the reference is not of type {@link ResourceReference.ReferenceType#LITERAL_INTERNAL} * @see ResourceReference#getType(String) */ - boolean resolveReference(User user, Resource resource, Integer bundleIndex, ResourceReference resourceReference, - Connection connection) throws WebApplicationException, IllegalArgumentException; + Optional checkLiteralInternalReference(Resource resource, ResourceReference resourceReference, + Connection connection) throws IllegalArgumentException; /** * @param resource @@ -113,36 +47,15 @@ boolean resolveReference(User user, Resource resource, Integer bundleIndex, Reso * not null * @param connection * not null - * @return true if the resource was changed by resolving the reference (always returns - * false for literal references) - * @throws WebApplicationException - * if the reference could not be resolved - * @throws IllegalArgumentException - * if the reference is not of type {@link ResourceReference.ReferenceType#LITERAL_INTERNAL} - * @see ResourceReference#getType(String) - */ - boolean resolveLiteralInternalReference(Resource resource, ResourceReference resourceReference, - Connection connection) throws WebApplicationException, IllegalArgumentException; - - /** - * @param resource - * not null * @param bundleIndex * may be null - * @param resourceReference - * not null - * @param connection - * not null - * @return true if the resource was changed by resolving the reference (always returns - * false for literal references) - * @throws WebApplicationException - * if the reference could not be resolved + * @return {@link Optional#empty()} if the reference could be resolved * @throws IllegalArgumentException * if the reference is not of type {@link ResourceReference.ReferenceType#LITERAL_INTERNAL} * @see ResourceReference#getType(String) */ - boolean resolveLiteralInternalReference(Resource resource, Integer bundleIndex, ResourceReference resourceReference, - Connection connection) throws WebApplicationException; + Optional checkLiteralInternalReference(Resource resource, ResourceReference resourceReference, + Connection connection, Integer bundleIndex) throws IllegalArgumentException; /** * @param resource @@ -151,35 +64,30 @@ boolean resolveLiteralInternalReference(Resource resource, Integer bundleIndex, * not null * @param connection * not null - * @return true if the resource was changed by resolving the reference (always returns - * false for literal references) - * @throws WebApplicationException - * if the reference could not be resolved + * @return * @throws IllegalArgumentException * if the reference is not of type {@link ResourceReference.ReferenceType#LITERAL_EXTERNAL} * @see ResourceReference#getType(String) */ - boolean resolveLiteralExternalReference(Resource resource, ResourceReference resourceReference); + Optional checkLiteralExternalReference(Resource resource, ResourceReference resourceReference) + throws IllegalArgumentException; /** * @param resource * not null - * @param bundleIndex - * may be null * @param resourceReference * not null * @param connection * not null - * @return true if the resource was changed by resolving the reference (always returns - * false for literal references) - * @throws WebApplicationException - * if the reference could not be resolved + * @param bundleIndex + * may be null + * @return * @throws IllegalArgumentException * if the reference is not of type {@link ResourceReference.ReferenceType#LITERAL_EXTERNAL} * @see ResourceReference#getType(String) */ - boolean resolveLiteralExternalReference(Resource resource, Integer bundleIndex, ResourceReference resourceReference) - throws WebApplicationException, IllegalArgumentException; + Optional checkLiteralExternalReference(Resource resource, ResourceReference resourceReference, + Integer bundleIndex) throws IllegalArgumentException; /** * @param user @@ -190,39 +98,16 @@ boolean resolveLiteralExternalReference(Resource resource, Integer bundleIndex, * not null * @param connection * not null - * @return true if the resource was changed by resolving the reference (always returns - * false for literal references) - * @throws WebApplicationException - * if the reference could not be resolved - * @throws IllegalArgumentException - * if the reference is not of type {@link ResourceReference.ReferenceType#CONDITIONAL} - * @see ResourceReference#getType(String) - */ - boolean resolveConditionalReference(User user, Resource resource, ResourceReference resourceReference, - Connection connection) throws WebApplicationException, IllegalArgumentException; - - /** - * @param user - * not null - * @param resource - * not null * @param bundleIndex * may be null - * @param resourceReference - * not null - * @param connection - * not null - * @return true if the resource was changed by resolving the reference (always returns - * false for literal references) - * @throws WebApplicationException - * if the reference could not be resolved + * @return * @throws IllegalArgumentException * if the reference is not of type {@link ResourceReference.ReferenceType#CONDITIONAL} * @see ResourceReference#getType(String) */ - boolean resolveConditionalReference(User user, Resource resource, Integer bundleIndex, - ResourceReference resourceReference, Connection connection) - throws WebApplicationException, IllegalArgumentException; + Optional checkConditionalReference(User user, Resource resource, + ResourceReference resourceReference, Connection connection, Integer bundleIndex) + throws IllegalArgumentException; /** * @param user @@ -233,37 +118,30 @@ boolean resolveConditionalReference(User user, Resource resource, Integer bundle * not null * @param connection * not null - * @return true if the resource was changed by resolving the reference (always returns - * false for literal references) - * @throws WebApplicationException - * if the reference could not be resolved + * @return * @throws IllegalArgumentException * if the reference is not of type {@link ResourceReference.ReferenceType#LOGICAL} * @see ResourceReference#getType(String) */ - boolean resolveLogicalReference(User user, Resource resource, ResourceReference resourceReference, - Connection connection) throws WebApplicationException, IllegalArgumentException; + Optional checkLogicalReference(User user, Resource resource, ResourceReference resourceReference, + Connection connection) throws IllegalArgumentException; /** * @param user * not null * @param resource * not null - * @param bundleIndex - * may be null * @param resourceReference * not null * @param connection * not null - * @return true if the resource was changed by resolving the reference (always returns - * false for literal references) - * @throws WebApplicationException - * if the reference could not be resolved + * @param bundleIndex + * may be null + * @return * @throws IllegalArgumentException * if the reference is not of type {@link ResourceReference.ReferenceType#LOGICAL} * @see ResourceReference#getType(String) */ - boolean resolveLogicalReference(User user, Resource resource, Integer bundleIndex, - ResourceReference resourceReference, Connection connection) - throws WebApplicationException, IllegalArgumentException; + Optional checkLogicalReference(User user, Resource resource, ResourceReference resourceReference, + Connection connection, Integer bundleIndex) throws IllegalArgumentException; } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ReferenceResolverImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ReferenceResolverImpl.java index 282ddd1ab..015b825f7 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ReferenceResolverImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ReferenceResolverImpl.java @@ -11,8 +11,6 @@ import java.util.UUID; import java.util.stream.Collectors; -import javax.ws.rs.WebApplicationException; - import org.highmed.dsf.fhir.authentication.User; import org.highmed.dsf.fhir.client.ClientProvider; import org.highmed.dsf.fhir.dao.ResourceDao; @@ -27,7 +25,7 @@ import org.highmed.fhir.client.FhirWebserviceClient; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Identifier; -import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,38 +67,6 @@ public void afterPropertiesSet() throws Exception Objects.requireNonNull(parameterConverter, "parameterConverter"); } - @Override - public Optional resolveReference(User user, String referenceLocation, Reference reference, - List> referenceTypes) - { - Objects.requireNonNull(user, "user"); - Objects.requireNonNull(reference, "reference"); - - return resolveReference(user, new ResourceReference(referenceLocation, reference, referenceTypes)); - } - - @Override - public Optional resolveReference(User user, ResourceReference reference) - { - Objects.requireNonNull(user, "user"); - Objects.requireNonNull(reference, "reference"); - - switch (reference.getType(serverBase)) - { - case LITERAL_INTERNAL: - return resolveLiteralInternalReference(reference, null); - case LITERAL_EXTERNAL: - return resolveLiteralExternalReference(reference); - case CONDITIONAL: - return resolveConditionalReference(user, reference, null); - case LOGICAL: - return resolveLogicalReference(user, reference, null); - default: - throw new IllegalArgumentException( - "Reference of type " + reference.getType(serverBase) + " not supported"); - } - } - @Override public Optional resolveReference(User user, ResourceReference reference, Connection connection) { @@ -108,7 +74,8 @@ public Optional resolveReference(User user, ResourceReference referenc Objects.requireNonNull(reference, "reference"); Objects.requireNonNull(connection, "connection"); - switch (reference.getType(serverBase)) + ReferenceType type = reference.getType(serverBase); + switch (type) { case LITERAL_INTERNAL: return resolveLiteralInternalReference(reference, connection); @@ -119,67 +86,34 @@ public Optional resolveReference(User user, ResourceReference referenc case LOGICAL: return resolveLogicalReference(user, reference, connection); default: - throw new IllegalArgumentException( - "Reference of type " + reference.getType(serverBase) + " not supported"); + throw new IllegalArgumentException("Reference of type " + type + " not supported"); } } - @Override - public boolean resolveReference(User user, Resource resource, ResourceReference resourceReference, - Connection connection) + private Optional resolveLiteralInternalReference(ResourceReference reference, Connection connection) { - return resolveReference(user, resource, null, resourceReference, connection); - } - - @Override - public boolean resolveReference(User user, Resource resource, Integer bundleIndex, - ResourceReference resourceReference, Connection connection) - { - Objects.requireNonNull(user, "user"); - Objects.requireNonNull(resource, "resource"); - Objects.requireNonNull(resourceReference, "resourceReference"); - Objects.requireNonNull(connection, "connection"); - - switch (resourceReference.getType(serverBase)) - { - case LITERAL_INTERNAL: - return resolveLiteralInternalReference(resource, bundleIndex, resourceReference, connection); - case LITERAL_EXTERNAL: - return resolveLiteralExternalReference(resource, bundleIndex, resourceReference); - case CONDITIONAL: - return resolveConditionalReference(user, resource, bundleIndex, resourceReference, connection); - case LOGICAL: - return resolveLogicalReference(user, resource, bundleIndex, resourceReference, connection); - default: - throw new IllegalArgumentException( - "Reference of type " + resourceReference.getType(serverBase) + " not supported"); - } - } + Objects.requireNonNull(reference, "reference"); - private Optional resolveLiteralInternalReference(ResourceReference resourceReference, - Connection connection) - { - Objects.requireNonNull(resourceReference, "resourceReference"); - if (!ReferenceType.LITERAL_INTERNAL.equals(resourceReference.getType(serverBase))) + ReferenceType type = reference.getType(serverBase); + if (!ReferenceType.LITERAL_INTERNAL.equals(type)) throw new IllegalArgumentException("Not a literal internal reference"); - IdType id = new IdType(resourceReference.getReference().getReference()); + IdType id = new IdType(reference.getReference().getReference()); Optional> referenceDao = daoProvider.getDao(id.getResourceType()); if (referenceDao.isEmpty()) { logger.warn("Reference target type of reference at {} not supported by this implementation", - resourceReference.getReferenceLocation()); + reference.getReferenceLocation()); return Optional.empty(); } else { @SuppressWarnings("unchecked") ResourceDao d = (ResourceDao) referenceDao.get(); - if (!resourceReference.supportsType(d.getResourceType())) + if (!reference.supportsType(d.getResourceType())) { - logger.warn("Reference target type of reference at {} not supported", - resourceReference.getReferenceLocation()); + logger.warn("Reference target type of reference at {} not supported", reference.getReferenceLocation()); return Optional.empty(); } @@ -204,68 +138,29 @@ private Optional resolveLiteralInternalReference(ResourceReference res } } - @Override - public boolean resolveLiteralInternalReference(Resource resource, ResourceReference resourceReference, - Connection connection) throws WebApplicationException, IllegalArgumentException - { - return resolveLiteralInternalReference(resource, null, resourceReference, connection); - } - - @Override - public boolean resolveLiteralInternalReference(Resource resource, Integer bundleIndex, - ResourceReference resourceReference, Connection connection) - throws WebApplicationException, IllegalArgumentException + private Optional resolveLiteralExternalReference(ResourceReference reference) { - Objects.requireNonNull(resource, "resource"); - Objects.requireNonNull(resourceReference, "resourceReference"); - Objects.requireNonNull(connection, "connection"); - if (!ReferenceType.LITERAL_INTERNAL.equals(resourceReference.getType(serverBase))) - throw new IllegalArgumentException("Not a literal internal reference"); - - IdType id = new IdType(resourceReference.getReference().getReference()); - Optional> referenceDao = daoProvider.getDao(id.getResourceType()); - - if (referenceDao.isEmpty()) - throw new WebApplicationException(responseGenerator - .referenceTargetTypeNotSupportedByImplementation(bundleIndex, resource, resourceReference)); - else - { - ResourceDao d = referenceDao.get(); - if (!resourceReference.supportsType(d.getResourceType())) - throw new WebApplicationException(responseGenerator - .referenceTargetTypeNotSupportedByResource(bundleIndex, resource, resourceReference)); - - boolean exists = exceptionHandler.handleSqlException( - () -> d.existsNotDeletedWithTransaction(connection, id.getIdPart(), id.getVersionIdPart())); - if (!exists) - throw new WebApplicationException( - responseGenerator.referenceTargetNotFoundLocally(bundleIndex, resource, resourceReference)); - } - - return false; // throws exception if reference could not be resolved - } + Objects.requireNonNull(reference, "reference"); - private Optional resolveLiteralExternalReference(ResourceReference resourceReference) - { - Objects.requireNonNull(resourceReference, "resourceReference"); - if (!ReferenceType.LITERAL_EXTERNAL.equals(resourceReference.getType(serverBase))) + ReferenceType type = reference.getType(serverBase); + if (!ReferenceType.LITERAL_EXTERNAL.equals(type)) throw new IllegalArgumentException("Not a literal external reference"); - String remoteServerBase = resourceReference.getServerBase(serverBase); + String remoteServerBase = reference.getServerBase(serverBase); Optional client = clientProvider.getClient(remoteServerBase); if (client.isEmpty()) { logger.warn( "Error while resolving literal external reference {}, no remote client found for server base {}", - resourceReference.getReference().getReference(), remoteServerBase); + reference.getReference().getReference(), remoteServerBase); return Optional.empty(); } else { - IdType referenceId = new IdType(resourceReference.getReference().getReference()); + IdType referenceId = new IdType(reference.getReference().getReference()); logger.debug("Trying to resolve literal external reference {}, at remote server {}", - resourceReference.getReference().getReference(), remoteServerBase); + reference.getReference().getReference(), remoteServerBase); if (!referenceId.hasVersionIdPart()) return Optional.ofNullable(client.get().read(referenceId.getResourceType(), referenceId.getIdPart())); @@ -275,65 +170,21 @@ private Optional resolveLiteralExternalReference(ResourceReference res } } - @Override - public boolean resolveLiteralExternalReference(Resource resource, ResourceReference resourceReference) - throws WebApplicationException, IllegalArgumentException - { - return resolveLiteralExternalReference(resource, null, resourceReference); - } - - @Override - public boolean resolveLiteralExternalReference(Resource resource, Integer bundleIndex, - ResourceReference resourceReference) throws WebApplicationException, IllegalArgumentException - { - Objects.requireNonNull(resource, "resource"); - Objects.requireNonNull(resourceReference, "resourceReference"); - if (!ReferenceType.LITERAL_EXTERNAL.equals(resourceReference.getType(serverBase))) - throw new IllegalArgumentException("Not a literal external reference"); - - String remoteServerBase = resourceReference.getServerBase(serverBase); - Optional client = clientProvider.getClient(remoteServerBase); - - if (client.isEmpty()) - { - logger.error( - "Error while resolving literal external reference {}, no remote client found for server base {}", - resourceReference.getReference().getReference(), remoteServerBase); - throw new WebApplicationException(responseGenerator.noEndpointFoundForLiteralExternalReference(bundleIndex, - resource, resourceReference)); - } - else - { - IdType referenceId = new IdType(resourceReference.getReference().getReference()); - logger.debug("Trying to resolve literal external reference {}, at remote server {}", - resourceReference.getReference().getReference(), remoteServerBase); - if (!client.get().exists(referenceId)) - { - logger.error( - "Error while resolving literal external reference {}, resource could not be found on remote server {}", - resourceReference.getReference().getReference(), remoteServerBase); - throw new WebApplicationException(responseGenerator.referenceTargetNotFoundRemote(bundleIndex, resource, - resourceReference, remoteServerBase)); - } - } - - return true; // throws exception if reference could not be resolved - } - - private Optional resolveConditionalReference(User user, ResourceReference resourceReference, + private Optional resolveConditionalReference(User user, ResourceReference reference, Connection connection) { - Objects.requireNonNull(resourceReference, "resourceReference"); - if (!ReferenceType.CONDITIONAL.equals(resourceReference.getType(serverBase))) + Objects.requireNonNull(reference, "reference"); + + ReferenceType type = reference.getType(serverBase); + if (!ReferenceType.CONDITIONAL.equals(type)) throw new IllegalArgumentException("Not a conditional reference"); - UriComponents condition = UriComponentsBuilder.fromUriString(resourceReference.getReference().getReference()) - .build(); + UriComponents condition = UriComponentsBuilder.fromUriString(reference.getReference().getReference()).build(); String path = condition.getPath(); if (path == null || path.isBlank()) { logger.warn("Bad conditional reference target '{}' of reference at {}", - resourceReference.getReference().getReference(), resourceReference.getReferenceLocation()); + reference.getReference().getReference(), reference.getReferenceLocation()); return Optional.empty(); } @@ -342,146 +193,54 @@ private Optional resolveConditionalReference(User user, ResourceRefere if (referenceDao.isEmpty()) { logger.warn("Reference target type of reference at {} not supported by this implementation", - resourceReference.getReferenceLocation()); + reference.getReferenceLocation()); return Optional.empty(); } else { ResourceDao d = referenceDao.get(); - if (!resourceReference.supportsType(d.getResourceType())) + if (!reference.supportsType(d.getResourceType())) { - logger.warn("Reference target type of reference at {} not supported", - resourceReference.getReferenceLocation()); + logger.warn("Reference target type of reference at {} not supported", reference.getReferenceLocation()); return Optional.empty(); } - return search(user, connection, d, resourceReference, condition.getQueryParams(), true); + return search(user, connection, d, reference, condition.getQueryParams(), true); } } - @Override - public boolean resolveConditionalReference(User user, Resource resource, ResourceReference resourceReference, - Connection connection) throws WebApplicationException, IllegalArgumentException - { - return resolveConditionalReference(user, resource, null, resourceReference, connection); - } - - @Override - public boolean resolveConditionalReference(User user, Resource resource, Integer bundleIndex, - ResourceReference resourceReference, Connection connection) - throws WebApplicationException, IllegalArgumentException + private Optional resolveLogicalReference(User user, ResourceReference reference, Connection connection) { - Objects.requireNonNull(user, "user"); - Objects.requireNonNull(resource, "resource"); - Objects.requireNonNull(resourceReference, "resourceReference"); - Objects.requireNonNull(connection, "connection"); - if (!ReferenceType.CONDITIONAL.equals(resourceReference.getType(serverBase))) - throw new IllegalArgumentException("Not a conditional reference"); - - UriComponents condition = UriComponentsBuilder.fromUriString(resourceReference.getReference().getReference()) - .build(); - String path = condition.getPath(); - if (path == null || path.isBlank()) - throw new WebApplicationException( - responseGenerator.referenceTargetBadCondition(bundleIndex, resource, resourceReference)); - - Optional> referenceDao = daoProvider.getDao(path); - - if (referenceDao.isEmpty()) - throw new WebApplicationException(responseGenerator - .referenceTargetTypeNotSupportedByImplementation(bundleIndex, resource, resourceReference)); - else - { - ResourceDao d = referenceDao.get(); - if (!resourceReference.supportsType(d.getResourceType())) - throw new WebApplicationException(responseGenerator - .referenceTargetTypeNotSupportedByResource(bundleIndex, resource, resourceReference)); - - Resource target = search(user, resource, bundleIndex, connection, d, resourceReference, - condition.getQueryParams(), true); - - resourceReference.getReference().setIdentifier(null).setReferenceElement( - new IdType(target.getResourceType().name(), target.getIdElement().getIdPart())); - } - - return true; // throws exception if reference could not be resolved - } + Objects.requireNonNull(reference, "reference"); - private Optional resolveLogicalReference(User user, ResourceReference resourceReference, - Connection connection) - { - Objects.requireNonNull(resourceReference, "resourceReference"); - if (!ReferenceType.LOGICAL.equals(resourceReference.getType(serverBase))) + ReferenceType type = reference.getType(serverBase); + if (!ReferenceType.LOGICAL.equals(type)) throw new IllegalArgumentException("Not a logical reference"); - String targetType = resourceReference.getReference().getType(); + String targetType = reference.getReference().getType(); Optional> referenceDao = daoProvider.getDao(targetType); if (referenceDao.isEmpty()) { logger.warn("Reference target type of reference at {} not supported by this implementation", - resourceReference.getReferenceLocation()); + reference.getReferenceLocation()); return Optional.empty(); } else { ResourceDao d = referenceDao.get(); - if (!resourceReference.supportsType(d.getResourceType())) + if (!reference.supportsType(d.getResourceType())) { logger.warn("Reference target type of reference at {} not supported by this implementation", - resourceReference.getReferenceLocation()); + reference.getReferenceLocation()); return Optional.empty(); } - Identifier targetIdentifier = resourceReference.getReference().getIdentifier(); - return search(user, connection, d, resourceReference, Map.of("identifier", - Collections.singletonList(targetIdentifier.getSystem() + "|" + targetIdentifier.getValue())), true); - } - } - - @Override - public boolean resolveLogicalReference(User user, Resource resource, ResourceReference resourceReference, - Connection connection) throws WebApplicationException, IllegalArgumentException - { - return resolveLogicalReference(user, resource, null, resourceReference, connection); - } - - @Override - public boolean resolveLogicalReference(User user, Resource resource, Integer bundleIndex, - ResourceReference resourceReference, Connection connection) - throws WebApplicationException, IllegalArgumentException - { - Objects.requireNonNull(user, "user"); - Objects.requireNonNull(resource, "resource"); - Objects.requireNonNull(resourceReference, "resourceReference"); - Objects.requireNonNull(connection, "connection"); - if (!ReferenceType.LOGICAL.equals(resourceReference.getType(serverBase))) - throw new IllegalArgumentException("Not a logical reference"); - - String targetType = resourceReference.getReference().getType(); - - Optional> referenceDao = daoProvider.getDao(targetType); - - if (referenceDao.isEmpty()) - throw new WebApplicationException(responseGenerator - .referenceTargetTypeNotSupportedByImplementation(bundleIndex, resource, resourceReference)); - else - { - ResourceDao d = referenceDao.get(); - if (!resourceReference.supportsType(d.getResourceType())) - throw new WebApplicationException(responseGenerator - .referenceTargetTypeNotSupportedByResource(bundleIndex, resource, resourceReference)); - - Identifier targetIdentifier = resourceReference.getReference().getIdentifier(); - Resource target = search(user, resource, bundleIndex, connection, d, resourceReference, Map.of("identifier", + Identifier targetIdentifier = reference.getReference().getIdentifier(); + return search(user, connection, d, reference, Map.of("identifier", Collections.singletonList(targetIdentifier.getSystem() + "|" + targetIdentifier.getValue())), true); - - resourceReference.getReference().setIdentifier(null).setReferenceElement( - new IdType(target.getResourceType().name(), target.getIdElement().getIdPart())); } - - return true; // throws exception if reference could not be resolved } private Optional search(User user, Connection connection, ResourceDao referenceTargetDao, @@ -527,7 +286,7 @@ private Optional search(User user, Connection connection, ResourceDao< return referenceTargetDao.searchWithTransaction(connection, query); }); - if (result.getOverallCount() <= 0) + if (result.getTotal() <= 0) { if (logicalNotConditional) logger.warn("Reference target by identifier '{}|{}' of reference at {} in resource", @@ -535,19 +294,19 @@ private Optional search(User user, Connection connection, ResourceDao< resourceReference.getReference().getIdentifier().getValue(), resourceReference.getReferenceLocation()); else - logger.warn("Reference target by identifier '{}|{}' of reference at {} in resource", - resourceReference.getReference().getIdentifier().getSystem(), - resourceReference.getReference().getIdentifier().getValue(), + logger.warn("Reference target by condition '{}' of reference at {} in resource", + UriComponentsBuilder.newInstance().path(referenceTargetDao.getResourceTypeName()) + .replaceQueryParams(CollectionUtils.toMultiValueMap(queryParameters)).toUriString(), resourceReference.getReferenceLocation()); return Optional.empty(); } - else if (result.getOverallCount() == 1) + else if (result.getTotal() == 1) { return Optional.of(result.getPartialResult().get(0)); } else // if (result.getOverallCount() > 1) { - int overallCount = result.getOverallCount(); + int overallCount = result.getTotal(); if (logicalNotConditional) logger.warn( @@ -557,13 +316,195 @@ else if (result.getOverallCount() == 1) resourceReference.getReferenceLocation()); else logger.warn("Found {} matches for reference target by condition '{}' of reference at {} in resource", - overallCount, queryParameters, resourceReference.getReferenceLocation()); + overallCount, + UriComponentsBuilder.newInstance().path(referenceTargetDao.getResourceTypeName()) + .replaceQueryParams(CollectionUtils.toMultiValueMap(queryParameters)).toUriString(), + resourceReference.getReferenceLocation()); return Optional.empty(); } } - private Resource search(User user, Resource resource, Integer bundleIndex, Connection connection, + @Override + public Optional checkLiteralInternalReference(Resource resource, + ResourceReference resourceReference, Connection connection) throws IllegalArgumentException + { + return checkLiteralInternalReference(resource, resourceReference, connection, null); + } + + @Override + public Optional checkLiteralInternalReference(Resource resource, ResourceReference reference, + Connection connection, Integer bundleIndex) throws IllegalArgumentException + { + Objects.requireNonNull(resource, "resource"); + Objects.requireNonNull(reference, "reference"); + Objects.requireNonNull(connection, "connection"); + + ReferenceType type = reference.getType(serverBase); + if (!ReferenceType.LITERAL_INTERNAL.equals(type)) + throw new IllegalArgumentException("Not a literal internal reference"); + + IdType id = new IdType(reference.getReference().getReference()); + Optional> referenceDao = daoProvider.getDao(id.getResourceType()); + + if (referenceDao.isEmpty()) + return Optional.of(responseGenerator.referenceTargetTypeNotSupportedByImplementation(bundleIndex, resource, + reference)); + else + { + ResourceDao d = referenceDao.get(); + if (!reference.supportsType(d.getResourceType())) + return Optional.of( + responseGenerator.referenceTargetTypeNotSupportedByResource(bundleIndex, resource, reference)); + + boolean exists = exceptionHandler.handleSqlException( + () -> d.existsNotDeletedWithTransaction(connection, id.getIdPart(), id.getVersionIdPart())); + if (!exists) + return Optional.of(responseGenerator.referenceTargetNotFoundLocally(bundleIndex, resource, reference)); + } + + return Optional.empty(); + } + + @Override + public Optional checkLiteralExternalReference(Resource resource, + ResourceReference resourceReference) throws IllegalArgumentException + { + return checkLiteralExternalReference(resource, resourceReference, null); + } + + @Override + public Optional checkLiteralExternalReference(Resource resource, ResourceReference reference, + Integer bundleIndex) throws IllegalArgumentException + { + Objects.requireNonNull(resource, "resource"); + Objects.requireNonNull(reference, "reference"); + + ReferenceType type = reference.getType(serverBase); + if (!ReferenceType.LITERAL_EXTERNAL.equals(type)) + throw new IllegalArgumentException("Not a literal external reference"); + + String remoteServerBase = reference.getServerBase(serverBase); + Optional client = clientProvider.getClient(remoteServerBase); + + if (client.isEmpty()) + { + logger.error( + "Error while resolving literal external reference {}, no remote client found for server base {}", + reference.getReference().getReference(), remoteServerBase); + return Optional + .of(responseGenerator.noEndpointFoundForLiteralExternalReference(bundleIndex, resource, reference)); + } + else + { + IdType referenceId = new IdType(reference.getReference().getReference()); + logger.debug("Trying to resolve literal external reference {}, at remote server {}", + reference.getReference().getReference(), remoteServerBase); + if (!client.get().exists(referenceId)) + { + logger.error( + "Error while resolving literal external reference {}, resource could not be found on remote server {}", + reference.getReference().getReference(), remoteServerBase); + return Optional.of(responseGenerator.referenceTargetNotFoundRemote(bundleIndex, resource, reference, + remoteServerBase)); + } + } + + return Optional.empty(); + } + + @Override + public Optional checkConditionalReference(User user, Resource resource, + ResourceReference reference, Connection connection, Integer bundleIndex) throws IllegalArgumentException + { + Objects.requireNonNull(user, "user"); + Objects.requireNonNull(resource, "resource"); + Objects.requireNonNull(reference, "reference"); + Objects.requireNonNull(connection, "connection"); + + ReferenceType type = reference.getType(serverBase); + if (!ReferenceType.CONDITIONAL.equals(type)) + throw new IllegalArgumentException("Not a conditional reference"); + + UriComponents condition = UriComponentsBuilder.fromUriString(reference.getReference().getReference()).build(); + String path = condition.getPath(); + if (path == null || path.isBlank()) + return Optional.of(responseGenerator.referenceTargetBadCondition(bundleIndex, resource, reference)); + + Optional> referenceDao = daoProvider.getDao(path); + + if (referenceDao.isEmpty()) + return Optional.of(responseGenerator.referenceTargetTypeNotSupportedByImplementation(bundleIndex, resource, + reference)); + else + { + ResourceDao d = referenceDao.get(); + if (!reference.supportsType(d.getResourceType())) + return Optional.of( + responseGenerator.referenceTargetTypeNotSupportedByResource(bundleIndex, resource, reference)); + + // Resource target = + return search(user, resource, bundleIndex, connection, d, reference, condition.getQueryParams(), true); + + // TODO add literal reference for conditional reference somewhere else + // reference.getReference().setIdentifier(null).setReferenceElement( + // new IdType(target.getResourceType().name(), target.getIdElement().getIdPart())); + } + + // return Optional.empty(); + } + + @Override + public Optional checkLogicalReference(User user, Resource resource, + ResourceReference resourceReference, Connection connection) throws IllegalArgumentException + { + return checkLogicalReference(user, resource, resourceReference, connection, null); + } + + @Override + public Optional checkLogicalReference(User user, Resource resource, ResourceReference reference, + Connection connection, Integer bundleIndex) throws IllegalArgumentException + { + Objects.requireNonNull(user, "user"); + Objects.requireNonNull(resource, "resource"); + Objects.requireNonNull(reference, "reference"); + Objects.requireNonNull(connection, "connection"); + + ReferenceType type = reference.getType(serverBase); + if (!ReferenceType.LOGICAL.equals(type)) + throw new IllegalArgumentException("Not a logical reference"); + + String targetType = reference.getReference().getType(); + + Optional> referenceDao = daoProvider.getDao(targetType); + + if (referenceDao.isEmpty()) + return Optional.of(responseGenerator.referenceTargetTypeNotSupportedByImplementation(bundleIndex, resource, + reference)); + else + { + ResourceDao d = referenceDao.get(); + if (!reference.supportsType(d.getResourceType())) + return Optional.of( + responseGenerator.referenceTargetTypeNotSupportedByResource(bundleIndex, resource, reference)); + + Identifier targetIdentifier = reference.getReference().getIdentifier(); + // Resource target = + return search(user, resource, bundleIndex, connection, d, reference, Map.of("identifier", + Collections.singletonList(targetIdentifier.getSystem() + "|" + targetIdentifier.getValue())), true); + + // resourceReference.getReference().setIdentifier(null).setReferenceElement( + // new IdType(target.getResourceType().name(), target.getIdElement().getIdPart())); + + // TODO add literal reference for logical reference somewhere else + // reference.getReference().setReferenceElement( + // new IdType(target.getResourceType().name(), target.getIdElement().getIdPart())); + } + + // return Optional.empty(); + } + + private Optional search(User user, Resource resource, Integer bundleIndex, Connection connection, ResourceDao referenceTargetDao, ResourceReference resourceReference, Map> queryParameters, boolean logicalNotConditional) { @@ -586,8 +527,8 @@ private Resource search(User user, Resource resource, Integer bundleIndex, Conne List unsupportedQueryParameters = query .getUnsupportedQueryParameters(queryParameters); if (!unsupportedQueryParameters.isEmpty()) - throw new WebApplicationException( - responseGenerator.badReference(logicalNotConditional, bundleIndex, resource, resourceReference, + return Optional + .of(responseGenerator.badReference(logicalNotConditional, bundleIndex, resource, resourceReference, UriComponentsBuilder.newInstance() .replaceQueryParams(CollectionUtils.toMultiValueMap(queryParameters)).toUriString(), unsupportedQueryParameters)); @@ -595,30 +536,28 @@ private Resource search(User user, Resource resource, Integer bundleIndex, Conne PartialResult result = exceptionHandler .handleSqlException(() -> referenceTargetDao.searchWithTransaction(connection, query)); - if (result.getOverallCount() <= 0) + if (result.getTotal() <= 0) { if (logicalNotConditional) - throw new WebApplicationException(responseGenerator - .referenceTargetNotFoundLocallyByIdentifier(bundleIndex, resource, resourceReference)); + return Optional.of(responseGenerator.referenceTargetNotFoundLocallyByIdentifier(bundleIndex, resource, + resourceReference)); else - throw new WebApplicationException(responseGenerator.referenceTargetNotFoundLocallyByCondition( - bundleIndex, resource, resourceReference, UriComponentsBuilder.newInstance() - .replaceQueryParams(CollectionUtils.toMultiValueMap(queryParameters)).toUriString())); + return Optional.of(responseGenerator.referenceTargetNotFoundLocallyByCondition(bundleIndex, resource, + resourceReference)); } - else if (result.getOverallCount() == 1) + else if (result.getTotal() == 1) { - return result.getPartialResult().get(0); + // return result.getPartialResult().get(0); + return Optional.empty(); } else // if (result.getOverallCount() > 1) { if (logicalNotConditional) - throw new WebApplicationException(responseGenerator.referenceTargetMultipleMatchesLocallyByIdentifier( - bundleIndex, resource, resourceReference, result.getOverallCount())); + return Optional.of(responseGenerator.referenceTargetMultipleMatchesLocallyByIdentifier(bundleIndex, + resource, resourceReference, result.getTotal())); else - throw new WebApplicationException(responseGenerator.referenceTargetMultipleMatchesLocallyByCondition( - bundleIndex, resource, resourceReference, result.getOverallCount(), - UriComponentsBuilder.newInstance() - .replaceQueryParams(CollectionUtils.toMultiValueMap(queryParameters)).toUriString())); + return Optional.of(responseGenerator.referenceTargetMultipleMatchesLocallyByCondition(bundleIndex, + resource, resourceReference, result.getTotal())); } } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ResourceValidatorImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ResourceValidatorImpl.java index bb54f3857..4075cbc57 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ResourceValidatorImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ResourceValidatorImpl.java @@ -1,10 +1,10 @@ package org.highmed.dsf.fhir.service; -import org.hl7.fhir.r4.hapi.ctx.IValidationSupport; -import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator; +import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; import org.hl7.fhir.r4.model.Resource; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.ValidationResult; @@ -19,9 +19,7 @@ public ResourceValidatorImpl(FhirContext context, IValidationSupport validationS protected FhirValidator configureValidator(FhirValidator validator, IValidationSupport validationSupport) { - FhirInstanceValidator instanceValidator = new FhirInstanceValidator(); - instanceValidator.setValidationSupport(validationSupport); - + FhirInstanceValidator instanceValidator = new FhirInstanceValidator(validationSupport); validator.registerValidatorModule(instanceValidator); return validator; } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotDependencies.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotDependencies.java deleted file mode 100755 index a7097ee88..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotDependencies.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.highmed.dsf.fhir.service; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class SnapshotDependencies -{ - private final List profiles = new ArrayList<>(); - private final List targetProfiles = new ArrayList<>(); - - @JsonCreator - public SnapshotDependencies(@JsonProperty("profiles") List profiles, - @JsonProperty("targetProfiles") List targetProfiles) - { - if (profiles != null) - this.profiles.addAll(profiles); - if (targetProfiles != null) - this.targetProfiles.addAll(targetProfiles); - } - - public List getProfiles() - { - return Collections.unmodifiableList(profiles); - } - - public List getTargetProfiles() - { - return Collections.unmodifiableList(targetProfiles); - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotDependencyAnalyzer.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotDependencyAnalyzer.java deleted file mode 100755 index 58b25f675..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotDependencyAnalyzer.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.highmed.dsf.fhir.service; - -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -import org.hl7.fhir.r4.model.CanonicalType; -import org.hl7.fhir.r4.model.ElementDefinition; -import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent; -import org.hl7.fhir.r4.model.StructureDefinition; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SnapshotDependencyAnalyzer -{ - private static final Logger logger = LoggerFactory.getLogger(SnapshotDependencyAnalyzer.class); - - public SnapshotDependencies analyzeSnapshotDependencies(StructureDefinition structureDefinition) - { - Objects.requireNonNull(structureDefinition, "structureDefinition"); - if (!structureDefinition.hasSnapshot()) - throw new IllegalArgumentException("StructureDefinition with snapshot expected"); - - logger.debug("Analyzing profile dependencies of StructureDefinition if id {} and url {}", - structureDefinition.getIdElement().getIdPart(), structureDefinition.getUrl()); - - Set profiles = new HashSet<>(), targetProfiles = new HashSet<>(); - for (ElementDefinition element : structureDefinition.getSnapshot().getElement()) - { - if (element.getType().stream().filter(t -> !t.getProfile().isEmpty() || !t.getTargetProfile().isEmpty()) - .findAny().isPresent()) - { - for (TypeRefComponent type : element.getType()) - { - for (CanonicalType profile : type.getProfile()) - profiles.add(profile.getValue()); - - for (CanonicalType targetProfile : type.getTargetProfile()) - targetProfiles.add(targetProfile.getValue()); - } - } - } - - List profilesList = profiles.stream().sorted().collect(Collectors.toList()); - logger.debug("Profile dependencies: {}", targetProfiles); - List targetProfilesList = targetProfiles.stream().sorted().collect(Collectors.toList()); - logger.debug("TargetProfile dependencies: {}", targetProfilesList); - - return new SnapshotDependencies(profilesList, targetProfilesList); - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotGenerator.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotGenerator.java index 81cfaafa8..d8afa6387 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotGenerator.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotGenerator.java @@ -28,8 +28,8 @@ public List getMessages() return messages; } } - + SnapshotWithValidationMessages generateSnapshot(StructureDefinition differential); - SnapshotWithValidationMessages generateSnapshot(String baseAbsoluteUrlPrefix, StructureDefinition differential); + SnapshotWithValidationMessages generateSnapshot(StructureDefinition differential, String baseAbsoluteUrlPrefix); } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotGeneratorImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotGeneratorImpl.java index 937b0ca18..c2eb107d0 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotGeneratorImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotGeneratorImpl.java @@ -2,19 +2,18 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; -import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.r4.conformance.ProfileUtilities; import org.hl7.fhir.r4.context.IWorkerContext; import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext; -import org.hl7.fhir.r4.hapi.ctx.IValidationSupport; import org.hl7.fhir.r4.model.StructureDefinition; -import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionMappingComponent; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; public class SnapshotGeneratorImpl implements SnapshotGenerator { @@ -29,63 +28,35 @@ public SnapshotGeneratorImpl(FhirContext fhirContext, IValidationSupport validat protected HapiWorkerContext createWorker(FhirContext context, IValidationSupport validationSupport) { - return new HapiWorkerContext(context, validationSupport); + HapiWorkerContext workerContext = new HapiWorkerContext(context, validationSupport); + workerContext.setLocale(context.getLocalizer().getLocale()); + return workerContext; } @Override public SnapshotWithValidationMessages generateSnapshot(StructureDefinition differential) { - return generateSnapshot("", differential); + return generateSnapshot(differential, ""); } @Override - public SnapshotWithValidationMessages generateSnapshot(String baseAbsoluteUrlPrefix, - StructureDefinition differential) + public SnapshotWithValidationMessages generateSnapshot(StructureDefinition differential, + String baseAbsoluteUrlPrefix) { - logger.debug("Generating snapshot for StructureDefinition with id {}, url {}, version {}", - differential.getIdElement().getIdPart(), differential.getUrl(), differential.getVersion()); + Objects.requireNonNull(differential, "differential"); - StructureDefinition base = worker.fetchTypeDefinition(differential.getType()); + logger.debug("Generating snapshot for StructureDefinition with id {}, url {}, version {}, base {}", + differential.getIdElement().getIdPart(), differential.getUrl(), differential.getVersion(), + differential.getBaseDefinition()); + + StructureDefinition base = worker.fetchResource(StructureDefinition.class, differential.getBaseDefinition()); + + if (base == null) + logger.warn("Base definition with url {} not found", differential.getBaseDefinition()); /* ProfileUtilities is not thread safe */ List messages = new ArrayList<>(); - ProfileUtilities profileUtils = new ProfileUtilities(worker, messages, null) - { - @Override - public void updateMaps(StructureDefinition base, StructureDefinition derived) throws DefinitionException - { - if (base == null) - throw new DefinitionException("no base profile provided"); - if (derived == null) - throw new DefinitionException("no derived structure provided"); - - for (StructureDefinitionMappingComponent baseMap : base.getMapping()) - { - boolean found = false; - for (StructureDefinitionMappingComponent derivedMap : derived.getMapping()) - { - /* - * XXX NullPointerException if mapping.uri is null, see original if statement: - * - * if (derivedMap.getUri().equals(baseMap.getUri())) - * - * NPE fix by checking getUri != null - * - * also fixes missing name based matching, via specification rule: StructureDefinition.mapping - * "Must have at least a name or a uri (or both)" - */ - if ((derivedMap.getUri() != null && derivedMap.getUri().equals(baseMap.getUri())) - || (derivedMap.getName() != null && derivedMap.getName().equals(baseMap.getName()))) - { - found = true; - break; - } - } - if (!found) - derived.getMapping().add(baseMap); - } - } - }; + ProfileUtilities profileUtils = new ProfileUtilities(worker, messages, null); profileUtils.generateSnapshot(base, differential, baseAbsoluteUrlPrefix, baseAbsoluteUrlPrefix, null); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotInfo.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotInfo.java deleted file mode 100755 index f4302cf27..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/SnapshotInfo.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.highmed.dsf.fhir.service; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class SnapshotInfo -{ - private final SnapshotDependencies dependencies; - - @JsonCreator - public SnapshotInfo(@JsonProperty("dependencies") SnapshotDependencies dependencies) - { - this.dependencies = dependencies; - } - - public SnapshotDependencies getDependencies() - { - return dependencies; - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/StructureDefinitionReader.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/StructureDefinitionReader.java index 0bb21a828..34b64f29f 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/StructureDefinitionReader.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/StructureDefinitionReader.java @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.hl7.fhir.r4.model.StructureDefinition; @@ -24,7 +25,17 @@ public StructureDefinitionReader(FhirContext context) public List readXml(Path... xmlPaths) { - return Arrays.stream(xmlPaths).map(this::readXml).collect(Collectors.toList()); + return readXml(Arrays.asList(xmlPaths)); + } + + public List readXml(List xmlPaths) + { + return readXml(xmlPaths.stream()).collect(Collectors.toList()); + } + + public Stream readXml(Stream xmlPaths) + { + return xmlPaths.map(this::readXml); } public StructureDefinition readXml(Path xmlPath) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithCache.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithCache.java new file mode 100644 index 000000000..d774cccb7 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithCache.java @@ -0,0 +1,336 @@ +package org.highmed.dsf.fhir.service; + +import java.lang.ref.SoftReference; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.highmed.dsf.fhir.event.Event; +import org.highmed.dsf.fhir.event.EventHandler; +import org.highmed.dsf.fhir.event.ResourceCreatedEvent; +import org.highmed.dsf.fhir.event.ResourceDeletedEvent; +import org.highmed.dsf.fhir.event.ResourceUpdatedEvent; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.ValueSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.ConceptValidationOptions; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.ValueSetExpansionOptions; + +public class ValidationSupportWithCache implements IValidationSupport, EventHandler +{ + private static final Logger logger = LoggerFactory.getLogger(ValidationSupportWithCache.class); + + private final class CacheEntry + { + private final Supplier resourceSupplier; + private SoftReference ref; + + public CacheEntry(R resource, Supplier resourceSupplier) + { + this.ref = new SoftReference<>(resource); + this.resourceSupplier = resourceSupplier; + } + + private SoftReference read() + { + return new SoftReference<>(resourceSupplier.get()); + } + + public R get() + { + if (ref == null || ref.get() == null) + { + ref = read(); + } + + return ref.get(); + } + } + + private final FhirContext context; + private final IValidationSupport delegate; + + private final AtomicBoolean fetchAllStructureDefinitionsDone = new AtomicBoolean(); + private final AtomicBoolean fetchAllConformanceResourcesDone = new AtomicBoolean(); + + private final ConcurrentMap> structureDefinitions = new ConcurrentHashMap<>(); + private final ConcurrentMap> codeSystems = new ConcurrentHashMap<>(); + private final ConcurrentMap> valueSets = new ConcurrentHashMap<>(); + + public ValidationSupportWithCache(FhirContext context, IValidationSupport delegate) + { + this.context = context; + this.delegate = delegate; + } + + public ValidationSupportWithCache populateCache(List cacheValues) + { + logger.trace("populating cache"); + + cacheValues.stream().filter(r -> r instanceof Resource).map(r -> (Resource) r).forEach(this::add); + + fetchAllConformanceResourcesDone.set(true); + fetchAllStructureDefinitionsDone.set(true); + + return this; + } + + @Override + public FhirContext getFhirContext() + { + return context; + } + + @Override + public void handleEvent(Event event) + { + if (event == null) + return; + + logger.trace("handling event {}", event.getClass().getSimpleName()); + + if (event instanceof ResourceCreatedEvent && resourceSupported(event.getResource())) + add(event.getResource()); + else if (event instanceof ResourceDeletedEvent && resourceSupported(event.getResource())) + remove(event.getResource()); + else if (event instanceof ResourceUpdatedEvent && resourceSupported(event.getResource())) + update(event.getResource()); + } + + private boolean resourceSupported(Resource resource) + { + return resource != null && (resource instanceof CodeSystem || resource instanceof StructureDefinition + || resource instanceof ValueSet); + } + + private void add(Resource resource) + { + if (resource instanceof CodeSystem) + doAdd((CodeSystem) resource, codeSystems, CodeSystem::getUrl, CodeSystem::getVersion, + url -> (CodeSystem) delegate.fetchCodeSystem(url)); + else if (resource instanceof StructureDefinition) + doAdd((StructureDefinition) resource, structureDefinitions, StructureDefinition::getUrl, + StructureDefinition::getVersion, + url -> (StructureDefinition) delegate.fetchStructureDefinition(url)); + else if (resource instanceof ValueSet) + doAdd((ValueSet) resource, valueSets, ValueSet::getUrl, ValueSet::getVersion, + url -> (ValueSet) delegate.fetchValueSet(url)); + } + + private void doAdd(R resource, ConcurrentMap> cache, + Function toUrl, Function toVersion, Function fetch) + { + String url = toUrl.apply(resource); + String version = toVersion.apply(resource); + + cache.put(url, new CacheEntry<>(resource, () -> fetch.apply(url))); + + if (version != null) + { + String urlAndVersion = url + "|" + version; + cache.put(urlAndVersion, new CacheEntry<>(resource, () -> fetch.apply(urlAndVersion))); + } + } + + private void update(Resource resource) + { + remove(resource); + add(resource); + } + + private void remove(Resource resource) + { + if (resource instanceof CodeSystem) + doRemove((CodeSystem) resource, codeSystems, CodeSystem::getUrl, CodeSystem::getVersion); + else if (resource instanceof StructureDefinition) + doRemove((StructureDefinition) resource, structureDefinitions, StructureDefinition::getUrl, + StructureDefinition::getVersion); + else if (resource instanceof ValueSet) + doRemove((ValueSet) resource, valueSets, ValueSet::getUrl, ValueSet::getVersion); + } + + private void doRemove(R resource, ConcurrentMap> cache, + Function toUrl, Function toVersion) + { + String url = toUrl.apply(resource); + String version = toVersion.apply(resource); + + cache.remove(url); + cache.remove(url + "|" + version); + } + + public List fetchAllConformanceResources() + { + if (!fetchAllConformanceResourcesDone.get()) + { + logger.trace("Fetching all conformance resources"); + + List allConformanceResources = delegate.fetchAllConformanceResources(); + + allConformanceResources.stream().filter(r -> r instanceof Resource).map(r -> (Resource) r) + .forEach(this::update); + + fetchAllConformanceResourcesDone.set(true); + fetchAllStructureDefinitionsDone.set(true); + + return allConformanceResources; + } + else + { + logger.trace("Fetching all conformance resources from cache"); + + return Stream + .concat(codeSystems.values().stream(), + Stream.concat(structureDefinitions.values().stream(), valueSets.values().stream())) + .map(c -> (IBaseResource) c.get()).collect(Collectors.toList()); + } + } + + @Override + public List fetchAllStructureDefinitions() + { + if (!fetchAllStructureDefinitionsDone.get()) + { + logger.trace("Fetching all structure-definitions"); + + List allStructureDefinitions = delegate.fetchAllStructureDefinitions(); + + allStructureDefinitions.stream().filter(r -> r instanceof Resource).map(r -> (Resource) r) + .forEach(this::update); + + fetchAllStructureDefinitionsDone.set(true); + + return allStructureDefinitions; + } + else + { + logger.trace("Fetching all structure-definitions from cache"); + + @SuppressWarnings("unchecked") + List all = (List) structureDefinitions.values().stream().map(c -> (IBaseResource) c.get()) + .collect(Collectors.toList()); + return all; + } + } + + @Override + public IBaseResource fetchStructureDefinition(String url) + { + logger.trace("Fetiching structure-definition '{}'", url); + + if (url == null || url.isBlank()) + return null; + + return fetch(structureDefinitions, url, () -> (StructureDefinition) delegate.fetchStructureDefinition(url)); + } + + @Override + public boolean isCodeSystemSupported(IValidationSupport theRootValidationSupport, String url) + { + return fetchCodeSystem(url) != null; + } + + @Override + public IBaseResource fetchCodeSystem(String url) + { + logger.trace("Fetiching code-system '{}'", url); + + if (url == null || url.isBlank()) + return null; + + return fetch(codeSystems, url, () -> (CodeSystem) delegate.fetchCodeSystem(url)); + } + + @Override + public boolean isValueSetSupported(IValidationSupport theRootValidationSupport, String url) + { + return fetchValueSet(url) != null; + } + + @Override + public IBaseResource fetchValueSet(String url) + { + logger.trace("Fetiching value-set '{}'", url); + + if (url == null || url.isBlank()) + return null; + + return fetch(valueSets, url, () -> (ValueSet) delegate.fetchValueSet(url)); + } + + private R fetch(ConcurrentMap> cache, String url, Supplier fetch) + { + CacheEntry cacheEntry = cache.get(url); + if (cacheEntry != null) + return cacheEntry.get(); + + R resource = fetch.get(); + if (resource == null) + return null; + + cache.put(url, new CacheEntry<>(resource, fetch)); + return resource; + } + + public ValueSetExpansionOutcome expandValueSet(IValidationSupport theRootValidationSupport, + ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand) + { + return delegate.expandValueSet(theRootValidationSupport, theExpansionOptions, theValueSetToExpand); + } + + public T fetchResource(Class theClass, String theUri) + { + return delegate.fetchResource(theClass, theUri); + } + + public CodeValidationResult validateCode(IValidationSupport theRootValidationSupport, + ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, + String theValueSetUrl) + { + return delegate.validateCode(theRootValidationSupport, theOptions, theCodeSystem, theCode, theDisplay, + theValueSetUrl); + } + + public CodeValidationResult validateCodeInValueSet(IValidationSupport theRootValidationSupport, + ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, + IBaseResource theValueSet) + { + return delegate.validateCodeInValueSet(theRootValidationSupport, theOptions, theCodeSystem, theCode, theDisplay, + theValueSet); + } + + public LookupCodeResult lookupCode(IValidationSupport theRootValidationSupport, String theSystem, String theCode) + { + return delegate.lookupCode(theRootValidationSupport, theSystem, theCode); + } + + public IBaseResource generateSnapshot(IValidationSupport theRootValidationSupport, IBaseResource theInput, + String theUrl, String theWebUrl, String theProfileName) + { + return delegate.generateSnapshot(theRootValidationSupport, theInput, theUrl, theWebUrl, theProfileName); + } + + public void invalidateCaches() + { + codeSystems.clear(); + structureDefinitions.clear(); + valueSets.clear(); + + fetchAllStructureDefinitionsDone.set(false); + fetchAllConformanceResourcesDone.set(false); + + delegate.invalidateCaches(); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithCustomResources.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithCustomResources.java new file mode 100644 index 000000000..8765cae47 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithCustomResources.java @@ -0,0 +1,112 @@ +package org.highmed.dsf.fhir.service; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.ValueSet; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; + +public class ValidationSupportWithCustomResources implements IValidationSupport +{ + private final FhirContext context; + + private final Map structureDefinitionsByUrl = new HashMap<>(); + private final Map codeSystemsByUrl = new HashMap<>(); + private final Map valueSetsByUrl = new HashMap<>(); + + public ValidationSupportWithCustomResources(FhirContext context) + { + this(context, null, null, null); + } + + public ValidationSupportWithCustomResources(FhirContext context, + Collection structureDefinitions, + Collection codeSystems, Collection valueSets) + { + this.context = context; + + if (structureDefinitions != null) + structureDefinitions.forEach(s -> structureDefinitionsByUrl.put(s.getUrl(), s)); + if (codeSystems != null) + codeSystems.forEach(s -> codeSystemsByUrl.put(s.getUrl(), s)); + if (valueSets != null) + valueSets.forEach(s -> valueSetsByUrl.put(s.getUrl(), s)); + } + + @Override + public FhirContext getFhirContext() + { + return context; + } + + @Override + public List fetchAllConformanceResources() + { + return Stream + .concat(codeSystemsByUrl.values().stream(), + Stream.concat(fetchAllStructureDefinitions().stream(), valueSetsByUrl.values().stream())) + .collect(Collectors.toList()); + } + + @SuppressWarnings("unchecked") + @Override + public List fetchAllStructureDefinitions() + { + return new ArrayList<>(structureDefinitionsByUrl.values()); + } + + @Override + public StructureDefinition fetchStructureDefinition(String url) + { + return structureDefinitionsByUrl.getOrDefault(url, null); + } + + public void addOrReplace(StructureDefinition s) + { + structureDefinitionsByUrl.put(s.getUrl(), s); + } + + @Override + public CodeSystem fetchCodeSystem(String url) + { + return codeSystemsByUrl.getOrDefault(url, null); + } + + @Override + public boolean isCodeSystemSupported(IValidationSupport theRootValidationSupport, String url) + { + return codeSystemsByUrl.containsKey(url); + } + + public void addOrReplace(CodeSystem s) + { + codeSystemsByUrl.put(s.getUrl(), s); + } + + @Override + public ValueSet fetchValueSet(String url) + { + return valueSetsByUrl.getOrDefault(url, null); + } + + @Override + public boolean isValueSetSupported(IValidationSupport theRootValidationSupport, String url) + { + return valueSetsByUrl.containsKey(url); + } + + public void addOrReplace(ValueSet s) + { + valueSetsByUrl.put(s.getUrl(), s); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/DefaultProfileValidationSupportWithFetchFromDb.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithFetchFromDb.java old mode 100755 new mode 100644 similarity index 57% rename from dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/DefaultProfileValidationSupportWithFetchFromDb.java rename to dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithFetchFromDb.java index fb3aecce3..ebb2a76ef --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/DefaultProfileValidationSupportWithFetchFromDb.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithFetchFromDb.java @@ -2,16 +2,19 @@ import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.highmed.dsf.fhir.dao.CodeSystemDao; import org.highmed.dsf.fhir.dao.StructureDefinitionDao; -import org.highmed.dsf.fhir.dao.StructureDefinitionSnapshotDao; import org.highmed.dsf.fhir.dao.ValueSetDao; import org.highmed.dsf.fhir.function.SupplierWithSqlException; -import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport; +import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.StructureDefinition; import org.hl7.fhir.r4.model.ValueSet; @@ -20,22 +23,24 @@ import org.springframework.beans.factory.InitializingBean; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; -public class DefaultProfileValidationSupportWithFetchFromDb extends DefaultProfileValidationSupport - implements InitializingBean +public class ValidationSupportWithFetchFromDb implements IValidationSupport, InitializingBean { - private static final Logger logger = LoggerFactory.getLogger(DefaultProfileValidationSupportWithFetchFromDb.class); + private static final Logger logger = LoggerFactory.getLogger(ValidationSupportWithFetchFromDb.class); + + private final FhirContext context; private final StructureDefinitionDao structureDefinitionDao; - private final StructureDefinitionSnapshotDao structureDefinitionSnapshotDao; + private final StructureDefinitionDao structureDefinitionSnapshotDao; private final CodeSystemDao codeSystemDao; private final ValueSetDao valueSetDao; - public DefaultProfileValidationSupportWithFetchFromDb(FhirContext context, - StructureDefinitionDao structureDefinitionDao, - StructureDefinitionSnapshotDao structureDefinitionSnapshotDao, CodeSystemDao codeSystemDao, - ValueSetDao valueSetDao) + public ValidationSupportWithFetchFromDb(FhirContext context, StructureDefinitionDao structureDefinitionDao, + StructureDefinitionDao structureDefinitionSnapshotDao, CodeSystemDao codeSystemDao, ValueSetDao valueSetDao) { + this.context = context; + this.structureDefinitionDao = structureDefinitionDao; this.structureDefinitionSnapshotDao = structureDefinitionSnapshotDao; this.codeSystemDao = codeSystemDao; @@ -52,19 +57,34 @@ public void afterPropertiesSet() throws Exception } @Override - public List fetchAllStructureDefinitions(FhirContext context) + public FhirContext getFhirContext() { - List structureDefinitions = new ArrayList<>(); - structureDefinitions.addAll(throwRuntimeException(() -> structureDefinitionDao.readAll())); - structureDefinitions.addAll(throwRuntimeException(() -> structureDefinitionSnapshotDao.readAll())); + return context; + } - structureDefinitions.addAll(super.fetchAllStructureDefinitions(context)); + @Override + public List fetchAllConformanceResources() + { + return Stream + .concat(throwRuntimeException(() -> codeSystemDao.readAll()).stream(), + Stream.concat(fetchAllStructureDefinitions().stream(), + throwRuntimeException(() -> valueSetDao.readAll()).stream())) + .collect(Collectors.toList()); + } - return structureDefinitions; + @Override + @SuppressWarnings("unchecked") + public List fetchAllStructureDefinitions() + { + Map byUrl = new HashMap<>(); + throwRuntimeException(() -> structureDefinitionSnapshotDao.readAll()).forEach(s -> byUrl.put(s.getUrl(), s)); + throwRuntimeException(() -> structureDefinitionDao.readAll()).forEach(s -> byUrl.putIfAbsent(s.getUrl(), s)); + + return new ArrayList<>(byUrl.values()); } @Override - public StructureDefinition fetchStructureDefinition(FhirContext context, String url) + public StructureDefinition fetchStructureDefinition(String url) { Optional structureDefinition = null; structureDefinition = throwRuntimeException(() -> structureDefinitionSnapshotDao.readByUrlAndVersion(url)); @@ -75,7 +95,7 @@ public StructureDefinition fetchStructureDefinition(FhirContext context, String if (structureDefinition.isPresent()) return structureDefinition.get(); - return super.fetchStructureDefinition(context, url); + return null; } private R throwRuntimeException(SupplierWithSqlException reader) @@ -92,22 +112,22 @@ private R throwRuntimeException(SupplierWithSqlException reader) } @Override - public CodeSystem fetchCodeSystem(FhirContext context, String url) + public CodeSystem fetchCodeSystem(String url) { Optional codeSystem = throwRuntimeException(() -> codeSystemDao.readByUrlAndVersion(url)); if (codeSystem.isPresent()) return codeSystem.get(); - - return super.fetchCodeSystem(context, url); + else + return null; } @Override - public ValueSet fetchValueSet(FhirContext context, String url) + public ValueSet fetchValueSet(String url) { Optional valueSet = throwRuntimeException(() -> valueSetDao.readByUrlAndVersion(url)); if (valueSet.isPresent()) return valueSet.get(); - - return super.fetchValueSet(context, url); + else + return null; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithFetchFromDbWithTransaction.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithFetchFromDbWithTransaction.java new file mode 100644 index 000000000..aefbf5641 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValidationSupportWithFetchFromDbWithTransaction.java @@ -0,0 +1,145 @@ +package org.highmed.dsf.fhir.service; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.highmed.dsf.fhir.dao.CodeSystemDao; +import org.highmed.dsf.fhir.dao.StructureDefinitionDao; +import org.highmed.dsf.fhir.dao.ValueSetDao; +import org.highmed.dsf.fhir.function.SupplierWithSqlException; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.ValueSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; + +public class ValidationSupportWithFetchFromDbWithTransaction implements IValidationSupport, InitializingBean +{ + private static final Logger logger = LoggerFactory.getLogger(ValidationSupportWithFetchFromDbWithTransaction.class); + + private final FhirContext context; + + private final StructureDefinitionDao structureDefinitionDao; + private final StructureDefinitionDao structureDefinitionSnapshotDao; + private final CodeSystemDao codeSystemDao; + private final ValueSetDao valueSetDao; + + private final Connection connection; + + public ValidationSupportWithFetchFromDbWithTransaction(FhirContext context, + StructureDefinitionDao structureDefinitionDao, StructureDefinitionDao structureDefinitionSnapshotDao, + CodeSystemDao codeSystemDao, ValueSetDao valueSetDao, Connection connection) + { + this.context = context; + + this.structureDefinitionDao = structureDefinitionDao; + this.structureDefinitionSnapshotDao = structureDefinitionSnapshotDao; + this.codeSystemDao = codeSystemDao; + this.valueSetDao = valueSetDao; + + this.connection = connection; + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(structureDefinitionDao, "structureDefinitionDao"); + Objects.requireNonNull(structureDefinitionSnapshotDao, "structureDefinitionSnapshotDao"); + Objects.requireNonNull(codeSystemDao, "codeSystemDao"); + Objects.requireNonNull(valueSetDao, "valueSetDao"); + } + + @Override + public FhirContext getFhirContext() + { + return context; + } + + @Override + public List fetchAllConformanceResources() + { + return Stream + .concat(throwRuntimeException(() -> codeSystemDao.readAllWithTransaction(connection)).stream(), + Stream.concat(fetchAllStructureDefinitions().stream(), + throwRuntimeException(() -> valueSetDao.readAllWithTransaction(connection)).stream())) + .collect(Collectors.toList()); + } + + @Override + @SuppressWarnings("unchecked") + public List fetchAllStructureDefinitions() + { + Map byUrl = new HashMap<>(); + throwRuntimeException(() -> structureDefinitionSnapshotDao.readAllWithTransaction(connection)) + .forEach(s -> byUrl.put(s.getUrl(), s)); + throwRuntimeException(() -> structureDefinitionDao.readAllWithTransaction(connection)) + .forEach(s -> byUrl.putIfAbsent(s.getUrl(), s)); + + return new ArrayList<>(byUrl.values()); + } + + @Override + public StructureDefinition fetchStructureDefinition(String url) + { + Optional structureDefinition = null; + structureDefinition = throwRuntimeException( + () -> structureDefinitionSnapshotDao.readByUrlAndVersionWithTransaction(connection, url)); + if (structureDefinition.isPresent()) + return structureDefinition.get(); + + structureDefinition = throwRuntimeException( + () -> structureDefinitionDao.readByUrlAndVersionWithTransaction(connection, url)); + if (structureDefinition.isPresent()) + return structureDefinition.get(); + + return null; + } + + private R throwRuntimeException(SupplierWithSqlException reader) + { + try + { + return reader.get(); + } + catch (SQLException e) + { + logger.warn("Error while accessing DB", e); + throw new RuntimeException(e); + } + } + + @Override + public CodeSystem fetchCodeSystem(String url) + { + Optional codeSystem = throwRuntimeException( + () -> codeSystemDao.readByUrlAndVersionWithTransaction(connection, url)); + if (codeSystem.isPresent()) + return codeSystem.get(); + else + return null; + } + + @Override + public ValueSet fetchValueSet(String url) + { + Optional valueSet = throwRuntimeException( + () -> valueSetDao.readByUrlAndVersionWithTransaction(connection, url)); + if (valueSet.isPresent()) + return valueSet.get(); + else + return null; + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValueSetExpanderImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValueSetExpanderImpl.java index f52278199..b4e3731fd 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValueSetExpanderImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/service/ValueSetExpanderImpl.java @@ -1,28 +1,45 @@ package org.highmed.dsf.fhir.service; +import java.util.Objects; + import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext; -import org.hl7.fhir.r4.hapi.ctx.IValidationSupport; import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome; +import org.hl7.fhir.r4.terminologies.ValueSetExpanderSimple; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; public class ValueSetExpanderImpl implements ValueSetExpander { - private final HapiWorkerContext worker; + private static final Logger logger = LoggerFactory.getLogger(ValueSetExpanderImpl.class); + + private final HapiWorkerContext workerContext; public ValueSetExpanderImpl(FhirContext fhirContext, IValidationSupport validationSupport) { - worker = createWorker(fhirContext, validationSupport); + workerContext = createWorkerContext(fhirContext, validationSupport); } - protected HapiWorkerContext createWorker(FhirContext context, IValidationSupport validationSupport) + protected HapiWorkerContext createWorkerContext(FhirContext fhirContext, IValidationSupport validationSupport) { - return new HapiWorkerContext(context, validationSupport); + HapiWorkerContext workerContext = new HapiWorkerContext(fhirContext, validationSupport); + workerContext.setLocale(fhirContext.getLocalizer().getLocale()); + return workerContext; } public ValueSetExpansionOutcome expand(ValueSet valueSet) { - return worker.expand(valueSet, null); + Objects.requireNonNull(valueSet, "valueSet"); + + // ValueSetExpanderSimple can't be reused + ValueSetExpanderSimple valueSetExpander = new ValueSetExpanderSimple(workerContext); + + logger.debug("Generating expansion for ValueSet with id {}, url {}, version {}", + valueSet.getIdElement().getIdPart(), valueSet.getUrl(), valueSet.getVersion()); + + return valueSetExpander.expand(valueSet, null); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/AuthorizationConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/AuthorizationConfig.java index ef055b097..0177137fa 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/AuthorizationConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/AuthorizationConfig.java @@ -8,6 +8,7 @@ import org.highmed.dsf.fhir.authorization.ActivityDefinitionAuthorizationRule; import org.highmed.dsf.fhir.authorization.ActivityDefinitionProvider; import org.highmed.dsf.fhir.authorization.ActivityDefinitionProviderImpl; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.authorization.AuthorizationRuleProviderImpl; import org.highmed.dsf.fhir.authorization.BinaryAuthorizationRule; @@ -24,10 +25,33 @@ import org.highmed.dsf.fhir.authorization.PractitionerRoleAuthorizationRule; import org.highmed.dsf.fhir.authorization.ProvenanceAuthorizationRule; import org.highmed.dsf.fhir.authorization.ResearchStudyAuthorizationRule; +import org.highmed.dsf.fhir.authorization.RootAuthorizationRule; import org.highmed.dsf.fhir.authorization.StructureDefinitionAuthorizationRule; import org.highmed.dsf.fhir.authorization.SubscriptionAuthorizationRule; import org.highmed.dsf.fhir.authorization.TaskAuthorizationRule; import org.highmed.dsf.fhir.authorization.ValueSetAuthorizationRule; +import org.highmed.dsf.fhir.dao.command.AuthorizationHelper; +import org.highmed.dsf.fhir.dao.command.AuthorizationHelperImpl; +import org.hl7.fhir.r4.model.ActivityDefinition; +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.Group; +import org.hl7.fhir.r4.model.HealthcareService; +import org.hl7.fhir.r4.model.Location; +import org.hl7.fhir.r4.model.NamingSystem; +import org.hl7.fhir.r4.model.Organization; +import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Practitioner; +import org.hl7.fhir.r4.model.PractitionerRole; +import org.hl7.fhir.r4.model.Provenance; +import org.hl7.fhir.r4.model.ResearchStudy; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.Subscription; +import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.ValueSet; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -77,133 +101,133 @@ public ActivityDefinitionProvider activityDefinitionProvider() } @Bean - public ActivityDefinitionAuthorizationRule activityDefinitionAuthorizationRule() + public AuthorizationRule activityDefinitionAuthorizationRule() { return new ActivityDefinitionAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public BinaryAuthorizationRule binaryAuthorizationRule() + public AuthorizationRule binaryAuthorizationRule() { return new BinaryAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public BundleAuthorizationRule bundleAuthorizationRule() + public AuthorizationRule bundleAuthorizationRule() { return new BundleAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public CodeSystemAuthorizationRule codeSystemAuthorizationRule() + public AuthorizationRule codeSystemAuthorizationRule() { return new CodeSystemAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public EndpointAuthorizationRule endpointAuthorizationRule() + public AuthorizationRule endpointAuthorizationRule() { return new EndpointAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public GroupAuthorizationRule groupAuthorizationRule() + public AuthorizationRule groupAuthorizationRule() { return new GroupAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public HealthcareServiceAuthorizationRule healthcareServiceAuthorizationRule() + public AuthorizationRule healthcareServiceAuthorizationRule() { return new HealthcareServiceAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public LocationAuthorizationRule locationAuthorizationRule() + public AuthorizationRule locationAuthorizationRule() { return new LocationAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public NamingSystemAuthorizationRule namingSystemAuthorizationRule() + public AuthorizationRule namingSystemAuthorizationRule() { return new NamingSystemAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public OrganizationAuthorizationRule organizationAuthorizationRule() + public AuthorizationRule organizationAuthorizationRule() { return new OrganizationAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public PatientAuthorizationRule patientAuthorizationRule() + public AuthorizationRule patientAuthorizationRule() { return new PatientAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public PractitionerAuthorizationRule practitionerAuthorizationRule() + public AuthorizationRule practitionerAuthorizationRule() { return new PractitionerAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public PractitionerRoleAuthorizationRule practitionerRoleAuthorizationRule() + public AuthorizationRule practitionerRoleAuthorizationRule() { return new PractitionerRoleAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public ProvenanceAuthorizationRule provenanceAuthorizationRule() + public AuthorizationRule provenanceAuthorizationRule() { return new ProvenanceAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public ResearchStudyAuthorizationRule researchStudyAuthorizationRule() + public AuthorizationRule researchStudyAuthorizationRule() { return new ResearchStudyAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public StructureDefinitionAuthorizationRule structureDefinitionAuthorizationRule() + public AuthorizationRule structureDefinitionAuthorizationRule() { return new StructureDefinitionAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public SubscriptionAuthorizationRule subscriptionAuthorizationRule() + public AuthorizationRule subscriptionAuthorizationRule() { return new SubscriptionAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); } @Bean - public TaskAuthorizationRule taskAuthorizationRule() + public AuthorizationRule taskAuthorizationRule() { return new TaskAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider(), activityDefinitionProvider()); } @Bean - public ValueSetAuthorizationRule valueSetAuthorizationRule() + public AuthorizationRule valueSetAuthorizationRule() { return new ValueSetAuthorizationRule(daoConfig.daoProvider(), serverBase, referenceConfig.referenceResolver(), organizationProvider()); @@ -220,4 +244,16 @@ public AuthorizationRuleProvider authorizationRuleProvider() researchStudyAuthorizationRule(), structureDefinitionAuthorizationRule(), subscriptionAuthorizationRule(), taskAuthorizationRule(), valueSetAuthorizationRule()); } + + @Bean + public AuthorizationHelper authorizationHelper() + { + return new AuthorizationHelperImpl(authorizationRuleProvider(), helperConfig.responseGenerator()); + } + + @Bean + public AuthorizationRule rootAuthorizationRule() + { + return new RootAuthorizationRule(); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ClientConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ClientConfig.java index 8b3161c99..cdcb09074 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ClientConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ClientConfig.java @@ -70,7 +70,7 @@ public ClientProvider clientProvider() return new ClientProviderImpl(webserviceTrustStore, webserviceKeyStore, webserviceKeyStorePassword, remoteReadTimeout, remoteConnectTimeout, remoteProxyPassword, remoteProxyUsername, - remoteProxySchemeHostPort, fhirConfig.fhirContext(), referenceConfig.referenceExtractor(), + remoteProxySchemeHostPort, fhirConfig.fhirContext(), referenceConfig.referenceCleaner(), daoConfig.endpointDao(), helperConfig.exceptionHandler()); } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/CommandConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/CommandConfig.java index 872dc476b..0e32ad0cd 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/CommandConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/CommandConfig.java @@ -1,13 +1,25 @@ package org.highmed.dsf.fhir.spring.config; -import org.highmed.dsf.fhir.dao.command.AuthorizationHelper; -import org.highmed.dsf.fhir.dao.command.AuthorizationHelperImpl; +import java.sql.Connection; + import org.highmed.dsf.fhir.dao.command.CommandFactory; import org.highmed.dsf.fhir.dao.command.CommandFactoryImpl; +import org.highmed.dsf.fhir.dao.command.TransactionEventHandler; +import org.highmed.dsf.fhir.dao.command.TransactionResources; +import org.highmed.dsf.fhir.dao.command.ValidationHelper; +import org.highmed.dsf.fhir.dao.command.ValidationHelperImpl; +import org.highmed.dsf.fhir.event.EventHandler; +import org.highmed.dsf.fhir.service.ResourceValidatorImpl; +import org.highmed.dsf.fhir.service.SnapshotGenerator; +import org.highmed.dsf.fhir.service.SnapshotGeneratorImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +import ca.uhn.fhir.context.support.IValidationSupport; @Configuration public class CommandConfig @@ -24,33 +36,50 @@ public class CommandConfig @Autowired private HelperConfig helperConfig; - @Autowired - private SnapshotConfig snapshotConfig; - @Autowired private EventConfig eventConfig; @Autowired private ReferenceConfig referenceConfig; + @Autowired + private SnapshotConfig snapshotConfig; + @Autowired private AuthorizationConfig authorizationConfig; + @Autowired + private ValidationConfig validationConfig; + + @Autowired + private FhirConfig fhirConfig; + @Bean public CommandFactory commandFactory() { return new CommandFactoryImpl(serverBase, defaultPageCount, daoConfig.dataSource(), daoConfig.daoProvider(), referenceConfig.referenceExtractor(), referenceConfig.referenceResolver(), - helperConfig.responseGenerator(), helperConfig.exceptionHandler(), eventConfig.eventManager(), - eventConfig.eventGenerator(), snapshotConfig.snapshotGenerator(), - snapshotConfig.snapshotDependencyAnalyzer(), helperConfig.parameterConverter(), - authorizationHelper()); + referenceConfig.referenceCleaner(), helperConfig.responseGenerator(), helperConfig.exceptionHandler(), + helperConfig.parameterConverter(), eventConfig.eventManager(), eventConfig.eventGenerator(), + authorizationConfig.authorizationHelper(), validationConfig.validationHelper(), + snapshotConfig.snapshotGenerator(), this::transactionResourceFactory); } @Bean - public AuthorizationHelper authorizationHelper() + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public TransactionResources transactionResourceFactory(Connection connection) { - return new AuthorizationHelperImpl(authorizationConfig.authorizationRuleProvider(), + IValidationSupport validationSupport = validationConfig.validationSupportWithTransaction(connection); + + ValidationHelper validationHelper = new ValidationHelperImpl( + new ResourceValidatorImpl(fhirConfig.fhirContext(), validationSupport), helperConfig.responseGenerator()); + + SnapshotGenerator snapshotGenerator = new SnapshotGeneratorImpl(fhirConfig.fhirContext(), validationSupport); + + TransactionEventHandler transactionEventHandler = new TransactionEventHandler(eventConfig.eventManager(), + validationSupport instanceof EventHandler ? (EventHandler) validationSupport : null); + + return new TransactionResources(validationHelper, snapshotGenerator, transactionEventHandler); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/DaoConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/DaoConfig.java index 79eee1478..4697303f4 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/DaoConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/DaoConfig.java @@ -8,6 +8,7 @@ import org.highmed.dsf.fhir.dao.EndpointDao; import org.highmed.dsf.fhir.dao.GroupDao; import org.highmed.dsf.fhir.dao.HealthcareServiceDao; +import org.highmed.dsf.fhir.dao.HistoryDao; import org.highmed.dsf.fhir.dao.LocationDao; import org.highmed.dsf.fhir.dao.NamingSystemDao; import org.highmed.dsf.fhir.dao.OrganizationDao; @@ -17,11 +18,9 @@ import org.highmed.dsf.fhir.dao.ProvenanceDao; import org.highmed.dsf.fhir.dao.ResearchStudyDao; import org.highmed.dsf.fhir.dao.StructureDefinitionDao; -import org.highmed.dsf.fhir.dao.StructureDefinitionSnapshotDao; import org.highmed.dsf.fhir.dao.SubscriptionDao; import org.highmed.dsf.fhir.dao.TaskDao; import org.highmed.dsf.fhir.dao.ValueSetDao; -import org.highmed.dsf.fhir.dao.converter.SnapshotInfoConverter; import org.highmed.dsf.fhir.dao.jdbc.ActivityDefinitionDaoJdbc; import org.highmed.dsf.fhir.dao.jdbc.BinaryDaoJdbc; import org.highmed.dsf.fhir.dao.jdbc.BundleDaoJdbc; @@ -29,6 +28,7 @@ import org.highmed.dsf.fhir.dao.jdbc.EndpointDaoJdbc; import org.highmed.dsf.fhir.dao.jdbc.GroupDaoJdbc; import org.highmed.dsf.fhir.dao.jdbc.HealthcareServiceDaoJdbc; +import org.highmed.dsf.fhir.dao.jdbc.HistroyDaoJdbc; import org.highmed.dsf.fhir.dao.jdbc.LocationDaoJdbc; import org.highmed.dsf.fhir.dao.jdbc.NamingSystemDaoJdbc; import org.highmed.dsf.fhir.dao.jdbc.OrganizationDaoJdbc; @@ -65,9 +65,6 @@ public class DaoConfig @Autowired private FhirConfig fhirConfig; - @Autowired - private JsonConfig jsonConfig; - @Bean public BasicDataSource dataSource() { @@ -180,15 +177,9 @@ public StructureDefinitionDao structureDefinitionDao() } @Bean - public SnapshotInfoConverter snapshotInfoConverter() - { - return new SnapshotInfoConverter(jsonConfig.objectMapper()); - } - - @Bean - public StructureDefinitionSnapshotDao structureDefinitionSnapshotDao() + public StructureDefinitionDao structureDefinitionSnapshotDao() { - return new StructureDefinitionSnapshotDaoJdbc(dataSource(), fhirConfig.fhirContext(), snapshotInfoConverter()); + return new StructureDefinitionSnapshotDaoJdbc(dataSource(), fhirConfig.fhirContext()); } @Bean @@ -218,4 +209,10 @@ public DaoProvider daoProvider() structureDefinitionDao(), structureDefinitionSnapshotDao(), subscriptionDao(), taskDao(), valueSetDao()); } + + @Bean + public HistoryDao historyDao() + { + return new HistroyDaoJdbc(dataSource(), fhirConfig.fhirContext(), (BinaryDaoJdbc) binaryDao()); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/EventConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/EventConfig.java index 433f45588..c4baab22c 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/EventConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/EventConfig.java @@ -1,14 +1,20 @@ package org.highmed.dsf.fhir.spring.config; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.highmed.dsf.fhir.dao.ResourceDao; import org.highmed.dsf.fhir.event.EventGenerator; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.event.EventManager; import org.highmed.dsf.fhir.event.EventManagerImpl; -import org.highmed.dsf.fhir.event.MatcherFactory; -import org.hl7.fhir.r4.model.DomainResource; +import org.highmed.dsf.fhir.subscription.MatcherFactory; +import org.highmed.dsf.fhir.subscription.WebSocketSubscriptionManager; +import org.highmed.dsf.fhir.subscription.WebSocketSubscriptionManagerImpl; +import org.hl7.fhir.r4.model.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -28,14 +34,22 @@ public class EventConfig @Autowired private AuthorizationConfig authorizationConfig; + @Autowired + private ValidationConfig validationConfig; + @Bean public MatcherFactory matcherFactory() { - Map> daosByResourceName = new HashMap<>(); + Map> daosByResourceName = new HashMap<>(); + put(daosByResourceName, daoConfig.binaryDao()); + put(daosByResourceName, daoConfig.bundleDao()); put(daosByResourceName, daoConfig.codeSystemDao()); + put(daosByResourceName, daoConfig.endpointDao()); + put(daosByResourceName, daoConfig.groupDao()); put(daosByResourceName, daoConfig.healthcareServiceDao()); put(daosByResourceName, daoConfig.locationDao()); + put(daosByResourceName, daoConfig.namingSystemDao()); put(daosByResourceName, daoConfig.organizationDao()); put(daosByResourceName, daoConfig.patientDao()); put(daosByResourceName, daoConfig.practitionerDao()); @@ -50,8 +64,8 @@ public MatcherFactory matcherFactory() return new MatcherFactory(daosByResourceName); } - private void put(Map> daosByResourceName, - ResourceDao dao) + private void put(Map> daosByResourceName, + ResourceDao dao) { daosByResourceName.put(dao.getResourceTypeName(), dao); } @@ -59,8 +73,18 @@ private void put(Map> daos @Bean public EventManager eventManager() { - return new EventManagerImpl(daoConfig.daoProvider(), helperConfig.exceptionHandler(), matcherFactory(), - fhirConfig.fhirContext(), authorizationConfig.authorizationRuleProvider()); + List eventHandlers = Stream + .of(validationConfig.validationSupport(), webSocketSubscriptionManager()) + .filter(o -> o instanceof EventHandler).map(o -> (EventHandler) o).collect(Collectors.toList()); + + return new EventManagerImpl(eventHandlers); + } + + @Bean + public WebSocketSubscriptionManager webSocketSubscriptionManager() + { + return new WebSocketSubscriptionManagerImpl(daoConfig.daoProvider(), helperConfig.exceptionHandler(), + matcherFactory(), fhirConfig.fhirContext(), authorizationConfig.authorizationRuleProvider()); } @Bean diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/FhirConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/FhirConfig.java index 152020bf3..3a2b69b01 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/FhirConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/FhirConfig.java @@ -1,29 +1,29 @@ package org.highmed.dsf.fhir.spring.config; -import org.highmed.dsf.fhir.service.DefaultProfileValidationSupportWithFetchFromDb; -import org.hl7.fhir.r4.hapi.ctx.IValidationSupport; -import org.springframework.beans.factory.annotation.Autowired; +import java.util.Locale; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.i18n.HapiLocalizer; @Configuration public class FhirConfig { - @Autowired - private DaoConfig daoConfig; - @Bean public FhirContext fhirContext() { - return FhirContext.forR4(); - } - - @Bean - public IValidationSupport validationSupport() - { - return new DefaultProfileValidationSupportWithFetchFromDb(fhirContext(), daoConfig.structureDefinitionDao(), - daoConfig.structureDefinitionSnapshotDao(), daoConfig.codeSystemDao(), daoConfig.valueSetDao()); + FhirContext context = FhirContext.forR4(); + HapiLocalizer localizer = new HapiLocalizer() + { + @Override + public Locale getLocale() + { + return Locale.ROOT; + } + }; + context.setLocalizer(localizer); + return context; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/HistoryConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/HistoryConfig.java new file mode 100644 index 000000000..6694fa92b --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/HistoryConfig.java @@ -0,0 +1,40 @@ +package org.highmed.dsf.fhir.spring.config; + +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.history.HistoryServiceImpl; +import org.highmed.dsf.fhir.history.user.HistoryUserFilterFactory; +import org.highmed.dsf.fhir.history.user.HistoryUserFilterFactoryImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class HistoryConfig +{ + @Value("${org.highmed.dsf.fhir.serverBase}") + private String serverBase; + + @Value("${org.highmed.dsf.fhir.defaultPageCount}") + private int defaultPageCount; + + @Autowired + private HelperConfig helperConfig; + + @Autowired + private DaoConfig daoConfig; + + @Bean + public HistoryUserFilterFactory historyUserFilterFactory() + { + return new HistoryUserFilterFactoryImpl(); + } + + @Bean + public HistoryService historyService() + { + return new HistoryServiceImpl(serverBase, defaultPageCount, helperConfig.parameterConverter(), + helperConfig.exceptionHandler(), helperConfig.responseGenerator(), daoConfig.historyDao(), + historyUserFilterFactory()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/InitialDataLoaderConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/InitialDataLoaderConfig.java index 6063c1f29..9f1f6bf0f 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/InitialDataLoaderConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/InitialDataLoaderConfig.java @@ -34,6 +34,9 @@ public class InitialDataLoaderConfig @Autowired private FhirConfig fhirConfig; + @Autowired + private ReferenceConfig referenceConfig; + @Bean public InitialDataLoader initialDataLoader() { @@ -49,6 +52,11 @@ public void onContextRefreshedEvent(ContextRefreshedEvent event) throws IOExcept Bundle bundle = parseXmlBundle(fileIn); initialDataLoader().load(bundle); } + catch (Exception e) + { + logger.warn("Error while loading data from JAR bundle", e); + throw e; + } Path file = Paths.get(initBundleFile); if (!Files.isReadable(file)) @@ -60,6 +68,11 @@ public void onContextRefreshedEvent(ContextRefreshedEvent event) throws IOExcept Bundle bundle = parseXmlBundle(fileIn); initialDataLoader().load(bundle); } + catch (Exception e) + { + logger.warn("Error while loading data from external bundle", e); + throw e; + } } private Bundle parseXmlBundle(InputStream in) @@ -68,6 +81,7 @@ private Bundle parseXmlBundle(InputStream in) p.setStripVersionsFromReferences(false); p.setOverrideResourceIdWithBundleEntryFullUrl(false); - return p.parseResource(Bundle.class, in); + Bundle bundle = p.parseResource(Bundle.class, in); + return referenceConfig.referenceCleaner().cleanReferenceResourcesIfBundle(bundle); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ReferenceConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ReferenceConfig.java index 49893430c..5918198e8 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ReferenceConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ReferenceConfig.java @@ -1,5 +1,8 @@ package org.highmed.dsf.fhir.spring.config; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.ReferenceCleanerImpl; +import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceExtractorImpl; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ReferenceResolverImpl; @@ -24,7 +27,7 @@ public class ReferenceConfig private ClientConfig clientConfig; @Bean - public ReferenceExtractorImpl referenceExtractor() + public ReferenceExtractor referenceExtractor() { return new ReferenceExtractorImpl(); } @@ -35,4 +38,10 @@ public ReferenceResolver referenceResolver() return new ReferenceResolverImpl(serverBase, daoConfig.daoProvider(), helperConfig.responseGenerator(), helperConfig.exceptionHandler(), clientConfig.clientProvider(), helperConfig.parameterConverter()); } + + @Bean + public ReferenceCleaner referenceCleaner() + { + return new ReferenceCleanerImpl(referenceExtractor()); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/SnapshotConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/SnapshotConfig.java index bd6629d9d..064351431 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/SnapshotConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/SnapshotConfig.java @@ -1,6 +1,5 @@ package org.highmed.dsf.fhir.spring.config; -import org.highmed.dsf.fhir.service.SnapshotDependencyAnalyzer; import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.highmed.dsf.fhir.service.SnapshotGeneratorImpl; import org.springframework.beans.factory.annotation.Autowired; @@ -13,15 +12,12 @@ public class SnapshotConfig @Autowired private FhirConfig fhirConfig; - @Bean - public SnapshotGenerator snapshotGenerator() - { - return new SnapshotGeneratorImpl(fhirConfig.fhirContext(), fhirConfig.validationSupport()); - } + @Autowired + private ValidationConfig validationConfig; @Bean - public SnapshotDependencyAnalyzer snapshotDependencyAnalyzer() + public SnapshotGenerator snapshotGenerator() { - return new SnapshotDependencyAnalyzer(); + return new SnapshotGeneratorImpl(fhirConfig.fhirContext(), validationConfig.validationSupport()); } -} +} \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ValidationConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ValidationConfig.java index ed47fbb62..c882e3b5c 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ValidationConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/ValidationConfig.java @@ -1,20 +1,79 @@ package org.highmed.dsf.fhir.spring.config; +import java.sql.Connection; + +import org.highmed.dsf.fhir.dao.command.ValidationHelper; +import org.highmed.dsf.fhir.dao.command.ValidationHelperImpl; import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.service.ResourceValidatorImpl; +import org.highmed.dsf.fhir.service.ValidationSupportWithCache; +import org.highmed.dsf.fhir.service.ValidationSupportWithFetchFromDb; +import org.highmed.dsf.fhir.service.ValidationSupportWithFetchFromDbWithTransaction; +import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService; +import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; +import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.DefaultProfileValidationSupport; +import ca.uhn.fhir.context.support.IValidationSupport; @Configuration public class ValidationConfig { + @Autowired + private DaoConfig daoConfig; + @Autowired private FhirConfig fhirConfig; + @Autowired + private HelperConfig helperConfig; + + @Bean + public IValidationSupport validationSupport() + { + return new ValidationSupportWithCache(fhirConfig.fhirContext(), + validationSupportChain(new ValidationSupportWithFetchFromDb(fhirConfig.fhirContext(), + daoConfig.structureDefinitionDao(), daoConfig.structureDefinitionSnapshotDao(), + daoConfig.codeSystemDao(), daoConfig.valueSetDao()))); + } + + private ValidationSupportChain validationSupportChain(IValidationSupport dbSupport) + { + DefaultProfileValidationSupport dpvs = new DefaultProfileValidationSupport(FhirContext.forR4()); + dpvs.fetchCodeSystem(""); // FIXME HAPI bug workaround, to initialize + dpvs.fetchAllStructureDefinitions(); // FIXME HAPI bug workaround, to initialize + + return new ValidationSupportChain(new InMemoryTerminologyServerValidationSupport(fhirConfig.fhirContext()), + dbSupport, dpvs, new CommonCodeSystemsTerminologyService(fhirConfig.fhirContext())); + } + @Bean public ResourceValidator resourceValidator() { - return new ResourceValidatorImpl(fhirConfig.fhirContext(), fhirConfig.validationSupport()); + return new ResourceValidatorImpl(fhirConfig.fhirContext(), validationSupport()); + } + + @Bean + public ValidationHelper validationHelper() + { + return new ValidationHelperImpl(resourceValidator(), helperConfig.responseGenerator()); + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public IValidationSupport validationSupportWithTransaction(Connection connection) + { + ValidationSupportWithCache validationSupport = new ValidationSupportWithCache(fhirConfig.fhirContext(), + validationSupportChain(new ValidationSupportWithFetchFromDbWithTransaction(fhirConfig.fhirContext(), + daoConfig.structureDefinitionDao(), daoConfig.structureDefinitionSnapshotDao(), + daoConfig.codeSystemDao(), daoConfig.valueSetDao(), connection))); + + return validationSupport.populateCache(validationSupport().fetchAllConformanceResources()); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/WebserviceConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/WebserviceConfig.java index b05a34df5..bcc42acaf 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/WebserviceConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/WebserviceConfig.java @@ -131,6 +131,9 @@ public class WebserviceConfig @Autowired private ReferenceConfig referenceConfig; + @Autowired + private HistoryConfig historyConfig; + @Bean public ServerBaseProvider serverBaseProvider() { @@ -153,8 +156,9 @@ private ActivityDefinitionServiceSecure activityDefinitionServiceSecure() { return new ActivityDefinitionServiceSecure(activityDefinitionServiceImpl(), serverBase, helperConfig.responseGenerator(), referenceConfig.referenceResolver(), - daoConfig.activityDefinitionDao(), helperConfig.exceptionHandler(), helperConfig.parameterConverter(), - authorizationConfig.activityDefinitionAuthorizationRule()); + referenceConfig.referenceCleaner(), daoConfig.activityDefinitionDao(), helperConfig.exceptionHandler(), + helperConfig.parameterConverter(), authorizationConfig.activityDefinitionAuthorizationRule(), + validationConfig.resourceValidator()); } private ActivityDefinitionServiceImpl activityDefinitionServiceImpl() @@ -163,42 +167,22 @@ private ActivityDefinitionServiceImpl activityDefinitionServiceImpl() daoConfig.activityDefinitionDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider()); - } - - @Bean - public CodeSystemService codeSystemService() - { - return new CodeSystemServiceJaxrs(codeSystemServiceSecure()); - } - - private CodeSystemServiceSecure codeSystemServiceSecure() - { - return new CodeSystemServiceSecure(codeSystemServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.codeSystemDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.codeSystemAuthorizationRule()); - } - - private CodeSystemServiceImpl codeSystemServiceImpl() - { - return new CodeSystemServiceImpl(CodeSystemServiceJaxrs.PATH, serverBase, defaultPageCount, - daoConfig.codeSystemDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), - helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), - helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), historyConfig.historyService()); } @Bean public BinaryService binaryService() { - return new BinaryServiceJaxrs(binaryServiceSecure()); + return new BinaryServiceJaxrs(binaryServiceSecure(), helperConfig.parameterConverter()); } private BinaryServiceSecure binaryServiceSecure() { return new BinaryServiceSecure(binaryServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.binaryDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.binaryAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.binaryDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.binaryAuthorizationRule(), validationConfig.resourceValidator()); } private BinaryService binaryServiceImpl() @@ -207,7 +191,8 @@ private BinaryService binaryServiceImpl() validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), referenceConfig.referenceResolver(), - authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceCleaner(), authorizationConfig.authorizationRuleProvider(), + historyConfig.historyService()); } @Bean @@ -219,8 +204,9 @@ public BundleService bundleService() private BundleServiceSecure bundleServiceSecure() { return new BundleServiceSecure(bundleServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.bundleDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.bundleAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.bundleDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.bundleAuthorizationRule(), validationConfig.resourceValidator()); } private BundleService bundleServiceImpl() @@ -229,7 +215,32 @@ private BundleService bundleServiceImpl() validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), referenceConfig.referenceResolver(), - authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceCleaner(), authorizationConfig.authorizationRuleProvider(), + historyConfig.historyService()); + } + + @Bean + public CodeSystemService codeSystemService() + { + return new CodeSystemServiceJaxrs(codeSystemServiceSecure()); + } + + private CodeSystemServiceSecure codeSystemServiceSecure() + { + return new CodeSystemServiceSecure(codeSystemServiceImpl(), serverBase, helperConfig.responseGenerator(), + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.codeSystemDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.codeSystemAuthorizationRule(), validationConfig.resourceValidator()); + } + + private CodeSystemServiceImpl codeSystemServiceImpl() + { + return new CodeSystemServiceImpl(CodeSystemServiceJaxrs.PATH, serverBase, defaultPageCount, + daoConfig.codeSystemDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), + helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), + helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), historyConfig.historyService()); } @Bean @@ -241,8 +252,9 @@ public EndpointService endpointService() private EndpointServiceSecure endpointServiceSecure() { return new EndpointServiceSecure(endpointServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.endpointDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.endpointAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.endpointDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.endpointAuthorizationRule(), validationConfig.resourceValidator()); } private EndpointServiceImpl endpointServiceImpl() @@ -251,7 +263,8 @@ private EndpointServiceImpl endpointServiceImpl() validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), referenceConfig.referenceResolver(), - authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceCleaner(), authorizationConfig.authorizationRuleProvider(), + historyConfig.historyService()); } @Bean @@ -263,8 +276,9 @@ public GroupService groupService() private GroupServiceSecure groupServiceSecure() { return new GroupServiceSecure(groupServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.groupDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.groupAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.groupDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.groupAuthorizationRule(), validationConfig.resourceValidator()); } private GroupServiceImpl groupServiceImpl() @@ -273,7 +287,8 @@ private GroupServiceImpl groupServiceImpl() validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), referenceConfig.referenceResolver(), - authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceCleaner(), authorizationConfig.authorizationRuleProvider(), + historyConfig.historyService()); } @Bean @@ -285,9 +300,10 @@ public HealthcareServiceService healthcareServiceService() private HealthcareServiceServiceSecure healthcareServiceServiceSecure() { return new HealthcareServiceServiceSecure(healthcareServiceServiceImpl(), serverBase, - helperConfig.responseGenerator(), referenceConfig.referenceResolver(), daoConfig.healthcareServiceDao(), - helperConfig.exceptionHandler(), helperConfig.parameterConverter(), - authorizationConfig.healthcareServiceAuthorizationRule()); + helperConfig.responseGenerator(), referenceConfig.referenceResolver(), + referenceConfig.referenceCleaner(), daoConfig.healthcareServiceDao(), helperConfig.exceptionHandler(), + helperConfig.parameterConverter(), authorizationConfig.healthcareServiceAuthorizationRule(), + validationConfig.resourceValidator()); } private HealthcareServiceServiceImpl healthcareServiceServiceImpl() @@ -296,7 +312,8 @@ private HealthcareServiceServiceImpl healthcareServiceServiceImpl() daoConfig.healthcareServiceDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), historyConfig.historyService()); } @Bean @@ -308,8 +325,9 @@ public LocationService locationService() private LocationServiceSecure locationServiceSecure() { return new LocationServiceSecure(locationServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.locationDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.locationAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.locationDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.locationAuthorizationRule(), validationConfig.resourceValidator()); } private LocationServiceImpl locationServiceImpl() @@ -318,7 +336,8 @@ private LocationServiceImpl locationServiceImpl() validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), referenceConfig.referenceResolver(), - authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceCleaner(), authorizationConfig.authorizationRuleProvider(), + historyConfig.historyService()); } @Bean @@ -330,8 +349,9 @@ public NamingSystemService namingSystemService() private NamingSystemServiceSecure namingSystemServiceSecure() { return new NamingSystemServiceSecure(namingSystemServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.namingSystemDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.namingSystemAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.namingSystemDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.namingSystemAuthorizationRule(), validationConfig.resourceValidator()); } private NamingSystemService namingSystemServiceImpl() @@ -340,7 +360,8 @@ private NamingSystemService namingSystemServiceImpl() daoConfig.namingSystemDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), historyConfig.historyService()); } @Bean @@ -352,8 +373,9 @@ public OrganizationService organizationService() private OrganizationServiceSecure organizationServiceSecure() { return new OrganizationServiceSecure(organizationServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.organizationDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.organizationAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.organizationDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.organizationAuthorizationRule(), validationConfig.resourceValidator()); } private OrganizationServiceImpl organizationServiceImpl() @@ -362,7 +384,8 @@ private OrganizationServiceImpl organizationServiceImpl() daoConfig.organizationDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), historyConfig.historyService()); } @Bean @@ -374,8 +397,9 @@ public PatientService patientService() private PatientServiceSecure patientServiceSecure() { return new PatientServiceSecure(patientServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.patientDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.patientAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.patientDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.patientAuthorizationRule(), validationConfig.resourceValidator()); } private PatientServiceImpl patientServiceImpl() @@ -384,7 +408,8 @@ private PatientServiceImpl patientServiceImpl() validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), referenceConfig.referenceResolver(), - authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceCleaner(), authorizationConfig.authorizationRuleProvider(), + historyConfig.historyService()); } @Bean @@ -396,9 +421,10 @@ public PractitionerRoleService practitionerRoleService() private PractitionerRoleServiceSecure practitionerRoleServiceSecure() { return new PractitionerRoleServiceSecure(practitionerRoleServiceImpl(), serverBase, - helperConfig.responseGenerator(), referenceConfig.referenceResolver(), daoConfig.practitionerRoleDao(), - helperConfig.exceptionHandler(), helperConfig.parameterConverter(), - authorizationConfig.practitionerRoleAuthorizationRule()); + helperConfig.responseGenerator(), referenceConfig.referenceResolver(), + referenceConfig.referenceCleaner(), daoConfig.practitionerRoleDao(), helperConfig.exceptionHandler(), + helperConfig.parameterConverter(), authorizationConfig.practitionerRoleAuthorizationRule(), + validationConfig.resourceValidator()); } private PractitionerRoleServiceImpl practitionerRoleServiceImpl() @@ -407,7 +433,8 @@ private PractitionerRoleServiceImpl practitionerRoleServiceImpl() daoConfig.practitionerRoleDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), historyConfig.historyService()); } @Bean @@ -419,8 +446,9 @@ public PractitionerService practitionerService() private PractitionerServiceSecure practitionerServiceSecure() { return new PractitionerServiceSecure(practitionerServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.practitionerDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.practitionerAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.practitionerDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.practitionerAuthorizationRule(), validationConfig.resourceValidator()); } private PractitionerServiceImpl practitionerServiceImpl() @@ -429,7 +457,8 @@ private PractitionerServiceImpl practitionerServiceImpl() daoConfig.practitionerDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), historyConfig.historyService()); } @Bean @@ -441,8 +470,9 @@ public ProvenanceService provenanceService() private ProvenanceServiceSecure provenanceServiceSecure() { return new ProvenanceServiceSecure(provenanceServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.provenanceDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.provenanceAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.provenanceDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.provenanceAuthorizationRule(), validationConfig.resourceValidator()); } private ProvenanceServiceImpl provenanceServiceImpl() @@ -451,7 +481,8 @@ private ProvenanceServiceImpl provenanceServiceImpl() daoConfig.provenanceDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), historyConfig.historyService()); } @Bean @@ -463,8 +494,9 @@ public ResearchStudyService researchStudyService() private ResearchStudyServiceSecure researchStudyServiceSecure() { return new ResearchStudyServiceSecure(researchStudyServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.researchStudyDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.researchStudyAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.researchStudyDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.researchStudyAuthorizationRule(), validationConfig.resourceValidator()); } private ResearchStudyServiceImpl researchStudyServiceImpl() @@ -473,7 +505,8 @@ private ResearchStudyServiceImpl researchStudyServiceImpl() daoConfig.researchStudyDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), historyConfig.historyService()); } @Bean @@ -486,8 +519,9 @@ private StructureDefinitionServiceSecure structureDefinitionServiceSecure() { return new StructureDefinitionServiceSecure(structureDefinitionServiceImpl(), serverBase, helperConfig.responseGenerator(), referenceConfig.referenceResolver(), - daoConfig.structureDefinitionDao(), helperConfig.exceptionHandler(), helperConfig.parameterConverter(), - authorizationConfig.structureDefinitionAuthorizationRule()); + referenceConfig.referenceCleaner(), daoConfig.structureDefinitionDao(), helperConfig.exceptionHandler(), + helperConfig.parameterConverter(), authorizationConfig.structureDefinitionAuthorizationRule(), + validationConfig.resourceValidator()); } private StructureDefinitionServiceImpl structureDefinitionServiceImpl() @@ -496,9 +530,9 @@ private StructureDefinitionServiceImpl structureDefinitionServiceImpl() daoConfig.structureDefinitionDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider(), - daoConfig.structureDefinitionSnapshotDao(), snapshotConfig.snapshotGenerator(), - snapshotConfig.snapshotDependencyAnalyzer()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), daoConfig.structureDefinitionSnapshotDao(), + snapshotConfig.snapshotGenerator(), historyConfig.historyService()); } @Bean @@ -510,8 +544,9 @@ public SubscriptionService subscriptionService() private SubscriptionServiceSecure subscriptionServiceSecure() { return new SubscriptionServiceSecure(subscriptionServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.subscriptionDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.subscriptionAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.subscriptionDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.subscriptionAuthorizationRule(), validationConfig.resourceValidator()); } private SubscriptionServiceImpl subscriptionServiceImpl() @@ -520,7 +555,8 @@ private SubscriptionServiceImpl subscriptionServiceImpl() daoConfig.subscriptionDao(), validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), - referenceConfig.referenceResolver(), authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), + authorizationConfig.authorizationRuleProvider(), historyConfig.historyService()); } @Bean @@ -532,8 +568,9 @@ public TaskService taskService() private TaskServiceSecure taskServiceSecure() { return new TaskServiceSecure(taskServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.taskDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.taskAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.taskDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.taskAuthorizationRule(), validationConfig.resourceValidator()); } private TaskServiceImpl taskServiceImpl() @@ -542,7 +579,8 @@ private TaskServiceImpl taskServiceImpl() validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), referenceConfig.referenceResolver(), - authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceCleaner(), authorizationConfig.authorizationRuleProvider(), + historyConfig.historyService()); } @Bean @@ -554,8 +592,9 @@ public ValueSetService valueSetService() private ValueSetServiceSecure valueSetServiceSecure() { return new ValueSetServiceSecure(valueSetServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver(), daoConfig.valueSetDao(), helperConfig.exceptionHandler(), - helperConfig.parameterConverter(), authorizationConfig.valueSetAuthorizationRule()); + referenceConfig.referenceResolver(), referenceConfig.referenceCleaner(), daoConfig.valueSetDao(), + helperConfig.exceptionHandler(), helperConfig.parameterConverter(), + authorizationConfig.valueSetAuthorizationRule(), validationConfig.resourceValidator()); } private ValueSetServiceImpl valueSetServiceImpl() @@ -564,7 +603,8 @@ private ValueSetServiceImpl valueSetServiceImpl() validationConfig.resourceValidator(), eventConfig.eventManager(), helperConfig.exceptionHandler(), eventConfig.eventGenerator(), helperConfig.responseGenerator(), helperConfig.parameterConverter(), referenceConfig.referenceExtractor(), referenceConfig.referenceResolver(), - authorizationConfig.authorizationRuleProvider()); + referenceConfig.referenceCleaner(), authorizationConfig.authorizationRuleProvider(), + historyConfig.historyService()); } @Bean @@ -576,13 +616,14 @@ public RootService rootService() private RootServiceSecure rootServiceSecure() { return new RootServiceSecure(rootServiceImpl(), serverBase, helperConfig.responseGenerator(), - referenceConfig.referenceResolver()); + referenceConfig.referenceResolver(), authorizationConfig.rootAuthorizationRule()); } private RootServiceImpl rootServiceImpl() { return new RootServiceImpl(RootServiceJaxrs.PATH, commandConfig.commandFactory(), - helperConfig.responseGenerator(), helperConfig.parameterConverter(), helperConfig.exceptionHandler()); + helperConfig.responseGenerator(), helperConfig.parameterConverter(), helperConfig.exceptionHandler(), + referenceConfig.referenceCleaner(), historyConfig.historyService()); } @Bean @@ -600,7 +641,8 @@ private ConformanceServiceSecure conformanceServiceSecure() private ConformanceServiceImpl conformanceServiceImpl() { return new ConformanceServiceImpl(ConformanceServiceJaxrs.PATH, serverBase, defaultPageCount, - buildInfoReaderConfig.buildInfoReader(), helperConfig.parameterConverter()); + buildInfoReaderConfig.buildInfoReader(), helperConfig.parameterConverter(), + validationConfig.validationSupport()); } @Bean diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/WebsocketConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/WebsocketConfig.java index 4283170f2..72c78b49c 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/WebsocketConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/spring/config/WebsocketConfig.java @@ -15,15 +15,15 @@ public class WebsocketConfig private EventConfig eventConfig; @Bean - public ServerEndpoint eventEndpoint() + public ServerEndpoint subscriptionEndpoint() { - return new ServerEndpoint(eventConfig.eventManager()); + return new ServerEndpoint(eventConfig.webSocketSubscriptionManager()); } @Bean - public ServerEndpointRegistration eventEndpointRegistration() + public ServerEndpointRegistration subscriptionEndpointRegistration() { - return new ServerEndpointRegistrationForAuthentication(ServerEndpoint.PATH, eventEndpoint()); + return new ServerEndpointRegistrationForAuthentication(ServerEndpoint.PATH, subscriptionEndpoint()); } @Bean diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/MatcherFactory.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/MatcherFactory.java similarity index 67% rename from dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/MatcherFactory.java rename to dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/MatcherFactory.java index c093e7e47..0e2e01dc7 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/MatcherFactory.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/MatcherFactory.java @@ -1,4 +1,4 @@ -package org.highmed.dsf.fhir.event; +package org.highmed.dsf.fhir.subscription; import java.util.HashMap; import java.util.Map; @@ -7,16 +7,16 @@ import org.highmed.dsf.fhir.dao.ResourceDao; import org.highmed.dsf.fhir.search.Matcher; import org.highmed.dsf.fhir.search.SearchQuery; -import org.hl7.fhir.r4.model.DomainResource; +import org.hl7.fhir.r4.model.Resource; import org.springframework.util.MultiValueMap; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; public class MatcherFactory { - private final Map> daosByResourceName = new HashMap<>(); + private final Map> daosByResourceName = new HashMap<>(); - public MatcherFactory(Map> daosByResourceName) + public MatcherFactory(Map> daosByResourceName) { if (daosByResourceName != null) this.daosByResourceName.putAll(daosByResourceName); @@ -31,8 +31,8 @@ public Optional createMatcher(String uri) if (daosByResourceName.containsKey(path)) { - ResourceDao dao = daosByResourceName.get(path); - SearchQuery query = dao.createSearchQueryWithoutUserFilter(1, 1); + ResourceDao dao = daosByResourceName.get(path); + SearchQuery query = dao.createSearchQueryWithoutUserFilter(1, 1); query.configureParameters(queryParameters); return Optional.of(query); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/ReadWriteMap.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/ReadWriteMap.java similarity index 97% rename from dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/ReadWriteMap.java rename to dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/ReadWriteMap.java index bd718bd2d..002de9586 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/event/ReadWriteMap.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/ReadWriteMap.java @@ -1,4 +1,4 @@ -package org.highmed.dsf.fhir.event; +package org.highmed.dsf.fhir.subscription; import java.util.HashMap; import java.util.Iterator; diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/WebSocketSubscriptionManager.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/WebSocketSubscriptionManager.java new file mode 100755 index 000000000..33c833d9b --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/WebSocketSubscriptionManager.java @@ -0,0 +1,12 @@ +package org.highmed.dsf.fhir.subscription; + +import javax.websocket.Session; + +import org.highmed.dsf.fhir.authentication.User; + +public interface WebSocketSubscriptionManager +{ + void bind(User user, Session session, String subscriptionIdPart); + + void close(String sessionId); +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/WebSocketSubscriptionManagerImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/WebSocketSubscriptionManagerImpl.java new file mode 100755 index 000000000..deaab45d6 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/subscription/WebSocketSubscriptionManagerImpl.java @@ -0,0 +1,414 @@ +package org.highmed.dsf.fhir.subscription; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.websocket.CloseReason; +import javax.websocket.CloseReason.CloseCodes; +import javax.websocket.RemoteEndpoint.Async; +import javax.websocket.Session; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; +import org.highmed.dsf.fhir.dao.SubscriptionDao; +import org.highmed.dsf.fhir.dao.provider.DaoProvider; +import org.highmed.dsf.fhir.event.Event; +import org.highmed.dsf.fhir.event.EventHandler; +import org.highmed.dsf.fhir.help.ExceptionHandler; +import org.highmed.dsf.fhir.search.Matcher; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.Subscription; +import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.annotation.ResourceDef; +import ca.uhn.fhir.parser.IParser; +import ca.uhn.fhir.rest.api.Constants; + +public class WebSocketSubscriptionManagerImpl + implements WebSocketSubscriptionManager, EventHandler, InitializingBean, DisposableBean +{ + private static final Logger logger = LoggerFactory.getLogger(WebSocketSubscriptionManagerImpl.class); + + private static class SubscriptionAndMatcher + { + final Subscription subscription; + final Matcher matcher; + + SubscriptionAndMatcher(Subscription subscription, Matcher matcher) + { + this.subscription = subscription; + this.matcher = matcher; + } + + boolean matches(Resource resource, DaoProvider daoProvider) + { + try + { + matcher.resloveReferencesForMatching(resource, daoProvider); + } + catch (SQLException e) + { + throw new RuntimeException(e); + } + + return matcher.matches(resource); + } + } + + private static class SessionIdAndRemoteAsync + { + final User user; + final String sessionId; + final Async remoteAsync; + + SessionIdAndRemoteAsync(User user, String sessionId, Async remoteAsync) + { + this.user = user; + this.sessionId = sessionId; + this.remoteAsync = remoteAsync; + } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + ((sessionId == null) ? 0 : sessionId.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SessionIdAndRemoteAsync other = (SessionIdAndRemoteAsync) obj; + if (sessionId == null) + { + if (other.sessionId != null) + return false; + } + else if (!sessionId.equals(other.sessionId)) + return false; + return true; + } + } + + private final ExecutorService executor = Executors.newCachedThreadPool(); + + private final DaoProvider daoProvider; + private final SubscriptionDao subscriptionDao; + private final ExceptionHandler exceptionHandler; + private final MatcherFactory matcherFactory; + private final FhirContext fhirContext; + private final AuthorizationRuleProvider authorizationRuleProvider; + + private final AtomicBoolean firstCall = new AtomicBoolean(true); + private final ReadWriteMap subscriptionsByIdPart = new ReadWriteMap<>(); + private final ReadWriteMap, List> matchersByResource = new ReadWriteMap<>(); + private final ReadWriteMap> asyncRemotesBySubscriptionIdPart = new ReadWriteMap<>(); + + public WebSocketSubscriptionManagerImpl(DaoProvider daoProvider, ExceptionHandler exceptionHandler, + MatcherFactory matcherFactory, FhirContext fhirContext, AuthorizationRuleProvider authorizationRuleProvider) + { + this.daoProvider = daoProvider; + this.subscriptionDao = daoProvider.getSubscriptionDao(); + this.exceptionHandler = exceptionHandler; + this.matcherFactory = matcherFactory; + this.fhirContext = fhirContext; + this.authorizationRuleProvider = authorizationRuleProvider; + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(daoProvider, "daoProvider"); + Objects.requireNonNull(subscriptionDao, "subscriptionDao"); + Objects.requireNonNull(exceptionHandler, "exceptionHandler"); + Objects.requireNonNull(matcherFactory, "matcherFactory"); + Objects.requireNonNull(fhirContext, "fhirContext"); + Objects.requireNonNull(authorizationRuleProvider, "authorizationRuleProvider"); + } + + private void refreshMatchers() + { + logger.info("Refreshing subscriptions"); + firstCall.set(false); + + try + { + List subscriptions = subscriptionDao.readByStatus(SubscriptionStatus.ACTIVE); + Map, List> matchers = new HashMap<>(); + for (Subscription subscription : subscriptions) + { + Optional matcher = matcherFactory.createMatcher(subscription.getCriteria()); + if (matcher.isPresent()) + { + if (matchers.containsKey(matcher.get().getResourceType())) + { + matchers.get(matcher.get().getResourceType()) + .add(new SubscriptionAndMatcher(subscription, matcher.get())); + } + else + { + matchers.put(matcher.get().getResourceType(), new ArrayList<>( + Collections.singletonList(new SubscriptionAndMatcher(subscription, matcher.get())))); + } + } + } + matchersByResource.replaceAll(matchers); + subscriptionsByIdPart.replaceAll(subscriptions.stream() + .collect(Collectors.toMap(s -> s.getIdElement().getIdPart(), Function.identity()))); + + logger.debug("Current active subscription-ids (after refreshing): {}", subscriptionsByIdPart.getAllKeys()); + } + catch (SQLException e) + { + logger.error("Error while accessing DB", e); + } + } + + @Override + public void destroy() throws Exception + { + executor.shutdown(); + try + { + if (!executor.awaitTermination(60, TimeUnit.SECONDS)) + { + executor.shutdownNow(); + if (!executor.awaitTermination(60, TimeUnit.SECONDS)) + logger.warn("EventManager executor did not terminate"); + } + } + catch (InterruptedException ie) + { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + @Override + public void handleEvents(List events) + { + executor.execute(() -> doHandleEventsAndRefreshMatchers(events)); + } + + private void doHandleEventsAndRefreshMatchers(List events) + { + if (events.stream().anyMatch(e -> e.getResource() instanceof Subscription || firstCall.get())) + refreshMatchers(); + + events.stream().forEach(this::doHandleEvent); + } + + @Override + public void handleEvent(Event event) + { + executor.execute(() -> doHandleEventAndRefreshMatchers(event)); + } + + private void doHandleEventAndRefreshMatchers(Event event) + { + if (event.getResource() instanceof Subscription || firstCall.get()) + refreshMatchers(); + + doHandleEvent(event); + } + + private void doHandleEvent(Event event) + { + logger.debug("handling event {} for resource of type {} with id {}", event.getClass().getSimpleName(), + event.getResourceType().getAnnotation(ResourceDef.class).name(), event.getId()); + + Optional> optMatchers = matchersByResource.get(event.getResourceType()); + if (optMatchers.isEmpty()) + { + logger.debug("No subscriptions for event {} for resource of type {} with id {}", + event.getClass().getSimpleName(), event.getResourceType().getAnnotation(ResourceDef.class).name(), + event.getId()); + return; + } + + List matchingSubscriptions = optMatchers.get().stream() + .filter(sAndM -> sAndM.matches(event.getResource(), daoProvider)).collect(Collectors.toList()); + + if (matchingSubscriptions.isEmpty()) + { + logger.debug("No matching subscriptions for event {} for resource of type {} with id {}", + event.getClass().getSimpleName(), event.getResourceType().getAnnotation(ResourceDef.class).name(), + event.getId()); + return; + } + + matchingSubscriptions.forEach(sAndM -> doHandleEventWithSubscription(sAndM.subscription, event)); + } + + private void doHandleEventWithSubscription(Subscription s, Event event) + { + Optional> optRemotes = asyncRemotesBySubscriptionIdPart + .get(s.getIdElement().getIdPart()); + + if (optRemotes.isEmpty()) + { + logger.debug("No remotes connected to subscription with id {}", s.getIdElement().getIdPart()); + return; + } + + final String text; + if (Constants.CT_FHIR_JSON_NEW.equals(s.getChannel().getPayload())) + text = newJsonParser().encodeResourceToString(event.getResource()); + else if (Constants.CT_FHIR_XML_NEW.contentEquals(s.getChannel().getPayload())) + text = newXmlParser().encodeResourceToString(event.getResource()); + else + text = "ping " + s.getIdElement().getIdPart(); + + logger.debug("Calling {} remote{} connected to subscription with id {}", optRemotes.get().size(), + optRemotes.get().size() != 1 ? "s" : "", s.getIdElement().getIdPart()); + + // defensive copy because list could be changed by other threads while we are reading + List remotes = new ArrayList<>(optRemotes.get()); + remotes.stream().filter(r -> userHasReadAccess(r, event)).forEach(r -> send(r, text)); + } + + private IParser newXmlParser() + { + return configureParser(fhirContext.newXmlParser()); + } + + private IParser newJsonParser() + { + return configureParser(fhirContext.newJsonParser()); + } + + private IParser configureParser(IParser p) + { + p.setStripVersionsFromReferences(false); + p.setOverrideResourceIdWithBundleEntryFullUrl(false); + return p; + } + + private boolean userHasReadAccess(SessionIdAndRemoteAsync sessionAndRemote, Event event) + { + Optional> optRule = authorizationRuleProvider + .getAuthorizationRule(event.getResourceType()); + if (optRule.isPresent()) + { + @SuppressWarnings("unchecked") + AuthorizationRule rule = (AuthorizationRule) optRule.get(); + Optional optReason = rule.reasonReadAllowed(sessionAndRemote.user, event.getResource()); + + if (optReason.isPresent()) + { + logger.info("Sending event {} to user {}, read of {} allowed {}", event.getClass().getSimpleName(), + sessionAndRemote.user.getName(), event.getResourceType().getSimpleName(), optReason.get()); + return true; + } + else + { + logger.warn("Skipping event {} for user {}, read of {} not allowed", event.getClass().getSimpleName(), + sessionAndRemote.user.getName(), event.getResourceType().getSimpleName()); + return false; + } + } + else + { + logger.warn("Skipping event {} for user {}, no authorization rule for resource of type {} found", + event.getClass().getSimpleName(), sessionAndRemote.user.getName(), + event.getResourceType().getSimpleName()); + return false; + } + } + + private void send(SessionIdAndRemoteAsync sessionAndRemote, String text) + { + try + { + sessionAndRemote.remoteAsync.sendText(text); + } + catch (Exception e) + { + logger.warn("Error while sending event to remote with session id {}", sessionAndRemote.sessionId); + } + } + + @Override + public void bind(User user, Session session, String subscriptionIdPart) + { + if (firstCall.get()) + refreshMatchers(); + + if (subscriptionsByIdPart.containsKey(subscriptionIdPart)) + { + logger.debug("Binding websocket session {} to subscription {}", session.getId(), subscriptionIdPart); + asyncRemotesBySubscriptionIdPart.replace(subscriptionIdPart, list -> + { + if (list == null) + { + List newList = new ArrayList<>(); + newList.add(new SessionIdAndRemoteAsync(user, session.getId(), session.getAsyncRemote())); + return newList; + } + else + { + list.add(new SessionIdAndRemoteAsync(user, session.getId(), session.getAsyncRemote())); + return list; + } + }); + session.getAsyncRemote().sendText("bound " + subscriptionIdPart); + } + else + { + logger.warn("Could not bind websocket session {} to subscription {}, subscription not found", + session.getId(), subscriptionIdPart); + logger.debug("Current active subscription-ids: {}", subscriptionsByIdPart.getAllKeys()); + closeNotFound(user, session, subscriptionIdPart); + } + } + + private void closeNotFound(User user, Session session, String subscriptionIdPart) + { + try + { + session.close(new CloseReason(CloseCodes.CANNOT_ACCEPT, + "Subscription with " + subscriptionIdPart + " not found")); + } + catch (IOException e) + { + logger.warn("Error while closing websocket with user {}, session {}, {}", user.getName(), session.getId(), + e.getMessage()); + logger.debug("Error while closing websocket", e); + } + } + + @Override + public void close(String sessionId) + { + logger.debug("Removing websocket session {}", sessionId); + asyncRemotesBySubscriptionIdPart.removeWhereValueMatches(list -> list.isEmpty(), + list -> list.remove(new SessionIdAndRemoteAsync(null, sessionId, null))); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java index 3e3d9e0c0..a5c46e6f6 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java @@ -22,6 +22,7 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.EntityTag; import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; @@ -31,22 +32,26 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.ResourceDao; -import org.highmed.dsf.fhir.dao.exception.ResourceNotFoundException; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.prefer.PreferHandlingType; import org.highmed.dsf.fhir.search.PartialResult; import org.highmed.dsf.fhir.search.SearchQuery; import org.highmed.dsf.fhir.search.SearchQueryParameterError; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceReference; +import org.highmed.dsf.fhir.service.ResourceReference.ReferenceType; import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.base.AbstractBasicService; import org.highmed.dsf.fhir.webservice.specification.BasicResourceService; import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.IdType; @@ -84,20 +89,23 @@ public abstract class AbstractResourceServiceImpl, R ex protected final int defaultPageCount; protected final D dao; protected final ResourceValidator validator; - protected final EventManager eventManager; + protected final EventHandler eventHandler; protected final ExceptionHandler exceptionHandler; protected final EventGenerator eventGenerator; protected final ResponseGenerator responseGenerator; protected final ParameterConverter parameterConverter; protected final ReferenceExtractor referenceExtractor; protected final ReferenceResolver referenceResolver; + protected final ReferenceCleaner referenceCleaner; protected final AuthorizationRuleProvider authorizationRuleProvider; + protected final HistoryService historyService; public AbstractResourceServiceImpl(String path, Class resourceType, String serverBase, int defaultPageCount, - D dao, ResourceValidator validator, EventManager eventManager, ExceptionHandler exceptionHandler, + D dao, ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - AuthorizationRuleProvider authorizationRuleProvider) + ReferenceCleaner referenceCleaner, AuthorizationRuleProvider authorizationRuleProvider, + HistoryService historyService) { super(path); @@ -107,14 +115,16 @@ public AbstractResourceServiceImpl(String path, Class resourceType, String se this.defaultPageCount = defaultPageCount; this.dao = dao; this.validator = validator; - this.eventManager = eventManager; + this.eventHandler = eventHandler; this.exceptionHandler = exceptionHandler; this.eventGenerator = eventGenerator; this.responseGenerator = responseGenerator; this.parameterConverter = parameterConverter; this.referenceExtractor = referenceExtractor; this.referenceResolver = referenceResolver; + this.referenceCleaner = referenceCleaner; this.authorizationRuleProvider = authorizationRuleProvider; + this.historyService = historyService; } public void afterPropertiesSet() throws Exception @@ -127,14 +137,16 @@ public void afterPropertiesSet() throws Exception Objects.requireNonNull(defaultPageCount, "defaultPageCount"); Objects.requireNonNull(dao, "dao"); Objects.requireNonNull(validator, "validator"); - Objects.requireNonNull(eventManager, "eventManager"); + Objects.requireNonNull(eventHandler, "eventHandler"); Objects.requireNonNull(exceptionHandler, "exceptionHandler"); Objects.requireNonNull(eventGenerator, "eventGenerator"); Objects.requireNonNull(responseGenerator, "responseGenerator"); Objects.requireNonNull(parameterConverter, "parameterConverter"); Objects.requireNonNull(referenceExtractor, "referenceExtractor"); Objects.requireNonNull(referenceResolver, "referenceResolver"); + Objects.requireNonNull(referenceCleaner, "referenceCleaner"); Objects.requireNonNull(authorizationRuleProvider, "authorizationRuleProvider"); + Objects.requireNonNull(historyService, "historyService"); } @Override @@ -150,9 +162,9 @@ public Response create(R resource, UriInfo uri, HttpHeaders headers) { try { - R created = dao.createWithTransactionAndId(connection, resource, UUID.randomUUID()); + resolveLogicalReferences(resource, connection); - created = resolveReferences(connection, created); + R created = dao.createWithTransactionAndId(connection, resource, UUID.randomUUID()); connection.commit(); @@ -166,61 +178,58 @@ public Response create(R resource, UriInfo uri, HttpHeaders headers) } }); - eventManager.handleEvent(eventGenerator.newResourceCreatedEvent(createdResource)); + referenceCleaner.cleanLiteralReferences(createdResource); + + eventHandler.handleEvent(eventGenerator.newResourceCreatedEvent(createdResource)); if (afterCreate != null) afterCreate.accept(createdResource); - URI location = uri.getAbsolutePathBuilder().path("/{id}/" + Constants.PARAM_HISTORY + "/{vid}") - .build(createdResource.getIdElement().getIdPart(), createdResource.getIdElement().getVersionIdPart()); + URI location = toLocation(uri, createdResource); - return responseGenerator - .response(Status.CREATED, createdResource, parameterConverter.getMediaType(uri, headers)) + return responseGenerator.response(Status.CREATED, createdResource, + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers), + parameterConverter.getPreferReturn(headers), () -> responseGenerator.created(location, createdResource)) .location(location).lastModified(createdResource.getMeta().getLastUpdated()) .tag(new EntityTag(createdResource.getMeta().getVersionId(), true)).build(); } - private R resolveReferences(Connection connection, final R created) throws SQLException + private URI toLocation(UriInfo uri, R resource) { - boolean resourceNeedsUpdated = false; - List references = referenceExtractor.getReferences(created).collect(Collectors.toList()); - // Don't use stream.map(...).anyMatch(b -> b), anyMatch is a shortcut operation stopping after first match - for (ResourceReference ref : references) - { - boolean needsUpdate = resolveReference(created, connection, ref); - if (needsUpdate) - resourceNeedsUpdated = true; - } + return uri.getBaseUriBuilder().path(resource.getResourceType().name()) + .path("/{id}/" + Constants.PARAM_HISTORY + "/{vid}") + .build(resource.getIdElement().getIdPart(), resource.getIdElement().getVersionIdPart()); + } - if (resourceNeedsUpdated) - { - try - { - return dao.updateSameRowWithTransaction(connection, created); - } - catch (ResourceNotFoundException e) - { - throw exceptionHandler.internalServerError(e); - } - } - return created; + private void resolveLogicalReferences(Resource resource, Connection connection) throws WebApplicationException + { + referenceExtractor.getReferences(resource).filter(ref -> ReferenceType.LOGICAL.equals(ref.getType(serverBase))) + .forEach(ref -> + { + Optional outcome = resolveLogicalReference(resource, ref, connection); + if (outcome.isPresent()) + { + Response response = Response.status(Status.FORBIDDEN).entity(outcome.get()).build(); + throw new WebApplicationException(response); + } + }); } - private boolean resolveReference(Resource resource, Connection connection, ResourceReference resourceReference) - throws WebApplicationException + private Optional resolveLogicalReference(Resource resource, ResourceReference reference, + Connection connection) { - switch (resourceReference.getType(serverBase)) + Optional resolvedResource = referenceResolver.resolveReference(getCurrentUser(), reference, + connection); + if (resolvedResource.isPresent()) { - case LITERAL_INTERNAL: - return referenceResolver.resolveLiteralInternalReference(resource, resourceReference, connection); - case LITERAL_EXTERNAL: - return referenceResolver.resolveLiteralExternalReference(resource, resourceReference); - case LOGICAL: - return referenceResolver.resolveLogicalReference(getCurrentUser(), resource, resourceReference, - connection); - default: - throw new WebApplicationException(responseGenerator.unknownReference(resource, resourceReference)); + Resource target = resolvedResource.get(); + reference.getReference().setReferenceElement( + new IdType(target.getResourceType().name(), target.getIdElement().getIdPart())); + + return Optional.empty(); } + else + return Optional.of(responseGenerator.referenceTargetNotFoundLocallyByIdentifier(resource, reference)); } private void checkAlreadyExists(HttpHeaders headers) throws WebApplicationException @@ -267,10 +276,10 @@ private void checkAlreadyExists(HttpHeaders headers) throws WebApplicationExcept responseGenerator.badIfNoneExistHeaderValue(ifNoneExistHeader.get(), unsupportedQueryParameters)); PartialResult result = exceptionHandler.handleSqlException(() -> dao.search(query)); - if (result.getOverallCount() == 1) + if (result.getTotal() == 1) throw new WebApplicationException( responseGenerator.oneExists(result.getPartialResult().get(0), ifNoneExistHeader.get())); - else if (result.getOverallCount() > 1) + else if (result.getTotal() > 1) throw new WebApplicationException( responseGenerator.multipleExists(resourceTypeName, ifNoneExistHeader.get())); } @@ -300,7 +309,7 @@ protected Consumer preCreate(R resource) throws WebApplicationException @Override public Response read(String id, UriInfo uri, HttpHeaders headers) { - Optional read = exceptionHandler.handleSqlAndResourceDeletedException(resourceTypeName, + Optional read = exceptionHandler.handleSqlAndResourceDeletedException(serverBase, resourceTypeName, () -> dao.read(parameterConverter.toUuid(resourceTypeName, id))); Optional ifModifiedSince = getHeaderString(headers, Constants.HEADER_IF_MODIFIED_SINCE, @@ -310,17 +319,23 @@ public Response read(String id, UriInfo uri, HttpHeaders headers) return read.map(resource -> { + referenceCleaner.cleanLiteralReferences(resource); + EntityTag resourceTag = new EntityTag(resource.getMeta().getVersionId(), true); if (ifNoneMatch.map(t -> t.equals(resourceTag)).orElse(false)) return Response.notModified(resourceTag).lastModified(resource.getMeta().getLastUpdated()).build(); else if (ifModifiedSince.map(d -> resource.getMeta().getLastUpdated().after(d)).orElse(false)) return Response.notModified(resourceTag).lastModified(resource.getMeta().getLastUpdated()).build(); else - return responseGenerator.response(Status.OK, resource, parameterConverter.getMediaType(uri, headers)) - .build(); + return responseGenerator.response(Status.OK, resource, getMediaTypeForRead(uri, headers)).build(); }).orElseGet(() -> Response.status(Status.NOT_FOUND).build()); // TODO return OperationOutcome } + protected MediaType getMediaTypeForRead(UriInfo uri, HttpHeaders headers) + { + return parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers); + } + /** * @param rfc1123DateValue * RFC 1123 date string @@ -348,8 +363,8 @@ private Optional toDate(String rfc1123DateValue) @Override public Response vread(String id, long version, UriInfo uri, HttpHeaders headers) { - Optional read = exceptionHandler - .handleSqlException(() -> dao.readVersion(parameterConverter.toUuid(resourceTypeName, id), version)); + Optional read = exceptionHandler.handleSqlAndResourceDeletedException(serverBase, id, + () -> dao.readVersion(parameterConverter.toUuid(resourceTypeName, id), version)); Optional ifModifiedSince = getHeaderString(headers, Constants.HEADER_IF_MODIFIED_SINCE, Constants.HEADER_IF_MODIFIED_SINCE_LC).flatMap(this::toDate); @@ -358,17 +373,41 @@ public Response vread(String id, long version, UriInfo uri, HttpHeaders headers) return read.map(resource -> { + referenceCleaner.cleanLiteralReferences(resource); + EntityTag resourceTag = new EntityTag(resource.getMeta().getVersionId(), true); if (ifNoneMatch.map(t -> t.equals(resourceTag)).orElse(false)) return Response.notModified(resourceTag).lastModified(resource.getMeta().getLastUpdated()).build(); else if (ifModifiedSince.map(d -> resource.getMeta().getLastUpdated().after(d)).orElse(false)) return Response.notModified(resourceTag).lastModified(resource.getMeta().getLastUpdated()).build(); else - return responseGenerator.response(Status.OK, resource, parameterConverter.getMediaType(uri, headers)) - .build(); + return responseGenerator.response(Status.OK, resource, getMediaTypeForVRead(uri, headers)).build(); }).orElseGet(() -> Response.status(Status.NOT_FOUND).build()); // TODO return OperationOutcome } + protected MediaType getMediaTypeForVRead(UriInfo uri, HttpHeaders headers) + { + return parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers); + } + + @Override + public Response history(UriInfo uri, HttpHeaders headers) + { + Bundle history = historyService.getHistory(getCurrentUser(), uri, headers, resourceType); + + return responseGenerator.response(Status.OK, referenceCleaner.cleanLiteralReferences(history), + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); + } + + @Override + public Response history(String id, UriInfo uri, HttpHeaders headers) + { + Bundle history = historyService.getHistory(getCurrentUser(), uri, headers, resourceType, id); + + return responseGenerator.response(Status.OK, referenceCleaner.cleanLiteralReferences(history), + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); + } + @Override public Response update(String id, R resource, UriInfo uri, HttpHeaders headers) { @@ -391,9 +430,11 @@ public Response update(String id, R resource, UriInfo uri, HttpHeaders headers) { try { + resolveLogicalReferences(resource, connection); + R updated = dao.update(resource, ifMatch.orElse(null)); - updated = resolveReferences(connection, updated); + // updated = resolveReferences(connection, updated); connection.commit(); @@ -407,13 +448,21 @@ public Response update(String id, R resource, UriInfo uri, HttpHeaders headers) } }); - eventManager.handleEvent(eventGenerator.newResourceUpdatedEvent(updatedResource)); + referenceCleaner.cleanLiteralReferences(updatedResource); + + eventHandler.handleEvent(eventGenerator.newResourceUpdatedEvent(updatedResource)); if (afterUpdate != null) afterUpdate.accept(updatedResource); - return responseGenerator.response(Status.OK, updatedResource, parameterConverter.getMediaType(uri, headers)) - .build(); + URI location = toLocation(uri, updatedResource); + + return responseGenerator + .response(Status.OK, updatedResource, parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers), + parameterConverter.getPreferReturn(headers), + () -> responseGenerator.updated(location, updatedResource)) + .location(location).lastModified(updatedResource.getMeta().getLastUpdated()) + .tag(new EntityTag(updatedResource.getMeta().getVersionId(), true)).build(); } /** @@ -448,13 +497,13 @@ public Response delete(String id, UriInfo uri, HttpHeaders headers) () -> dao.delete(parameterConverter.toUuid(resourceTypeName, id))); if (deleted) - eventManager.handleEvent(eventGenerator.newResourceDeletedEvent(resourceType, id)); + eventHandler.handleEvent(eventGenerator.newResourceDeletedEvent(resourceType, id)); if (afterDelete != null) afterDelete.accept(id); return responseGenerator.response(Status.OK, responseGenerator.resourceDeleted(resourceTypeName, id), - parameterConverter.getMediaType(uri, headers)).build(); + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); } /** @@ -494,7 +543,11 @@ public Response search(UriInfo uri, HttpHeaders headers) SearchQuery query = dao.createSearchQuery(getCurrentUser(), effectivePage, effectiveCount); query.configureParameters(queryParameters); List errors = query.getUnsupportedQueryParameters(queryParameters); - // TODO throw error if strict param handling is configured, include warning else + + // if query parameter errors and client requests strict handling -> bad request outcome + if (!errors.isEmpty() && PreferHandlingType.STRICT.equals(parameterConverter.getPreferHandling(headers))) + return responseGenerator.response(Status.BAD_REQUEST, responseGenerator.toOperationOutcomeError(errors), + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); PartialResult result = exceptionHandler.handleSqlException(() -> dao.search(query)); @@ -506,14 +559,19 @@ public Response search(UriInfo uri, HttpHeaders headers) String pretty = queryParameters.getFirst(SearchQuery.PARAMETER_PRETTY); Bundle searchSet = responseGenerator.createSearchSet(result, errors, bundleUri, format, pretty); - return responseGenerator.response(Status.OK, searchSet, parameterConverter.getMediaType(uri, headers)).build(); + // clean literal references from bundle entries + searchSet.getEntry().stream().filter(BundleEntryComponent::hasResource).map(BundleEntryComponent::getResource) + .forEach(referenceCleaner::cleanLiteralReferences); + + return responseGenerator + .response(Status.OK, searchSet, parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)) + .build(); } private PartialResult filterIncludeResources(PartialResult result) { List includes = filterIncludeResources(result.getIncludes()); - return new PartialResult(result.getOverallCount(), result.getPageAndCount(), result.getPartialResult(), - includes, result.isCountOnly()); + return new PartialResult(result.getTotal(), result.getPageAndCount(), result.getPartialResult(), includes); } private List filterIncludeResources(List includes) @@ -652,7 +710,7 @@ public Response postValidateExisting(String validate, String id, Parameters para UriType profileUri = (UriType) profile; - Optional read = exceptionHandler.handleSqlAndResourceDeletedException(resourceTypeName, + Optional read = exceptionHandler.handleSqlAndResourceDeletedException(serverBase, resourceTypeName, () -> dao.read(parameterConverter.toUuid(resourceTypeName, id))); R resource = read.get(); @@ -663,10 +721,10 @@ public Response postValidateExisting(String validate, String id, Parameters para if (result.isSuccessful()) return responseGenerator.response(Status.OK, createValidationOutcomeOk(result.getMessages(), Collections.singletonList(profileUri.getValue())), - parameterConverter.getMediaType(uri, headers)).build(); + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); else return responseGenerator.response(Status.OK, createValidationOutcomeError(result.getMessages()), - parameterConverter.getMediaType(uri, headers)).build(); + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); } @Override @@ -681,7 +739,7 @@ public Response getValidateExisting(String validate, String id, UriInfo uri, Htt if ("profile".equals(mode)) { - Optional read = exceptionHandler.handleSqlAndResourceDeletedException(resourceTypeName, + Optional read = exceptionHandler.handleSqlAndResourceDeletedException(serverBase, resourceTypeName, () -> dao.read(parameterConverter.toUuid(resourceTypeName, id))); R resource = read.get(); @@ -695,10 +753,10 @@ public Response getValidateExisting(String validate, String id, UriInfo uri, Htt createValidationOutcomeOk(result.getMessages(), resource.getMeta().getProfile().stream().map(t -> t.getValue()) .collect(Collectors.toList())), - parameterConverter.getMediaType(uri, headers)).build(); + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); else return responseGenerator.response(Status.OK, createValidationOutcomeError(result.getMessages()), - parameterConverter.getMediaType(uri, headers)).build(); + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); } else if ("delete".equals(mode)) return Response.status(Status.METHOD_NOT_ALLOWED).build(); // TODO mode = delete diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/ActivityDefinitionServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/ActivityDefinitionServiceImpl.java index 8daaae460..b91fa8adb 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/ActivityDefinitionServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/ActivityDefinitionServiceImpl.java @@ -3,10 +3,12 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.ActivityDefinitionDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; @@ -17,13 +19,14 @@ public class ActivityDefinitionServiceImpl extends AbstractResourceServiceImpl implements ActivityDefinitionService { public ActivityDefinitionServiceImpl(String path, String serverBase, int defaultPageCount, - ActivityDefinitionDao dao, ResourceValidator validator, EventManager eventManager, + ActivityDefinitionDao dao, ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, - ReferenceResolver referenceResolver, AuthorizationRuleProvider authorizationRuleProvider) + ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, + AuthorizationRuleProvider authorizationRuleProvider, HistoryService historyService) { - super(path, ActivityDefinition.class, serverBase, defaultPageCount, dao, validator, eventManager, + super(path, ActivityDefinition.class, serverBase, defaultPageCount, dao, validator, eventHandler, exceptionHandler, eventGenerator, responseGenerator, parameterConverter, referenceExtractor, - referenceResolver, authorizationRuleProvider); + referenceResolver, referenceCleaner, authorizationRuleProvider, historyService); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/BinaryServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/BinaryServiceImpl.java index 0bbcaafc1..21f94268b 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/BinaryServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/BinaryServiceImpl.java @@ -1,28 +1,77 @@ package org.highmed.dsf.fhir.webservice.impl; +import java.io.InputStream; +import java.util.List; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.BinaryDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.BinaryService; import org.hl7.fhir.r4.model.Binary; +import ca.uhn.fhir.rest.api.Constants; + public class BinaryServiceImpl extends AbstractResourceServiceImpl implements BinaryService { public BinaryServiceImpl(String path, String serverBase, int defaultPageCount, BinaryDao dao, - ResourceValidator validator, EventManager eventManager, ExceptionHandler exceptionHandler, + ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - AuthorizationRuleProvider authorizationRuleProvider) + ReferenceCleaner referenceCleaner, AuthorizationRuleProvider authorizationRuleProvider, + HistoryService historyService) { - super(path, Binary.class, serverBase, defaultPageCount, dao, validator, eventManager, exceptionHandler, + super(path, Binary.class, serverBase, defaultPageCount, dao, validator, eventHandler, exceptionHandler, eventGenerator, responseGenerator, parameterConverter, referenceExtractor, referenceResolver, - authorizationRuleProvider); + referenceCleaner, authorizationRuleProvider, historyService); + } + + @Override + public Response create(InputStream in, UriInfo uri, HttpHeaders headers) + { + throw new UnsupportedOperationException("Implemented and delegated by jaxrs layer"); + } + + @Override + public Response update(String id, InputStream in, UriInfo uri, HttpHeaders headers) + { + throw new UnsupportedOperationException("Implemented and delegated by jaxrs layer"); + } + + @Override + protected MediaType getMediaTypeForRead(UriInfo uri, HttpHeaders headers) + { + if (uri.getQueryParameters().containsKey(Constants.PARAM_FORMAT)) + return super.getMediaTypeForRead(uri, headers); + else + return getMediaType(uri, headers); + } + + @Override + protected MediaType getMediaTypeForVRead(UriInfo uri, HttpHeaders headers) + { + if (uri.getQueryParameters().containsKey(Constants.PARAM_FORMAT)) + return super.getMediaTypeForVRead(uri, headers); + else + return getMediaType(uri, headers); + } + + private MediaType getMediaType(UriInfo uri, HttpHeaders headers) + { + List types = headers.getAcceptableMediaTypes(); + return types == null ? null : types.get(0); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/BundleServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/BundleServiceImpl.java index d5615d8be..76f993ee5 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/BundleServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/BundleServiceImpl.java @@ -3,10 +3,12 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.BundleDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; @@ -16,13 +18,14 @@ public class BundleServiceImpl extends AbstractResourceServiceImpl implements BundleService { public BundleServiceImpl(String path, String serverBase, int defaultPageCount, BundleDao dao, - ResourceValidator validator, EventManager eventManager, ExceptionHandler exceptionHandler, + ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - AuthorizationRuleProvider authorizationRuleProvider) + ReferenceCleaner referenceCleaner, AuthorizationRuleProvider authorizationRuleProvider, + HistoryService historyService) { - super(path, Bundle.class, serverBase, defaultPageCount, dao, validator, eventManager, exceptionHandler, + super(path, Bundle.class, serverBase, defaultPageCount, dao, validator, eventHandler, exceptionHandler, eventGenerator, responseGenerator, parameterConverter, referenceExtractor, referenceResolver, - authorizationRuleProvider); + referenceCleaner, authorizationRuleProvider, historyService); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/CodeSystemServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/CodeSystemServiceImpl.java index ac068a160..ab9e3bbb5 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/CodeSystemServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/CodeSystemServiceImpl.java @@ -3,10 +3,12 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.CodeSystemDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; @@ -17,13 +19,14 @@ public class CodeSystemServiceImpl extends AbstractResourceServiceImpl, List>(); + var searchParameters = new HashMap, List>>>(); var revIncludeParameters = new HashMap, List>>(); - var activityDefinitionUrl = createSearchParameter(ActivityDefinitionUrl.class); - var activityDefinitionIdentifier = createSearchParameter(ActivityDefinitionIdentifier.class); - var activityDefinitionVersion = createSearchParameter(ActivityDefinitionVersion.class); - var activityDefinitionName = createSearchParameter(ActivityDefinitionName.class); - var activityDefinitionStatus = createSearchParameter(ActivityDefinitionStatus.class); searchParameters.put(ActivityDefinition.class, - Arrays.asList(activityDefinitionUrl, activityDefinitionIdentifier, activityDefinitionVersion, - activityDefinitionName, activityDefinitionStatus)); - - var binaryContentType = createSearchParameter(BinaryContentType.class); - searchParameters.put(Binary.class, Arrays.asList(binaryContentType)); - - var bundleIdentifier = createSearchParameter(BundleIdentifier.class); - searchParameters.put(Bundle.class, Arrays.asList(bundleIdentifier)); - - var codeSystemIdentifier = createSearchParameter(CodeSystemIdentifier.class); - var codeSystemUrl = createSearchParameter(CodeSystemUrl.class); - var codeSystemVersion = createSearchParameter(CodeSystemVersion.class); - var codeSystemStatus = createSearchParameter(CodeSystemStatus.class); - searchParameters.put(CodeSystem.class, - Arrays.asList(codeSystemIdentifier, codeSystemUrl, codeSystemVersion, codeSystemStatus)); - - var endpointAddress = createSearchParameter(EndpointAddress.class); - var endpointIdentifier = createSearchParameter(EndpointIdentifier.class); - var endpointName = createSearchParameter(EndpointName.class); - var endpointOrganization = createSearchParameter(EndpointOrganization.class); - var endpointStatus = createSearchParameter(EndpointStatus.class); - searchParameters.put(Endpoint.class, - Arrays.asList(endpointAddress, endpointIdentifier, endpointName, endpointOrganization, endpointStatus)); - revIncludeParameters.put(Endpoint.class, Collections.singletonList(OrganizationEndpointRevInclude.class)); - - // Group - revIncludeParameters.put(Group.class, Collections.singletonList(ResearchStudyEnrollmentRevInclude.class)); - - var healthcareServiceActive = createSearchParameter(HealthcareServiceActive.class); - var healthcareServiceIdentifier = createSearchParameter(HealthcareServiceIdentifier.class); + Arrays.asList(ActivityDefinitionUrl.class, ActivityDefinitionIdentifier.class, + ActivityDefinitionVersion.class, ActivityDefinitionName.class, ActivityDefinitionStatus.class)); + + searchParameters.put(Binary.class, Arrays.asList(BinaryContentType.class)); + + searchParameters.put(Bundle.class, Arrays.asList(BundleIdentifier.class)); + + searchParameters.put(CodeSystem.class, Arrays.asList(CodeSystemIdentifier.class, CodeSystemUrl.class, + CodeSystemVersion.class, CodeSystemStatus.class)); + + searchParameters.put(Endpoint.class, Arrays.asList(EndpointAddress.class, EndpointIdentifier.class, + EndpointName.class, EndpointOrganization.class, EndpointStatus.class)); + revIncludeParameters.put(Endpoint.class, Arrays.asList(OrganizationEndpointRevInclude.class)); + + // no Group search parameters + revIncludeParameters.put(Group.class, Arrays.asList(ResearchStudyEnrollmentRevInclude.class)); + searchParameters.put(HealthcareService.class, - Arrays.asList(healthcareServiceActive, healthcareServiceIdentifier)); + Arrays.asList(HealthcareServiceActive.class, HealthcareServiceIdentifier.class)); - var locationIdentifier = createSearchParameter(LocationIdentifier.class); - searchParameters.put(Location.class, Arrays.asList(locationIdentifier)); + searchParameters.put(Location.class, Arrays.asList(LocationIdentifier.class)); - var namingSystemName = createSearchParameter(NamingSystemName.class); - searchParameters.put(NamingSystem.class, Arrays.asList(namingSystemName)); + searchParameters.put(NamingSystem.class, Arrays.asList(NamingSystemName.class)); - var organizationActive = createSearchParameter(OrganizationActive.class); - var organizationEndpoint = createSearchParameter(OrganizationEndpoint.class); - var organizationIdentifier = createSearchParameter(OrganizationIdentifier.class); - var organizationNameOrAlias = createSearchParameter(OrganizationName.class); - var organizationType = createSearchParameter(OrganizationType.class); - searchParameters.put(Organization.class, Arrays.asList(organizationActive, organizationEndpoint, - organizationIdentifier, organizationNameOrAlias, organizationType)); + searchParameters.put(Organization.class, Arrays.asList(OrganizationActive.class, OrganizationEndpoint.class, + OrganizationIdentifier.class, OrganizationName.class, OrganizationType.class)); revIncludeParameters.put(Organization.class, Collections.singletonList(EndpointOrganizationRevInclude.class)); - var patientActive = createSearchParameter(PatientActive.class); - var patientIdentifier = createSearchParameter(PatientIdentifier.class); - searchParameters.put(Patient.class, Arrays.asList(patientActive, patientIdentifier)); - - var practitionerActive = createSearchParameter(PractitionerActive.class); - var practitionerIdentifier = createSearchParameter(PractitionerIdentifier.class); - searchParameters.put(Practitioner.class, Arrays.asList(practitionerActive, practitionerIdentifier)); - - var practitionerRoleActive = createSearchParameter(PractitionerRoleActive.class); - var practitionerRoleIdentifier = createSearchParameter(PractitionerRoleIdentifier.class); - var practitionerRoleOrganization = createSearchParameter(PractitionerRoleOrganization.class); - var practitionerRolePractitioner = createSearchParameter(PractitionerRolePractitioner.class); - searchParameters.put(PractitionerRole.class, Arrays.asList(practitionerRoleActive, practitionerRoleIdentifier, - practitionerRoleOrganization, practitionerRolePractitioner)); - - var researchStudyIdentifier = createSearchParameter(ResearchStudyIdentifier.class); - var researchStudyEnrollment = createSearchParameter(ResearchStudyEnrollment.class); - var researchStudyPrincipalInvestigator = createSearchParameter(ResearchStudyPrincipalInvestigator.class); - searchParameters.put(ResearchStudy.class, - Arrays.asList(researchStudyIdentifier, researchStudyEnrollment, researchStudyPrincipalInvestigator)); - - var structureDefinitionIdentifier = createSearchParameter(StructureDefinitionIdentifier.class); - var structureDefinitionStatus = createSearchParameter(StructureDefinitionStatus.class); - var structureDefinitionUrl = createSearchParameter(StructureDefinitionUrl.class); - var structureDefinitionVersion = createSearchParameter(StructureDefinitionVersion.class); - searchParameters.put(StructureDefinition.class, Arrays.asList(structureDefinitionIdentifier, - structureDefinitionStatus, structureDefinitionUrl, structureDefinitionVersion)); - - var subscriptionCriteria = createSearchParameter(SubscriptionCriteria.class); - var subscriptionPayload = createSearchParameter(SubscriptionPayload.class); - var subscriptionStatus = createSearchParameter(SubscriptionStatus.class); - var subscriptionType = createSearchParameter(SubscriptionType.class); - searchParameters.put(Subscription.class, - Arrays.asList(subscriptionCriteria, subscriptionPayload, subscriptionStatus, subscriptionType)); - - var taskIdentifier = createSearchParameter(TaskIdentifier.class); - var taskRequester = createSearchParameter(TaskRequester.class); - var taskStatus = createSearchParameter(TaskStatus.class); - searchParameters.put(Task.class, Arrays.asList(taskIdentifier, taskRequester, taskStatus)); - - var valueSetIdentifier = createSearchParameter(ValueSetIdentifier.class); - var valueSetUrl = createSearchParameter(ValueSetUrl.class); - var valueSetVersion = createSearchParameter(ValueSetVersion.class); - var valueSetStatus = createSearchParameter(ValueSetStatus.class); - searchParameters.put(ValueSet.class, - Arrays.asList(valueSetIdentifier, valueSetUrl, valueSetVersion, valueSetStatus)); + searchParameters.put(Patient.class, Arrays.asList(PatientActive.class, PatientIdentifier.class)); + + searchParameters.put(Practitioner.class, Arrays.asList(PractitionerActive.class, PractitionerIdentifier.class)); + + searchParameters.put(PractitionerRole.class, + Arrays.asList(PractitionerRoleActive.class, PractitionerRoleIdentifier.class, + PractitionerRoleOrganization.class, PractitionerRolePractitioner.class)); + + searchParameters.put(ResearchStudy.class, Arrays.asList(ResearchStudyIdentifier.class, + ResearchStudyEnrollment.class, ResearchStudyPrincipalInvestigator.class)); + + searchParameters.put(StructureDefinition.class, Arrays.asList(StructureDefinitionIdentifier.class, + StructureDefinitionStatus.class, StructureDefinitionUrl.class, StructureDefinitionVersion.class)); + + searchParameters.put(Subscription.class, Arrays.asList(SubscriptionCriteria.class, SubscriptionPayload.class, + SubscriptionStatus.class, SubscriptionType.class)); + + searchParameters.put(Task.class, Arrays.asList(TaskAuthoredOn.class, TaskIdentifier.class, TaskModified.class, + TaskRequester.class, TaskStatus.class)); + + searchParameters.put(ValueSet.class, Arrays.asList(ValueSetIdentifier.class, ValueSetUrl.class, + ValueSetVersion.class, ValueSetStatus.class)); var operations = new HashMap, List>(); @@ -312,10 +278,16 @@ private CapabilityStatement createCapabilityStatement(String serverBase, int def "Generates a StructureDefinition instance with a snapshot, based on a differential in a specified StructureDefinition"); operations.put(StructureDefinition.class, Arrays.asList(snapshotOperation)); - var standardSortableSearchParameters = Arrays.asList(createSearchParameter(ResourceId.class), - createSearchParameter(ResourceLastUpdated.class)); + var standardSortableSearchParameters = Arrays.asList(ResourceId.class, ResourceLastUpdated.class); var standardOperations = Arrays.asList(createValidateOperation()); + Map> profileUrlsByResource = validationSupport.fetchAllStructureDefinitions() + .stream().filter(r -> r instanceof StructureDefinition).map(r -> (StructureDefinition) r) + .filter(s -> StructureDefinitionKind.RESOURCE.equals(s.getKind()) && !s.getAbstract() + && !s.getUrl().contains("hl7.org")) + .collect(Collectors.groupingBy(StructureDefinition::getType, + Collectors.mapping(s -> new CanonicalType(s.getUrl()), Collectors.toList()))); + for (Class resource : resources) { CapabilityStatementRestResourceComponent r = rest.addResource(); @@ -326,10 +298,12 @@ private CapabilityStatement createCapabilityStatement(String serverBase, int def r.setConditionalRead(ConditionalReadStatus.FULLSUPPORT); r.setConditionalUpdate(true); r.setConditionalDelete(ConditionalDeleteStatus.SINGLE); - r.addReferencePolicy(ReferenceHandlingPolicy.ENFORCED); + r.addReferencePolicy(ReferenceHandlingPolicy.LITERAL); + r.addReferencePolicy(ReferenceHandlingPolicy.LOGICAL); - r.setType(resource.getAnnotation(ResourceDef.class).name()); - r.setProfile(resource.getAnnotation(ResourceDef.class).profile()); + ResourceDef resourceDefAnnotation = resource.getAnnotation(ResourceDef.class); + r.setType(resourceDefAnnotation.name()); + r.setProfile(resourceDefAnnotation.profile()); r.addInteraction().setCode(TypeRestfulInteraction.CREATE); r.addInteraction().setCode(TypeRestfulInteraction.READ); r.addInteraction().setCode(TypeRestfulInteraction.VREAD); @@ -337,62 +311,77 @@ private CapabilityStatement createCapabilityStatement(String serverBase, int def r.addInteraction().setCode(TypeRestfulInteraction.DELETE); r.addInteraction().setCode(TypeRestfulInteraction.SEARCHTYPE); - standardSortableSearchParameters.stream().forEach(r::addSearchParam); - var resourceSearchParameters = searchParameters.getOrDefault(resource, Collections.emptyList()); - resourceSearchParameters.stream() + var resourceRevIncludeParameters = revIncludeParameters.getOrDefault(resource, Collections.emptyList()); + + resourceSearchParameters.stream().map(this::createSearchParameter) .sorted(Comparator.comparing(CapabilityStatementRestResourceSearchParamComponent::getName)) .forEach(r::addSearchParam); - if (resourceSearchParameters.stream().anyMatch(s -> SearchParamType.REFERENCE.equals(s.getType()))) - r.addSearchParam(createIncludeParameter(resource, resourceSearchParameters)); - - r.setSearchInclude(resourceSearchParameters.stream() - .filter(s -> SearchParamType.REFERENCE.equals(s.getType())) - .map(s -> new StringType(resource.getAnnotation(ResourceDef.class).name() + ":" + s.getName())) - .collect(Collectors.toList())); - - r.setSearchRevInclude( - revIncludeParameters.getOrDefault(resource, Collections.emptyList()).stream().flatMap(c -> - { - RevIncludeDefinition def = c.getAnnotation(RevIncludeDefinition.class); - if (def == null) - return Stream.empty(); - else - { - String resourceTypeName = def.resourceType().getAnnotation(ResourceDef.class).name(); - String parameterName = def.parameterName(); - return Arrays.stream(def.targetResourceTypes()) - .map(t -> t.getAnnotation(ResourceDef.class).name()) - .map(targetResourceTypeName -> new StringType( - resourceTypeName + ":" + parameterName + ":" + targetResourceTypeName)); - } - }).collect(Collectors.toList())); + var includes = resourceSearchParameters.stream().map(p -> p.getAnnotation(IncludeParameterDefinition.class)) + .filter(def -> def != null).collect(Collectors.toList()); + if (!includes.isEmpty()) + { + r.addSearchParam(createIncludeParameter(includes)); + r.setSearchInclude(includes.stream().flatMap(this::toIncludeParameterNames).sorted() + .map(StringType::new).collect(Collectors.toList())); + } + + var revIncludes = resourceRevIncludeParameters.stream() + .map(p -> p.getAnnotation(IncludeParameterDefinition.class)).filter(def -> def != null) + .collect(Collectors.toList()); + if (!revIncludes.isEmpty()) + { + r.addSearchParam(createRevIncludeParameter(revIncludes)); + r.setSearchRevInclude(revIncludes.stream().flatMap(this::toIncludeParameterNames).sorted() + .map(StringType::new).collect(Collectors.toList())); + } r.addSearchParam(createFormatParameter()); r.addSearchParam(createPrettyParameter()); r.addSearchParam(createCountParameter(defaultPageCount)); r.addSearchParam(createPageParameter()); - r.addSearchParam(createSortParameter(standardSortableSearchParameters, resourceSearchParameters)); + r.addSearchParam(createSortParameter( + Stream.concat(standardSortableSearchParameters.stream(), resourceSearchParameters.stream()))); operations.getOrDefault(resource, Collections.emptyList()).forEach(r::addOperation); standardOperations.forEach(r::addOperation); + + r.setSupportedProfile( + profileUrlsByResource.getOrDefault(resourceDefAnnotation.name(), Collections.emptyList())); } + return statement; } private CapabilityStatementRestResourceSearchParamComponent createIncludeParameter( - Class resource, - List resourceSearchParameters) + List includes) { + String values = includes.stream().flatMap(this::toIncludeParameterNames).sorted() + .collect(Collectors.joining(", ", "[", "]")); return createSearchParameter("_include", "", SearchParamType.SPECIAL, - "Additional resources to return, allowed values: " - + resourceSearchParameters.stream().filter(s -> SearchParamType.REFERENCE.equals(s.getType())) - .map(s -> resource.getAnnotation(ResourceDef.class).name() + ":" + s.getName()) - .collect(Collectors.joining(", ", "[", "]")) + "Additional resources to return, allowed values: " + values + " (use one _include parameter for every resource to include)"); } + private CapabilityStatementRestResourceSearchParamComponent createRevIncludeParameter( + List revIncludes) + { + String values = revIncludes.stream().flatMap(this::toIncludeParameterNames).sorted() + .collect(Collectors.joining(", ", "[", "]")); + + return createSearchParameter("_revinclude", "", SearchParamType.SPECIAL, + "Additional resources to return, allowed values: " + values + + " (use one _revinclude parameter for every resource to include)"); + } + + private Stream toIncludeParameterNames(IncludeParameterDefinition def) + { + return Arrays.stream(def.targetResourceTypes()).map(target -> target.getAnnotation(ResourceDef.class).name()) + .map(target -> def.resourceType().getAnnotation(ResourceDef.class).name() + ":" + def.parameterName() + + ":" + target); + } + private CapabilityStatementRestResourceOperationComponent createValidateOperation() { return createOperation("validate", "http://hl7.org/fhir/OperationDefinition/Resource-validate", @@ -400,13 +389,13 @@ private CapabilityStatementRestResourceOperationComponent createValidateOperatio } private CapabilityStatementRestResourceSearchParamComponent createSortParameter( - List standardSearchParameters, - List resourceSearchParameters) + @SuppressWarnings("rawtypes") Stream> parameters) { + String values = parameters.map(p -> p.getAnnotation(SearchParameterDefinition.class)).map(def -> def.name()) + .sorted().collect(Collectors.joining(", ", "[", "]")); + return createSearchParameter("_sort", "", SearchParamType.SPECIAL, - "Specify the returned order, allowed values: " - + Streams.concat(standardSearchParameters.stream(), resourceSearchParameters.stream()) - .map(s -> s.getName()).collect(Collectors.joining(", ", "[", "]")) + "Specify the returned order, allowed values: " + values + " (one or multiple as comma separated string), prefix with '-' for reversed order"); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/EndpointServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/EndpointServiceImpl.java index 5993c6211..ed6286509 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/EndpointServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/EndpointServiceImpl.java @@ -3,10 +3,12 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.EndpointDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; @@ -16,13 +18,14 @@ public class EndpointServiceImpl extends AbstractResourceServiceImpl implements EndpointService { public EndpointServiceImpl(String path, String serverBase, int defaultPageCount, EndpointDao dao, - ResourceValidator validator, EventManager eventManager, ExceptionHandler exceptionHandler, + ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - AuthorizationRuleProvider authorizationRuleProvider) + ReferenceCleaner referenceCleaner, AuthorizationRuleProvider authorizationRuleProvider, + HistoryService historyService) { - super(path, Endpoint.class, serverBase, defaultPageCount, dao, validator, eventManager, exceptionHandler, + super(path, Endpoint.class, serverBase, defaultPageCount, dao, validator, eventHandler, exceptionHandler, eventGenerator, responseGenerator, parameterConverter, referenceExtractor, referenceResolver, - authorizationRuleProvider); + referenceCleaner, authorizationRuleProvider, historyService); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/GroupServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/GroupServiceImpl.java index cd40e00f2..c28708524 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/GroupServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/GroupServiceImpl.java @@ -3,10 +3,12 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.GroupDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; @@ -16,13 +18,14 @@ public class GroupServiceImpl extends AbstractResourceServiceImpl implements GroupService { public GroupServiceImpl(String path, String serverBase, int defaultPageCount, GroupDao dao, - ResourceValidator validator, EventManager eventManager, ExceptionHandler exceptionHandler, + ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - AuthorizationRuleProvider authorizationRuleProvider) + ReferenceCleaner referenceCleaner, AuthorizationRuleProvider authorizationRuleProvider, + HistoryService historyService) { - super(path, Group.class, serverBase, defaultPageCount, dao, validator, eventManager, exceptionHandler, + super(path, Group.class, serverBase, defaultPageCount, dao, validator, eventHandler, exceptionHandler, eventGenerator, responseGenerator, parameterConverter, referenceExtractor, referenceResolver, - authorizationRuleProvider); + referenceCleaner, authorizationRuleProvider, historyService); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/HealthcareServiceServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/HealthcareServiceServiceImpl.java index b57990e93..cb5eb1b9f 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/HealthcareServiceServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/HealthcareServiceServiceImpl.java @@ -3,10 +3,12 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.HealthcareServiceDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; @@ -17,13 +19,14 @@ public class HealthcareServiceServiceImpl extends AbstractResourceServiceImpl implements LocationService { public LocationServiceImpl(String path, String serverBase, int defaultPageCount, LocationDao dao, - ResourceValidator validator, EventManager eventManager, ExceptionHandler exceptionHandler, + ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - AuthorizationRuleProvider authorizationRuleProvider) + ReferenceCleaner referenceCleaner, AuthorizationRuleProvider authorizationRuleProvider, + HistoryService historyService) { - super(path, Location.class, serverBase, defaultPageCount, dao, validator, eventManager, exceptionHandler, + super(path, Location.class, serverBase, defaultPageCount, dao, validator, eventHandler, exceptionHandler, eventGenerator, responseGenerator, parameterConverter, referenceExtractor, referenceResolver, - authorizationRuleProvider); + referenceCleaner, authorizationRuleProvider, historyService); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/NamingSystemServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/NamingSystemServiceImpl.java index 8ac640087..37d522680 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/NamingSystemServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/NamingSystemServiceImpl.java @@ -3,10 +3,12 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.NamingSystemDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; @@ -17,13 +19,14 @@ public class NamingSystemServiceImpl extends AbstractResourceServiceImpl implements PatientService { public PatientServiceImpl(String path, String serverBase, int defaultPageCount, PatientDao dao, - ResourceValidator validator, EventManager eventManager, ExceptionHandler exceptionHandler, + ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - AuthorizationRuleProvider authorizationRuleProvider) + ReferenceCleaner referenceCleaner, AuthorizationRuleProvider authorizationRuleProvider, + HistoryService historyService) { - super(path, Patient.class, serverBase, defaultPageCount, dao, validator, eventManager, exceptionHandler, + super(path, Patient.class, serverBase, defaultPageCount, dao, validator, eventHandler, exceptionHandler, eventGenerator, responseGenerator, parameterConverter, referenceExtractor, referenceResolver, - authorizationRuleProvider); + referenceCleaner, authorizationRuleProvider, historyService); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/PractitionerRoleServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/PractitionerRoleServiceImpl.java index 7292c311f..e337553f7 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/PractitionerRoleServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/PractitionerRoleServiceImpl.java @@ -3,10 +3,12 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.PractitionerRoleDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; @@ -17,13 +19,14 @@ public class PractitionerRoleServiceImpl extends AbstractResourceServiceImpl commandFactory.createCommands(bundle, getCurrentUser())); + .handleBadBundleException(() -> commandFactory.createCommands(bundle, getCurrentUser(), + parameterConverter.getPreferReturn(headers), parameterConverter.getPreferHandling(headers))); Bundle result = commands.execute(); // throws WebApplicationException - return responseGenerator.response(Status.OK, result, parameterConverter.getMediaType(uri, headers)).build(); + return responseGenerator + .response(Status.OK, result, parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); + } + + @Override + public Response history(UriInfo uri, HttpHeaders headers) + { + Bundle history = historyService.getHistory(getCurrentUser(), uri, headers); + + return responseGenerator.response(Status.OK, referenceCleaner.cleanLiteralReferences(history), + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/StructureDefinitionServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/StructureDefinitionServiceImpl.java index 5bf294dc7..0f046acbb 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/StructureDefinitionServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/StructureDefinitionServiceImpl.java @@ -17,25 +17,22 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.StructureDefinitionDao; -import org.highmed.dsf.fhir.dao.StructureDefinitionSnapshotDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; -import org.highmed.dsf.fhir.function.ConsumerWithSqlAndResourceNotFoundException; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; import org.highmed.dsf.fhir.search.PartialResult; import org.highmed.dsf.fhir.search.SearchQuery; import org.highmed.dsf.fhir.search.parameters.ResourceLastUpdated; import org.highmed.dsf.fhir.search.parameters.StructureDefinitionUrl; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; -import org.highmed.dsf.fhir.service.SnapshotDependencies; -import org.highmed.dsf.fhir.service.SnapshotDependencyAnalyzer; import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.highmed.dsf.fhir.service.SnapshotGenerator.SnapshotWithValidationMessages; -import org.highmed.dsf.fhir.service.SnapshotInfo; import org.highmed.dsf.fhir.webservice.specification.StructureDefinitionService; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity; @@ -56,25 +53,23 @@ public class StructureDefinitionServiceImpl extends { private static final Logger logger = LoggerFactory.getLogger(StructureDefinitionServiceImpl.class); - private final StructureDefinitionSnapshotDao snapshotDao; + private final StructureDefinitionDao snapshotDao; private final SnapshotGenerator snapshotGenerator; - private final SnapshotDependencyAnalyzer snapshotDependencyAnalyzer; public StructureDefinitionServiceImpl(String path, String serverBase, int defaultPageCount, - StructureDefinitionDao dao, ResourceValidator validator, EventManager eventManager, + StructureDefinitionDao dao, ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, - ReferenceResolver referenceResolver, AuthorizationRuleProvider authorizationRuleProvider, - StructureDefinitionSnapshotDao structureDefinitionSnapshotDao, SnapshotGenerator sanapshotGenerator, - SnapshotDependencyAnalyzer snapshotDependencyAnalyzer) + ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, + AuthorizationRuleProvider authorizationRuleProvider, StructureDefinitionDao structureDefinitionSnapshotDao, + SnapshotGenerator sanapshotGenerator, HistoryService historyService) { - super(path, StructureDefinition.class, serverBase, defaultPageCount, dao, validator, eventManager, + super(path, StructureDefinition.class, serverBase, defaultPageCount, dao, validator, eventHandler, exceptionHandler, eventGenerator, responseGenerator, parameterConverter, referenceExtractor, - referenceResolver, authorizationRuleProvider); + referenceResolver, referenceCleaner, authorizationRuleProvider, historyService); this.snapshotDao = structureDefinitionSnapshotDao; this.snapshotGenerator = sanapshotGenerator; - this.snapshotDependencyAnalyzer = snapshotDependencyAnalyzer; } @Override @@ -111,10 +106,9 @@ private Consumer postCreate(StructureDefinition preResource { if (preResource != null && preResource.hasSnapshot()) { - handleSnapshot(preResource, - info -> snapshotDao.create( - parameterConverter.toUuid(resourceTypeName, postResource.getIdElement().getIdPart()), - preResource, info)); + exceptionHandler.catchAndLogSqlAndResourceNotFoundException(resourceTypeName, + () -> snapshotDao.createWithId(preResource, + parameterConverter.toUuid(resourceTypeName, postResource.getIdElement().getIdPart()))); } else if (postResource != null) { @@ -123,9 +117,9 @@ else if (postResource != null) SnapshotWithValidationMessages s = snapshotGenerator.generateSnapshot(postResource); if (s != null && s.getSnapshot() != null && s.getMessages().isEmpty()) - handleSnapshot(s.getSnapshot(), info -> snapshotDao.create( - parameterConverter.toUuid(resourceTypeName, postResource.getIdElement().getIdPart()), - postResource, info)); + exceptionHandler.catchAndLogSqlAndResourceNotFoundException(resourceTypeName, + () -> snapshotDao.createWithId(postResource, parameterConverter.toUuid(resourceTypeName, + postResource.getIdElement().getIdPart()))); } catch (Exception e) { @@ -142,7 +136,11 @@ private Consumer postUpdate(StructureDefinition preResource { if (preResource != null && preResource.hasSnapshot()) { - handleSnapshot(preResource, info -> snapshotDao.update(preResource, info)); + if (postResource != null) + preResource.setIdElement(postResource.getIdElement().copy()); + + exceptionHandler.catchAndLogSqlAndResourceNotFoundException(resourceTypeName, + () -> snapshotDao.update(preResource)); } else if (postResource != null) { @@ -151,7 +149,8 @@ else if (postResource != null) SnapshotWithValidationMessages s = snapshotGenerator.generateSnapshot(postResource); if (s != null && s.getSnapshot() != null && s.getMessages().isEmpty()) - handleSnapshot(s.getSnapshot(), info -> snapshotDao.update(s.getSnapshot(), info)); + exceptionHandler.catchAndLogSqlAndResourceNotFoundException(resourceTypeName, + () -> snapshotDao.update(s.getSnapshot())); } catch (Exception e) { @@ -162,17 +161,6 @@ else if (postResource != null) }; } - private void handleSnapshot(StructureDefinition snapshot, - ConsumerWithSqlAndResourceNotFoundException dbOp) - { - SnapshotDependencies dependencies = snapshotDependencyAnalyzer.analyzeSnapshotDependencies(snapshot); - - exceptionHandler.catchAndLogSqlException(() -> snapshotDao.deleteAllByDependency(snapshot.getUrl())); - - exceptionHandler.catchAndLogSqlAndResourceNotFoundException(resourceTypeName, - () -> dbOp.accept(new SnapshotInfo(dependencies))); - } - @Override protected Consumer preDelete(String id) { @@ -217,11 +205,12 @@ else if (urlType == null && resource.isPresent() && resource.get().getResource() return Response.status(Status.BAD_REQUEST).build(); // TODO OperationOutcome if (sd.hasSnapshot()) - return responseGenerator.response(Status.OK, sd, parameterConverter.getMediaType(uri, headers)).build(); - else return responseGenerator - .response(Status.OK, generateSnapshot(sd), parameterConverter.getMediaType(uri, headers)) + .response(Status.OK, sd, parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)) .build(); + else + return responseGenerator.response(Status.OK, generateSnapshot(sd), + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); } else { @@ -246,7 +235,8 @@ private Response getSnapshot(String url, UriInfo uri, HttpHeaders headers) .ofNullable(result.getPartialResult().isEmpty() ? null : result.getPartialResult().get(0)); return snapshot - .map(d -> responseGenerator.response(Status.OK, d, parameterConverter.getMediaType(uri, headers))) + .map(d -> responseGenerator.response(Status.OK, d, + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers))) .orElse(Response.status(Status.NOT_FOUND)).build(); } @@ -270,15 +260,15 @@ public Response getSnapshotExisting(String snapshotPath, String id, UriInfo uri, Optional::empty); if (snapshot.isPresent()) - return snapshot - .map(d -> responseGenerator.response(Status.OK, d, parameterConverter.getMediaType(uri, headers))) - .get().build(); + return snapshot.map(d -> responseGenerator.response(Status.OK, d, + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers))).get().build(); - Optional differential = exceptionHandler.handleSqlAndResourceDeletedException( + Optional differential = exceptionHandler.handleSqlAndResourceDeletedException(serverBase, resourceTypeName, () -> dao.read(parameterConverter.toUuid(resourceTypeName, id))); return differential.map(this::generateSnapshot) - .map(d -> responseGenerator.response(Status.OK, d, parameterConverter.getMediaType(uri, headers))) + .map(d -> responseGenerator.response(Status.OK, d, + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers))) .orElse(Response.status(Status.NOT_FOUND)).build(); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/SubscriptionServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/SubscriptionServiceImpl.java index 321e53c21..6f144f632 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/SubscriptionServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/SubscriptionServiceImpl.java @@ -3,10 +3,12 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.SubscriptionDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; @@ -17,13 +19,14 @@ public class SubscriptionServiceImpl extends AbstractResourceServiceImpl implements TaskService { public TaskServiceImpl(String path, String serverBase, int defaultPageCount, TaskDao dao, - ResourceValidator validator, EventManager eventManager, ExceptionHandler exceptionHandler, + ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - AuthorizationRuleProvider authorizationRuleProvider) + ReferenceCleaner referenceCleaner, AuthorizationRuleProvider authorizationRuleProvider, + HistoryService historyService) { - super(path, Task.class, serverBase, defaultPageCount, dao, validator, eventManager, exceptionHandler, + super(path, Task.class, serverBase, defaultPageCount, dao, validator, eventHandler, exceptionHandler, eventGenerator, responseGenerator, parameterConverter, referenceExtractor, referenceResolver, - authorizationRuleProvider); + referenceCleaner, authorizationRuleProvider, historyService); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/ValueSetServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/ValueSetServiceImpl.java index 9692bc008..eb5a7920d 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/ValueSetServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/impl/ValueSetServiceImpl.java @@ -3,10 +3,12 @@ import org.highmed.dsf.fhir.authorization.AuthorizationRuleProvider; import org.highmed.dsf.fhir.dao.ValueSetDao; import org.highmed.dsf.fhir.event.EventGenerator; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.event.EventHandler; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.history.HistoryService; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.service.ResourceValidator; @@ -16,13 +18,14 @@ public class ValueSetServiceImpl extends AbstractResourceServiceImpl implements ValueSetService { public ValueSetServiceImpl(String path, String serverBase, int defaultPageCount, ValueSetDao dao, - ResourceValidator validator, EventManager eventManager, ExceptionHandler exceptionHandler, + ResourceValidator validator, EventHandler eventHandler, ExceptionHandler exceptionHandler, EventGenerator eventGenerator, ResponseGenerator responseGenerator, ParameterConverter parameterConverter, ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver, - AuthorizationRuleProvider authorizationRuleProvider) + ReferenceCleaner referenceCleaner, AuthorizationRuleProvider authorizationRuleProvider, + HistoryService historyService) { - super(path, ValueSet.class, serverBase, defaultPageCount, dao, validator, eventManager, exceptionHandler, + super(path, ValueSet.class, serverBase, defaultPageCount, dao, validator, eventHandler, exceptionHandler, eventGenerator, responseGenerator, parameterConverter, referenceExtractor, referenceResolver, - authorizationRuleProvider); + referenceCleaner, authorizationRuleProvider, historyService); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/AbstractResourceServiceJaxrs.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/AbstractResourceServiceJaxrs.java index 1bb7d7309..47fa55fab 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/AbstractResourceServiceJaxrs.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/AbstractResourceServiceJaxrs.java @@ -1,13 +1,16 @@ package org.highmed.dsf.fhir.webservice.jaxrs; +import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @@ -18,6 +21,8 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; +import ca.uhn.fhir.rest.api.Constants; + public abstract class AbstractResourceServiceJaxrs> extends AbstractServiceJaxrs implements BasicResourceService, InitializingBean { @@ -29,6 +34,10 @@ public AbstractResourceServiceJaxrs(S delegate) } @POST + @Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response create(R resource, @Context UriInfo uri, @Context HttpHeaders headers) { @@ -39,6 +48,8 @@ public Response create(R resource, @Context UriInfo uri, @Context HttpHeaders he @GET @Path("/{id}") + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response read(@PathParam("id") String id, @Context UriInfo uri, @Context HttpHeaders headers) { @@ -49,6 +60,8 @@ public Response read(@PathParam("id") String id, @Context UriInfo uri, @Context @GET @Path("/{id}/_history/{version}") + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response vread(@PathParam("id") String id, @PathParam("version") long version, @Context UriInfo uri, @Context HttpHeaders headers) @@ -58,8 +71,36 @@ public Response vread(@PathParam("id") String id, @PathParam("version") long ver return delegate.vread(id, version, uri, headers); } + @GET + @Path("/_history") + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Override + public Response history(@Context UriInfo uri, @Context HttpHeaders headers) + { + logger.trace("GET {}", uri.getRequestUri().toString()); + + return delegate.history(uri, headers); + } + + @GET + @Path("/{id}/_history") + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Override + public Response history(@PathParam("id") String id, @Context UriInfo uri, @Context HttpHeaders headers) + { + logger.trace("GET {}", uri.getRequestUri().toString()); + + return delegate.history(id, uri, headers); + } + @PUT @Path("/{id}") + @Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response update(@PathParam("id") String id, R resource, @Context UriInfo uri, @Context HttpHeaders headers) { @@ -69,6 +110,10 @@ public Response update(@PathParam("id") String id, R resource, @Context UriInfo } @PUT + @Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response update(R resource, @Context UriInfo uri, @Context HttpHeaders headers) { @@ -79,6 +124,10 @@ public Response update(R resource, @Context UriInfo uri, @Context HttpHeaders he @DELETE @Path("/{id}") + @Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response delete(@PathParam("id") String id, @Context UriInfo uri, @Context HttpHeaders headers) { @@ -88,6 +137,10 @@ public Response delete(@PathParam("id") String id, @Context UriInfo uri, @Contex } @DELETE + @Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response delete(@Context UriInfo uri, @Context HttpHeaders headers) { @@ -97,6 +150,8 @@ public Response delete(@Context UriInfo uri, @Context HttpHeaders headers) } @GET + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response search(@Context UriInfo uri, @Context HttpHeaders headers) { @@ -107,6 +162,10 @@ public Response search(@Context UriInfo uri, @Context HttpHeaders headers) @POST @Path("/{validate : [$]validate(/)?}") + @Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response postValidateNew(@PathParam("validate") String validate, Parameters parameters, @Context UriInfo uri, @Context HttpHeaders headers) @@ -118,6 +177,10 @@ public Response postValidateNew(@PathParam("validate") String validate, Paramete @GET @Path("/{validate : [$]validate(/)?}") + @Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response getValidateNew(@PathParam("validate") String validate, @Context UriInfo uri, @Context HttpHeaders headers) @@ -129,6 +192,10 @@ public Response getValidateNew(@PathParam("validate") String validate, @Context @POST @Path("/{id}/{validate : [$]validate(/)?}") + @Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response postValidateExisting(@PathParam("validate") String validatePath, @PathParam("id") String id, Parameters parameters, @Context UriInfo uri, @Context HttpHeaders headers) @@ -140,6 +207,10 @@ public Response postValidateExisting(@PathParam("validate") String validatePath, @GET @Path("/{id}/{validate : [$]validate(/)?}") + @Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) @Override public Response getValidateExisting(@PathParam("validate") String validatePath, @PathParam("id") String id, @Context UriInfo uri, @Context HttpHeaders headers) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/AbstractServiceJaxrs.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/AbstractServiceJaxrs.java index ed3407754..0357d82a1 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/AbstractServiceJaxrs.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/AbstractServiceJaxrs.java @@ -1,22 +1,13 @@ package org.highmed.dsf.fhir.webservice.jaxrs; import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.Consumes; -import javax.ws.rs.Produces; import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; import org.highmed.dsf.fhir.authentication.UserProvider; import org.highmed.dsf.fhir.webservice.base.AbstractDelegatingBasicService; import org.highmed.dsf.fhir.webservice.base.BasicService; import org.springframework.beans.factory.InitializingBean; -import ca.uhn.fhir.rest.api.Constants; - -@Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, - Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) -@Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, - Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) public abstract class AbstractServiceJaxrs extends AbstractDelegatingBasicService implements BasicService, InitializingBean { diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/BinaryServiceJaxrs.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/BinaryServiceJaxrs.java index 9bc0ad481..99fd57b27 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/BinaryServiceJaxrs.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/BinaryServiceJaxrs.java @@ -1,17 +1,262 @@ package org.highmed.dsf.fhir.webservice.jaxrs; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.EntityTag; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; +import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.webservice.specification.BinaryService; import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.rest.api.Constants; @Path(BinaryServiceJaxrs.PATH) public class BinaryServiceJaxrs extends AbstractResourceServiceJaxrs implements BinaryService { public static final String PATH = "Binary"; - public BinaryServiceJaxrs(BinaryService delegate) + private static final Logger logger = LoggerFactory.getLogger(BinaryServiceJaxrs.class); + + private final String[] FHIR_MEDIA_TYPES = { Constants.CT_FHIR_XML_NEW, Constants.CT_FHIR_JSON_NEW, + Constants.CT_FHIR_XML, Constants.CT_FHIR_JSON }; + private final ParameterConverter parameterConverter; + + public BinaryServiceJaxrs(BinaryService delegate, ParameterConverter parameterConverter) { super(delegate); + + this.parameterConverter = parameterConverter; + } + + @Override + public void afterPropertiesSet() throws Exception + { + super.afterPropertiesSet(); + + Objects.requireNonNull(parameterConverter, "parameterConverter"); + } + + @POST + @Consumes + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Override + public Response create(InputStream in, @Context UriInfo uri, @Context HttpHeaders headers) + { + logger.trace("POST {}", uri.getRequestUri().toString()); + + try (in) + { + String securityContext = getSecurityContext(headers); + String contentType = getContentType(headers); + byte[] content = in.readAllBytes(); + + Binary resource = createBinary(contentType, content, securityContext); + return delegate.create(resource, uri, headers); + } + catch (IOException e) + { + throw new WebApplicationException(e); + } + } + + private Binary createBinary(String contentType, byte[] content, String securityContextReference) + { + Binary resource = new Binary(); + resource.setContentType(contentType); + resource.setContent(content); + resource.setSecurityContext(new Reference(securityContextReference)); + return resource; + } + + private String getSecurityContext(HttpHeaders headers) + { + return getHeaderValueOrThrowBadRequest(headers, Constants.HEADER_X_SECURITY_CONTEXT); + } + + private String getContentType(HttpHeaders headers) + { + return getHeaderValueOrThrowBadRequest(headers, HttpHeaders.CONTENT_TYPE); + } + + private String getHeaderValueOrThrowBadRequest(HttpHeaders headers, String header) + { + List headerValue = headers.getRequestHeader(header); + if (headerValue != null && headerValue.size() == 1) + { + String hV0 = headerValue.get(0); + if (hV0 != null && !hV0.isBlank()) + return hV0; + else + { + logger.warn("{} header found, no value, sending {}", header, Status.BAD_REQUEST); + throw new WebApplicationException(Status.BAD_REQUEST); + } + } + else if (headerValue != null && headerValue.size() > 1) + { + logger.warn("{} header found, more than one value, sending {}", header, Status.BAD_REQUEST); + throw new WebApplicationException(Status.BAD_REQUEST); + } + + headerValue = headers.getRequestHeader(header.toLowerCase()); + if (headerValue != null && headerValue.size() == 1) + { + String hV0 = headerValue.get(0); + if (hV0 != null && !hV0.isBlank()) + return hV0; + else + { + logger.warn("{} header found, no value, sending {}", header, Status.BAD_REQUEST); + throw new WebApplicationException(Status.BAD_REQUEST); + } + } + else if (headerValue != null && headerValue.size() > 1) + { + logger.warn("{} header found, more than one value, sending {}", header, Status.BAD_REQUEST); + throw new WebApplicationException(Status.BAD_REQUEST); + } + + logger.warn("{} header not found, sending {}", header, Status.BAD_REQUEST); + throw new WebApplicationException(Status.BAD_REQUEST); + } + + @GET + @Path("/{id}") + @Produces + @Override + public Response read(@PathParam("id") String id, @Context UriInfo uri, @Context HttpHeaders headers) + { + Response read = super.read(id, uri, headers); + + if (read.getEntity() instanceof Binary && !isValidFhirRequest(uri, headers)) + { + Binary binary = (Binary) read.getEntity(); + if (mediaTypeMatches(headers, binary)) + return toStream(binary); + else + return Response.status(Status.NOT_ACCEPTABLE).build(); + } + else + return read; + } + + private boolean mediaTypeMatches(HttpHeaders headers, Binary binary) + { + MediaType binaryMediaType = MediaType.valueOf(binary.getContentType()); + return headers.getAcceptableMediaTypes() != null && headers.getAcceptableMediaTypes().stream() + .anyMatch(acceptType -> acceptType.isCompatible(binaryMediaType)); + } + + private Response toStream(Binary binary) + { + String contentType = binary.getContentType(); + byte[] content = binary.getContent(); + + ResponseBuilder b = Response.status(Status.OK).entity(new ByteArrayInputStream(content)); + b = b.type(contentType); + + if (binary.getMeta() != null && binary.getMeta().getLastUpdated() != null + && binary.getMeta().getVersionId() != null) + { + b = b.lastModified(binary.getMeta().getLastUpdated()); + b = b.tag(new EntityTag(binary.getMeta().getVersionId(), true)); + } + + if (binary.hasSecurityContext() && binary.getSecurityContext().hasReference()) + { + // Not setting header for logical references + b.header(Constants.HEADER_X_SECURITY_CONTEXT, binary.getSecurityContext().getReference()); + } + + return b.build(); + } + + @GET + @Path("/{id}/_history/{version}") + @Produces + @Override + public Response vread(@PathParam("id") String id, @PathParam("version") long version, @Context UriInfo uri, + @Context HttpHeaders headers) + { + Response read = super.vread(id, version, uri, headers); + + if (read.getEntity() instanceof Binary && !isValidFhirRequest(uri, headers)) + { + Binary binary = (Binary) read.getEntity(); + if (mediaTypeMatches(headers, binary)) + return toStream(binary); + else + return Response.status(Status.NOT_ACCEPTABLE).build(); + } + else + return read; + } + + private boolean isValidFhirRequest(UriInfo uri, HttpHeaders headers) + { + // _format parameter override present and valid + if (uri.getQueryParameters().containsKey(Constants.PARAM_FORMAT)) + { + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers); + return true; + } + else + { + List types = headers.getAcceptableMediaTypes(); + MediaType accept = types == null ? null : types.get(0); + + // accept header is FHIR mime-type + return Arrays.stream(FHIR_MEDIA_TYPES).anyMatch(f -> f.equals(accept.toString())); + } + } + + @PUT + @Path("/{id}") + @Consumes + @Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) + @Override + public Response update(@PathParam("id") String id, InputStream in, @Context UriInfo uri, + @Context HttpHeaders headers) + { + logger.trace("PUT {}", uri.getRequestUri().toString()); + + try (in) + { + String securityContext = getSecurityContext(headers); + String contentType = getContentType(headers); + byte[] content = in.readAllBytes(); + + Binary resource = createBinary(contentType, content, securityContext); + return delegate.update(id, resource, uri, headers); + } + catch (IOException e) + { + throw new WebApplicationException(e); + } } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/ConformanceServiceJaxrs.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/ConformanceServiceJaxrs.java index b6bb8650a..677c81a08 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/ConformanceServiceJaxrs.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/ConformanceServiceJaxrs.java @@ -1,10 +1,13 @@ package org.highmed.dsf.fhir.webservice.jaxrs; +import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.Path; +import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @@ -12,7 +15,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ca.uhn.fhir.rest.api.Constants; + @Path(ConformanceServiceJaxrs.PATH) +@Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) +@Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) public class ConformanceServiceJaxrs extends AbstractServiceJaxrs implements ConformanceService { public static final String PATH = "metadata"; diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/RootServiceJaxrs.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/RootServiceJaxrs.java index d748c4a30..324227b51 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/RootServiceJaxrs.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/RootServiceJaxrs.java @@ -1,10 +1,13 @@ package org.highmed.dsf.fhir.webservice.jaxrs; +import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; +import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @@ -13,7 +16,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ca.uhn.fhir.rest.api.Constants; + @Path(RootServiceJaxrs.PATH) +@Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) +@Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) public class RootServiceJaxrs extends AbstractServiceJaxrs implements RootService { public static final String PATH = ""; @@ -34,6 +43,16 @@ public Response root(@Context UriInfo uri, @Context HttpHeaders headers) return delegate.root(uri, headers); } + @GET + @Path("/_history") + @Override + public Response history(@Context UriInfo uri, @Context HttpHeaders headers) + { + logger.trace("GET {}", uri.getRequestUri().toString()); + + return delegate.history(uri, headers); + } + @POST @Override public Response handleBundle(Bundle bundle, @Context UriInfo uri, @Context HttpHeaders headers) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/StaticResourcesServiceJaxrs.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/StaticResourcesServiceJaxrs.java index 4777cf10f..35a6a713e 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/StaticResourcesServiceJaxrs.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/jaxrs/StaticResourcesServiceJaxrs.java @@ -1,10 +1,13 @@ package org.highmed.dsf.fhir.webservice.jaxrs; +import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @@ -12,7 +15,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ca.uhn.fhir.rest.api.Constants; + @Path(StaticResourcesServiceJaxrs.PATH) +@Consumes({ Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, Constants.CT_FHIR_XML, + Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) +@Produces({ MediaType.TEXT_HTML, Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW, MediaType.APPLICATION_JSON, + Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW, MediaType.APPLICATION_XML }) public class StaticResourcesServiceJaxrs extends AbstractServiceJaxrs implements StaticResourcesService { diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/AbstractResourceServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/AbstractResourceServiceSecure.java index 8d43d281c..fea8e49d5 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/AbstractResourceServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/AbstractResourceServiceSecure.java @@ -6,11 +6,13 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; +import java.util.function.Supplier; import java.util.stream.Collectors; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; import org.highmed.dsf.fhir.authorization.AuthorizationRule; @@ -18,10 +20,13 @@ import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.prefer.PreferReturnType; import org.highmed.dsf.fhir.search.PartialResult; import org.highmed.dsf.fhir.search.SearchQuery; import org.highmed.dsf.fhir.search.SearchQueryParameterError; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.BasicResourceService; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.OperationOutcome; @@ -34,12 +39,15 @@ import org.springframework.web.util.UriComponentsBuilder; import ca.uhn.fhir.model.api.annotation.ResourceDef; +import ca.uhn.fhir.validation.ResultSeverityEnum; +import ca.uhn.fhir.validation.ValidationResult; public abstract class AbstractResourceServiceSecure, R extends Resource, S extends BasicResourceService> extends AbstractServiceSecure implements BasicResourceService, InitializingBean { private static final Logger logger = LoggerFactory.getLogger(AbstractResourceServiceSecure.class); + protected final ReferenceCleaner referenceCleaner; protected final Class resourceType; protected final String resourceTypeName; protected final String serverBase; @@ -47,13 +55,16 @@ public abstract class AbstractResourceServiceSecure, R protected final ExceptionHandler exceptionHandler; protected final ParameterConverter parameterConverter; protected final AuthorizationRule authorizationRule; + protected final ResourceValidator resourceValidator; public AbstractResourceServiceSecure(S delegate, String serverBase, ResponseGenerator responseGenerator, - ReferenceResolver referenceResolver, Class resourceType, D dao, ExceptionHandler exceptionHandler, - ParameterConverter parameterConverter, AuthorizationRule authorizationRule) + ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, Class resourceType, D dao, + ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + AuthorizationRule authorizationRule, ResourceValidator resourceValidator) { super(delegate, serverBase, responseGenerator, referenceResolver); + this.referenceCleaner = referenceCleaner; this.resourceType = resourceType; this.resourceTypeName = resourceType.getAnnotation(ResourceDef.class).name(); this.serverBase = serverBase; @@ -61,6 +72,7 @@ public AbstractResourceServiceSecure(S delegate, String serverBase, ResponseGene this.exceptionHandler = exceptionHandler; this.parameterConverter = parameterConverter; this.authorizationRule = authorizationRule; + this.resourceValidator = resourceValidator; } @Override @@ -75,6 +87,44 @@ public void afterPropertiesSet() throws Exception Objects.requireNonNull(exceptionHandler, "exceptionHandler"); Objects.requireNonNull(parameterConverter, "parameterConverter"); Objects.requireNonNull(authorizationRule, "authorizationRule"); + Objects.requireNonNull(resourceValidator, "resourceValidator"); + } + + private String toValidationLogMessage(ValidationResult validationResult) + { + return validationResult + .getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" + + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()) + .collect(Collectors.joining(", ", "[", "]")); + } + + private Response withResourceValidation(R resource, UriInfo uri, HttpHeaders headers, String method, + Supplier delegate) + { + // FIXME hapi parser bug workaround + referenceCleaner.cleanReferenceResourcesIfBundle(resource); + + ValidationResult validationResult = resourceValidator.validate(resource); + + if (validationResult.getMessages().stream().anyMatch(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity()))) + { + logger.warn("{} of {} unauthorized, resource not valid: {}", method, resource.fhirType(), + toValidationLogMessage(validationResult)); + + OperationOutcome outcome = new OperationOutcome(); + validationResult.populateOperationOutcome(outcome); + return responseGenerator.response(Status.FORBIDDEN, outcome, + parameterConverter.getMediaTypeThrowIfNotSupported(uri, headers)).build(); + } + else + { + if (!validationResult.getMessages().isEmpty()) + logger.warn("Resource {} validated with messages: {}", resource.fhirType(), + toValidationLogMessage(validationResult)); + + return delegate.get(); + } } @Override @@ -92,18 +142,22 @@ public Response create(R resource, UriInfo uri, HttpHeaders headers) } else { - audit.info("Create of resource {} allowed for user '{}': {}", resourceTypeName, getCurrentUser().getName(), - reasonCreateAllowed.get()); + return withResourceValidation(resource, uri, headers, "Create", () -> + { + audit.info("Create of resource {} allowed for user '{}': {}", resourceTypeName, + getCurrentUser().getName(), reasonCreateAllowed.get()); - Response created = delegate.create(resource, uri, headers); + Response created = delegate.create(resource, uri, headers); - if (created.hasEntity() && !resourceType.isInstance(created.getEntity()) - && !(created.getEntity() instanceof OperationOutcome)) - logger.warn("Update returned with entity of type {}", created.getEntity().getClass().getName()); - else if (!created.hasEntity()) - logger.info("Update returned with status {}, but no entity", created.getStatus()); + if (created.hasEntity() && !resourceType.isInstance(created.getEntity()) + && !(created.getEntity() instanceof OperationOutcome)) + logger.warn("Update returned with entity of type {}", created.getEntity().getClass().getName()); + else if (!created.hasEntity() + && !PreferReturnType.MINIMAL.equals(parameterConverter.getPreferReturn(headers))) + logger.warn("Update returned with status {}, but no entity", created.getStatus()); - return created; + return created; + }); } } @@ -211,13 +265,54 @@ else if (read.hasEntity()) } } + @Override + public Response history(UriInfo uri, HttpHeaders headers) + { + logger.debug("Current user '{}', role '{}'", userProvider.getCurrentUser().getName(), + userProvider.getCurrentUser().getRole()); + + Optional reasonHistoryAllowed = authorizationRule.reasonHistoryAllowed(getCurrentUser()); + if (reasonHistoryAllowed.isEmpty()) + { + audit.info("History of resource {} denied for user '{}'", resourceTypeName, getCurrentUser().getName()); + return forbidden("search"); + } + else + { + audit.info("History of resource {} allowed for user '{}': {}", resourceTypeName, getCurrentUser().getName(), + reasonHistoryAllowed.get()); + return delegate.history(uri, headers); + } + } + + @Override + public Response history(String id, UriInfo uri, HttpHeaders headers) + { + logger.debug("Current user '{}', role '{}'", userProvider.getCurrentUser().getName(), + userProvider.getCurrentUser().getRole()); + + Optional reasonHistoryAllowed = authorizationRule.reasonHistoryAllowed(getCurrentUser()); + if (reasonHistoryAllowed.isEmpty()) + { + audit.info("History of resource {}/{} denied for user '{}'", resourceTypeName, id, + getCurrentUser().getName()); + return forbidden("search"); + } + else + { + audit.info("History of resource {}/{} allowed for user '{}': {}", resourceTypeName, id, + getCurrentUser().getName(), reasonHistoryAllowed.get()); + return delegate.history(id, uri, headers); + } + } + @Override public Response update(String id, R resource, UriInfo uri, HttpHeaders headers) { logger.debug("Current user '{}', role '{}'", userProvider.getCurrentUser().getName(), userProvider.getCurrentUser().getRole()); - Optional dbResource = exceptionHandler.handleSqlAndResourceDeletedException(resourceTypeName, + Optional dbResource = exceptionHandler.handleSqlAndResourceDeletedException(serverBase, resourceTypeName, () -> dao.read(parameterConverter.toUuid(resourceTypeName, id))); if (dbResource.isEmpty()) @@ -227,7 +322,10 @@ public Response update(String id, R resource, UriInfo uri, HttpHeaders headers) return responseGenerator.updateAsCreateNotAllowed(resourceTypeName, resourceTypeName + "/" + id); } else - return update(id, resource, uri, headers, dbResource.get()); + { + R cleanedResource = referenceCleaner.cleanLiteralReferences(dbResource.get()); + return update(id, resource, uri, headers, cleanedResource); + } } private Response update(String id, R newResource, UriInfo uri, HttpHeaders headers, R oldResource) @@ -243,18 +341,22 @@ private Response update(String id, R newResource, UriInfo uri, HttpHeaders heade } else { - audit.info("Update of resource {} allowed for user '{}': {}", oldResource.getIdElement().getValue(), - getCurrentUser().getName(), reasonUpdateAllowed.get()); + return withResourceValidation(newResource, uri, headers, "Update", () -> + { + audit.info("Update of resource {} allowed for user '{}': {}", oldResource.getIdElement().getValue(), + getCurrentUser().getName(), reasonUpdateAllowed.get()); - Response updated = delegate.update(id, newResource, uri, headers); + Response updated = delegate.update(id, newResource, uri, headers); - if (updated.hasEntity() && !resourceType.isInstance(updated.getEntity()) - && !(updated.getEntity() instanceof OperationOutcome)) - logger.warn("Update returned with entity of type {}", updated.getEntity().getClass().getName()); - else if (!updated.hasEntity()) - logger.info("Update returned with status {}, but no entity", updated.getStatus()); + if (updated.hasEntity() && !resourceType.isInstance(updated.getEntity()) + && !(updated.getEntity() instanceof OperationOutcome)) + logger.warn("Update returned with entity of type {}", updated.getEntity().getClass().getName()); + else if (!updated.hasEntity() + && !PreferReturnType.MINIMAL.equals(parameterConverter.getPreferReturn(headers))) + logger.warn("Update returned with status {}, but no entity", updated.getStatus()); - return updated; + return updated; + }); } } @@ -268,7 +370,7 @@ public Response update(R resource, UriInfo uri, HttpHeaders headers) PartialResult result = getExisting(queryParameters); // No matches, no id provided: The server creates the resource. - if (result.getOverallCount() <= 0 && !resource.hasId()) + if (result.getTotal() <= 0 && !resource.hasId()) { // more security checks and audit log in create method return create(resource, uri, headers); @@ -276,7 +378,7 @@ public Response update(R resource, UriInfo uri, HttpHeaders headers) // No matches, id provided: The server treats the interaction as an Update as Create interaction (or rejects it, // if it does not support Update as Create) -> reject - else if (result.getOverallCount() <= 0 && resource.hasId()) + else if (result.getTotal() <= 0 && resource.hasId()) { audit.info("Create as Update of non existing resource {} denied for user '{}'", resource.getIdElement().getValue(), getCurrentUser().getName()); @@ -285,7 +387,7 @@ else if (result.getOverallCount() <= 0 && resource.hasId()) // One Match, no resource id provided OR (resource id provided and it matches the found resource): // The server performs the update against the matching resource - else if (result.getOverallCount() == 1) + else if (result.getTotal() == 1) { R dbResource = result.getPartialResult().get(0); IdType dbResourceId = dbResource.getIdElement(); @@ -436,14 +538,14 @@ public Response delete(UriInfo uri, HttpHeaders headers) PartialResult result = exceptionHandler.handleSqlException(() -> dao.search(query)); // No matches - if (result.getOverallCount() <= 0) + if (result.getTotal() <= 0) { // TODO audit log return Response.noContent().build(); // TODO return OperationOutcome } // One Match: The server performs an ordinary delete on the matching resource - else if (result.getOverallCount() == 1) + else if (result.getTotal() == 1) { R resource = result.getPartialResult().get(0); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ActivityDefinitionServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ActivityDefinitionServiceSecure.java index 445b2fb74..8d52042f5 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ActivityDefinitionServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ActivityDefinitionServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.ActivityDefinitionAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.ActivityDefinitionDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.ActivityDefinitionService; import org.hl7.fhir.r4.model.ActivityDefinition; @@ -14,11 +16,12 @@ public class ActivityDefinitionServiceSecure implements ActivityDefinitionService { public ActivityDefinitionServiceSecure(ActivityDefinitionService delegate, String serverBase, - ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, + ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, ActivityDefinitionDao activityDefinitionDao, ExceptionHandler exceptionHandler, - ParameterConverter parameterConverter, ActivityDefinitionAuthorizationRule authorizationRule) + ParameterConverter parameterConverter, AuthorizationRule authorizationRule, + ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, ActivityDefinition.class, - activityDefinitionDao, exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, ActivityDefinition.class, + activityDefinitionDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/BinaryServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/BinaryServiceSecure.java index 7a68df885..c59f8f244 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/BinaryServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/BinaryServiceSecure.java @@ -1,11 +1,19 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.BinaryAuthorizationRule; +import java.io.InputStream; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.BinaryDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.BinaryService; import org.hl7.fhir.r4.model.Binary; @@ -13,10 +21,23 @@ public class BinaryServiceSecure extends AbstractResourceServiceSecure authorizationRule, ResourceValidator resourceValidator) + { + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Binary.class, binaryDao, + exceptionHandler, parameterConverter, authorizationRule, resourceValidator); + } + + @Override + public Response create(InputStream in, UriInfo uri, HttpHeaders headers) + { + throw new UnsupportedOperationException("Implemented and delegated by jaxrs layer"); + } + + @Override + public Response update(String id, InputStream in, UriInfo uri, HttpHeaders headers) { - super(delegate, serverBase, responseGenerator, referenceResolver, Binary.class, binaryDao, exceptionHandler, - parameterConverter, authorizationRule); + throw new UnsupportedOperationException("Implemented and delegated by jaxrs layer"); } } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/BundleServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/BundleServiceSecure.java index 95dd5ea8a..783c93f27 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/BundleServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/BundleServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.BundleAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.BundleDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.BundleService; import org.hl7.fhir.r4.model.Bundle; @@ -13,10 +15,11 @@ public class BundleServiceSecure extends AbstractResourceServiceSecure authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, Bundle.class, bundleDao, exceptionHandler, - parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Bundle.class, bundleDao, + exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/CodeSystemServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/CodeSystemServiceSecure.java index d8dfe9cd7..4a4c34c93 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/CodeSystemServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/CodeSystemServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.CodeSystemAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.CodeSystemDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.CodeSystemService; import org.hl7.fhir.r4.model.CodeSystem; @@ -13,10 +15,11 @@ public class CodeSystemServiceSecure extends AbstractResourceServiceSecure authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, CodeSystem.class, codeSystemDao, - exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, CodeSystem.class, + codeSystemDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/EndpointServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/EndpointServiceSecure.java index 5e7624f9c..6bb9fed30 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/EndpointServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/EndpointServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.EndpointAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.EndpointDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.EndpointService; import org.hl7.fhir.r4.model.Endpoint; @@ -13,10 +15,11 @@ public class EndpointServiceSecure extends AbstractResourceServiceSecure authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, Endpoint.class, endpointDao, exceptionHandler, - parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Endpoint.class, endpointDao, + exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/GroupServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/GroupServiceSecure.java index 7f99acdd3..24ac60e13 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/GroupServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/GroupServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.GroupAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.GroupDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.GroupService; import org.hl7.fhir.r4.model.Group; @@ -13,10 +15,11 @@ public class GroupServiceSecure extends AbstractResourceServiceSecure authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, Group.class, groupDao, exceptionHandler, - parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Group.class, groupDao, + exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/HealthcareServiceServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/HealthcareServiceServiceSecure.java index a881e3c1e..445615950 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/HealthcareServiceServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/HealthcareServiceServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.HealthcareServiceAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.HealthcareServiceDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.HealthcareServiceService; import org.hl7.fhir.r4.model.HealthcareService; @@ -14,11 +16,12 @@ public class HealthcareServiceServiceSecure implements HealthcareServiceService { public HealthcareServiceServiceSecure(HealthcareServiceService delegate, String serverBase, - ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, + ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, HealthcareServiceDao healthcareServiceDao, ExceptionHandler exceptionHandler, - ParameterConverter parameterConverter, HealthcareServiceAuthorizationRule authorizationRule) + ParameterConverter parameterConverter, AuthorizationRule authorizationRule, + ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, HealthcareService.class, healthcareServiceDao, - exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, HealthcareService.class, + healthcareServiceDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/LocationServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/LocationServiceSecure.java index 372344171..7467e5de2 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/LocationServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/LocationServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.LocationAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.LocationDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.LocationService; import org.hl7.fhir.r4.model.Location; @@ -13,10 +15,11 @@ public class LocationServiceSecure extends AbstractResourceServiceSecure authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, Location.class, locationDao, exceptionHandler, - parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Location.class, locationDao, + exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/NamingSystemServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/NamingSystemServiceSecure.java index cb06b3c9a..6ffc0a2e9 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/NamingSystemServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/NamingSystemServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.NamingSystemAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.NamingSystemDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.NamingSystemService; import org.hl7.fhir.r4.model.NamingSystem; @@ -13,11 +15,11 @@ public class NamingSystemServiceSecure extends AbstractResourceServiceSecure implements NamingSystemService { public NamingSystemServiceSecure(NamingSystemService delegate, String serverBase, - ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, NamingSystemDao naminngSystemDao, - ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, - NamingSystemAuthorizationRule authorizationRule) + ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, + NamingSystemDao naminngSystemDao, ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + AuthorizationRule authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, NamingSystem.class, naminngSystemDao, - exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, NamingSystem.class, + naminngSystemDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/OrganizationServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/OrganizationServiceSecure.java index 03492f00d..58965ea54 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/OrganizationServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/OrganizationServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.OrganizationAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.OrganizationDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.OrganizationService; import org.hl7.fhir.r4.model.Organization; @@ -13,11 +15,11 @@ public class OrganizationServiceSecure extends AbstractResourceServiceSecure implements OrganizationService { public OrganizationServiceSecure(OrganizationService delegate, String serverBase, - ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, OrganizationDao organizationDao, - ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, - OrganizationAuthorizationRule authorizationRule) + ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, + OrganizationDao organizationDao, ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + AuthorizationRule authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, Organization.class, organizationDao, - exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Organization.class, + organizationDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PatientServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PatientServiceSecure.java index 8a8b54ffd..f1e1194c6 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PatientServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PatientServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.PatientAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.PatientDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.PatientService; import org.hl7.fhir.r4.model.Patient; @@ -13,10 +15,11 @@ public class PatientServiceSecure extends AbstractResourceServiceSecure authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, Patient.class, patientDao, exceptionHandler, - parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Patient.class, patientDao, + exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PractitionerRoleServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PractitionerRoleServiceSecure.java index 9c39f6fb8..211606d08 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PractitionerRoleServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PractitionerRoleServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.PractitionerRoleAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.PractitionerRoleDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.PractitionerRoleService; import org.hl7.fhir.r4.model.PractitionerRole; @@ -14,11 +16,12 @@ public class PractitionerRoleServiceSecure implements PractitionerRoleService { public PractitionerRoleServiceSecure(PractitionerRoleService delegate, String serverBase, - ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, + ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, PractitionerRoleDao practitionerRoleDao, ExceptionHandler exceptionHandler, - ParameterConverter parameterConverter, PractitionerRoleAuthorizationRule authorizationRule) + ParameterConverter parameterConverter, AuthorizationRule authorizationRule, + ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, PractitionerRole.class, practitionerRoleDao, - exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, PractitionerRole.class, + practitionerRoleDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PractitionerServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PractitionerServiceSecure.java index cb51416d7..eee2a22e3 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PractitionerServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/PractitionerServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.PractitionerAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.PractitionerDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.PractitionerService; import org.hl7.fhir.r4.model.Practitioner; @@ -13,11 +15,11 @@ public class PractitionerServiceSecure extends AbstractResourceServiceSecure implements PractitionerService { public PractitionerServiceSecure(PractitionerService delegate, String serverBase, - ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, PractitionerDao practitionerDao, - ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, - PractitionerAuthorizationRule authorizationRule) + ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, + PractitionerDao practitionerDao, ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + AuthorizationRule authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, Practitioner.class, practitionerDao, - exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Practitioner.class, + practitionerDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ProvenanceServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ProvenanceServiceSecure.java index 30ee79ebc..2d46bb3b1 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ProvenanceServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ProvenanceServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.ProvenanceAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.ProvenanceDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.ProvenanceService; import org.hl7.fhir.r4.model.Provenance; @@ -13,10 +15,11 @@ public class ProvenanceServiceSecure extends AbstractResourceServiceSecure authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, Provenance.class, provenanceDao, - exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Provenance.class, + provenanceDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ResearchStudyServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ResearchStudyServiceSecure.java index ed2925c5a..d0edb8c5a 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ResearchStudyServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ResearchStudyServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.ResearchStudyAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.ResearchStudyDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.ResearchStudyService; import org.hl7.fhir.r4.model.ResearchStudy; @@ -14,11 +16,11 @@ public class ResearchStudyServiceSecure implements ResearchStudyService { public ResearchStudyServiceSecure(ResearchStudyService delegate, String serverBase, - ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, ResearchStudyDao researchStudyDao, - ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, - ResearchStudyAuthorizationRule authorizationRule) + ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, + ResearchStudyDao researchStudyDao, ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + AuthorizationRule authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, ResearchStudy.class, researchStudyDao, - exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, ResearchStudy.class, + researchStudyDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/RootServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/RootServiceSecure.java index ca747e811..3923d6cf8 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/RootServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/RootServiceSecure.java @@ -1,16 +1,19 @@ package org.highmed.dsf.fhir.webservice.secure; +import java.util.Objects; import java.util.Optional; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.help.ResponseGenerator; import org.highmed.dsf.fhir.service.ReferenceResolver; import org.highmed.dsf.fhir.webservice.specification.RootService; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleType; +import org.hl7.fhir.r4.model.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,10 +21,22 @@ public class RootServiceSecure extends AbstractServiceSecure implem { private static final Logger logger = LoggerFactory.getLogger(AbstractResourceServiceSecure.class); + private final AuthorizationRule authorizationRule; + public RootServiceSecure(RootService delegate, String serverBase, ResponseGenerator responseGenerator, - ReferenceResolver referenceResolver) + ReferenceResolver referenceResolver, AuthorizationRule authorizationRule) { super(delegate, serverBase, responseGenerator, referenceResolver); + + this.authorizationRule = authorizationRule; + } + + @Override + public void afterPropertiesSet() throws Exception + { + super.afterPropertiesSet(); + + Objects.requireNonNull(authorizationRule, "authorizationRule"); } @Override @@ -70,4 +85,24 @@ private Optional reasonHandleBundleAllowed(Bundle bundle) return Optional.empty(); } } + + @Override + public Response history(UriInfo uri, HttpHeaders headers) + { + logger.debug("Current user '{}', role '{}'", userProvider.getCurrentUser().getName(), + userProvider.getCurrentUser().getRole()); + + Optional reasonHistoryAllowed = authorizationRule.reasonHistoryAllowed(getCurrentUser()); + if (reasonHistoryAllowed.isEmpty()) + { + audit.info("Root History denied for user '{}'", getCurrentUser().getName()); + return forbidden("search"); + } + else + { + audit.info("Root History allowed for user '{}': {}", getCurrentUser().getName(), + reasonHistoryAllowed.get()); + return delegate.history(uri, headers); + } + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/StructureDefinitionServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/StructureDefinitionServiceSecure.java index 14d70e068..e97c82fa1 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/StructureDefinitionServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/StructureDefinitionServiceSecure.java @@ -4,12 +4,14 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; -import org.highmed.dsf.fhir.authorization.StructureDefinitionAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.StructureDefinitionDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.StructureDefinitionService; import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.StructureDefinition; @@ -23,12 +25,13 @@ public class StructureDefinitionServiceSecure private static final Logger logger = LoggerFactory.getLogger(StructureDefinitionServiceSecure.class); public StructureDefinitionServiceSecure(StructureDefinitionService delegate, String serverBase, - ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, + ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, StructureDefinitionDao structureDefinitionDao, ExceptionHandler exceptionHandler, - ParameterConverter parameterConverter, StructureDefinitionAuthorizationRule authorizationRule) + ParameterConverter parameterConverter, AuthorizationRule authorizationRule, + ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, StructureDefinition.class, - structureDefinitionDao, exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, StructureDefinition.class, + structureDefinitionDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } @Override diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/SubscriptionServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/SubscriptionServiceSecure.java index a9809f522..0412184bc 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/SubscriptionServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/SubscriptionServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.SubscriptionAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.SubscriptionDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.SubscriptionService; import org.hl7.fhir.r4.model.Subscription; @@ -13,11 +15,11 @@ public class SubscriptionServiceSecure extends AbstractResourceServiceSecure implements SubscriptionService { public SubscriptionServiceSecure(SubscriptionService delegate, String serverBase, - ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, SubscriptionDao subscriptionDao, - ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, - SubscriptionAuthorizationRule authorizationRule) + ResponseGenerator responseGenerator, ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, + SubscriptionDao subscriptionDao, ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + AuthorizationRule authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, Subscription.class, subscriptionDao, - exceptionHandler, parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Subscription.class, + subscriptionDao, exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/TaskServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/TaskServiceSecure.java index dc0756072..c5eef9214 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/TaskServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/TaskServiceSecure.java @@ -1,21 +1,24 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.TaskAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.TaskDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.TaskService; import org.hl7.fhir.r4.model.Task; public class TaskServiceSecure extends AbstractResourceServiceSecure implements TaskService { public TaskServiceSecure(TaskService delegate, String serverBase, ResponseGenerator responseGenerator, - ReferenceResolver referenceResolver, TaskDao taskDao, ExceptionHandler exceptionHandler, - ParameterConverter parameterConverter, TaskAuthorizationRule authorizationRule) + ReferenceResolver referenceResolver, ReferenceCleaner referenceCleaner, TaskDao taskDao, + ExceptionHandler exceptionHandler, ParameterConverter parameterConverter, + AuthorizationRule authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, Task.class, taskDao, exceptionHandler, - parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, Task.class, taskDao, + exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ValueSetServiceSecure.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ValueSetServiceSecure.java index 52cd7f298..09db1b221 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ValueSetServiceSecure.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/secure/ValueSetServiceSecure.java @@ -1,11 +1,13 @@ package org.highmed.dsf.fhir.webservice.secure; -import org.highmed.dsf.fhir.authorization.ValueSetAuthorizationRule; +import org.highmed.dsf.fhir.authorization.AuthorizationRule; import org.highmed.dsf.fhir.dao.ValueSetDao; import org.highmed.dsf.fhir.help.ExceptionHandler; import org.highmed.dsf.fhir.help.ParameterConverter; import org.highmed.dsf.fhir.help.ResponseGenerator; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.dsf.fhir.service.ReferenceResolver; +import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.webservice.specification.ValueSetService; import org.hl7.fhir.r4.model.ValueSet; @@ -13,10 +15,11 @@ public class ValueSetServiceSecure extends AbstractResourceServiceSecure authorizationRule, ResourceValidator resourceValidator) { - super(delegate, serverBase, responseGenerator, referenceResolver, ValueSet.class, valueSetDao, exceptionHandler, - parameterConverter, authorizationRule); + super(delegate, serverBase, responseGenerator, referenceResolver, referenceCleaner, ValueSet.class, valueSetDao, + exceptionHandler, parameterConverter, authorizationRule, resourceValidator); } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/BasicResourceService.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/BasicResourceService.java index a598e0d90..a2fa6bfe6 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/BasicResourceService.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/BasicResourceService.java @@ -41,6 +41,10 @@ public interface BasicResourceService extends BasicService */ Response vread(String id, long version, UriInfo uri, HttpHeaders headers); + Response history(UriInfo uri, HttpHeaders headers); + + Response history(String id, UriInfo uri, HttpHeaders headers); + /** * standard update * diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/BinaryService.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/BinaryService.java index 903907769..d5b8340e6 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/BinaryService.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/BinaryService.java @@ -1,7 +1,16 @@ package org.highmed.dsf.fhir.webservice.specification; +import java.io.InputStream; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + import org.hl7.fhir.r4.model.Binary; public interface BinaryService extends BasicResourceService { + Response create(InputStream in, UriInfo uri, HttpHeaders headers); + + Response update(String id, InputStream in, UriInfo uri, HttpHeaders headers); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/RootService.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/RootService.java index 4217821ea..14ef2c15a 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/RootService.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/webservice/specification/RootService.java @@ -1,6 +1,5 @@ package org.highmed.dsf.fhir.webservice.specification; -import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @@ -10,7 +9,9 @@ public interface RootService extends BasicService { - Response root(@Context UriInfo uri, @Context HttpHeaders headers); - + Response root(UriInfo uri, HttpHeaders headers); + + Response history(UriInfo uri, HttpHeaders headers); + Response handleBundle(Bundle bundle, UriInfo uri, HttpHeaders headers); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/websocket/ServerEndpoint.java b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/websocket/ServerEndpoint.java index 98a614cb8..1d9a5d43e 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/websocket/ServerEndpoint.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/org/highmed/dsf/fhir/websocket/ServerEndpoint.java @@ -22,7 +22,7 @@ import org.highmed.dsf.fhir.authentication.NeedsAuthentication; import org.highmed.dsf.fhir.authentication.User; import org.highmed.dsf.fhir.authentication.UserRole; -import org.highmed.dsf.fhir.event.EventManager; +import org.highmed.dsf.fhir.subscription.WebSocketSubscriptionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; @@ -39,17 +39,17 @@ public class ServerEndpoint extends Endpoint implements InitializingBean, NeedsA private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); - private final EventManager eventManager; + private final WebSocketSubscriptionManager subscriptionManager; - public ServerEndpoint(EventManager eventManager) + public ServerEndpoint(WebSocketSubscriptionManager subscriptionManager) { - this.eventManager = eventManager; + this.subscriptionManager = subscriptionManager; } @Override public void afterPropertiesSet() throws Exception { - Objects.requireNonNull(eventManager, "eventManager"); + Objects.requireNonNull(subscriptionManager, "subscriptionManager"); } @Override @@ -90,8 +90,7 @@ public void onMessage(String message) if (message != null && !message.isBlank() && message.startsWith(BIND_MESSAGE_START)) { logger.debug("Websocket bind message received: {}", message); - eventManager.bind(user, session.getId(), session.getAsyncRemote(), - message.substring(BIND_MESSAGE_START.length())); + subscriptionManager.bind(user, session, message.substring(BIND_MESSAGE_START.length())); } } }); @@ -149,7 +148,7 @@ private User getUser(Session session) public void onClose(Session session, CloseReason closeReason) { logger.debug("onClose " + session.getId()); - eventManager.close(session.getId()); + subscriptionManager.close(session.getId()); ScheduledFuture pinger = (ScheduledFuture) session.getUserProperties().get(PINGER_PROPERTY); if (pinger != null) diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.activity_definitions.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.activity_definitions.changelog-0.2.0.xml new file mode 100644 index 000000000..da7d888eb --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.activity_definitions.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE activity_definitions SET deleted = current_ad.deleted_new + FROM ( + SELECT activity_definition_id, deleted_old, ((activity_definition->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (activity_definition_id) activity_definition_id, version, deleted_old, activity_definition + FROM activity_definitions ORDER BY activity_definition_id, version DESC + ) AS current_ad + WHERE deleted_old + ) AS current_ad + WHERE activity_definitions.activity_definition_id = current_ad.activity_definition_id + + + + + + SELECT activity_definition_id, version, activity_definition + FROM ( + SELECT DISTINCT ON (activity_definition_id) activity_definition_id, version, deleted, activity_definition + FROM activity_definitions ORDER BY activity_definition_id, version DESC + ) AS current_ad + WHERE deleted IS NULL + + + + ALTER TABLE current_activity_definitions OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_activity_definitions TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_activity_definitions TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.binaries.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.binaries.changelog-0.2.0.xml new file mode 100644 index 000000000..74ed2ec58 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.binaries.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE binaries SET deleted = current_b.deleted_new + FROM ( + SELECT binary_id, deleted_old, ((binary_json->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (binary_id) binary_id, version, deleted_old, binary_json + FROM binaries ORDER BY binary_id, version DESC + ) AS current_b + WHERE deleted_old + ) AS current_b + WHERE binaries.binary_id = current_b.binary_id + + + + + + SELECT binary_id, version, binary_json, binary_data + FROM ( + SELECT DISTINCT ON (binary_id) binary_id, version, deleted, binary_json, binary_data + FROM binaries ORDER BY binary_id, version DESC + ) AS current_b + WHERE deleted IS NULL + + + + ALTER TABLE current_binaries OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_binaries TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_binaries TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.bundles.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.bundles.changelog-0.2.0.xml new file mode 100644 index 000000000..4eea83dd0 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.bundles.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE bundles SET deleted = current_b.deleted_new + FROM ( + SELECT bundle_id, deleted_old, ((bundle->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (bundle_id) bundle_id, version, deleted_old, bundle + FROM bundles ORDER BY bundle_id, version DESC + ) AS current_b + WHERE deleted_old + ) AS current_b + WHERE bundles.bundle_id = current_b.bundle_id + + + + + + SELECT bundle_id, version, bundle + FROM ( + SELECT DISTINCT ON (bundle_id) bundle_id, version, deleted, bundle + FROM bundles ORDER BY bundle_id, version DESC + ) AS current_b + WHERE deleted IS NULL + + + + ALTER TABLE current_bundles OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_bundles TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_bundles TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.changelog.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.changelog.xml index e585d0921..1a97e5a90 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.changelog.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.changelog.xml @@ -9,7 +9,6 @@ - @@ -27,4 +26,27 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.code_systems.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.code_systems.changelog-0.2.0.xml new file mode 100644 index 000000000..21a2a0a5c --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.code_systems.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE code_systems SET deleted = current_cs.deleted_new + FROM ( + SELECT code_system_id, deleted_old, ((code_system->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (code_system_id) code_system_id, version, deleted_old, code_system + FROM code_systems ORDER BY code_system_id, version DESC + ) AS current_cs + WHERE deleted_old + ) AS current_cs + WHERE code_systems.code_system_id = current_cs.code_system_id + + + + + + SELECT code_system_id, version, code_system + FROM ( + SELECT DISTINCT ON (code_system_id) code_system_id, version, deleted, code_system + FROM code_systems ORDER BY code_system_id, version DESC + ) AS current_cs + WHERE deleted IS NULL + + + + ALTER TABLE current_code_systems OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_code_systems TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_code_systems TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.endpoints.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.endpoints.changelog-0.2.0.xml new file mode 100644 index 000000000..88050d919 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.endpoints.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE endpoints SET deleted = current_e.deleted_new + FROM ( + SELECT endpoint_id, deleted_old, ((endpoint->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (endpoint_id) endpoint_id, version, deleted_old, endpoint + FROM endpoints ORDER BY endpoint_id, version DESC + ) AS current_e + WHERE deleted_old + ) AS current_e + WHERE endpoints.endpoint_id = current_e.endpoint_id + + + + + + SELECT endpoint_id, version, endpoint + FROM ( + SELECT DISTINCT ON (endpoint_id) endpoint_id, version, deleted, endpoint + FROM endpoints ORDER BY endpoint_id, version DESC + ) AS current_e + WHERE deleted IS NULL + + + + ALTER TABLE current_endpoints OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_endpoints TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_endpoints TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.groups.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.groups.changelog-0.2.0.xml new file mode 100644 index 000000000..9660d39ae --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.groups.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE groups SET deleted = current_g.deleted_new + FROM ( + SELECT group_id, deleted_old, ((group_json->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (group_id) group_id, version, deleted_old, group_json + FROM groups ORDER BY group_id, version DESC + ) AS current_g + WHERE deleted_old + ) AS current_g + WHERE groups.group_id = current_g.group_id + + + + + + SELECT group_id, version, group_json + FROM ( + SELECT DISTINCT ON (group_id) group_id, version, deleted, group_json + FROM groups ORDER BY group_id, version DESC + ) AS current_g + WHERE deleted IS NULL + + + + ALTER TABLE current_groups OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_groups TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_groups TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.healthcare_services.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.healthcare_services.changelog-0.2.0.xml new file mode 100644 index 000000000..66a231da0 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.healthcare_services.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE healthcare_services SET deleted = current_hs.deleted_new + FROM ( + SELECT healthcare_service_id, deleted_old, ((healthcare_service->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (healthcare_service_id) healthcare_service_id, version, deleted_old, healthcare_service + FROM healthcare_services ORDER BY healthcare_service_id, version DESC + ) AS current_hs + WHERE deleted_old + ) AS current_hs + WHERE healthcare_services.healthcare_service_id = current_hs.healthcare_service_id + + + + + + SELECT healthcare_service_id, version, healthcare_service + FROM ( + SELECT DISTINCT ON (healthcare_service_id) healthcare_service_id, version, deleted, healthcare_service + FROM healthcare_services ORDER BY healthcare_service_id, version DESC + ) AS current_hs + WHERE deleted IS NULL + + + + ALTER TABLE current_healthcare_services OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_healthcare_services TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_healthcare_services TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.history.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.history.changelog-0.2.0.xml new file mode 100644 index 000000000..f827a7bac --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.history.changelog-0.2.0.xml @@ -0,0 +1,288 @@ + + + + + + + + + SELECT id, version, type, method, last_updated, resource + FROM ( + + SELECT activity_definition_id AS id, version, 'ActivityDefinition' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (activity_definition->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + activity_definition AS resource + FROM activity_definitions + + UNION + + SELECT activity_definition_id AS id, version + 1, 'ActivityDefinition' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM activity_definitions + WHERE deleted IS NOT NULL + + UNION + + SELECT binary_id AS id, version, 'Binary' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (binary_json->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + binary_json AS resource + FROM binaries + + UNION + + SELECT binary_id AS id, version + 1, 'Binary' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM binaries + WHERE deleted IS NOT NULL + + UNION + + SELECT bundle_id AS id, version, 'Bundle' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (bundle->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + bundle AS resource + FROM bundles + + UNION + + SELECT bundle_id AS id, version + 1, 'Bundle' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM bundles + WHERE deleted IS NOT NULL + + UNION + + SELECT code_system_id AS id, version, 'CodeSystem' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (code_system->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + code_system AS resource + FROM code_systems + + UNION + + SELECT code_system_id AS id, version + 1, 'CodeSystem' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM code_systems + WHERE deleted IS NOT NULL + + UNION + + SELECT endpoint_id AS id, version, 'Endpoint' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (endpoint->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + endpoint AS resource + FROM endpoints + + UNION + + SELECT endpoint_id AS id, version + 1, 'Endpoint' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM endpoints + WHERE deleted IS NOT NULL + + UNION + + SELECT group_id AS id, version, 'Group' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (group_json->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + group_json AS resource + FROM groups + + UNION + + SELECT group_id AS id, version + 1, 'Group' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM groups + WHERE deleted IS NOT NULL + + UNION + + SELECT healthcare_service_id AS id, version, 'HealthcareService' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (healthcare_service->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + healthcare_service AS resource + FROM healthcare_services + + UNION + + SELECT healthcare_service_id AS id, version + 1, 'HealthcareService' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM healthcare_services + WHERE deleted IS NOT NULL + + UNION + + SELECT location_id AS id, version, 'Location' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (location->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + location AS resource + FROM locations + + UNION + + SELECT location_id AS id, version + 1, 'Location' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM locations + WHERE deleted IS NOT NULL + + UNION + + SELECT naming_system_id AS id, version, 'NamingSystem' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (naming_system->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + naming_system AS resource + FROM naming_systems + + UNION + + SELECT naming_system_id AS id, version + 1, 'NamingSystem' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM naming_systems + WHERE deleted IS NOT NULL + + UNION + + SELECT organization_id AS id, version, 'Organization' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (organization->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + organization AS resource + FROM organizations + + UNION + + SELECT organization_id AS id, version + 1, 'Organization' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM organizations + WHERE deleted IS NOT NULL + + UNION + + SELECT patient_id AS id, version, 'Patient' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (patient->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + patient AS resource + FROM patients + + UNION + + SELECT patient_id AS id, version + 1, 'Patient' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM patients + WHERE deleted IS NOT NULL + + UNION + + SELECT practitioner_role_id AS id, version, 'PractitionerRole' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (practitioner_role->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + practitioner_role AS resource + FROM practitioner_roles + + UNION + + SELECT practitioner_role_id AS id, version + 1, 'PractitionerRole' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM practitioner_roles + WHERE deleted IS NOT NULL + + UNION + + SELECT practitioner_id AS id, version, 'Practitioner' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (practitioner->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + practitioner AS resource + FROM practitioners + + UNION + + SELECT practitioner_id AS id, version + 1, 'Practitioner' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM practitioners + WHERE deleted IS NOT NULL + + UNION + + SELECT provenance_id AS id, version, 'Provenance' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (provenance->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + provenance AS resource + FROM provenances + + UNION + + SELECT provenance_id AS id, version + 1, 'Provenance' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM provenances + WHERE deleted IS NOT NULL + + UNION + + SELECT research_study_id AS id, version, 'ResearchStudy' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (research_study->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + research_study AS resource + FROM research_studies + + UNION + + SELECT research_study_id AS id, version + 1, 'ResearchStudy' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM research_studies + WHERE deleted IS NOT NULL + + UNION + + SELECT structure_definition_id AS id, version, 'StructureDefinition' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (structure_definition->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + structure_definition AS resource + FROM structure_definitions + + UNION + + SELECT structure_definition_id AS id, version + 1, 'StructureDefinition' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM structure_definitions + WHERE deleted IS NOT NULL + + UNION + + SELECT subscription_id AS id, version, 'Subscription' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (subscription->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + subscription AS resource + FROM subscriptions + + UNION + + SELECT subscription_id AS id, version + 1, 'Subscription' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM subscriptions + WHERE deleted IS NOT NULL + + UNION + + SELECT task_id AS id, version, 'Task' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (task->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + task AS resource + FROM tasks + + UNION + + SELECT task_id AS id, version + 1, 'Task' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM tasks + WHERE deleted IS NOT NULL + + UNION + + SELECT value_set_id AS id, version, 'ValueSet' AS type, + CASE WHEN version = 1 THEN 'POST' ELSE 'PUT' END AS method, + (value_set->'meta'->>'lastUpdated')::TIMESTAMP AS last_updated, + value_set AS resource + FROM value_sets + + UNION + + SELECT value_set_id AS id, version + 1, 'ValueSet' AS type, 'DELETE' AS method, deleted AS last_updated, NULL AS resource + FROM value_sets + WHERE deleted IS NOT NULL + + ) AS history + ORDER BY last_updated, id, version + + + + ALTER TABLE history OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE history TO ${db.liquibase_user}; + GRANT SELECT ON TABLE history TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.locations.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.locations.changelog-0.2.0.xml new file mode 100644 index 000000000..5bbc582ea --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.locations.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE locations SET deleted = current_l.deleted_new + FROM ( + SELECT location_id, deleted_old, ((location->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (location_id) location_id, version, deleted_old, location + FROM locations ORDER BY location_id, version DESC + ) AS current_l + WHERE deleted_old + ) AS current_l + WHERE locations.location_id = current_l.location_id + + + + + + SELECT location_id, version, location + FROM ( + SELECT DISTINCT ON (location_id) location_id, version, deleted, location + FROM locations ORDER BY location_id, version DESC + ) AS current_l + WHERE deleted IS NULL + + + + ALTER TABLE current_locations OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_locations TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_locations TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.naming_systems.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.naming_systems.changelog-0.2.0.xml new file mode 100644 index 000000000..101d7ac8d --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.naming_systems.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE naming_systems SET deleted = current_ns.deleted_new + FROM ( + SELECT naming_system_id, deleted_old, ((naming_system->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (naming_system_id) naming_system_id, version, deleted_old, naming_system + FROM naming_systems ORDER BY naming_system_id, version DESC + ) AS current_ns + WHERE deleted_old + ) AS current_ns + WHERE naming_systems.naming_system_id = current_ns.naming_system_id + + + + + + SELECT naming_system_id, version, naming_system + FROM ( + SELECT DISTINCT ON (naming_system_id) naming_system_id, version, deleted, naming_system + FROM naming_systems ORDER BY naming_system_id, version DESC + ) AS current_ns + WHERE deleted IS NULL + + + + ALTER TABLE current_naming_systems OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_naming_systems TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_naming_systems TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.organizations.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.organizations.changelog-0.2.0.xml new file mode 100644 index 000000000..b3c8b5dc8 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.organizations.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE organizations SET deleted = current_o.deleted_new + FROM ( + SELECT organization_id, deleted_old, ((organization->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (organization_id) organization_id, version, deleted_old, organization + FROM organizations ORDER BY organization_id, version DESC + ) AS current_o + WHERE deleted_old + ) AS current_o + WHERE organizations.organization_id = current_o.organization_id + + + + + + SELECT organization_id, version, organization + FROM ( + SELECT DISTINCT ON (organization_id) organization_id, version, deleted, organization + FROM organizations ORDER BY organization_id, version DESC + ) AS current_o + WHERE deleted IS NULL + + + + ALTER TABLE current_organizations OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_organizations TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_organizations TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.patients.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.patients.changelog-0.2.0.xml new file mode 100644 index 000000000..e934c7826 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.patients.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE patients SET deleted = current_p.deleted_new + FROM ( + SELECT patient_id, deleted_old, ((patient->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (patient_id) patient_id, version, deleted_old, patient + FROM patients ORDER BY patient_id, version DESC + ) AS current_p + WHERE deleted_old + ) AS current_p + WHERE patients.patient_id = current_p.patient_id + + + + + + SELECT patient_id, version, patient + FROM ( + SELECT DISTINCT ON (patient_id) patient_id, version, deleted, patient + FROM patients ORDER BY patient_id, version DESC + ) AS current_p + WHERE deleted IS NULL + + + + ALTER TABLE current_patients OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_patients TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_patients TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.practitioner_roles.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.practitioner_roles.changelog-0.2.0.xml new file mode 100644 index 000000000..1349b17fc --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.practitioner_roles.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE practitioner_roles SET deleted = current_pr.deleted_new + FROM ( + SELECT practitioner_role_id, deleted_old, ((practitioner_role->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (practitioner_role_id) practitioner_role_id, version, deleted_old, practitioner_role + FROM practitioner_roles ORDER BY practitioner_role_id, version DESC + ) AS current_pr + WHERE deleted_old + ) AS current_pr + WHERE practitioner_roles.practitioner_role_id = current_pr.practitioner_role_id + + + + + + SELECT practitioner_role_id, version, practitioner_role + FROM ( + SELECT DISTINCT ON (practitioner_role_id) practitioner_role_id, version, deleted, practitioner_role + FROM practitioner_roles ORDER BY practitioner_role_id, version DESC + ) AS current_pr + WHERE deleted IS NULL + + + + ALTER TABLE current_practitioner_roles OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_practitioner_roles TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_practitioner_roles TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.practitioners.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.practitioners.changelog-0.2.0.xml new file mode 100644 index 000000000..ede0f75b0 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.practitioners.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE practitioners SET deleted = current_p.deleted_new + FROM ( + SELECT practitioner_id, deleted_old, ((practitioner->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (practitioner_id) practitioner_id, version, deleted_old, practitioner + FROM practitioners ORDER BY practitioner_id, version DESC + ) AS current_p + WHERE deleted_old + ) AS current_p + WHERE practitioners.practitioner_id = current_p.practitioner_id + + + + + + SELECT practitioner_id, version, practitioner + FROM ( + SELECT DISTINCT ON (practitioner_id) practitioner_id, version, deleted, practitioner + FROM practitioners ORDER BY practitioner_id, version DESC + ) AS current_p + WHERE deleted IS NULL + + + + ALTER TABLE current_practitioners OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_practitioners TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_practitioners TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.provenances.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.provenances.changelog-0.2.0.xml new file mode 100644 index 000000000..984834229 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.provenances.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE provenances SET deleted = current_p.deleted_new + FROM ( + SELECT provenance_id, deleted_old, ((provenance->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (provenance_id) provenance_id, version, deleted_old, provenance + FROM provenances ORDER BY provenance_id, version DESC + ) AS current_p + WHERE deleted_old + ) AS current_p + WHERE provenances.provenance_id = current_p.provenance_id + + + + + + SELECT provenance_id, version, provenance + FROM ( + SELECT DISTINCT ON (provenance_id) provenance_id, version, deleted, provenance + FROM provenances ORDER BY provenance_id, version DESC + ) AS current_p + WHERE deleted IS NULL + + + + ALTER TABLE current_provenances OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_provenances TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_provenances TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.research_studies.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.research_studies.changelog-0.2.0.xml new file mode 100644 index 000000000..c19b3d88b --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.research_studies.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE research_studies SET deleted = current_rs.deleted_new + FROM ( + SELECT research_study_id, deleted_old, ((research_study->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (research_study_id) research_study_id, version, deleted_old, research_study + FROM research_studies ORDER BY research_study_id, version DESC + ) AS current_rs + WHERE deleted_old + ) AS current_rs + WHERE research_studies.research_study_id = current_rs.research_study_id + + + + + + SELECT research_study_id, version, research_study + FROM ( + SELECT DISTINCT ON (research_study_id) research_study_id, version, deleted, research_study + FROM research_studies ORDER BY research_study_id, version DESC + ) AS current_rs + WHERE deleted IS NULL + + + + ALTER TABLE current_research_studies OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_research_studies TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_research_studies TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.structure_definition_snapshots.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.structure_definition_snapshots.changelog-0.2.0.xml new file mode 100644 index 000000000..291231337 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.structure_definition_snapshots.changelog-0.2.0.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + DROP INDEX IF EXISTS structure_definition_snapshot_info_index; + + + + + + + + + + + + + + UPDATE structure_definition_snapshots SET deleted = current_sds.deleted_new + FROM ( + SELECT structure_definition_snapshot_id, deleted_old, ((structure_definition_snapshot->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (structure_definition_snapshot_id) structure_definition_snapshot_id, version, deleted_old, structure_definition_snapshot + FROM structure_definition_snapshots ORDER BY structure_definition_snapshot_id, version DESC + ) AS current_sds + WHERE deleted_old + ) AS current_sds + WHERE structure_definition_snapshots.structure_definition_snapshot_id = current_sds.structure_definition_snapshot_id + + + + + + SELECT structure_definition_snapshot_id, version, structure_definition_snapshot + FROM ( + SELECT DISTINCT ON (structure_definition_snapshot_id) structure_definition_snapshot_id, version, deleted, structure_definition_snapshot + FROM structure_definition_snapshots ORDER BY structure_definition_snapshot_id, version DESC + ) AS current_sds + WHERE deleted IS NULL + + + + ALTER TABLE current_structure_definition_snapshots OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_structure_definition_snapshots TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_structure_definition_snapshots TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.structure_definitions.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.structure_definitions.changelog-0.2.0.xml new file mode 100644 index 000000000..493198b4b --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.structure_definitions.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE structure_definitions SET deleted = current_sd.deleted_new + FROM ( + SELECT structure_definition_id, deleted_old, ((structure_definition->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (structure_definition_id) structure_definition_id, version, deleted_old, structure_definition + FROM structure_definitions ORDER BY structure_definition_id, version DESC + ) AS current_sd + WHERE deleted_old + ) AS current_sd + WHERE structure_definitions.structure_definition_id = current_sd.structure_definition_id + + + + + + SELECT structure_definition_id, version, structure_definition + FROM ( + SELECT DISTINCT ON (structure_definition_id) structure_definition_id, version, deleted, structure_definition + FROM structure_definitions ORDER BY structure_definition_id, version DESC + ) AS current_sd + WHERE deleted IS NULL + + + + ALTER TABLE current_structure_definitions OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_structure_definitions TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_structure_definitions TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.subscriptions.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.subscriptions.changelog-0.2.0.xml new file mode 100644 index 000000000..e5b27f538 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.subscriptions.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE subscriptions SET deleted = current_s.deleted_new + FROM ( + SELECT subscription_id, deleted_old, ((subscription->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (subscription_id) subscription_id, version, deleted_old, subscription + FROM subscriptions ORDER BY subscription_id, version DESC + ) AS current_s + WHERE deleted_old + ) AS current_s + WHERE subscriptions.subscription_id = current_s.subscription_id + + + + + + SELECT subscription_id, version, subscription + FROM ( + SELECT DISTINCT ON (subscription_id) subscription_id, version, deleted, subscription + FROM subscriptions ORDER BY subscription_id, version DESC + ) AS current_s + WHERE deleted IS NULL + + + + ALTER TABLE current_subscriptions OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_subscriptions TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_subscriptions TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.tasks.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.tasks.changelog-0.2.0.xml new file mode 100644 index 000000000..9e2e499d4 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.tasks.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE tasks SET deleted = current_t.deleted_new + FROM ( + SELECT task_id, deleted_old, ((task->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (task_id) task_id, version, deleted_old, task + FROM tasks ORDER BY task_id, version DESC + ) AS current_t + WHERE deleted_old + ) AS current_t + WHERE tasks.task_id = current_t.task_id + + + + + + SELECT task_id, version, task + FROM ( + SELECT DISTINCT ON (task_id) task_id, version, deleted, task + FROM tasks ORDER BY task_id, version DESC + ) AS current_t + WHERE deleted IS NULL + + + + ALTER TABLE current_tasks OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_tasks TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_tasks TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.value_sets.changelog-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.value_sets.changelog-0.2.0.xml new file mode 100644 index 000000000..bdf2f6ba6 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.value_sets.changelog-0.2.0.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + UPDATE value_sets SET deleted = current_vs.deleted_new + FROM ( + SELECT value_set_id, deleted_old, ((value_set->'meta'->>'lastUpdated')::timestamp + interval '1' second) AS deleted_new + FROM ( + SELECT DISTINCT ON (value_set_id) value_set_id, version, deleted_old, value_set + FROM value_sets ORDER BY value_set_id, version DESC + ) AS current_vs + WHERE deleted_old + ) AS current_vs + WHERE value_sets.value_set_id = current_vs.value_set_id + + + + + + SELECT value_set_id, version, value_set + FROM ( + SELECT DISTINCT ON (value_set_id) value_set_id, version, deleted, value_set + FROM value_sets ORDER BY value_set_id, version DESC + ) AS current_vs + WHERE deleted IS NULL + + + + ALTER TABLE current_value_sets OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE current_value_sets TO ${db.liquibase_user}; + GRANT SELECT ON TABLE current_value_sets TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.1.0.xml.put deleted file mode 100644 index 409d243ff..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -ActivityDefinition?url=http://highmed.org/bpe/Process/computeSimpleFeasibility&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.2.0.xml similarity index 97% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.2.0.xml index 1a138ee6d..76a324b4e 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.2.0.xml @@ -70,13 +70,13 @@ - + <subtitle value="Process to compute simple feasibility result" /> <status value="draft" /> <experimental value="true" /> - <date value="2020-03-10T12:12:12+01:00" /> + <date value="2020-05-20" /> <publisher value="HiGHmed" /> <contact> <name value="HiGHmed" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.2.0.xml.post new file mode 100644 index 000000000..dcf1b03c4 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/computeSimpleFeasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/bpe/Process/computeSimpleFeasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.1.0.xml.put deleted file mode 100644 index e87d6183e..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -ActivityDefinition?url=http://highmed.org/bpe/Process/executeSimpleFeasibility&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.2.0.xml similarity index 96% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.2.0.xml index a162028bf..a463a00fa 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.2.0.xml @@ -44,13 +44,13 @@ </extension> </extension> <url value="http://highmed.org/bpe/Process/executeSimpleFeasibility" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="ExecuteSimpleFeasibility" /> <title value="Execute a Simple Feasibility" /> <subtitle value="Process to execute a simple feasibility query" /> <status value="draft" /> <experimental value="true" /> - <date value="2020-03-10T12:05:00+01:00" /> + <date value="2020-05-20" /> <publisher value="HiGHmed" /> <contact> <name value="HiGHmed" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.2.0.xml.post new file mode 100644 index 000000000..cbc396be9 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeSimpleFeasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/bpe/Process/executeSimpleFeasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.1.0.xml.put deleted file mode 100644 index c0170516e..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -ActivityDefinition?url=http://highmed.org/bpe/Process/executeUpdateResources&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.2.0.xml similarity index 96% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.2.0.xml index c5c0652f1..e4aa74cd9 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.2.0.xml @@ -44,13 +44,13 @@ </extension> </extension> <url value="http://highmed.org/bpe/Process/executeUpdateResources" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="ExecuteUpdateResources" /> <title value="Execute Update of Resources" /> <subtitle value="Process to Download and Execute FHIR Bundle" /> <status value="draft" /> <experimental value="true" /> - <date value="2020-03-10T10:40:00+01:00" /> + <date value="2020-05-25" /> <publisher value="HiGHmed" /> <contact> <name value="HiGHmed" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.2.0.xml.post new file mode 100644 index 000000000..a60338eb6 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/executeUpdateResources-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/bpe/Process/executeUpdateResources&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.1.0.xml.put deleted file mode 100644 index f1518ab7f..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -ActivityDefinition?url=http://highmed.org/bpe/Process/ping&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.2.0.xml similarity index 96% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.2.0.xml index 8fd0d75ff..28bf7abe5 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.2.0.xml @@ -7,7 +7,7 @@ </meta> <extension url="http://highmed.org/fhir/StructureDefinition/process-authorization"> <extension url="message-name"> - <valueString value="startProcessMessage" /> + <valueString value="startPingProcessMessage" /> </extension> <extension url="authorization-roles"> <extension url="authorization-role"> @@ -46,7 +46,7 @@ </extension> </extension> <extension url="task-profile"> - <valueCanonical value="http://highmed.org/fhir/StructureDefinition/highmed-task-start-process" /> + <valueCanonical value="http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process" /> </extension> </extension> <extension url="http://highmed.org/fhir/StructureDefinition/process-authorization"> @@ -94,13 +94,13 @@ </extension> </extension> <url value="http://highmed.org/bpe/Process/ping" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="PingProcess" /> <title value="PING process" /> <subtitle value="Communication Testing Process" /> <status value="draft" /> <experimental value="true" /> - <date value="2020-03-03T10:14:14+01:00" /> + <date value="2020-05-25" /> <publisher value="HiGHmed" /> <contact> <name value="HiGHmed" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.2.0.xml.post new file mode 100644 index 000000000..d581fa290 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/ping-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/bpe/Process/ping&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.1.0.xml.put deleted file mode 100644 index 36a3ab2c7..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -ActivityDefinition?url=http://highmed.org/bpe/Process/pong&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.2.0.xml similarity index 96% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.2.0.xml index 7c0d53f24..e4cd54603 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.2.0.xml @@ -50,13 +50,13 @@ </extension> </extension> <url value="http://highmed.org/bpe/Process/pong" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="PongProcess" /> <title value="PONG process" /> <subtitle value="Communication Testing Process" /> <status value="draft" /> <experimental value="true" /> - <date value="2020-03-03T10:14:14+01:00" /> + <date value="2020-05-25" /> <publisher value="HiGHmed" /> <contact> <name value="HiGHmed" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.2.0.xml.post new file mode 100644 index 000000000..92b49bab4 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/pong-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/bpe/Process/pong&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.1.0.xml.put deleted file mode 100644 index e2e134a4e..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -ActivityDefinition?url=http://highmed.org/bpe/Process/requestSimpleFeasibility&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.2.0.xml similarity index 97% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.2.0.xml index fa0abc6cc..0f923e5dc 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.2.0.xml @@ -70,13 +70,13 @@ </extension> </extension> <url value="http://highmed.org/bpe/Process/requestSimpleFeasibility" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="RequestSimpleFeasibility" /> <title value="Request simple feasibility" /> <subtitle value="Feasibility Request Process" /> <status value="draft" /> <experimental value="true" /> - <date value="2020-03-09T21:07:00+01:00" /> + <date value="2020-05-20" /> <publisher value="HiGHmed" /> <contact> <name value="HiGHmed" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.2.0.xml.post new file mode 100644 index 000000000..98053f209 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestSimpleFeasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/bpe/Process/requestSimpleFeasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.1.0.xml.put deleted file mode 100644 index 0a2f93bb2..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -ActivityDefinition?url=http://highmed.org/bpe/Process/requestUpdateResources&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.2.0.xml similarity index 96% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.2.0.xml index eb90b56af..2771fad17 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.2.0.xml @@ -38,13 +38,13 @@ </extension> </extension> <url value="http://highmed.org/bpe/Process/requestUpdateResources" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="RequestUpdateResources" /> <title value="Request Update of Resources" /> <subtitle value="Process to Request a Bundle Download" /> <status value="draft" /> <experimental value="true" /> - <date value="2020-03-10T11:02:00+01:00" /> + <date value="2020-05-25" /> <publisher value="HiGHmed" /> <contact> <name value="HiGHmed" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.2.0.xml.post new file mode 100644 index 000000000..9e8ef8bcf --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/requestUpdateResources-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/bpe/Process/requestUpdateResources&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhiteList-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhiteList-0.1.0.xml.put deleted file mode 100644 index 4cc51c434..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhiteList-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -ActivityDefinition?url=http://highmed.org/bpe/Process/updateWhiteList&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhiteList-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhitelist-0.2.0.xml similarity index 82% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhiteList-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhitelist-0.2.0.xml index 6cbdeea6f..baf767625 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhiteList-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhitelist-0.2.0.xml @@ -37,14 +37,14 @@ <valueCanonical value="http://highmed.org/fhir/StructureDefinition/highmed-task-update-whitelist" /> </extension> </extension> - <url value="http://highmed.org/bpe/Process/updateWhiteList" /> - <version value="0.1.0" /> - <name value="UpdateWhiteList" /> - <title value="Update White List" /> - <subtitle value="Update White List Bundle Process" /> + <url value="http://highmed.org/bpe/Process/updateWhitelist" /> + <version value="0.2.0" /> + <name value="UpdateWhitelist" /> + <title value="Update Whitelist" /> + <subtitle value="Update Whitelist Bundle Process" /> <status value="draft" /> <experimental value="true" /> - <date value="2020-03-10T10:40:00+01:00" /> + <date value="2020-05-25" /> <publisher value="HiGHmed" /> <contact> <name value="HiGHmed" /> @@ -53,6 +53,6 @@ <value value="pmo@highmed.org" /> </telecom> </contact> - <description value="Process to update the white list FHIR bundle" /> + <description value="Process to update the whitelist FHIR bundle" /> <kind value="Task" /> </ActivityDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhitelist-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhitelist-0.2.0.xml.post new file mode 100644 index 000000000..5b3b88f93 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ActivityDefinition/updateWhitelist-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/bpe/Process/updateWhitelist&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.1.0.xml.put deleted file mode 100644 index a1c148e79..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -CodeSystem?url=http://highmed.org/fhir/CodeSystem/authorization-role&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.2.0.xml similarity index 68% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.2.0.xml index b206e96c7..819c8a1d1 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.2.0.xml @@ -1,5 +1,4 @@ -<CodeSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<CodeSystem xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> @@ -7,12 +6,12 @@ </tag> </meta> <url value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <version value="0.1.0"/> - <name value="HiGHmed_Authorization_Values"/> - <title value="HiGHmed authorization values"/> + <version value="0.2.0"/> + <name value="HiGHmed_Authorization_Role"/> + <title value="HiGHmed Authorization Role"/> <status value="active"/> <experimental value="false"/> - <date value="2020-02-18T11:00:00+02:00"/> + <date value="2020-05-25"/> <publisher value="HiGHmed"/> <description value="CodeSystem with authorization roles"/> <caseSensitive value="true"/> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.2.0.xml.post new file mode 100644 index 000000000..d5ff27b5b --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/authorization-role-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/CodeSystem/authorization-role&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.1.0.xml.put deleted file mode 100755 index 96eae8039..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -CodeSystem?url=http://highmed.org/fhir/CodeSystem/bpmn-message&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.2.0.xml old mode 100755 new mode 100644 similarity index 83% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.2.0.xml index b941c7a77..943835c34 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.2.0.xml @@ -1,5 +1,4 @@ -<CodeSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<CodeSystem xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> @@ -7,12 +6,12 @@ </tag> </meta> <url value="http://highmed.org/fhir/CodeSystem/bpmn-message"/> - <version value="0.1.0"/> + <version value="0.2.0"/> <name value="HiGHmed_Bpmn_Message_Values"/> <title value="HiGHmed BPMN message values"/> <status value="active"/> <experimental value="false"/> - <date value="2019-08-21T18:40:00+02:00"/> + <date value="2020-05-25"/> <publisher value="HiGHmed"/> <description value="CodeSystem with standard BPMN message values for Task resources"/> <caseSensitive value="true"/> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.2.0.xml.post new file mode 100644 index 000000000..ccba20165 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/bpmn-message-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/CodeSystem/bpmn-message&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.1.0.xml.put deleted file mode 100644 index 5fe5c302d..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -CodeSystem?url=http://highmed.org/fhir/CodeSystem/feasibility&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.2.0.xml similarity index 52% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.2.0.xml index 8fc7d5265..929e72680 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.2.0.xml @@ -1,5 +1,4 @@ -<CodeSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<CodeSystem xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> @@ -7,36 +6,61 @@ </tag> </meta> <url value="http://highmed.org/fhir/CodeSystem/feasibility"/> - <version value="0.1.0"/> - <name value="HiGHmed_Feasibility_Values"/> - <title value="HiGHmed Feasibility Values"/> + <version value="0.2.0"/> + <name value="HiGHmed_Feasibility"/> + <title value="HiGHmed Feasibility"/> <status value="active"/> <experimental value="false"/> - <date value="2019-09-23T09:40:00+02:00"/> + <date value="2020-05-20"/> <publisher value="HiGHmed"/> <description value="CodeSystem with standard values for feasibility processes"/> <caseSensitive value="true"/> <hierarchyMeaning value="grouped-by"/> <versionNeeded value="false"/> <content value="complete"/> - <concept> + <concept> <code value="research-study-reference"/> <display value="Research Study Reference"/> <definition value="HiGHmed Research Study Reference to define what data is requested from which MeDICs and for what purpose"/> </concept> + <concept> + <code value="needs-record-linkage"/> + <display value="Needs Record Linkage"/> + <definition value="Boolean indicating if a data analysis needs record linkage"/> + </concept> + <concept> + <code value="needs-consent-check"/> + <display value="Needs Consent Check"/> + <definition value="Boolean indicating if a data analysis needs consent check"/> + </concept> + <concept> + <code value="bloom-filter-configuration"/> + <display value="Bloom Filter Cconfiguration"/> + <definition value="Base64 binary encoded bloom filter configuration"/> + </concept> + <concept> + <code value="medic-correlation-key"/> + <display value="MeDIC Correlation Key"/> + <definition value="MeDIC Correlation Key transfered to TTP for correlating incoming medic results"/> + </concept> <concept> <code value="single-medic-result"/> <display value="Single MeDIC Result"/> <definition value="Result of a single feasibility query execution"/> </concept> <concept> - <code value="multi-medic-result"/> - <display value="Multi MeDIC Result"/> - <definition value="Aggregated result of all single medic results"/> + <code value="single-medic-result-reference"/> + <display value="Single MeDIC Result Reference"/> + <definition value="Reference to an openEHR ResultSet as a result of a single feasibility query execution"/> </concept> <concept> <code value="participating-medics"/> <display value="Participating MeDICs"/> <definition value="Count of all MeDICs who participated in a feasibility query"/> </concept> + <concept> + <code value="multi-medic-result"/> + <display value="Multi MeDIC Result"/> + <definition value="Aggregated result of all single medic results"/> + </concept> </CodeSystem> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.2.0.xml.post new file mode 100644 index 000000000..356372056 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/feasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/CodeSystem/feasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.1.0.xml.put deleted file mode 100755 index 2a74050b2..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -CodeSystem?url=http://highmed.org/fhir/CodeSystem/organization-type&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.2.0.xml old mode 100755 new mode 100644 similarity index 76% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.2.0.xml index 39a7fd579..cd6f98ab2 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.2.0.xml @@ -1,5 +1,4 @@ -<CodeSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<CodeSystem xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> @@ -7,18 +6,19 @@ </tag> </meta> <url value="http://highmed.org/fhir/CodeSystem/organization-type"/> - <version value="0.1.0"/> + <version value="0.2.0"/> <name value="HiGHmed_Organization_Type"/> <title value="HiGHmed Organization Type"/> <status value="active"/> <experimental value="false"/> - <date value="2019-08-21T18:40:00+02:00"/> + <date value="2020-05-25"/> <publisher value="HiGHmed"/> <description value="CodeSystem with HiGHmed organization roles used in Organization resources"/> <caseSensitive value="true"/> <hierarchyMeaning value="grouped-by"/> <versionNeeded value="false"/> <content value="complete"/> + <count value="2"/> <concept> <code value="TTP"/> <definition value="Trusted Third Party"/> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.2.0.xml.post new file mode 100644 index 000000000..533d0559e --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/organization-type-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/CodeSystem/organization-type&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.1.0.xml.put deleted file mode 100755 index fa34ca540..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -CodeSystem?url=http://highmed.org/fhir/CodeSystem/query-type&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.2.0.xml similarity index 75% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.2.0.xml index 0509bd121..a7caebbf3 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.2.0.xml @@ -1,5 +1,4 @@ -<CodeSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<CodeSystem xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> @@ -7,12 +6,12 @@ </tag> </meta> <url value="http://highmed.org/fhir/CodeSystem/query-type"/> - <version value="0.1.0"/> + <version value="0.2.0"/> <name value="HiGHmed_Query_Type"/> <title value="HiGHmed Query Type"/> <status value="active"/> <experimental value="false"/> - <date value="2019-09-23T09:40:00+02:00"/> + <date value="2020-05-20"/> <publisher value="HiGHmed"/> <description value="CodeSystem with HiGHmed query types for medical data stored in the data lake repositories"/> <caseSensitive value="true"/> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.2.0.xml.post new file mode 100755 index 000000000..a67306bf4 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/query-type-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/CodeSystem/query-type&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resource-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resource-0.1.0.xml.put deleted file mode 100644 index ccf26c9f6..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resource-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -CodeSystem?url=http://highmed.org/fhir/CodeSystem/update-resources&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resource-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resources-0.2.0.xml similarity index 74% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resource-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resources-0.2.0.xml index 5277112b8..a8046e6ff 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resource-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resources-0.2.0.xml @@ -1,5 +1,4 @@ -<CodeSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<CodeSystem xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> @@ -7,12 +6,12 @@ </tag> </meta> <url value="http://highmed.org/fhir/CodeSystem/update-resources"/> - <version value="0.1.0"/> - <name value="HiGHmed_Update_Resource"/> - <title value="HiGHmed Update Resource"/> + <version value="0.2.0"/> + <name value="HiGHmed_Update_Resources"/> + <title value="HiGHmed Update Resources"/> <status value="active"/> <experimental value="false"/> - <date value="2019-10-17T08:40:00+02:00"/> + <date value="2020-05-25"/> <publisher value="HiGHmed"/> <description value="CodeSystem with standard values for the process update resources"/> <caseSensitive value="true"/> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resources-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resources-0.2.0.xml.post new file mode 100644 index 000000000..4764d0219 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-resources-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/CodeSystem/update-resources&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.1.0.xml.put deleted file mode 100644 index 8c2a40d41..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -CodeSystem?url=http://highmed.org/fhir/CodeSystem/update-whitelist&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.2.0.xml similarity index 59% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.2.0.xml index 7ee34e513..4bf6a65bd 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.2.0.xml @@ -1,5 +1,4 @@ -<CodeSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<CodeSystem xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> @@ -7,12 +6,12 @@ </tag> </meta> <url value="http://highmed.org/fhir/CodeSystem/update-whitelist"/> - <version value="0.1.0"/> - <name value="HiGHmed_Update_Whitelist_Values"/> - <title value="HiGHmed Update Whitelist Values"/> + <version value="0.2.0"/> + <name value="HiGHmed_Update_Whitelist"/> + <title value="HiGHmed Update Whitelist"/> <status value="active"/> <experimental value="false"/> - <date value="2019-09-23T09:40:00+02:00"/> + <date value="2020-05-25"/> <publisher value="HiGHmed"/> <description value="CodeSystem with standard values for the process update whitelist"/> <caseSensitive value="true"/> @@ -20,8 +19,8 @@ <versionNeeded value="false"/> <content value="complete"/> <concept> - <code value="HiGHmed_white_list"/> - <display value="HiGHmed White List"/> + <code value="highmed_whitelist"/> + <display value="HiGHmed Whitelist"/> <definition value="White list identifying organizations as part of HiGHmed"/> </concept> </CodeSystem> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.2.0.xml.post new file mode 100644 index 000000000..d13193464 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/update-whitelist-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/CodeSystem/update-whitelist&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/urn_ietf_bcp_13.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/urn_ietf_bcp_13.xml new file mode 100644 index 000000000..2c4eabea4 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/urn_ietf_bcp_13.xml @@ -0,0 +1,9271 @@ +<CodeSystem xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> + </meta> + <url value="urn:ietf:bcp:13" /> + <version value="4.0.1"/> + <name value="IANA_Media_Types" /> + <title value="IANA Media Types" /> + <status value="active" /> + <experimental value="false" /> + <date value="2020-05-29" /> + <publisher value="IANA" /> + <description value="Multipurpose Internet Mail Extensions (MIME) and Media Types as published by IANA at https://www.iana.org/assignments/media-types/media-types.xml" /> + <caseSensitive value="true" /> + <hierarchyMeaning value="grouped-by" /> + <versionNeeded value="false" /> + <content value="complete" /> + <concept> + <code value="application/1d-interleaved-parityfec" /> + <display value="1d-interleaved-parityfec" /> + <definition value="As defined by rfc6015"/> + </concept> + <concept> + <code value="application/3gpdash-qoe-report+xml" /> + <display value="3gpdash-qoe-report+xml" /> + <definition value="As defined by 3GPP, and Ozgur Oyman"/> + </concept> + <concept> + <code value="application/3gpp-ims+xml" /> + <display value="3gpp-ims+xml" /> + <definition value="As defined by John M Meredith"/> + </concept> + <concept> + <code value="application/A2L" /> + <display value="A2L" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/activemessage" /> + <display value="activemessage" /> + <definition value="As defined by Ehud Shapiro"/> + </concept> + <concept> + <code value="application/activity+json" /> + <display value="activity+json" /> + <definition value="As defined by W3C, and Benjamin Goering"/> + </concept> + <concept> + <code value="application/alto-costmap+json" /> + <display value="alto-costmap+json" /> + <definition value="As defined by rfc7285"/> + </concept> + <concept> + <code value="application/alto-costmapfilter+json" /> + <display value="alto-costmapfilter+json" /> + <definition value="As defined by rfc7285"/> + </concept> + <concept> + <code value="application/alto-directory+json" /> + <display value="alto-directory+json" /> + <definition value="As defined by rfc7285"/> + </concept> + <concept> + <code value="application/alto-endpointprop+json" /> + <display value="alto-endpointprop+json" /> + <definition value="As defined by rfc7285"/> + </concept> + <concept> + <code value="application/alto-endpointpropparams+json" /> + <display value="alto-endpointpropparams+json" /> + <definition value="As defined by rfc7285"/> + </concept> + <concept> + <code value="application/alto-endpointcost+json" /> + <display value="alto-endpointcost+json" /> + <definition value="As defined by rfc7285"/> + </concept> + <concept> + <code value="application/alto-endpointcostparams+json" /> + <display value="alto-endpointcostparams+json" /> + <definition value="As defined by rfc7285"/> + </concept> + <concept> + <code value="application/alto-error+json" /> + <display value="alto-error+json" /> + <definition value="As defined by rfc7285"/> + </concept> + <concept> + <code value="application/alto-networkmapfilter+json" /> + <display value="alto-networkmapfilter+json" /> + <definition value="As defined by rfc7285"/> + </concept> + <concept> + <code value="application/alto-networkmap+json" /> + <display value="alto-networkmap+json" /> + <definition value="As defined by rfc7285"/> + </concept> + <concept> + <code value="application/alto-updatestreamcontrol+json" /> + <display value="alto-updatestreamcontrol+json" /> + <definition value="As defined by RFC-ietf-alto-incr-update-sse-22"/> + </concept> + <concept> + <code value="application/alto-updatestreamparams+json" /> + <display value="alto-updatestreamparams+json" /> + <definition value="As defined by RFC-ietf-alto-incr-update-sse-22"/> + </concept> + <concept> + <code value="application/AML" /> + <display value="AML" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/andrew-inset" /> + <display value="andrew-inset" /> + <definition value="As defined by Nathaniel Borenstein"/> + </concept> + <concept> + <code value="application/applefile" /> + <display value="applefile" /> + <definition value="As defined by Patrik Faltstrom"/> + </concept> + <concept> + <code value="application/ATF" /> + <display value="ATF" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/ATFX" /> + <display value="ATFX" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/atom+xml" /> + <display value="atom+xml" /> + <definition value="As defined by rfc4287, and rfc5023"/> + </concept> + <concept> + <code value="application/atomcat+xml" /> + <display value="atomcat+xml" /> + <definition value="As defined by rfc5023"/> + </concept> + <concept> + <code value="application/atomdeleted+xml" /> + <display value="atomdeleted+xml" /> + <definition value="As defined by rfc6721"/> + </concept> + <concept> + <code value="application/atomicmail" /> + <display value="atomicmail" /> + <definition value="As defined by Nathaniel Borenstein"/> + </concept> + <concept> + <code value="application/atomsvc+xml" /> + <display value="atomsvc+xml" /> + <definition value="As defined by rfc5023"/> + </concept> + <concept> + <code value="application/atsc-dwd+xml" /> + <display value="atsc-dwd+xml" /> + <definition value="As defined by ATSC"/> + </concept> + <concept> + <code value="application/atsc-dynamic-event-message" /> + <display value="atsc-dynamic-event-message" /> + <definition value="As defined by ATSC"/> + </concept> + <concept> + <code value="application/atsc-held+xml" /> + <display value="atsc-held+xml" /> + <definition value="As defined by ATSC"/> + </concept> + <concept> + <code value="application/atsc-rdt+json" /> + <display value="atsc-rdt+json" /> + <definition value="As defined by ATSC"/> + </concept> + <concept> + <code value="application/atsc-rsat+xml" /> + <display value="atsc-rsat+xml" /> + <definition value="As defined by ATSC"/> + </concept> + <concept> + <code value="application/ATXML" /> + <display value="ATXML" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/auth-policy+xml" /> + <display value="auth-policy+xml" /> + <definition value="As defined by rfc4745"/> + </concept> + <concept> + <code value="application/bacnet-xdd+zip" /> + <display value="bacnet-xdd+zip" /> + <definition value="As defined by ASHRAE, and Dave Robin"/> + </concept> + <concept> + <code value="application/batch-SMTP" /> + <display value="batch-SMTP" /> + <definition value="As defined by rfc2442"/> + </concept> + <concept> + <code value="application/beep+xml" /> + <display value="beep+xml" /> + <definition value="As defined by rfc3080"/> + </concept> + <concept> + <code value="application/calendar+json" /> + <display value="calendar+json" /> + <definition value="As defined by rfc7265"/> + </concept> + <concept> + <code value="application/calendar+xml" /> + <display value="calendar+xml" /> + <definition value="As defined by rfc6321"/> + </concept> + <concept> + <code value="application/call-completion" /> + <display value="call-completion" /> + <definition value="As defined by rfc6910"/> + </concept> + <concept> + <code value="application/CALS-1840" /> + <display value="CALS-1840" /> + <definition value="As defined by rfc1895"/> + </concept> + <concept> + <code value="application/cap+xml" /> + <display value="cap+xml" /> + <definition value="As defined by RFC-ietf-ecrit-data-only-ea-22"/> + </concept> + <concept> + <code value="application/cbor" /> + <display value="cbor" /> + <definition value="As defined by rfc7049"/> + </concept> + <concept> + <code value="application/cbor-seq" /> + <display value="cbor-seq" /> + <definition value="As defined by rfc8742"/> + </concept> + <concept> + <code value="application/cccex" /> + <display value="cccex" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/ccmp+xml" /> + <display value="ccmp+xml" /> + <definition value="As defined by rfc6503"/> + </concept> + <concept> + <code value="application/ccxml+xml" /> + <display value="ccxml+xml" /> + <definition value="As defined by rfc4267"/> + </concept> + <concept> + <code value="application/CDFX+XML" /> + <display value="CDFX+XML" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/cdmi-capability" /> + <display value="cdmi-capability" /> + <definition value="As defined by rfc6208"/> + </concept> + <concept> + <code value="application/cdmi-container" /> + <display value="cdmi-container" /> + <definition value="As defined by rfc6208"/> + </concept> + <concept> + <code value="application/cdmi-domain" /> + <display value="cdmi-domain" /> + <definition value="As defined by rfc6208"/> + </concept> + <concept> + <code value="application/cdmi-object" /> + <display value="cdmi-object" /> + <definition value="As defined by rfc6208"/> + </concept> + <concept> + <code value="application/cdmi-queue" /> + <display value="cdmi-queue" /> + <definition value="As defined by rfc6208"/> + </concept> + <concept> + <code value="application/cdni" /> + <display value="cdni" /> + <definition value="As defined by rfc7736"/> + </concept> + <concept> + <code value="application/CEA" /> + <display value="CEA" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/cea-2018+xml" /> + <display value="cea-2018+xml" /> + <definition value="As defined by Gottfried Zimmermann"/> + </concept> + <concept> + <code value="application/cellml+xml" /> + <display value="cellml+xml" /> + <definition value="As defined by rfc4708"/> + </concept> + <concept> + <code value="application/cfw" /> + <display value="cfw" /> + <definition value="As defined by rfc6230"/> + </concept> + <concept> + <code value="application/clue_info+xml" /> + <display value="clue_info+xml" /> + <definition value="As defined by RFC-ietf-clue-data-model-schema-17"/> + </concept> + <concept> + <code value="application/clue+xml" /> + <display value="clue+xml" /> + <definition value="As defined by RFC-ietf-clue-protocol-19"/> + </concept> + <concept> + <code value="application/cms" /> + <display value="cms" /> + <definition value="As defined by rfc7193"/> + </concept> + <concept> + <code value="application/cnrp+xml" /> + <display value="cnrp+xml" /> + <definition value="As defined by rfc3367"/> + </concept> + <concept> + <code value="application/coap-group+json" /> + <display value="coap-group+json" /> + <definition value="As defined by rfc7390"/> + </concept> + <concept> + <code value="application/coap-payload" /> + <display value="coap-payload" /> + <definition value="As defined by rfc8075"/> + </concept> + <concept> + <code value="application/commonground" /> + <display value="commonground" /> + <definition value="As defined by David Glazer"/> + </concept> + <concept> + <code value="application/conference-info+xml" /> + <display value="conference-info+xml" /> + <definition value="As defined by rfc4575"/> + </concept> + <concept> + <code value="application/cpl+xml" /> + <display value="cpl+xml" /> + <definition value="As defined by rfc3880"/> + </concept> + <concept> + <code value="application/cose" /> + <display value="cose" /> + <definition value="As defined by rfc8152"/> + </concept> + <concept> + <code value="application/cose-key" /> + <display value="cose-key" /> + <definition value="As defined by rfc8152"/> + </concept> + <concept> + <code value="application/cose-key-set" /> + <display value="cose-key-set" /> + <definition value="As defined by rfc8152"/> + </concept> + <concept> + <code value="application/csrattrs" /> + <display value="csrattrs" /> + <definition value="As defined by rfc7030"/> + </concept> + <concept> + <code value="application/csta+xml" /> + <display value="csta+xml" /> + <definition value="As defined by Ecma International Helpdesk"/> + </concept> + <concept> + <code value="application/CSTAdata+xml" /> + <display value="CSTAdata+xml" /> + <definition value="As defined by Ecma International Helpdesk"/> + </concept> + <concept> + <code value="application/csvm+json" /> + <display value="csvm+json" /> + <definition value="As defined by W3C, and Ivan Herman"/> + </concept> + <concept> + <code value="application/cwt" /> + <display value="cwt" /> + <definition value="As defined by rfc8392"/> + </concept> + <concept> + <code value="application/cybercash" /> + <display value="cybercash" /> + <definition value="As defined by Donald E. Eastlake 3rd"/> + </concept> + <concept> + <code value="application/dash+xml" /> + <display value="dash+xml" /> + <definition value="As defined by Thomas Stockhammer, and ISO-IEC JTC1"/> + </concept> + <concept> + <code value="application/dashdelta" /> + <display value="dashdelta" /> + <definition value="As defined by David Furbeck"/> + </concept> + <concept> + <code value="application/davmount+xml" /> + <display value="davmount+xml" /> + <definition value="As defined by rfc4709"/> + </concept> + <concept> + <code value="application/dca-rft" /> + <display value="dca-rft" /> + <definition value="As defined by Larry Campbell"/> + </concept> + <concept> + <code value="application/DCD" /> + <display value="DCD" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/dec-dx" /> + <display value="dec-dx" /> + <definition value="As defined by Larry Campbell"/> + </concept> + <concept> + <code value="application/dialog-info+xml" /> + <display value="dialog-info+xml" /> + <definition value="As defined by rfc4235"/> + </concept> + <concept> + <code value="application/dicom" /> + <display value="dicom" /> + <definition value="As defined by rfc3240"/> + </concept> + <concept> + <code value="application/dicom+json" /> + <display value="dicom+json" /> + <definition value="As defined by DICOM Standards Committee, David Clunie, and James F Philbin"/> + </concept> + <concept> + <code value="application/dicom+xml" /> + <display value="dicom+xml" /> + <definition value="As defined by DICOM Standards Committee, David Clunie, and James F Philbin"/> + </concept> + <concept> + <code value="application/DII" /> + <display value="DII" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/DIT" /> + <display value="DIT" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/dns" /> + <display value="dns" /> + <definition value="As defined by rfc4027"/> + </concept> + <concept> + <code value="application/dns+json" /> + <display value="dns+json" /> + <definition value="As defined by rfc8427"/> + </concept> + <concept> + <code value="application/dns-message" /> + <display value="dns-message" /> + <definition value="As defined by rfc8484"/> + </concept> + <concept> + <code value="application/dots+cbor" /> + <display value="dots+cbor" /> + <definition value="As defined by RFC-ietf-dots-signal-channel-41"/> + </concept> + <concept> + <code value="application/dskpp+xml" /> + <display value="dskpp+xml" /> + <definition value="As defined by rfc6063"/> + </concept> + <concept> + <code value="application/dssc+der" /> + <display value="dssc+der" /> + <definition value="As defined by rfc5698"/> + </concept> + <concept> + <code value="application/dssc+xml" /> + <display value="dssc+xml" /> + <definition value="As defined by rfc5698"/> + </concept> + <concept> + <code value="application/dvcs" /> + <display value="dvcs" /> + <definition value="As defined by rfc3029"/> + </concept> + <concept> + <code value="application/ecmascript" /> + <display value="ecmascript" /> + <definition value="As defined by rfc4329"/> + </concept> + <concept> + <code value="application/EDI-consent" /> + <display value="EDI-consent" /> + <definition value="As defined by rfc1767"/> + </concept> + <concept> + <code value="application/EDIFACT" /> + <display value="EDIFACT" /> + <definition value="As defined by rfc1767"/> + </concept> + <concept> + <code value="application/EDI-X12" /> + <display value="EDI-X12" /> + <definition value="As defined by rfc1767"/> + </concept> + <concept> + <code value="application/efi" /> + <display value="efi" /> + <definition value="As defined by UEFI Forum, and Samer El-Haj-Mahmoud"/> + </concept> + <concept> + <code value="application/EmergencyCallData.Comment+xml" /> + <display value="EmergencyCallData.Comment+xml" /> + <definition value="As defined by rfc7852"/> + </concept> + <concept> + <code value="application/EmergencyCallData.Control+xml" /> + <display value="EmergencyCallData.Control+xml" /> + <definition value="As defined by rfc8147"/> + </concept> + <concept> + <code value="application/EmergencyCallData.DeviceInfo+xml" /> + <display value="EmergencyCallData.DeviceInfo+xml" /> + <definition value="As defined by rfc7852"/> + </concept> + <concept> + <code value="application/EmergencyCallData.eCall.MSD" /> + <display value="EmergencyCallData.eCall.MSD" /> + <definition value="As defined by rfc8147"/> + </concept> + <concept> + <code value="application/EmergencyCallData.ProviderInfo+xml" /> + <display value="EmergencyCallData.ProviderInfo+xml" /> + <definition value="As defined by rfc7852"/> + </concept> + <concept> + <code value="application/EmergencyCallData.ServiceInfo+xml" /> + <display value="EmergencyCallData.ServiceInfo+xml" /> + <definition value="As defined by rfc7852"/> + </concept> + <concept> + <code value="application/EmergencyCallData.SubscriberInfo+xml" /> + <display value="EmergencyCallData.SubscriberInfo+xml" /> + <definition value="As defined by rfc7852"/> + </concept> + <concept> + <code value="application/EmergencyCallData.VEDS+xml" /> + <display value="EmergencyCallData.VEDS+xml" /> + <definition value="As defined by rfc8148"/> + </concept> + <concept> + <code value="application/emma+xml" /> + <display value="emma+xml" /> + <definition value="As defined by W3C, http://www.w3.org/TR/2007/CR-emma-20071211/#media-type-registration, and ISO-IEC JTC1"/> + </concept> + <concept> + <code value="application/emotionml+xml" /> + <display value="emotionml+xml" /> + <definition value="As defined by W3C, and Kazuyuki Ashimura"/> + </concept> + <concept> + <code value="application/encaprtp" /> + <display value="encaprtp" /> + <definition value="As defined by rfc6849"/> + </concept> + <concept> + <code value="application/epp+xml" /> + <display value="epp+xml" /> + <definition value="As defined by rfc5730"/> + </concept> + <concept> + <code value="application/epub+zip" /> + <display value="epub+zip" /> + <definition value="As defined by International Digital Publishing Forum, and William McCoy"/> + </concept> + <concept> + <code value="application/eshop" /> + <display value="eshop" /> + <definition value="As defined by Steve Katz"/> + </concept> + <concept> + <code value="application/example" /> + <display value="example" /> + <definition value="As defined by rfc4735"/> + </concept> + <concept> + <code value="application/exi" /> + <display value="exi" /> + <definition value="As defined by W3C, and http://www.w3.org/TR/2009/CR-exi-20091208/#mediaTypeRegistration"/> + </concept> + <concept> + <code value="application/expect-ct-report+json" /> + <display value="expect-ct-report+json" /> + <definition value="As defined by RFC-ietf-httpbis-expect-ct-08"/> + </concept> + <concept> + <code value="application/fastinfoset" /> + <display value="fastinfoset" /> + <definition value="As defined by ITU-T ASN.1 Rapporteur"/> + </concept> + <concept> + <code value="application/fastsoap" /> + <display value="fastsoap" /> + <definition value="As defined by ITU-T ASN.1 Rapporteur"/> + </concept> + <concept> + <code value="application/fdt+xml" /> + <display value="fdt+xml" /> + <definition value="As defined by rfc6726"/> + </concept> + <concept> + <code value="application/fhir+json" /> + <display value="fhir+json" /> + <definition value="As defined by HL7, and Grahame Grieve"/> + </concept> + <concept> + <code value="application/fhir+xml" /> + <display value="fhir+xml" /> + <definition value="As defined by HL7, and Grahame Grieve"/> + </concept> + <concept> + <code value="application/fits" /> + <display value="fits" /> + <definition value="As defined by rfc4047"/> + </concept> + <concept> + <code value="application/flexfec" /> + <display value="flexfec" /> + <definition value="As defined by rfc8627"/> + </concept> + <concept> + <code value="application/font-sfnt - DEPRECATED in favor of font/sfnt" /> + <display value="font-sfnt - DEPRECATED in favor of font/sfnt" /> + <definition value="As defined by Levantovsky, ISO-IEC JTC1, and rfc8081"/> + </concept> + <concept> + <code value="application/font-tdpfr" /> + <display value="font-tdpfr" /> + <definition value="As defined by rfc3073"/> + </concept> + <concept> + <code value="application/font-woff - DEPRECATED in favor of font/woff" /> + <display value="font-woff - DEPRECATED in favor of font/woff" /> + <definition value="As defined by W3C, and rfc8081"/> + </concept> + <concept> + <code value="application/framework-attributes+xml" /> + <display value="framework-attributes+xml" /> + <definition value="As defined by rfc6230"/> + </concept> + <concept> + <code value="application/geo+json" /> + <display value="geo+json" /> + <definition value="As defined by rfc7946"/> + </concept> + <concept> + <code value="application/geo+json-seq" /> + <display value="geo+json-seq" /> + <definition value="As defined by rfc8142"/> + </concept> + <concept> + <code value="application/geopackage+sqlite3" /> + <display value="geopackage+sqlite3" /> + <definition value="As defined by OGC, and Scott Simmons"/> + </concept> + <concept> + <code value="application/geoxacml+xml" /> + <display value="geoxacml+xml" /> + <definition value="As defined by OGC, and Scott Simmons"/> + </concept> + <concept> + <code value="application/gltf-buffer" /> + <display value="gltf-buffer" /> + <definition value="As defined by Khronos, and Saurabh Bhatia"/> + </concept> + <concept> + <code value="application/gml+xml" /> + <display value="gml+xml" /> + <definition value="As defined by OGC, and Clemens Portele"/> + </concept> + <concept> + <code value="application/gzip" /> + <display value="gzip" /> + <definition value="As defined by rfc6713"/> + </concept> + <concept> + <code value="application/H224" /> + <display value="H224" /> + <definition value="As defined by rfc4573"/> + </concept> + <concept> + <code value="application/held+xml" /> + <display value="held+xml" /> + <definition value="As defined by rfc5985"/> + </concept> + <concept> + <code value="application/http" /> + <display value="http" /> + <definition value="As defined by rfc7230"/> + </concept> + <concept> + <code value="application/hyperstudio" /> + <display value="hyperstudio" /> + <definition value="As defined by Michael Domino"/> + </concept> + <concept> + <code value="application/ibe-key-request+xml" /> + <display value="ibe-key-request+xml" /> + <definition value="As defined by rfc5408"/> + </concept> + <concept> + <code value="application/ibe-pkg-reply+xml" /> + <display value="ibe-pkg-reply+xml" /> + <definition value="As defined by rfc5408"/> + </concept> + <concept> + <code value="application/ibe-pp-data" /> + <display value="ibe-pp-data" /> + <definition value="As defined by rfc5408"/> + </concept> + <concept> + <code value="application/iges" /> + <display value="iges" /> + <definition value="As defined by Curtis Parks"/> + </concept> + <concept> + <code value="application/im-iscomposing+xml" /> + <display value="im-iscomposing+xml" /> + <definition value="As defined by rfc3994"/> + </concept> + <concept> + <code value="application/index" /> + <display value="index" /> + <definition value="As defined by rfc2652"/> + </concept> + <concept> + <code value="application/index.cmd" /> + <display value="index.cmd" /> + <definition value="As defined by rfc2652"/> + </concept> + <concept> + <code value="application/index.obj" /> + <display value="index.obj" /> + <definition value="As defined by rfc2652"/> + </concept> + <concept> + <code value="application/index.response" /> + <display value="index.response" /> + <definition value="As defined by rfc2652"/> + </concept> + <concept> + <code value="application/index.vnd" /> + <display value="index.vnd" /> + <definition value="As defined by rfc2652"/> + </concept> + <concept> + <code value="application/inkml+xml" /> + <display value="inkml+xml" /> + <definition value="As defined by Kazuyuki Ashimura"/> + </concept> + <concept> + <code value="application/IOTP" /> + <display value="IOTP" /> + <definition value="As defined by rfc2935"/> + </concept> + <concept> + <code value="application/ipfix" /> + <display value="ipfix" /> + <definition value="As defined by rfc5655"/> + </concept> + <concept> + <code value="application/ipp" /> + <display value="ipp" /> + <definition value="As defined by rfc8010"/> + </concept> + <concept> + <code value="application/ISUP" /> + <display value="ISUP" /> + <definition value="As defined by rfc3204"/> + </concept> + <concept> + <code value="application/its+xml" /> + <display value="its+xml" /> + <definition value="As defined by W3C, and ITS-IG-W3C"/> + </concept> + <concept> + <code value="application/javascript" /> + <display value="javascript" /> + <definition value="As defined by rfc4329"/> + </concept> + <concept> + <code value="application/jf2feed+json" /> + <display value="jf2feed+json" /> + <definition value="As defined by W3C, and Ivan Herman"/> + </concept> + <concept> + <code value="application/jose" /> + <display value="jose" /> + <definition value="As defined by rfc7515"/> + </concept> + <concept> + <code value="application/jose+json" /> + <display value="jose+json" /> + <definition value="As defined by rfc7515"/> + </concept> + <concept> + <code value="application/jrd+json" /> + <display value="jrd+json" /> + <definition value="As defined by rfc7033"/> + </concept> + <concept> + <code value="application/json" /> + <display value="json" /> + <definition value="As defined by rfc8259"/> + </concept> + <concept> + <code value="application/json-patch+json" /> + <display value="json-patch+json" /> + <definition value="As defined by rfc6902"/> + </concept> + <concept> + <code value="application/json-seq" /> + <display value="json-seq" /> + <definition value="As defined by rfc7464"/> + </concept> + <concept> + <code value="application/jwk+json" /> + <display value="jwk+json" /> + <definition value="As defined by rfc7517"/> + </concept> + <concept> + <code value="application/jwk-set+json" /> + <display value="jwk-set+json" /> + <definition value="As defined by rfc7517"/> + </concept> + <concept> + <code value="application/jwt" /> + <display value="jwt" /> + <definition value="As defined by rfc7519"/> + </concept> + <concept> + <code value="application/kpml-request+xml" /> + <display value="kpml-request+xml" /> + <definition value="As defined by rfc4730"/> + </concept> + <concept> + <code value="application/kpml-response+xml" /> + <display value="kpml-response+xml" /> + <definition value="As defined by rfc4730"/> + </concept> + <concept> + <code value="application/ld+json" /> + <display value="ld+json" /> + <definition value="As defined by W3C, and Ivan Herman"/> + </concept> + <concept> + <code value="application/lgr+xml" /> + <display value="lgr+xml" /> + <definition value="As defined by rfc7940"/> + </concept> + <concept> + <code value="application/link-format" /> + <display value="link-format" /> + <definition value="As defined by rfc6690"/> + </concept> + <concept> + <code value="application/load-control+xml" /> + <display value="load-control+xml" /> + <definition value="As defined by rfc7200"/> + </concept> + <concept> + <code value="application/lost+xml" /> + <display value="lost+xml" /> + <definition value="As defined by rfc5222"/> + </concept> + <concept> + <code value="application/lostsync+xml" /> + <display value="lostsync+xml" /> + <definition value="As defined by rfc6739"/> + </concept> + <concept> + <code value="application/lpf+zip" /> + <display value="lpf+zip" /> + <definition value="As defined by W3C, and Ivan Herman"/> + </concept> + <concept> + <code value="application/LXF" /> + <display value="LXF" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/mac-binhex40" /> + <display value="mac-binhex40" /> + <definition value="As defined by Patrik Faltstrom"/> + </concept> + <concept> + <code value="application/macwriteii" /> + <display value="macwriteii" /> + <definition value="As defined by Paul Lindner"/> + </concept> + <concept> + <code value="application/mads+xml" /> + <display value="mads+xml" /> + <definition value="As defined by rfc6207"/> + </concept> + <concept> + <code value="application/marc" /> + <display value="marc" /> + <definition value="As defined by rfc2220"/> + </concept> + <concept> + <code value="application/marcxml+xml" /> + <display value="marcxml+xml" /> + <definition value="As defined by rfc6207"/> + </concept> + <concept> + <code value="application/mathematica" /> + <display value="mathematica" /> + <definition value="As defined by Wolfram"/> + </concept> + <concept> + <code value="application/mathml-content+xml" /> + <display value="mathml-content+xml" /> + <definition value="As defined by W3C, and http://www.w3.org/TR/MathML3/appendixb.html"/> + </concept> + <concept> + <code value="application/mathml-presentation+xml" /> + <display value="mathml-presentation+xml" /> + <definition value="As defined by W3C, and http://www.w3.org/TR/MathML3/appendixb.html"/> + </concept> + <concept> + <code value="application/mathml+xml" /> + <display value="mathml+xml" /> + <definition value="As defined by W3C, and http://www.w3.org/TR/MathML3/appendixb.html"/> + </concept> + <concept> + <code value="application/mbms-associated-procedure-description+xml" /> + <display value="mbms-associated-procedure-description+xml" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/mbms-deregister+xml" /> + <display value="mbms-deregister+xml" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/mbms-envelope+xml" /> + <display value="mbms-envelope+xml" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/mbms-msk-response+xml" /> + <display value="mbms-msk-response+xml" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/mbms-msk+xml" /> + <display value="mbms-msk+xml" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/mbms-protection-description+xml" /> + <display value="mbms-protection-description+xml" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/mbms-reception-report+xml" /> + <display value="mbms-reception-report+xml" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/mbms-register-response+xml" /> + <display value="mbms-register-response+xml" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/mbms-register+xml" /> + <display value="mbms-register+xml" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/mbms-schedule+xml" /> + <display value="mbms-schedule+xml" /> + <definition value="As defined by 3GPP, and Eric Turcotte"/> + </concept> + <concept> + <code value="application/mbms-user-service-description+xml" /> + <display value="mbms-user-service-description+xml" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/mbox" /> + <display value="mbox" /> + <definition value="As defined by rfc4155"/> + </concept> + <concept> + <code value="application/media_control+xml" /> + <display value="media_control+xml" /> + <definition value="As defined by rfc5168"/> + </concept> + <concept> + <code value="application/media-policy-dataset+xml" /> + <display value="media-policy-dataset+xml" /> + <definition value="As defined by rfc6796"/> + </concept> + <concept> + <code value="application/mediaservercontrol+xml" /> + <display value="mediaservercontrol+xml" /> + <definition value="As defined by rfc5022"/> + </concept> + <concept> + <code value="application/merge-patch+json" /> + <display value="merge-patch+json" /> + <definition value="As defined by rfc7396"/> + </concept> + <concept> + <code value="application/metalink4+xml" /> + <display value="metalink4+xml" /> + <definition value="As defined by rfc5854"/> + </concept> + <concept> + <code value="application/mets+xml" /> + <display value="mets+xml" /> + <definition value="As defined by rfc6207"/> + </concept> + <concept> + <code value="application/MF4" /> + <display value="MF4" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/mikey" /> + <display value="mikey" /> + <definition value="As defined by rfc3830"/> + </concept> + <concept> + <code value="application/mipc" /> + <display value="mipc" /> + <definition value="As defined by NCGIS, and Bryan Blank"/> + </concept> + <concept> + <code value="application/mmt-aei+xml" /> + <display value="mmt-aei+xml" /> + <definition value="As defined by ATSC"/> + </concept> + <concept> + <code value="application/mmt-usd+xml" /> + <display value="mmt-usd+xml" /> + <definition value="As defined by ATSC"/> + </concept> + <concept> + <code value="application/mods+xml" /> + <display value="mods+xml" /> + <definition value="As defined by rfc6207"/> + </concept> + <concept> + <code value="application/moss-keys" /> + <display value="moss-keys" /> + <definition value="As defined by rfc1848"/> + </concept> + <concept> + <code value="application/moss-signature" /> + <display value="moss-signature" /> + <definition value="As defined by rfc1848"/> + </concept> + <concept> + <code value="application/mosskey-data" /> + <display value="mosskey-data" /> + <definition value="As defined by rfc1848"/> + </concept> + <concept> + <code value="application/mosskey-request" /> + <display value="mosskey-request" /> + <definition value="As defined by rfc1848"/> + </concept> + <concept> + <code value="application/mp21" /> + <display value="mp21" /> + <definition value="As defined by rfc6381, and David Singer"/> + </concept> + <concept> + <code value="application/mp4" /> + <display value="mp4" /> + <definition value="As defined by rfc4337, and rfc6381"/> + </concept> + <concept> + <code value="application/mpeg4-generic" /> + <display value="mpeg4-generic" /> + <definition value="As defined by rfc3640"/> + </concept> + <concept> + <code value="application/mpeg4-iod" /> + <display value="mpeg4-iod" /> + <definition value="As defined by rfc4337"/> + </concept> + <concept> + <code value="application/mpeg4-iod-xmt" /> + <display value="mpeg4-iod-xmt" /> + <definition value="As defined by rfc4337"/> + </concept> + <concept> + <code value="application/mrb-consumer+xml" /> + <display value="mrb-consumer+xml" /> + <definition value="As defined by rfc6917"/> + </concept> + <concept> + <code value="application/mrb-publish+xml" /> + <display value="mrb-publish+xml" /> + <definition value="As defined by rfc6917"/> + </concept> + <concept> + <code value="application/msc-ivr+xml" /> + <display value="msc-ivr+xml" /> + <definition value="As defined by rfc6231"/> + </concept> + <concept> + <code value="application/msc-mixer+xml" /> + <display value="msc-mixer+xml" /> + <definition value="As defined by rfc6505"/> + </concept> + <concept> + <code value="application/msword" /> + <display value="msword" /> + <definition value="As defined by Paul Lindner"/> + </concept> + <concept> + <code value="application/mud+json" /> + <display value="mud+json" /> + <definition value="As defined by rfc8520"/> + </concept> + <concept> + <code value="application/multipart-core" /> + <display value="multipart-core" /> + <definition value="As defined by rfc8710"/> + </concept> + <concept> + <code value="application/mxf" /> + <display value="mxf" /> + <definition value="As defined by rfc4539"/> + </concept> + <concept> + <code value="application/n-quads" /> + <display value="n-quads" /> + <definition value="As defined by W3C, and Eric Prudhommeaux"/> + </concept> + <concept> + <code value="application/n-triples" /> + <display value="n-triples" /> + <definition value="As defined by W3C, and Eric Prudhommeaux"/> + </concept> + <concept> + <code value="application/nasdata" /> + <display value="nasdata" /> + <definition value="As defined by rfc4707"/> + </concept> + <concept> + <code value="application/news-checkgroups" /> + <display value="news-checkgroups" /> + <definition value="As defined by rfc5537"/> + </concept> + <concept> + <code value="application/news-groupinfo" /> + <display value="news-groupinfo" /> + <definition value="As defined by rfc5537"/> + </concept> + <concept> + <code value="application/news-transmission" /> + <display value="news-transmission" /> + <definition value="As defined by rfc5537"/> + </concept> + <concept> + <code value="application/nlsml+xml" /> + <display value="nlsml+xml" /> + <definition value="As defined by rfc6787"/> + </concept> + <concept> + <code value="application/node" /> + <display value="node" /> + <definition value="As defined by Node.js TSC"/> + </concept> + <concept> + <code value="application/nss" /> + <display value="nss" /> + <definition value="As defined by Michael Hammer"/> + </concept> + <concept> + <code value="application/ocsp-request" /> + <display value="ocsp-request" /> + <definition value="As defined by rfc6960"/> + </concept> + <concept> + <code value="application/ocsp-response" /> + <display value="ocsp-response" /> + <definition value="As defined by rfc6960"/> + </concept> + <concept> + <code value="application/octet-stream" /> + <display value="octet-stream" /> + <definition value="As defined by rfc2045, and rfc2046"/> + </concept> + <concept> + <code value="application/ODA" /> + <display value="ODA" /> + <definition value="As defined by rfc1494"/> + </concept> + <concept> + <code value="application/odm+xml" /> + <display value="odm+xml" /> + <definition value="As defined by CDISC, and Sam Hume"/> + </concept> + <concept> + <code value="application/ODX" /> + <display value="ODX" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/oebps-package+xml" /> + <display value="oebps-package+xml" /> + <definition value="As defined by rfc4839"/> + </concept> + <concept> + <code value="application/ogg" /> + <display value="ogg" /> + <definition value="As defined by rfc5334, and rfc7845"/> + </concept> + <concept> + <code value="application/oscore" /> + <display value="oscore" /> + <definition value="As defined by rfc8613"/> + </concept> + <concept> + <code value="application/oxps" /> + <display value="oxps" /> + <definition value="As defined by Ecma International Helpdesk"/> + </concept> + <concept> + <code value="application/p2p-overlay+xml" /> + <display value="p2p-overlay+xml" /> + <definition value="As defined by rfc6940"/> + </concept> + <concept> + <code value="application/parityfec" /> + <display value="parityfec" /> + <definition value="As defined by rfc5109"/> + </concept> + <concept> + <code value="application/passport" /> + <display value="passport" /> + <definition value="As defined by rfc8225"/> + </concept> + <concept> + <code value="application/patch-ops-error+xml" /> + <display value="patch-ops-error+xml" /> + <definition value="As defined by rfc5261"/> + </concept> + <concept> + <code value="application/pdf" /> + <display value="pdf" /> + <definition value="As defined by rfc8118"/> + </concept> + <concept> + <code value="application/PDX" /> + <display value="PDX" /> + <definition value="As defined by ASAM, and Thomas Thomsen"/> + </concept> + <concept> + <code value="application/pem-certificate-chain" /> + <display value="pem-certificate-chain" /> + <definition value="As defined by rfc8555"/> + </concept> + <concept> + <code value="application/pgp-encrypted" /> + <display value="pgp-encrypted" /> + <definition value="As defined by rfc3156"/> + </concept> + <concept> + <code value="application/pgp-keys" /> + <display value="pgp-keys" /> + <definition value="As defined by rfc3156"/> + </concept> + <concept> + <code value="application/pgp-signature" /> + <display value="pgp-signature" /> + <definition value="As defined by rfc3156"/> + </concept> + <concept> + <code value="application/pidf-diff+xml" /> + <display value="pidf-diff+xml" /> + <definition value="As defined by rfc5262"/> + </concept> + <concept> + <code value="application/pidf+xml" /> + <display value="pidf+xml" /> + <definition value="As defined by rfc3863"/> + </concept> + <concept> + <code value="application/pkcs10" /> + <display value="pkcs10" /> + <definition value="As defined by rfc5967"/> + </concept> + <concept> + <code value="application/pkcs7-mime" /> + <display value="pkcs7-mime" /> + <definition value="As defined by rfc8551, and rfc7114"/> + </concept> + <concept> + <code value="application/pkcs7-signature" /> + <display value="pkcs7-signature" /> + <definition value="As defined by rfc8551"/> + </concept> + <concept> + <code value="application/pkcs8" /> + <display value="pkcs8" /> + <definition value="As defined by rfc5958"/> + </concept> + <concept> + <code value="application/pkcs8-encrypted" /> + <display value="pkcs8-encrypted" /> + <definition value="As defined by rfc8351"/> + </concept> + <concept> + <code value="application/pkcs12" /> + <display value="pkcs12" /> + <definition value="As defined by IETF"/> + </concept> + <concept> + <code value="application/pkix-attr-cert" /> + <display value="pkix-attr-cert" /> + <definition value="As defined by rfc5877"/> + </concept> + <concept> + <code value="application/pkix-cert" /> + <display value="pkix-cert" /> + <definition value="As defined by rfc2585"/> + </concept> + <concept> + <code value="application/pkix-crl" /> + <display value="pkix-crl" /> + <definition value="As defined by rfc2585"/> + </concept> + <concept> + <code value="application/pkix-pkipath" /> + <display value="pkix-pkipath" /> + <definition value="As defined by rfc6066"/> + </concept> + <concept> + <code value="application/pkixcmp" /> + <display value="pkixcmp" /> + <definition value="As defined by rfc2510"/> + </concept> + <concept> + <code value="application/pls+xml" /> + <display value="pls+xml" /> + <definition value="As defined by rfc4267"/> + </concept> + <concept> + <code value="application/poc-settings+xml" /> + <display value="poc-settings+xml" /> + <definition value="As defined by rfc4354"/> + </concept> + <concept> + <code value="application/postscript" /> + <display value="postscript" /> + <definition value="As defined by rfc2045, and rfc2046"/> + </concept> + <concept> + <code value="application/ppsp-tracker+json" /> + <display value="ppsp-tracker+json" /> + <definition value="As defined by rfc7846"/> + </concept> + <concept> + <code value="application/problem+json" /> + <display value="problem+json" /> + <definition value="As defined by rfc7807"/> + </concept> + <concept> + <code value="application/problem+xml" /> + <display value="problem+xml" /> + <definition value="As defined by rfc7807"/> + </concept> + <concept> + <code value="application/provenance+xml" /> + <display value="provenance+xml" /> + <definition value="As defined by W3C, and Ivan Herman"/> + </concept> + <concept> + <code value="application/prs.alvestrand.titrax-sheet" /> + <display value="prs.alvestrand.titrax-sheet" /> + <definition value="As defined by Harald T. Alvestrand"/> + </concept> + <concept> + <code value="application/prs.cww" /> + <display value="prs.cww" /> + <definition value="As defined by Khemchart Rungchavalnont"/> + </concept> + <concept> + <code value="application/prs.hpub+zip" /> + <display value="prs.hpub+zip" /> + <definition value="As defined by Giulio Zambon"/> + </concept> + <concept> + <code value="application/prs.nprend" /> + <display value="prs.nprend" /> + <definition value="As defined by Jay Doggett"/> + </concept> + <concept> + <code value="application/prs.plucker" /> + <display value="prs.plucker" /> + <definition value="As defined by Bill Janssen"/> + </concept> + <concept> + <code value="application/prs.rdf-xml-crypt" /> + <display value="prs.rdf-xml-crypt" /> + <definition value="As defined by Toby Inkster"/> + </concept> + <concept> + <code value="application/prs.xsf+xml" /> + <display value="prs.xsf+xml" /> + <definition value="As defined by Maik Stührenberg"/> + </concept> + <concept> + <code value="application/pskc+xml" /> + <display value="pskc+xml" /> + <definition value="As defined by rfc6030"/> + </concept> + <concept> + <code value="application/pvd+json" /> + <display value="pvd+json" /> + <definition value="As defined by RFC-ietf-intarea-provisioning-domains-11"/> + </concept> + <concept> + <code value="application/rdf+xml" /> + <display value="rdf+xml" /> + <definition value="As defined by rfc3870"/> + </concept> + <concept> + <code value="application/route-apd+xml" /> + <display value="route-apd+xml" /> + <definition value="As defined by ATSC"/> + </concept> + <concept> + <code value="application/route-s-tsid+xml" /> + <display value="route-s-tsid+xml" /> + <definition value="As defined by ATSC"/> + </concept> + <concept> + <code value="application/route-usd+xml" /> + <display value="route-usd+xml" /> + <definition value="As defined by ATSC"/> + </concept> + <concept> + <code value="application/QSIG" /> + <display value="QSIG" /> + <definition value="As defined by rfc3204"/> + </concept> + <concept> + <code value="application/raptorfec" /> + <display value="raptorfec" /> + <definition value="As defined by rfc6682"/> + </concept> + <concept> + <code value="application/rdap+json" /> + <display value="rdap+json" /> + <definition value="As defined by rfc7483"/> + </concept> + <concept> + <code value="application/reginfo+xml" /> + <display value="reginfo+xml" /> + <definition value="As defined by rfc3680"/> + </concept> + <concept> + <code value="application/relax-ng-compact-syntax" /> + <display value="relax-ng-compact-syntax" /> + <definition value="As defined by http://www.jtc1sc34.org/repository/0661.pdf"/> + </concept> + <concept> + <code value="application/remote-printing" /> + <display value="remote-printing" /> + <definition value="As defined by rfc1486, and Marshall Rose"/> + </concept> + <concept> + <code value="application/reputon+json" /> + <display value="reputon+json" /> + <definition value="As defined by rfc7071"/> + </concept> + <concept> + <code value="application/resource-lists-diff+xml" /> + <display value="resource-lists-diff+xml" /> + <definition value="As defined by rfc5362"/> + </concept> + <concept> + <code value="application/resource-lists+xml" /> + <display value="resource-lists+xml" /> + <definition value="As defined by rfc4826"/> + </concept> + <concept> + <code value="application/rfc+xml" /> + <display value="rfc+xml" /> + <definition value="As defined by rfc7991"/> + </concept> + <concept> + <code value="application/riscos" /> + <display value="riscos" /> + <definition value="As defined by Nick Smith"/> + </concept> + <concept> + <code value="application/rlmi+xml" /> + <display value="rlmi+xml" /> + <definition value="As defined by rfc4662"/> + </concept> + <concept> + <code value="application/rls-services+xml" /> + <display value="rls-services+xml" /> + <definition value="As defined by rfc4826"/> + </concept> + <concept> + <code value="application/rpki-ghostbusters" /> + <display value="rpki-ghostbusters" /> + <definition value="As defined by rfc6493"/> + </concept> + <concept> + <code value="application/rpki-manifest" /> + <display value="rpki-manifest" /> + <definition value="As defined by rfc6481"/> + </concept> + <concept> + <code value="application/rpki-publication" /> + <display value="rpki-publication" /> + <definition value="As defined by rfc8181"/> + </concept> + <concept> + <code value="application/rpki-roa" /> + <display value="rpki-roa" /> + <definition value="As defined by rfc6481"/> + </concept> + <concept> + <code value="application/rpki-updown" /> + <display value="rpki-updown" /> + <definition value="As defined by rfc6492"/> + </concept> + <concept> + <code value="application/rtf" /> + <display value="rtf" /> + <definition value="As defined by Paul Lindner"/> + </concept> + <concept> + <code value="application/rtploopback" /> + <display value="rtploopback" /> + <definition value="As defined by rfc6849"/> + </concept> + <concept> + <code value="application/rtx" /> + <display value="rtx" /> + <definition value="As defined by rfc4588"/> + </concept> + <concept> + <code value="application/samlassertion+xml" /> + <display value="samlassertion+xml" /> + <definition value="As defined by OASIS Security Services Technical Committee SSTC"/> + </concept> + <concept> + <code value="application/samlmetadata+xml" /> + <display value="samlmetadata+xml" /> + <definition value="As defined by OASIS Security Services Technical Committee SSTC"/> + </concept> + <concept> + <code value="application/sbe" /> + <display value="sbe" /> + <definition value="As defined by FIX Trading Community, and Donald L. Mendelson"/> + </concept> + <concept> + <code value="application/sbml+xml" /> + <display value="sbml+xml" /> + <definition value="As defined by rfc3823"/> + </concept> + <concept> + <code value="application/scaip+xml" /> + <display value="scaip+xml" /> + <definition value="As defined by SIS, and Oskar Jonsson"/> + </concept> + <concept> + <code value="application/scim+json" /> + <display value="scim+json" /> + <definition value="As defined by rfc7644"/> + </concept> + <concept> + <code value="application/scvp-cv-request" /> + <display value="scvp-cv-request" /> + <definition value="As defined by rfc5055"/> + </concept> + <concept> + <code value="application/scvp-cv-response" /> + <display value="scvp-cv-response" /> + <definition value="As defined by rfc5055"/> + </concept> + <concept> + <code value="application/scvp-vp-request" /> + <display value="scvp-vp-request" /> + <definition value="As defined by rfc5055"/> + </concept> + <concept> + <code value="application/scvp-vp-response" /> + <display value="scvp-vp-response" /> + <definition value="As defined by rfc5055"/> + </concept> + <concept> + <code value="application/sdp" /> + <display value="sdp" /> + <definition value="As defined by RFC-ietf-mmusic-rfc4566bis-37"/> + </concept> + <concept> + <code value="application/secevent+jwt" /> + <display value="secevent+jwt" /> + <definition value="As defined by rfc8417"/> + </concept> + <concept> + <code value="application/senml-etch+cbor" /> + <display value="senml-etch+cbor" /> + <definition value="As defined by RFC-ietf-core-senml-etch-07"/> + </concept> + <concept> + <code value="application/senml-etch+json" /> + <display value="senml-etch+json" /> + <definition value="As defined by RFC-ietf-core-senml-etch-07"/> + </concept> + <concept> + <code value="application/senml-exi" /> + <display value="senml-exi" /> + <definition value="As defined by rfc8428"/> + </concept> + <concept> + <code value="application/senml+cbor" /> + <display value="senml+cbor" /> + <definition value="As defined by rfc8428"/> + </concept> + <concept> + <code value="application/senml+json" /> + <display value="senml+json" /> + <definition value="As defined by rfc8428"/> + </concept> + <concept> + <code value="application/senml+xml" /> + <display value="senml+xml" /> + <definition value="As defined by rfc8428"/> + </concept> + <concept> + <code value="application/sensml-exi" /> + <display value="sensml-exi" /> + <definition value="As defined by rfc8428"/> + </concept> + <concept> + <code value="application/sensml+cbor" /> + <display value="sensml+cbor" /> + <definition value="As defined by rfc8428"/> + </concept> + <concept> + <code value="application/sensml+json" /> + <display value="sensml+json" /> + <definition value="As defined by rfc8428"/> + </concept> + <concept> + <code value="application/sensml+xml" /> + <display value="sensml+xml" /> + <definition value="As defined by rfc8428"/> + </concept> + <concept> + <code value="application/sep-exi" /> + <display value="sep-exi" /> + <definition value="As defined by Robby Simpson, and ZigBee"/> + </concept> + <concept> + <code value="application/sep+xml" /> + <display value="sep+xml" /> + <definition value="As defined by Robby Simpson, and ZigBee"/> + </concept> + <concept> + <code value="application/session-info" /> + <display value="session-info" /> + <definition value="As defined by 3GPP, and Frederic Firmin"/> + </concept> + <concept> + <code value="application/set-payment" /> + <display value="set-payment" /> + <definition value="As defined by Brian Korver"/> + </concept> + <concept> + <code value="application/set-payment-initiation" /> + <display value="set-payment-initiation" /> + <definition value="As defined by Brian Korver"/> + </concept> + <concept> + <code value="application/set-registration" /> + <display value="set-registration" /> + <definition value="As defined by Brian Korver"/> + </concept> + <concept> + <code value="application/set-registration-initiation" /> + <display value="set-registration-initiation" /> + <definition value="As defined by Brian Korver"/> + </concept> + <concept> + <code value="application/SGML" /> + <display value="SGML" /> + <definition value="As defined by rfc1874"/> + </concept> + <concept> + <code value="application/sgml-open-catalog" /> + <display value="sgml-open-catalog" /> + <definition value="As defined by Paul Grosso"/> + </concept> + <concept> + <code value="application/shf+xml" /> + <display value="shf+xml" /> + <definition value="As defined by rfc4194"/> + </concept> + <concept> + <code value="application/sieve" /> + <display value="sieve" /> + <definition value="As defined by rfc5228"/> + </concept> + <concept> + <code value="application/simple-filter+xml" /> + <display value="simple-filter+xml" /> + <definition value="As defined by rfc4661"/> + </concept> + <concept> + <code value="application/simple-message-summary" /> + <display value="simple-message-summary" /> + <definition value="As defined by rfc3842"/> + </concept> + <concept> + <code value="application/simpleSymbolContainer" /> + <display value="simpleSymbolContainer" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="application/sipc" /> + <display value="sipc" /> + <definition value="As defined by NCGIS, and Bryan Blank"/> + </concept> + <concept> + <code value="application/slate" /> + <display value="slate" /> + <definition value="As defined by Terry Crowley"/> + </concept> + <concept> + <code value="application/smil+xml" /> + <display value="smil+xml" /> + <definition value="As defined by rfc4536"/> + </concept> + <concept> + <code value="application/smpte336m" /> + <display value="smpte336m" /> + <definition value="As defined by rfc6597"/> + </concept> + <concept> + <code value="application/soap+fastinfoset" /> + <display value="soap+fastinfoset" /> + <definition value="As defined by ITU-T ASN.1 Rapporteur"/> + </concept> + <concept> + <code value="application/soap+xml" /> + <display value="soap+xml" /> + <definition value="As defined by rfc3902"/> + </concept> + <concept> + <code value="application/sparql-query" /> + <display value="sparql-query" /> + <definition value="As defined by W3C, and http://www.w3.org/TR/2007/CR-rdf-sparql-query-20070614/#mediaType"/> + </concept> + <concept> + <code value="application/sparql-results+xml" /> + <display value="sparql-results+xml" /> + <definition value="As defined by W3C, and http://www.w3.org/TR/2007/CR-rdf-sparql-XMLres-20070925/#mime"/> + </concept> + <concept> + <code value="application/spirits-event+xml" /> + <display value="spirits-event+xml" /> + <definition value="As defined by rfc3910"/> + </concept> + <concept> + <code value="application/sql" /> + <display value="sql" /> + <definition value="As defined by rfc6922"/> + </concept> + <concept> + <code value="application/srgs" /> + <display value="srgs" /> + <definition value="As defined by rfc4267"/> + </concept> + <concept> + <code value="application/srgs+xml" /> + <display value="srgs+xml" /> + <definition value="As defined by rfc4267"/> + </concept> + <concept> + <code value="application/sru+xml" /> + <display value="sru+xml" /> + <definition value="As defined by rfc6207"/> + </concept> + <concept> + <code value="application/ssml+xml" /> + <display value="ssml+xml" /> + <definition value="As defined by rfc4267"/> + </concept> + <concept> + <code value="application/stix+json" /> + <display value="stix+json" /> + <definition value="As defined by OASIS, and Chet Ensign"/> + </concept> + <concept> + <code value="application/swid+xml" /> + <display value="swid+xml" /> + <definition value="As defined by ISO-IEC JTC1, David Waltermire, and Ron Brill"/> + </concept> + <concept> + <code value="application/tamp-apex-update" /> + <display value="tamp-apex-update" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/tamp-apex-update-confirm" /> + <display value="tamp-apex-update-confirm" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/tamp-community-update" /> + <display value="tamp-community-update" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/tamp-community-update-confirm" /> + <display value="tamp-community-update-confirm" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/tamp-error" /> + <display value="tamp-error" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/tamp-sequence-adjust" /> + <display value="tamp-sequence-adjust" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/tamp-sequence-adjust-confirm" /> + <display value="tamp-sequence-adjust-confirm" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/tamp-status-query" /> + <display value="tamp-status-query" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/tamp-status-response" /> + <display value="tamp-status-response" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/tamp-update" /> + <display value="tamp-update" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/tamp-update-confirm" /> + <display value="tamp-update-confirm" /> + <definition value="As defined by rfc5934"/> + </concept> + <concept> + <code value="application/taxii+json" /> + <display value="taxii+json" /> + <definition value="As defined by OASIS, and Chet Ensign"/> + </concept> + <concept> + <code value="application/td+json" /> + <display value="td+json" /> + <definition value="As defined by W3C, and Matthias Kovatsch"/> + </concept> + <concept> + <code value="application/tei+xml" /> + <display value="tei+xml" /> + <definition value="As defined by rfc6129"/> + </concept> + <concept> + <code value="application/TETRA_ISI" /> + <display value="TETRA_ISI" /> + <definition value="As defined by ETSI, and Miguel Angel Reina Ortega"/> + </concept> + <concept> + <code value="application/thraud+xml" /> + <display value="thraud+xml" /> + <definition value="As defined by rfc5941"/> + </concept> + <concept> + <code value="application/timestamp-query" /> + <display value="timestamp-query" /> + <definition value="As defined by rfc3161"/> + </concept> + <concept> + <code value="application/timestamp-reply" /> + <display value="timestamp-reply" /> + <definition value="As defined by rfc3161"/> + </concept> + <concept> + <code value="application/timestamped-data" /> + <display value="timestamped-data" /> + <definition value="As defined by rfc5955"/> + </concept> + <concept> + <code value="application/tlsrpt+gzip" /> + <display value="tlsrpt+gzip" /> + <definition value="As defined by rfc8460"/> + </concept> + <concept> + <code value="application/tlsrpt+json" /> + <display value="tlsrpt+json" /> + <definition value="As defined by rfc8460"/> + </concept> + <concept> + <code value="application/tnauthlist" /> + <display value="tnauthlist" /> + <definition value="As defined by rfc8226"/> + </concept> + <concept> + <code value="application/trickle-ice-sdpfrag" /> + <display value="trickle-ice-sdpfrag" /> + <definition value="As defined by RFC-ietf-mmusic-trickle-ice-sip-18"/> + </concept> + <concept> + <code value="application/trig" /> + <display value="trig" /> + <definition value="As defined by W3C, and W3C RDF Working Group"/> + </concept> + <concept> + <code value="application/ttml+xml" /> + <display value="ttml+xml" /> + <definition value="As defined by W3C, and W3C Timed Text Working Group"/> + </concept> + <concept> + <code value="application/tve-trigger" /> + <display value="tve-trigger" /> + <definition value="As defined by Linda Welsh"/> + </concept> + <concept> + <code value="application/tzif" /> + <display value="tzif" /> + <definition value="As defined by rfc8536"/> + </concept> + <concept> + <code value="application/tzif-leap" /> + <display value="tzif-leap" /> + <definition value="As defined by rfc8536"/> + </concept> + <concept> + <code value="application/ulpfec" /> + <display value="ulpfec" /> + <definition value="As defined by rfc5109"/> + </concept> + <concept> + <code value="application/urc-grpsheet+xml" /> + <display value="urc-grpsheet+xml" /> + <definition value="As defined by Gottfried Zimmermann, and ISO-IEC JTC1"/> + </concept> + <concept> + <code value="application/urc-ressheet+xml" /> + <display value="urc-ressheet+xml" /> + <definition value="As defined by Gottfried Zimmermann, and ISO-IEC JTC1"/> + </concept> + <concept> + <code value="application/urc-targetdesc+xml" /> + <display value="urc-targetdesc+xml" /> + <definition value="As defined by Gottfried Zimmermann, and ISO-IEC JTC1"/> + </concept> + <concept> + <code value="application/urc-uisocketdesc+xml" /> + <display value="urc-uisocketdesc+xml" /> + <definition value="As defined by Gottfried Zimmermann"/> + </concept> + <concept> + <code value="application/vcard+json" /> + <display value="vcard+json" /> + <definition value="As defined by rfc7095"/> + </concept> + <concept> + <code value="application/vcard+xml" /> + <display value="vcard+xml" /> + <definition value="As defined by rfc6351"/> + </concept> + <concept> + <code value="application/vemmi" /> + <display value="vemmi" /> + <definition value="As defined by rfc2122"/> + </concept> + <concept> + <code value="application/vnd.1000minds.decision-model+xml" /> + <display value="vnd.1000minds.decision-model+xml" /> + <definition value="As defined by Franz Ombler"/> + </concept> + <concept> + <code value="application/vnd.3gpp.access-transfer-events+xml" /> + <display value="vnd.3gpp.access-transfer-events+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.bsf+xml" /> + <display value="vnd.3gpp.bsf+xml" /> + <definition value="As defined by John M Meredith"/> + </concept> + <concept> + <code value="application/vnd.3gpp.GMOP+xml" /> + <display value="vnd.3gpp.GMOP+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mc-signalling-ear" /> + <display value="vnd.3gpp.mc-signalling-ear" /> + <definition value="As defined by Tim Woodward"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcdata-affiliation-command+xml" /> + <display value="vnd.3gpp.mcdata-affiliation-command+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcdata-info+xml" /> + <display value="vnd.3gpp.mcdata-info+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcdata-payload" /> + <display value="vnd.3gpp.mcdata-payload" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcdata-service-config+xml" /> + <display value="vnd.3gpp.mcdata-service-config+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcdata-signalling" /> + <display value="vnd.3gpp.mcdata-signalling" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcdata-ue-config+xml" /> + <display value="vnd.3gpp.mcdata-ue-config+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcdata-user-profile+xml" /> + <display value="vnd.3gpp.mcdata-user-profile+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcptt-affiliation-command+xml" /> + <display value="vnd.3gpp.mcptt-affiliation-command+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcptt-floor-request+xml" /> + <display value="vnd.3gpp.mcptt-floor-request+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcptt-info+xml" /> + <display value="vnd.3gpp.mcptt-info+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcptt-location-info+xml" /> + <display value="vnd.3gpp.mcptt-location-info+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcptt-mbms-usage-info+xml" /> + <display value="vnd.3gpp.mcptt-mbms-usage-info+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcptt-service-config+xml" /> + <display value="vnd.3gpp.mcptt-service-config+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcptt-signed+xml" /> + <display value="vnd.3gpp.mcptt-signed+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcptt-ue-config+xml" /> + <display value="vnd.3gpp.mcptt-ue-config+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcptt-ue-init-config+xml" /> + <display value="vnd.3gpp.mcptt-ue-init-config+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcptt-user-profile+xml" /> + <display value="vnd.3gpp.mcptt-user-profile+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcvideo-affiliation-command+xml" /> + <display value="vnd.3gpp.mcvideo-affiliation-command+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcvideo-info+xml" /> + <display value="vnd.3gpp.mcvideo-info+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcvideo-location-info+xml" /> + <display value="vnd.3gpp.mcvideo-location-info+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcvideo-mbms-usage-info+xml" /> + <display value="vnd.3gpp.mcvideo-mbms-usage-info+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcvideo-service-config+xml" /> + <display value="vnd.3gpp.mcvideo-service-config+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcvideo-transmission-request+xml" /> + <display value="vnd.3gpp.mcvideo-transmission-request+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcvideo-ue-config+xml" /> + <display value="vnd.3gpp.mcvideo-ue-config+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mcvideo-user-profile+xml" /> + <display value="vnd.3gpp.mcvideo-user-profile+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.mid-call+xml" /> + <display value="vnd.3gpp.mid-call+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.pic-bw-large" /> + <display value="vnd.3gpp.pic-bw-large" /> + <definition value="As defined by John M Meredith"/> + </concept> + <concept> + <code value="application/vnd.3gpp.pic-bw-small" /> + <display value="vnd.3gpp.pic-bw-small" /> + <definition value="As defined by John M Meredith"/> + </concept> + <concept> + <code value="application/vnd.3gpp.pic-bw-var" /> + <display value="vnd.3gpp.pic-bw-var" /> + <definition value="As defined by John M Meredith"/> + </concept> + <concept> + <code value="application/vnd.3gpp-prose-pc3ch+xml" /> + <display value="vnd.3gpp-prose-pc3ch+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp-prose+xml" /> + <display value="vnd.3gpp-prose+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.sms" /> + <display value="vnd.3gpp.sms" /> + <definition value="As defined by John M Meredith"/> + </concept> + <concept> + <code value="application/vnd.3gpp.sms+xml" /> + <display value="vnd.3gpp.sms+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.srvcc-ext+xml" /> + <display value="vnd.3gpp.srvcc-ext+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.SRVCC-info+xml" /> + <display value="vnd.3gpp.SRVCC-info+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.state-and-event-info+xml" /> + <display value="vnd.3gpp.state-and-event-info+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp.ussd+xml" /> + <display value="vnd.3gpp.ussd+xml" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp-v2x-local-service-information" /> + <display value="vnd.3gpp-v2x-local-service-information" /> + <definition value="As defined by Frederic Firmin"/> + </concept> + <concept> + <code value="application/vnd.3gpp2.bcmcsinfo+xml" /> + <display value="vnd.3gpp2.bcmcsinfo+xml" /> + <definition value="As defined by Andy Dryden"/> + </concept> + <concept> + <code value="application/vnd.3gpp2.sms" /> + <display value="vnd.3gpp2.sms" /> + <definition value="As defined by AC Mahendran"/> + </concept> + <concept> + <code value="application/vnd.3gpp2.tcap" /> + <display value="vnd.3gpp2.tcap" /> + <definition value="As defined by AC Mahendran"/> + </concept> + <concept> + <code value="application/vnd.3lightssoftware.imagescal" /> + <display value="vnd.3lightssoftware.imagescal" /> + <definition value="As defined by Gus Asadi"/> + </concept> + <concept> + <code value="application/vnd.3M.Post-it-Notes" /> + <display value="vnd.3M.Post-it-Notes" /> + <definition value="As defined by Michael OBrien"/> + </concept> + <concept> + <code value="application/vnd.accpac.simply.aso" /> + <display value="vnd.accpac.simply.aso" /> + <definition value="As defined by Steve Leow"/> + </concept> + <concept> + <code value="application/vnd.accpac.simply.imp" /> + <display value="vnd.accpac.simply.imp" /> + <definition value="As defined by Steve Leow"/> + </concept> + <concept> + <code value="application/vnd.acucobol" /> + <display value="vnd.acucobol" /> + <definition value="As defined by Dovid Lubin"/> + </concept> + <concept> + <code value="application/vnd.acucorp" /> + <display value="vnd.acucorp" /> + <definition value="As defined by Dovid Lubin"/> + </concept> + <concept> + <code value="application/vnd.adobe.flash.movie" /> + <display value="vnd.adobe.flash.movie" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="application/vnd.adobe.formscentral.fcdt" /> + <display value="vnd.adobe.formscentral.fcdt" /> + <definition value="As defined by Chris Solc"/> + </concept> + <concept> + <code value="application/vnd.adobe.fxp" /> + <display value="vnd.adobe.fxp" /> + <definition value="As defined by Robert Brambley, and Steven Heintz"/> + </concept> + <concept> + <code value="application/vnd.adobe.partial-upload" /> + <display value="vnd.adobe.partial-upload" /> + <definition value="As defined by Tapani Otala"/> + </concept> + <concept> + <code value="application/vnd.adobe.xdp+xml" /> + <display value="vnd.adobe.xdp+xml" /> + <definition value="As defined by John Brinkman"/> + </concept> + <concept> + <code value="application/vnd.adobe.xfdf" /> + <display value="vnd.adobe.xfdf" /> + <definition value="As defined by Roberto Perelman"/> + </concept> + <concept> + <code value="application/vnd.aether.imp" /> + <display value="vnd.aether.imp" /> + <definition value="As defined by Jay Moskowitz"/> + </concept> + <concept> + <code value="application/vnd.afpc.afplinedata" /> + <display value="vnd.afpc.afplinedata" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.afpc.afplinedata-pagedef" /> + <display value="vnd.afpc.afplinedata-pagedef" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.afpc.foca-charset" /> + <display value="vnd.afpc.foca-charset" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.afpc.foca-codedfont" /> + <display value="vnd.afpc.foca-codedfont" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.afpc.foca-codepage" /> + <display value="vnd.afpc.foca-codepage" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.afpc.modca" /> + <display value="vnd.afpc.modca" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.afpc.modca-formdef" /> + <display value="vnd.afpc.modca-formdef" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.afpc.modca-mediummap" /> + <display value="vnd.afpc.modca-mediummap" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.afpc.modca-objectcontainer" /> + <display value="vnd.afpc.modca-objectcontainer" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.afpc.modca-overlay" /> + <display value="vnd.afpc.modca-overlay" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.afpc.modca-pagesegment" /> + <display value="vnd.afpc.modca-pagesegment" /> + <definition value="As defined by Jörg Palmer"/> + </concept> + <concept> + <code value="application/vnd.ah-barcode" /> + <display value="vnd.ah-barcode" /> + <definition value="As defined by Katsuhiko Ichinose"/> + </concept> + <concept> + <code value="application/vnd.ahead.space" /> + <display value="vnd.ahead.space" /> + <definition value="As defined by Tor Kristensen"/> + </concept> + <concept> + <code value="application/vnd.airzip.filesecure.azf" /> + <display value="vnd.airzip.filesecure.azf" /> + <definition value="As defined by Daniel Mould, and Gary Clueit"/> + </concept> + <concept> + <code value="application/vnd.airzip.filesecure.azs" /> + <display value="vnd.airzip.filesecure.azs" /> + <definition value="As defined by Daniel Mould, and Gary Clueit"/> + </concept> + <concept> + <code value="application/vnd.amadeus+json" /> + <display value="vnd.amadeus+json" /> + <definition value="As defined by Patrick Brosse"/> + </concept> + <concept> + <code value="application/vnd.amazon.mobi8-ebook" /> + <display value="vnd.amazon.mobi8-ebook" /> + <definition value="As defined by Kim Scarborough"/> + </concept> + <concept> + <code value="application/vnd.americandynamics.acc" /> + <display value="vnd.americandynamics.acc" /> + <definition value="As defined by Gary Sands"/> + </concept> + <concept> + <code value="application/vnd.amiga.ami" /> + <display value="vnd.amiga.ami" /> + <definition value="As defined by Kevin Blumberg"/> + </concept> + <concept> + <code value="application/vnd.amundsen.maze+xml" /> + <display value="vnd.amundsen.maze+xml" /> + <definition value="As defined by Mike Amundsen"/> + </concept> + <concept> + <code value="application/vnd.android.ota" /> + <display value="vnd.android.ota" /> + <definition value="As defined by Greg Kaiser"/> + </concept> + <concept> + <code value="application/vnd.anki" /> + <display value="vnd.anki" /> + <definition value="As defined by Kerrick Staley"/> + </concept> + <concept> + <code value="application/vnd.anser-web-certificate-issue-initiation" /> + <display value="vnd.anser-web-certificate-issue-initiation" /> + <definition value="As defined by Hiroyoshi Mori"/> + </concept> + <concept> + <code value="application/vnd.antix.game-component" /> + <display value="vnd.antix.game-component" /> + <definition value="As defined by Daniel Shelton"/> + </concept> + <concept> + <code value="application/vnd.apache.thrift.binary" /> + <display value="vnd.apache.thrift.binary" /> + <definition value="As defined by Roger Meier"/> + </concept> + <concept> + <code value="application/vnd.apache.thrift.compact" /> + <display value="vnd.apache.thrift.compact" /> + <definition value="As defined by Roger Meier"/> + </concept> + <concept> + <code value="application/vnd.apache.thrift.json" /> + <display value="vnd.apache.thrift.json" /> + <definition value="As defined by Roger Meier"/> + </concept> + <concept> + <code value="application/vnd.api+json" /> + <display value="vnd.api+json" /> + <definition value="As defined by Steve Klabnik"/> + </concept> + <concept> + <code value="application/vnd.aplextor.warrp+json" /> + <display value="vnd.aplextor.warrp+json" /> + <definition value="As defined by Oleg Uryutin"/> + </concept> + <concept> + <code value="application/vnd.apothekende.reservation+json" /> + <display value="vnd.apothekende.reservation+json" /> + <definition value="As defined by Adrian Föder"/> + </concept> + <concept> + <code value="application/vnd.apple.installer+xml" /> + <display value="vnd.apple.installer+xml" /> + <definition value="As defined by Peter Bierman"/> + </concept> + <concept> + <code value="application/vnd.apple.keynote" /> + <display value="vnd.apple.keynote" /> + <definition value="As defined by Manichandra Sajjanapu"/> + </concept> + <concept> + <code value="application/vnd.apple.mpegurl" /> + <display value="vnd.apple.mpegurl" /> + <definition value="As defined by rfc8216"/> + </concept> + <concept> + <code value="application/vnd.apple.numbers" /> + <display value="vnd.apple.numbers" /> + <definition value="As defined by Manichandra Sajjanapu"/> + </concept> + <concept> + <code value="application/vnd.apple.pages" /> + <display value="vnd.apple.pages" /> + <definition value="As defined by Manichandra Sajjanapu"/> + </concept> + <concept> + <code value="application/vnd.aristanetworks.swi" /> + <display value="vnd.aristanetworks.swi" /> + <definition value="As defined by Bill Fenner"/> + </concept> + <concept> + <code value="application/vnd.artisan+json" /> + <display value="vnd.artisan+json" /> + <definition value="As defined by Brad Turner"/> + </concept> + <concept> + <code value="application/vnd.artsquare" /> + <display value="vnd.artsquare" /> + <definition value="As defined by Christopher Smith"/> + </concept> + <concept> + <code value="application/vnd.astraea-software.iota" /> + <display value="vnd.astraea-software.iota" /> + <definition value="As defined by Christopher Snazell"/> + </concept> + <concept> + <code value="application/vnd.audiograph" /> + <display value="vnd.audiograph" /> + <definition value="As defined by Horia Cristian Slusanschi"/> + </concept> + <concept> + <code value="application/vnd.autopackage" /> + <display value="vnd.autopackage" /> + <definition value="As defined by Mike Hearn"/> + </concept> + <concept> + <code value="application/vnd.avalon+json" /> + <display value="vnd.avalon+json" /> + <definition value="As defined by Ben Hinman"/> + </concept> + <concept> + <code value="application/vnd.avistar+xml" /> + <display value="vnd.avistar+xml" /> + <definition value="As defined by Vladimir Vysotsky"/> + </concept> + <concept> + <code value="application/vnd.balsamiq.bmml+xml" /> + <display value="vnd.balsamiq.bmml+xml" /> + <definition value="As defined by Giacomo Guilizzoni"/> + </concept> + <concept> + <code value="application/vnd.banana-accounting" /> + <display value="vnd.banana-accounting" /> + <definition value="As defined by José Del Romano"/> + </concept> + <concept> + <code value="application/vnd.bbf.usp.error" /> + <display value="vnd.bbf.usp.error" /> + <definition value="As defined by Broadband Forum"/> + </concept> + <concept> + <code value="application/vnd.bbf.usp.msg" /> + <display value="vnd.bbf.usp.msg" /> + <definition value="As defined by Broadband Forum"/> + </concept> + <concept> + <code value="application/vnd.bbf.usp.msg+json" /> + <display value="vnd.bbf.usp.msg+json" /> + <definition value="As defined by Broadband Forum"/> + </concept> + <concept> + <code value="application/vnd.balsamiq.bmpr" /> + <display value="vnd.balsamiq.bmpr" /> + <definition value="As defined by Giacomo Guilizzoni"/> + </concept> + <concept> + <code value="application/vnd.bekitzur-stech+json" /> + <display value="vnd.bekitzur-stech+json" /> + <definition value="As defined by Jegulsky"/> + </concept> + <concept> + <code value="application/vnd.bint.med-content" /> + <display value="vnd.bint.med-content" /> + <definition value="As defined by Heinz-Peter Schütz"/> + </concept> + <concept> + <code value="application/vnd.biopax.rdf+xml" /> + <display value="vnd.biopax.rdf+xml" /> + <definition value="As defined by Pathway Commons"/> + </concept> + <concept> + <code value="application/vnd.blink-idb-value-wrapper" /> + <display value="vnd.blink-idb-value-wrapper" /> + <definition value="As defined by Victor Costan"/> + </concept> + <concept> + <code value="application/vnd.blueice.multipass" /> + <display value="vnd.blueice.multipass" /> + <definition value="As defined by Thomas Holmstrom"/> + </concept> + <concept> + <code value="application/vnd.bluetooth.ep.oob" /> + <display value="vnd.bluetooth.ep.oob" /> + <definition value="As defined by Mike Foley"/> + </concept> + <concept> + <code value="application/vnd.bluetooth.le.oob" /> + <display value="vnd.bluetooth.le.oob" /> + <definition value="As defined by Mark Powell"/> + </concept> + <concept> + <code value="application/vnd.bmi" /> + <display value="vnd.bmi" /> + <definition value="As defined by Tadashi Gotoh"/> + </concept> + <concept> + <code value="application/vnd.bpf" /> + <display value="vnd.bpf" /> + <definition value="As defined by NCGIS, and Bryan Blank"/> + </concept> + <concept> + <code value="application/vnd.bpf3" /> + <display value="vnd.bpf3" /> + <definition value="As defined by NCGIS, and Bryan Blank"/> + </concept> + <concept> + <code value="application/vnd.businessobjects" /> + <display value="vnd.businessobjects" /> + <definition value="As defined by Philippe Imoucha"/> + </concept> + <concept> + <code value="application/vnd.byu.uapi+json" /> + <display value="vnd.byu.uapi+json" /> + <definition value="As defined by Brent Moore"/> + </concept> + <concept> + <code value="application/vnd.cab-jscript" /> + <display value="vnd.cab-jscript" /> + <definition value="As defined by Joerg Falkenberg"/> + </concept> + <concept> + <code value="application/vnd.canon-cpdl" /> + <display value="vnd.canon-cpdl" /> + <definition value="As defined by Shin Muto"/> + </concept> + <concept> + <code value="application/vnd.canon-lips" /> + <display value="vnd.canon-lips" /> + <definition value="As defined by Shin Muto"/> + </concept> + <concept> + <code value="application/vnd.capasystems-pg+json" /> + <display value="vnd.capasystems-pg+json" /> + <definition value="As defined by Yüksel Aydemir"/> + </concept> + <concept> + <code value="application/vnd.cendio.thinlinc.clientconf" /> + <display value="vnd.cendio.thinlinc.clientconf" /> + <definition value="As defined by Peter Astrand"/> + </concept> + <concept> + <code value="application/vnd.century-systems.tcp_stream" /> + <display value="vnd.century-systems.tcp_stream" /> + <definition value="As defined by Shuji Fujii"/> + </concept> + <concept> + <code value="application/vnd.chemdraw+xml" /> + <display value="vnd.chemdraw+xml" /> + <definition value="As defined by Glenn Howes"/> + </concept> + <concept> + <code value="application/vnd.chess-pgn" /> + <display value="vnd.chess-pgn" /> + <definition value="As defined by Kim Scarborough"/> + </concept> + <concept> + <code value="application/vnd.chipnuts.karaoke-mmd" /> + <display value="vnd.chipnuts.karaoke-mmd" /> + <definition value="As defined by Chunyun Xiong"/> + </concept> + <concept> + <code value="application/vnd.ciedi" /> + <display value="vnd.ciedi" /> + <definition value="As defined by Hidekazu Enjo"/> + </concept> + <concept> + <code value="application/vnd.cinderella" /> + <display value="vnd.cinderella" /> + <definition value="As defined by Ulrich Kortenkamp"/> + </concept> + <concept> + <code value="application/vnd.cirpack.isdn-ext" /> + <display value="vnd.cirpack.isdn-ext" /> + <definition value="As defined by Pascal Mayeux"/> + </concept> + <concept> + <code value="application/vnd.citationstyles.style+xml" /> + <display value="vnd.citationstyles.style+xml" /> + <definition value="As defined by Rintze M. Zelle"/> + </concept> + <concept> + <code value="application/vnd.claymore" /> + <display value="vnd.claymore" /> + <definition value="As defined by Ray Simpson"/> + </concept> + <concept> + <code value="application/vnd.cloanto.rp9" /> + <display value="vnd.cloanto.rp9" /> + <definition value="As defined by Mike Labatt"/> + </concept> + <concept> + <code value="application/vnd.clonk.c4group" /> + <display value="vnd.clonk.c4group" /> + <definition value="As defined by Guenther Brammer"/> + </concept> + <concept> + <code value="application/vnd.cluetrust.cartomobile-config" /> + <display value="vnd.cluetrust.cartomobile-config" /> + <definition value="As defined by Gaige Paulsen"/> + </concept> + <concept> + <code value="application/vnd.cluetrust.cartomobile-config-pkg" /> + <display value="vnd.cluetrust.cartomobile-config-pkg" /> + <definition value="As defined by Gaige Paulsen"/> + </concept> + <concept> + <code value="application/vnd.coffeescript" /> + <display value="vnd.coffeescript" /> + <definition value="As defined by Devyn Collier Johnson"/> + </concept> + <concept> + <code value="application/vnd.collabio.xodocuments.document" /> + <display value="vnd.collabio.xodocuments.document" /> + <definition value="As defined by Alexey Meandrov"/> + </concept> + <concept> + <code value="application/vnd.collabio.xodocuments.document-template" /> + <display value="vnd.collabio.xodocuments.document-template" /> + <definition value="As defined by Alexey Meandrov"/> + </concept> + <concept> + <code value="application/vnd.collabio.xodocuments.presentation" /> + <display value="vnd.collabio.xodocuments.presentation" /> + <definition value="As defined by Alexey Meandrov"/> + </concept> + <concept> + <code value="application/vnd.collabio.xodocuments.presentation-template" /> + <display value="vnd.collabio.xodocuments.presentation-template" /> + <definition value="As defined by Alexey Meandrov"/> + </concept> + <concept> + <code value="application/vnd.collabio.xodocuments.spreadsheet" /> + <display value="vnd.collabio.xodocuments.spreadsheet" /> + <definition value="As defined by Alexey Meandrov"/> + </concept> + <concept> + <code value="application/vnd.collabio.xodocuments.spreadsheet-template" /> + <display value="vnd.collabio.xodocuments.spreadsheet-template" /> + <definition value="As defined by Alexey Meandrov"/> + </concept> + <concept> + <code value="application/vnd.collection.doc+json" /> + <display value="vnd.collection.doc+json" /> + <definition value="As defined by Irakli Nadareishvili"/> + </concept> + <concept> + <code value="application/vnd.collection+json" /> + <display value="vnd.collection+json" /> + <definition value="As defined by Mike Amundsen"/> + </concept> + <concept> + <code value="application/vnd.collection.next+json" /> + <display value="vnd.collection.next+json" /> + <definition value="As defined by Ioseb Dzmanashvili"/> + </concept> + <concept> + <code value="application/vnd.comicbook-rar" /> + <display value="vnd.comicbook-rar" /> + <definition value="As defined by Kim Scarborough"/> + </concept> + <concept> + <code value="application/vnd.comicbook+zip" /> + <display value="vnd.comicbook+zip" /> + <definition value="As defined by Kim Scarborough"/> + </concept> + <concept> + <code value="application/vnd.commerce-battelle" /> + <display value="vnd.commerce-battelle" /> + <definition value="As defined by David Applebaum"/> + </concept> + <concept> + <code value="application/vnd.commonspace" /> + <display value="vnd.commonspace" /> + <definition value="As defined by Ravinder Chandhok"/> + </concept> + <concept> + <code value="application/vnd.coreos.ignition+json" /> + <display value="vnd.coreos.ignition+json" /> + <definition value="As defined by Alex Crawford"/> + </concept> + <concept> + <code value="application/vnd.cosmocaller" /> + <display value="vnd.cosmocaller" /> + <definition value="As defined by Steve Dellutri"/> + </concept> + <concept> + <code value="application/vnd.contact.cmsg" /> + <display value="vnd.contact.cmsg" /> + <definition value="As defined by Frank Patz"/> + </concept> + <concept> + <code value="application/vnd.crick.clicker" /> + <display value="vnd.crick.clicker" /> + <definition value="As defined by Andrew Burt"/> + </concept> + <concept> + <code value="application/vnd.crick.clicker.keyboard" /> + <display value="vnd.crick.clicker.keyboard" /> + <definition value="As defined by Andrew Burt"/> + </concept> + <concept> + <code value="application/vnd.crick.clicker.palette" /> + <display value="vnd.crick.clicker.palette" /> + <definition value="As defined by Andrew Burt"/> + </concept> + <concept> + <code value="application/vnd.crick.clicker.template" /> + <display value="vnd.crick.clicker.template" /> + <definition value="As defined by Andrew Burt"/> + </concept> + <concept> + <code value="application/vnd.crick.clicker.wordbank" /> + <display value="vnd.crick.clicker.wordbank" /> + <definition value="As defined by Andrew Burt"/> + </concept> + <concept> + <code value="application/vnd.criticaltools.wbs+xml" /> + <display value="vnd.criticaltools.wbs+xml" /> + <definition value="As defined by Jim Spiller"/> + </concept> + <concept> + <code value="application/vnd.cryptii.pipe+json" /> + <display value="vnd.cryptii.pipe+json" /> + <definition value="As defined by Fränz Friederes"/> + </concept> + <concept> + <code value="application/vnd.crypto-shade-file" /> + <display value="vnd.crypto-shade-file" /> + <definition value="As defined by Connor Horman"/> + </concept> + <concept> + <code value="application/vnd.ctc-posml" /> + <display value="vnd.ctc-posml" /> + <definition value="As defined by Bayard Kohlhepp"/> + </concept> + <concept> + <code value="application/vnd.ctct.ws+xml" /> + <display value="vnd.ctct.ws+xml" /> + <definition value="As defined by Jim Ancona"/> + </concept> + <concept> + <code value="application/vnd.cups-pdf" /> + <display value="vnd.cups-pdf" /> + <definition value="As defined by Michael Sweet"/> + </concept> + <concept> + <code value="application/vnd.cups-postscript" /> + <display value="vnd.cups-postscript" /> + <definition value="As defined by Michael Sweet"/> + </concept> + <concept> + <code value="application/vnd.cups-ppd" /> + <display value="vnd.cups-ppd" /> + <definition value="As defined by Michael Sweet"/> + </concept> + <concept> + <code value="application/vnd.cups-raster" /> + <display value="vnd.cups-raster" /> + <definition value="As defined by Michael Sweet"/> + </concept> + <concept> + <code value="application/vnd.cups-raw" /> + <display value="vnd.cups-raw" /> + <definition value="As defined by Michael Sweet"/> + </concept> + <concept> + <code value="application/vnd.curl" /> + <display value="vnd.curl" /> + <definition value="As defined by Robert Byrnes"/> + </concept> + <concept> + <code value="application/vnd.cyan.dean.root+xml" /> + <display value="vnd.cyan.dean.root+xml" /> + <definition value="As defined by Matt Kern"/> + </concept> + <concept> + <code value="application/vnd.cybank" /> + <display value="vnd.cybank" /> + <definition value="As defined by Nor Helmee"/> + </concept> + <concept> + <code value="application/vnd.d2l.coursepackage1p0+zip" /> + <display value="vnd.d2l.coursepackage1p0+zip" /> + <definition value="As defined by Viktor Haag"/> + </concept> + <concept> + <code value="application/vnd.dart" /> + <display value="vnd.dart" /> + <definition value="As defined by Anders Sandholm"/> + </concept> + <concept> + <code value="application/vnd.data-vision.rdz" /> + <display value="vnd.data-vision.rdz" /> + <definition value="As defined by James Fields"/> + </concept> + <concept> + <code value="application/vnd.datapackage+json" /> + <display value="vnd.datapackage+json" /> + <definition value="As defined by Paul Walsh"/> + </concept> + <concept> + <code value="application/vnd.dataresource+json" /> + <display value="vnd.dataresource+json" /> + <definition value="As defined by Paul Walsh"/> + </concept> + <concept> + <code value="application/vnd.dbf" /> + <display value="vnd.dbf" /> + <definition value="As defined by Mi Tar"/> + </concept> + <concept> + <code value="application/vnd.debian.binary-package" /> + <display value="vnd.debian.binary-package" /> + <definition value="As defined by Charles Plessy"/> + </concept> + <concept> + <code value="application/vnd.dece.data" /> + <display value="vnd.dece.data" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="application/vnd.dece.ttml+xml" /> + <display value="vnd.dece.ttml+xml" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="application/vnd.dece.unspecified" /> + <display value="vnd.dece.unspecified" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="application/vnd.dece.zip" /> + <display value="vnd.dece.zip" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="application/vnd.denovo.fcselayout-link" /> + <display value="vnd.denovo.fcselayout-link" /> + <definition value="As defined by Michael Dixon"/> + </concept> + <concept> + <code value="application/vnd.desmume.movie" /> + <display value="vnd.desmume.movie" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="application/vnd.dir-bi.plate-dl-nosuffix" /> + <display value="vnd.dir-bi.plate-dl-nosuffix" /> + <definition value="As defined by Yamanaka"/> + </concept> + <concept> + <code value="application/vnd.dm.delegation+xml" /> + <display value="vnd.dm.delegation+xml" /> + <definition value="As defined by Axel Ferrazzini"/> + </concept> + <concept> + <code value="application/vnd.dna" /> + <display value="vnd.dna" /> + <definition value="As defined by Meredith Searcy"/> + </concept> + <concept> + <code value="application/vnd.document+json" /> + <display value="vnd.document+json" /> + <definition value="As defined by Tom Christie"/> + </concept> + <concept> + <code value="application/vnd.dolby.mobile.1" /> + <display value="vnd.dolby.mobile.1" /> + <definition value="As defined by Steve Hattersley"/> + </concept> + <concept> + <code value="application/vnd.dolby.mobile.2" /> + <display value="vnd.dolby.mobile.2" /> + <definition value="As defined by Steve Hattersley"/> + </concept> + <concept> + <code value="application/vnd.doremir.scorecloud-binary-document" /> + <display value="vnd.doremir.scorecloud-binary-document" /> + <definition value="As defined by Erik Ronström"/> + </concept> + <concept> + <code value="application/vnd.dpgraph" /> + <display value="vnd.dpgraph" /> + <definition value="As defined by David Parker"/> + </concept> + <concept> + <code value="application/vnd.dreamfactory" /> + <display value="vnd.dreamfactory" /> + <definition value="As defined by William C. Appleton"/> + </concept> + <concept> + <code value="application/vnd.drive+json" /> + <display value="vnd.drive+json" /> + <definition value="As defined by Keith Kester"/> + </concept> + <concept> + <code value="application/vnd.dtg.local" /> + <display value="vnd.dtg.local" /> + <definition value="As defined by Ali Teffahi"/> + </concept> + <concept> + <code value="application/vnd.dtg.local.flash" /> + <display value="vnd.dtg.local.flash" /> + <definition value="As defined by Ali Teffahi"/> + </concept> + <concept> + <code value="application/vnd.dtg.local.html" /> + <display value="vnd.dtg.local.html" /> + <definition value="As defined by Ali Teffahi"/> + </concept> + <concept> + <code value="application/vnd.dvb.ait" /> + <display value="vnd.dvb.ait" /> + <definition value="As defined by Peter Siebert, and Michael Lagally"/> + </concept> + <concept> + <code value="application/vnd.dvb.dvbisl+xml" /> + <display value="vnd.dvb.dvbisl+xml" /> + <definition value="As defined by Emily DUBS"/> + </concept> + <concept> + <code value="application/vnd.dvb.dvbj" /> + <display value="vnd.dvb.dvbj" /> + <definition value="As defined by Peter Siebert, and Michael Lagally"/> + </concept> + <concept> + <code value="application/vnd.dvb.esgcontainer" /> + <display value="vnd.dvb.esgcontainer" /> + <definition value="As defined by Joerg Heuer"/> + </concept> + <concept> + <code value="application/vnd.dvb.ipdcdftnotifaccess" /> + <display value="vnd.dvb.ipdcdftnotifaccess" /> + <definition value="As defined by Roy Yue"/> + </concept> + <concept> + <code value="application/vnd.dvb.ipdcesgaccess" /> + <display value="vnd.dvb.ipdcesgaccess" /> + <definition value="As defined by Joerg Heuer"/> + </concept> + <concept> + <code value="application/vnd.dvb.ipdcesgaccess2" /> + <display value="vnd.dvb.ipdcesgaccess2" /> + <definition value="As defined by Jerome Marcon"/> + </concept> + <concept> + <code value="application/vnd.dvb.ipdcesgpdd" /> + <display value="vnd.dvb.ipdcesgpdd" /> + <definition value="As defined by Jerome Marcon"/> + </concept> + <concept> + <code value="application/vnd.dvb.ipdcroaming" /> + <display value="vnd.dvb.ipdcroaming" /> + <definition value="As defined by Yiling Xu"/> + </concept> + <concept> + <code value="application/vnd.dvb.iptv.alfec-base" /> + <display value="vnd.dvb.iptv.alfec-base" /> + <definition value="As defined by Jean-Baptiste Henry"/> + </concept> + <concept> + <code value="application/vnd.dvb.iptv.alfec-enhancement" /> + <display value="vnd.dvb.iptv.alfec-enhancement" /> + <definition value="As defined by Jean-Baptiste Henry"/> + </concept> + <concept> + <code value="application/vnd.dvb.notif-aggregate-root+xml" /> + <display value="vnd.dvb.notif-aggregate-root+xml" /> + <definition value="As defined by Roy Yue"/> + </concept> + <concept> + <code value="application/vnd.dvb.notif-container+xml" /> + <display value="vnd.dvb.notif-container+xml" /> + <definition value="As defined by Roy Yue"/> + </concept> + <concept> + <code value="application/vnd.dvb.notif-generic+xml" /> + <display value="vnd.dvb.notif-generic+xml" /> + <definition value="As defined by Roy Yue"/> + </concept> + <concept> + <code value="application/vnd.dvb.notif-ia-msglist+xml" /> + <display value="vnd.dvb.notif-ia-msglist+xml" /> + <definition value="As defined by Roy Yue"/> + </concept> + <concept> + <code value="application/vnd.dvb.notif-ia-registration-request+xml" /> + <display value="vnd.dvb.notif-ia-registration-request+xml" /> + <definition value="As defined by Roy Yue"/> + </concept> + <concept> + <code value="application/vnd.dvb.notif-ia-registration-response+xml" /> + <display value="vnd.dvb.notif-ia-registration-response+xml" /> + <definition value="As defined by Roy Yue"/> + </concept> + <concept> + <code value="application/vnd.dvb.notif-init+xml" /> + <display value="vnd.dvb.notif-init+xml" /> + <definition value="As defined by Roy Yue"/> + </concept> + <concept> + <code value="application/vnd.dvb.pfr" /> + <display value="vnd.dvb.pfr" /> + <definition value="As defined by Peter Siebert, and Michael Lagally"/> + </concept> + <concept> + <code value="application/vnd.dvb.service" /> + <display value="vnd.dvb.service" /> + <definition value="As defined by Peter Siebert, and Michael Lagally"/> + </concept> + <concept> + <code value="application/vnd.dxr" /> + <display value="vnd.dxr" /> + <definition value="As defined by Michael Duffy"/> + </concept> + <concept> + <code value="application/vnd.dynageo" /> + <display value="vnd.dynageo" /> + <definition value="As defined by Roland Mechling"/> + </concept> + <concept> + <code value="application/vnd.dzr" /> + <display value="vnd.dzr" /> + <definition value="As defined by Carl Anderson"/> + </concept> + <concept> + <code value="application/vnd.easykaraoke.cdgdownload" /> + <display value="vnd.easykaraoke.cdgdownload" /> + <definition value="As defined by Iain Downs"/> + </concept> + <concept> + <code value="application/vnd.ecip.rlp" /> + <display value="vnd.ecip.rlp" /> + <definition value="As defined by Wei Tang"/> + </concept> + <concept> + <code value="application/vnd.ecdis-update" /> + <display value="vnd.ecdis-update" /> + <definition value="As defined by Gert Buettgenbach"/> + </concept> + <concept> + <code value="application/vnd.ecowin.chart" /> + <display value="vnd.ecowin.chart" /> + <definition value="As defined by Thomas Olsson"/> + </concept> + <concept> + <code value="application/vnd.ecowin.filerequest" /> + <display value="vnd.ecowin.filerequest" /> + <definition value="As defined by Thomas Olsson"/> + </concept> + <concept> + <code value="application/vnd.ecowin.fileupdate" /> + <display value="vnd.ecowin.fileupdate" /> + <definition value="As defined by Thomas Olsson"/> + </concept> + <concept> + <code value="application/vnd.ecowin.series" /> + <display value="vnd.ecowin.series" /> + <definition value="As defined by Thomas Olsson"/> + </concept> + <concept> + <code value="application/vnd.ecowin.seriesrequest" /> + <display value="vnd.ecowin.seriesrequest" /> + <definition value="As defined by Thomas Olsson"/> + </concept> + <concept> + <code value="application/vnd.ecowin.seriesupdate" /> + <display value="vnd.ecowin.seriesupdate" /> + <definition value="As defined by Thomas Olsson"/> + </concept> + <concept> + <code value="application/vnd.efi.img" /> + <display value="vnd.efi.img" /> + <definition value="As defined by UEFI Forum, and Fu Siyuan"/> + </concept> + <concept> + <code value="application/vnd.efi.iso" /> + <display value="vnd.efi.iso" /> + <definition value="As defined by UEFI Forum, and Fu Siyuan"/> + </concept> + <concept> + <code value="application/vnd.emclient.accessrequest+xml" /> + <display value="vnd.emclient.accessrequest+xml" /> + <definition value="As defined by Filip Navara"/> + </concept> + <concept> + <code value="application/vnd.enliven" /> + <display value="vnd.enliven" /> + <definition value="As defined by Paul Santinelli Jr."/> + </concept> + <concept> + <code value="application/vnd.enphase.envoy" /> + <display value="vnd.enphase.envoy" /> + <definition value="As defined by Chris Eich"/> + </concept> + <concept> + <code value="application/vnd.eprints.data+xml" /> + <display value="vnd.eprints.data+xml" /> + <definition value="As defined by Tim Brody"/> + </concept> + <concept> + <code value="application/vnd.epson.esf" /> + <display value="vnd.epson.esf" /> + <definition value="As defined by Shoji Hoshina"/> + </concept> + <concept> + <code value="application/vnd.epson.msf" /> + <display value="vnd.epson.msf" /> + <definition value="As defined by Shoji Hoshina"/> + </concept> + <concept> + <code value="application/vnd.epson.quickanime" /> + <display value="vnd.epson.quickanime" /> + <definition value="As defined by Yu Gu"/> + </concept> + <concept> + <code value="application/vnd.epson.salt" /> + <display value="vnd.epson.salt" /> + <definition value="As defined by Yasuhito Nagatomo"/> + </concept> + <concept> + <code value="application/vnd.epson.ssf" /> + <display value="vnd.epson.ssf" /> + <definition value="As defined by Shoji Hoshina"/> + </concept> + <concept> + <code value="application/vnd.ericsson.quickcall" /> + <display value="vnd.ericsson.quickcall" /> + <definition value="As defined by Paul Tidwell"/> + </concept> + <concept> + <code value="application/vnd.espass-espass+zip" /> + <display value="vnd.espass-espass+zip" /> + <definition value="As defined by Marcus Ligi Büschleb"/> + </concept> + <concept> + <code value="application/vnd.eszigno3+xml" /> + <display value="vnd.eszigno3+xml" /> + <definition value="As defined by Szilveszter Tóth"/> + </concept> + <concept> + <code value="application/vnd.etsi.aoc+xml" /> + <display value="vnd.etsi.aoc+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.asic-s+zip" /> + <display value="vnd.etsi.asic-s+zip" /> + <definition value="As defined by Miguel Angel Reina Ortega"/> + </concept> + <concept> + <code value="application/vnd.etsi.asic-e+zip" /> + <display value="vnd.etsi.asic-e+zip" /> + <definition value="As defined by Miguel Angel Reina Ortega"/> + </concept> + <concept> + <code value="application/vnd.etsi.cug+xml" /> + <display value="vnd.etsi.cug+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.iptvcommand+xml" /> + <display value="vnd.etsi.iptvcommand+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.iptvdiscovery+xml" /> + <display value="vnd.etsi.iptvdiscovery+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.iptvprofile+xml" /> + <display value="vnd.etsi.iptvprofile+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.iptvsad-bc+xml" /> + <display value="vnd.etsi.iptvsad-bc+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.iptvsad-cod+xml" /> + <display value="vnd.etsi.iptvsad-cod+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.iptvsad-npvr+xml" /> + <display value="vnd.etsi.iptvsad-npvr+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.iptvservice+xml" /> + <display value="vnd.etsi.iptvservice+xml" /> + <definition value="As defined by Miguel Angel Reina Ortega"/> + </concept> + <concept> + <code value="application/vnd.etsi.iptvsync+xml" /> + <display value="vnd.etsi.iptvsync+xml" /> + <definition value="As defined by Miguel Angel Reina Ortega"/> + </concept> + <concept> + <code value="application/vnd.etsi.iptvueprofile+xml" /> + <display value="vnd.etsi.iptvueprofile+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.mcid+xml" /> + <display value="vnd.etsi.mcid+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.mheg5" /> + <display value="vnd.etsi.mheg5" /> + <definition value="As defined by Miguel Angel Reina Ortega, and Ian Medland"/> + </concept> + <concept> + <code value="application/vnd.etsi.overload-control-policy-dataset+xml" /> + <display value="vnd.etsi.overload-control-policy-dataset+xml" /> + <definition value="As defined by Miguel Angel Reina Ortega"/> + </concept> + <concept> + <code value="application/vnd.etsi.pstn+xml" /> + <display value="vnd.etsi.pstn+xml" /> + <definition value="As defined by Jiwan Han, and Thomas Belling"/> + </concept> + <concept> + <code value="application/vnd.etsi.sci+xml" /> + <display value="vnd.etsi.sci+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.simservs+xml" /> + <display value="vnd.etsi.simservs+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.timestamp-token" /> + <display value="vnd.etsi.timestamp-token" /> + <definition value="As defined by Miguel Angel Reina Ortega"/> + </concept> + <concept> + <code value="application/vnd.etsi.tsl+xml" /> + <display value="vnd.etsi.tsl+xml" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.etsi.tsl.der" /> + <display value="vnd.etsi.tsl.der" /> + <definition value="As defined by Shicheng Hu"/> + </concept> + <concept> + <code value="application/vnd.evolv.ecig.profile" /> + <display value="vnd.evolv.ecig.profile" /> + <definition value="As defined by James Bellinger"/> + </concept> + <concept> + <code value="application/vnd.evolv.ecig.settings" /> + <display value="vnd.evolv.ecig.settings" /> + <definition value="As defined by James Bellinger"/> + </concept> + <concept> + <code value="application/vnd.evolv.ecig.theme" /> + <display value="vnd.evolv.ecig.theme" /> + <definition value="As defined by James Bellinger"/> + </concept> + <concept> + <code value="application/vnd.eudora.data" /> + <display value="vnd.eudora.data" /> + <definition value="As defined by Pete Resnick"/> + </concept> + <concept> + <code value="application/vnd.exstream-empower+zip" /> + <display value="vnd.exstream-empower+zip" /> + <definition value="As defined by Bill Kidwell"/> + </concept> + <concept> + <code value="application/vnd.exstream-package" /> + <display value="vnd.exstream-package" /> + <definition value="As defined by Bill Kidwell"/> + </concept> + <concept> + <code value="application/vnd.ezpix-album" /> + <display value="vnd.ezpix-album" /> + <definition value="As defined by ElectronicZombieCorp"/> + </concept> + <concept> + <code value="application/vnd.ezpix-package" /> + <display value="vnd.ezpix-package" /> + <definition value="As defined by ElectronicZombieCorp"/> + </concept> + <concept> + <code value="application/vnd.f-secure.mobile" /> + <display value="vnd.f-secure.mobile" /> + <definition value="As defined by Samu Sarivaara"/> + </concept> + <concept> + <code value="application/vnd.fastcopy-disk-image" /> + <display value="vnd.fastcopy-disk-image" /> + <definition value="As defined by Thomas Huth"/> + </concept> + <concept> + <code value="application/vnd.fdf" /> + <display value="vnd.fdf" /> + <definition value="As defined by Steve Zilles"/> + </concept> + <concept> + <code value="application/vnd.fdsn.mseed" /> + <display value="vnd.fdsn.mseed" /> + <definition value="As defined by Chad Trabant"/> + </concept> + <concept> + <code value="application/vnd.fdsn.seed" /> + <display value="vnd.fdsn.seed" /> + <definition value="As defined by Chad Trabant"/> + </concept> + <concept> + <code value="application/vnd.ffsns" /> + <display value="vnd.ffsns" /> + <definition value="As defined by Holstage"/> + </concept> + <concept> + <code value="application/vnd.ficlab.flb+zip" /> + <display value="vnd.ficlab.flb+zip" /> + <definition value="As defined by Steve Gilberd"/> + </concept> + <concept> + <code value="application/vnd.filmit.zfc" /> + <display value="vnd.filmit.zfc" /> + <definition value="As defined by Harms Moeller"/> + </concept> + <concept> + <code value="application/vnd.fints" /> + <display value="vnd.fints" /> + <definition value="As defined by Ingo Hammann"/> + </concept> + <concept> + <code value="application/vnd.firemonkeys.cloudcell" /> + <display value="vnd.firemonkeys.cloudcell" /> + <definition value="As defined by Alex Dubov"/> + </concept> + <concept> + <code value="application/vnd.FloGraphIt" /> + <display value="vnd.FloGraphIt" /> + <definition value="As defined by Dick Floersch"/> + </concept> + <concept> + <code value="application/vnd.fluxtime.clip" /> + <display value="vnd.fluxtime.clip" /> + <definition value="As defined by Marc Winter"/> + </concept> + <concept> + <code value="application/vnd.font-fontforge-sfd" /> + <display value="vnd.font-fontforge-sfd" /> + <definition value="As defined by George Williams"/> + </concept> + <concept> + <code value="application/vnd.framemaker" /> + <display value="vnd.framemaker" /> + <definition value="As defined by Mike Wexler"/> + </concept> + <concept> + <code value="application/vnd.fsc.weblaunch" /> + <display value="vnd.fsc.weblaunch" /> + <definition value="As defined by Derek Smith"/> + </concept> + <concept> + <code value="application/vnd.fujitsu.oasys" /> + <display value="vnd.fujitsu.oasys" /> + <definition value="As defined by Nobukazu Togashi"/> + </concept> + <concept> + <code value="application/vnd.fujitsu.oasys2" /> + <display value="vnd.fujitsu.oasys2" /> + <definition value="As defined by Nobukazu Togashi"/> + </concept> + <concept> + <code value="application/vnd.fujitsu.oasys3" /> + <display value="vnd.fujitsu.oasys3" /> + <definition value="As defined by Seiji Okudaira"/> + </concept> + <concept> + <code value="application/vnd.fujitsu.oasysgp" /> + <display value="vnd.fujitsu.oasysgp" /> + <definition value="As defined by Masahiko Sugimoto"/> + </concept> + <concept> + <code value="application/vnd.fujitsu.oasysprs" /> + <display value="vnd.fujitsu.oasysprs" /> + <definition value="As defined by Masumi Ogita"/> + </concept> + <concept> + <code value="application/vnd.fujixerox.ART4" /> + <display value="vnd.fujixerox.ART4" /> + <definition value="As defined by Fumio Tanabe"/> + </concept> + <concept> + <code value="application/vnd.fujixerox.ART-EX" /> + <display value="vnd.fujixerox.ART-EX" /> + <definition value="As defined by Fumio Tanabe"/> + </concept> + <concept> + <code value="application/vnd.fujixerox.ddd" /> + <display value="vnd.fujixerox.ddd" /> + <definition value="As defined by Masanori Onda"/> + </concept> + <concept> + <code value="application/vnd.fujixerox.docuworks" /> + <display value="vnd.fujixerox.docuworks" /> + <definition value="As defined by Takatomo Wakibayashi"/> + </concept> + <concept> + <code value="application/vnd.fujixerox.docuworks.binder" /> + <display value="vnd.fujixerox.docuworks.binder" /> + <definition value="As defined by Takashi Matsumoto"/> + </concept> + <concept> + <code value="application/vnd.fujixerox.docuworks.container" /> + <display value="vnd.fujixerox.docuworks.container" /> + <definition value="As defined by Kiyoshi Tashiro"/> + </concept> + <concept> + <code value="application/vnd.fujixerox.HBPL" /> + <display value="vnd.fujixerox.HBPL" /> + <definition value="As defined by Fumio Tanabe"/> + </concept> + <concept> + <code value="application/vnd.fut-misnet" /> + <display value="vnd.fut-misnet" /> + <definition value="As defined by Jann Pruulman"/> + </concept> + <concept> + <code value="application/vnd.futoin+cbor" /> + <display value="vnd.futoin+cbor" /> + <definition value="As defined by Andrey Galkin"/> + </concept> + <concept> + <code value="application/vnd.futoin+json" /> + <display value="vnd.futoin+json" /> + <definition value="As defined by Andrey Galkin"/> + </concept> + <concept> + <code value="application/vnd.fuzzysheet" /> + <display value="vnd.fuzzysheet" /> + <definition value="As defined by Simon Birtwistle"/> + </concept> + <concept> + <code value="application/vnd.genomatix.tuxedo" /> + <display value="vnd.genomatix.tuxedo" /> + <definition value="As defined by Torben Frey"/> + </concept> + <concept> + <code value="application/vnd.gentics.grd+json" /> + <display value="vnd.gentics.grd+json" /> + <definition value="As defined by Philipp Gortan"/> + </concept> + <concept> + <code value="application/vnd.geogebra.file" /> + <display value="vnd.geogebra.file" /> + <definition value="As defined by GeoGebra, and Yves Kreis"/> + </concept> + <concept> + <code value="application/vnd.geogebra.tool" /> + <display value="vnd.geogebra.tool" /> + <definition value="As defined by GeoGebra, and Yves Kreis"/> + </concept> + <concept> + <code value="application/vnd.geometry-explorer" /> + <display value="vnd.geometry-explorer" /> + <definition value="As defined by Michael Hvidsten"/> + </concept> + <concept> + <code value="application/vnd.geonext" /> + <display value="vnd.geonext" /> + <definition value="As defined by Matthias Ehmann"/> + </concept> + <concept> + <code value="application/vnd.geoplan" /> + <display value="vnd.geoplan" /> + <definition value="As defined by Christian Mercat"/> + </concept> + <concept> + <code value="application/vnd.geospace" /> + <display value="vnd.geospace" /> + <definition value="As defined by Christian Mercat"/> + </concept> + <concept> + <code value="application/vnd.gerber" /> + <display value="vnd.gerber" /> + <definition value="As defined by Thomas Weyn"/> + </concept> + <concept> + <code value="application/vnd.globalplatform.card-content-mgt" /> + <display value="vnd.globalplatform.card-content-mgt" /> + <definition value="As defined by Gil Bernabeu"/> + </concept> + <concept> + <code value="application/vnd.globalplatform.card-content-mgt-response" /> + <display value="vnd.globalplatform.card-content-mgt-response" /> + <definition value="As defined by Gil Bernabeu"/> + </concept> + <concept> + <code value="application/vnd.gmx - DEPRECATED" /> + <display value="vnd.gmx - DEPRECATED" /> + <definition value="As defined by Christian V. Sciberras"/> + </concept> + <concept> + <code value="application/vnd.google-earth.kml+xml" /> + <display value="vnd.google-earth.kml+xml" /> + <definition value="As defined by Michael Ashbridge"/> + </concept> + <concept> + <code value="application/vnd.google-earth.kmz" /> + <display value="vnd.google-earth.kmz" /> + <definition value="As defined by Michael Ashbridge"/> + </concept> + <concept> + <code value="application/vnd.gov.sk.e-form+xml" /> + <display value="vnd.gov.sk.e-form+xml" /> + <definition value="As defined by Peter Biro, and Stefan Szilva"/> + </concept> + <concept> + <code value="application/vnd.gov.sk.e-form+zip" /> + <display value="vnd.gov.sk.e-form+zip" /> + <definition value="As defined by Peter Biro, and Stefan Szilva"/> + </concept> + <concept> + <code value="application/vnd.gov.sk.xmldatacontainer+xml" /> + <display value="vnd.gov.sk.xmldatacontainer+xml" /> + <definition value="As defined by Peter Biro, and Stefan Szilva"/> + </concept> + <concept> + <code value="application/vnd.grafeq" /> + <display value="vnd.grafeq" /> + <definition value="As defined by Jeff Tupper"/> + </concept> + <concept> + <code value="application/vnd.gridmp" /> + <display value="vnd.gridmp" /> + <definition value="As defined by Jeff Lawson"/> + </concept> + <concept> + <code value="application/vnd.groove-account" /> + <display value="vnd.groove-account" /> + <definition value="As defined by Todd Joseph"/> + </concept> + <concept> + <code value="application/vnd.groove-help" /> + <display value="vnd.groove-help" /> + <definition value="As defined by Todd Joseph"/> + </concept> + <concept> + <code value="application/vnd.groove-identity-message" /> + <display value="vnd.groove-identity-message" /> + <definition value="As defined by Todd Joseph"/> + </concept> + <concept> + <code value="application/vnd.groove-injector" /> + <display value="vnd.groove-injector" /> + <definition value="As defined by Todd Joseph"/> + </concept> + <concept> + <code value="application/vnd.groove-tool-message" /> + <display value="vnd.groove-tool-message" /> + <definition value="As defined by Todd Joseph"/> + </concept> + <concept> + <code value="application/vnd.groove-tool-template" /> + <display value="vnd.groove-tool-template" /> + <definition value="As defined by Todd Joseph"/> + </concept> + <concept> + <code value="application/vnd.groove-vcard" /> + <display value="vnd.groove-vcard" /> + <definition value="As defined by Todd Joseph"/> + </concept> + <concept> + <code value="application/vnd.hal+json" /> + <display value="vnd.hal+json" /> + <definition value="As defined by Mike Kelly"/> + </concept> + <concept> + <code value="application/vnd.hal+xml" /> + <display value="vnd.hal+xml" /> + <definition value="As defined by Mike Kelly"/> + </concept> + <concept> + <code value="application/vnd.HandHeld-Entertainment+xml" /> + <display value="vnd.HandHeld-Entertainment+xml" /> + <definition value="As defined by Eric Hamilton"/> + </concept> + <concept> + <code value="application/vnd.hbci" /> + <display value="vnd.hbci" /> + <definition value="As defined by Ingo Hammann"/> + </concept> + <concept> + <code value="application/vnd.hc+json" /> + <display value="vnd.hc+json" /> + <definition value="As defined by Jan Schütze"/> + </concept> + <concept> + <code value="application/vnd.hcl-bireports" /> + <display value="vnd.hcl-bireports" /> + <definition value="As defined by Doug R. Serres"/> + </concept> + <concept> + <code value="application/vnd.hdt" /> + <display value="vnd.hdt" /> + <definition value="As defined by Javier D. Fernández"/> + </concept> + <concept> + <code value="application/vnd.heroku+json" /> + <display value="vnd.heroku+json" /> + <definition value="As defined by Wesley Beary"/> + </concept> + <concept> + <code value="application/vnd.hhe.lesson-player" /> + <display value="vnd.hhe.lesson-player" /> + <definition value="As defined by Randy Jones"/> + </concept> + <concept> + <code value="application/vnd.hp-HPGL" /> + <display value="vnd.hp-HPGL" /> + <definition value="As defined by Bob Pentecost"/> + </concept> + <concept> + <code value="application/vnd.hp-hpid" /> + <display value="vnd.hp-hpid" /> + <definition value="As defined by Aloke Gupta"/> + </concept> + <concept> + <code value="application/vnd.hp-hps" /> + <display value="vnd.hp-hps" /> + <definition value="As defined by Steve Aubrey"/> + </concept> + <concept> + <code value="application/vnd.hp-jlyt" /> + <display value="vnd.hp-jlyt" /> + <definition value="As defined by Amir Gaash"/> + </concept> + <concept> + <code value="application/vnd.hp-PCL" /> + <display value="vnd.hp-PCL" /> + <definition value="As defined by Bob Pentecost"/> + </concept> + <concept> + <code value="application/vnd.hp-PCLXL" /> + <display value="vnd.hp-PCLXL" /> + <definition value="As defined by Bob Pentecost"/> + </concept> + <concept> + <code value="application/vnd.httphone" /> + <display value="vnd.httphone" /> + <definition value="As defined by Franck Lefevre"/> + </concept> + <concept> + <code value="application/vnd.hydrostatix.sof-data" /> + <display value="vnd.hydrostatix.sof-data" /> + <definition value="As defined by Allen Gillam"/> + </concept> + <concept> + <code value="application/vnd.hyper-item+json" /> + <display value="vnd.hyper-item+json" /> + <definition value="As defined by Mario Demuth"/> + </concept> + <concept> + <code value="application/vnd.hyper+json" /> + <display value="vnd.hyper+json" /> + <definition value="As defined by Irakli Nadareishvili"/> + </concept> + <concept> + <code value="application/vnd.hyperdrive+json" /> + <display value="vnd.hyperdrive+json" /> + <definition value="As defined by Daniel Sims"/> + </concept> + <concept> + <code value="application/vnd.hzn-3d-crossword" /> + <display value="vnd.hzn-3d-crossword" /> + <definition value="As defined by James Minnis"/> + </concept> + <concept> + <code value="application/vnd.ibm.electronic-media" /> + <display value="vnd.ibm.electronic-media" /> + <definition value="As defined by Bruce Tantlinger"/> + </concept> + <concept> + <code value="application/vnd.ibm.MiniPay" /> + <display value="vnd.ibm.MiniPay" /> + <definition value="As defined by Amir Herzberg"/> + </concept> + <concept> + <code value="application/vnd.ibm.rights-management" /> + <display value="vnd.ibm.rights-management" /> + <definition value="As defined by Bruce Tantlinger"/> + </concept> + <concept> + <code value="application/vnd.ibm.secure-container" /> + <display value="vnd.ibm.secure-container" /> + <definition value="As defined by Bruce Tantlinger"/> + </concept> + <concept> + <code value="application/vnd.iccprofile" /> + <display value="vnd.iccprofile" /> + <definition value="As defined by Phil Green"/> + </concept> + <concept> + <code value="application/vnd.ieee.1905" /> + <display value="vnd.ieee.1905" /> + <definition value="As defined by Purva R Rajkotia"/> + </concept> + <concept> + <code value="application/vnd.igloader" /> + <display value="vnd.igloader" /> + <definition value="As defined by Tim Fisher"/> + </concept> + <concept> + <code value="application/vnd.imagemeter.folder+zip" /> + <display value="vnd.imagemeter.folder+zip" /> + <definition value="As defined by Dirk Farin"/> + </concept> + <concept> + <code value="application/vnd.imagemeter.image+zip" /> + <display value="vnd.imagemeter.image+zip" /> + <definition value="As defined by Dirk Farin"/> + </concept> + <concept> + <code value="application/vnd.immervision-ivp" /> + <display value="vnd.immervision-ivp" /> + <definition value="As defined by Mathieu Villegas"/> + </concept> + <concept> + <code value="application/vnd.immervision-ivu" /> + <display value="vnd.immervision-ivu" /> + <definition value="As defined by Mathieu Villegas"/> + </concept> + <concept> + <code value="application/vnd.ims.imsccv1p1" /> + <display value="vnd.ims.imsccv1p1" /> + <definition value="As defined by Lisa Mattson"/> + </concept> + <concept> + <code value="application/vnd.ims.imsccv1p2" /> + <display value="vnd.ims.imsccv1p2" /> + <definition value="As defined by Lisa Mattson"/> + </concept> + <concept> + <code value="application/vnd.ims.imsccv1p3" /> + <display value="vnd.ims.imsccv1p3" /> + <definition value="As defined by Lisa Mattson"/> + </concept> + <concept> + <code value="application/vnd.ims.lis.v2.result+json" /> + <display value="vnd.ims.lis.v2.result+json" /> + <definition value="As defined by Lisa Mattson"/> + </concept> + <concept> + <code value="application/vnd.ims.lti.v2.toolconsumerprofile+json" /> + <display value="vnd.ims.lti.v2.toolconsumerprofile+json" /> + <definition value="As defined by Lisa Mattson"/> + </concept> + <concept> + <code value="application/vnd.ims.lti.v2.toolproxy.id+json" /> + <display value="vnd.ims.lti.v2.toolproxy.id+json" /> + <definition value="As defined by Lisa Mattson"/> + </concept> + <concept> + <code value="application/vnd.ims.lti.v2.toolproxy+json" /> + <display value="vnd.ims.lti.v2.toolproxy+json" /> + <definition value="As defined by Lisa Mattson"/> + </concept> + <concept> + <code value="application/vnd.ims.lti.v2.toolsettings+json" /> + <display value="vnd.ims.lti.v2.toolsettings+json" /> + <definition value="As defined by Lisa Mattson"/> + </concept> + <concept> + <code value="application/vnd.ims.lti.v2.toolsettings.simple+json" /> + <display value="vnd.ims.lti.v2.toolsettings.simple+json" /> + <definition value="As defined by Lisa Mattson"/> + </concept> + <concept> + <code value="application/vnd.informedcontrol.rms+xml" /> + <display value="vnd.informedcontrol.rms+xml" /> + <definition value="As defined by Mark Wahl"/> + </concept> + <concept> + <code value="application/vnd.infotech.project" /> + <display value="vnd.infotech.project" /> + <definition value="As defined by Charles Engelke"/> + </concept> + <concept> + <code value="application/vnd.infotech.project+xml" /> + <display value="vnd.infotech.project+xml" /> + <definition value="As defined by Charles Engelke"/> + </concept> + <concept> + <code value="application/vnd.innopath.wamp.notification" /> + <display value="vnd.innopath.wamp.notification" /> + <definition value="As defined by Takanori Sudo"/> + </concept> + <concept> + <code value="application/vnd.insors.igm" /> + <display value="vnd.insors.igm" /> + <definition value="As defined by Jon Swanson"/> + </concept> + <concept> + <code value="application/vnd.intercon.formnet" /> + <display value="vnd.intercon.formnet" /> + <definition value="As defined by Tom Gurak"/> + </concept> + <concept> + <code value="application/vnd.intergeo" /> + <display value="vnd.intergeo" /> + <definition value="As defined by Yves Kreis 2"/> + </concept> + <concept> + <code value="application/vnd.intertrust.digibox" /> + <display value="vnd.intertrust.digibox" /> + <definition value="As defined by Luke Tomasello"/> + </concept> + <concept> + <code value="application/vnd.intertrust.nncp" /> + <display value="vnd.intertrust.nncp" /> + <definition value="As defined by Luke Tomasello"/> + </concept> + <concept> + <code value="application/vnd.intu.qbo" /> + <display value="vnd.intu.qbo" /> + <definition value="As defined by Greg Scratchley"/> + </concept> + <concept> + <code value="application/vnd.intu.qfx" /> + <display value="vnd.intu.qfx" /> + <definition value="As defined by Greg Scratchley"/> + </concept> + <concept> + <code value="application/vnd.iptc.g2.catalogitem+xml" /> + <display value="vnd.iptc.g2.catalogitem+xml" /> + <definition value="As defined by Michael Steidl"/> + </concept> + <concept> + <code value="application/vnd.iptc.g2.conceptitem+xml" /> + <display value="vnd.iptc.g2.conceptitem+xml" /> + <definition value="As defined by Michael Steidl"/> + </concept> + <concept> + <code value="application/vnd.iptc.g2.knowledgeitem+xml" /> + <display value="vnd.iptc.g2.knowledgeitem+xml" /> + <definition value="As defined by Michael Steidl"/> + </concept> + <concept> + <code value="application/vnd.iptc.g2.newsitem+xml" /> + <display value="vnd.iptc.g2.newsitem+xml" /> + <definition value="As defined by Michael Steidl"/> + </concept> + <concept> + <code value="application/vnd.iptc.g2.newsmessage+xml" /> + <display value="vnd.iptc.g2.newsmessage+xml" /> + <definition value="As defined by Michael Steidl"/> + </concept> + <concept> + <code value="application/vnd.iptc.g2.packageitem+xml" /> + <display value="vnd.iptc.g2.packageitem+xml" /> + <definition value="As defined by Michael Steidl"/> + </concept> + <concept> + <code value="application/vnd.iptc.g2.planningitem+xml" /> + <display value="vnd.iptc.g2.planningitem+xml" /> + <definition value="As defined by Michael Steidl"/> + </concept> + <concept> + <code value="application/vnd.ipunplugged.rcprofile" /> + <display value="vnd.ipunplugged.rcprofile" /> + <definition value="As defined by Per Ersson"/> + </concept> + <concept> + <code value="application/vnd.irepository.package+xml" /> + <display value="vnd.irepository.package+xml" /> + <definition value="As defined by Martin Knowles"/> + </concept> + <concept> + <code value="application/vnd.is-xpr" /> + <display value="vnd.is-xpr" /> + <definition value="As defined by Satish Navarajan"/> + </concept> + <concept> + <code value="application/vnd.isac.fcs" /> + <display value="vnd.isac.fcs" /> + <definition value="As defined by Ryan Brinkman"/> + </concept> + <concept> + <code value="application/vnd.jam" /> + <display value="vnd.jam" /> + <definition value="As defined by Brijesh Kumar"/> + </concept> + <concept> + <code value="application/vnd.iso11783-10+zip" /> + <display value="vnd.iso11783-10+zip" /> + <definition value="As defined by Frank Wiebeler"/> + </concept> + <concept> + <code value="application/vnd.japannet-directory-service" /> + <display value="vnd.japannet-directory-service" /> + <definition value="As defined by Kiyofusa Fujii"/> + </concept> + <concept> + <code value="application/vnd.japannet-jpnstore-wakeup" /> + <display value="vnd.japannet-jpnstore-wakeup" /> + <definition value="As defined by Jun Yoshitake"/> + </concept> + <concept> + <code value="application/vnd.japannet-payment-wakeup" /> + <display value="vnd.japannet-payment-wakeup" /> + <definition value="As defined by Kiyofusa Fujii"/> + </concept> + <concept> + <code value="application/vnd.japannet-registration" /> + <display value="vnd.japannet-registration" /> + <definition value="As defined by Jun Yoshitake"/> + </concept> + <concept> + <code value="application/vnd.japannet-registration-wakeup" /> + <display value="vnd.japannet-registration-wakeup" /> + <definition value="As defined by Kiyofusa Fujii"/> + </concept> + <concept> + <code value="application/vnd.japannet-setstore-wakeup" /> + <display value="vnd.japannet-setstore-wakeup" /> + <definition value="As defined by Jun Yoshitake"/> + </concept> + <concept> + <code value="application/vnd.japannet-verification" /> + <display value="vnd.japannet-verification" /> + <definition value="As defined by Jun Yoshitake"/> + </concept> + <concept> + <code value="application/vnd.japannet-verification-wakeup" /> + <display value="vnd.japannet-verification-wakeup" /> + <definition value="As defined by Kiyofusa Fujii"/> + </concept> + <concept> + <code value="application/vnd.jcp.javame.midlet-rms" /> + <display value="vnd.jcp.javame.midlet-rms" /> + <definition value="As defined by Mikhail Gorshenev"/> + </concept> + <concept> + <code value="application/vnd.jisp" /> + <display value="vnd.jisp" /> + <definition value="As defined by Sebastiaan Deckers"/> + </concept> + <concept> + <code value="application/vnd.joost.joda-archive" /> + <display value="vnd.joost.joda-archive" /> + <definition value="As defined by Joost"/> + </concept> + <concept> + <code value="application/vnd.jsk.isdn-ngn" /> + <display value="vnd.jsk.isdn-ngn" /> + <definition value="As defined by Yokoyama Kiyonobu"/> + </concept> + <concept> + <code value="application/vnd.kahootz" /> + <display value="vnd.kahootz" /> + <definition value="As defined by Tim Macdonald"/> + </concept> + <concept> + <code value="application/vnd.kde.karbon" /> + <display value="vnd.kde.karbon" /> + <definition value="As defined by David Faure"/> + </concept> + <concept> + <code value="application/vnd.kde.kchart" /> + <display value="vnd.kde.kchart" /> + <definition value="As defined by David Faure"/> + </concept> + <concept> + <code value="application/vnd.kde.kformula" /> + <display value="vnd.kde.kformula" /> + <definition value="As defined by David Faure"/> + </concept> + <concept> + <code value="application/vnd.kde.kivio" /> + <display value="vnd.kde.kivio" /> + <definition value="As defined by David Faure"/> + </concept> + <concept> + <code value="application/vnd.kde.kontour" /> + <display value="vnd.kde.kontour" /> + <definition value="As defined by David Faure"/> + </concept> + <concept> + <code value="application/vnd.kde.kpresenter" /> + <display value="vnd.kde.kpresenter" /> + <definition value="As defined by David Faure"/> + </concept> + <concept> + <code value="application/vnd.kde.kspread" /> + <display value="vnd.kde.kspread" /> + <definition value="As defined by David Faure"/> + </concept> + <concept> + <code value="application/vnd.kde.kword" /> + <display value="vnd.kde.kword" /> + <definition value="As defined by David Faure"/> + </concept> + <concept> + <code value="application/vnd.kenameaapp" /> + <display value="vnd.kenameaapp" /> + <definition value="As defined by Dirk DiGiorgio-Haag"/> + </concept> + <concept> + <code value="application/vnd.kidspiration" /> + <display value="vnd.kidspiration" /> + <definition value="As defined by Jack Bennett"/> + </concept> + <concept> + <code value="application/vnd.Kinar" /> + <display value="vnd.Kinar" /> + <definition value="As defined by Hemant Thakkar"/> + </concept> + <concept> + <code value="application/vnd.koan" /> + <display value="vnd.koan" /> + <definition value="As defined by Pete Cole"/> + </concept> + <concept> + <code value="application/vnd.kodak-descriptor" /> + <display value="vnd.kodak-descriptor" /> + <definition value="As defined by Michael J. Donahue"/> + </concept> + <concept> + <code value="application/vnd.las" /> + <display value="vnd.las" /> + <definition value="As defined by NCGIS, and Bryan Blank"/> + </concept> + <concept> + <code value="application/vnd.las.las+json" /> + <display value="vnd.las.las+json" /> + <definition value="As defined by Rob Bailey"/> + </concept> + <concept> + <code value="application/vnd.las.las+xml" /> + <display value="vnd.las.las+xml" /> + <definition value="As defined by Rob Bailey"/> + </concept> + <concept> + <code value="application/vnd.laszip" /> + <display value="vnd.laszip" /> + <definition value="As defined by NCGIS, and Bryan Blank"/> + </concept> + <concept> + <code value="application/vnd.leap+json" /> + <display value="vnd.leap+json" /> + <definition value="As defined by Mark C Fralick"/> + </concept> + <concept> + <code value="application/vnd.liberty-request+xml" /> + <display value="vnd.liberty-request+xml" /> + <definition value="As defined by Brett McDowell"/> + </concept> + <concept> + <code value="application/vnd.llamagraphics.life-balance.desktop" /> + <display value="vnd.llamagraphics.life-balance.desktop" /> + <definition value="As defined by Catherine E. White"/> + </concept> + <concept> + <code value="application/vnd.llamagraphics.life-balance.exchange+xml" /> + <display value="vnd.llamagraphics.life-balance.exchange+xml" /> + <definition value="As defined by Catherine E. White"/> + </concept> + <concept> + <code value="application/vnd.logipipe.circuit+zip" /> + <display value="vnd.logipipe.circuit+zip" /> + <definition value="As defined by Victor Kuchynsky"/> + </concept> + <concept> + <code value="application/vnd.loom" /> + <display value="vnd.loom" /> + <definition value="As defined by Sten Linnarsson"/> + </concept> + <concept> + <code value="application/vnd.lotus-1-2-3" /> + <display value="vnd.lotus-1-2-3" /> + <definition value="As defined by Paul Wattenberger"/> + </concept> + <concept> + <code value="application/vnd.lotus-approach" /> + <display value="vnd.lotus-approach" /> + <definition value="As defined by Paul Wattenberger"/> + </concept> + <concept> + <code value="application/vnd.lotus-freelance" /> + <display value="vnd.lotus-freelance" /> + <definition value="As defined by Paul Wattenberger"/> + </concept> + <concept> + <code value="application/vnd.lotus-notes" /> + <display value="vnd.lotus-notes" /> + <definition value="As defined by Michael Laramie"/> + </concept> + <concept> + <code value="application/vnd.lotus-organizer" /> + <display value="vnd.lotus-organizer" /> + <definition value="As defined by Paul Wattenberger"/> + </concept> + <concept> + <code value="application/vnd.lotus-screencam" /> + <display value="vnd.lotus-screencam" /> + <definition value="As defined by Paul Wattenberger"/> + </concept> + <concept> + <code value="application/vnd.lotus-wordpro" /> + <display value="vnd.lotus-wordpro" /> + <definition value="As defined by Paul Wattenberger"/> + </concept> + <concept> + <code value="application/vnd.macports.portpkg" /> + <display value="vnd.macports.portpkg" /> + <definition value="As defined by James Berry"/> + </concept> + <concept> + <code value="application/vnd.mapbox-vector-tile" /> + <display value="vnd.mapbox-vector-tile" /> + <definition value="As defined by Blake Thompson"/> + </concept> + <concept> + <code value="application/vnd.marlin.drm.actiontoken+xml" /> + <display value="vnd.marlin.drm.actiontoken+xml" /> + <definition value="As defined by Gary Ellison"/> + </concept> + <concept> + <code value="application/vnd.marlin.drm.conftoken+xml" /> + <display value="vnd.marlin.drm.conftoken+xml" /> + <definition value="As defined by Gary Ellison"/> + </concept> + <concept> + <code value="application/vnd.marlin.drm.license+xml" /> + <display value="vnd.marlin.drm.license+xml" /> + <definition value="As defined by Gary Ellison"/> + </concept> + <concept> + <code value="application/vnd.marlin.drm.mdcf" /> + <display value="vnd.marlin.drm.mdcf" /> + <definition value="As defined by Gary Ellison"/> + </concept> + <concept> + <code value="application/vnd.mason+json" /> + <display value="vnd.mason+json" /> + <definition value="As defined by Jorn Wildt"/> + </concept> + <concept> + <code value="application/vnd.maxmind.maxmind-db" /> + <display value="vnd.maxmind.maxmind-db" /> + <definition value="As defined by William Stevenson"/> + </concept> + <concept> + <code value="application/vnd.mcd" /> + <display value="vnd.mcd" /> + <definition value="As defined by Tadashi Gotoh"/> + </concept> + <concept> + <code value="application/vnd.medcalcdata" /> + <display value="vnd.medcalcdata" /> + <definition value="As defined by Frank Schoonjans"/> + </concept> + <concept> + <code value="application/vnd.mediastation.cdkey" /> + <display value="vnd.mediastation.cdkey" /> + <definition value="As defined by Henry Flurry"/> + </concept> + <concept> + <code value="application/vnd.meridian-slingshot" /> + <display value="vnd.meridian-slingshot" /> + <definition value="As defined by Eric Wedel"/> + </concept> + <concept> + <code value="application/vnd.MFER" /> + <display value="vnd.MFER" /> + <definition value="As defined by Masaaki Hirai"/> + </concept> + <concept> + <code value="application/vnd.mfmp" /> + <display value="vnd.mfmp" /> + <definition value="As defined by Yukari Ikeda"/> + </concept> + <concept> + <code value="application/vnd.micro+json" /> + <display value="vnd.micro+json" /> + <definition value="As defined by Dali Zheng"/> + </concept> + <concept> + <code value="application/vnd.micrografx.flo" /> + <display value="vnd.micrografx.flo" /> + <definition value="As defined by Joe Prevo"/> + </concept> + <concept> + <code value="application/vnd.micrografx.igx" /> + <display value="vnd.micrografx.igx" /> + <definition value="As defined by Joe Prevo"/> + </concept> + <concept> + <code value="application/vnd.microsoft.portable-executable" /> + <display value="vnd.microsoft.portable-executable" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="application/vnd.microsoft.windows.thumbnail-cache" /> + <display value="vnd.microsoft.windows.thumbnail-cache" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="application/vnd.miele+json" /> + <display value="vnd.miele+json" /> + <definition value="As defined by Nils Langhammer"/> + </concept> + <concept> + <code value="application/vnd.mif" /> + <display value="vnd.mif" /> + <definition value="As defined by Mike Wexler"/> + </concept> + <concept> + <code value="application/vnd.minisoft-hp3000-save" /> + <display value="vnd.minisoft-hp3000-save" /> + <definition value="As defined by Chris Bartram"/> + </concept> + <concept> + <code value="application/vnd.mitsubishi.misty-guard.trustweb" /> + <display value="vnd.mitsubishi.misty-guard.trustweb" /> + <definition value="As defined by Tanaka"/> + </concept> + <concept> + <code value="application/vnd.Mobius.DAF" /> + <display value="vnd.Mobius.DAF" /> + <definition value="As defined by Allen K. Kabayama"/> + </concept> + <concept> + <code value="application/vnd.Mobius.DIS" /> + <display value="vnd.Mobius.DIS" /> + <definition value="As defined by Allen K. Kabayama"/> + </concept> + <concept> + <code value="application/vnd.Mobius.MBK" /> + <display value="vnd.Mobius.MBK" /> + <definition value="As defined by Alex Devasia"/> + </concept> + <concept> + <code value="application/vnd.Mobius.MQY" /> + <display value="vnd.Mobius.MQY" /> + <definition value="As defined by Alex Devasia"/> + </concept> + <concept> + <code value="application/vnd.Mobius.MSL" /> + <display value="vnd.Mobius.MSL" /> + <definition value="As defined by Allen K. Kabayama"/> + </concept> + <concept> + <code value="application/vnd.Mobius.PLC" /> + <display value="vnd.Mobius.PLC" /> + <definition value="As defined by Allen K. Kabayama"/> + </concept> + <concept> + <code value="application/vnd.Mobius.TXF" /> + <display value="vnd.Mobius.TXF" /> + <definition value="As defined by Allen K. Kabayama"/> + </concept> + <concept> + <code value="application/vnd.mophun.application" /> + <display value="vnd.mophun.application" /> + <definition value="As defined by Bjorn Wennerstrom"/> + </concept> + <concept> + <code value="application/vnd.mophun.certificate" /> + <display value="vnd.mophun.certificate" /> + <definition value="As defined by Bjorn Wennerstrom"/> + </concept> + <concept> + <code value="application/vnd.motorola.flexsuite" /> + <display value="vnd.motorola.flexsuite" /> + <definition value="As defined by Mark Patton"/> + </concept> + <concept> + <code value="application/vnd.motorola.flexsuite.adsi" /> + <display value="vnd.motorola.flexsuite.adsi" /> + <definition value="As defined by Mark Patton"/> + </concept> + <concept> + <code value="application/vnd.motorola.flexsuite.fis" /> + <display value="vnd.motorola.flexsuite.fis" /> + <definition value="As defined by Mark Patton"/> + </concept> + <concept> + <code value="application/vnd.motorola.flexsuite.gotap" /> + <display value="vnd.motorola.flexsuite.gotap" /> + <definition value="As defined by Mark Patton"/> + </concept> + <concept> + <code value="application/vnd.motorola.flexsuite.kmr" /> + <display value="vnd.motorola.flexsuite.kmr" /> + <definition value="As defined by Mark Patton"/> + </concept> + <concept> + <code value="application/vnd.motorola.flexsuite.ttc" /> + <display value="vnd.motorola.flexsuite.ttc" /> + <definition value="As defined by Mark Patton"/> + </concept> + <concept> + <code value="application/vnd.motorola.flexsuite.wem" /> + <display value="vnd.motorola.flexsuite.wem" /> + <definition value="As defined by Mark Patton"/> + </concept> + <concept> + <code value="application/vnd.motorola.iprm" /> + <display value="vnd.motorola.iprm" /> + <definition value="As defined by Rafie Shamsaasef"/> + </concept> + <concept> + <code value="application/vnd.mozilla.xul+xml" /> + <display value="vnd.mozilla.xul+xml" /> + <definition value="As defined by Braden N McDaniel"/> + </concept> + <concept> + <code value="application/vnd.ms-artgalry" /> + <display value="vnd.ms-artgalry" /> + <definition value="As defined by Dean Slawson"/> + </concept> + <concept> + <code value="application/vnd.ms-asf" /> + <display value="vnd.ms-asf" /> + <definition value="As defined by Eric Fleischman"/> + </concept> + <concept> + <code value="application/vnd.ms-cab-compressed" /> + <display value="vnd.ms-cab-compressed" /> + <definition value="As defined by Kim Scarborough"/> + </concept> + <concept> + <code value="application/vnd.ms-3mfdocument" /> + <display value="vnd.ms-3mfdocument" /> + <definition value="As defined by Shawn Maloney"/> + </concept> + <concept> + <code value="application/vnd.ms-excel" /> + <display value="vnd.ms-excel" /> + <definition value="As defined by Sukvinder S. Gill"/> + </concept> + <concept> + <code value="application/vnd.ms-excel.addin.macroEnabled.12" /> + <display value="vnd.ms-excel.addin.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-excel.sheet.binary.macroEnabled.12" /> + <display value="vnd.ms-excel.sheet.binary.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-excel.sheet.macroEnabled.12" /> + <display value="vnd.ms-excel.sheet.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-excel.template.macroEnabled.12" /> + <display value="vnd.ms-excel.template.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-fontobject" /> + <display value="vnd.ms-fontobject" /> + <definition value="As defined by Kim Scarborough"/> + </concept> + <concept> + <code value="application/vnd.ms-htmlhelp" /> + <display value="vnd.ms-htmlhelp" /> + <definition value="As defined by Anatoly Techtonik"/> + </concept> + <concept> + <code value="application/vnd.ms-ims" /> + <display value="vnd.ms-ims" /> + <definition value="As defined by Eric Ledoux"/> + </concept> + <concept> + <code value="application/vnd.ms-lrm" /> + <display value="vnd.ms-lrm" /> + <definition value="As defined by Eric Ledoux"/> + </concept> + <concept> + <code value="application/vnd.ms-office.activeX+xml" /> + <display value="vnd.ms-office.activeX+xml" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-officetheme" /> + <display value="vnd.ms-officetheme" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-playready.initiator+xml" /> + <display value="vnd.ms-playready.initiator+xml" /> + <definition value="As defined by Daniel Schneider"/> + </concept> + <concept> + <code value="application/vnd.ms-powerpoint" /> + <display value="vnd.ms-powerpoint" /> + <definition value="As defined by Sukvinder S. Gill"/> + </concept> + <concept> + <code value="application/vnd.ms-powerpoint.addin.macroEnabled.12" /> + <display value="vnd.ms-powerpoint.addin.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-powerpoint.presentation.macroEnabled.12" /> + <display value="vnd.ms-powerpoint.presentation.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-powerpoint.slide.macroEnabled.12" /> + <display value="vnd.ms-powerpoint.slide.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-powerpoint.slideshow.macroEnabled.12" /> + <display value="vnd.ms-powerpoint.slideshow.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-powerpoint.template.macroEnabled.12" /> + <display value="vnd.ms-powerpoint.template.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-PrintDeviceCapabilities+xml" /> + <display value="vnd.ms-PrintDeviceCapabilities+xml" /> + <definition value="As defined by Justin Hutchings"/> + </concept> + <concept> + <code value="application/vnd.ms-PrintSchemaTicket+xml" /> + <display value="vnd.ms-PrintSchemaTicket+xml" /> + <definition value="As defined by Justin Hutchings"/> + </concept> + <concept> + <code value="application/vnd.ms-project" /> + <display value="vnd.ms-project" /> + <definition value="As defined by Sukvinder S. Gill"/> + </concept> + <concept> + <code value="application/vnd.ms-tnef" /> + <display value="vnd.ms-tnef" /> + <definition value="As defined by Sukvinder S. Gill"/> + </concept> + <concept> + <code value="application/vnd.ms-windows.devicepairing" /> + <display value="vnd.ms-windows.devicepairing" /> + <definition value="As defined by Justin Hutchings"/> + </concept> + <concept> + <code value="application/vnd.ms-windows.nwprinting.oob" /> + <display value="vnd.ms-windows.nwprinting.oob" /> + <definition value="As defined by Justin Hutchings"/> + </concept> + <concept> + <code value="application/vnd.ms-windows.printerpairing" /> + <display value="vnd.ms-windows.printerpairing" /> + <definition value="As defined by Justin Hutchings"/> + </concept> + <concept> + <code value="application/vnd.ms-windows.wsd.oob" /> + <display value="vnd.ms-windows.wsd.oob" /> + <definition value="As defined by Justin Hutchings"/> + </concept> + <concept> + <code value="application/vnd.ms-wmdrm.lic-chlg-req" /> + <display value="vnd.ms-wmdrm.lic-chlg-req" /> + <definition value="As defined by Kevin Lau"/> + </concept> + <concept> + <code value="application/vnd.ms-wmdrm.lic-resp" /> + <display value="vnd.ms-wmdrm.lic-resp" /> + <definition value="As defined by Kevin Lau"/> + </concept> + <concept> + <code value="application/vnd.ms-wmdrm.meter-chlg-req" /> + <display value="vnd.ms-wmdrm.meter-chlg-req" /> + <definition value="As defined by Kevin Lau"/> + </concept> + <concept> + <code value="application/vnd.ms-wmdrm.meter-resp" /> + <display value="vnd.ms-wmdrm.meter-resp" /> + <definition value="As defined by Kevin Lau"/> + </concept> + <concept> + <code value="application/vnd.ms-word.document.macroEnabled.12" /> + <display value="vnd.ms-word.document.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-word.template.macroEnabled.12" /> + <display value="vnd.ms-word.template.macroEnabled.12" /> + <definition value="As defined by Chris Rae"/> + </concept> + <concept> + <code value="application/vnd.ms-works" /> + <display value="vnd.ms-works" /> + <definition value="As defined by Sukvinder S. Gill"/> + </concept> + <concept> + <code value="application/vnd.ms-wpl" /> + <display value="vnd.ms-wpl" /> + <definition value="As defined by Dan Plastina"/> + </concept> + <concept> + <code value="application/vnd.ms-xpsdocument" /> + <display value="vnd.ms-xpsdocument" /> + <definition value="As defined by Jesse McGatha"/> + </concept> + <concept> + <code value="application/vnd.msa-disk-image" /> + <display value="vnd.msa-disk-image" /> + <definition value="As defined by Thomas Huth"/> + </concept> + <concept> + <code value="application/vnd.mseq" /> + <display value="vnd.mseq" /> + <definition value="As defined by Gwenael Le Bodic"/> + </concept> + <concept> + <code value="application/vnd.msign" /> + <display value="vnd.msign" /> + <definition value="As defined by Malte Borcherding"/> + </concept> + <concept> + <code value="application/vnd.multiad.creator" /> + <display value="vnd.multiad.creator" /> + <definition value="As defined by Steve Mills"/> + </concept> + <concept> + <code value="application/vnd.multiad.creator.cif" /> + <display value="vnd.multiad.creator.cif" /> + <definition value="As defined by Steve Mills"/> + </concept> + <concept> + <code value="application/vnd.musician" /> + <display value="vnd.musician" /> + <definition value="As defined by Greg Adams"/> + </concept> + <concept> + <code value="application/vnd.music-niff" /> + <display value="vnd.music-niff" /> + <definition value="As defined by Tim Butler"/> + </concept> + <concept> + <code value="application/vnd.muvee.style" /> + <display value="vnd.muvee.style" /> + <definition value="As defined by Chandrashekhara Anantharamu"/> + </concept> + <concept> + <code value="application/vnd.mynfc" /> + <display value="vnd.mynfc" /> + <definition value="As defined by Franck Lefevre"/> + </concept> + <concept> + <code value="application/vnd.ncd.control" /> + <display value="vnd.ncd.control" /> + <definition value="As defined by Lauri Tarkkala"/> + </concept> + <concept> + <code value="application/vnd.ncd.reference" /> + <display value="vnd.ncd.reference" /> + <definition value="As defined by Lauri Tarkkala"/> + </concept> + <concept> + <code value="application/vnd.nearst.inv+json" /> + <display value="vnd.nearst.inv+json" /> + <definition value="As defined by Thomas Schoffelen"/> + </concept> + <concept> + <code value="application/vnd.nervana" /> + <display value="vnd.nervana" /> + <definition value="As defined by Steve Judkins"/> + </concept> + <concept> + <code value="application/vnd.netfpx" /> + <display value="vnd.netfpx" /> + <definition value="As defined by Andy Mutz"/> + </concept> + <concept> + <code value="application/vnd.neurolanguage.nlu" /> + <display value="vnd.neurolanguage.nlu" /> + <definition value="As defined by Dan DuFeu"/> + </concept> + <concept> + <code value="application/vnd.nimn" /> + <display value="vnd.nimn" /> + <definition value="As defined by Amit Kumar Gupta"/> + </concept> + <concept> + <code value="application/vnd.nintendo.snes.rom" /> + <display value="vnd.nintendo.snes.rom" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="application/vnd.nintendo.nitro.rom" /> + <display value="vnd.nintendo.nitro.rom" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="application/vnd.nitf" /> + <display value="vnd.nitf" /> + <definition value="As defined by Steve Rogan"/> + </concept> + <concept> + <code value="application/vnd.noblenet-directory" /> + <display value="vnd.noblenet-directory" /> + <definition value="As defined by Monty Solomon"/> + </concept> + <concept> + <code value="application/vnd.noblenet-sealer" /> + <display value="vnd.noblenet-sealer" /> + <definition value="As defined by Monty Solomon"/> + </concept> + <concept> + <code value="application/vnd.noblenet-web" /> + <display value="vnd.noblenet-web" /> + <definition value="As defined by Monty Solomon"/> + </concept> + <concept> + <code value="application/vnd.nokia.catalogs" /> + <display value="vnd.nokia.catalogs" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.conml+wbxml" /> + <display value="vnd.nokia.conml+wbxml" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.conml+xml" /> + <display value="vnd.nokia.conml+xml" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.iptv.config+xml" /> + <display value="vnd.nokia.iptv.config+xml" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.iSDS-radio-presets" /> + <display value="vnd.nokia.iSDS-radio-presets" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.landmark+wbxml" /> + <display value="vnd.nokia.landmark+wbxml" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.landmark+xml" /> + <display value="vnd.nokia.landmark+xml" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.landmarkcollection+xml" /> + <display value="vnd.nokia.landmarkcollection+xml" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.ncd" /> + <display value="vnd.nokia.ncd" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.n-gage.ac+xml" /> + <display value="vnd.nokia.n-gage.ac+xml" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.n-gage.data" /> + <display value="vnd.nokia.n-gage.data" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.pcd+wbxml" /> + <display value="vnd.nokia.pcd+wbxml" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.pcd+xml" /> + <display value="vnd.nokia.pcd+xml" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.radio-preset" /> + <display value="vnd.nokia.radio-preset" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.nokia.radio-presets" /> + <display value="vnd.nokia.radio-presets" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="application/vnd.novadigm.EDM" /> + <display value="vnd.novadigm.EDM" /> + <definition value="As defined by Janine Swenson"/> + </concept> + <concept> + <code value="application/vnd.novadigm.EDX" /> + <display value="vnd.novadigm.EDX" /> + <definition value="As defined by Janine Swenson"/> + </concept> + <concept> + <code value="application/vnd.novadigm.EXT" /> + <display value="vnd.novadigm.EXT" /> + <definition value="As defined by Janine Swenson"/> + </concept> + <concept> + <code value="application/vnd.ntt-local.content-share" /> + <display value="vnd.ntt-local.content-share" /> + <definition value="As defined by Akinori Taya"/> + </concept> + <concept> + <code value="application/vnd.ntt-local.file-transfer" /> + <display value="vnd.ntt-local.file-transfer" /> + <definition value="As defined by NTT-local"/> + </concept> + <concept> + <code value="application/vnd.ntt-local.ogw_remote-access" /> + <display value="vnd.ntt-local.ogw_remote-access" /> + <definition value="As defined by NTT-local"/> + </concept> + <concept> + <code value="application/vnd.ntt-local.sip-ta_remote" /> + <display value="vnd.ntt-local.sip-ta_remote" /> + <definition value="As defined by NTT-local"/> + </concept> + <concept> + <code value="application/vnd.ntt-local.sip-ta_tcp_stream" /> + <display value="vnd.ntt-local.sip-ta_tcp_stream" /> + <definition value="As defined by NTT-local"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.chart" /> + <display value="vnd.oasis.opendocument.chart" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.chart-template" /> + <display value="vnd.oasis.opendocument.chart-template" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.database" /> + <display value="vnd.oasis.opendocument.database" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.formula" /> + <display value="vnd.oasis.opendocument.formula" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.formula-template" /> + <display value="vnd.oasis.opendocument.formula-template" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.graphics" /> + <display value="vnd.oasis.opendocument.graphics" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.graphics-template" /> + <display value="vnd.oasis.opendocument.graphics-template" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.image" /> + <display value="vnd.oasis.opendocument.image" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.image-template" /> + <display value="vnd.oasis.opendocument.image-template" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.presentation" /> + <display value="vnd.oasis.opendocument.presentation" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.presentation-template" /> + <display value="vnd.oasis.opendocument.presentation-template" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.spreadsheet" /> + <display value="vnd.oasis.opendocument.spreadsheet" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.spreadsheet-template" /> + <display value="vnd.oasis.opendocument.spreadsheet-template" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.text" /> + <display value="vnd.oasis.opendocument.text" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.text-master" /> + <display value="vnd.oasis.opendocument.text-master" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.text-template" /> + <display value="vnd.oasis.opendocument.text-template" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.oasis.opendocument.text-web" /> + <display value="vnd.oasis.opendocument.text-web" /> + <definition value="As defined by Svante Schubert, and OASIS"/> + </concept> + <concept> + <code value="application/vnd.obn" /> + <display value="vnd.obn" /> + <definition value="As defined by Matthias Hessling"/> + </concept> + <concept> + <code value="application/vnd.ocf+cbor" /> + <display value="vnd.ocf+cbor" /> + <definition value="As defined by Michael Koster"/> + </concept> + <concept> + <code value="application/vnd.oci.image.manifest.v1+json" /> + <display value="vnd.oci.image.manifest.v1+json" /> + <definition value="As defined by Steven Lasker"/> + </concept> + <concept> + <code value="application/vnd.oftn.l10n+json" /> + <display value="vnd.oftn.l10n+json" /> + <definition value="As defined by Eli Grey"/> + </concept> + <concept> + <code value="application/vnd.oipf.contentaccessdownload+xml" /> + <display value="vnd.oipf.contentaccessdownload+xml" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.oipf.contentaccessstreaming+xml" /> + <display value="vnd.oipf.contentaccessstreaming+xml" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.oipf.cspg-hexbinary" /> + <display value="vnd.oipf.cspg-hexbinary" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.oipf.dae.svg+xml" /> + <display value="vnd.oipf.dae.svg+xml" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.oipf.dae.xhtml+xml" /> + <display value="vnd.oipf.dae.xhtml+xml" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.oipf.mippvcontrolmessage+xml" /> + <display value="vnd.oipf.mippvcontrolmessage+xml" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.oipf.pae.gem" /> + <display value="vnd.oipf.pae.gem" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.oipf.spdiscovery+xml" /> + <display value="vnd.oipf.spdiscovery+xml" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.oipf.spdlist+xml" /> + <display value="vnd.oipf.spdlist+xml" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.oipf.ueprofile+xml" /> + <display value="vnd.oipf.ueprofile+xml" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.oipf.userprofile+xml" /> + <display value="vnd.oipf.userprofile+xml" /> + <definition value="As defined by Claire DEsclercs"/> + </concept> + <concept> + <code value="application/vnd.olpc-sugar" /> + <display value="vnd.olpc-sugar" /> + <definition value="As defined by John Palmieri"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.associated-procedure-parameter+xml" /> + <display value="vnd.oma.bcast.associated-procedure-parameter+xml" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.drm-trigger+xml" /> + <display value="vnd.oma.bcast.drm-trigger+xml" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.imd+xml" /> + <display value="vnd.oma.bcast.imd+xml" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.ltkm" /> + <display value="vnd.oma.bcast.ltkm" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.notification+xml" /> + <display value="vnd.oma.bcast.notification+xml" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.provisioningtrigger" /> + <display value="vnd.oma.bcast.provisioningtrigger" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.sgboot" /> + <display value="vnd.oma.bcast.sgboot" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.sgdd+xml" /> + <display value="vnd.oma.bcast.sgdd+xml" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.sgdu" /> + <display value="vnd.oma.bcast.sgdu" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.simple-symbol-container" /> + <display value="vnd.oma.bcast.simple-symbol-container" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.smartcard-trigger+xml" /> + <display value="vnd.oma.bcast.smartcard-trigger+xml" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.sprov+xml" /> + <display value="vnd.oma.bcast.sprov+xml" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.bcast.stkm" /> + <display value="vnd.oma.bcast.stkm" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.cab-address-book+xml" /> + <display value="vnd.oma.cab-address-book+xml" /> + <definition value="As defined by Hao Wang, and OMA"/> + </concept> + <concept> + <code value="application/vnd.oma.cab-feature-handler+xml" /> + <display value="vnd.oma.cab-feature-handler+xml" /> + <definition value="As defined by Hao Wang, and OMA"/> + </concept> + <concept> + <code value="application/vnd.oma.cab-pcc+xml" /> + <display value="vnd.oma.cab-pcc+xml" /> + <definition value="As defined by Hao Wang, and OMA"/> + </concept> + <concept> + <code value="application/vnd.oma.cab-subs-invite+xml" /> + <display value="vnd.oma.cab-subs-invite+xml" /> + <definition value="As defined by Hao Wang, and OMA"/> + </concept> + <concept> + <code value="application/vnd.oma.cab-user-prefs+xml" /> + <display value="vnd.oma.cab-user-prefs+xml" /> + <definition value="As defined by Hao Wang, and OMA"/> + </concept> + <concept> + <code value="application/vnd.oma.dcd" /> + <display value="vnd.oma.dcd" /> + <definition value="As defined by Avi Primo, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.dcdc" /> + <display value="vnd.oma.dcdc" /> + <definition value="As defined by Avi Primo, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.dd2+xml" /> + <display value="vnd.oma.dd2+xml" /> + <definition value="As defined by Jun Sato, and Open Mobile Alliance BAC DLDRM Working Group"/> + </concept> + <concept> + <code value="application/vnd.oma.drm.risd+xml" /> + <display value="vnd.oma.drm.risd+xml" /> + <definition value="As defined by Uwe Rauschenbach, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.group-usage-list+xml" /> + <display value="vnd.oma.group-usage-list+xml" /> + <definition value="As defined by Sean Kelley, and OMA Presence and Availability PAG Working Group"/> + </concept> + <concept> + <code value="application/vnd.oma.lwm2m+json" /> + <display value="vnd.oma.lwm2m+json" /> + <definition value="As defined by John Mudge, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.lwm2m+tlv" /> + <display value="vnd.oma.lwm2m+tlv" /> + <definition value="As defined by John Mudge, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.pal+xml" /> + <display value="vnd.oma.pal+xml" /> + <definition value="As defined by Brian McColgan, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.poc.detailed-progress-report+xml" /> + <display value="vnd.oma.poc.detailed-progress-report+xml" /> + <definition value="As defined by OMA Push to Talk over Cellular POC Working Group"/> + </concept> + <concept> + <code value="application/vnd.oma.poc.final-report+xml" /> + <display value="vnd.oma.poc.final-report+xml" /> + <definition value="As defined by OMA Push to Talk over Cellular POC Working Group"/> + </concept> + <concept> + <code value="application/vnd.oma.poc.groups+xml" /> + <display value="vnd.oma.poc.groups+xml" /> + <definition value="As defined by Sean Kelley, and OMA Push to Talk over Cellular POC Working Group"/> + </concept> + <concept> + <code value="application/vnd.oma.poc.invocation-descriptor+xml" /> + <display value="vnd.oma.poc.invocation-descriptor+xml" /> + <definition value="As defined by OMA Push to Talk over Cellular POC Working Group"/> + </concept> + <concept> + <code value="application/vnd.oma.poc.optimized-progress-report+xml" /> + <display value="vnd.oma.poc.optimized-progress-report+xml" /> + <definition value="As defined by OMA Push to Talk over Cellular POC Working Group"/> + </concept> + <concept> + <code value="application/vnd.oma.push" /> + <display value="vnd.oma.push" /> + <definition value="As defined by Bryan Sullivan, and OMA"/> + </concept> + <concept> + <code value="application/vnd.oma.scidm.messages+xml" /> + <display value="vnd.oma.scidm.messages+xml" /> + <definition value="As defined by Wenjun Zeng, and Open Mobile Naming Authority"/> + </concept> + <concept> + <code value="application/vnd.oma.xcap-directory+xml" /> + <display value="vnd.oma.xcap-directory+xml" /> + <definition value="As defined by Sean Kelley, and OMA Presence and Availability PAG Working Group"/> + </concept> + <concept> + <code value="application/vnd.omads-email+xml" /> + <display value="vnd.omads-email+xml" /> + <definition value="As defined by OMA Data Synchronization Working Group"/> + </concept> + <concept> + <code value="application/vnd.omads-file+xml" /> + <display value="vnd.omads-file+xml" /> + <definition value="As defined by OMA Data Synchronization Working Group"/> + </concept> + <concept> + <code value="application/vnd.omads-folder+xml" /> + <display value="vnd.omads-folder+xml" /> + <definition value="As defined by OMA Data Synchronization Working Group"/> + </concept> + <concept> + <code value="application/vnd.omaloc-supl-init" /> + <display value="vnd.omaloc-supl-init" /> + <definition value="As defined by Julien Grange"/> + </concept> + <concept> + <code value="application/vnd.oma-scws-config" /> + <display value="vnd.oma-scws-config" /> + <definition value="As defined by Ilan Mahalal"/> + </concept> + <concept> + <code value="application/vnd.oma-scws-http-request" /> + <display value="vnd.oma-scws-http-request" /> + <definition value="As defined by Ilan Mahalal"/> + </concept> + <concept> + <code value="application/vnd.oma-scws-http-response" /> + <display value="vnd.oma-scws-http-response" /> + <definition value="As defined by Ilan Mahalal"/> + </concept> + <concept> + <code value="application/vnd.onepager" /> + <display value="vnd.onepager" /> + <definition value="As defined by Nathan Black"/> + </concept> + <concept> + <code value="application/vnd.onepagertamp" /> + <display value="vnd.onepagertamp" /> + <definition value="As defined by Nathan Black"/> + </concept> + <concept> + <code value="application/vnd.onepagertamx" /> + <display value="vnd.onepagertamx" /> + <definition value="As defined by Nathan Black"/> + </concept> + <concept> + <code value="application/vnd.onepagertat" /> + <display value="vnd.onepagertat" /> + <definition value="As defined by Nathan Black"/> + </concept> + <concept> + <code value="application/vnd.onepagertatp" /> + <display value="vnd.onepagertatp" /> + <definition value="As defined by Nathan Black"/> + </concept> + <concept> + <code value="application/vnd.onepagertatx" /> + <display value="vnd.onepagertatx" /> + <definition value="As defined by Nathan Black"/> + </concept> + <concept> + <code value="application/vnd.openblox.game-binary" /> + <display value="vnd.openblox.game-binary" /> + <definition value="As defined by Mark Otaris"/> + </concept> + <concept> + <code value="application/vnd.openblox.game+xml" /> + <display value="vnd.openblox.game+xml" /> + <definition value="As defined by Mark Otaris"/> + </concept> + <concept> + <code value="application/vnd.openeye.oeb" /> + <display value="vnd.openeye.oeb" /> + <definition value="As defined by Craig Bruce"/> + </concept> + <concept> + <code value="application/vnd.openstreetmap.data+xml" /> + <display value="vnd.openstreetmap.data+xml" /> + <definition value="As defined by Paul Norman"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.custom-properties+xml" /> + <display value="vnd.openxmlformats-officedocument.custom-properties+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.customXmlProperties+xml" /> + <display value="vnd.openxmlformats-officedocument.customXmlProperties+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.drawing+xml" /> + <display value="vnd.openxmlformats-officedocument.drawing+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.drawingml.chart+xml" /> + <display value="vnd.openxmlformats-officedocument.drawingml.chart+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml" /> + <display value="vnd.openxmlformats-officedocument.drawingml.chartshapes+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml" /> + <display value="vnd.openxmlformats-officedocument.drawingml.diagramColors+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml" /> + <display value="vnd.openxmlformats-officedocument.drawingml.diagramData+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml" /> + <display value="vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml" /> + <display value="vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.extended-properties+xml" /> + <display value="vnd.openxmlformats-officedocument.extended-properties+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.commentAuthors+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.commentAuthors+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.comments+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.comments+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.handoutMaster+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.handoutMaster+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.notesMaster+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.notesSlide+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.presentation" /> + <display value="vnd.openxmlformats-officedocument.presentationml.presentation" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.presentation.main+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.presProps+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.presProps+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.slide" /> + <display value="vnd.openxmlformats-officedocument.presentationml.slide" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.slide+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.slide+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.slideLayout+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.slideMaster+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.slideshow" /> + <display value="vnd.openxmlformats-officedocument.presentationml.slideshow" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.slideUpdateInfo+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.slideUpdateInfo+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.tableStyles+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.tags+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.tags+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.template" /> + <display value="vnd.openxmlformats-officedocument.presentationml.template" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.template.main+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.template.main+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml" /> + <display value="vnd.openxmlformats-officedocument.presentationml.viewProps+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.comments+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.connections+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.sheet" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.table+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.template" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.template" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" /> + <display value="vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.theme+xml" /> + <display value="vnd.openxmlformats-officedocument.theme+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.themeOverride+xml" /> + <display value="vnd.openxmlformats-officedocument.themeOverride+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.vmlDrawing" /> + <display value="vnd.openxmlformats-officedocument.vmlDrawing" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.comments+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.document" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.document" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.footer+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.template" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.template" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml" /> + <display value="vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-package.core-properties+xml" /> + <display value="vnd.openxmlformats-package.core-properties+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml" /> + <display value="vnd.openxmlformats-package.digital-signature-xmlsignature+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.openxmlformats-package.relationships+xml" /> + <display value="vnd.openxmlformats-package.relationships+xml" /> + <definition value="As defined by Makoto Murata"/> + </concept> + <concept> + <code value="application/vnd.oracle.resource+json" /> + <display value="vnd.oracle.resource+json" /> + <definition value="As defined by Ning Dong"/> + </concept> + <concept> + <code value="application/vnd.orange.indata" /> + <display value="vnd.orange.indata" /> + <definition value="As defined by CHATRAS Bruno"/> + </concept> + <concept> + <code value="application/vnd.osa.netdeploy" /> + <display value="vnd.osa.netdeploy" /> + <definition value="As defined by Steven Klos"/> + </concept> + <concept> + <code value="application/vnd.osgeo.mapguide.package" /> + <display value="vnd.osgeo.mapguide.package" /> + <definition value="As defined by Jason Birch"/> + </concept> + <concept> + <code value="application/vnd.osgi.bundle" /> + <display value="vnd.osgi.bundle" /> + <definition value="As defined by Peter Kriens"/> + </concept> + <concept> + <code value="application/vnd.osgi.dp" /> + <display value="vnd.osgi.dp" /> + <definition value="As defined by Peter Kriens"/> + </concept> + <concept> + <code value="application/vnd.osgi.subsystem" /> + <display value="vnd.osgi.subsystem" /> + <definition value="As defined by Peter Kriens"/> + </concept> + <concept> + <code value="application/vnd.otps.ct-kip+xml" /> + <display value="vnd.otps.ct-kip+xml" /> + <definition value="As defined by Magnus Nystrom"/> + </concept> + <concept> + <code value="application/vnd.oxli.countgraph" /> + <display value="vnd.oxli.countgraph" /> + <definition value="As defined by C. Titus Brown"/> + </concept> + <concept> + <code value="application/vnd.pagerduty+json" /> + <display value="vnd.pagerduty+json" /> + <definition value="As defined by Steve Rice"/> + </concept> + <concept> + <code value="application/vnd.palm" /> + <display value="vnd.palm" /> + <definition value="As defined by Gavin Peacock"/> + </concept> + <concept> + <code value="application/vnd.panoply" /> + <display value="vnd.panoply" /> + <definition value="As defined by Natarajan Balasundara"/> + </concept> + <concept> + <code value="application/vnd.paos.xml" /> + <display value="vnd.paos.xml" /> + <definition value="As defined by John Kemp"/> + </concept> + <concept> + <code value="application/vnd.patentdive" /> + <display value="vnd.patentdive" /> + <definition value="As defined by Christian Trosclair"/> + </concept> + <concept> + <code value="application/vnd.patientecommsdoc" /> + <display value="vnd.patientecommsdoc" /> + <definition value="As defined by Andrew David Kendall"/> + </concept> + <concept> + <code value="application/vnd.pawaafile" /> + <display value="vnd.pawaafile" /> + <definition value="As defined by Prakash Baskaran"/> + </concept> + <concept> + <code value="application/vnd.pcos" /> + <display value="vnd.pcos" /> + <definition value="As defined by Slawomir Lisznianski"/> + </concept> + <concept> + <code value="application/vnd.pg.format" /> + <display value="vnd.pg.format" /> + <definition value="As defined by April Gandert"/> + </concept> + <concept> + <code value="application/vnd.pg.osasli" /> + <display value="vnd.pg.osasli" /> + <definition value="As defined by April Gandert"/> + </concept> + <concept> + <code value="application/vnd.piaccess.application-licence" /> + <display value="vnd.piaccess.application-licence" /> + <definition value="As defined by Lucas Maneos"/> + </concept> + <concept> + <code value="application/vnd.picsel" /> + <display value="vnd.picsel" /> + <definition value="As defined by Giuseppe Naccarato"/> + </concept> + <concept> + <code value="application/vnd.pmi.widget" /> + <display value="vnd.pmi.widget" /> + <definition value="As defined by Rhys Lewis"/> + </concept> + <concept> + <code value="application/vnd.poc.group-advertisement+xml" /> + <display value="vnd.poc.group-advertisement+xml" /> + <definition value="As defined by Sean Kelley, and OMA Push to Talk over Cellular POC Working Group"/> + </concept> + <concept> + <code value="application/vnd.pocketlearn" /> + <display value="vnd.pocketlearn" /> + <definition value="As defined by Jorge Pando"/> + </concept> + <concept> + <code value="application/vnd.powerbuilder6" /> + <display value="vnd.powerbuilder6" /> + <definition value="As defined by David Guy"/> + </concept> + <concept> + <code value="application/vnd.powerbuilder6-s" /> + <display value="vnd.powerbuilder6-s" /> + <definition value="As defined by David Guy"/> + </concept> + <concept> + <code value="application/vnd.powerbuilder7" /> + <display value="vnd.powerbuilder7" /> + <definition value="As defined by Reed Shilts"/> + </concept> + <concept> + <code value="application/vnd.powerbuilder75" /> + <display value="vnd.powerbuilder75" /> + <definition value="As defined by Reed Shilts"/> + </concept> + <concept> + <code value="application/vnd.powerbuilder75-s" /> + <display value="vnd.powerbuilder75-s" /> + <definition value="As defined by Reed Shilts"/> + </concept> + <concept> + <code value="application/vnd.powerbuilder7-s" /> + <display value="vnd.powerbuilder7-s" /> + <definition value="As defined by Reed Shilts"/> + </concept> + <concept> + <code value="application/vnd.preminet" /> + <display value="vnd.preminet" /> + <definition value="As defined by Juoko Tenhunen"/> + </concept> + <concept> + <code value="application/vnd.previewsystems.box" /> + <display value="vnd.previewsystems.box" /> + <definition value="As defined by Roman Smolgovsky"/> + </concept> + <concept> + <code value="application/vnd.proteus.magazine" /> + <display value="vnd.proteus.magazine" /> + <definition value="As defined by Pete Hoch"/> + </concept> + <concept> + <code value="application/vnd.psfs" /> + <display value="vnd.psfs" /> + <definition value="As defined by Kristopher Durski"/> + </concept> + <concept> + <code value="application/vnd.publishare-delta-tree" /> + <display value="vnd.publishare-delta-tree" /> + <definition value="As defined by Oren Ben-Kiki"/> + </concept> + <concept> + <code value="application/vnd.pvi.ptid1" /> + <display value="vnd.pvi.ptid1" /> + <definition value="As defined by Charles P. Lamb"/> + </concept> + <concept> + <code value="application/vnd.pwg-multiplexed" /> + <display value="vnd.pwg-multiplexed" /> + <definition value="As defined by rfc3391"/> + </concept> + <concept> + <code value="application/vnd.pwg-xhtml-print+xml" /> + <display value="vnd.pwg-xhtml-print+xml" /> + <definition value="As defined by Don Wright"/> + </concept> + <concept> + <code value="application/vnd.qualcomm.brew-app-res" /> + <display value="vnd.qualcomm.brew-app-res" /> + <definition value="As defined by Glenn Forrester"/> + </concept> + <concept> + <code value="application/vnd.quarantainenet" /> + <display value="vnd.quarantainenet" /> + <definition value="As defined by Casper Joost Eyckelhof"/> + </concept> + <concept> + <code value="application/vnd.Quark.QuarkXPress" /> + <display value="vnd.Quark.QuarkXPress" /> + <definition value="As defined by Hannes Scheidler"/> + </concept> + <concept> + <code value="application/vnd.quobject-quoxdocument" /> + <display value="vnd.quobject-quoxdocument" /> + <definition value="As defined by Matthias Ludwig"/> + </concept> + <concept> + <code value="application/vnd.radisys.moml+xml" /> + <display value="vnd.radisys.moml+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-audit-conf+xml" /> + <display value="vnd.radisys.msml-audit-conf+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-audit-conn+xml" /> + <display value="vnd.radisys.msml-audit-conn+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-audit-dialog+xml" /> + <display value="vnd.radisys.msml-audit-dialog+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-audit-stream+xml" /> + <display value="vnd.radisys.msml-audit-stream+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-audit+xml" /> + <display value="vnd.radisys.msml-audit+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-conf+xml" /> + <display value="vnd.radisys.msml-conf+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-dialog-base+xml" /> + <display value="vnd.radisys.msml-dialog-base+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-dialog-fax-detect+xml" /> + <display value="vnd.radisys.msml-dialog-fax-detect+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-dialog-fax-sendrecv+xml" /> + <display value="vnd.radisys.msml-dialog-fax-sendrecv+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-dialog-group+xml" /> + <display value="vnd.radisys.msml-dialog-group+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-dialog-speech+xml" /> + <display value="vnd.radisys.msml-dialog-speech+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-dialog-transform+xml" /> + <display value="vnd.radisys.msml-dialog-transform+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml-dialog+xml" /> + <display value="vnd.radisys.msml-dialog+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.radisys.msml+xml" /> + <display value="vnd.radisys.msml+xml" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="application/vnd.rainstor.data" /> + <display value="vnd.rainstor.data" /> + <definition value="As defined by Kevin Crook"/> + </concept> + <concept> + <code value="application/vnd.rapid" /> + <display value="vnd.rapid" /> + <definition value="As defined by Etay Szekely"/> + </concept> + <concept> + <code value="application/vnd.rar" /> + <display value="vnd.rar" /> + <definition value="As defined by Kim Scarborough"/> + </concept> + <concept> + <code value="application/vnd.realvnc.bed" /> + <display value="vnd.realvnc.bed" /> + <definition value="As defined by Nick Reeves"/> + </concept> + <concept> + <code value="application/vnd.recordare.musicxml" /> + <display value="vnd.recordare.musicxml" /> + <definition value="As defined by W3C Music Notation Community Group"/> + </concept> + <concept> + <code value="application/vnd.recordare.musicxml+xml" /> + <display value="vnd.recordare.musicxml+xml" /> + <definition value="As defined by W3C Music Notation Community Group"/> + </concept> + <concept> + <code value="application/vnd.RenLearn.rlprint" /> + <display value="vnd.RenLearn.rlprint" /> + <definition value="As defined by James Wick"/> + </concept> + <concept> + <code value="application/vnd.restful+json" /> + <display value="vnd.restful+json" /> + <definition value="As defined by Stephen Mizell"/> + </concept> + <concept> + <code value="application/vnd.rig.cryptonote" /> + <display value="vnd.rig.cryptonote" /> + <definition value="As defined by Ken Jibiki"/> + </concept> + <concept> + <code value="application/vnd.route66.link66+xml" /> + <display value="vnd.route66.link66+xml" /> + <definition value="As defined by Sybren Kikstra"/> + </concept> + <concept> + <code value="application/vnd.rs-274x" /> + <display value="vnd.rs-274x" /> + <definition value="As defined by Lee Harding"/> + </concept> + <concept> + <code value="application/vnd.ruckus.download" /> + <display value="vnd.ruckus.download" /> + <definition value="As defined by Jerry Harris"/> + </concept> + <concept> + <code value="application/vnd.s3sms" /> + <display value="vnd.s3sms" /> + <definition value="As defined by Lauri Tarkkala"/> + </concept> + <concept> + <code value="application/vnd.sailingtracker.track" /> + <display value="vnd.sailingtracker.track" /> + <definition value="As defined by Heikki Vesalainen"/> + </concept> + <concept> + <code value="application/vnd.sar" /> + <display value="vnd.sar" /> + <definition value="As defined by Markus Strehle"/> + </concept> + <concept> + <code value="application/vnd.sbm.cid" /> + <display value="vnd.sbm.cid" /> + <definition value="As defined by Shinji Kusakari"/> + </concept> + <concept> + <code value="application/vnd.sbm.mid2" /> + <display value="vnd.sbm.mid2" /> + <definition value="As defined by Masanori Murai"/> + </concept> + <concept> + <code value="application/vnd.scribus" /> + <display value="vnd.scribus" /> + <definition value="As defined by Craig Bradney"/> + </concept> + <concept> + <code value="application/vnd.sealed.3df" /> + <display value="vnd.sealed.3df" /> + <definition value="As defined by John Kwan"/> + </concept> + <concept> + <code value="application/vnd.sealed.csf" /> + <display value="vnd.sealed.csf" /> + <definition value="As defined by John Kwan"/> + </concept> + <concept> + <code value="application/vnd.sealed.doc" /> + <display value="vnd.sealed.doc" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="application/vnd.sealed.eml" /> + <display value="vnd.sealed.eml" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="application/vnd.sealed.mht" /> + <display value="vnd.sealed.mht" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="application/vnd.sealed.net" /> + <display value="vnd.sealed.net" /> + <definition value="As defined by Martin Lambert"/> + </concept> + <concept> + <code value="application/vnd.sealed.ppt" /> + <display value="vnd.sealed.ppt" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="application/vnd.sealed.tiff" /> + <display value="vnd.sealed.tiff" /> + <definition value="As defined by John Kwan, and Martin Lambert"/> + </concept> + <concept> + <code value="application/vnd.sealed.xls" /> + <display value="vnd.sealed.xls" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="application/vnd.sealedmedia.softseal.html" /> + <display value="vnd.sealedmedia.softseal.html" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="application/vnd.sealedmedia.softseal.pdf" /> + <display value="vnd.sealedmedia.softseal.pdf" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="application/vnd.seemail" /> + <display value="vnd.seemail" /> + <definition value="As defined by Steve Webb"/> + </concept> + <concept> + <code value="application/vnd.sema" /> + <display value="vnd.sema" /> + <definition value="As defined by Anders Hansson"/> + </concept> + <concept> + <code value="application/vnd.semd" /> + <display value="vnd.semd" /> + <definition value="As defined by Anders Hansson"/> + </concept> + <concept> + <code value="application/vnd.semf" /> + <display value="vnd.semf" /> + <definition value="As defined by Anders Hansson"/> + </concept> + <concept> + <code value="application/vnd.shade-save-file" /> + <display value="vnd.shade-save-file" /> + <definition value="As defined by Connor Horman"/> + </concept> + <concept> + <code value="application/vnd.shana.informed.formdata" /> + <display value="vnd.shana.informed.formdata" /> + <definition value="As defined by Guy Selzler"/> + </concept> + <concept> + <code value="application/vnd.shana.informed.formtemplate" /> + <display value="vnd.shana.informed.formtemplate" /> + <definition value="As defined by Guy Selzler"/> + </concept> + <concept> + <code value="application/vnd.shana.informed.interchange" /> + <display value="vnd.shana.informed.interchange" /> + <definition value="As defined by Guy Selzler"/> + </concept> + <concept> + <code value="application/vnd.shana.informed.package" /> + <display value="vnd.shana.informed.package" /> + <definition value="As defined by Guy Selzler"/> + </concept> + <concept> + <code value="application/vnd.shootproof+json" /> + <display value="vnd.shootproof+json" /> + <definition value="As defined by Ben Ramsey"/> + </concept> + <concept> + <code value="application/vnd.shopkick+json" /> + <display value="vnd.shopkick+json" /> + <definition value="As defined by Ronald Jacobs"/> + </concept> + <concept> + <code value="application/vnd.shp" /> + <display value="vnd.shp" /> + <definition value="As defined by Mi Tar"/> + </concept> + <concept> + <code value="application/vnd.shx" /> + <display value="vnd.shx" /> + <definition value="As defined by Mi Tar"/> + </concept> + <concept> + <code value="application/vnd.sigrok.session" /> + <display value="vnd.sigrok.session" /> + <definition value="As defined by Uwe Hermann"/> + </concept> + <concept> + <code value="application/vnd.SimTech-MindMapper" /> + <display value="vnd.SimTech-MindMapper" /> + <definition value="As defined by Patrick Koh"/> + </concept> + <concept> + <code value="application/vnd.siren+json" /> + <display value="vnd.siren+json" /> + <definition value="As defined by Kevin Swiber"/> + </concept> + <concept> + <code value="application/vnd.smaf" /> + <display value="vnd.smaf" /> + <definition value="As defined by Hiroaki Takahashi"/> + </concept> + <concept> + <code value="application/vnd.smart.notebook" /> + <display value="vnd.smart.notebook" /> + <definition value="As defined by Jonathan Neitz"/> + </concept> + <concept> + <code value="application/vnd.smart.teacher" /> + <display value="vnd.smart.teacher" /> + <definition value="As defined by Michael Boyle"/> + </concept> + <concept> + <code value="application/vnd.snesdev-page-table" /> + <display value="vnd.snesdev-page-table" /> + <definition value="As defined by Connor Horman"/> + </concept> + <concept> + <code value="application/vnd.software602.filler.form+xml" /> + <display value="vnd.software602.filler.form+xml" /> + <definition value="As defined by Jakub Hytka, and Martin Vondrous"/> + </concept> + <concept> + <code value="application/vnd.software602.filler.form-xml-zip" /> + <display value="vnd.software602.filler.form-xml-zip" /> + <definition value="As defined by Jakub Hytka, and Martin Vondrous"/> + </concept> + <concept> + <code value="application/vnd.solent.sdkm+xml" /> + <display value="vnd.solent.sdkm+xml" /> + <definition value="As defined by Cliff Gauntlett"/> + </concept> + <concept> + <code value="application/vnd.spotfire.dxp" /> + <display value="vnd.spotfire.dxp" /> + <definition value="As defined by Stefan Jernberg"/> + </concept> + <concept> + <code value="application/vnd.spotfire.sfs" /> + <display value="vnd.spotfire.sfs" /> + <definition value="As defined by Stefan Jernberg"/> + </concept> + <concept> + <code value="application/vnd.sqlite3" /> + <display value="vnd.sqlite3" /> + <definition value="As defined by Clemens Ladisch"/> + </concept> + <concept> + <code value="application/vnd.sss-cod" /> + <display value="vnd.sss-cod" /> + <definition value="As defined by Asang Dani"/> + </concept> + <concept> + <code value="application/vnd.sss-dtf" /> + <display value="vnd.sss-dtf" /> + <definition value="As defined by Eric Bruno"/> + </concept> + <concept> + <code value="application/vnd.sss-ntf" /> + <display value="vnd.sss-ntf" /> + <definition value="As defined by Eric Bruno"/> + </concept> + <concept> + <code value="application/vnd.stepmania.package" /> + <display value="vnd.stepmania.package" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="application/vnd.stepmania.stepchart" /> + <display value="vnd.stepmania.stepchart" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="application/vnd.street-stream" /> + <display value="vnd.street-stream" /> + <definition value="As defined by Glenn Levitt"/> + </concept> + <concept> + <code value="application/vnd.sun.wadl+xml" /> + <display value="vnd.sun.wadl+xml" /> + <definition value="As defined by Marc Hadley"/> + </concept> + <concept> + <code value="application/vnd.sus-calendar" /> + <display value="vnd.sus-calendar" /> + <definition value="As defined by Jonathan Niedfeldt"/> + </concept> + <concept> + <code value="application/vnd.svd" /> + <display value="vnd.svd" /> + <definition value="As defined by Scott Becker"/> + </concept> + <concept> + <code value="application/vnd.swiftview-ics" /> + <display value="vnd.swiftview-ics" /> + <definition value="As defined by Glenn Widener"/> + </concept> + <concept> + <code value="application/vnd.syncml.dm.notification" /> + <display value="vnd.syncml.dm.notification" /> + <definition value="As defined by Peter Thompson, and OMA-DM Work Group"/> + </concept> + <concept> + <code value="application/vnd.syncml.dmddf+xml" /> + <display value="vnd.syncml.dmddf+xml" /> + <definition value="As defined by OMA-DM Work Group"/> + </concept> + <concept> + <code value="application/vnd.syncml.dmtnds+wbxml" /> + <display value="vnd.syncml.dmtnds+wbxml" /> + <definition value="As defined by OMA-DM Work Group"/> + </concept> + <concept> + <code value="application/vnd.syncml.dmtnds+xml" /> + <display value="vnd.syncml.dmtnds+xml" /> + <definition value="As defined by OMA-DM Work Group"/> + </concept> + <concept> + <code value="application/vnd.syncml.dmddf+wbxml" /> + <display value="vnd.syncml.dmddf+wbxml" /> + <definition value="As defined by OMA-DM Work Group"/> + </concept> + <concept> + <code value="application/vnd.syncml.dm+wbxml" /> + <display value="vnd.syncml.dm+wbxml" /> + <definition value="As defined by OMA-DM Work Group"/> + </concept> + <concept> + <code value="application/vnd.syncml.dm+xml" /> + <display value="vnd.syncml.dm+xml" /> + <definition value="As defined by Bindu Rama Rao, and OMA-DM Work Group"/> + </concept> + <concept> + <code value="application/vnd.syncml.ds.notification" /> + <display value="vnd.syncml.ds.notification" /> + <definition value="As defined by OMA Data Synchronization Working Group"/> + </concept> + <concept> + <code value="application/vnd.syncml+xml" /> + <display value="vnd.syncml+xml" /> + <definition value="As defined by OMA Data Synchronization Working Group"/> + </concept> + <concept> + <code value="application/vnd.tableschema+json" /> + <display value="vnd.tableschema+json" /> + <definition value="As defined by Paul Walsh"/> + </concept> + <concept> + <code value="application/vnd.tao.intent-module-archive" /> + <display value="vnd.tao.intent-module-archive" /> + <definition value="As defined by Daniel Shelton"/> + </concept> + <concept> + <code value="application/vnd.tcpdump.pcap" /> + <display value="vnd.tcpdump.pcap" /> + <definition value="As defined by Guy Harris, and Glen Turner"/> + </concept> + <concept> + <code value="application/vnd.think-cell.ppttc+json" /> + <display value="vnd.think-cell.ppttc+json" /> + <definition value="As defined by Arno Schoedl"/> + </concept> + <concept> + <code value="application/vnd.tml" /> + <display value="vnd.tml" /> + <definition value="As defined by Joey Smith"/> + </concept> + <concept> + <code value="application/vnd.tmd.mediaflex.api+xml" /> + <display value="vnd.tmd.mediaflex.api+xml" /> + <definition value="As defined by Alex Sibilev"/> + </concept> + <concept> + <code value="application/vnd.tmobile-livetv" /> + <display value="vnd.tmobile-livetv" /> + <definition value="As defined by Nicolas Helin"/> + </concept> + <concept> + <code value="application/vnd.tri.onesource" /> + <display value="vnd.tri.onesource" /> + <definition value="As defined by Rick Rupp"/> + </concept> + <concept> + <code value="application/vnd.trid.tpt" /> + <display value="vnd.trid.tpt" /> + <definition value="As defined by Frank Cusack"/> + </concept> + <concept> + <code value="application/vnd.triscape.mxs" /> + <display value="vnd.triscape.mxs" /> + <definition value="As defined by Steven Simonoff"/> + </concept> + <concept> + <code value="application/vnd.trueapp" /> + <display value="vnd.trueapp" /> + <definition value="As defined by J. Scott Hepler"/> + </concept> + <concept> + <code value="application/vnd.truedoc" /> + <display value="vnd.truedoc" /> + <definition value="As defined by Brad Chase"/> + </concept> + <concept> + <code value="application/vnd.ubisoft.webplayer" /> + <display value="vnd.ubisoft.webplayer" /> + <definition value="As defined by Martin Talbot"/> + </concept> + <concept> + <code value="application/vnd.ufdl" /> + <display value="vnd.ufdl" /> + <definition value="As defined by Dave Manning"/> + </concept> + <concept> + <code value="application/vnd.uiq.theme" /> + <display value="vnd.uiq.theme" /> + <definition value="As defined by Tim Ocock"/> + </concept> + <concept> + <code value="application/vnd.umajin" /> + <display value="vnd.umajin" /> + <definition value="As defined by Jamie Riden"/> + </concept> + <concept> + <code value="application/vnd.unity" /> + <display value="vnd.unity" /> + <definition value="As defined by Unity3d"/> + </concept> + <concept> + <code value="application/vnd.uoml+xml" /> + <display value="vnd.uoml+xml" /> + <definition value="As defined by Arne Gerdes"/> + </concept> + <concept> + <code value="application/vnd.uplanet.alert" /> + <display value="vnd.uplanet.alert" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.alert-wbxml" /> + <display value="vnd.uplanet.alert-wbxml" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.bearer-choice" /> + <display value="vnd.uplanet.bearer-choice" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.bearer-choice-wbxml" /> + <display value="vnd.uplanet.bearer-choice-wbxml" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.cacheop" /> + <display value="vnd.uplanet.cacheop" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.cacheop-wbxml" /> + <display value="vnd.uplanet.cacheop-wbxml" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.channel" /> + <display value="vnd.uplanet.channel" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.channel-wbxml" /> + <display value="vnd.uplanet.channel-wbxml" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.list" /> + <display value="vnd.uplanet.list" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.listcmd" /> + <display value="vnd.uplanet.listcmd" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.listcmd-wbxml" /> + <display value="vnd.uplanet.listcmd-wbxml" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uplanet.list-wbxml" /> + <display value="vnd.uplanet.list-wbxml" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.uri-map" /> + <display value="vnd.uri-map" /> + <definition value="As defined by Sebastian Baer"/> + </concept> + <concept> + <code value="application/vnd.uplanet.signal" /> + <display value="vnd.uplanet.signal" /> + <definition value="As defined by Bruce Martin"/> + </concept> + <concept> + <code value="application/vnd.valve.source.material" /> + <display value="vnd.valve.source.material" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="application/vnd.vcx" /> + <display value="vnd.vcx" /> + <definition value="As defined by Taisuke Sugimoto"/> + </concept> + <concept> + <code value="application/vnd.vd-study" /> + <display value="vnd.vd-study" /> + <definition value="As defined by Luc Rogge"/> + </concept> + <concept> + <code value="application/vnd.vectorworks" /> + <display value="vnd.vectorworks" /> + <definition value="As defined by Lyndsey Ferguson, and Biplab Sarkar"/> + </concept> + <concept> + <code value="application/vnd.vel+json" /> + <display value="vnd.vel+json" /> + <definition value="As defined by James Wigger"/> + </concept> + <concept> + <code value="application/vnd.verimatrix.vcas" /> + <display value="vnd.verimatrix.vcas" /> + <definition value="As defined by Petr Peterka"/> + </concept> + <concept> + <code value="application/vnd.veryant.thin" /> + <display value="vnd.veryant.thin" /> + <definition value="As defined by Massimo Bertoli"/> + </concept> + <concept> + <code value="application/vnd.ves.encrypted" /> + <display value="vnd.ves.encrypted" /> + <definition value="As defined by Jim Zubov"/> + </concept> + <concept> + <code value="application/vnd.vidsoft.vidconference" /> + <display value="vnd.vidsoft.vidconference" /> + <definition value="As defined by Robert Hess"/> + </concept> + <concept> + <code value="application/vnd.visio" /> + <display value="vnd.visio" /> + <definition value="As defined by Troy Sandal"/> + </concept> + <concept> + <code value="application/vnd.visionary" /> + <display value="vnd.visionary" /> + <definition value="As defined by Gayatri Aravindakumar"/> + </concept> + <concept> + <code value="application/vnd.vividence.scriptfile" /> + <display value="vnd.vividence.scriptfile" /> + <definition value="As defined by Mark Risher"/> + </concept> + <concept> + <code value="application/vnd.vsf" /> + <display value="vnd.vsf" /> + <definition value="As defined by Delton Rowe"/> + </concept> + <concept> + <code value="application/vnd.wap.sic" /> + <display value="vnd.wap.sic" /> + <definition value="As defined by WAP-Forum"/> + </concept> + <concept> + <code value="application/vnd.wap.slc" /> + <display value="vnd.wap.slc" /> + <definition value="As defined by WAP-Forum"/> + </concept> + <concept> + <code value="application/vnd.wap.wbxml" /> + <display value="vnd.wap.wbxml" /> + <definition value="As defined by Peter Stark"/> + </concept> + <concept> + <code value="application/vnd.wap.wmlc" /> + <display value="vnd.wap.wmlc" /> + <definition value="As defined by Peter Stark"/> + </concept> + <concept> + <code value="application/vnd.wap.wmlscriptc" /> + <display value="vnd.wap.wmlscriptc" /> + <definition value="As defined by Peter Stark"/> + </concept> + <concept> + <code value="application/vnd.webturbo" /> + <display value="vnd.webturbo" /> + <definition value="As defined by Yaser Rehem"/> + </concept> + <concept> + <code value="application/vnd.wfa.p2p" /> + <display value="vnd.wfa.p2p" /> + <definition value="As defined by Mick Conley"/> + </concept> + <concept> + <code value="application/vnd.wfa.wsc" /> + <display value="vnd.wfa.wsc" /> + <definition value="As defined by Wi-Fi Alliance"/> + </concept> + <concept> + <code value="application/vnd.windows.devicepairing" /> + <display value="vnd.windows.devicepairing" /> + <definition value="As defined by Priya Dandawate"/> + </concept> + <concept> + <code value="application/vnd.wmc" /> + <display value="vnd.wmc" /> + <definition value="As defined by Thomas Kjornes"/> + </concept> + <concept> + <code value="application/vnd.wmf.bootstrap" /> + <display value="vnd.wmf.bootstrap" /> + <definition value="As defined by Thinh Nguyenphu, and Prakash Iyer"/> + </concept> + <concept> + <code value="application/vnd.wolfram.mathematica" /> + <display value="vnd.wolfram.mathematica" /> + <definition value="As defined by Wolfram"/> + </concept> + <concept> + <code value="application/vnd.wolfram.mathematica.package" /> + <display value="vnd.wolfram.mathematica.package" /> + <definition value="As defined by Wolfram"/> + </concept> + <concept> + <code value="application/vnd.wolfram.player" /> + <display value="vnd.wolfram.player" /> + <definition value="As defined by Wolfram"/> + </concept> + <concept> + <code value="application/vnd.wordperfect" /> + <display value="vnd.wordperfect" /> + <definition value="As defined by Kim Scarborough"/> + </concept> + <concept> + <code value="application/vnd.wqd" /> + <display value="vnd.wqd" /> + <definition value="As defined by Jan Bostrom"/> + </concept> + <concept> + <code value="application/vnd.wrq-hp3000-labelled" /> + <display value="vnd.wrq-hp3000-labelled" /> + <definition value="As defined by Chris Bartram"/> + </concept> + <concept> + <code value="application/vnd.wt.stf" /> + <display value="vnd.wt.stf" /> + <definition value="As defined by Bill Wohler"/> + </concept> + <concept> + <code value="application/vnd.wv.csp+xml" /> + <display value="vnd.wv.csp+xml" /> + <definition value="As defined by John Ingi Ingimundarson"/> + </concept> + <concept> + <code value="application/vnd.wv.csp+wbxml" /> + <display value="vnd.wv.csp+wbxml" /> + <definition value="As defined by Matti Salmi"/> + </concept> + <concept> + <code value="application/vnd.wv.ssp+xml" /> + <display value="vnd.wv.ssp+xml" /> + <definition value="As defined by John Ingi Ingimundarson"/> + </concept> + <concept> + <code value="application/vnd.xacml+json" /> + <display value="vnd.xacml+json" /> + <definition value="As defined by David Brossard"/> + </concept> + <concept> + <code value="application/vnd.xara" /> + <display value="vnd.xara" /> + <definition value="As defined by David Matthewman"/> + </concept> + <concept> + <code value="application/vnd.xfdl" /> + <display value="vnd.xfdl" /> + <definition value="As defined by Dave Manning"/> + </concept> + <concept> + <code value="application/vnd.xfdl.webform" /> + <display value="vnd.xfdl.webform" /> + <definition value="As defined by Michael Mansell"/> + </concept> + <concept> + <code value="application/vnd.xmi+xml" /> + <display value="vnd.xmi+xml" /> + <definition value="As defined by Fred Waskiewicz"/> + </concept> + <concept> + <code value="application/vnd.xmpie.cpkg" /> + <display value="vnd.xmpie.cpkg" /> + <definition value="As defined by Reuven Sherwin"/> + </concept> + <concept> + <code value="application/vnd.xmpie.dpkg" /> + <display value="vnd.xmpie.dpkg" /> + <definition value="As defined by Reuven Sherwin"/> + </concept> + <concept> + <code value="application/vnd.xmpie.plan" /> + <display value="vnd.xmpie.plan" /> + <definition value="As defined by Reuven Sherwin"/> + </concept> + <concept> + <code value="application/vnd.xmpie.ppkg" /> + <display value="vnd.xmpie.ppkg" /> + <definition value="As defined by Reuven Sherwin"/> + </concept> + <concept> + <code value="application/vnd.xmpie.xlim" /> + <display value="vnd.xmpie.xlim" /> + <definition value="As defined by Reuven Sherwin"/> + </concept> + <concept> + <code value="application/vnd.yamaha.hv-dic" /> + <display value="vnd.yamaha.hv-dic" /> + <definition value="As defined by Tomohiro Yamamoto"/> + </concept> + <concept> + <code value="application/vnd.yamaha.hv-script" /> + <display value="vnd.yamaha.hv-script" /> + <definition value="As defined by Tomohiro Yamamoto"/> + </concept> + <concept> + <code value="application/vnd.yamaha.hv-voice" /> + <display value="vnd.yamaha.hv-voice" /> + <definition value="As defined by Tomohiro Yamamoto"/> + </concept> + <concept> + <code value="application/vnd.yamaha.openscoreformat.osfpvg+xml" /> + <display value="vnd.yamaha.openscoreformat.osfpvg+xml" /> + <definition value="As defined by Mark Olleson"/> + </concept> + <concept> + <code value="application/vnd.yamaha.openscoreformat" /> + <display value="vnd.yamaha.openscoreformat" /> + <definition value="As defined by Mark Olleson"/> + </concept> + <concept> + <code value="application/vnd.yamaha.remote-setup" /> + <display value="vnd.yamaha.remote-setup" /> + <definition value="As defined by Takehiro Sukizaki"/> + </concept> + <concept> + <code value="application/vnd.yamaha.smaf-audio" /> + <display value="vnd.yamaha.smaf-audio" /> + <definition value="As defined by Keiichi Shinoda"/> + </concept> + <concept> + <code value="application/vnd.yamaha.smaf-phrase" /> + <display value="vnd.yamaha.smaf-phrase" /> + <definition value="As defined by Keiichi Shinoda"/> + </concept> + <concept> + <code value="application/vnd.yamaha.through-ngn" /> + <display value="vnd.yamaha.through-ngn" /> + <definition value="As defined by Takehiro Sukizaki"/> + </concept> + <concept> + <code value="application/vnd.yamaha.tunnel-udpencap" /> + <display value="vnd.yamaha.tunnel-udpencap" /> + <definition value="As defined by Takehiro Sukizaki"/> + </concept> + <concept> + <code value="application/vnd.yaoweme" /> + <display value="vnd.yaoweme" /> + <definition value="As defined by Jens Jorgensen"/> + </concept> + <concept> + <code value="application/vnd.yellowriver-custom-menu" /> + <display value="vnd.yellowriver-custom-menu" /> + <definition value="As defined by Mr. Yellow"/> + </concept> + <concept> + <code value="application/vnd.zul" /> + <display value="vnd.zul" /> + <definition value="As defined by Rene Grothmann"/> + </concept> + <concept> + <code value="application/vnd.zzazz.deck+xml" /> + <display value="vnd.zzazz.deck+xml" /> + <definition value="As defined by Micheal Hewett"/> + </concept> + <concept> + <code value="application/voicexml+xml" /> + <display value="voicexml+xml" /> + <definition value="As defined by rfc4267"/> + </concept> + <concept> + <code value="application/voucher-cms+json" /> + <display value="voucher-cms+json" /> + <definition value="As defined by rfc8366"/> + </concept> + <concept> + <code value="application/vq-rtcpxr" /> + <display value="vq-rtcpxr" /> + <definition value="As defined by rfc6035"/> + </concept> + <concept> + <code value="application/watcherinfo+xml" /> + <display value="watcherinfo+xml" /> + <definition value="As defined by rfc3858"/> + </concept> + <concept> + <code value="application/webpush-options+json" /> + <display value="webpush-options+json" /> + <definition value="As defined by rfc8292"/> + </concept> + <concept> + <code value="application/whoispp-query" /> + <display value="whoispp-query" /> + <definition value="As defined by rfc2957"/> + </concept> + <concept> + <code value="application/whoispp-response" /> + <display value="whoispp-response" /> + <definition value="As defined by rfc2958"/> + </concept> + <concept> + <code value="application/widget" /> + <display value="widget" /> + <definition value="As defined by W3C, Steven Pemberton, and http://www.w3.org/TR/widgets/#media-type-registration-for-application/widget"/> + </concept> + <concept> + <code value="application/wita" /> + <display value="wita" /> + <definition value="As defined by Larry Campbell"/> + </concept> + <concept> + <code value="application/wordperfect5.1" /> + <display value="wordperfect5.1" /> + <definition value="As defined by Paul Lindner"/> + </concept> + <concept> + <code value="application/wsdl+xml" /> + <display value="wsdl+xml" /> + <definition value="As defined by W3C"/> + </concept> + <concept> + <code value="application/wspolicy+xml" /> + <display value="wspolicy+xml" /> + <definition value="As defined by W3C"/> + </concept> + <concept> + <code value="application/x-pki-message" /> + <display value="x-pki-message" /> + <definition value="As defined by RFC-gutmann-scep-16"/> + </concept> + <concept> + <code value="application/x-www-form-urlencoded" /> + <display value="x-www-form-urlencoded" /> + <definition value="As defined by W3C, and Robin Berjon"/> + </concept> + <concept> + <code value="application/x-x509-ca-cert" /> + <display value="x-x509-ca-cert" /> + <definition value="As defined by RFC-gutmann-scep-16"/> + </concept> + <concept> + <code value="application/x-x509-ca-ra-cert" /> + <display value="x-x509-ca-ra-cert" /> + <definition value="As defined by RFC-gutmann-scep-16"/> + </concept> + <concept> + <code value="application/x-x509-next-ca-cert" /> + <display value="x-x509-next-ca-cert" /> + <definition value="As defined by RFC-gutmann-scep-16"/> + </concept> + <concept> + <code value="application/x400-bp" /> + <display value="x400-bp" /> + <definition value="As defined by rfc1494"/> + </concept> + <concept> + <code value="application/xacml+xml" /> + <display value="xacml+xml" /> + <definition value="As defined by rfc7061"/> + </concept> + <concept> + <code value="application/xcap-att+xml" /> + <display value="xcap-att+xml" /> + <definition value="As defined by rfc4825"/> + </concept> + <concept> + <code value="application/xcap-caps+xml" /> + <display value="xcap-caps+xml" /> + <definition value="As defined by rfc4825"/> + </concept> + <concept> + <code value="application/xcap-diff+xml" /> + <display value="xcap-diff+xml" /> + <definition value="As defined by rfc5874"/> + </concept> + <concept> + <code value="application/xcap-el+xml" /> + <display value="xcap-el+xml" /> + <definition value="As defined by rfc4825"/> + </concept> + <concept> + <code value="application/xcap-error+xml" /> + <display value="xcap-error+xml" /> + <definition value="As defined by rfc4825"/> + </concept> + <concept> + <code value="application/xcap-ns+xml" /> + <display value="xcap-ns+xml" /> + <definition value="As defined by rfc4825"/> + </concept> + <concept> + <code value="application/xcon-conference-info-diff+xml" /> + <display value="xcon-conference-info-diff+xml" /> + <definition value="As defined by rfc6502"/> + </concept> + <concept> + <code value="application/xcon-conference-info+xml" /> + <display value="xcon-conference-info+xml" /> + <definition value="As defined by rfc6502"/> + </concept> + <concept> + <code value="application/xenc+xml" /> + <display value="xenc+xml" /> + <definition value="As defined by Joseph Reagle, and XENC Working Group"/> + </concept> + <concept> + <code value="application/xhtml+xml" /> + <display value="xhtml+xml" /> + <definition value="As defined by W3C, and Robin Berjon"/> + </concept> + <concept> + <code value="application/xliff+xml" /> + <display value="xliff+xml" /> + <definition value="As defined by OASIS, and Chet Ensign"/> + </concept> + <concept> + <code value="application/xml" /> + <display value="xml" /> + <definition value="As defined by rfc7303"/> + </concept> + <concept> + <code value="application/xml-dtd" /> + <display value="xml-dtd" /> + <definition value="As defined by rfc7303"/> + </concept> + <concept> + <code value="application/xml-external-parsed-entity" /> + <display value="xml-external-parsed-entity" /> + <definition value="As defined by rfc7303"/> + </concept> + <concept> + <code value="application/xml-patch+xml" /> + <display value="xml-patch+xml" /> + <definition value="As defined by rfc7351"/> + </concept> + <concept> + <code value="application/xmpp+xml" /> + <display value="xmpp+xml" /> + <definition value="As defined by rfc3923"/> + </concept> + <concept> + <code value="application/xop+xml" /> + <display value="xop+xml" /> + <definition value="As defined by Mark Nottingham"/> + </concept> + <concept> + <code value="application/xslt+xml" /> + <display value="xslt+xml" /> + <definition value="As defined by W3C, and http://www.w3.org/TR/2007/REC-xslt20-20070123/#media-type-registration"/> + </concept> + <concept> + <code value="application/xv+xml" /> + <display value="xv+xml" /> + <definition value="As defined by rfc4374"/> + </concept> + <concept> + <code value="application/yang" /> + <display value="yang" /> + <definition value="As defined by rfc6020"/> + </concept> + <concept> + <code value="application/yang-data+json" /> + <display value="yang-data+json" /> + <definition value="As defined by rfc8040"/> + </concept> + <concept> + <code value="application/yang-data+xml" /> + <display value="yang-data+xml" /> + <definition value="As defined by rfc8040"/> + </concept> + <concept> + <code value="application/yang-patch+json" /> + <display value="yang-patch+json" /> + <definition value="As defined by rfc8072"/> + </concept> + <concept> + <code value="application/yang-patch+xml" /> + <display value="yang-patch+xml" /> + <definition value="As defined by rfc8072"/> + </concept> + <concept> + <code value="application/yin+xml" /> + <display value="yin+xml" /> + <definition value="As defined by rfc6020"/> + </concept> + <concept> + <code value="application/zip" /> + <display value="zip" /> + <definition value="As defined by Paul Lindner"/> + </concept> + <concept> + <code value="application/zlib" /> + <display value="zlib" /> + <definition value="As defined by rfc6713"/> + </concept> + <concept> + <code value="application/zstd" /> + <display value="zstd" /> + <definition value="As defined by RFC-kucherawy-rfc8478bis-05"/> + </concept> + <concept> + <code value="audio/1d-interleaved-parityfec" /> + <display value="1d-interleaved-parityfec" /> + <definition value="As defined by rfc6015"/> + </concept> + <concept> + <code value="audio/32kadpcm" /> + <display value="32kadpcm" /> + <definition value="As defined by rfc3802, and rfc2421"/> + </concept> + <concept> + <code value="audio/3gpp" /> + <display value="3gpp" /> + <definition value="As defined by rfc3839, and rfc6381"/> + </concept> + <concept> + <code value="audio/3gpp2" /> + <display value="3gpp2" /> + <definition value="As defined by rfc4393, and rfc6381"/> + </concept> + <concept> + <code value="audio/aac" /> + <display value="aac" /> + <definition value="As defined by ISO-IEC JTC1, and Max Neuendorf"/> + </concept> + <concept> + <code value="audio/ac3" /> + <display value="ac3" /> + <definition value="As defined by rfc4184"/> + </concept> + <concept> + <code value="audio/AMR" /> + <display value="AMR" /> + <definition value="As defined by rfc4867"/> + </concept> + <concept> + <code value="audio/AMR-WB" /> + <display value="AMR-WB" /> + <definition value="As defined by rfc4867"/> + </concept> + <concept> + <code value="audio/amr-wb+" /> + <display value="amr-wb+" /> + <definition value="As defined by rfc4352"/> + </concept> + <concept> + <code value="audio/aptx" /> + <display value="aptx" /> + <definition value="As defined by rfc7310"/> + </concept> + <concept> + <code value="audio/asc" /> + <display value="asc" /> + <definition value="As defined by rfc6295"/> + </concept> + <concept> + <code value="audio/ATRAC-ADVANCED-LOSSLESS" /> + <display value="ATRAC-ADVANCED-LOSSLESS" /> + <definition value="As defined by rfc5584"/> + </concept> + <concept> + <code value="audio/ATRAC-X" /> + <display value="ATRAC-X" /> + <definition value="As defined by rfc5584"/> + </concept> + <concept> + <code value="audio/ATRAC3" /> + <display value="ATRAC3" /> + <definition value="As defined by rfc5584"/> + </concept> + <concept> + <code value="audio/basic" /> + <display value="basic" /> + <definition value="As defined by rfc2045, and rfc2046"/> + </concept> + <concept> + <code value="audio/BV16" /> + <display value="BV16" /> + <definition value="As defined by rfc4298"/> + </concept> + <concept> + <code value="audio/BV32" /> + <display value="BV32" /> + <definition value="As defined by rfc4298"/> + </concept> + <concept> + <code value="audio/clearmode" /> + <display value="clearmode" /> + <definition value="As defined by rfc4040"/> + </concept> + <concept> + <code value="audio/CN" /> + <display value="CN" /> + <definition value="As defined by rfc3389"/> + </concept> + <concept> + <code value="audio/DAT12" /> + <display value="DAT12" /> + <definition value="As defined by rfc3190"/> + </concept> + <concept> + <code value="audio/dls" /> + <display value="dls" /> + <definition value="As defined by rfc4613"/> + </concept> + <concept> + <code value="audio/dsr-es201108" /> + <display value="dsr-es201108" /> + <definition value="As defined by rfc3557"/> + </concept> + <concept> + <code value="audio/dsr-es202050" /> + <display value="dsr-es202050" /> + <definition value="As defined by rfc4060"/> + </concept> + <concept> + <code value="audio/dsr-es202211" /> + <display value="dsr-es202211" /> + <definition value="As defined by rfc4060"/> + </concept> + <concept> + <code value="audio/dsr-es202212" /> + <display value="dsr-es202212" /> + <definition value="As defined by rfc4060"/> + </concept> + <concept> + <code value="audio/DV" /> + <display value="DV" /> + <definition value="As defined by rfc6469"/> + </concept> + <concept> + <code value="audio/DVI4" /> + <display value="DVI4" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/eac3" /> + <display value="eac3" /> + <definition value="As defined by rfc4598"/> + </concept> + <concept> + <code value="audio/encaprtp" /> + <display value="encaprtp" /> + <definition value="As defined by rfc6849"/> + </concept> + <concept> + <code value="audio/EVRC" /> + <display value="EVRC" /> + <definition value="As defined by rfc4788"/> + </concept> + <concept> + <code value="audio/EVRC-QCP" /> + <display value="EVRC-QCP" /> + <definition value="As defined by rfc3625"/> + </concept> + <concept> + <code value="audio/EVRC0" /> + <display value="EVRC0" /> + <definition value="As defined by rfc4788"/> + </concept> + <concept> + <code value="audio/EVRC1" /> + <display value="EVRC1" /> + <definition value="As defined by rfc4788"/> + </concept> + <concept> + <code value="audio/EVRCB" /> + <display value="EVRCB" /> + <definition value="As defined by rfc5188"/> + </concept> + <concept> + <code value="audio/EVRCB0" /> + <display value="EVRCB0" /> + <definition value="As defined by rfc5188"/> + </concept> + <concept> + <code value="audio/EVRCB1" /> + <display value="EVRCB1" /> + <definition value="As defined by rfc4788"/> + </concept> + <concept> + <code value="audio/EVRCNW" /> + <display value="EVRCNW" /> + <definition value="As defined by rfc6884"/> + </concept> + <concept> + <code value="audio/EVRCNW0" /> + <display value="EVRCNW0" /> + <definition value="As defined by rfc6884"/> + </concept> + <concept> + <code value="audio/EVRCNW1" /> + <display value="EVRCNW1" /> + <definition value="As defined by rfc6884"/> + </concept> + <concept> + <code value="audio/EVRCWB" /> + <display value="EVRCWB" /> + <definition value="As defined by rfc5188"/> + </concept> + <concept> + <code value="audio/EVRCWB0" /> + <display value="EVRCWB0" /> + <definition value="As defined by rfc5188"/> + </concept> + <concept> + <code value="audio/EVRCWB1" /> + <display value="EVRCWB1" /> + <definition value="As defined by rfc5188"/> + </concept> + <concept> + <code value="audio/EVS" /> + <display value="EVS" /> + <definition value="As defined by 3GPP, and Kyunghun Jung"/> + </concept> + <concept> + <code value="audio/example" /> + <display value="example" /> + <definition value="As defined by rfc4735"/> + </concept> + <concept> + <code value="audio/flexfec" /> + <display value="flexfec" /> + <definition value="As defined by rfc8627"/> + </concept> + <concept> + <code value="audio/fwdred" /> + <display value="fwdred" /> + <definition value="As defined by rfc6354"/> + </concept> + <concept> + <code value="audio/G711-0" /> + <display value="G711-0" /> + <definition value="As defined by rfc7655"/> + </concept> + <concept> + <code value="audio/G719" /> + <display value="G719" /> + <definition value="As defined by rfc5404, and 3245"/> + </concept> + <concept> + <code value="audio/G7221" /> + <display value="G7221" /> + <definition value="As defined by rfc5577"/> + </concept> + <concept> + <code value="audio/G722" /> + <display value="G722" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/G723" /> + <display value="G723" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/G726-16" /> + <display value="G726-16" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/G726-24" /> + <display value="G726-24" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/G726-32" /> + <display value="G726-32" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/G726-40" /> + <display value="G726-40" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/G728" /> + <display value="G728" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/G729" /> + <display value="G729" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/G7291" /> + <display value="G7291" /> + <definition value="As defined by rfc4749, and rfc5459"/> + </concept> + <concept> + <code value="audio/G729D" /> + <display value="G729D" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/G729E" /> + <display value="G729E" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/GSM" /> + <display value="GSM" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/GSM-EFR" /> + <display value="GSM-EFR" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/GSM-HR-08" /> + <display value="GSM-HR-08" /> + <definition value="As defined by rfc5993"/> + </concept> + <concept> + <code value="audio/iLBC" /> + <display value="iLBC" /> + <definition value="As defined by rfc3952"/> + </concept> + <concept> + <code value="audio/ip-mr_v2.5" /> + <display value="ip-mr_v2.5" /> + <definition value="As defined by rfc6262"/> + </concept> + <concept> + <code value="audio/L8" /> + <display value="L8" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/L16" /> + <display value="L16" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/L20" /> + <display value="L20" /> + <definition value="As defined by rfc3190"/> + </concept> + <concept> + <code value="audio/L24" /> + <display value="L24" /> + <definition value="As defined by rfc3190"/> + </concept> + <concept> + <code value="audio/LPC" /> + <display value="LPC" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/MELP" /> + <display value="MELP" /> + <definition value="As defined by rfc8130"/> + </concept> + <concept> + <code value="audio/MELP600" /> + <display value="MELP600" /> + <definition value="As defined by rfc8130"/> + </concept> + <concept> + <code value="audio/MELP1200" /> + <display value="MELP1200" /> + <definition value="As defined by rfc8130"/> + </concept> + <concept> + <code value="audio/MELP2400" /> + <display value="MELP2400" /> + <definition value="As defined by rfc8130"/> + </concept> + <concept> + <code value="audio/mhas" /> + <display value="mhas" /> + <definition value="As defined by ISO-IEC JTC1, Nils Peters, and Ingo Hofmann"/> + </concept> + <concept> + <code value="audio/mobile-xmf" /> + <display value="mobile-xmf" /> + <definition value="As defined by rfc4723"/> + </concept> + <concept> + <code value="audio/MPA" /> + <display value="MPA" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="audio/mp4" /> + <display value="mp4" /> + <definition value="As defined by rfc4337, and rfc6381"/> + </concept> + <concept> + <code value="audio/MP4A-LATM" /> + <display value="MP4A-LATM" /> + <definition value="As defined by rfc6416"/> + </concept> + <concept> + <code value="audio/mpa-robust" /> + <display value="mpa-robust" /> + <definition value="As defined by rfc5219"/> + </concept> + <concept> + <code value="audio/mpeg" /> + <display value="mpeg" /> + <definition value="As defined by rfc3003"/> + </concept> + <concept> + <code value="audio/mpeg4-generic" /> + <display value="mpeg4-generic" /> + <definition value="As defined by rfc3640, rfc5691, and rfc6295"/> + </concept> + <concept> + <code value="audio/ogg" /> + <display value="ogg" /> + <definition value="As defined by rfc5334, and rfc7845"/> + </concept> + <concept> + <code value="audio/opus" /> + <display value="opus" /> + <definition value="As defined by rfc7587"/> + </concept> + <concept> + <code value="audio/parityfec" /> + <display value="parityfec" /> + <definition value="As defined by rfc5109"/> + </concept> + <concept> + <code value="audio/PCMA" /> + <display value="PCMA" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/PCMA-WB" /> + <display value="PCMA-WB" /> + <definition value="As defined by rfc5391"/> + </concept> + <concept> + <code value="audio/PCMU" /> + <display value="PCMU" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/PCMU-WB" /> + <display value="PCMU-WB" /> + <definition value="As defined by rfc5391"/> + </concept> + <concept> + <code value="audio/prs.sid" /> + <display value="prs.sid" /> + <definition value="As defined by Linus Walleij"/> + </concept> + <concept> + <code value="audio/QCELP" /> + <display value="QCELP" /> + <definition value="As defined by rfc3555, and rfc3625"/> + </concept> + <concept> + <code value="audio/raptorfec" /> + <display value="raptorfec" /> + <definition value="As defined by rfc6682"/> + </concept> + <concept> + <code value="audio/RED" /> + <display value="RED" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="audio/rtp-enc-aescm128" /> + <display value="rtp-enc-aescm128" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="audio/rtploopback" /> + <display value="rtploopback" /> + <definition value="As defined by rfc6849"/> + </concept> + <concept> + <code value="audio/rtp-midi" /> + <display value="rtp-midi" /> + <definition value="As defined by rfc6295"/> + </concept> + <concept> + <code value="audio/rtx" /> + <display value="rtx" /> + <definition value="As defined by rfc4588"/> + </concept> + <concept> + <code value="audio/SMV" /> + <display value="SMV" /> + <definition value="As defined by rfc3558"/> + </concept> + <concept> + <code value="audio/SMV0" /> + <display value="SMV0" /> + <definition value="As defined by rfc3558"/> + </concept> + <concept> + <code value="audio/SMV-QCP" /> + <display value="SMV-QCP" /> + <definition value="As defined by rfc3625"/> + </concept> + <concept> + <code value="audio/sp-midi" /> + <display value="sp-midi" /> + <definition value="As defined by Timo Kosonen, and Tom White"/> + </concept> + <concept> + <code value="audio/speex" /> + <display value="speex" /> + <definition value="As defined by rfc5574"/> + </concept> + <concept> + <code value="audio/t140c" /> + <display value="t140c" /> + <definition value="As defined by rfc4351"/> + </concept> + <concept> + <code value="audio/t38" /> + <display value="t38" /> + <definition value="As defined by rfc4612"/> + </concept> + <concept> + <code value="audio/telephone-event" /> + <display value="telephone-event" /> + <definition value="As defined by rfc4733"/> + </concept> + <concept> + <code value="audio/TETRA_ACELP" /> + <display value="TETRA_ACELP" /> + <definition value="As defined by ETSI, and Miguel Angel Reina Ortega"/> + </concept> + <concept> + <code value="audio/TETRA_ACELP_BB" /> + <display value="TETRA_ACELP_BB" /> + <definition value="As defined by ETSI, and Miguel Angel Reina Ortega"/> + </concept> + <concept> + <code value="audio/tone" /> + <display value="tone" /> + <definition value="As defined by rfc4733"/> + </concept> + <concept> + <code value="audio/UEMCLIP" /> + <display value="UEMCLIP" /> + <definition value="As defined by rfc5686"/> + </concept> + <concept> + <code value="audio/ulpfec" /> + <display value="ulpfec" /> + <definition value="As defined by rfc5109"/> + </concept> + <concept> + <code value="audio/usac" /> + <display value="usac" /> + <definition value="As defined by ISO-IEC JTC1, and Max Neuendorf"/> + </concept> + <concept> + <code value="audio/VDVI" /> + <display value="VDVI" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="audio/VMR-WB" /> + <display value="VMR-WB" /> + <definition value="As defined by rfc4348, and rfc4424"/> + </concept> + <concept> + <code value="audio/vnd.3gpp.iufp" /> + <display value="vnd.3gpp.iufp" /> + <definition value="As defined by Thomas Belling"/> + </concept> + <concept> + <code value="audio/vnd.4SB" /> + <display value="vnd.4SB" /> + <definition value="As defined by Serge De Jaham"/> + </concept> + <concept> + <code value="audio/vnd.audiokoz" /> + <display value="vnd.audiokoz" /> + <definition value="As defined by Vicki DeBarros"/> + </concept> + <concept> + <code value="audio/vnd.CELP" /> + <display value="vnd.CELP" /> + <definition value="As defined by Serge De Jaham"/> + </concept> + <concept> + <code value="audio/vnd.cisco.nse" /> + <display value="vnd.cisco.nse" /> + <definition value="As defined by Rajesh Kumar"/> + </concept> + <concept> + <code value="audio/vnd.cmles.radio-events" /> + <display value="vnd.cmles.radio-events" /> + <definition value="As defined by Jean-Philippe Goulet"/> + </concept> + <concept> + <code value="audio/vnd.cns.anp1" /> + <display value="vnd.cns.anp1" /> + <definition value="As defined by Ann McLaughlin"/> + </concept> + <concept> + <code value="audio/vnd.cns.inf1" /> + <display value="vnd.cns.inf1" /> + <definition value="As defined by Ann McLaughlin"/> + </concept> + <concept> + <code value="audio/vnd.dece.audio" /> + <display value="vnd.dece.audio" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="audio/vnd.digital-winds" /> + <display value="vnd.digital-winds" /> + <definition value="As defined by Armands Strazds"/> + </concept> + <concept> + <code value="audio/vnd.dlna.adts" /> + <display value="vnd.dlna.adts" /> + <definition value="As defined by Edwin Heredia"/> + </concept> + <concept> + <code value="audio/vnd.dolby.heaac.1" /> + <display value="vnd.dolby.heaac.1" /> + <definition value="As defined by Steve Hattersley"/> + </concept> + <concept> + <code value="audio/vnd.dolby.heaac.2" /> + <display value="vnd.dolby.heaac.2" /> + <definition value="As defined by Steve Hattersley"/> + </concept> + <concept> + <code value="audio/vnd.dolby.mlp" /> + <display value="vnd.dolby.mlp" /> + <definition value="As defined by Mike Ward"/> + </concept> + <concept> + <code value="audio/vnd.dolby.mps" /> + <display value="vnd.dolby.mps" /> + <definition value="As defined by Steve Hattersley"/> + </concept> + <concept> + <code value="audio/vnd.dolby.pl2" /> + <display value="vnd.dolby.pl2" /> + <definition value="As defined by Steve Hattersley"/> + </concept> + <concept> + <code value="audio/vnd.dolby.pl2x" /> + <display value="vnd.dolby.pl2x" /> + <definition value="As defined by Steve Hattersley"/> + </concept> + <concept> + <code value="audio/vnd.dolby.pl2z" /> + <display value="vnd.dolby.pl2z" /> + <definition value="As defined by Steve Hattersley"/> + </concept> + <concept> + <code value="audio/vnd.dolby.pulse.1" /> + <display value="vnd.dolby.pulse.1" /> + <definition value="As defined by Steve Hattersley"/> + </concept> + <concept> + <code value="audio/vnd.dra" /> + <display value="vnd.dra" /> + <definition value="As defined by Jiang Tian"/> + </concept> + <concept> + <code value="audio/vnd.dts" /> + <display value="vnd.dts" /> + <definition value="As defined by William Zou"/> + </concept> + <concept> + <code value="audio/vnd.dts.hd" /> + <display value="vnd.dts.hd" /> + <definition value="As defined by William Zou"/> + </concept> + <concept> + <code value="audio/vnd.dts.uhd" /> + <display value="vnd.dts.uhd" /> + <definition value="As defined by Phillip Maness"/> + </concept> + <concept> + <code value="audio/vnd.dvb.file" /> + <display value="vnd.dvb.file" /> + <definition value="As defined by Peter Siebert"/> + </concept> + <concept> + <code value="audio/vnd.everad.plj" /> + <display value="vnd.everad.plj" /> + <definition value="As defined by Shay Cicelsky"/> + </concept> + <concept> + <code value="audio/vnd.hns.audio" /> + <display value="vnd.hns.audio" /> + <definition value="As defined by Swaminathan"/> + </concept> + <concept> + <code value="audio/vnd.lucent.voice" /> + <display value="vnd.lucent.voice" /> + <definition value="As defined by Greg Vaudreuil"/> + </concept> + <concept> + <code value="audio/vnd.ms-playready.media.pya" /> + <display value="vnd.ms-playready.media.pya" /> + <definition value="As defined by Steve DiAcetis"/> + </concept> + <concept> + <code value="audio/vnd.nokia.mobile-xmf" /> + <display value="vnd.nokia.mobile-xmf" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="audio/vnd.nortel.vbk" /> + <display value="vnd.nortel.vbk" /> + <definition value="As defined by Glenn Parsons"/> + </concept> + <concept> + <code value="audio/vnd.nuera.ecelp4800" /> + <display value="vnd.nuera.ecelp4800" /> + <definition value="As defined by Michael Fox"/> + </concept> + <concept> + <code value="audio/vnd.nuera.ecelp7470" /> + <display value="vnd.nuera.ecelp7470" /> + <definition value="As defined by Michael Fox"/> + </concept> + <concept> + <code value="audio/vnd.nuera.ecelp9600" /> + <display value="vnd.nuera.ecelp9600" /> + <definition value="As defined by Michael Fox"/> + </concept> + <concept> + <code value="audio/vnd.octel.sbc" /> + <display value="vnd.octel.sbc" /> + <definition value="As defined by Greg Vaudreuil"/> + </concept> + <concept> + <code value="audio/vnd.presonus.multitrack" /> + <display value="vnd.presonus.multitrack" /> + <definition value="As defined by Matthias Juwan"/> + </concept> + <concept> + <code value="audio/vnd.qcelp - DEPRECATED in favor of audio/qcelp" /> + <display value="vnd.qcelp - DEPRECATED in favor of audio/qcelp" /> + <definition value="As defined by rfc3625"/> + </concept> + <concept> + <code value="audio/vnd.rhetorex.32kadpcm" /> + <display value="vnd.rhetorex.32kadpcm" /> + <definition value="As defined by Greg Vaudreuil"/> + </concept> + <concept> + <code value="audio/vnd.rip" /> + <display value="vnd.rip" /> + <definition value="As defined by Martin Dawe"/> + </concept> + <concept> + <code value="audio/vnd.sealedmedia.softseal.mpeg" /> + <display value="vnd.sealedmedia.softseal.mpeg" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="audio/vnd.vmx.cvsd" /> + <display value="vnd.vmx.cvsd" /> + <definition value="As defined by Greg Vaudreuil"/> + </concept> + <concept> + <code value="audio/vorbis" /> + <display value="vorbis" /> + <definition value="As defined by rfc5215"/> + </concept> + <concept> + <code value="audio/vorbis-config" /> + <display value="vorbis-config" /> + <definition value="As defined by rfc5215"/> + </concept> + <concept> + <code value="font/collection" /> + <display value="collection" /> + <definition value="As defined by rfc8081"/> + </concept> + <concept> + <code value="font/otf" /> + <display value="otf" /> + <definition value="As defined by rfc8081"/> + </concept> + <concept> + <code value="font/sfnt" /> + <display value="sfnt" /> + <definition value="As defined by rfc8081"/> + </concept> + <concept> + <code value="font/ttf" /> + <display value="ttf" /> + <definition value="As defined by rfc8081"/> + </concept> + <concept> + <code value="font/woff" /> + <display value="woff" /> + <definition value="As defined by rfc8081"/> + </concept> + <concept> + <code value="font/woff2" /> + <display value="woff2" /> + <definition value="As defined by rfc8081"/> + </concept> + <concept> + <code value="image/aces" /> + <display value="aces" /> + <definition value="As defined by SMPTE, and Howard Lukk"/> + </concept> + <concept> + <code value="image/avci" /> + <display value="avci" /> + <definition value="As defined by ISO-IEC JTC1, and David Singer"/> + </concept> + <concept> + <code value="image/avcs" /> + <display value="avcs" /> + <definition value="As defined by ISO-IEC JTC1, and David Singer"/> + </concept> + <concept> + <code value="image/bmp" /> + <display value="bmp" /> + <definition value="As defined by rfc7903"/> + </concept> + <concept> + <code value="image/cgm" /> + <display value="cgm" /> + <definition value="As defined by Alan Francis"/> + </concept> + <concept> + <code value="image/dicom-rle" /> + <display value="dicom-rle" /> + <definition value="As defined by DICOM Standards Committee, and David Clunie"/> + </concept> + <concept> + <code value="image/emf" /> + <display value="emf" /> + <definition value="As defined by rfc7903"/> + </concept> + <concept> + <code value="image/example" /> + <display value="example" /> + <definition value="As defined by rfc4735"/> + </concept> + <concept> + <code value="image/fits" /> + <display value="fits" /> + <definition value="As defined by rfc4047"/> + </concept> + <concept> + <code value="image/g3fax" /> + <display value="g3fax" /> + <definition value="As defined by rfc1494"/> + </concept> + <concept> + <code value="image/gif" /> + <display value="gif" /> + <definition value="As defined by rfc2045, and rfc2046"/> + </concept> + <concept> + <code value="image/heic" /> + <display value="heic" /> + <definition value="As defined by ISO-IEC JTC1, and David Singer"/> + </concept> + <concept> + <code value="image/heic-sequence" /> + <display value="heic-sequence" /> + <definition value="As defined by ISO-IEC JTC1, and David Singer"/> + </concept> + <concept> + <code value="image/heif" /> + <display value="heif" /> + <definition value="As defined by ISO-IEC JTC1, and David Singer"/> + </concept> + <concept> + <code value="image/heif-sequence" /> + <display value="heif-sequence" /> + <definition value="As defined by ISO-IEC JTC1, and David Singer"/> + </concept> + <concept> + <code value="image/hej2k" /> + <display value="hej2k" /> + <definition value="As defined by ISO-IEC JTC1, and ITU-T"/> + </concept> + <concept> + <code value="image/hsj2" /> + <display value="hsj2" /> + <definition value="As defined by ISO-IEC JTC1, and ITU-T"/> + </concept> + <concept> + <code value="image/ief" /> + <display value="ief" /> + <definition value="As defined by rfc1314"/> + </concept> + <concept> + <code value="image/jls" /> + <display value="jls" /> + <definition value="As defined by DICOM Standards Committee, and David Clunie"/> + </concept> + <concept> + <code value="image/jp2" /> + <display value="jp2" /> + <definition value="As defined by rfc3745"/> + </concept> + <concept> + <code value="image/jpeg" /> + <display value="jpeg" /> + <definition value="As defined by rfc2045, and rfc2046"/> + </concept> + <concept> + <code value="image/jph" /> + <display value="jph" /> + <definition value="As defined by ISO-IEC JTC1, and ITU-T"/> + </concept> + <concept> + <code value="image/jphc" /> + <display value="jphc" /> + <definition value="As defined by ISO-IEC JTC1, and ITU-T"/> + </concept> + <concept> + <code value="image/jpm" /> + <display value="jpm" /> + <definition value="As defined by rfc3745"/> + </concept> + <concept> + <code value="image/jpx" /> + <display value="jpx" /> + <definition value="As defined by rfc3745"/> + </concept> + <concept> + <code value="image/jxr" /> + <display value="jxr" /> + <definition value="As defined by ISO-IEC JTC1, and ITU-T"/> + </concept> + <concept> + <code value="image/jxrA" /> + <display value="jxrA" /> + <definition value="As defined by ISO-IEC JTC1, and ITU-T"/> + </concept> + <concept> + <code value="image/jxrS" /> + <display value="jxrS" /> + <definition value="As defined by ISO-IEC JTC1, and ITU-T"/> + </concept> + <concept> + <code value="image/jxs" /> + <display value="jxs" /> + <definition value="As defined by ISO-IEC JTC1"/> + </concept> + <concept> + <code value="image/jxsc" /> + <display value="jxsc" /> + <definition value="As defined by ISO-IEC JTC1"/> + </concept> + <concept> + <code value="image/jxsi" /> + <display value="jxsi" /> + <definition value="As defined by ISO-IEC JTC1"/> + </concept> + <concept> + <code value="image/jxss" /> + <display value="jxss" /> + <definition value="As defined by ISO-IEC JTC1"/> + </concept> + <concept> + <code value="image/ktx" /> + <display value="ktx" /> + <definition value="As defined by Khronos, Mark Callow, and http://www.khronos.org/opengles/sdk/tools/KTX/file format spec/#mimeregistration"/> + </concept> + <concept> + <code value="image/naplps" /> + <display value="naplps" /> + <definition value="As defined by Ilya Ferber"/> + </concept> + <concept> + <code value="image/png" /> + <display value="png" /> + <definition value="As defined by Glenn Randers-Pehrson"/> + </concept> + <concept> + <code value="image/prs.btif" /> + <display value="prs.btif" /> + <definition value="As defined by Ben Simon"/> + </concept> + <concept> + <code value="image/prs.pti" /> + <display value="prs.pti" /> + <definition value="As defined by Juern Laun"/> + </concept> + <concept> + <code value="image/pwg-raster" /> + <display value="pwg-raster" /> + <definition value="As defined by Michael Sweet"/> + </concept> + <concept> + <code value="image/svg+xml" /> + <display value="svg+xml" /> + <definition value="As defined by W3C, and http://www.w3.org/TR/SVG/mimereg.html"/> + </concept> + <concept> + <code value="image/t38" /> + <display value="t38" /> + <definition value="As defined by rfc3362"/> + </concept> + <concept> + <code value="image/tiff" /> + <display value="tiff" /> + <definition value="As defined by rfc3302"/> + </concept> + <concept> + <code value="image/tiff-fx" /> + <display value="tiff-fx" /> + <definition value="As defined by rfc3950"/> + </concept> + <concept> + <code value="image/vnd.adobe.photoshop" /> + <display value="vnd.adobe.photoshop" /> + <definition value="As defined by Kim Scarborough"/> + </concept> + <concept> + <code value="image/vnd.airzip.accelerator.azv" /> + <display value="vnd.airzip.accelerator.azv" /> + <definition value="As defined by Gary Clueit"/> + </concept> + <concept> + <code value="image/vnd.cns.inf2" /> + <display value="vnd.cns.inf2" /> + <definition value="As defined by Ann McLaughlin"/> + </concept> + <concept> + <code value="image/vnd.dece.graphic" /> + <display value="vnd.dece.graphic" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="image/vnd.djvu" /> + <display value="vnd.djvu" /> + <definition value="As defined by Leon Bottou"/> + </concept> + <concept> + <code value="image/vnd.dwg" /> + <display value="vnd.dwg" /> + <definition value="As defined by Jodi Moline"/> + </concept> + <concept> + <code value="image/vnd.dxf" /> + <display value="vnd.dxf" /> + <definition value="As defined by Jodi Moline"/> + </concept> + <concept> + <code value="image/vnd.dvb.subtitle" /> + <display value="vnd.dvb.subtitle" /> + <definition value="As defined by Peter Siebert, and Michael Lagally"/> + </concept> + <concept> + <code value="image/vnd.fastbidsheet" /> + <display value="vnd.fastbidsheet" /> + <definition value="As defined by Scott Becker"/> + </concept> + <concept> + <code value="image/vnd.fpx" /> + <display value="vnd.fpx" /> + <definition value="As defined by Marc Douglas Spencer"/> + </concept> + <concept> + <code value="image/vnd.fst" /> + <display value="vnd.fst" /> + <definition value="As defined by Arild Fuldseth"/> + </concept> + <concept> + <code value="image/vnd.fujixerox.edmics-mmr" /> + <display value="vnd.fujixerox.edmics-mmr" /> + <definition value="As defined by Masanori Onda"/> + </concept> + <concept> + <code value="image/vnd.fujixerox.edmics-rlc" /> + <display value="vnd.fujixerox.edmics-rlc" /> + <definition value="As defined by Masanori Onda"/> + </concept> + <concept> + <code value="image/vnd.globalgraphics.pgb" /> + <display value="vnd.globalgraphics.pgb" /> + <definition value="As defined by Martin Bailey"/> + </concept> + <concept> + <code value="image/vnd.microsoft.icon" /> + <display value="vnd.microsoft.icon" /> + <definition value="As defined by Simon Butcher"/> + </concept> + <concept> + <code value="image/vnd.mix" /> + <display value="vnd.mix" /> + <definition value="As defined by Saveen Reddy"/> + </concept> + <concept> + <code value="image/vnd.ms-modi" /> + <display value="vnd.ms-modi" /> + <definition value="As defined by Gregory Vaughan"/> + </concept> + <concept> + <code value="image/vnd.mozilla.apng" /> + <display value="vnd.mozilla.apng" /> + <definition value="As defined by Stuart Parmenter"/> + </concept> + <concept> + <code value="image/vnd.net-fpx" /> + <display value="vnd.net-fpx" /> + <definition value="As defined by Marc Douglas Spencer"/> + </concept> + <concept> + <code value="image/vnd.radiance" /> + <display value="vnd.radiance" /> + <definition value="As defined by Randolph Fritz, and Greg Ward"/> + </concept> + <concept> + <code value="image/vnd.sealed.png" /> + <display value="vnd.sealed.png" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="image/vnd.sealedmedia.softseal.gif" /> + <display value="vnd.sealedmedia.softseal.gif" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="image/vnd.sealedmedia.softseal.jpg" /> + <display value="vnd.sealedmedia.softseal.jpg" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="image/vnd.svf" /> + <display value="vnd.svf" /> + <definition value="As defined by Jodi Moline"/> + </concept> + <concept> + <code value="image/vnd.tencent.tap" /> + <display value="vnd.tencent.tap" /> + <definition value="As defined by Ni Hui"/> + </concept> + <concept> + <code value="image/vnd.valve.source.texture" /> + <display value="vnd.valve.source.texture" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="image/vnd.wap.wbmp" /> + <display value="vnd.wap.wbmp" /> + <definition value="As defined by Peter Stark"/> + </concept> + <concept> + <code value="image/vnd.xiff" /> + <display value="vnd.xiff" /> + <definition value="As defined by Steven Martin"/> + </concept> + <concept> + <code value="image/vnd.zbrush.pcx" /> + <display value="vnd.zbrush.pcx" /> + <definition value="As defined by Chris Charabaruk"/> + </concept> + <concept> + <code value="image/wmf" /> + <display value="wmf" /> + <definition value="As defined by rfc7903"/> + </concept> + <concept> + <code value="image/x-emf - DEPRECATED in favor of image/emf" /> + <display value="x-emf - DEPRECATED in favor of image/emf" /> + <definition value="As defined by rfc7903"/> + </concept> + <concept> + <code value="image/x-wmf - DEPRECATED in favor of image/wmf" /> + <display value="x-wmf - DEPRECATED in favor of image/wmf" /> + <definition value="As defined by rfc7903"/> + </concept> + <concept> + <code value="message/CPIM" /> + <display value="CPIM" /> + <definition value="As defined by rfc3862"/> + </concept> + <concept> + <code value="message/delivery-status" /> + <display value="delivery-status" /> + <definition value="As defined by rfc1894"/> + </concept> + <concept> + <code value="message/disposition-notification" /> + <display value="disposition-notification" /> + <definition value="As defined by rfc8098"/> + </concept> + <concept> + <code value="message/example" /> + <display value="example" /> + <definition value="As defined by rfc4735"/> + </concept> + <concept> + <code value="message/external-body" /> + <display value="external-body" /> + <definition value="As defined by rfc2045, and rfc2046"/> + </concept> + <concept> + <code value="message/feedback-report" /> + <display value="feedback-report" /> + <definition value="As defined by rfc5965"/> + </concept> + <concept> + <code value="message/global" /> + <display value="global" /> + <definition value="As defined by rfc6532"/> + </concept> + <concept> + <code value="message/global-delivery-status" /> + <display value="global-delivery-status" /> + <definition value="As defined by rfc6533"/> + </concept> + <concept> + <code value="message/global-disposition-notification" /> + <display value="global-disposition-notification" /> + <definition value="As defined by rfc6533"/> + </concept> + <concept> + <code value="message/global-headers" /> + <display value="global-headers" /> + <definition value="As defined by rfc6533"/> + </concept> + <concept> + <code value="message/http" /> + <display value="http" /> + <definition value="As defined by rfc7230"/> + </concept> + <concept> + <code value="message/imdn+xml" /> + <display value="imdn+xml" /> + <definition value="As defined by rfc5438"/> + </concept> + <concept> + <code value="message/partial" /> + <display value="partial" /> + <definition value="As defined by rfc2045, and rfc2046"/> + </concept> + <concept> + <code value="message/rfc822" /> + <display value="rfc822" /> + <definition value="As defined by rfc2045, and rfc2046"/> + </concept> + <concept> + <code value="message/s-http" /> + <display value="s-http" /> + <definition value="As defined by rfc2660"/> + </concept> + <concept> + <code value="message/sip" /> + <display value="sip" /> + <definition value="As defined by rfc3261"/> + </concept> + <concept> + <code value="message/sipfrag" /> + <display value="sipfrag" /> + <definition value="As defined by rfc3420"/> + </concept> + <concept> + <code value="message/tracking-status" /> + <display value="tracking-status" /> + <definition value="As defined by rfc3886"/> + </concept> + <concept> + <code value="message/vnd.wfa.wsc" /> + <display value="vnd.wfa.wsc" /> + <definition value="As defined by Mick Conley"/> + </concept> + <concept> + <code value="model/3mf" /> + <display value="3mf" /> + <definition value="As defined by http://www.3mf.io/specification, 3MF, and Michael Sweet"/> + </concept> + <concept> + <code value="model/example" /> + <display value="example" /> + <definition value="As defined by rfc4735"/> + </concept> + <concept> + <code value="model/gltf-binary" /> + <display value="gltf-binary" /> + <definition value="As defined by Khronos, and Saurabh Bhatia"/> + </concept> + <concept> + <code value="model/gltf+json" /> + <display value="gltf+json" /> + <definition value="As defined by Khronos, and Uli Klumpp"/> + </concept> + <concept> + <code value="model/iges" /> + <display value="iges" /> + <definition value="As defined by Curtis Parks"/> + </concept> + <concept> + <code value="model/mesh" /> + <display value="mesh" /> + <definition value="As defined by rfc2077"/> + </concept> + <concept> + <code value="model/mtl" /> + <display value="mtl" /> + <definition value="As defined by DICOM Standards Committee, and Luiza Kowalczyk"/> + </concept> + <concept> + <code value="model/obj" /> + <display value="obj" /> + <definition value="As defined by DICOM Standards Committee, and Luiza Kowalczyk"/> + </concept> + <concept> + <code value="model/stl" /> + <display value="stl" /> + <definition value="As defined by DICOM Standards Committee, and Lisa Spellman"/> + </concept> + <concept> + <code value="model/vnd.collada+xml" /> + <display value="vnd.collada+xml" /> + <definition value="As defined by James Riordon"/> + </concept> + <concept> + <code value="model/vnd.dwf" /> + <display value="vnd.dwf" /> + <definition value="As defined by Jason Pratt"/> + </concept> + <concept> + <code value="model/vnd.flatland.3dml" /> + <display value="vnd.flatland.3dml" /> + <definition value="As defined by Michael Powers"/> + </concept> + <concept> + <code value="model/vnd.gdl" /> + <display value="vnd.gdl" /> + <definition value="As defined by Attila Babits"/> + </concept> + <concept> + <code value="model/vnd.gs-gdl" /> + <display value="vnd.gs-gdl" /> + <definition value="As defined by Attila Babits"/> + </concept> + <concept> + <code value="model/vnd.gtw" /> + <display value="vnd.gtw" /> + <definition value="As defined by Yutaka Ozaki"/> + </concept> + <concept> + <code value="model/vnd.moml+xml" /> + <display value="vnd.moml+xml" /> + <definition value="As defined by Christopher Brooks"/> + </concept> + <concept> + <code value="model/vnd.mts" /> + <display value="vnd.mts" /> + <definition value="As defined by Boris Rabinovitch"/> + </concept> + <concept> + <code value="model/vnd.opengex" /> + <display value="vnd.opengex" /> + <definition value="As defined by Eric Lengyel"/> + </concept> + <concept> + <code value="model/vnd.parasolid.transmit.binary" /> + <display value="vnd.parasolid.transmit.binary" /> + <definition value="As defined by Parasolid"/> + </concept> + <concept> + <code value="model/vnd.parasolid.transmit.text" /> + <display value="vnd.parasolid.transmit.text" /> + <definition value="As defined by Parasolid"/> + </concept> + <concept> + <code value="model/vnd.rosette.annotated-data-model" /> + <display value="vnd.rosette.annotated-data-model" /> + <definition value="As defined by Benson Margulies"/> + </concept> + <concept> + <code value="model/vnd.usdz+zip" /> + <display value="vnd.usdz+zip" /> + <definition value="As defined by Sebastian Grassia"/> + </concept> + <concept> + <code value="model/vnd.valve.source.compiled-map" /> + <display value="vnd.valve.source.compiled-map" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="model/vnd.vtu" /> + <display value="vnd.vtu" /> + <definition value="As defined by Boris Rabinovitch"/> + </concept> + <concept> + <code value="model/vrml" /> + <display value="vrml" /> + <definition value="As defined by rfc2077"/> + </concept> + <concept> + <code value="model/x3d-vrml" /> + <display value="x3d-vrml" /> + <definition value="As defined by Web3D, and Web3D X3D"/> + </concept> + <concept> + <code value="model/x3d+fastinfoset" /> + <display value="x3d+fastinfoset" /> + <definition value="As defined by Web3D X3D"/> + </concept> + <concept> + <code value="model/x3d+xml" /> + <display value="x3d+xml" /> + <definition value="As defined by Web3D, and Web3D X3D"/> + </concept> + <concept> + <code value="multipart/alternative" /> + <display value="alternative" /> + <definition value="As defined by rfc2046, and rfc2045"/> + </concept> + <concept> + <code value="multipart/appledouble" /> + <display value="appledouble" /> + <definition value="As defined by Patrik Faltstrom"/> + </concept> + <concept> + <code value="multipart/byteranges" /> + <display value="byteranges" /> + <definition value="As defined by rfc7233"/> + </concept> + <concept> + <code value="multipart/digest" /> + <display value="digest" /> + <definition value="As defined by rfc2046, and rfc2045"/> + </concept> + <concept> + <code value="multipart/encrypted" /> + <display value="encrypted" /> + <definition value="As defined by rfc1847"/> + </concept> + <concept> + <code value="multipart/example" /> + <display value="example" /> + <definition value="As defined by rfc4735"/> + </concept> + <concept> + <code value="multipart/form-data" /> + <display value="form-data" /> + <definition value="As defined by rfc7578"/> + </concept> + <concept> + <code value="multipart/header-set" /> + <display value="header-set" /> + <definition value="As defined by Dave Crocker"/> + </concept> + <concept> + <code value="multipart/mixed" /> + <display value="mixed" /> + <definition value="As defined by rfc2046, and rfc2045"/> + </concept> + <concept> + <code value="multipart/multilingual" /> + <display value="multilingual" /> + <definition value="As defined by rfc8255"/> + </concept> + <concept> + <code value="multipart/parallel" /> + <display value="parallel" /> + <definition value="As defined by rfc2046, and rfc2045"/> + </concept> + <concept> + <code value="multipart/related" /> + <display value="related" /> + <definition value="As defined by rfc2387"/> + </concept> + <concept> + <code value="multipart/report" /> + <display value="report" /> + <definition value="As defined by rfc6522"/> + </concept> + <concept> + <code value="multipart/signed" /> + <display value="signed" /> + <definition value="As defined by rfc1847"/> + </concept> + <concept> + <code value="multipart/vnd.bint.med-plus" /> + <display value="vnd.bint.med-plus" /> + <definition value="As defined by Heinz-Peter Schütz"/> + </concept> + <concept> + <code value="multipart/voice-message" /> + <display value="voice-message" /> + <definition value="As defined by rfc3801"/> + </concept> + <concept> + <code value="multipart/x-mixed-replace" /> + <display value="x-mixed-replace" /> + <definition value="As defined by W3C, and Robin Berjon"/> + </concept> + <concept> + <code value="text/1d-interleaved-parityfec" /> + <display value="1d-interleaved-parityfec" /> + <definition value="As defined by rfc6015"/> + </concept> + <concept> + <code value="text/cache-manifest" /> + <display value="cache-manifest" /> + <definition value="As defined by W3C, and Robin Berjon"/> + </concept> + <concept> + <code value="text/calendar" /> + <display value="calendar" /> + <definition value="As defined by rfc5545"/> + </concept> + <concept> + <code value="text/css" /> + <display value="css" /> + <definition value="As defined by rfc2318"/> + </concept> + <concept> + <code value="text/csv" /> + <display value="csv" /> + <definition value="As defined by rfc4180, and rfc7111"/> + </concept> + <concept> + <code value="text/csv-schema" /> + <display value="csv-schema" /> + <definition value="As defined by National Archives UK, and David Underdown"/> + </concept> + <concept> + <code value="text/directory - DEPRECATED by RFC6350" /> + <display value="directory - DEPRECATED by RFC6350" /> + <definition value="As defined by rfc2425, and rfc6350"/> + </concept> + <concept> + <code value="text/dns" /> + <display value="dns" /> + <definition value="As defined by rfc4027"/> + </concept> + <concept> + <code value="text/encaprtp" /> + <display value="encaprtp" /> + <definition value="As defined by rfc6849"/> + </concept> + <concept> + <code value="text/enriched" /> + <display value="enriched" /> + <definition value="As defined by rfc1896"/> + </concept> + <concept> + <code value="text/example" /> + <display value="example" /> + <definition value="As defined by rfc4735"/> + </concept> + <concept> + <code value="text/flexfec" /> + <display value="flexfec" /> + <definition value="As defined by rfc8627"/> + </concept> + <concept> + <code value="text/fwdred" /> + <display value="fwdred" /> + <definition value="As defined by rfc6354"/> + </concept> + <concept> + <code value="text/grammar-ref-list" /> + <display value="grammar-ref-list" /> + <definition value="As defined by rfc6787"/> + </concept> + <concept> + <code value="text/html" /> + <display value="html" /> + <definition value="As defined by W3C, and Robin Berjon"/> + </concept> + <concept> + <code value="text/jcr-cnd" /> + <display value="jcr-cnd" /> + <definition value="As defined by Peeter Piegaze"/> + </concept> + <concept> + <code value="text/markdown" /> + <display value="markdown" /> + <definition value="As defined by rfc7763"/> + </concept> + <concept> + <code value="text/mizar" /> + <display value="mizar" /> + <definition value="As defined by Jesse Alama"/> + </concept> + <concept> + <code value="text/n3" /> + <display value="n3" /> + <definition value="As defined by W3C, and Eric Prudhommeaux"/> + </concept> + <concept> + <code value="text/parameters" /> + <display value="parameters" /> + <definition value="As defined by rfc7826"/> + </concept> + <concept> + <code value="text/parityfec" /> + <display value="parityfec" /> + <definition value="As defined by rfc5109"/> + </concept> + <concept> + <code value="text/plain" /> + <display value="plain" /> + <definition value="As defined by rfc2046, rfc3676, and rfc5147"/> + </concept> + <concept> + <code value="text/provenance-notation" /> + <display value="provenance-notation" /> + <definition value="As defined by W3C, and Ivan Herman"/> + </concept> + <concept> + <code value="text/prs.fallenstein.rst" /> + <display value="prs.fallenstein.rst" /> + <definition value="As defined by Benja Fallenstein"/> + </concept> + <concept> + <code value="text/prs.lines.tag" /> + <display value="prs.lines.tag" /> + <definition value="As defined by John Lines"/> + </concept> + <concept> + <code value="text/prs.prop.logic" /> + <display value="prs.prop.logic" /> + <definition value="As defined by Hans-Dieter A. Hiep"/> + </concept> + <concept> + <code value="text/raptorfec" /> + <display value="raptorfec" /> + <definition value="As defined by rfc6682"/> + </concept> + <concept> + <code value="text/RED" /> + <display value="RED" /> + <definition value="As defined by rfc4102"/> + </concept> + <concept> + <code value="text/rfc822-headers" /> + <display value="rfc822-headers" /> + <definition value="As defined by rfc6522"/> + </concept> + <concept> + <code value="text/richtext" /> + <display value="richtext" /> + <definition value="As defined by rfc2045, and rfc2046"/> + </concept> + <concept> + <code value="text/rtf" /> + <display value="rtf" /> + <definition value="As defined by Paul Lindner"/> + </concept> + <concept> + <code value="text/rtp-enc-aescm128" /> + <display value="rtp-enc-aescm128" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="text/rtploopback" /> + <display value="rtploopback" /> + <definition value="As defined by rfc6849"/> + </concept> + <concept> + <code value="text/rtx" /> + <display value="rtx" /> + <definition value="As defined by rfc4588"/> + </concept> + <concept> + <code value="text/SGML" /> + <display value="SGML" /> + <definition value="As defined by rfc1874"/> + </concept> + <concept> + <code value="text/spdx" /> + <display value="spdx" /> + <definition value="As defined by Linux Foundation, and Rose Judge"/> + </concept> + <concept> + <code value="text/strings" /> + <display value="strings" /> + <definition value="As defined by IEEE-ISTO-PWG-PPP"/> + </concept> + <concept> + <code value="text/t140" /> + <display value="t140" /> + <definition value="As defined by rfc4103"/> + </concept> + <concept> + <code value="text/tab-separated-values" /> + <display value="tab-separated-values" /> + <definition value="As defined by Paul Lindner"/> + </concept> + <concept> + <code value="text/troff" /> + <display value="troff" /> + <definition value="As defined by rfc4263"/> + </concept> + <concept> + <code value="text/turtle" /> + <display value="turtle" /> + <definition value="As defined by W3C, and Eric Prudhommeaux"/> + </concept> + <concept> + <code value="text/ulpfec" /> + <display value="ulpfec" /> + <definition value="As defined by rfc5109"/> + </concept> + <concept> + <code value="text/uri-list" /> + <display value="uri-list" /> + <definition value="As defined by rfc2483"/> + </concept> + <concept> + <code value="text/vcard" /> + <display value="vcard" /> + <definition value="As defined by rfc6350"/> + </concept> + <concept> + <code value="text/vnd.a" /> + <display value="vnd.a" /> + <definition value="As defined by Regis Dehoux"/> + </concept> + <concept> + <code value="text/vnd.abc" /> + <display value="vnd.abc" /> + <definition value="As defined by Steve Allen"/> + </concept> + <concept> + <code value="text/vnd.ascii-art" /> + <display value="vnd.ascii-art" /> + <definition value="As defined by Kim Scarborough"/> + </concept> + <concept> + <code value="text/vnd.curl" /> + <display value="vnd.curl" /> + <definition value="As defined by Robert Byrnes"/> + </concept> + <concept> + <code value="text/vnd.debian.copyright" /> + <display value="vnd.debian.copyright" /> + <definition value="As defined by Charles Plessy"/> + </concept> + <concept> + <code value="text/vnd.DMClientScript" /> + <display value="vnd.DMClientScript" /> + <definition value="As defined by Dan Bradley"/> + </concept> + <concept> + <code value="text/vnd.dvb.subtitle" /> + <display value="vnd.dvb.subtitle" /> + <definition value="As defined by Peter Siebert, and Michael Lagally"/> + </concept> + <concept> + <code value="text/vnd.esmertec.theme-descriptor" /> + <display value="vnd.esmertec.theme-descriptor" /> + <definition value="As defined by Stefan Eilemann"/> + </concept> + <concept> + <code value="text/vnd.ficlab.flt" /> + <display value="vnd.ficlab.flt" /> + <definition value="As defined by Steve Gilberd"/> + </concept> + <concept> + <code value="text/vnd.fly" /> + <display value="vnd.fly" /> + <definition value="As defined by John-Mark Gurney"/> + </concept> + <concept> + <code value="text/vnd.fmi.flexstor" /> + <display value="vnd.fmi.flexstor" /> + <definition value="As defined by Kari E. Hurtta"/> + </concept> + <concept> + <code value="text/vnd.gml" /> + <display value="vnd.gml" /> + <definition value="As defined by Mi Tar"/> + </concept> + <concept> + <code value="text/vnd.graphviz" /> + <display value="vnd.graphviz" /> + <definition value="As defined by John Ellson"/> + </concept> + <concept> + <code value="text/vnd.hgl" /> + <display value="vnd.hgl" /> + <definition value="As defined by Heungsub Lee"/> + </concept> + <concept> + <code value="text/vnd.in3d.3dml" /> + <display value="vnd.in3d.3dml" /> + <definition value="As defined by Michael Powers"/> + </concept> + <concept> + <code value="text/vnd.in3d.spot" /> + <display value="vnd.in3d.spot" /> + <definition value="As defined by Michael Powers"/> + </concept> + <concept> + <code value="text/vnd.IPTC.NewsML" /> + <display value="vnd.IPTC.NewsML" /> + <definition value="As defined by IPTC"/> + </concept> + <concept> + <code value="text/vnd.IPTC.NITF" /> + <display value="vnd.IPTC.NITF" /> + <definition value="As defined by IPTC"/> + </concept> + <concept> + <code value="text/vnd.latex-z" /> + <display value="vnd.latex-z" /> + <definition value="As defined by Mikusiak Lubos"/> + </concept> + <concept> + <code value="text/vnd.motorola.reflex" /> + <display value="vnd.motorola.reflex" /> + <definition value="As defined by Mark Patton"/> + </concept> + <concept> + <code value="text/vnd.ms-mediapackage" /> + <display value="vnd.ms-mediapackage" /> + <definition value="As defined by Jan Nelson"/> + </concept> + <concept> + <code value="text/vnd.net2phone.commcenter.command" /> + <display value="vnd.net2phone.commcenter.command" /> + <definition value="As defined by Feiyu Xie"/> + </concept> + <concept> + <code value="text/vnd.radisys.msml-basic-layout" /> + <display value="vnd.radisys.msml-basic-layout" /> + <definition value="As defined by rfc5707"/> + </concept> + <concept> + <code value="text/vnd.senx.warpscript" /> + <display value="vnd.senx.warpscript" /> + <definition value="As defined by Pierre Papin"/> + </concept> + <concept> + <code value="text/vnd.sun.j2me.app-descriptor" /> + <display value="vnd.sun.j2me.app-descriptor" /> + <definition value="As defined by Gary Adams"/> + </concept> + <concept> + <code value="text/vnd.sosi" /> + <display value="vnd.sosi" /> + <definition value="As defined by Petter Reinholdtsen"/> + </concept> + <concept> + <code value="text/vnd.trolltech.linguist" /> + <display value="vnd.trolltech.linguist" /> + <definition value="As defined by David Lee Lambert"/> + </concept> + <concept> + <code value="text/vnd.wap.si" /> + <display value="vnd.wap.si" /> + <definition value="As defined by WAP-Forum"/> + </concept> + <concept> + <code value="text/vnd.wap.sl" /> + <display value="vnd.wap.sl" /> + <definition value="As defined by WAP-Forum"/> + </concept> + <concept> + <code value="text/vnd.wap.wml" /> + <display value="vnd.wap.wml" /> + <definition value="As defined by Peter Stark"/> + </concept> + <concept> + <code value="text/vnd.wap.wmlscript" /> + <display value="vnd.wap.wmlscript" /> + <definition value="As defined by Peter Stark"/> + </concept> + <concept> + <code value="text/vtt" /> + <display value="vtt" /> + <definition value="As defined by W3C, and Silvia Pfeiffer"/> + </concept> + <concept> + <code value="text/xml" /> + <display value="xml" /> + <definition value="As defined by rfc7303"/> + </concept> + <concept> + <code value="text/xml-external-parsed-entity" /> + <display value="xml-external-parsed-entity" /> + <definition value="As defined by rfc7303"/> + </concept> + <concept> + <code value="video/1d-interleaved-parityfec" /> + <display value="1d-interleaved-parityfec" /> + <definition value="As defined by rfc6015"/> + </concept> + <concept> + <code value="video/3gpp" /> + <display value="3gpp" /> + <definition value="As defined by rfc3839, and rfc6381"/> + </concept> + <concept> + <code value="video/3gpp2" /> + <display value="3gpp2" /> + <definition value="As defined by rfc4393, and rfc6381"/> + </concept> + <concept> + <code value="video/3gpp-tt" /> + <display value="3gpp-tt" /> + <definition value="As defined by rfc4396"/> + </concept> + <concept> + <code value="video/BMPEG" /> + <display value="BMPEG" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="video/BT656" /> + <display value="BT656" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="video/CelB" /> + <display value="CelB" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="video/DV" /> + <display value="DV" /> + <definition value="As defined by rfc6469"/> + </concept> + <concept> + <code value="video/encaprtp" /> + <display value="encaprtp" /> + <definition value="As defined by rfc6849"/> + </concept> + <concept> + <code value="video/example" /> + <display value="example" /> + <definition value="As defined by rfc4735"/> + </concept> + <concept> + <code value="video/flexfec" /> + <display value="flexfec" /> + <definition value="As defined by rfc8627"/> + </concept> + <concept> + <code value="video/H261" /> + <display value="H261" /> + <definition value="As defined by rfc4587"/> + </concept> + <concept> + <code value="video/H263" /> + <display value="H263" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="video/H263-1998" /> + <display value="H263-1998" /> + <definition value="As defined by rfc4629"/> + </concept> + <concept> + <code value="video/H263-2000" /> + <display value="H263-2000" /> + <definition value="As defined by rfc4629"/> + </concept> + <concept> + <code value="video/H264" /> + <display value="H264" /> + <definition value="As defined by rfc6184"/> + </concept> + <concept> + <code value="video/H264-RCDO" /> + <display value="H264-RCDO" /> + <definition value="As defined by rfc6185"/> + </concept> + <concept> + <code value="video/H264-SVC" /> + <display value="H264-SVC" /> + <definition value="As defined by rfc6190"/> + </concept> + <concept> + <code value="video/H265" /> + <display value="H265" /> + <definition value="As defined by rfc7798"/> + </concept> + <concept> + <code value="video/iso.segment" /> + <display value="iso.segment" /> + <definition value="As defined by David Singer, and ISO-IEC JTC1"/> + </concept> + <concept> + <code value="video/JPEG" /> + <display value="JPEG" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="video/jpeg2000" /> + <display value="jpeg2000" /> + <definition value="As defined by rfc5371, and rfc5372"/> + </concept> + <concept> + <code value="video/mj2" /> + <display value="mj2" /> + <definition value="As defined by rfc3745"/> + </concept> + <concept> + <code value="video/MP1S" /> + <display value="MP1S" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="video/MP2P" /> + <display value="MP2P" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="video/MP2T" /> + <display value="MP2T" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="video/mp4" /> + <display value="mp4" /> + <definition value="As defined by rfc4337, and rfc6381"/> + </concept> + <concept> + <code value="video/MP4V-ES" /> + <display value="MP4V-ES" /> + <definition value="As defined by rfc6416"/> + </concept> + <concept> + <code value="video/MPV" /> + <display value="MPV" /> + <definition value="As defined by rfc3555"/> + </concept> + <concept> + <code value="video/mpeg" /> + <display value="mpeg" /> + <definition value="As defined by rfc2045, and rfc2046"/> + </concept> + <concept> + <code value="video/mpeg4-generic" /> + <display value="mpeg4-generic" /> + <definition value="As defined by rfc3640"/> + </concept> + <concept> + <code value="video/nv" /> + <display value="nv" /> + <definition value="As defined by rfc4856"/> + </concept> + <concept> + <code value="video/ogg" /> + <display value="ogg" /> + <definition value="As defined by rfc5334, and rfc7845"/> + </concept> + <concept> + <code value="video/parityfec" /> + <display value="parityfec" /> + <definition value="As defined by rfc5109"/> + </concept> + <concept> + <code value="video/pointer" /> + <display value="pointer" /> + <definition value="As defined by rfc2862"/> + </concept> + <concept> + <code value="video/quicktime" /> + <display value="quicktime" /> + <definition value="As defined by rfc6381, and Paul Lindner"/> + </concept> + <concept> + <code value="video/raptorfec" /> + <display value="raptorfec" /> + <definition value="As defined by rfc6682"/> + </concept> + <concept> + <code value="video/raw" /> + <display value="raw" /> + <definition value="As defined by rfc4175"/> + </concept> + <concept> + <code value="video/rtp-enc-aescm128" /> + <display value="rtp-enc-aescm128" /> + <definition value="As defined by 3GPP"/> + </concept> + <concept> + <code value="video/rtploopback" /> + <display value="rtploopback" /> + <definition value="As defined by rfc6849"/> + </concept> + <concept> + <code value="video/rtx" /> + <display value="rtx" /> + <definition value="As defined by rfc4588"/> + </concept> + <concept> + <code value="video/smpte291" /> + <display value="smpte291" /> + <definition value="As defined by rfc8331"/> + </concept> + <concept> + <code value="video/SMPTE292M" /> + <display value="SMPTE292M" /> + <definition value="As defined by rfc3497"/> + </concept> + <concept> + <code value="video/ulpfec" /> + <display value="ulpfec" /> + <definition value="As defined by rfc5109"/> + </concept> + <concept> + <code value="video/vc1" /> + <display value="vc1" /> + <definition value="As defined by rfc4425"/> + </concept> + <concept> + <code value="video/vc2" /> + <display value="vc2" /> + <definition value="As defined by rfc8450"/> + </concept> + <concept> + <code value="video/vnd.CCTV" /> + <display value="vnd.CCTV" /> + <definition value="As defined by Frank Rottmann"/> + </concept> + <concept> + <code value="video/vnd.dece.hd" /> + <display value="vnd.dece.hd" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="video/vnd.dece.mobile" /> + <display value="vnd.dece.mobile" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="video/vnd.dece.mp4" /> + <display value="vnd.dece.mp4" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="video/vnd.dece.pd" /> + <display value="vnd.dece.pd" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="video/vnd.dece.sd" /> + <display value="vnd.dece.sd" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="video/vnd.dece.video" /> + <display value="vnd.dece.video" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="video/vnd.directv.mpeg" /> + <display value="vnd.directv.mpeg" /> + <definition value="As defined by Nathan Zerbe"/> + </concept> + <concept> + <code value="video/vnd.directv.mpeg-tts" /> + <display value="vnd.directv.mpeg-tts" /> + <definition value="As defined by Nathan Zerbe"/> + </concept> + <concept> + <code value="video/vnd.dlna.mpeg-tts" /> + <display value="vnd.dlna.mpeg-tts" /> + <definition value="As defined by Edwin Heredia"/> + </concept> + <concept> + <code value="video/vnd.dvb.file" /> + <display value="vnd.dvb.file" /> + <definition value="As defined by Peter Siebert, and Kevin Murray"/> + </concept> + <concept> + <code value="video/vnd.fvt" /> + <display value="vnd.fvt" /> + <definition value="As defined by Arild Fuldseth"/> + </concept> + <concept> + <code value="video/vnd.hns.video" /> + <display value="vnd.hns.video" /> + <definition value="As defined by Swaminathan"/> + </concept> + <concept> + <code value="video/vnd.iptvforum.1dparityfec-1010" /> + <display value="vnd.iptvforum.1dparityfec-1010" /> + <definition value="As defined by Shuji Nakamura"/> + </concept> + <concept> + <code value="video/vnd.iptvforum.1dparityfec-2005" /> + <display value="vnd.iptvforum.1dparityfec-2005" /> + <definition value="As defined by Shuji Nakamura"/> + </concept> + <concept> + <code value="video/vnd.iptvforum.2dparityfec-1010" /> + <display value="vnd.iptvforum.2dparityfec-1010" /> + <definition value="As defined by Shuji Nakamura"/> + </concept> + <concept> + <code value="video/vnd.iptvforum.2dparityfec-2005" /> + <display value="vnd.iptvforum.2dparityfec-2005" /> + <definition value="As defined by Shuji Nakamura"/> + </concept> + <concept> + <code value="video/vnd.iptvforum.ttsavc" /> + <display value="vnd.iptvforum.ttsavc" /> + <definition value="As defined by Shuji Nakamura"/> + </concept> + <concept> + <code value="video/vnd.iptvforum.ttsmpeg2" /> + <display value="vnd.iptvforum.ttsmpeg2" /> + <definition value="As defined by Shuji Nakamura"/> + </concept> + <concept> + <code value="video/vnd.motorola.video" /> + <display value="vnd.motorola.video" /> + <definition value="As defined by Tom McGinty"/> + </concept> + <concept> + <code value="video/vnd.motorola.videop" /> + <display value="vnd.motorola.videop" /> + <definition value="As defined by Tom McGinty"/> + </concept> + <concept> + <code value="video/vnd.mpegurl" /> + <display value="vnd.mpegurl" /> + <definition value="As defined by Heiko Recktenwald"/> + </concept> + <concept> + <code value="video/vnd.ms-playready.media.pyv" /> + <display value="vnd.ms-playready.media.pyv" /> + <definition value="As defined by Steve DiAcetis"/> + </concept> + <concept> + <code value="video/vnd.nokia.interleaved-multimedia" /> + <display value="vnd.nokia.interleaved-multimedia" /> + <definition value="As defined by Petteri Kangaslampi"/> + </concept> + <concept> + <code value="video/vnd.nokia.mp4vr" /> + <display value="vnd.nokia.mp4vr" /> + <definition value="As defined by Miska M. Hannuksela"/> + </concept> + <concept> + <code value="video/vnd.nokia.videovoip" /> + <display value="vnd.nokia.videovoip" /> + <definition value="As defined by Nokia"/> + </concept> + <concept> + <code value="video/vnd.objectvideo" /> + <display value="vnd.objectvideo" /> + <definition value="As defined by John Clark"/> + </concept> + <concept> + <code value="video/vnd.radgamettools.bink" /> + <display value="vnd.radgamettools.bink" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="video/vnd.radgamettools.smacker" /> + <display value="vnd.radgamettools.smacker" /> + <definition value="As defined by Henrik Andersson"/> + </concept> + <concept> + <code value="video/vnd.sealed.mpeg1" /> + <display value="vnd.sealed.mpeg1" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="video/vnd.sealed.mpeg4" /> + <display value="vnd.sealed.mpeg4" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="video/vnd.sealed.swf" /> + <display value="vnd.sealed.swf" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="video/vnd.sealedmedia.softseal.mov" /> + <display value="vnd.sealedmedia.softseal.mov" /> + <definition value="As defined by David Petersen"/> + </concept> + <concept> + <code value="video/vnd.uvvu.mp4" /> + <display value="vnd.uvvu.mp4" /> + <definition value="As defined by Michael A Dolan"/> + </concept> + <concept> + <code value="video/vnd.youtube.yt" /> + <display value="vnd.youtube.yt" /> + <definition value="As defined by Google"/> + </concept> + <concept> + <code value="video/vnd.vivo" /> + <display value="vnd.vivo" /> + <definition value="As defined by John Wolfe"/> + </concept> + <concept> + <code value="video/VP8" /> + <display value="VP8" /> + <definition value="As defined by rfc7741"/> + </concept> +</CodeSystem> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/urn_ietf_bcp_13.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/urn_ietf_bcp_13.xml.post new file mode 100644 index 000000000..347ea76b5 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/CodeSystem/urn_ietf_bcp_13.xml.post @@ -0,0 +1 @@ +url=urn:ietf:bcp:13&version=4.0.1 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-endpoint.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-endpoint.xml index f05c170e5..7892c74e9 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-endpoint.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-endpoint.xml @@ -1,5 +1,4 @@ -<NamingSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<NamingSystem xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-endpoint.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-endpoint.xml.post new file mode 100755 index 000000000..ff7d0f566 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-endpoint.xml.post @@ -0,0 +1 @@ +name=HiGHmed_Endpoint_Identifier \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-endpoint.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-endpoint.xml.put deleted file mode 100755 index b5facfc23..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-endpoint.xml.put +++ /dev/null @@ -1 +0,0 @@ -NamingSystem?name=HiGHmed_Endpoint_Identifier \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-organization.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-organization.xml index 14902dbb0..1efba0549 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-organization.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-organization.xml @@ -1,5 +1,4 @@ -<NamingSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<NamingSystem xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-organization.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-organization.xml.post new file mode 100755 index 000000000..211e5b85a --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-organization.xml.post @@ -0,0 +1 @@ +name=HiGHmed_Organization_Identifier \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-organization.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-organization.xml.put deleted file mode 100755 index 9aa46c1c8..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-organization.xml.put +++ /dev/null @@ -1 +0,0 @@ -NamingSystem?name=HiGHmed_Organization_Identifier \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-research-study.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-research-study.xml index 2660b1ec2..e55b7c1ed 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-research-study.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-research-study.xml @@ -1,5 +1,4 @@ -<NamingSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<NamingSystem xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-research-study.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-research-study.xml.post new file mode 100644 index 000000000..a63f52dd4 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-research-study.xml.post @@ -0,0 +1 @@ +name=HiGHmed_ResearchStudy_Identifier \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-research-study.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-research-study.xml.put deleted file mode 100644 index 701aa10b9..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/NamingSystem/highmed-research-study.xml.put +++ /dev/null @@ -1 +0,0 @@ -NamingSystem?name=HiGHmed_ResearchStudy_Identifier \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.1.0.xml deleted file mode 100755 index f2816fae3..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.1.0.xml +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<StructureDefinition xmlns="http://hl7.org/fhir"> - <meta> - <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> - </meta> - <url value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint" /> - <version value="0.1.0" /> - <name value="Endpoint" /> - <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> - <kind value="resource" /> - <abstract value="false" /> - <type value="Endpoint" /> - <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Endpoint" /> - <derivation value="constraint" /> - <differential> - <element id="Endpoint.identifier"> - <path value="Endpoint.identifier" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="system" /> - </discriminator> - <rules value="open" /> - </slicing> - <min value="1" /> - </element> - <element id="Endpoint.identifier:sliceIdentifier"> - <path value="Endpoint.identifier" /> - <sliceName value="sliceIdentifier" /> - </element> - <element id="Endpoint.identifier:sliceIdentifier.system"> - <path value="Endpoint.identifier.system" /> - <min value="1" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/endpoint-identifier" /> - </element> - <element id="Endpoint.managingOrganization"> - <path value="Endpoint.managingOrganization" /> - <min value="1" /> - <type> - <code value="Reference" /> - <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-organization" /> - </type> - </element> - </differential> -</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.1.0.xml.put deleted file mode 100755 index 60f454e88..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-endpoint&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.2.0.xml new file mode 100644 index 000000000..e004a271f --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.2.0.xml @@ -0,0 +1,138 @@ +<StructureDefinition xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> + </meta> + <url value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint" /> + <version value="0.2.0" /> + <name value="Endpoint" /> + <status value="draft" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> + <kind value="resource" /> + <abstract value="false" /> + <type value="Endpoint" /> + <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Endpoint" /> + <derivation value="constraint" /> + <differential> + <element id="Endpoint.identifier"> + <path value="Endpoint.identifier" /> + <slicing> + <discriminator> + <type value="value" /> + <path value="system" /> + </discriminator> + <discriminator> + <type value="value" /> + <path value="value" /> + </discriminator> + <rules value="open" /> + </slicing> + <min value="1" /> + </element> + <element id="Endpoint.identifier:highmedIdentifier"> + <path value="Endpoint.identifier" /> + <sliceName value="highmedIdentifier" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Endpoint.identifier:highmedIdentifier.system"> + <path value="Endpoint.identifier.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/NamingSystem/endpoint-identifier" /> + </element> + <element id="Endpoint.identifier:highmedIdentifier.value"> + <path value="Endpoint.identifier.value" /> + <min value="1" /> + </element> + <element id="Endpoint.connectionType.system"> + <path value="Endpoint.connectionType.system" /> + <min value="1" /> + <fixedUri value="http://terminology.hl7.org/CodeSystem/endpoint-connection-type" /> + </element> + <element id="Endpoint.connectionType.code"> + <path value="Endpoint.connectionType.code" /> + <min value="1" /> + <fixedCode value="hl7-fhir-rest" /> + </element> + <element id="Endpoint.managingOrganization"> + <path value="Endpoint.managingOrganization" /> + <min value="1" /> + <type> + <code value="Reference" /> + <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-organization" /> + </type> + </element> + <element id="Endpoint.managingOrganization.reference"> + <path value="Endpoint.managingOrganization.reference" /> + <min value="1" /> + </element> + <element id="Endpoint.managingOrganization.identifier"> + <path value="Endpoint.managingOrganization.identifier" /> + <max value="0" /> + </element> + <element id="Endpoint.payloadType"> + <path value="Endpoint.payloadType" /> + <slicing> + <discriminator> + <type value="value" /> + <path value="coding.system" /> + </discriminator> + <discriminator> + <type value="value" /> + <path value="coding.code" /> + </discriminator> + <rules value="open" /> + </slicing> + </element> + <element id="Endpoint.payloadType:slicePayloadType"> + <path value="Endpoint.payloadType" /> + <sliceName value="slicePayloadType" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Endpoint.payloadType:slicePayloadType.coding"> + <path value="Endpoint.payloadType.coding" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Endpoint.payloadType:slicePayloadType.coding.system"> + <path value="Endpoint.payloadType.coding.system" /> + <min value="1" /> + <fixedUri value="http://hl7.org/fhir/resource-types" /> + </element> + <element id="Endpoint.payloadType:slicePayloadType.coding.code"> + <path value="Endpoint.payloadType.coding.code" /> + <min value="1" /> + <fixedCode value="Task" /> + </element> + <element id="Endpoint.payloadMimeType"> + <path value="Endpoint.payloadMimeType" /> + <slicing> + <discriminator> + <type value="value" /> + <path value="value" /> + </discriminator> + <rules value="open" /> + </slicing> + <min value="2" /> + <max value="2" /> + </element> + <element id="Endpoint.payloadMimeType:fhirXml"> + <path value="Endpoint.payloadMimeType" /> + <sliceName value="fhirXml" /> + <min value="1" /> + <max value="1" /> + <fixedCode value="application/fhir+xml" /> + </element> + <element id="Endpoint.payloadMimeType:fhirJson"> + <path value="Endpoint.payloadMimeType" /> + <sliceName value="fhirJson" /> + <min value="1" /> + <max value="1" /> + <fixedCode value="application/fhir+json" /> + </element> + </differential> +</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.2.0.xml.post new file mode 100644 index 000000000..d6b46a06e --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-endpoint-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-endpoint&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.1.0.xml deleted file mode 100755 index 292712a9a..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.1.0.xml +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<StructureDefinition xmlns="http://hl7.org/fhir"> - <meta> - <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> - </meta> - <url value="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint"/> - <version value="0.1.0"/> - <name value="CertificateThumbprint"/> - <status value="draft"/> - <date value="2019-05-21"/> - <fhirVersion value="4.0.0"/> - <kind value="complex-type"/> - <abstract value="false"/> - <context> - <type value="element"/> - <expression value="Organization"/> - </context> - <type value="Extension"/> - <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Extension"/> - <derivation value="constraint"/> - <differential> - <element id="Extension.url"> - <path value="Extension.url"/> - <type> - <code value="uri"/> - </type> - <fixedUri value="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint"/> - </element> - <element id="Extension.value[x]"> - <path value="Extension.value[x]"/> - <min value="1"/> - <type> - <code value="string"/> - </type> - </element> - </differential> -</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.1.0.xml.put deleted file mode 100755 index 3e5f9d371..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/certificate-thumbprint&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.2.0.xml new file mode 100644 index 000000000..ae41d0f6f --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.2.0.xml @@ -0,0 +1,39 @@ +<StructureDefinition xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> + </meta> + <url value="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint" /> + <version value="0.2.0" /> + <name value="CertificateThumbprint" /> + <status value="draft" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> + <kind value="complex-type" /> + <abstract value="false" /> + <context> + <type value="element" /> + <expression value="Organization" /> + </context> + <type value="Extension" /> + <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Extension" /> + <derivation value="constraint" /> + <differential> + <element id="Extension.url"> + <path value="Extension.url" /> + <type> + <code value="uri" /> + </type> + <fixedUri value="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint" /> + </element> + <element id="Extension.value[x]"> + <path value="Extension.value[x]" /> + <min value="1" /> + <type> + <code value="string" /> + </type> + </element> + </differential> +</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.2.0.xml.post new file mode 100644 index 000000000..e0a91b685 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-certificate-thumbprint-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/certificate-thumbprint&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.1.0.xml.put deleted file mode 100755 index c606eb152..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/group-id&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.2.0.xml similarity index 73% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.2.0.xml index 97478164b..e0e17b3a8 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.2.0.xml @@ -1,17 +1,16 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/group-id" /> - <version value="0.1.0" /> - <name value="group-id" /> + <version value="0.2.0" /> + <name value="GroupId" /> <status value="draft" /> - <date value="2019-12-16" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-20" /> + <fhirVersion value="4.0.1" /> <mapping> <identity value="rim" /> <uri value="http://hl7.org/v3" /> @@ -43,5 +42,13 @@ <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-group" /> </type> </element> + <element id="Extension.value[x].reference"> + <path value="Extension.value[x].reference" /> + <min value="1" /> + </element> + <element id="Extension.value[x].identifier"> + <path value="Extension.value[x].identifier" /> + <max value="0" /> + </element> </differential> </StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.2.0.xml.post new file mode 100755 index 000000000..90000b8aa --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-group-id-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/group-id&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.1.0.xml.put deleted file mode 100755 index 6e14fd71c..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/participating-medic&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.2.0.xml similarity index 62% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.2.0.xml index d214997da..e7e6dc711 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.2.0.xml @@ -1,4 +1,3 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> @@ -7,11 +6,11 @@ </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/participating-medic" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="ParticipatingMedic" /> <status value="draft" /> - <date value="2019-08-05" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-20" /> + <fhirVersion value="4.0.1" /> <kind value="complex-type" /> <abstract value="false" /> <context> @@ -35,10 +34,33 @@ <path value="Extension.value[x]" /> <short value="ParticipatingMedic" /> <definition value="Organization reference used to denote the medic organizations that are requested to supply data for the study at hand." /> + <min value="1" /> <type> <code value="Reference" /> <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-organization" /> </type> </element> + <element id="Extension.value[x].reference"> + <path value="Extension.value[x].reference" /> + <max value="0" /> + </element> + <element id="Extension.value[x].type"> + <path value="Extension.value[x].type" /> + <min value="1" /> + <fixedUri value="Organization" /> + </element> + <element id="Extension.value[x].identifier"> + <path value="Extension.value[x].identifier" /> + <min value="1" /> + </element> + <element id="Extension.value[x].identifier.system"> + <path value="Extension.value[x].identifier.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/NamingSystem/organization-identifier" /> + </element> + <element id="Extension.value[x].identifier.value"> + <path value="Extension.value[x].identifier.value" /> + <min value="1" /> + </element> </differential> </StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.2.0.xml.post new file mode 100755 index 000000000..f5ab78957 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-medic-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/participating-medic&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.1.0.xml.put deleted file mode 100644 index e5994fc5f..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/participating-ttp&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.2.0.xml similarity index 61% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.2.0.xml index fbf697cbd..5aeb29287 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.2.0.xml @@ -1,4 +1,3 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> @@ -7,11 +6,11 @@ </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/participating-ttp" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="ParticipatingTtp" /> <status value="draft" /> - <date value="2020-03-04" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-20" /> + <fhirVersion value="4.0.1" /> <kind value="complex-type" /> <abstract value="false" /> <context> @@ -35,10 +34,33 @@ <path value="Extension.value[x]" /> <short value="ParticipatingMedic" /> <definition value="Organization reference used to denote the TTP organization that is used to record link and pseudonymize data." /> + <min value="1" /> <type> <code value="Reference" /> <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-organization" /> </type> </element> + <element id="Extension.value[x].reference"> + <path value="Extension.value[x].reference" /> + <max value="0" /> + </element> + <element id="Extension.value[x].type"> + <path value="Extension.value[x].type" /> + <min value="1" /> + <fixedUri value="Organization" /> + </element> + <element id="Extension.value[x].identifier"> + <path value="Extension.value[x].identifier" /> + <min value="1" /> + </element> + <element id="Extension.value[x].identifier.system"> + <path value="Extension.value[x].identifier.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/NamingSystem/organization-identifier" /> + </element> + <element id="Extension.value[x].identifier.value"> + <path value="Extension.value[x].identifier.value" /> + <min value="1" /> + </element> </differential> </StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.2.0.xml.post new file mode 100644 index 000000000..3141dabfd --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-participating-ttp-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/participating-ttp&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-process-authorization-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-process-authorization-0.1.0.xml index 1c6e98e33..46bcf6e54 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-process-authorization-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-process-authorization-0.1.0.xml @@ -1,4 +1,3 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-process-authorization-0.1.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-process-authorization-0.1.0.xml.post new file mode 100644 index 000000000..9deab0f16 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-process-authorization-0.1.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/process-authorization&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-process-authorization-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-process-authorization-0.1.0.xml.put deleted file mode 100644 index 885afab45..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-process-authorization-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/process-authorization&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.1.0.xml deleted file mode 100755 index 4d345f4b6..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.1.0.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<StructureDefinition xmlns="http://hl7.org/fhir"> - <meta> - <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> - </meta> - <url value="http://highmed.org/fhir/StructureDefinition/query"/> - <version value="0.1.0"/> - <name value="Query"/> - <status value="draft"/> - <fhirVersion value="4.0.0"/> - <kind value="complex-type"/> - <abstract value="false"/> - <context> - <type value="element"/> - <expression value="Group"/> - </context> - <type value="Extension"/> - <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Extension"/> - <derivation value="constraint"/> - <differential> - <element id="Extension.url"> - <path value="Extension.url"/> - <fixedString value="http://highmed.org/fhir/StructureDefinition/query"/> - </element> - <element id="Extension.value[x]"> - <path value="Extension.value[x]"/> - <min value="1"/> - <type> - <code value="Expression"/> - </type> - </element> - <element id="Extension.value[x].language"> - <path value="Extension.value[x].language"/> - <short value="application/x-fhir-query | application/x-aql-query"/> - <binding> - <strength value="required"/> - <valueSet value="http://highmed.org/fhir/ValueSet/query-type"/> - </binding> - </element> - <element id="Extension.value[x].expression"> - <path value="Extension.value[x].expression"/> - <min value="1"/> - </element> - </differential> -</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.1.0.xml.put deleted file mode 100755 index f50b39290..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/query&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.2.0.xml new file mode 100755 index 000000000..e55a0ece3 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.2.0.xml @@ -0,0 +1,48 @@ +<StructureDefinition xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> + </meta> + <url value="http://highmed.org/fhir/StructureDefinition/query" /> + <version value="0.2.0" /> + <name value="Query" /> + <status value="draft" /> + <date value="2020-05-20" /> + <fhirVersion value="4.0.1" /> + <kind value="complex-type" /> + <abstract value="false" /> + <context> + <type value="element" /> + <expression value="Group" /> + </context> + <type value="Extension" /> + <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Extension" /> + <derivation value="constraint" /> + <differential> + <element id="Extension.url"> + <path value="Extension.url" /> + <fixedUri value="http://highmed.org/fhir/StructureDefinition/query" /> + </element> + <element id="Extension.value[x]"> + <path value="Extension.value[x]" /> + <min value="1" /> + <type> + <code value="Expression" /> + </type> + </element> + <element id="Extension.value[x].language"> + <path value="Extension.value[x].language" /> + <short value="application/x-fhir-query | application/x-aql-query" /> + <binding> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/query-type" /> + </binding> + </element> + <element id="Extension.value[x].expression"> + <path value="Extension.value[x].expression" /> + <min value="1" /> + </element> + </differential> +</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.2.0.xml.post new file mode 100755 index 000000000..6a7c2c55e --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-extension-query-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/query&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.1.0.xml deleted file mode 100755 index a89e85cc8..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.1.0.xml +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<StructureDefinition xmlns="http://hl7.org/fhir"> - <meta> - <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> - </meta> - <url value="http://highmed.org/fhir/StructureDefinition/highmed-group"/> - <version value="0.1.0"/> - <name value="Group"/> - <status value="draft"/> - <fhirVersion value="4.0.0"/> - <kind value="resource"/> - <abstract value="false"/> - <type value="Group"/> - <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Group"/> - <derivation value="constraint"/> - <differential> - <element id="Group.extension"> - <path value="Group.extension"/> - <slicing> - <discriminator> - <type value="value"/> - <path value="url"/> - </discriminator> - <rules value="open"/> - </slicing> - </element> - <element id="Group.extension:query"> - <path value="Group.extension"/> - <sliceName value="query"/> - <min value="1"/> - <max value="*"/> - <type> - <code value="Extension"/> - <profile value="http://highmed.org/fhir/StructureDefinition/query"/> - </type> - </element> - <element id="Group.actual"> - <path value="Group.actual"/> - <fixedBoolean value="true"/> - </element> - </differential> -</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.1.0.xml.put deleted file mode 100755 index e54667106..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-group&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.2.0.xml new file mode 100755 index 000000000..ceb901b72 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.2.0.xml @@ -0,0 +1,49 @@ +<StructureDefinition xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> + </meta> + <url value="http://highmed.org/fhir/StructureDefinition/highmed-group" /> + <version value="0.2.0" /> + <name value="Group" /> + <status value="draft" /> + <date value="2020-05-20" /> + <fhirVersion value="4.0.1" /> + <kind value="resource" /> + <abstract value="false" /> + <type value="Group" /> + <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Group" /> + <derivation value="constraint" /> + <differential> + <element id="Group.extension"> + <path value="Group.extension" /> + <slicing> + <discriminator> + <type value="value" /> + <path value="url" /> + </discriminator> + <rules value="open" /> + </slicing> + </element> + <element id="Group.extension:query"> + <path value="Group.extension" /> + <sliceName value="query" /> + <min value="1" /> + <max value="1" /> + <type> + <code value="Extension" /> + <profile value="http://highmed.org/fhir/StructureDefinition/query" /> + </type> + </element> + <element id="Group.type"> + <path value="Group.type" /> + <fixedCode value="person" /> + </element> + <element id="Group.actual"> + <path value="Group.actual" /> + <fixedBoolean value="false" /> + </element> + </differential> +</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.2.0.xml.post new file mode 100755 index 000000000..12ca06ecf --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-group-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-group&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.1.0.xml deleted file mode 100755 index 13daaf47c..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.1.0.xml +++ /dev/null @@ -1,69 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<StructureDefinition xmlns="http://hl7.org/fhir"> - <meta> - <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> - </meta> - <url value="http://highmed.org/fhir/StructureDefinition/highmed-organization" /> - <version value="0.1.0" /> - <name value="Organization" /> - <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> - <kind value="resource" /> - <abstract value="false" /> - <type value="Organization" /> - <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Organization" /> - <derivation value="constraint" /> - <differential> - <element id="Organization.extension"> - <path value="Organization.extension" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="url" /> - </discriminator> - <rules value="open" /> - </slicing> - </element> - <element id="Organization.extension:certificateThumbprint"> - <path value="Organization.extension" /> - <sliceName value="certificateThumbprint" /> - <min value="1" /> - <type> - <code value="Extension" /> - <profile value="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint" /> - </type> - </element> - <element id="Organization.identifier"> - <path value="Organization.identifier" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="system" /> - </discriminator> - <rules value="open" /> - </slicing> - <min value="1" /> - </element> - <element id="Organization.identifier:sliceIdentifier"> - <path value="Organization.identifier" /> - <sliceName value="sliceIdentifier" /> - </element> - <element id="Organization.identifier:sliceIdentifier.system"> - <path value="Organization.identifier.system" /> - <min value="1" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/organization-identifier" /> - </element> - <element id="Organization.endpoint"> - <path value="Organization.endpoint" /> - <min value="1" /> - <type> - <code value="Reference" /> - <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint" /> - </type> - </element> - </differential> -</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.1.0.xml.put deleted file mode 100755 index 9003d43bf..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-organization&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.2.0.xml new file mode 100644 index 000000000..a5326eac2 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.2.0.xml @@ -0,0 +1,139 @@ +<StructureDefinition xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> + </meta> + <url value="http://highmed.org/fhir/StructureDefinition/highmed-organization" /> + <version value="0.2.0" /> + <name value="Organization" /> + <status value="draft" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> + <kind value="resource" /> + <abstract value="false" /> + <type value="Organization" /> + <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Organization" /> + <derivation value="constraint" /> + <differential> + <element id="Organization.extension"> + <path value="Organization.extension" /> + <slicing> + <discriminator> + <type value="value" /> + <path value="url" /> + </discriminator> + <rules value="open" /> + </slicing> + </element> + <element id="Organization.extension:certificateThumbprint"> + <path value="Organization.extension" /> + <sliceName value="certificateThumbprint" /> + <min value="1" /> + <type> + <code value="Extension" /> + <profile value="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint" /> + </type> + </element> + <element id="Organization.identifier"> + <path value="Organization.identifier" /> + <slicing> + <discriminator> + <type value="value" /> + <path value="system" /> + </discriminator> + <discriminator> + <type value="value" /> + <path value="value" /> + </discriminator> + <rules value="open" /> + </slicing> + <min value="1" /> + </element> + <element id="Organization.identifier:highmedIdentifier"> + <path value="Organization.identifier" /> + <sliceName value="highmedIdentifier" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Organization.identifier:highmedIdentifier.system"> + <path value="Organization.identifier.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/NamingSystem/organization-identifier" /> + </element> + <element id="Organization.identifier:highmedIdentifier.value"> + <path value="Organization.identifier.value" /> + <min value="1" /> + </element> + <element id="Organization.active"> + <path value="Organization.active" /> + <min value="1" /> + </element> + <element id="Organization.type"> + <path value="Organization.type" /> + <slicing> + <discriminator> + <type value="value" /> + <path value="coding.system" /> + </discriminator> + <discriminator> + <type value="value" /> + <path value="coding.code" /> + </discriminator> + <rules value="open" /> + </slicing> + <min value="1" /> + </element> + <element id="Organization.type:highmedOrganizationType"> + <path value="Organization.type" /> + <sliceName value="highmedOrganizationType" /> + <min value="1" /> + <max value="1" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="OrganizationType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/organization-type" /> + </binding> + </element> + <element id="Organization.type:highmedOrganizationType.coding"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status"> + <valueCode value="normative" /> + </extension> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-normative-version"> + <valueCode value="4.0.0" /> + </extension> + <path value="Organization.type.coding" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Organization.type:highmedOrganizationType.coding.system"> + <path value="Organization.type.coding.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/organization-type" /> + </element> + <element id="Organization.type:highmedOrganizationType.coding.code"> + <path value="Organization.type.coding.code" /> + <min value="1" /> + </element> + <element id="Organization.endpoint"> + <path value="Organization.endpoint" /> + <min value="1" /> + <max value="1" /> + <type> + <code value="Reference" /> + <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint" /> + </type> + </element> + <element id="Organization.endpoint.reference"> + <path value="Organization.endpoint.reference" /> + <min value="1" /> + </element> + <element id="Organization.endpoint.identifier"> + <path value="Organization.endpoint.identifier" /> + <max value="0" /> + </element> + </differential> +</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.2.0.xml.post new file mode 100644 index 000000000..095bc5da7 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-organization-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-organization&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-0.1.0.xml deleted file mode 100755 index a0fb80555..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-0.1.0.xml +++ /dev/null @@ -1,131 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<StructureDefinition xmlns="http://hl7.org/fhir"> - <meta> - <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> - </meta> - <url value="http://highmed.org/fhir/StructureDefinition/highmed-practitioner"/> - <version value="0.1.0"/> - <name value="Practitioner"/> - <status value="draft"/> - <fhirVersion value="4.0.0"/> - <kind value="resource"/> - <abstract value="false"/> - <type value="Practitioner"/> - <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Practitioner"/> - <derivation value="constraint"/> - <differential> - <element id="Practitioner.identifier"> - <path value="Practitioner.identifier"/> - <slicing> - <discriminator> - <type value="value"/> - <path value="system"/> - </discriminator> - <rules value="open"/> - </slicing> - <min value="1"/> - </element> - <element id="Practitioner.identifier:HiGHmed"> - <path value="Practitioner.identifier"/> - <sliceName value="HiGHmed"/> - <min value="1"/> - <max value="1"/> - </element> - <element id="Practitioner.identifier:HiGHmed.system"> - <path value="Practitioner.identifier.system"/> - <min value="1"/> - <fixedUri value="http://highmed.org/fhir/CodeSystem/practitioner"/> - </element> - <element id="Practitioner.identifier:HiGHmed.value"> - <path value="Practitioner.identifier.value"/> - <min value="1"/> - <binding> - <strength value="required"/> - <valueSet value="http://highmed.org/fhir/ValueSet/practitioner"/> - </binding> - </element> - <element id="Practitioner.name"> - <path value="Practitioner.name"/> - <min value="1"/> - <max value="1"/> - <type> - <code value="HumanName"/> - </type> - </element> - <element id="Practitioner.name.family"> - <path value="Practitioner.name.family"/> - <min value="1"/> - </element> - <element id="Practitioner.name.given"> - <path value="Practitioner.name.given"/> - <min value="1"/> - </element> - <element id="Practitioner.telecom"> - <path value="Practitioner.telecom"/> - <slicing> - <discriminator> - <type value="value"/> - <path value="system"/> - </discriminator> - <rules value="open"/> - </slicing> - <min value="1"/> - </element> - <element id="Practitioner.telecom:email"> - <path value="Practitioner.telecom"/> - <sliceName value="email"/> - <min value="1"/> - <max value="1"/> - </element> - <element id="Practitioner.telecom:email.system"> - <path value="Practitioner.telecom.system"/> - <min value="1"/> - <fixedCode value="email"/> - </element> - <element id="Practitioner.telecom:email.value"> - <path value="Practitioner.telecom.value"/> - <min value="1"/> - </element> - <element id="Practitioner.telecom:phone"> - <path value="Practitioner.telecom"/> - <sliceName value="phone"/> - <min value="1"/> - <max value="1"/> - </element> - <element id="Practitioner.telecom:phone.system"> - <path value="Practitioner.telecom.system"/> - <min value="1"/> - <fixedCode value="phone"/> - </element> - <element id="Practitioner.telecom:phone.value"> - <path value="Practitioner.telecom.value"/> - <min value="1"/> - </element> - <element id="Practitioner.address"> - <path value="Practitioner.address"/> - <min value="1"/> - <type> - <code value="Address"/> - </type> - </element> - <element id="Practitioner.address.line"> - <path value="Practitioner.address.line"/> - <min value="1"/> - </element> - <element id="Practitioner.address.city"> - <path value="Practitioner.address.city"/> - <min value="1"/> - </element> - <element id="Practitioner.address.postalCode"> - <path value="Practitioner.address.postalCode"/> - <min value="1"/> - </element> - <element id="Practitioner.address.country"> - <path value="Practitioner.address.country"/> - <min value="1"/> - </element> - </differential> -</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-0.1.0.xml.put deleted file mode 100755 index aba23d76f..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-practitioner&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-role-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-role-0.1.0.xml deleted file mode 100755 index f88b8955c..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-role-0.1.0.xml +++ /dev/null @@ -1,67 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<StructureDefinition xmlns="http://hl7.org/fhir"> - <meta> - <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> - </meta> - <url value="http://highmed.org/fhir/StructureDefinition/highmed-practitioner-role"/> - <version value="0.1.0"/> - <name value="PractitionerRole"/> - <status value="draft"/> - <fhirVersion value="4.0.0"/> - <kind value="resource"/> - <abstract value="false"/> - <type value="PractitionerRole"/> - <baseDefinition value="http://hl7.org/fhir/StructureDefinition/PractitionerRole"/> - <derivation value="constraint"/> - <differential> - <element id="PractitionerRole.identifier"> - <path value="PractitionerRole.identifier"/> - <slicing> - <discriminator> - <type value="value"/> - <path value="system"/> - </discriminator> - <rules value="open"/> - </slicing> - <min value="1"/> - </element> - <element id="PractitionerRole.identifier:HiGHmed"> - <path value="PractitionerRole.identifier"/> - <sliceName value="HiGHmed"/> - <min value="1"/> - <max value="1"/> - </element> - <element id="PractitionerRole.identifier:HiGHmed.system"> - <path value="PractitionerRole.identifier.system"/> - <min value="1"/> - <fixedUri value="http://highmed.org/fhir/CodeSystem/practitioner-role"/> - </element> - <element id="PractitionerRole.identifier:HiGHmed.value"> - <path value="PractitionerRole.identifier.value"/> - <min value="1"/> - <binding> - <strength value="required"/> - <valueSet value="http://highmed.org/fhir/ValueSet/practitioner-role"/> - </binding> - </element> - <element id="PractitionerRole.practitioner"> - <path value="PractitionerRole.practitioner"/> - <min value="1"/> - <type> - <code value="Reference"/> - <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-practitioner"/> - </type> - </element> - <element id="PractitionerRole.organization"> - <path value="PractitionerRole.organization"/> - <min value="1"/> - <type> - <code value="Reference"/> - <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-organization"/> - </type> - </element> - </differential> -</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-role-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-role-0.1.0.xml.put deleted file mode 100755 index 188c32c96..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-practitioner-role-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-practitioner-role&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-0.1.0.xml.put deleted file mode 100755 index 52d812fcc..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-research-study&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-feasibility-0.2.0.xml similarity index 81% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-feasibility-0.2.0.xml index 0bd8076c8..af65860de 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-feasibility-0.2.0.xml @@ -1,4 +1,3 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> @@ -6,11 +5,12 @@ <code value="REMOTE" /> </tag> </meta> - <url value="http://highmed.org/fhir/StructureDefinition/highmed-research-study" /> - <version value="0.1.0" /> - <name value="ResearchStudy" /> + <url value="http://highmed.org/fhir/StructureDefinition/highmed-research-study-feasibility" /> + <version value="0.2.0" /> + <name value="ResearchStudyFeasibility" /> <status value="draft" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> <abstract value="false" /> <type value="ResearchStudy" /> @@ -41,7 +41,6 @@ <path value="ResearchStudy.extension" /> <sliceName value="participating-medic" /> <min value="1" /> - <max value="*" /> <type> <code value="Extension" /> <profile value="http://highmed.org/fhir/StructureDefinition/participating-medic" /> @@ -66,10 +65,11 @@ </element> <element id="ResearchStudy.identifier:highmedIdentifier.system"> <path value="ResearchStudy.identifier.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/NamingSystem/research-study-identifier" /> </element> - <element id="ResearchStudy.description"> - <path value="ResearchStudy.description" /> + <element id="ResearchStudy.identifier:highmedIdentifier.value"> + <path value="ResearchStudy.identifier.value" /> <min value="1" /> </element> <element id="ResearchStudy.enrollment"> @@ -84,14 +84,9 @@ <path value="ResearchStudy.enrollment.reference" /> <min value="1" /> </element> - <element id="ResearchStudy.principalInvestigator"> - <path value="ResearchStudy.principalInvestigator" /> - <min value="1" /> - <type> - <code value="Reference" /> - <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-practitioner" /> - <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-practitioner-role" /> - </type> + <element id="ResearchStudy.enrollment.identifier"> + <path value="ResearchStudy.enrollment.identifier" /> + <max value="0" /> </element> </differential> </StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-feasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-feasibility-0.2.0.xml.post new file mode 100755 index 000000000..347245ca8 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-research-study-feasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-research-study-feasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.1.0.xml.put deleted file mode 100644 index d55f73384..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-base&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.2.0.xml similarity index 55% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.2.0.xml index 8d11963f3..2b89c4116 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.2.0.xml @@ -1,19 +1,18 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-base" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="TaskBase" /> <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> - <abstract value="false" /> + <abstract value="true" /> <type value="Task" /> <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Task" /> <derivation value="constraint" /> @@ -38,6 +37,23 @@ <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-organization" /> </type> </element> + <element id="Task.requester.reference"> + <path value="Task.requester.reference" /> + <max value="0" /> + </element> + <element id="Task.requester.identifier"> + <path value="Task.requester.identifier" /> + <min value="1" /> + </element> + <element id="Task.requester.identifier.system"> + <path value="Task.requester.identifier.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/NamingSystem/organization-identifier" /> + </element> + <element id="Task.requester.identifier.value"> + <path value="Task.requester.identifier.value" /> + <min value="1" /> + </element> <element id="Task.restriction"> <path value="Task.restriction" /> <min value="1" /> @@ -51,23 +67,60 @@ <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-organization" /> </type> </element> + <element id="Task.restriction.recipient.reference"> + <path value="Task.restriction.recipient.reference" /> + <max value="0" /> + </element> + <element id="Task.restriction.recipient.identifier"> + <path value="Task.restriction.recipient.identifier" /> + <min value="1" /> + </element> + <element id="Task.restriction.recipient.identifier.system"> + <path value="Task.restriction.recipient.identifier.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/NamingSystem/organization-identifier" /> + </element> + <element id="Task.restriction.recipient.identifier.value"> + <path value="Task.restriction.recipient.identifier.value" /> + <min value="1" /> + </element> <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <slicing> + <discriminator> + <type value="value" /> + <path value="type.coding.system" /> + </discriminator> <discriminator> <type value="value" /> <path value="type.coding.code" /> </discriminator> - <rules value="closed" /> + <rules value="openAtEnd" /> </slicing> <min value="1" /> </element> <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="message-name" /> <min value="1" /> <max value="1" /> </element> + <element id="Task.input:message-name.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/bpmn-message" /> + </binding> + </element> <element id="Task.input:message-name.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -75,10 +128,12 @@ </element> <element id="Task.input:message-name.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/bpmn-message" /> </element> <element id="Task.input:message-name.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="message-name" /> </element> <element id="Task.input:message-name.value[x]"> @@ -88,10 +143,23 @@ </type> </element> <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="business-key" /> <max value="1" /> </element> + <element id="Task.input:business-key.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/bpmn-message" /> + </binding> + </element> <element id="Task.input:business-key.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -99,10 +167,12 @@ </element> <element id="Task.input:business-key.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/bpmn-message" /> </element> <element id="Task.input:business-key.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="business-key" /> </element> <element id="Task.input:business-key.value[x]"> @@ -112,10 +182,23 @@ </type> </element> <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="correlation-key" /> <max value="1" /> </element> + <element id="Task.input:correlation-key.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/bpmn-message" /> + </binding> + </element> <element id="Task.input:correlation-key.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -123,10 +206,12 @@ </element> <element id="Task.input:correlation-key.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/bpmn-message" /> </element> <element id="Task.input:correlation-key.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="correlation-key" /> </element> <element id="Task.input:correlation-key.value[x]"> @@ -138,17 +223,31 @@ <element id="Task.output"> <path value="Task.output" /> <slicing> + <discriminator> + <type value="value" /> + <path value="type.coding.system" /> + </discriminator> <discriminator> <type value="value" /> <path value="type.coding.code" /> </discriminator> - <rules value="open" /> + <rules value="openAtEnd" /> </slicing> </element> <element id="Task.output:error"> <path value="Task.output" /> <sliceName value="error" /> </element> + <element id="Task.output:error.type"> + <path value="Task.output.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskOutputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/bpmn-message" /> + </binding> + </element> <element id="Task.output:error.type.coding"> <path value="Task.output.type.coding" /> <min value="1" /> @@ -156,10 +255,12 @@ </element> <element id="Task.output:error.type.coding.system"> <path value="Task.output.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/bpmn-message" /> </element> <element id="Task.output:error.type.coding.code"> <path value="Task.output.type.coding.code" /> + <min value="1" /> <fixedCode value="error" /> </element> <element id="Task.output:error.value[x]"> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.2.0.xml.post new file mode 100644 index 000000000..cbc621441 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-base-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-base&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.1.0.xml deleted file mode 100644 index fd9d61532..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.1.0.xml +++ /dev/null @@ -1,201 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<StructureDefinition xmlns="http://hl7.org/fhir"> - <meta> - <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> - </meta> - <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-compute-simple-feasibility" /> - <version value="0.1.0" /> - <name value="TaskComputeSimpleFeasibility" /> - <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> - <kind value="resource" /> - <abstract value="false" /> - <type value="Task" /> - <baseDefinition value="http://highmed.org/fhir/StructureDefinition/highmed-task-base" /> - <derivation value="constraint" /> - <differential> - <element id="Task.instantiatesUri"> - <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/computeSimpleFeasibility/1.0.0" /> - </element> - <element id="Task.input"> - <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> - <min value="5" /> - </element> - <element id="Task.input:message-name"> - <path value="Task.input" /> - <sliceName value="message-name" /> - </element> - <element id="Task.input:message-name.value[x]"> - <path value="Task.input.value[x]" /> - <fixedString value="computeSimpleFeasibilityMessage" /> - </element> - <element id="Task.input:business-key"> - <path value="Task.input" /> - <sliceName value="business-key" /> - <min value="1" /> - </element> - <element id="Task.input:correlation-key"> - <path value="Task.input" /> - <sliceName value="correlation-key" /> - <min value="1" /> - </element> - <element id="Task.input:medic-correlation-key"> - <path value="Task.input" /> - <sliceName value="medic-correlation-key" /> - <min value="1" /> - </element> - <element id="Task.input:medic-correlation-key.type.coding"> - <path value="Task.input.type.coding" /> - <min value="1" /> - <max value="1" /> - </element> - <element id="Task.input:medic-correlation-key.type.coding.system"> - <path value="Task.input.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> - </element> - <element id="Task.input:medic-correlation-key.type.coding.code"> - <path value="Task.input.type.coding.code" /> - <fixedCode value="medic-correlation-key" /> - </element> - <element id="Task.input:medic-correlation-key.value[x]"> - <path value="Task.input.value[x]" /> - <type> - <code value="string" /> - </type> - </element> - <element id="Task.input:needs-record-linkage"> - <path value="Task.input" /> - <sliceName value="needs-record-linkage" /> - <min value="1" /> - <max value="1" /> - </element> - <element id="Task.input:needs-record-linkage.type.coding"> - <path value="Task.input.type.coding" /> - <min value="1" /> - <max value="1" /> - </element> - <element id="Task.input:needs-record-linkage.type.coding.system"> - <path value="Task.input.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> - </element> - <element id="Task.input:needs-record-linkage.type.coding.code"> - <path value="Task.input.type.coding.code" /> - <fixedCode value="needs-record-linkage" /> - </element> - <element id="Task.input:needs-record-linkage.value[x]"> - <path value="Task.input.value[x]" /> - <type> - <code value="boolean" /> - </type> - </element> - <element id="Task.output"> - <path value="Task.output" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> - <min value="1" /> - </element> - <element id="Task.output:participating-medics"> - <path value="Task.output" /> - <sliceName value="participating-medics" /> - </element> - <element id="Task.output:participating-medics.extension"> - <path value="Task.output.extension" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="url" /> - </discriminator> - <rules value="open" /> - </slicing> - </element> - <element id="Task.output:participating-medics.extension:group-id"> - <path value="Task.output.extension" /> - <sliceName value="group-id" /> - <min value="1" /> - <max value="1" /> - <type> - <code value="Extension" /> - <profile value="http://highmed.org/fhir/StructureDefinition/group-id" /> - </type> - </element> - <element id="Task.output:participating-medics.type.coding"> - <path value="Task.output.type.coding" /> - <min value="1" /> - <max value="1" /> - </element> - <element id="Task.output:participating-medics.type.coding.system"> - <path value="Task.output.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/feasibility" /> - </element> - <element id="Task.output:participating-medicss.type.coding.code"> - <path value="Task.output.type.coding.code" /> - <patternCode value="participating-medics" /> - </element> - <element id="Task.output:participating-medics.value[x]"> - <path value="Task.output.value[x]" /> - <type> - <code value="string" /> - </type> - </element> - <element id="Task.output:multi-medic-result"> - <path value="Task.output" /> - <sliceName value="multi-medic-result" /> - </element> - <element id="Task.output:multi-medic-result.extension"> - <path value="Task.output.extension" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="url" /> - </discriminator> - <rules value="open" /> - </slicing> - </element> - <element id="Task.output:multi-medic-result.extension:group-id"> - <path value="Task.output.extension" /> - <sliceName value="group-id" /> - <min value="1" /> - <max value="1" /> - <type> - <code value="Extension" /> - <profile value="http://highmed.org/fhir/StructureDefinition/group-id" /> - </type> - </element> - <element id="Task.output:multi-medic-result.type.coding"> - <path value="Task.output.type.coding" /> - <min value="1" /> - <max value="1" /> - </element> - <element id="Task.output:multi-medic-result.type.coding.system"> - <path value="Task.output.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/feasibility" /> - </element> - <element id="Task.output:multi-medic-result.type.coding.code"> - <path value="Task.output.type.coding.code" /> - <patternCode value="multi-medic-result" /> - </element> - <element id="Task.output:multi-medic-result.value[x]"> - <path value="Task.output.value[x]" /> - <type> - <code value="string" /> - </type> - </element> - </differential> -</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.1.0.xml.put deleted file mode 100644 index 905cf17c1..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-compute-simple-feasibility&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.2.0.xml new file mode 100644 index 000000000..147995f0a --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.2.0.xml @@ -0,0 +1,138 @@ +<StructureDefinition xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> + </meta> + <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-compute-simple-feasibility" /> + <version value="0.2.0" /> + <name value="TaskComputeSimpleFeasibility" /> + <status value="draft" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> + <kind value="resource" /> + <abstract value="false" /> + <type value="Task" /> + <baseDefinition value="http://highmed.org/fhir/StructureDefinition/highmed-task-base" /> + <derivation value="constraint" /> + <differential> + <element id="Task.instantiatesUri"> + <path value="Task.instantiatesUri" /> + <fixedUri value="http://highmed.org/bpe/Process/computeSimpleFeasibility/0.2.0" /> + </element> + <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <min value="5" /> + </element> + <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="message-name" /> + </element> + <element id="Task.input:message-name.value[x]"> + <path value="Task.input.value[x]" /> + <fixedString value="computeSimpleFeasibilityMessage" /> + </element> + <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="business-key" /> + <min value="1" /> + </element> + <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="correlation-key" /> + <min value="1" /> + </element> + <element id="Task.input:medic-correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="medic-correlation-key" /> + <min value="1" /> + </element> + <element id="Task.input:medic-correlation-key.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> + <element id="Task.input:medic-correlation-key.type.coding"> + <path value="Task.input.type.coding" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Task.input:medic-correlation-key.type.coding.system"> + <path value="Task.input.type.coding.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> + </element> + <element id="Task.input:medic-correlation-key.type.coding.code"> + <path value="Task.input.type.coding.code" /> + <min value="1" /> + <fixedCode value="medic-correlation-key" /> + </element> + <element id="Task.input:medic-correlation-key.value[x]"> + <path value="Task.input.value[x]" /> + <type> + <code value="string" /> + </type> + </element> + <element id="Task.input:needs-record-linkage"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="needs-record-linkage" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Task.input:needs-record-linkage.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> + <element id="Task.input:needs-record-linkage.type.coding"> + <path value="Task.input.type.coding" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Task.input:needs-record-linkage.type.coding.system"> + <path value="Task.input.type.coding.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> + </element> + <element id="Task.input:needs-record-linkage.type.coding.code"> + <path value="Task.input.type.coding.code" /> + <min value="1" /> + <fixedCode value="needs-record-linkage" /> + </element> + <element id="Task.input:needs-record-linkage.value[x]"> + <path value="Task.input.value[x]" /> + <type> + <code value="boolean" /> + </type> + </element> + </differential> +</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.2.0.xml.post new file mode 100644 index 000000000..fe863b0ca --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-compute-simple-feasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-compute-simple-feasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.1.0.xml.put deleted file mode 100644 index 7ef5ffc1c..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-execute-simple-feasibility&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.2.0.xml similarity index 51% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.2.0.xml index 9e8e29458..d129b69f3 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.2.0.xml @@ -1,17 +1,16 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-execute-simple-feasibility" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="TaskExecuteSimpleFeasibility" /> <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> <abstract value="false" /> <type value="Task" /> @@ -20,20 +19,20 @@ <differential> <element id="Task.instantiatesUri"> <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/executeSimpleFeasibility/1.0.0" /> + <fixedUri value="http://highmed.org/bpe/Process/executeSimpleFeasibility/0.2.0" /> </element> <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> <min value="6" /> + <max value="7" /> </element> <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="message-name" /> </element> @@ -42,21 +41,40 @@ <fixedString value="executeSimpleFeasibilityMessage" /> </element> <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="business-key" /> <min value="1" /> </element> <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="correlation-key" /> <min value="1" /> </element> <element id="Task.input:research-study"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="research-study" /> <min value="1" /> <max value="1" /> </element> + <element id="Task.input:research-study.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> <element id="Task.input:research-study.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -64,25 +82,40 @@ </element> <element id="Task.input:research-study.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> <element id="Task.input:research-study.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="research-study-reference" /> </element> <element id="Task.input:research-study.value[x]"> <path value="Task.input.value[x]" /> <type> <code value="Reference" /> - <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-research-study" /> + <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-research-study-feasibility" /> </type> </element> - <element id="Task.input:needs-record-linkage"> + <element id="Task.input:needs-record-linkage"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="needs-record-linkage" /> <min value="1" /> <max value="1" /> </element> + <element id="Task.input:needs-record-linkage.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> <element id="Task.input:needs-record-linkage.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -90,24 +123,39 @@ </element> <element id="Task.input:needs-record-linkage.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> <element id="Task.input:needs-record-linkage.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="needs-record-linkage" /> </element> <element id="Task.input:needs-record-linkage.value[x]"> <path value="Task.input.value[x]" /> <type> - <code value="boolean" /> + <code value="boolean" /> </type> </element> <element id="Task.input:needs-consent-check"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="needs-consent-check" /> <min value="1" /> <max value="1" /> </element> + <element id="Task.input:needs-consent-check.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> <element id="Task.input:needs-consent-check.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -115,70 +163,58 @@ </element> <element id="Task.input:needs-consent-check.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> <element id="Task.input:needs-consent-check.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="needs-consent-check" /> </element> <element id="Task.input:needs-consent-check.value[x]"> <path value="Task.input.value[x]" /> <type> - <code value="boolean" /> + <code value="boolean" /> </type> </element> - <element id="Task.output"> - <path value="Task.output" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> - <min value="1" /> - </element> - <element id="Task.output:single-medic-result"> - <path value="Task.output" /> - <sliceName value="single-medic-result" /> - </element> - <element id="Task.output:single-medic-result.extension"> - <path value="Task.output.extension" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="url" /> - </discriminator> - <rules value="open" /> - </slicing> - </element> - <element id="Task.output:single-medic-result.extension:group-id"> - <path value="Task.output.extension" /> - <sliceName value="group-id" /> - <min value="1" /> + <element id="Task.input:bloom-filter-configuration"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="bloom-filter-configuration" /> + <min value="0" /> <max value="1" /> - <type> - <code value="Extension" /> - <profile value="http://highmed.org/fhir/StructureDefinition/group-id" /> - </type> </element> - <element id="Task.output:single-medic-result.type.coding"> - <path value="Task.output.type.coding" /> + <element id="Task.input:bloom-filter-configuration.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> + <element id="Task.input:bloom-filter-configuration.type.coding"> + <path value="Task.input.type.coding" /> <min value="1" /> <max value="1" /> </element> - <element id="Task.output:single-medic-result.type.coding.system"> - <path value="Task.output.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/feasibility" /> + <element id="Task.input:bloom-filter-configuration.type.coding.system"> + <path value="Task.input.type.coding.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> - <element id="Task.output:single-medic-result.type.coding.code"> - <path value="Task.output.type.coding.code" /> - <patternCode value="single-medic-result" /> + <element id="Task.input:bloom-filter-configuration.type.coding.code"> + <path value="Task.input.type.coding.code" /> + <min value="1" /> + <fixedCode value="bloom-filter-configuration" /> </element> - <element id="Task.output:single-medic-result.value[x]"> - <path value="Task.output.value[x]" /> + <element id="Task.input:bloom-filter-configuration.value[x]"> + <path value="Task.input.value[x]" /> <type> - <code value="string" /> + <code value="base64Binary" /> </type> </element> </differential> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.2.0.xml.post new file mode 100644 index 000000000..cfabbf53f --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-simple-feasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-execute-simple-feasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.1.0.xml deleted file mode 100644 index fd0b40e85..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.1.0.xml +++ /dev/null @@ -1,80 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<StructureDefinition xmlns="http://hl7.org/fhir"> - <meta> - <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> - </meta> - <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-execute-update-resources" /> - <version value="0.1.0" /> - <name value="TaskExecuteUpdateResources" /> - <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> - <kind value="resource" /> - <abstract value="false" /> - <type value="Task" /> - <baseDefinition value="http://highmed.org/fhir/StructureDefinition/highmed-task-base" /> - <derivation value="constraint" /> - <differential> - <element id="Task.instantiatesUri"> - <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/executeUpdateResources/1.0.0" /> - </element> - <element id="Task.input"> - <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> - <min value="4" /> - </element> - <element id="Task.input:message-name"> - <path value="Task.input" /> - <sliceName value="message-name" /> - </element> - <element id="Task.input:message-name.value[x]"> - <path value="Task.input.value[x]" /> - <fixedString value="executeUpdateResourceMessage" /> - </element> - <element id="Task.input:business-key"> - <path value="Task.input" /> - <sliceName value="business-key" /> - <min value="1" /> - </element> - <element id="Task.input:correlation-key"> - <path value="Task.input" /> - <sliceName value="correlation-key" /> - <min value="1" /> - </element> - <element id="Task.input:bundle"> - <path value="Task.input" /> - <sliceName value="bundle" /> - <min value="1" /> - <max value="1" /> - </element> - <element id="Task.input:bundle.type.coding"> - <path value="Task.input.type.coding" /> - <min value="1" /> - <max value="1" /> - </element> - <element id="Task.input:bundle.type.coding.system"> - <path value="Task.input.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> - </element> - <element id="Task.input:bundle.type.coding.code"> - <path value="Task.input.type.coding.code" /> - <fixedCode value="bundle-reference" /> - </element> - <element id="Task.input:bundle.value[x]"> - <path value="Task.input.value[x]" /> - <type> - <code value="Reference" /> - </type> - </element> - </differential> -</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.1.0.xml.put deleted file mode 100644 index a1f381816..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-execute-update-resources&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.2.0.xml new file mode 100644 index 000000000..60d2034de --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.2.0.xml @@ -0,0 +1,108 @@ +<StructureDefinition xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> + </meta> + <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-execute-update-resources" /> + <version value="0.2.0" /> + <name value="TaskExecuteUpdateResources" /> + <status value="draft" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> + <kind value="resource" /> + <abstract value="false" /> + <type value="Task" /> + <baseDefinition value="http://highmed.org/fhir/StructureDefinition/highmed-task-base" /> + <derivation value="constraint" /> + <differential> + <element id="Task.instantiatesUri"> + <path value="Task.instantiatesUri" /> + <fixedUri value="http://highmed.org/bpe/Process/executeUpdateResources/0.2.0" /> + </element> + <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <min value="4" /> + <max value="4" /> + </element> + <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="message-name" /> + </element> + <element id="Task.input:message-name.value[x]"> + <path value="Task.input.value[x]" /> + <fixedString value="executeUpdateResourcesMessage" /> + </element> + <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="business-key" /> + <min value="1" /> + </element> + <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="correlation-key" /> + <min value="1" /> + </element> + <element id="Task.input:bundle-reference"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="bundle-reference" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Task.input:bundle-reference.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/update-resources" /> + </binding> + </element> + <element id="Task.input:bundle-reference.type.coding"> + <path value="Task.input.type.coding" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Task.input:bundle-reference.type.coding.system"> + <path value="Task.input.type.coding.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/update-resources" /> + </element> + <element id="Task.input:bundle-reference.type.coding.code"> + <path value="Task.input.type.coding.code" /> + <min value="1" /> + <fixedCode value="bundle-reference" /> + </element> + <element id="Task.input:bundle-reference.value[x]"> + <path value="Task.input.value[x]" /> + <type> + <code value="Reference" /> + </type> + </element> + <element id="Task.input:bundle-reference.value[x].reference"> + <path value="Task.input.value[x].reference" /> + <min value="1" /> + </element> + <element id="Task.input:bundle-reference.value[x].identifier"> + <path value="Task.input.value[x].identifier" /> + <max value="0" /> + </element> + </differential> +</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.2.0.xml.post new file mode 100644 index 000000000..d9a795154 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-execute-update-resources&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.1.0.xml.put deleted file mode 100644 index 34a6b1d3b..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.2.0.xml similarity index 60% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.2.0.xml index bde33ad08..3e03dc503 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.2.0.xml @@ -1,17 +1,16 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="TaskMultiMedicResultSimpleFeasibility" /> <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> <abstract value="false" /> <type value="Task" /> @@ -20,40 +19,49 @@ <differential> <element id="Task.instantiatesUri"> <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/requestSimpleFeasibility/1.0.0" /> + <fixedUri value="http://highmed.org/bpe/Process/requestSimpleFeasibility/0.2.0" /> </element> <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> - <min value="4" /> + <min value="5" /> </element> <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="message-name" /> </element> <element id="Task.input:message-name.value[x]"> <path value="Task.input.value[x]" /> - <fixedString value="resultSimpleFeasibilityMessage" /> + <fixedString value="resultMultiMedicSimpleFeasibilityMessage" /> </element> <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="business-key" /> <min value="1" /> </element> <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="correlation-key" /> <min value="1" /> </element> - <element id="Task.input:participating-medics"> + <element id="Task.input:participating-medics"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="participating-medics" /> + <min value="1" /> </element> <element id="Task.input:participating-medics.extension"> <path value="Task.input.extension" /> @@ -69,12 +77,21 @@ <path value="Task.input.extension" /> <sliceName value="group-id" /> <min value="1" /> - <max value="1" /> <type> <code value="Extension" /> <profile value="http://highmed.org/fhir/StructureDefinition/group-id" /> </type> </element> + <element id="Task.input:participating-medics.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> <element id="Task.input:participating-medics.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -82,21 +99,27 @@ </element> <element id="Task.input:participating-medics.type.coding.system"> <path value="Task.input.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/feasibility" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> - <element id="Task.input:participating-medicss.type.coding.code"> + <element id="Task.input:participating-medics.type.coding.code"> <path value="Task.input.type.coding.code" /> - <patternCode value="participating-medics" /> + <min value="1" /> + <fixedCode value="participating-medics" /> </element> <element id="Task.input:participating-medics.value[x]"> <path value="Task.input.value[x]" /> <type> - <code value="string" /> + <code value="unsignedInt" /> </type> </element> <element id="Task.input:multi-medic-result"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="multi-medic-result" /> + <min value="1" /> </element> <element id="Task.input:multi-medic-result.extension"> <path value="Task.input.extension" /> @@ -112,12 +135,21 @@ <path value="Task.input.extension" /> <sliceName value="group-id" /> <min value="1" /> - <max value="1" /> <type> <code value="Extension" /> <profile value="http://highmed.org/fhir/StructureDefinition/group-id" /> </type> </element> + <element id="Task.input:multi-medic-result.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> <element id="Task.input:multi-medic-result.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -125,39 +157,18 @@ </element> <element id="Task.input:multi-medic-result.type.coding.system"> <path value="Task.input.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/feasibility" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> <element id="Task.input:multi-medic-result.type.coding.code"> <path value="Task.input.type.coding.code" /> - <patternCode value="multi-medic-result" /> - </element> - <element id="Task.input:multi-medic-result.value[x]"> - <path value="Task.input.value[x]" /> - <type> - <code value="string" /> - </type> - </element> - <element id="Task.input:error"> - <path value="Task.input" /> - <sliceName value="error" /> - </element> - <element id="Task.input:error.type.coding"> - <path value="Task.input.type.coding" /> <min value="1" /> - <max value="1" /> - </element> - <element id="Task.input:error.type.coding.system"> - <path value="Task.input.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/feasibility" /> + <fixedCode value="multi-medic-result" /> </element> - <element id="Task.input:error.type.coding.code"> - <path value="Task.input.type.coding.code" /> - <patternCode value="error" /> - </element> - <element id="Task.input:error.value[x]"> + <element id="Task.input:multi-medic-result.value[x]"> <path value="Task.input.value[x]" /> <type> - <code value="string" /> + <code value="unsignedInt" /> </type> </element> </differential> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.2.0.xml.post new file mode 100644 index 000000000..ce980dbf6 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.1.0.xml.put deleted file mode 100644 index 60d12388a..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-parent-plugin&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.2.0.xml similarity index 64% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.2.0.xml index 8da0a75f9..a0b2ac1f0 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.2.0.xml @@ -1,17 +1,16 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-parent-plugin" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="ParentPlugin" /> <status value="draft" /> - <date value="2019-10-24" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> <abstract value="false" /> <type value="Task" /> @@ -20,33 +19,31 @@ <differential> <element id="Task.instantiatesUri"> <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/parentPlugin/1.0.0" /> - </element> - <element id="Task.input"> - <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> - <min value="1" /> + <fixedUri value="http://highmed.org/bpe/Process/parentPlugin/0.2.0" /> </element> <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="message-name" /> </element> <element id="Task.input:message-name.value[x]"> <path value="Task.input.value[x]" /> - <fixedString value="pingMessage" /> + <fixedString value="parentPluginMessage" /> </element> <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="business-key" /> <max value="0" /> </element> <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="correlation-key" /> <max value="0" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.2.0.xml.post new file mode 100644 index 000000000..2bb5a3b82 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-parent-plugin-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-parent-plugin&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.1.0.xml.put deleted file mode 100644 index 598b668c5..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-ping&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.2.0.xml similarity index 60% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.2.0.xml index 4f41d6f8d..f41e81a37 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.2.0.xml @@ -1,17 +1,16 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-ping" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="TaskPing" /> <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> <abstract value="false" /> <type value="Task" /> @@ -20,20 +19,20 @@ <differential> <element id="Task.instantiatesUri"> <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/pong/1.0.0" /> + <fixedUri value="http://highmed.org/bpe/Process/pong/0.2.0" /> </element> <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> <min value="3" /> + <max value="3" /> </element> <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="message-name" /> </element> @@ -42,11 +41,17 @@ <fixedString value="pingMessage" /> </element> <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="business-key" /> <min value="1" /> </element> <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="correlation-key" /> <min value="1" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.2.0.xml.post new file mode 100644 index 000000000..9a95c9033 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-ping-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-ping&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.1.0.xml.put deleted file mode 100644 index ef4a509ae..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-pong&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.2.0.xml similarity index 60% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.2.0.xml index 918e64ec7..ab36550dc 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.2.0.xml @@ -1,17 +1,16 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-pong" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="TaskPong" /> <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> <abstract value="false" /> <type value="Task" /> @@ -20,20 +19,20 @@ <differential> <element id="Task.instantiatesUri"> <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/ping/1.0.0" /> + <fixedUri value="http://highmed.org/bpe/Process/ping/0.2.0" /> </element> <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> <min value="3" /> + <max value="3" /> </element> <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="message-name" /> </element> @@ -42,11 +41,17 @@ <fixedString value="pongMessage" /> </element> <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="business-key" /> <min value="1" /> </element> <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="correlation-key" /> <min value="1" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.2.0.xml.post new file mode 100644 index 000000000..59bf9f095 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-pong-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-pong&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.1.0.xml.put deleted file mode 100644 index 4c6e6db28..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-request-simple-feasibility&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.2.0.xml similarity index 56% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.2.0.xml index e4252546b..4b36f09f2 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.2.0.xml @@ -1,17 +1,16 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-request-simple-feasibility" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="TaskRequestSimpleFeasibility" /> <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> <abstract value="false" /> <type value="Task" /> @@ -20,20 +19,20 @@ <differential> <element id="Task.instantiatesUri"> <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/requestSimpleFeasibility/1.0.0" /> + <fixedUri value="http://highmed.org/bpe/Process/requestSimpleFeasibility/0.2.0" /> </element> <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value"/> - <path value="type.coding.code"/> - </discriminator> - <rules value="open"/> - </slicing> <min value="4" /> + <max value="4" /> </element> <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="message-name" /> </element> @@ -42,47 +41,89 @@ <fixedString value="requestSimpleFeasibilityMessage" /> </element> <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="business-key" /> <max value="0" /> </element> <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="correlation-key" /> <max value="0" /> </element> - <element id="Task.input:research-study"> + <element id="Task.input:research-study-reference"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> - <sliceName value="research-study" /> + <sliceName value="research-study-reference" /> <min value="1" /> <max value="1" /> </element> - <element id="Task.input:research-study.type.coding"> + <element id="Task.input:research-study-reference.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> + <element id="Task.input:research-study-reference.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> <max value="1" /> </element> - <element id="Task.input:research-study.type.coding.system"> + <element id="Task.input:research-study-reference.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> - <element id="Task.input:research-study.type.coding.code"> + <element id="Task.input:research-study-reference.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="research-study-reference" /> </element> - <element id="Task.input:research-study.value[x]"> + <element id="Task.input:research-study-reference.value[x]"> <path value="Task.input.value[x]" /> <type> <code value="Reference" /> - <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-research-study" /> + <targetProfile value="http://highmed.org/fhir/StructureDefinition/highmed-research-study-feasibility" /> </type> </element> + <element id="Task.input:research-study-reference.value[x].reference"> + <path value="Task.input.value[x].reference" /> + <min value="1" /> + </element> + <element id="Task.input:research-study-reference.value[x].identifier"> + <path value="Task.input.value[x].identifier" /> + <max value="0" /> + </element> <element id="Task.input:needs-record-linkage"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="needs-record-linkage" /> <min value="1" /> <max value="1" /> </element> + <element id="Task.input:needs-record-linkage.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> <element id="Task.input:needs-record-linkage.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -90,24 +131,39 @@ </element> <element id="Task.input:needs-record-linkage.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> <element id="Task.input:needs-record-linkage.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="needs-record-linkage" /> </element> <element id="Task.input:needs-record-linkage.value[x]"> <path value="Task.input.value[x]" /> <type> - <code value="boolean" /> + <code value="boolean" /> </type> </element> <element id="Task.input:needs-consent-check"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="needs-consent-check" /> <min value="1" /> <max value="1" /> </element> + <element id="Task.input:needs-consent-check.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> <element id="Task.input:needs-consent-check.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -115,34 +171,25 @@ </element> <element id="Task.input:needs-consent-check.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> <element id="Task.input:needs-consent-check.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="needs-consent-check" /> </element> <element id="Task.input:needs-consent-check.value[x]"> <path value="Task.input.value[x]" /> <type> - <code value="boolean" /> + <code value="boolean" /> </type> </element> - <element id="Task.output"> - <path value="Task.output" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> - <min value="1" /> - </element> <element id="Task.output:participating-medics"> <path value="Task.output" /> <sliceName value="participating-medics" /> </element> - <element id="Task.output:participating-medics.extension"> + <element id="Task.output:participating-medics.extension"> <path value="Task.output.extension" /> <slicing> <discriminator> @@ -156,12 +203,21 @@ <path value="Task.output.extension" /> <sliceName value="group-id" /> <min value="1" /> - <max value="1" /> <type> <code value="Extension" /> <profile value="http://highmed.org/fhir/StructureDefinition/group-id" /> </type> </element> + <element id="Task.output:participating-medics.type"> + <path value="Task.output.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskOutputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> <element id="Task.output:participating-medics.type.coding"> <path value="Task.output.type.coding" /> <min value="1" /> @@ -169,23 +225,25 @@ </element> <element id="Task.output:participating-medics.type.coding.system"> <path value="Task.output.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/feasibility" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> - <element id="Task.output:participating-medicss.type.coding.code"> + <element id="Task.output:participating-medics.type.coding.code"> <path value="Task.output.type.coding.code" /> - <patternCode value="participating-medics" /> + <min value="1" /> + <fixedCode value="participating-medics" /> </element> <element id="Task.output:participating-medics.value[x]"> <path value="Task.output.value[x]" /> <type> - <code value="string" /> + <code value="unsignedInt" /> </type> </element> <element id="Task.output:multi-medic-result"> <path value="Task.output" /> <sliceName value="multi-medic-result" /> </element> - <element id="Task.output:multi-medic-result.extension"> + <element id="Task.output:multi-medic-result.extension"> <path value="Task.output.extension" /> <slicing> <discriminator> @@ -199,12 +257,21 @@ <path value="Task.output.extension" /> <sliceName value="group-id" /> <min value="1" /> - <max value="1" /> <type> <code value="Extension" /> <profile value="http://highmed.org/fhir/StructureDefinition/group-id" /> </type> </element> + <element id="Task.output:multi-medic-result.type"> + <path value="Task.output.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskOutputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> <element id="Task.output:multi-medic-result.type.coding"> <path value="Task.output.type.coding" /> <min value="1" /> @@ -212,16 +279,18 @@ </element> <element id="Task.output:multi-medic-result.type.coding.system"> <path value="Task.output.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/feasibility" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> </element> <element id="Task.output:multi-medic-result.type.coding.code"> <path value="Task.output.type.coding.code" /> - <patternCode value="multi-medic-result" /> + <min value="1" /> + <fixedCode value="multi-medic-result" /> </element> <element id="Task.output:multi-medic-result.value[x]"> <path value="Task.output.value[x]" /> <type> - <code value="string" /> + <code value="unsignedInt" /> </type> </element> </differential> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.2.0.xml.post new file mode 100644 index 000000000..5c5e82cbc --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-simple-feasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-request-simple-feasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.1.0.xml.put deleted file mode 100644 index 122329b31..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-request-update-resources&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.2.0.xml similarity index 51% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.2.0.xml index 0ccda7d46..c3096393c 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.2.0.xml @@ -1,17 +1,16 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-request-update-resources" /> - <version value="0.1.0" /> + <version value="0.2.0" /> <name value="TaskRequestUpdateResources" /> <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> <abstract value="false" /> <type value="Task" /> @@ -20,68 +19,111 @@ <differential> <element id="Task.instantiatesUri"> <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/requestUpdateResources/1.0.0" /> + <fixedUri value="http://highmed.org/bpe/Process/requestUpdateResources/0.2.0" /> </element> <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="openAtEnd" /> - </slicing> <min value="3" /> + <max value="3" /> </element> <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="message-name" /> </element> <element id="Task.input:message-name.value[x]"> <path value="Task.input.value[x]" /> - <fixedString value="executeUpdateResourcesMessage" /> + <fixedString value="requestUpdateResourcesMessage" /> </element> <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="business-key" /> <max value="0" /> </element> <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="correlation-key" /> <max value="0" /> </element> - <element id="Task.input:bundle"> + <element id="Task.input:bundle-reference"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> - <sliceName value="bundle" /> + <sliceName value="bundle-reference" /> <min value="1" /> <max value="1" /> </element> - <element id="Task.input:bundle.type.coding"> + <element id="Task.input:bundle-reference.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/update-resources" /> + </binding> + </element> + <element id="Task.input:bundle-reference.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> <max value="1" /> </element> - <element id="Task.input:bundle.type.coding.system"> + <element id="Task.input:bundle-reference.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/update-resources" /> </element> - <element id="Task.input:bundle.type.coding.code"> + <element id="Task.input:bundle-reference.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="bundle-reference" /> </element> - <element id="Task.input:bundle.value[x]"> + <element id="Task.input:bundle-reference.value[x]"> <path value="Task.input.value[x]" /> <type> <code value="Reference" /> + <targetProfile value="http://hl7.org/fhir/StructureDefinition/Bundle" /> </type> </element> + <element id="Task.input:bundle-reference.value[x].reference"> + <path value="Task.input.value[x].reference" /> + <min value="1" /> + </element> + <element id="Task.input:bundle-reference.value[x].identifier"> + <path value="Task.input.value[x].identifier" /> + <max value="0" /> + </element> <element id="Task.input:organization-identifier-search-parameter"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="organization-identifier-search-parameter" /> <min value="1" /> <max value="1" /> </element> + <element id="Task.input:organization-identifier-search-parameter.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/update-resources" /> + </binding> + </element> <element id="Task.input:organization-identifier-search-parameter.type.coding"> <path value="Task.input.type.coding" /> <min value="1" /> @@ -89,10 +131,12 @@ </element> <element id="Task.input:organization-identifier-search-parameter.type.coding.system"> <path value="Task.input.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/update-resources" /> </element> <element id="Task.input:organization-identifier-search-parameter.type.coding.code"> <path value="Task.input.type.coding.code" /> + <min value="1" /> <fixedCode value="organization-identifier-search-parameter" /> </element> <element id="Task.input:organization-identifier-search-parameter.value[x]"> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.2.0.xml.post new file mode 100644 index 000000000..cc381ddd7 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-request-update-resources-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-request-update-resources&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.1.0.xml deleted file mode 100644 index fc6e84037..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.1.0.xml +++ /dev/null @@ -1,121 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<StructureDefinition xmlns="http://hl7.org/fhir"> - <meta> - <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> - </meta> - <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility" /> - <version value="0.1.0" /> - <name value="TaskSingleMedicResultSimpleFeasibility" /> - <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> - <kind value="resource" /> - <abstract value="false" /> - <type value="Task" /> - <baseDefinition value="http://highmed.org/fhir/StructureDefinition/highmed-task-base" /> - <derivation value="constraint" /> - <differential> - <element id="Task.instantiatesUri"> - <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/computeSimpleFeasibility/1.0.0" /> - </element> - <element id="Task.input"> - <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> - <min value="4" /> - </element> - <element id="Task.input:message-name"> - <path value="Task.input" /> - <sliceName value="message-name" /> - </element> - <element id="Task.input:message-name.value[x]"> - <path value="Task.input.value[x]" /> - <fixedString value="resultSimpleFeasibilityMessage" /> - </element> - <element id="Task.input:business-key"> - <path value="Task.input" /> - <sliceName value="business-key" /> - <min value="1" /> - </element> - <element id="Task.input:correlation-key"> - <path value="Task.input" /> - <sliceName value="correlation-key" /> - <min value="1" /> - </element> - <element id="Task.input:single-medic-result"> - <path value="Task.input" /> - <sliceName value="single-medic-result" /> - </element> - <element id="Task.input:single-medic-result.extension"> - <path value="Task.input.extension" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="url" /> - </discriminator> - <rules value="open" /> - </slicing> - </element> - <element id="Task.input:single-medic-result.extension:group-id"> - <path value="Task.input.extension" /> - <sliceName value="group-id" /> - <min value="1" /> - <max value="1" /> - <type> - <code value="Extension" /> - <profile value="http://highmed.org/fhir/StructureDefinition/group-id" /> - </type> - </element> - <element id="Task.input:single-medic-result.type.coding"> - <path value="Task.input.type.coding" /> - <min value="1" /> - <max value="1" /> - </element> - <element id="Task.input:single-medic-result.type.coding.system"> - <path value="Task.input.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/feasibility" /> - </element> - <element id="Task.input:single-medic-result.type.coding.code"> - <path value="Task.input.type.coding.code" /> - <patternCode value="single-medic-result" /> - </element> - <element id="Task.input:single-medic-result.value[x]"> - <path value="Task.input.value[x]" /> - <type> - <code value="string" /> - </type> - </element> - <element id="Task.input:error"> - <path value="Task.input" /> - <sliceName value="error" /> - </element> - <element id="Task.input:error.type.coding"> - <path value="Task.input.type.coding" /> - <min value="1" /> - <max value="1" /> - </element> - <element id="Task.input:error.type.coding.system"> - <path value="Task.input.type.coding.system" /> - <fixedUri value="http://highmed.org/fhir/NamingSystem/feasibility" /> - </element> - <element id="Task.input:error.type.coding.code"> - <path value="Task.input.type.coding.code" /> - <patternCode value="error" /> - </element> - <element id="Task.input:error.value[x]"> - <path value="Task.input.value[x]" /> - <type> - <code value="string" /> - </type> - </element> - </differential> -</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.1.0.xml.put deleted file mode 100644 index a05b9dd69..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.2.0.xml new file mode 100644 index 000000000..b976ad9ff --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.2.0.xml @@ -0,0 +1,186 @@ +<StructureDefinition xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> + </meta> + <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility" /> + <version value="0.2.0" /> + <name value="TaskSingleMedicResultSimpleFeasibility" /> + <status value="draft" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> + <kind value="resource" /> + <abstract value="false" /> + <type value="Task" /> + <baseDefinition value="http://highmed.org/fhir/StructureDefinition/highmed-task-base" /> + <derivation value="constraint" /> + <differential> + <element id="Task.instantiatesUri"> + <path value="Task.instantiatesUri" /> + <fixedUri value="http://highmed.org/bpe/Process/computeSimpleFeasibility/0.2.0" /> + </element> + <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <min value="4" /> + </element> + <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="message-name" /> + </element> + <element id="Task.input:message-name.value[x]"> + <path value="Task.input.value[x]" /> + <fixedString value="resultSingleMedicSimpleFeasibilityMessage" /> + </element> + <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="business-key" /> + <min value="1" /> + </element> + <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="correlation-key" /> + <min value="1" /> + </element> + <element id="Task.input:single-medic-result"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="single-medic-result" /> + <min value="0" /> + <max value="*" /> + </element> + <element id="Task.input:single-medic-result.extension"> + <path value="Task.input.extension" /> + <slicing> + <discriminator> + <type value="value" /> + <path value="url" /> + </discriminator> + <rules value="open" /> + </slicing> + </element> + <element id="Task.input:single-medic-result.extension:group-id"> + <path value="Task.input.extension" /> + <sliceName value="group-id" /> + <min value="1" /> + <type> + <code value="Extension" /> + <profile value="http://highmed.org/fhir/StructureDefinition/group-id" /> + </type> + </element> + <element id="Task.input:single-medic-result.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> + <element id="Task.input:single-medic-result.type.coding"> + <path value="Task.input.type.coding" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Task.input:single-medic-result.type.coding.system"> + <path value="Task.input.type.coding.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> + </element> + <element id="Task.input:single-medic-result.type.coding.code"> + <path value="Task.input.type.coding.code" /> + <min value="1" /> + <fixedCode value="single-medic-result" /> + </element> + <element id="Task.input:single-medic-result.value[x]"> + <path value="Task.input.value[x]" /> + <type> + <code value="unsignedInt" /> + </type> + </element> + <element id="Task.input:single-medic-result-reference"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> + <path value="Task.input" /> + <sliceName value="single-medic-result-reference" /> + <min value="0" /> + <max value="*" /> + </element> + <element id="Task.input:single-medic-result-reference.extension"> + <path value="Task.input.extension" /> + <slicing> + <discriminator> + <type value="value" /> + <path value="url" /> + </discriminator> + <rules value="open" /> + </slicing> + </element> + <element id="Task.input:single-medic-result-reference.extension:group-id"> + <path value="Task.input.extension" /> + <sliceName value="group-id" /> + <min value="1" /> + <type> + <code value="Extension" /> + <profile value="http://highmed.org/fhir/StructureDefinition/group-id" /> + </type> + </element> + <element id="Task.input:single-medic-result-reference.type"> + <path value="Task.input.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskInputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/feasibility" /> + </binding> + </element> + <element id="Task.input:single-medic-result-reference.type.coding"> + <path value="Task.input.type.coding" /> + <min value="1" /> + <max value="1" /> + </element> + <element id="Task.input:single-medic-result-reference.type.coding.system"> + <path value="Task.input.type.coding.system" /> + <min value="1" /> + <fixedUri value="http://highmed.org/fhir/CodeSystem/feasibility" /> + </element> + <element id="Task.input:single-medic-result-reference.type.coding.code"> + <path value="Task.input.type.coding.code" /> + <min value="1" /> + <fixedCode value="single-medic-result-reference" /> + </element> + <element id="Task.input:single-medic-result-reference.value[x]"> + <path value="Task.input.value[x]" /> + <type> + <code value="Reference" /> + <targetProfile value="http://hl7.org/fhir/StructureDefinition/Binary" /> + </type> + </element> + <element id="Task.input:single-medic-result-reference.value[x].reference"> + <path value="Task.input.value[x].reference" /> + <min value="1" /> + </element> + <element id="Task.input:single-medic-result-reference.value[x].identifier"> + <path value="Task.input.value[x].identifier" /> + <max value="0" /> + </element> + </differential> +</StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.2.0.xml.post new file mode 100644 index 000000000..1d4b340b3 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-process-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-ping-process-0.2.0.xml similarity index 53% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-process-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-ping-process-0.2.0.xml index 631e2fb42..e20075f59 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-process-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-ping-process-0.2.0.xml @@ -1,17 +1,16 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> - <url value="http://highmed.org/fhir/StructureDefinition/highemd-task-start-process" /> - <version value="0.1.0" /> + <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process" /> + <version value="0.2.0" /> <name value="TaskStartProcess" /> <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> <abstract value="false" /> <type value="Task" /> @@ -20,33 +19,38 @@ <differential> <element id="Task.instantiatesUri"> <path value="Task.instantiatesUri" /> - <fixedUri value="http://highmed.org/bpe/Process/ping/1.0.0" /> + <fixedUri value="http://highmed.org/bpe/Process/ping/0.2.0" /> </element> <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> - <min value="1" /> + <max value="1" /> </element> <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="message-name" /> </element> <element id="Task.input:message-name.value[x]"> <path value="Task.input.value[x]" /> - <fixedString value="startProcessMessage" /> + <fixedString value="startPingProcessMessage" /> </element> <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="business-key" /> <max value="0" /> </element> <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="correlation-key" /> <max value="0" /> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-ping-process-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-ping-process-0.2.0.xml.post new file mode 100644 index 000000000..f7c9be801 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-ping-process-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-process-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-process-0.1.0.xml.put deleted file mode 100644 index e01ccbc47..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-start-process-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highemd-task-start-process&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.1.0.xml.put deleted file mode 100644 index 6fdeacb68..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -StructureDefinition?url=http://highmed.org/fhir/StructureDefinition/highmed-task-update-whitelist&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.2.0.xml similarity index 52% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.2.0.xml index 003c926a9..8881d43e7 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.2.0.xml @@ -1,35 +1,37 @@ -<?xml version="1.0" encoding="utf-8"?> <StructureDefinition xmlns="http://hl7.org/fhir"> <meta> <tag> - <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> - <code value="REMOTE"/> - </tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role" /> + <code value="REMOTE" /> + </tag> </meta> <url value="http://highmed.org/fhir/StructureDefinition/highmed-task-update-whitelist" /> - <version value="0.1.0" /> - <name value="TaskUpdateWhiteList" /> + <version value="0.2.0" /> + <name value="TaskUpdateWhitelist" /> <status value="draft" /> - <date value="2019-05-21" /> - <fhirVersion value="4.0.0" /> + <date value="2020-05-25" /> + <fhirVersion value="4.0.1" /> <kind value="resource" /> <abstract value="false" /> <type value="Task" /> <baseDefinition value="http://highmed.org/fhir/StructureDefinition/highmed-task-base" /> <derivation value="constraint" /> <differential> + <element id="Task.instantiatesUri"> + <path value="Task.instantiatesUri" /> + <fixedUri value="http://highmed.org/bpe/Process/updateWhitelist/0.2.0" /> + </element> <element id="Task.input"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> - <slicing> - <discriminator> - <type value="value" /> - <path value="type.coding.code" /> - </discriminator> - <rules value="closed" /> - </slicing> - <min value="1" /> + <max value="1" /> </element> <element id="Task.input:message-name"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="message-name" /> </element> @@ -38,32 +40,36 @@ <fixedString value="updateWhitelistMessage" /> </element> <element id="Task.input:business-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="business-key" /> <max value="0" /> </element> <element id="Task.input:correlation-key"> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"> + <valueString value="Parameter" /> + </extension> <path value="Task.input" /> <sliceName value="correlation-key" /> <max value="0" /> </element> - <element id="Task.output"> - <path value="Task.output"/> - <slicing> - <discriminator> - <type value="value"/> - <path value="type.coding.code"/> - </discriminator> - <rules value="open"/> - </slicing> - <min value="1" /> - </element> <element id="Task.output:whitelist"> <path value="Task.output" /> <sliceName value="whitelist" /> - <min value="0" /> <max value="1" /> </element> + <element id="Task.output:whitelist.type"> + <path value="Task.output.type" /> + <binding> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName"> + <valueString value="TaskOutputParameterType" /> + </extension> + <strength value="required" /> + <valueSet value="http://highmed.org/fhir/ValueSet/update-whitelist" /> + </binding> + </element> <element id="Task.output:whitelist.type.coding"> <path value="Task.output.type.coding" /> <min value="1" /> @@ -71,17 +77,27 @@ </element> <element id="Task.output:whitelist.type.coding.system"> <path value="Task.output.type.coding.system" /> + <min value="1" /> <fixedUri value="http://highmed.org/fhir/CodeSystem/update-whitelist" /> </element> <element id="Task.output:whitelist.type.coding.code"> <path value="Task.output.type.coding.code" /> - <fixedCode value="HiGHmed_white_list" /> + <min value="1" /> + <fixedCode value="highmed_whitelist" /> </element> <element id="Task.output:whitelist.value[x]"> <path value="Task.output.value[x]" /> <type> - <code value="string" /> + <code value="Reference" /> </type> </element> + <element id="Task.output:whitelist.value[x].reference"> + <path value="Task.output.value[x].reference" /> + <min value="1" /> + </element> + <element id="Task.output:whitelist.value[x].identifier"> + <path value="Task.output.value[x].identifier" /> + <max value="0" /> + </element> </differential> </StructureDefinition> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.2.0.xml.post new file mode 100644 index 000000000..13b1bb447 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/StructureDefinition/highmed-task-update-whitelist-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/StructureDefinition/highmed-task-update-whitelist&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/Subscription/bpmn-task-subscription.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/Subscription/bpmn-task-subscription.xml index 73c8dcba7..59582f7bb 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/Subscription/bpmn-task-subscription.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/Subscription/bpmn-task-subscription.xml @@ -1,5 +1,4 @@ -<Subscription xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir" - xsi:schemaLocation="http://hl7.org/fhir http://www.hl7.org/fhir/fhir-base.xsd"> +<Subscription xmlns="http://hl7.org/fhir"> <meta> <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/Subscription/bpmn-task-subscription.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/Subscription/bpmn-task-subscription.xml.post new file mode 100755 index 000000000..44827415c --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/Subscription/bpmn-task-subscription.xml.post @@ -0,0 +1 @@ +criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/Subscription/bpmn-task-subscription.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/Subscription/bpmn-task-subscription.xml.put deleted file mode 100755 index 683096ccf..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/Subscription/bpmn-task-subscription.xml.put +++ /dev/null @@ -1 +0,0 @@ -Subscription?criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/authorization-role-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/authorization-role-0.2.0.xml new file mode 100644 index 000000000..0e4887e6b --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/authorization-role-0.2.0.xml @@ -0,0 +1,23 @@ +<ValueSet xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> + <code value="REMOTE"/> + </tag> + </meta> + <url value="http://highmed.org/fhir/ValueSet/authorization-role"/> + <version value="0.2.0"/> + <name value="HiGHmed_Authorization_Role"/> + <title value="HiGHmed Authorization Role"/> + <status value="active"/> + <experimental value="false"/> + <date value="2020-05-25"/> + <publisher value="HiGHmed"/> + <description value="ValueSet with authorization roles"/> + <immutable value="true"/> + <compose> + <include> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> + </include> + </compose> +</ValueSet> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/authorization-role-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/authorization-role-0.2.0.xml.post new file mode 100644 index 000000000..0ff5c7975 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/authorization-role-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/ValueSet/authorization-role&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/bpmn-message-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/bpmn-message-0.2.0.xml new file mode 100644 index 000000000..43bbc8654 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/bpmn-message-0.2.0.xml @@ -0,0 +1,24 @@ +<ValueSet xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> + <code value="REMOTE"/> + </tag> + </meta> + <url value="http://highmed.org/fhir/ValueSet/bpmn-message"/> + <version value="0.2.0"/> + <name value="HiGHmed_Bpmn_Message_Values"/> + <title value="HiGHmed BPMN message values"/> + <status value="active"/> + <experimental value="false"/> + <date value="2020-05-25"/> + <publisher value="HiGHmed"/> + <description + value="ValueSet with standard BPMN message values for Task resources"/> + <immutable value="true"/> + <compose> + <include> + <system value="http://highmed.org/fhir/CodeSystem/bpmn-message"/> + </include> + </compose> +</ValueSet> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/bpmn-message-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/bpmn-message-0.2.0.xml.post new file mode 100644 index 000000000..ff71c84e3 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/bpmn-message-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/ValueSet/bpmn-message&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/feasibility-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/feasibility-0.2.0.xml new file mode 100644 index 000000000..b79eab934 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/feasibility-0.2.0.xml @@ -0,0 +1,23 @@ +<ValueSet xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> + <code value="REMOTE"/> + </tag> + </meta> + <url value="http://highmed.org/fhir/ValueSet/feasibility"/> + <version value="0.2.0"/> + <name value="HiGHmed_Feasibility"/> + <title value="HiGHmed Feasibility"/> + <status value="active"/> + <experimental value="false"/> + <date value="2020-05-25"/> + <publisher value="HiGHmed"/> + <description value="ValueSet with standard values for feasibility processes"/> + <immutable value="true"/> + <compose> + <include> + <system value="http://highmed.org/fhir/CodeSystem/feasibility"/> + </include> + </compose> +</ValueSet> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/feasibility-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/feasibility-0.2.0.xml.post new file mode 100644 index 000000000..b77245506 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/feasibility-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/ValueSet/feasibility&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/organization-type-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/organization-type-0.2.0.xml new file mode 100644 index 000000000..6f0263a9c --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/organization-type-0.2.0.xml @@ -0,0 +1,24 @@ +<ValueSet xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> + <code value="REMOTE"/> + </tag> + </meta> + <url value="http://highmed.org/fhir/ValueSet/organization-type"/> + <version value="0.2.0"/> + <name value="HiGHmed_Organization_Type"/> + <title value="HiGHmed Organization Type"/> + <status value="active"/> + <experimental value="false"/> + <date value="2020-05-25"/> + <publisher value="HiGHmed"/> + <description + value="ValueSet with HiGHmed organization types used in Organization resources"/> + <immutable value="true"/> + <compose> + <include> + <system value="http://highmed.org/fhir/CodeSystem/organization-type"/> + </include> + </compose> +</ValueSet> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/organization-type-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/organization-type-0.2.0.xml.post new file mode 100644 index 000000000..579b5efe5 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/organization-type-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/ValueSet/organization-type&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.1.0.xml.put b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.1.0.xml.put deleted file mode 100755 index 66958045f..000000000 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.1.0.xml.put +++ /dev/null @@ -1 +0,0 @@ -ValueSet?url=http://highmed.org/fhir/ValueSet/query-type&version=0.1.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.1.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.2.0.xml similarity index 82% rename from dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.1.0.xml rename to dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.2.0.xml index 7f1a0b28a..5cbbdbbe6 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.1.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.2.0.xml @@ -6,15 +6,15 @@ </tag> </meta> <url value="http://highmed.org/fhir/ValueSet/query-type"/> - <version value="0.1.0"/> + <version value="0.2.0"/> <name value="HiGHmed_Query_Type"/> <title value="HiGHmed Query Type"/> <status value="active"/> <experimental value="false"/> - <date value="2019-09-23T09:40:00+02:00"/> + <date value="2020-05-25"/> <publisher value="HiGHmed"/> <description - value="ValueSystem with HiGHmed query types used in Group resources query extension of the expression datatype"/> + value="ValueSet with HiGHmed query types used in Group resources query extension of the expression datatype"/> <immutable value="true"/> <compose> <include> diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.2.0.xml.post new file mode 100755 index 000000000..116406caa --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/query-type-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/ValueSet/query-type&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-resources-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-resources-0.2.0.xml new file mode 100644 index 000000000..c4e7d1914 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-resources-0.2.0.xml @@ -0,0 +1,24 @@ +<ValueSet xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> + <code value="REMOTE"/> + </tag> + </meta> + <url value="http://highmed.org/fhir/ValueSet/update-resources"/> + <version value="0.2.0"/> + <name value="HiGHmed_Update_Resources"/> + <title value="HiGHmed Update Resources"/> + <status value="active"/> + <experimental value="false"/> + <date value="2020-05-25"/> + <publisher value="HiGHmed"/> + <description + value="ValueSet with standard values for the process update resources"/> + <immutable value="true"/> + <compose> + <include> + <system value="http://highmed.org/fhir/CodeSystem/update-resources"/> + </include> + </compose> +</ValueSet> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-resources-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-resources-0.2.0.xml.post new file mode 100644 index 000000000..c7495663a --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-resources-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/ValueSet/update-resources&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-whitelist-0.2.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-whitelist-0.2.0.xml new file mode 100644 index 000000000..a389370b1 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-whitelist-0.2.0.xml @@ -0,0 +1,24 @@ +<ValueSet xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> + <code value="REMOTE"/> + </tag> + </meta> + <url value="http://highmed.org/fhir/ValueSet/update-whitelist"/> + <version value="0.2.0"/> + <name value="HiGHmed_Update_Whitelist"/> + <title value="HiGHmed Update Whitelist"/> + <status value="active"/> + <experimental value="false"/> + <date value="2020-05-25"/> + <publisher value="HiGHmed"/> + <description + value="ValueSet with standard values for the process update whitelist"/> + <immutable value="true"/> + <compose> + <include> + <system value="http://highmed.org/fhir/CodeSystem/update-whitelist"/> + </include> + </compose> +</ValueSet> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-whitelist-0.2.0.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-whitelist-0.2.0.xml.post new file mode 100644 index 000000000..10e003b0d --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/update-whitelist-0.2.0.xml.post @@ -0,0 +1 @@ +url=http://highmed.org/fhir/ValueSet/update-whitelist&version=0.2.0 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/valueset-mimetypes.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/valueset-mimetypes.xml new file mode 100644 index 000000000..17fcf9110 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/valueset-mimetypes.xml @@ -0,0 +1,61 @@ +<ValueSet xmlns="http://hl7.org/fhir"> + <meta> + <profile value="http://hl7.org/fhir/StructureDefinition/shareablevalueset"/> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> + <code value="REMOTE"/> + </tag> + </meta> + <text> + <status value="generated"/> + <div xmlns="http://www.w3.org/1999/xhtml"> + <h2>MimeType</h2> + <div> + <p>This value set includes all possible codes from BCP-13 (http://tools.ietf.org/html/bcp13)</p> + + </div> + <p>This value set includes codes from the following code systems:</p> + <ul> + <li>Include all codes defined in + <code>urn:ietf:bcp:13</code> + </li> + </ul> + </div> + </text> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-wg"> + <valueCode value="fhir"/> + </extension> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status"> + <valueCode value="normative"/> + </extension> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-normative-version"> + <valueCode value="4.0.0"/> + </extension> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm"> + <valueInteger value="5"/> + </extension> + <url value="http://hl7.org/fhir/ValueSet/mimetypes"/> + <identifier> + <system value="urn:ietf:rfc:3986"/> + <value value="urn:oid:2.16.840.1.113883.4.642.3.1024"/> + </identifier> + <version value="4.0.1"/> + <name value="Mime Types"/> + <title value="MimeType"/> + <status value="active"/> + <experimental value="false"/> + <date value="2019-11-01T09:29:23+11:00"/> + <publisher value="HL7 International - FHIR-Infrastructure"/> + <contact> + <telecom> + <system value="url"/> + <value value="http://hl7.org/fhir"/> + </telecom> + </contact> + <description value="This value set includes all possible codes from BCP-13 (http://tools.ietf.org/html/bcp13)"/> + <compose> + <include> + <system value="urn:ietf:bcp:13"/> + </include> + </compose> +</ValueSet> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/valueset-mimetypes.xml.post b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/valueset-mimetypes.xml.post new file mode 100644 index 000000000..bb1677f00 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/ValueSet/valueset-mimetypes.xml.post @@ -0,0 +1 @@ +url=http://hl7.org/fhir/ValueSet/mimetypes&version=4.0.1 \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/client/ClientProviderTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/client/ClientProviderTest.java index 2391255be..71326b3bc 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/client/ClientProviderTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/client/ClientProviderTest.java @@ -15,7 +15,7 @@ import org.highmed.dsf.fhir.dao.EndpointDao; import org.highmed.dsf.fhir.function.SupplierWithSqlException; import org.highmed.dsf.fhir.help.ExceptionHandler; -import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceCleaner; import org.highmed.fhir.client.FhirWebserviceClient; import org.junit.Before; import org.junit.Test; @@ -24,7 +24,7 @@ public class ClientProviderTest { - private ReferenceExtractor referenceExtractor; + private ReferenceCleaner referenceCleaner; private EndpointDao endpointDao; private ExceptionHandler exceptionHandler; private ClientProvider provider; @@ -45,13 +45,13 @@ public void before() throws Exception String remoteProxyUsername = null; String remoteProxySchemeHostPort = null; FhirContext fhirContext = mock(FhirContext.class); - referenceExtractor = mock(ReferenceExtractor.class); + referenceCleaner = mock(ReferenceCleaner.class); endpointDao = mock(EndpointDao.class); exceptionHandler = mock(ExceptionHandler.class); provider = new ClientProviderImpl(webserviceTrustStore, webserviceKeyStore, webserviceKeyStorePassword, remoteReadTimeout, remoteConnectTimeout, remoteProxyPassword, remoteProxyUsername, - remoteProxySchemeHostPort, fhirContext, referenceExtractor, endpointDao, exceptionHandler); + remoteProxySchemeHostPort, fhirContext, referenceCleaner, endpointDao, exceptionHandler); } @Test @@ -68,7 +68,7 @@ public void testGetClientExisting() throws Exception assertEquals(serverBase, client.get().getBaseUrl()); verify(exceptionHandler).handleSqlException(any(SupplierWithSqlException.class)); - verifyNoMoreInteractions(referenceExtractor, endpointDao, exceptionHandler); + verifyNoMoreInteractions(referenceCleaner, endpointDao, exceptionHandler); } @Test @@ -82,6 +82,6 @@ public void testGetClientExistingNotFound() throws Exception assertTrue(client.isEmpty()); verify(exceptionHandler).handleSqlException(any(SupplierWithSqlException.class)); - verifyNoMoreInteractions(referenceExtractor, endpointDao, exceptionHandler); + verifyNoMoreInteractions(referenceCleaner, endpointDao, exceptionHandler); } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/AbstractResourceDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/AbstractResourceDaoTest.java index 571d5986d..9d7252e92 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/AbstractResourceDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/AbstractResourceDaoTest.java @@ -1,12 +1,10 @@ package org.highmed.dsf.fhir.dao; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.sql.Connection; import java.sql.SQLException; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -52,6 +50,11 @@ public void before() throws Exception protected abstract C createDao(BasicDataSource dataSource, FhirContext fhirContext); + protected C getDao() + { + return dao; + } + @Test public void testEmpty() throws Exception { @@ -108,16 +111,28 @@ public void testUpdate() throws Exception D createdResource = dao.create(newResource); assertNotNull(createdResource); - assertNotNull(createdResource.getId()); + assertNotNull(createdResource.getIdElement()); + assertNotNull(createdResource.getIdElement().getIdPart()); + assertNotNull(createdResource.getIdElement().getVersionIdPart()); + assertEquals(ResourceDao.FIRST_VERSION_STRING, createdResource.getIdElement().getVersionIdPart()); + assertNotNull(createdResource.getMeta()); assertNotNull(createdResource.getMeta().getVersionId()); + assertEquals(ResourceDao.FIRST_VERSION_STRING, createdResource.getMeta().getVersionId()); newResource.setIdElement(createdResource.getIdElement().copy()); newResource.setMeta(createdResource.getMeta().copy()); - assertTrue(newResource.equalsDeep(createdResource)); - D updatedResource = dao.update(updateResource(createdResource), null); + D updatedResource = dao.update(updateResource(createdResource), (long) ResourceDao.FIRST_VERSION); assertNotNull(updatedResource); + assertNotNull(updatedResource.getIdElement()); + assertNotNull(updatedResource.getIdElement().getIdPart()); + assertNotNull(updatedResource.getIdElement().getVersionIdPart()); + assertEquals(String.valueOf(ResourceDao.FIRST_VERSION + 1), updatedResource.getIdElement().getVersionIdPart()); + assertNotNull(updatedResource.getMeta()); + assertNotNull(updatedResource.getMeta().getVersionId()); + assertEquals(String.valueOf(ResourceDao.FIRST_VERSION + 1), updatedResource.getMeta().getVersionId()); + assertTrue(updatedResource.getMeta().getLastUpdated().after(createdResource.getMeta().getLastUpdated())); checkUpdates(updatedResource); } @@ -173,6 +188,43 @@ public void testUpdateLatest() throws Exception assertNotNull(updatedResource); } + @Test + public void testUpdateDeleted() throws Exception + { + D newResource = createResource(); + assertNull(newResource.getId()); + assertNull(newResource.getMeta().getVersionId()); + + D createdResource = dao.create(newResource); + assertNotNull(createdResource); + assertNotNull(createdResource.getIdElement()); + assertNotNull(createdResource.getIdElement().getIdPart()); + assertNotNull(createdResource.getIdElement().getVersionIdPart()); + assertEquals(ResourceDao.FIRST_VERSION_STRING, createdResource.getIdElement().getVersionIdPart()); + assertNotNull(createdResource.getMeta()); + assertNotNull(createdResource.getMeta().getVersionId()); + assertEquals(ResourceDao.FIRST_VERSION_STRING, createdResource.getMeta().getVersionId()); + + newResource.setIdElement(createdResource.getIdElement().copy()); + newResource.setMeta(createdResource.getMeta().copy()); + assertTrue(newResource.equalsDeep(createdResource)); + + boolean deleted = dao.delete(UUID.fromString(createdResource.getIdElement().getIdPart())); + assertTrue(deleted); + + D updatedResource = dao.update(updateResource(createdResource), (long) ResourceDao.FIRST_VERSION + 1L); + assertNotNull(updatedResource); + assertNotNull(updatedResource.getIdElement()); + assertNotNull(updatedResource.getIdElement().getIdPart()); + assertNotNull(updatedResource.getIdElement().getVersionIdPart()); + assertEquals(String.valueOf(ResourceDao.FIRST_VERSION + 2), updatedResource.getIdElement().getVersionIdPart()); + assertNotNull(updatedResource.getMeta()); + assertNotNull(updatedResource.getMeta().getVersionId()); + assertEquals(String.valueOf(ResourceDao.FIRST_VERSION + 2), updatedResource.getMeta().getVersionId()); + + checkUpdates(updatedResource); + } + protected abstract void checkUpdates(D resource); @Test(expected = ResourceDeletedException.class) @@ -200,6 +252,33 @@ public void testDelete() throws Exception dao.read(UUID.fromString(createdResource.getIdElement().getIdPart())); } + @Test + public void testReadIncludingDeleted() throws Exception + { + D newResource = createResource(); + assertNull(newResource.getId()); + assertNull(newResource.getMeta().getVersionId()); + + D createdResource = dao.create(newResource); + assertNotNull(createdResource); + assertNotNull(createdResource.getId()); + assertNotNull(createdResource.getMeta().getVersionId()); + + newResource.setIdElement(createdResource.getIdElement().copy()); + newResource.setMeta(createdResource.getMeta().copy()); + + assertTrue(newResource.equalsDeep(createdResource)); + + Optional<D> read = dao.read(UUID.fromString(createdResource.getIdElement().getIdPart())); + assertTrue(read.isPresent()); + + boolean d = dao.delete(UUID.fromString(createdResource.getIdElement().getIdPart())); + assertTrue(d); + + Optional<D> deleted = dao.readIncludingDeleted(UUID.fromString(createdResource.getIdElement().getIdPart())); + assertTrue(deleted.isPresent()); + } + @Test public void testReadWithVersion() throws Exception { @@ -249,6 +328,52 @@ public void testRead() throws Exception assertTrue(s1 + "\nvs\n" + s2, newResource.equalsDeep(read.get())); } + @Test + public void testReadAll() throws Exception + { + D newResource = createResource(); + assertNull(newResource.getId()); + assertNull(newResource.getMeta().getVersionId()); + + D createdResource = dao.create(newResource); + assertNotNull(createdResource); + assertNotNull(createdResource.getIdElement()); + assertNotNull(createdResource.getIdElement().getIdPart()); + assertNotNull(createdResource.getIdElement().getVersionIdPart()); + assertEquals(ResourceDao.FIRST_VERSION_STRING, createdResource.getIdElement().getVersionIdPart()); + assertNotNull(createdResource.getMeta()); + assertNotNull(createdResource.getMeta().getVersionId()); + assertEquals(ResourceDao.FIRST_VERSION_STRING, createdResource.getMeta().getVersionId()); + + newResource.setIdElement(createdResource.getIdElement().copy()); + newResource.setMeta(createdResource.getMeta().copy()); + assertTrue(newResource.equalsDeep(createdResource)); + + D updatedResource = dao.update(updateResource(createdResource), (long) ResourceDao.FIRST_VERSION); + assertNotNull(updatedResource); + assertNotNull(updatedResource.getIdElement()); + assertNotNull(updatedResource.getIdElement().getIdPart()); + assertNotNull(updatedResource.getIdElement().getVersionIdPart()); + assertEquals(String.valueOf(ResourceDao.FIRST_VERSION + 1), updatedResource.getIdElement().getVersionIdPart()); + assertNotNull(updatedResource.getMeta()); + assertNotNull(updatedResource.getMeta().getVersionId()); + assertEquals(String.valueOf(ResourceDao.FIRST_VERSION + 1), updatedResource.getMeta().getVersionId()); + + checkUpdates(updatedResource); + + List<D> all = dao.readAll(); + assertNotNull(all); + assertEquals(1, all.size()); + assertNotNull(all.get(0)); + assertNotNull(all.get(0).getIdElement()); + assertNotNull(all.get(0).getIdElement().getIdPart()); + assertNotNull(all.get(0).getIdElement().getVersionIdPart()); + assertEquals(String.valueOf(ResourceDao.FIRST_VERSION + 1), all.get(0).getIdElement().getVersionIdPart()); + assertNotNull(all.get(0).getMeta()); + assertNotNull(all.get(0).getMeta().getVersionId()); + assertEquals(String.valueOf(ResourceDao.FIRST_VERSION + 1), all.get(0).getMeta().getVersionId()); + } + @Test public void testReadLatest() throws Exception { @@ -340,4 +465,40 @@ private Connection getNewTransaction() throws SQLException return connection; } + + @Test + public void testExistsNotDeletedNotExisting() throws Exception + { + boolean existsNotDeleted = dao.existsNotDeleted(UUID.randomUUID().toString(), "1"); + assertFalse(existsNotDeleted); + } + + @Test + public void testExistsNotDeletedExisting() throws Exception + { + D newResource = createResource(); + D createdResource = dao.create(newResource); + + boolean existsNotDeleted1 = dao.existsNotDeleted(createdResource.getIdElement().getIdPart(), null); + assertTrue(existsNotDeleted1); + + boolean existsNotDeleted2 = dao.existsNotDeleted(createdResource.getIdElement().getIdPart(), + createdResource.getIdElement().getVersionIdPart()); + assertTrue(existsNotDeleted2); + } + + @Test + public void testExistsNotDeletedDeleted() throws Exception + { + D newResource = createResource(); + D createdResource = dao.create(newResource); + dao.delete(UUID.fromString(createdResource.getIdElement().getIdPart())); + + boolean existsNotDeleted1 = dao.existsNotDeleted(createdResource.getIdElement().getIdPart(), null); + assertFalse(existsNotDeleted1); + + boolean existsNotDeleted2 = dao.existsNotDeleted(createdResource.getIdElement().getIdPart(), + createdResource.getIdElement().getVersionIdPart()); + assertFalse(existsNotDeleted2); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ActivityDefinitionDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ActivityDefinitionDaoTest.java index ef93df470..144533f05 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ActivityDefinitionDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ActivityDefinitionDaoTest.java @@ -5,10 +5,12 @@ import org.apache.commons.dbcp2.BasicDataSource; import org.highmed.dsf.fhir.dao.jdbc.ActivityDefinitionDaoJdbc; import org.hl7.fhir.r4.model.ActivityDefinition; +import org.junit.Test; import ca.uhn.fhir.context.FhirContext; public class ActivityDefinitionDaoTest extends AbstractResourceDaoTest<ActivityDefinition, ActivityDefinitionDao> + implements ReadByUrlDaoTest<ActivityDefinition> { private static final String name = "Demo ActivityDefinition Name"; private static final String title = "Demo ActivityDefinition Title"; @@ -50,4 +52,65 @@ protected void checkUpdates(ActivityDefinition resource) { assertEquals(title, resource.getTitle()); } + + @Override + public ActivityDefinition createResourceWithUrlAndVersion() + { + ActivityDefinition resource = createResource(); + resource.setUrl(getUrl()); + resource.setVersion(getVersion()); + return resource; + } + + @Override + public String getUrl() + { + return "http://test.com/fhir/CodeSystem/test-system"; + } + + @Override + public String getVersion() + { + return "0.2.0"; + } + + @Override + public ReadByUrlDao<ActivityDefinition> readByUrlDao() + { + return getDao(); + } + + @Override + public ResourceDao<ActivityDefinition> dao() + { + return getDao(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrl1() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrl1(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrlAndVersion1() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrlAndVersion1(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrl2() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrl2(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrlAndVersion2() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrlAndVersion2(); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/CodeSystemDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/CodeSystemDaoTest.java index 69bae42f0..8232f2b6c 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/CodeSystemDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/CodeSystemDaoTest.java @@ -5,10 +5,12 @@ import org.apache.commons.dbcp2.BasicDataSource; import org.highmed.dsf.fhir.dao.jdbc.CodeSystemDaoJdbc; import org.hl7.fhir.r4.model.CodeSystem; +import org.junit.Test; import ca.uhn.fhir.context.FhirContext; public class CodeSystemDaoTest extends AbstractResourceDaoTest<CodeSystem, CodeSystemDao> + implements ReadByUrlDaoTest<CodeSystem> { private static final String name = "Demo CodeSystem Name"; private static final String description = "Demo CodeSystem Description"; @@ -50,4 +52,65 @@ protected void checkUpdates(CodeSystem resource) { assertEquals(description, resource.getDescription()); } + + @Override + public CodeSystem createResourceWithUrlAndVersion() + { + CodeSystem resource = createResource(); + resource.setUrl(getUrl()); + resource.setVersion(getVersion()); + return resource; + } + + @Override + public String getUrl() + { + return "http://test.com/fhir/CodeSystem/test-system"; + } + + @Override + public String getVersion() + { + return "0.2.0"; + } + + @Override + public ReadByUrlDao<CodeSystem> readByUrlDao() + { + return getDao(); + } + + @Override + public ResourceDao<CodeSystem> dao() + { + return getDao(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrl1() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrl1(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrlAndVersion1() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrlAndVersion1(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrl2() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrl2(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrlAndVersion2() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrlAndVersion2(); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/HistoryDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/HistoryDaoTest.java new file mode 100644 index 000000000..3a072f2de --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/HistoryDaoTest.java @@ -0,0 +1,95 @@ +package org.highmed.dsf.fhir.dao; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.UUID; + +import org.highmed.dsf.fhir.authentication.User; +import org.highmed.dsf.fhir.authentication.UserRole; +import org.highmed.dsf.fhir.dao.jdbc.BinaryDaoJdbc; +import org.highmed.dsf.fhir.dao.jdbc.HistroyDaoJdbc; +import org.highmed.dsf.fhir.dao.jdbc.OrganizationDaoJdbc; +import org.highmed.dsf.fhir.history.AtParameter; +import org.highmed.dsf.fhir.history.History; +import org.highmed.dsf.fhir.history.SinceParameter; +import org.highmed.dsf.fhir.history.user.HistoryUserFilterFactory; +import org.highmed.dsf.fhir.history.user.HistoryUserFilterFactoryImpl; +import org.highmed.dsf.fhir.search.PageAndCount; +import org.highmed.dsf.fhir.test.FhirEmbeddedPostgresWithLiquibase; +import org.highmed.dsf.fhir.test.TestSuiteDbTests; +import org.hl7.fhir.r4.model.Organization; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import de.rwh.utils.test.Database; + +public class HistoryDaoTest +{ + @ClassRule + public static final FhirEmbeddedPostgresWithLiquibase template = new FhirEmbeddedPostgresWithLiquibase( + TestSuiteDbTests.template); + + @Rule + public final Database database = new Database(template); + + private final FhirContext fhirContext = FhirContext.forR4(); + private final OrganizationDao orgDao = new OrganizationDaoJdbc(database.getDataSource(), fhirContext); + private final HistoryDao dao = new HistroyDaoJdbc(database.getDataSource(), fhirContext, + new BinaryDaoJdbc(database.getDataSource(), fhirContext)); + private final HistoryUserFilterFactory filterFactory = new HistoryUserFilterFactoryImpl(); + + @Test + public void testReadHistory() throws Exception + { + Organization organization = new Organization(); + organization.getMeta().addTag("http://highmed.org/fhir/CodeSystem/authorization-role", "REMOTE", null); + organization.setName("Test Organization"); + Organization createdOrganization = orgDao.create(organization); + + History history = dao.readHistory(filterFactory.getUserFilters(new User(createdOrganization, UserRole.LOCAL)), + new PageAndCount(1, 1000), new AtParameter(), new SinceParameter()); + assertNotNull(history); + assertEquals(1, history.getTotal()); + assertNotNull(history.getEntries()); + assertEquals(1, history.getEntries().size()); + } + + @Test + public void testReadHistoryOrganization() throws Exception + { + Organization organization = new Organization(); + organization.getMeta().addTag("http://highmed.org/fhir/CodeSystem/authorization-role", "REMOTE", null); + organization.setName("Test Organization"); + Organization createdOrganization = orgDao.create(organization); + + History history = dao.readHistory( + filterFactory.getUserFilter(new User(createdOrganization, UserRole.LOCAL), Organization.class), + new PageAndCount(1, 1000), new AtParameter(), new SinceParameter(), Organization.class); + assertNotNull(history); + assertEquals(1, history.getTotal()); + assertNotNull(history.getEntries()); + assertEquals(1, history.getEntries().size()); + } + + @Test + public void testReadHistoryOrganizationWithId() throws Exception + { + Organization organization = new Organization(); + organization.getMeta().addTag("http://highmed.org/fhir/CodeSystem/authorization-role", "REMOTE", null); + organization.setName("Test Organization"); + Organization createdOrganization = orgDao.create(organization); + + History history = dao.readHistory( + filterFactory.getUserFilter(new User(createdOrganization, UserRole.LOCAL), Organization.class), + new PageAndCount(1, 1000), new AtParameter(), new SinceParameter(), Organization.class, + UUID.fromString(createdOrganization.getIdElement().getIdPart())); + + assertNotNull(history); + assertEquals(1, history.getTotal()); + assertNotNull(history.getEntries()); + assertEquals(1, history.getEntries().size()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/NamingSystemDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/NamingSystemDaoTest.java index 3407cab63..7269323a0 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/NamingSystemDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/NamingSystemDaoTest.java @@ -1,10 +1,13 @@ package org.highmed.dsf.fhir.dao; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; + +import java.util.Optional; import org.apache.commons.dbcp2.BasicDataSource; import org.highmed.dsf.fhir.dao.jdbc.NamingSystemDaoJdbc; import org.hl7.fhir.r4.model.NamingSystem; +import org.junit.Test; import ca.uhn.fhir.context.FhirContext; @@ -50,4 +53,14 @@ protected void checkUpdates(NamingSystem resource) { assertEquals(description, resource.getDescription()); } + + @Test + public void testReadByName() throws Exception + { + NamingSystem newResource = createResource(); + dao.create(newResource); + + Optional<NamingSystem> readByName = dao.readByName(name); + assertTrue(readByName.isPresent()); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/OrganizationDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/OrganizationDaoTest.java index 0cc0f14aa..115c455d1 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/OrganizationDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/OrganizationDaoTest.java @@ -1,8 +1,6 @@ package org.highmed.dsf.fhir.dao; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.nio.charset.StandardCharsets; import java.util.Optional; @@ -156,4 +154,17 @@ public void testReadActiveNotDeletedByThumbprintBlank() throws Exception assertNotNull(read); assertTrue(read.isEmpty()); } + + @Test + public void testReadActiveNotDeletedByIdentifier() throws Exception + { + final String identifierValue = "foo"; + + Organization createResource = createResource(); + createResource.getIdentifierFirstRep().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue(identifierValue); + dao.create(createResource); + + dao.readActiveNotDeletedByIdentifier(identifierValue); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ReadByUrlDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ReadByUrlDaoTest.java new file mode 100644 index 000000000..ec4f360ae --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ReadByUrlDaoTest.java @@ -0,0 +1,61 @@ +package org.highmed.dsf.fhir.dao; + +import static org.junit.Assert.assertTrue; + +import java.util.Optional; + +import org.hl7.fhir.r4.model.DomainResource; +import org.junit.Test; + +public interface ReadByUrlDaoTest<D extends DomainResource> +{ + D createResourceWithUrlAndVersion(); + + String getUrl(); + + String getVersion(); + + ReadByUrlDao<D> readByUrlDao(); + + ResourceDao<D> dao(); + + @Test + default void testReadByUrlAndVersionWithUrl1() throws Exception + { + D newResource = createResourceWithUrlAndVersion(); + dao().create(newResource); + + Optional<D> readByUrlAndVersion = readByUrlDao().readByUrlAndVersion(getUrl()); + assertTrue(readByUrlAndVersion.isPresent()); + } + + @Test + default void testReadByUrlAndVersionWithUrlAndVersion1() throws Exception + { + D newResource = createResourceWithUrlAndVersion(); + dao().create(newResource); + + Optional<D> readByUrlAndVersion = readByUrlDao().readByUrlAndVersion(getUrl() + "|" + getVersion()); + assertTrue(readByUrlAndVersion.isPresent()); + } + + @Test + default void testReadByUrlAndVersionWithUrl2() throws Exception + { + D newResource = createResourceWithUrlAndVersion(); + dao().create(newResource); + + Optional<D> readByUrlAndVersion = readByUrlDao().readByUrlAndVersion(getUrl(), null); + assertTrue(readByUrlAndVersion.isPresent()); + } + + @Test + default void testReadByUrlAndVersionWithUrlAndVersion2() throws Exception + { + D newResource = createResourceWithUrlAndVersion(); + dao().create(newResource); + + Optional<D> readByUrlAndVersion = readByUrlDao().readByUrlAndVersion(getUrl(), getVersion()); + assertTrue(readByUrlAndVersion.isPresent()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/StructureDefinitionDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/StructureDefinitionDaoTest.java index 7336dffb7..b25a8f103 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/StructureDefinitionDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/StructureDefinitionDaoTest.java @@ -5,10 +5,12 @@ import org.apache.commons.dbcp2.BasicDataSource; import org.highmed.dsf.fhir.dao.jdbc.StructureDefinitionDaoJdbc; import org.hl7.fhir.r4.model.StructureDefinition; +import org.junit.Test; import ca.uhn.fhir.context.FhirContext; public class StructureDefinitionDaoTest extends AbstractResourceDaoTest<StructureDefinition, StructureDefinitionDao> + implements ReadByUrlDaoTest<StructureDefinition> { private static final String name = "StructureDefinition"; private static final String title = "Demo Structure Definition"; @@ -50,4 +52,65 @@ protected void checkUpdates(StructureDefinition resource) { assertEquals(title, resource.getTitle()); } + + @Override + public StructureDefinition createResourceWithUrlAndVersion() + { + StructureDefinition resource = createResource(); + resource.setUrl(getUrl()); + resource.setVersion(getVersion()); + return resource; + } + + @Override + public String getUrl() + { + return "http://test.com/fhir/StructureDefinition/test-system"; + } + + @Override + public String getVersion() + { + return "0.2.0"; + } + + @Override + public ReadByUrlDao<StructureDefinition> readByUrlDao() + { + return getDao(); + } + + @Override + public ResourceDao<StructureDefinition> dao() + { + return getDao(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrl1() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrl1(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrlAndVersion1() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrlAndVersion1(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrl2() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrl2(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrlAndVersion2() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrlAndVersion2(); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/StructureDefinitionSnapshotDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/StructureDefinitionSnapshotDaoTest.java index 5e9793228..82854b8bd 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/StructureDefinitionSnapshotDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/StructureDefinitionSnapshotDaoTest.java @@ -3,32 +3,28 @@ import static org.junit.Assert.assertEquals; import org.apache.commons.dbcp2.BasicDataSource; -import org.highmed.dsf.fhir.dao.converter.SnapshotInfoConverter; import org.highmed.dsf.fhir.dao.jdbc.StructureDefinitionSnapshotDaoJdbc; -import org.highmed.dsf.fhir.spring.config.JsonConfig; import org.hl7.fhir.r4.model.StructureDefinition; - -import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; import ca.uhn.fhir.context.FhirContext; public class StructureDefinitionSnapshotDaoTest - extends AbstractResourceDaoTest<StructureDefinition, StructureDefinitionSnapshotDao> + extends AbstractResourceDaoTest<StructureDefinition, StructureDefinitionDao> + implements ReadByUrlDaoTest<StructureDefinition> { private static final String name = "StructureDefinitionSnapshot"; private static final String title = "Demo Structure Definition Snapshot"; - private final ObjectMapper objectMapper = new JsonConfig().objectMapper(); - public StructureDefinitionSnapshotDaoTest() { super(StructureDefinition.class); } @Override - protected StructureDefinitionSnapshotDao createDao(BasicDataSource dataSource, FhirContext fhirContext) + protected StructureDefinitionDao createDao(BasicDataSource dataSource, FhirContext fhirContext) { - return new StructureDefinitionSnapshotDaoJdbc(dataSource, fhirContext, new SnapshotInfoConverter(objectMapper)); + return new StructureDefinitionSnapshotDaoJdbc(dataSource, fhirContext); } @Override @@ -58,145 +54,64 @@ protected void checkUpdates(StructureDefinition resource) assertEquals(title, resource.getTitle()); } - // TODO - - // @Test - // public void testUpdateSnapshotInfo() throws Exception - // { - // StructureDefinition snapshot = dao.create(createResource()); - // - // try (Connection connection = database.getDataSource().getConnection(); - // PreparedStatement statement = connection.prepareStatement( - // "SELECT structure_definition_snapshot_info FROM structure_definition_snapshots WHERE - // structure_definition_snapshot_id = ?")) - // { - // statement.setObject(1, dao.uuidToPgObject(UUID.fromString(snapshot.getIdElement().getIdPart()))); - // try (ResultSet result = statement.executeQuery()) - // { - // assertTrue(result.next()); - // assertNull(result.getString(1)); - // } - // } - // - // final String profile0 = "profile0"; - // final String profile1 = "profile1"; - // final String targetProfile0 = "targetProfile0"; - // final String targetProfile1 = "targetProfile1"; - // - // SnapshotDependencies dependencies = new SnapshotDependencies(Arrays.asList(profile0, profile1), - // Arrays.asList(targetProfile0, targetProfile1)); - // SnapshotInfo info = new SnapshotInfo(dependencies); - // - // dao.updateSnapshotInfo(UUID.fromString(snapshot.getIdElement().getIdPart()), info); - // - // try (Connection connection = database.getDataSource().getConnection(); - // PreparedStatement statement = connection.prepareStatement( - // "SELECT structure_definition_snapshot_info FROM structure_definition_snapshots WHERE - // structure_definition_snapshot_id = ?")) - // { - // statement.setObject(1, dao.uuidToPgObject(UUID.fromString(snapshot.getIdElement().getIdPart()))); - // try (ResultSet result = statement.executeQuery()) - // { - // assertTrue(result.next()); - // String readInfoString = result.getString(1); - // assertNotNull(readInfoString); - // - // SnapshotInfo readInfo = objectMapper.reader().forType(SnapshotInfo.class).readValue(readInfoString); - // assertNotNull(readInfo); - // - // assertNotNull(readInfo); - // assertNotNull(readInfo.getDependencies()); - // assertNotNull(readInfo.getDependencies().getProfiles()); - // assertEquals(2, readInfo.getDependencies().getProfiles().size()); - // assertEquals(profile0, readInfo.getDependencies().getProfiles().get(0)); - // assertEquals(profile1, readInfo.getDependencies().getProfiles().get(1)); - // assertNotNull(readInfo.getDependencies().getTargetProfiles()); - // assertEquals(2, readInfo.getDependencies().getTargetProfiles().size()); - // assertEquals(targetProfile0, readInfo.getDependencies().getTargetProfiles().get(0)); - // assertEquals(targetProfile1, readInfo.getDependencies().getTargetProfiles().get(1)); - // } - // } - // } - // - // @Test - // public void testDeleteAllByDependency() throws Exception - // { - // StructureDefinition snapshot1a = dao.create(createResource()); - // StructureDefinition snapshot1b = dao.create(createResource()); - // StructureDefinition snapshot2 = dao.create(createResource()); - // - // try (Connection connection = database.getDataSource().getConnection(); - // PreparedStatement statement = connection.prepareStatement( - // "SELECT count(*) FROM structure_definition_snapshots WHERE structure_definition_snapshot_info IS NULL")) - // { - // try (ResultSet result = statement.executeQuery()) - // { - // assertTrue(result.next()); - // assertEquals(3, result.getInt(1)); - // } - // } - // - // final String profile10 = "profile10"; - // final String profile11 = "profile11"; - // final String targetProfile10 = "targetProfile10"; - // final String targetProfile11 = "targetProfile11"; - // - // SnapshotDependencies dependencies1a = new SnapshotDependencies(Arrays.asList(profile10, profile11), - // Arrays.asList(targetProfile10, targetProfile11)); - // SnapshotInfo info1a = new SnapshotInfo(dependencies1a); - // dao.updateSnapshotInfo(UUID.fromString(snapshot1a.getIdElement().getIdPart()), info1a); - // - // SnapshotDependencies dependencies1b = new SnapshotDependencies(Arrays.asList(profile10), - // Arrays.asList(targetProfile10)); - // SnapshotInfo info1b = new SnapshotInfo(dependencies1b); - // dao.updateSnapshotInfo(UUID.fromString(snapshot1b.getIdElement().getIdPart()), info1b); - // - // final String profile20 = "profile20"; - // final String profile21 = "profile21"; - // final String targetProfile20 = "targetProfile20"; - // final String targetProfile21 = "targetProfile21"; - // - // SnapshotDependencies dependencies2 = new SnapshotDependencies(Arrays.asList(profile20, profile21), - // Arrays.asList(targetProfile20, targetProfile21)); - // SnapshotInfo info2 = new SnapshotInfo(dependencies2); - // dao.updateSnapshotInfo(UUID.fromString(snapshot2.getIdElement().getIdPart()), info2); - // - // try (Connection connection = database.getDataSource().getConnection(); - // PreparedStatement statement = connection.prepareStatement( - // "SELECT count(*) FROM structure_definition_snapshots WHERE structure_definition_snapshot_info IS NOT NULL")) - // { - // try (ResultSet result = statement.executeQuery()) - // { - // assertTrue(result.next()); - // assertEquals(3, result.getInt(1)); - // } - // } - // - // try (Connection connection = database.getDataSource().getConnection(); - // PreparedStatement statement = connection.prepareStatement( - // "SELECT count(*) FROM structure_definition_snapshots WHERE - // structure_definition_snapshot_info->'dependencies'->'profiles' ?? ?")) - // { - // statement.setString(1, profile10); - // - // try (ResultSet result = statement.executeQuery()) - // { - // assertTrue(result.next()); - // assertEquals(2, result.getInt(1)); - // } - // } - // - // dao.deleteAllByDependency(profile10); - // - // try (Connection connection = database.getDataSource().getConnection(); - // PreparedStatement statement = connection - // .prepareStatement("SELECT count(*) FROM structure_definition_snapshots")) - // { - // try (ResultSet result = statement.executeQuery()) - // { - // assertTrue(result.next()); - // assertEquals(1, result.getInt(1)); - // } - // } - // } + @Override + public StructureDefinition createResourceWithUrlAndVersion() + { + StructureDefinition resource = createResource(); + resource.setUrl(getUrl()); + resource.setVersion(getVersion()); + return resource; + } + + @Override + public String getUrl() + { + return "http://test.com/fhir/StructureDefinition/test-system"; + } + + @Override + public String getVersion() + { + return "0.2.0"; + } + + @Override + public ReadByUrlDao<StructureDefinition> readByUrlDao() + { + return getDao(); + } + + @Override + public ResourceDao<StructureDefinition> dao() + { + return getDao(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrl1() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrl1(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrlAndVersion1() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrlAndVersion1(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrl2() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrl2(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrlAndVersion2() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrlAndVersion2(); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/SubscriptionDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/SubscriptionDaoTest.java index f54001c38..60538146b 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/SubscriptionDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/SubscriptionDaoTest.java @@ -1,11 +1,17 @@ package org.highmed.dsf.fhir.dao; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.UUID; import org.apache.commons.dbcp2.BasicDataSource; import org.highmed.dsf.fhir.dao.jdbc.SubscriptionDaoJdbc; import org.hl7.fhir.r4.model.Subscription; import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus; +import org.junit.Test; import ca.uhn.fhir.context.FhirContext; @@ -51,4 +57,28 @@ protected void checkUpdates(Subscription resource) { assertEquals(reason, resource.getReason()); } + + @Test + public void testExistsActiveNotDeletedByAddressDeleted() throws Exception + { + Subscription activeSubscriptionToDelete = createResource(); + Subscription createdActiveSubscriptionToDelete = dao.create(activeSubscriptionToDelete); + assertNotNull(createdActiveSubscriptionToDelete); + + boolean deleted = dao.delete(UUID.fromString(createdActiveSubscriptionToDelete.getIdElement().getIdPart())); + assertTrue(deleted); + + Subscription activeSubscription = createResource(); + Subscription createdActiveSubscription = dao.create(activeSubscription); + assertNotNull(createdActiveSubscription); + + Subscription offSubscription = createResource(); + offSubscription.setStatus(SubscriptionStatus.OFF); + Subscription createdOffSubscription = dao.create(offSubscription); + assertNotNull(createdOffSubscription); + + List<Subscription> activeSubscriptions = dao.readByStatus(SubscriptionStatus.ACTIVE); + assertNotNull(activeSubscriptions); + assertEquals(1, activeSubscriptions.size()); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ValueSetDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ValueSetDaoTest.java index ceafc4e5c..b342ddfd2 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ValueSetDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/dao/ValueSetDaoTest.java @@ -5,10 +5,12 @@ import org.apache.commons.dbcp2.BasicDataSource; import org.highmed.dsf.fhir.dao.jdbc.ValueSetDaoJdbc; import org.hl7.fhir.r4.model.ValueSet; +import org.junit.Test; import ca.uhn.fhir.context.FhirContext; public class ValueSetDaoTest extends AbstractResourceDaoTest<ValueSet, ValueSetDao> + implements ReadByUrlDaoTest<ValueSet> { private static final String name = "Demo ValueSet Name"; private static final String description = "Demo ValueSet Description"; @@ -50,4 +52,65 @@ protected void checkUpdates(ValueSet resource) { assertEquals(description, resource.getDescription()); } + + @Override + public ValueSet createResourceWithUrlAndVersion() + { + ValueSet resource = createResource(); + resource.setUrl(getUrl()); + resource.setVersion(getVersion()); + return resource; + } + + @Override + public String getUrl() + { + return "http://test.com/fhir/ValueSet/test-system"; + } + + @Override + public String getVersion() + { + return "0.2.0"; + } + + @Override + public ReadByUrlDao<ValueSet> readByUrlDao() + { + return getDao(); + } + + @Override + public ResourceDao<ValueSet> dao() + { + return getDao(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrl1() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrl1(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrlAndVersion1() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrlAndVersion1(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrl2() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrl2(); + } + + @Override + @Test + public void testReadByUrlAndVersionWithUrlAndVersion2() throws Exception + { + ReadByUrlDaoTest.super.testReadByUrlAndVersionWithUrlAndVersion2(); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/ActivityDefinitionWithExtension.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/ActivityDefinitionWithExtension.java index 2a3dd7f78..7aa5af986 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/ActivityDefinitionWithExtension.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/ActivityDefinitionWithExtension.java @@ -42,7 +42,7 @@ public void test() throws Exception Extension e1 = a.addExtension(); e1.setUrl("http://highmed.org/fhir/StructureDefinition/process-authorization"); - e1.addExtension("message-name", new StringType("startProcessMessage")); + e1.addExtension("message-name", new StringType("startPingProcessMessage")); e1.addExtension("authorization-role", new Coding("http://highmed.org/fhir/CodeSystem/authorization-role", "LOCAL", null)); Extension ot12 = e1.addExtension(); @@ -52,7 +52,7 @@ public void test() throws Exception ot12.addExtension("organization-type", new Coding("http://highmed.org/fhir/CodeSystem/authorization-role", "MeDIC", null)); e1.addExtension("task-profile", - new CanonicalType("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process")); + new CanonicalType("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process")); Extension e2 = a.addExtension(); e2.setUrl("http://highmed.org/fhir/StructureDefinition/process-authorization"); diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/BundleTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/BundleTest.java index 5a1477fa9..80585b243 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/BundleTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/BundleTest.java @@ -2,6 +2,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.UUID; @@ -11,6 +12,7 @@ import org.hl7.fhir.r4.model.Bundle.BundleType; import org.hl7.fhir.r4.model.Bundle.HTTPVerb; import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Organization; import org.junit.Test; import org.slf4j.Logger; @@ -28,7 +30,6 @@ private IParser newXmlParser() IParser p = FhirContext.forR4().newXmlParser(); p.setStripVersionsFromReferences(false); p.setOverrideResourceIdWithBundleEntryFullUrl(false); - p.setPrettyPrint(true); return p; } @@ -37,7 +38,6 @@ private IParser newJsonParser() IParser p = FhirContext.forR4().newJsonParser(); p.setStripVersionsFromReferences(false); p.setOverrideResourceIdWithBundleEntryFullUrl(false); - p.setPrettyPrint(true); return p; } @@ -66,10 +66,12 @@ private void testBundleWithParser(IParser parser) String eptTempId = "urn:uuid:" + UUID.randomUUID().toString(); Organization org = new Organization(); - org.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_Organization"); + org.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_Organization"); Endpoint ept = new Endpoint(); - ept.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/endpoint-identifier").setValue("Test_Endpoint"); + ept.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/endpoint-identifier") + .setValue("Test_Endpoint"); org.getEndpointFirstRep().setType("Endpoint").setReference(eptTempId); ept.getManagingOrganization().setType("Organization").setReference(orgTempId); @@ -77,8 +79,8 @@ private void testBundleWithParser(IParser parser) BundleEntryComponent orgEntry = bundle1.addEntry(); orgEntry.setFullUrl(orgTempId); orgEntry.setResource(org); - orgEntry.getRequest().setMethod(HTTPVerb.PUT) - .setUrl("Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_Organization"); + orgEntry.getRequest().setMethod(HTTPVerb.PUT).setUrl( + "Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_Organization"); BundleEntryComponent eptEntry = bundle1.addEntry(); eptEntry.setFullUrl(eptTempId); @@ -108,4 +110,25 @@ private void testBundleWithParser(IParser parser) assertEquals(bundle1String, bundle2String); } + + @Test + public void testBundleVersionTag() throws Exception + { + IdType i = new IdType(null, "id", "version"); + System.out.println(i.withResourceType("Bundle").getValueAsString()); + + Bundle b = new Bundle(); + b.setIdElement(new IdType("Bundle", UUID.randomUUID().toString(), "123")); + + String bundleTxt = newXmlParser().encodeResourceToString(b); + logger.debug(bundleTxt); + + Bundle bRead = newXmlParser().parseResource(Bundle.class, bundleTxt); + assertEquals("123", bRead.getMeta().getVersionId()); + assertNull(bRead.getIdElement().getVersionIdPart()); + + // FIXME workaround hapi parser bug + bRead.setIdElement(bRead.getIdElement().withVersion(bRead.getMeta().getVersionId())); + assertEquals("123", bRead.getIdElement().getVersionIdPart()); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/DefaultProfileValidationSupportTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/DefaultProfileValidationSupportTest.java new file mode 100644 index 000000000..016648151 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/DefaultProfileValidationSupportTest.java @@ -0,0 +1,29 @@ +package org.highmed.dsf.fhir.hapi; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.DefaultProfileValidationSupport; +import ca.uhn.fhir.context.support.IValidationSupport; + +public class DefaultProfileValidationSupportTest +{ + @Test(expected = NullPointerException.class) + public void testFetchAllBugInHapi() throws Exception + { + // XXX bug in HAPI framework + new DefaultProfileValidationSupport(FhirContext.forR4()).fetchAllConformanceResources(); + } + + @Test + public void testFetchAllBugInHapiWorkaround() throws Exception + { + // XXX bug in HAPI framework workaround + IValidationSupport support = new DefaultProfileValidationSupport(FhirContext.forR4()); + assertNull(support.fetchCodeSystem("")); + assertNotNull(support.fetchAllStructureDefinitions()); + assertNotNull(support.fetchAllConformanceResources()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/ReferenceTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/ReferenceTest.java new file mode 100644 index 000000000..377fe2a7b --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/ReferenceTest.java @@ -0,0 +1,41 @@ +package org.highmed.dsf.fhir.hapi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.UUID; + +import org.hl7.fhir.r4.model.Endpoint; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; + +public class ReferenceTest +{ + private static final Logger logger = LoggerFactory.getLogger(ReferenceTest.class); + + @Test + public void testLiteralAndLogicalReference() throws Exception + { + Endpoint endpoint = new Endpoint(); + endpoint.getManagingOrganization().setReference("Organization/" + UUID.randomUUID().toString()).getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("hs-heilbronn.de"); + + FhirContext context = FhirContext.forR4(); + String endpointString = context.newXmlParser().setPrettyPrint(true).encodeResourceToString(endpoint); + + logger.debug("Endpoint: {}", endpointString); + + Endpoint readEndpoint = context.newXmlParser().parseResource(Endpoint.class, endpointString); + + assertNotNull(readEndpoint); + assertEquals(endpoint.getManagingOrganization().getReference(), + readEndpoint.getManagingOrganization().getReference()); + assertEquals(endpoint.getManagingOrganization().getIdentifier().getSystem(), + readEndpoint.getManagingOrganization().getIdentifier().getSystem()); + assertEquals(endpoint.getManagingOrganization().getIdentifier().getValue(), + readEndpoint.getManagingOrganization().getIdentifier().getValue()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/SnapshotTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/SnapshotTest.java deleted file mode 100755 index 0c4183bc3..000000000 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/SnapshotTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.highmed.dsf.fhir.hapi; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.highmed.dsf.fhir.service.DefaultProfileValidationSupportWithCustomResources; -import org.highmed.dsf.fhir.service.SnapshotGenerator; -import org.highmed.dsf.fhir.service.SnapshotGenerator.SnapshotWithValidationMessages; -import org.highmed.dsf.fhir.service.SnapshotGeneratorImpl; -import org.highmed.dsf.fhir.service.StructureDefinitionReader; -import org.hl7.fhir.r4.conformance.ProfileUtilities; -import org.hl7.fhir.r4.context.IWorkerContext; -import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext; -import org.hl7.fhir.r4.model.ElementDefinition; -import org.hl7.fhir.r4.model.StructureDefinition; -import org.hl7.fhir.r4.model.Task; -import org.hl7.fhir.utilities.validation.ValidationMessage; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.model.api.annotation.ResourceDef; - -public class SnapshotTest -{ - private static final Logger logger = LoggerFactory.getLogger(SnapshotTest.class); - - @Test - public void testSnapshot() throws Exception - { - FhirContext context = FhirContext.forR4(); - - StructureDefinitionReader reader = new StructureDefinitionReader(context); - var validationSupport = new DefaultProfileValidationSupportWithCustomResources( - Collections.singletonList( - reader.readXml(Paths.get("src/test/resources/profiles/extension-workflow-researchstudy.xml"))), - Collections.emptyList(), Collections.emptyList()); - - IWorkerContext worker = new HapiWorkerContext(context, validationSupport); - List<ValidationMessage> messages = new ArrayList<>(); - - ProfileUtilities profileUtis = new ProfileUtilities(worker, messages, null); - - String url = ""; - String profileName = "highmed-data-sharing-task"; - StructureDefinition base = worker.fetchTypeDefinition(Task.class.getAnnotation(ResourceDef.class).name()) - .copy(); - StructureDefinition derived = reader.readXml(Paths.get("src/test/resources/profiles/highmed-task-0.5.0.xml")); - - profileUtis.generateSnapshot(base, derived, url, url, profileName); - - if (logger.isDebugEnabled()) - logger.debug("Snapshot: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(derived)); - - messages.forEach(m -> logger.error("Issue while generating snapshot: {} - {} - {}", m.getDisplay(), m.getLine(), - m.getMessage())); - } - - @Test - public void testSnapshotGenerator() throws Exception - { - FhirContext context = FhirContext.forR4(); - StructureDefinitionReader reader = new StructureDefinitionReader(context); - - StructureDefinition structureDefinition = reader - .readXml(Paths.get("src/test/resources/profiles/extension-workflow-researchstudy.xml")); - SnapshotGenerator generator = new SnapshotGeneratorImpl(context, - new DefaultProfileValidationSupportWithCustomResources(Collections.singletonList(structureDefinition), - Collections.emptyList(), Collections.emptyList())); - - SnapshotWithValidationMessages snapshot = generator - .generateSnapshot(reader.readXml(Paths.get("src/test/resources/profiles/highmed-task-0.5.0.xml"))); - - assertNotNull(snapshot); - assertNotNull(snapshot.getSnapshot()); - assertNotNull(snapshot.getMessages()); - assertTrue(snapshot.getMessages().isEmpty()); - - assertTrue(snapshot.getSnapshot().getSnapshot().getElement().stream().map(ElementDefinition::getId) - .anyMatch(id -> "Task.extension:researchStudy".equals(id))); - - snapshot.getSnapshot().getSnapshot().getElement() - .forEach(e -> logger.debug("snapshot.element.path#id: {}", e.getId())); - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/StructureDefinitionTreeTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/StructureDefinitionTreeTest.java index 005623c23..782c13379 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/StructureDefinitionTreeTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/StructureDefinitionTreeTest.java @@ -1,23 +1,16 @@ package org.highmed.dsf.fhir.hapi; -import static org.junit.Assert.assertNotNull; - import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; -import org.highmed.dsf.fhir.service.DefaultProfileValidationSupportWithCustomResources; -import org.highmed.dsf.fhir.service.SnapshotGenerator; -import org.highmed.dsf.fhir.service.SnapshotGenerator.SnapshotWithValidationMessages; -import org.highmed.dsf.fhir.service.SnapshotGeneratorImpl; import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.ElementDefinition; import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent; @@ -119,30 +112,4 @@ private StructureDefinition readStructureDefinition(FhirContext context, Path p) throw new RuntimeException(e); } } - - @Test - public void testBuildPatient() throws Exception - { - FhirContext context = FhirContext.forR4(); - - Map<String, StructureDefinition> structureDefinitionsByUrl = Files - .list(Paths.get("src/test/resources/profiles/DeBasis/")) - .map(p -> readStructureDefinition(context, p).setSnapshot(null)) - .filter(sd -> sd.getUrl().startsWith("http://fhir.de/")) - .collect(Collectors.toMap(StructureDefinition::getUrl, Function.identity())); - - StructureDefinition patientDeBasis = structureDefinitionsByUrl - .get("http://fhir.de/StructureDefinition/patient-de-basis/0.2.1"); - - SnapshotGenerator generator = new SnapshotGeneratorImpl(context, - new DefaultProfileValidationSupportWithCustomResources(structureDefinitionsByUrl.values(), - Collections.emptyList(), Collections.emptyList())); - - SnapshotWithValidationMessages snapshot = generator.generateSnapshot(patientDeBasis); - - logger.debug(context.newXmlParser().encodeResourceToString(snapshot.getSnapshot())); - snapshot.getMessages().forEach(vm -> logger.debug(vm.getMessage())); - - assertNotNull(snapshot.getSnapshot()); - } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/ValidationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/ValidationTest.java deleted file mode 100755 index ad0722fc9..000000000 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/hapi/ValidationTest.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.highmed.dsf.fhir.hapi; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.highmed.dsf.fhir.service.DefaultProfileValidationSupportWithCustomResources; -import org.highmed.dsf.fhir.service.ResourceValidator; -import org.highmed.dsf.fhir.service.ResourceValidatorImpl; -import org.highmed.dsf.fhir.service.SnapshotGenerator.SnapshotWithValidationMessages; -import org.highmed.dsf.fhir.service.SnapshotGeneratorImpl; -import org.highmed.dsf.fhir.service.StructureDefinitionReader; -import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator; -import org.hl7.fhir.r4.model.Patient; -import org.hl7.fhir.r4.model.StructureDefinition; -import org.junit.BeforeClass; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.validation.FhirValidator; -import ca.uhn.fhir.validation.ResultSeverityEnum; -import ca.uhn.fhir.validation.ValidationResult; - -public class ValidationTest -{ - private static final Logger logger = LoggerFactory.getLogger(ValidationTest.class); - - private static final FhirContext context = FhirContext.forR4(); - private static List<StructureDefinition> snapshots; - - @BeforeClass - public static void beforeClass() throws Exception - { - snapshots = createSnapshots(readStructureDefinitions(context), context); - } - - private static List<StructureDefinition> createSnapshots(List<StructureDefinition> diffs, FhirContext fhirContext) - { - List<StructureDefinition> snapshots = new ArrayList<StructureDefinition>(diffs.size()); - for (StructureDefinition diff : diffs) - { - SnapshotGeneratorImpl generator = new SnapshotGeneratorImpl(fhirContext, - new DefaultProfileValidationSupportWithCustomResources(snapshots, Collections.emptyList(), - Collections.emptyList())); - SnapshotWithValidationMessages result = generator.generateSnapshot(diff); - assertTrue(result.getMessages().isEmpty()); - - snapshots.add(result.getSnapshot()); - } - - return snapshots; - } - - private static List<StructureDefinition> readStructureDefinitions(FhirContext context) - { - StructureDefinitionReader reader = new StructureDefinitionReader(context); - - return reader.readXml(Paths.get("src/test/resources/profiles/DeBasis/AddressDeBasis.xml"), - Paths.get("src/test/resources/profiles/DeBasis/patient-de-basis-0.2.1.xml")); - } - - private Patient createNonValidPatient() - { - Patient patient = new Patient(); - patient.getMeta().addProfile("http://fhir.de/StructureDefinition/patient-de-basis/0.2.1"); - patient.getAddressFirstRep().setDistrict("district"); - return patient; - } - - @Test - public void testHapiValidation() throws Exception - { - FhirValidator validator = context.newValidator(); - - FhirInstanceValidator instanceValidator = new FhirInstanceValidator(); - validator.registerValidatorModule(instanceValidator); - - instanceValidator.setValidationSupport(new DefaultProfileValidationSupportWithCustomResources(snapshots, - Collections.emptyList(), Collections.emptyList())); - - Patient patient = createNonValidPatient(); - - ValidationResult result = validator.validateWithResult(patient); - - assertFalse(result.isSuccessful()); - assertEquals(1, result.getMessages().size()); - assertEquals(ResultSeverityEnum.ERROR, result.getMessages().get(0).getSeverity()); - - result.getMessages().forEach(r -> logger.info("Validation Issue: {} - {} - {}", r.getSeverity(), - r.getLocationString(), r.getMessage())); - } - - @Test - public void testValidatorImpl() - { - ResourceValidator validator = new ResourceValidatorImpl(context, - new DefaultProfileValidationSupportWithCustomResources(snapshots, Collections.emptyList(), - Collections.emptyList())); - - ValidationResult result = validator.validate(createNonValidPatient()); - - assertFalse(result.isSuccessful()); - assertEquals(1, result.getMessages().size()); - assertEquals(ResultSeverityEnum.ERROR, result.getMessages().get(0).getSeverity()); - - result.getMessages().forEach(r -> logger.info("Validation Issue: {} - {} - {}", r.getSeverity(), - r.getLocationString(), r.getMessage())); - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/AbstractIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/AbstractIntegrationTest.java index 0dc2c1e43..9c0f62032 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/AbstractIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/AbstractIntegrationTest.java @@ -47,7 +47,8 @@ import org.glassfish.jersey.servlet.init.JerseyServletContainerInitializer; import org.highmed.dsf.fhir.FhirContextLoaderListener; import org.highmed.dsf.fhir.authentication.AuthenticationFilter; -import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.ReferenceCleanerImpl; import org.highmed.dsf.fhir.service.ReferenceExtractorImpl; import org.highmed.dsf.fhir.spring.config.InitialDataLoaderConfig; import org.highmed.dsf.fhir.test.FhirEmbeddedPostgresWithLiquibase; @@ -92,14 +93,15 @@ public abstract class AbstractIntegrationTest private static final Logger logger = LoggerFactory.getLogger(AbstractIntegrationTest.class); - protected static final String BASE_URL = "https://localhost:8001/fhir/"; + protected static final String BASE_URL = "https://localhost:8001/fhir"; protected static final String WEBSOCKET_URL = "wss://localhost:8001/fhir/ws"; private static final Path FHIR_BUNDLE_FILE = Paths.get("target", UUID.randomUUID().toString() + ".xml"); private static final List<Path> FILES_TO_DELETE = Arrays.asList(FHIR_BUNDLE_FILE); - private static final FhirContext fhirContext = FhirContext.forR4(); - private static final ReferenceExtractor extractor = new ReferenceExtractorImpl(); + protected static final FhirContext fhirContext = FhirContext.forR4(); + + private static final ReferenceCleaner referenceCleaner = new ReferenceCleanerImpl(new ReferenceExtractorImpl()); private static JettyServer fhirServer; private static FhirWebserviceClient webserviceClient; @@ -118,29 +120,28 @@ public static void beforeClass() throws Exception logger.info("Creating webservice client ..."); webserviceClient = createWebserviceClient(certificates.getClientCertificate().getTrustStore(), certificates.getClientCertificate().getKeyStore(), - certificates.getClientCertificate().getKeyStorePassword(), fhirContext, extractor); + certificates.getClientCertificate().getKeyStorePassword(), fhirContext, referenceCleaner); logger.info("Creating external webservice client ..."); externalWebserviceClient = createWebserviceClient(certificates.getExternalClientCertificate().getTrustStore(), certificates.getExternalClientCertificate().getKeyStore(), - certificates.getExternalClientCertificate().getKeyStorePassword(), fhirContext, extractor); + certificates.getExternalClientCertificate().getKeyStorePassword(), fhirContext, referenceCleaner); logger.info("Starting FHIR Server ..."); fhirServer = startFhirServer(); } private static FhirWebserviceClient createWebserviceClient(KeyStore trustStore, KeyStore keyStore, - char[] keyStorePassword, FhirContext fhirContext, ReferenceExtractor referenceExtractor) + char[] keyStorePassword, FhirContext fhirContext, ReferenceCleaner referenceCleaner) { - return new FhirWebserviceClientJersey(BASE_URL, trustStore, keyStore, keyStorePassword, null, null, null, 500, - 5000, null, fhirContext, referenceExtractor); + return new FhirWebserviceClientJersey(BASE_URL, trustStore, keyStore, keyStorePassword, null, null, null, 0, 0, + null, fhirContext, referenceCleaner); } private static WebsocketClient createWebsocketClient(KeyStore trustStore, KeyStore keyStore, char[] keyStorePassword, String subscriptionIdPart) { - return new WebsocketClientTyrus(URI.create(WEBSOCKET_URL), trustStore, keyStore, keyStorePassword, - subscriptionIdPart); + return new WebsocketClientTyrus(() -> {}, URI.create(WEBSOCKET_URL), trustStore, keyStore, keyStorePassword, subscriptionIdPart); } private static JettyServer startFhirServer() throws Exception @@ -213,7 +214,8 @@ protected static Bundle readBundle(Path bundleTemplateFile, IParser parser) { try (InputStream in = Files.newInputStream(bundleTemplateFile)) { - return parser.parseResource(Bundle.class, in); + Bundle bundle = parser.parseResource(Bundle.class, in); + return referenceCleaner.cleanReferenceResourcesIfBundle(bundle); } catch (IOException e) { @@ -274,25 +276,12 @@ private static void createTestBundle(X509Certificate certificate, X509Certificat String externalClientCertHashHex = calculateSha512CertificateThumbprintHex(externalCertificate); externalThumbprintExtension.setValue(new StringType(externalClientCertHashHex)); - removeReferenceEmbeddedResources(testBundle); + // FIXME hapi parser can't handle embedded resources and creates them while parsing bundles + new ReferenceCleanerImpl(new ReferenceExtractorImpl()).cleanReferenceResourcesIfBundle(testBundle); writeBundle(FHIR_BUNDLE_FILE, testBundle); } - // FIXME hapi parser can't handle embedded resources and creates them while parsing bundles - private static void removeReferenceEmbeddedResources(Bundle bundle) - { - bundle.getEntry().stream().map(e -> e.getResource()).forEach(res -> - { - logger.debug("Extracting references from {} resource", res.getResourceType()); - extractor.getReferences(res).forEach(ref -> - { - logger.debug("Setting reference embedded resource to null at {}", ref.getReferenceLocation()); - ref.getReference().setResource(null); - }); - }); - } - @AfterClass public static void afterClass() throws Exception { @@ -375,7 +364,7 @@ protected static FhirWebserviceClient getExternalWebserviceClient() protected static WebsocketClient getWebsocketClient() { - Bundle bundle = getWebserviceClient().search(Subscription.class, + Bundle bundle = getWebserviceClient().searchWithStrictHandling(Subscription.class, Map.of("criteria", Collections.singletonList("Task?status=requested"), "status", Collections.singletonList("active"), "type", Collections.singletonList("websocket"), "payload", Collections.singletonList("application/fhir+json"))); diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/BinaryIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/BinaryIntegrationTest.java index 1adf9f43f..134ebd4d7 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/BinaryIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/BinaryIntegrationTest.java @@ -5,6 +5,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; @@ -14,6 +16,7 @@ import java.util.stream.Collectors; import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response.Status; import org.highmed.dsf.fhir.dao.BinaryDao; @@ -24,12 +27,20 @@ import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleType; import org.hl7.fhir.r4.model.Bundle.HTTPVerb; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Reference; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; public class BinaryIntegrationTest extends AbstractIntegrationTest { + private static final Logger logger = LoggerFactory.getLogger(BinaryIntegrationTest.class); + @Test public void testReadAllowedLocalUser() throws Exception { @@ -37,14 +48,14 @@ public void testReadAllowedLocalUser() throws Exception PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) .configureParameters(Map.of("name", Arrays.asList("Test Organization")))); assertNotNull(result); - assertEquals(1, result.getOverallCount()); + assertEquals(1, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(1, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); Organization org = result.getPartialResult().get(0); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -58,6 +69,142 @@ public void testReadAllowedLocalUser() throws Exception getWebserviceClient().read(Binary.class, created.getIdElement().getIdPart()); } + @Test + public void testReadAllowedLocalUserViaStream() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) + .configureParameters(Map.of("name", Arrays.asList("Test Organization")))); + assertNotNull(result); + assertEquals(1, result.getTotal()); + assertNotNull(result.getPartialResult()); + assertEquals(1, result.getPartialResult().size()); + assertNotNull(result.getPartialResult().get(0)); + + Organization org = result.getPartialResult().get(0); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data); + binary.setSecurityContext(new Reference(org.getIdElement().toVersionless())); + + BinaryDao binDao = getSpringWebApplicationContext().getBean(BinaryDao.class); + Binary created = binDao.create(binary); + + try (InputStream in = getWebserviceClient().readBinary(created.getIdElement().getIdPart(), + MediaType.TEXT_PLAIN_TYPE)) + { + assertTrue(Arrays.equals(data, in.readAllBytes())); + } + } + + @Test + public void testReadAllowedLocalUserViaStreamWithVersion() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) + .configureParameters(Map.of("name", Arrays.asList("Test Organization")))); + assertNotNull(result); + assertEquals(1, result.getTotal()); + assertNotNull(result.getPartialResult()); + assertEquals(1, result.getPartialResult().size()); + assertNotNull(result.getPartialResult().get(0)); + + Organization org = result.getPartialResult().get(0); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data); + binary.setSecurityContext(new Reference(org.getIdElement().toVersionless())); + + BinaryDao binDao = getSpringWebApplicationContext().getBean(BinaryDao.class); + Binary created = binDao.create(binary); + + try (InputStream in = getWebserviceClient().readBinary(created.getIdElement().getIdPart(), + created.getIdElement().getVersionIdPart(), MediaType.TEXT_PLAIN_TYPE)) + { + assertTrue(Arrays.equals(data, in.readAllBytes())); + } + } + + @Test + public void testReadAllowedLocalUserViaStreamAcceptWildcard() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) + .configureParameters(Map.of("name", Arrays.asList("Test Organization")))); + assertNotNull(result); + assertEquals(1, result.getTotal()); + assertNotNull(result.getPartialResult()); + assertEquals(1, result.getPartialResult().size()); + assertNotNull(result.getPartialResult().get(0)); + + Organization org = result.getPartialResult().get(0); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data); + binary.setSecurityContext(new Reference(org.getIdElement().toVersionless())); + + BinaryDao binDao = getSpringWebApplicationContext().getBean(BinaryDao.class); + Binary created = binDao.create(binary); + + try (InputStream in = getWebserviceClient().readBinary(created.getIdElement().getIdPart(), + MediaType.WILDCARD_TYPE)) + { + assertTrue(Arrays.equals(data, in.readAllBytes())); + } + } + + @Test(expected = WebApplicationException.class) + public void testReadAllowedLocalUserViaStreamMediaTypeNotSupported() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) + .configureParameters(Map.of("name", Arrays.asList("Test Organization")))); + assertNotNull(result); + assertEquals(1, result.getTotal()); + assertNotNull(result.getPartialResult()); + assertEquals(1, result.getPartialResult().size()); + assertNotNull(result.getPartialResult().get(0)); + + Organization org = result.getPartialResult().get(0); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data); + binary.setSecurityContext(new Reference(org.getIdElement().toVersionless())); + + BinaryDao binDao = getSpringWebApplicationContext().getBean(BinaryDao.class); + Binary created = binDao.create(binary); + + try + { + try (InputStream in = getWebserviceClient().readBinary(created.getIdElement().getIdPart(), + MediaType.APPLICATION_XML_TYPE)) + { + assertTrue(Arrays.equals(data, in.readAllBytes())); + } + } + catch (WebApplicationException e) + { + assertEquals(Status.NOT_ACCEPTABLE.getStatusCode(), e.getResponse().getStatus()); + throw e; + } + } + @Test public void testReadAllowedExternalUser() throws Exception { @@ -65,14 +212,14 @@ public void testReadAllowedExternalUser() throws Exception PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) .configureParameters(Map.of("name", Arrays.asList("External Test Organization")))); assertNotNull(result); - assertEquals(1, result.getOverallCount()); + assertEquals(1, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(1, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); Organization org = result.getPartialResult().get(0); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -93,14 +240,14 @@ public void testReadNotAllowedExternalUser() throws Exception PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) .configureParameters(Map.of("name", Arrays.asList("Test Organization")))); assertNotNull(result); - assertEquals(1, result.getOverallCount()); + assertEquals(1, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(1, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); Organization org = result.getPartialResult().get(0); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -129,14 +276,14 @@ public void testReadAllowedLocalUserViaTransactionBundle() throws Exception PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) .configureParameters(Map.of("name", Arrays.asList("Test Organization")))); assertNotNull(result); - assertEquals(1, result.getOverallCount()); + assertEquals(1, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(1, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); Organization org = result.getPartialResult().get(0); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -169,14 +316,14 @@ public void testReadAllowedExternalUserViaTransactionBundle() throws Exception PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) .configureParameters(Map.of("name", Arrays.asList("External Test Organization")))); assertNotNull(result); - assertEquals(1, result.getOverallCount()); + assertEquals(1, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(1, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); Organization org = result.getPartialResult().get(0); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -209,14 +356,14 @@ public void testReadNotAllowedExternalUserViaTransactionBundle() throws Exceptio PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) .configureParameters(Map.of("name", Arrays.asList("Test Organization")))); assertNotNull(result); - assertEquals(1, result.getOverallCount()); + assertEquals(1, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(1, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); Organization org = result.getPartialResult().get(0); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -249,14 +396,14 @@ public void testReadAllowedLocalUserViaBatchBundle() throws Exception PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) .configureParameters(Map.of("name", Arrays.asList("Test Organization")))); assertNotNull(result); - assertEquals(1, result.getOverallCount()); + assertEquals(1, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(1, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); Organization org = result.getPartialResult().get(0); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -289,14 +436,14 @@ public void testReadAllowedExternalUserViaBatchBundle() throws Exception PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) .configureParameters(Map.of("name", Arrays.asList("External Test Organization")))); assertNotNull(result); - assertEquals(1, result.getOverallCount()); + assertEquals(1, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(1, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); Organization org = result.getPartialResult().get(0); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -329,14 +476,14 @@ public void testReadNotAllowedExternalUserViaBatchBundle() throws Exception PartialResult<Organization> result = orgDao.search(orgDao.createSearchQueryWithoutUserFilter(1, 1) .configureParameters(Map.of("name", Arrays.asList("Test Organization")))); assertNotNull(result); - assertEquals(1, result.getOverallCount()); + assertEquals(1, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(1, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); Organization org = result.getPartialResult().get(0); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -368,7 +515,7 @@ public void testCreate() throws Exception OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -391,13 +538,123 @@ public void testCreate() throws Exception assertEquals(createdOrg.getIdElement().toVersionless(), created.getSecurityContext().getReferenceElement()); } + @Test + public void testCreateReturnMinimal() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + Organization createdOrg = orgDao.create(new Organization()); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data); + binary.setSecurityContext(new Reference(createdOrg.getIdElement().toVersionless())); + + IdType created = getWebserviceClient().withMinimalReturn().create(binary); + + assertNotNull(created); + assertNotNull(created.getBaseUrl()); + assertNotNull(created.getResourceType()); + assertNotNull(created.getIdPart()); + assertNotNull(created.getVersionIdPart()); + + assertEquals(BASE_URL, created.getBaseUrl()); + assertEquals("Binary", created.getResourceType()); + assertEquals("1", created.getVersionIdPart()); + } + + @Test + public void testCreateReturnOperationOutcome() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + Organization createdOrg = orgDao.create(new Organization()); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data); + binary.setSecurityContext(new Reference(createdOrg.getIdElement().toVersionless())); + + OperationOutcome created = getWebserviceClient().withOperationOutcomeReturn().create(binary); + + assertNotNull(created); + } + + @Test + public void testCreateViaInputStream() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + Organization createdOrg = orgDao.create(new Organization()); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + Binary created = getWebserviceClient().createBinary(new ByteArrayInputStream(data), + MediaType.valueOf(contentType), createdOrg.getIdElement().toVersionless().toString()); + + assertNotNull(created); + assertNotNull(created.getIdElement().toString()); + assertEquals("1", created.getMeta().getVersionId()); + assertNotNull(created.getMeta().getLastUpdated()); + + assertNotNull(created.getContentType()); + assertEquals(contentType, created.getContentType()); + assertTrue(Arrays.equals(data, created.getData())); + + assertNotNull(created.getSecurityContext()); + assertEquals(createdOrg.getIdElement().toVersionless(), created.getSecurityContext().getReferenceElement()); + } + + @Test + public void testCreateViaInputStreamReturnMinimal() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + Organization createdOrg = orgDao.create(new Organization()); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + IdType created = getWebserviceClient().withMinimalReturn().createBinary(new ByteArrayInputStream(data), + MediaType.valueOf(contentType), createdOrg.getIdElement().toVersionless().toString()); + + assertNotNull(created); + assertNotNull(created.getBaseUrl()); + assertNotNull(created.getResourceType()); + assertNotNull(created.getIdPart()); + assertNotNull(created.getVersionIdPart()); + + assertEquals(BASE_URL, created.getBaseUrl()); + assertEquals("Binary", created.getResourceType()); + assertEquals("1", created.getVersionIdPart()); + } + + @Test + public void testCreateViaInputStreamReturnOperationOutcome() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + Organization createdOrg = orgDao.create(new Organization()); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + OperationOutcome created = getWebserviceClient().withOperationOutcomeReturn().createBinary( + new ByteArrayInputStream(data), MediaType.valueOf(contentType), + createdOrg.getIdElement().toVersionless().toString()); + + assertNotNull(created); + } + @Test(expected = WebApplicationException.class) public void testCreateNotAllowedExternalUser() throws Exception { OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -419,7 +676,7 @@ public void testCreateNotAllowedExternalUser() throws Exception @Test(expected = WebApplicationException.class) public void testCreateSecurityContextOrgNotExisting() throws Exception { - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -438,13 +695,35 @@ public void testCreateSecurityContextOrgNotExisting() throws Exception } } + @Test + public void testCreateSecurityContextLogicalReference() throws Exception + { + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data); + Reference securityContext = new Reference(); + securityContext.setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("External_Test_Organization"); + binary.setSecurityContext(securityContext); + + logger.debug("Binary: {}", + FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(binary)); + + Binary created = getWebserviceClient().create(binary); + assertNotNull(created); + } + @Test public void testCreateViaTransactionBundle() throws Exception { OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -464,6 +743,80 @@ public void testCreateViaTransactionBundle() throws Exception assertEquals(1, responseBundle.getEntry().size()); assertNotNull(responseBundle.getEntry().get(0)); + assertNotNull(responseBundle.getEntry().get(0).getResource()); + assertTrue(responseBundle.getEntry().get(0).getResource() instanceof Binary); + assertNull(responseBundle.getEntry().get(0).getResponse().getOutcome()); + assertNotNull(responseBundle.getEntry().get(0).getResponse().getStatus()); + assertEquals("201 Created", responseBundle.getEntry().get(0).getResponse().getStatus()); + assertNotNull(responseBundle.getEntry().get(0).getResponse().getLocation()); + assertNotNull(responseBundle.getEntry().get(0).getResponse().getEtag()); + assertEquals("W/\"1\"", responseBundle.getEntry().get(0).getResponse().getEtag()); + } + + @Test + public void testCreateViaTransactionBundleWithMinimalReturn() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + Organization createdOrg = orgDao.create(new Organization()); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data); + binary.setSecurityContext(new Reference(createdOrg.getIdElement().toVersionless())); + + Bundle bundle = new Bundle(); + bundle.setType(BundleType.TRANSACTION); + bundle.addEntry().setFullUrl("urn:uuid:" + UUID.randomUUID().toString()).setResource(binary).getRequest() + .setMethod(HTTPVerb.POST).setUrl("Binary"); + + Bundle responseBundle = getWebserviceClient().withMinimalReturn().postBundle(bundle); + + assertNotNull(responseBundle); + assertEquals(BundleType.TRANSACTIONRESPONSE, responseBundle.getType()); + assertEquals(1, responseBundle.getEntry().size()); + assertNotNull(responseBundle.getEntry().get(0)); + + assertNull(responseBundle.getEntry().get(0).getResource()); + assertNull(responseBundle.getEntry().get(0).getResponse().getOutcome()); + assertNotNull(responseBundle.getEntry().get(0).getResponse().getStatus()); + assertEquals("201 Created", responseBundle.getEntry().get(0).getResponse().getStatus()); + assertNotNull(responseBundle.getEntry().get(0).getResponse().getLocation()); + assertNotNull(responseBundle.getEntry().get(0).getResponse().getEtag()); + assertEquals("W/\"1\"", responseBundle.getEntry().get(0).getResponse().getEtag()); + } + + @Test + public void testCreateViaTransactionBundleWithOperationOutcomeReturn() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + Organization createdOrg = orgDao.create(new Organization()); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data); + binary.setSecurityContext(new Reference(createdOrg.getIdElement().toVersionless())); + + Bundle bundle = new Bundle(); + bundle.setType(BundleType.TRANSACTION); + bundle.addEntry().setFullUrl("urn:uuid:" + UUID.randomUUID().toString()).setResource(binary).getRequest() + .setMethod(HTTPVerb.POST).setUrl("Binary"); + + Bundle responseBundle = getWebserviceClient().withOperationOutcomeReturn().postBundle(bundle); + + assertNotNull(responseBundle); + assertEquals(BundleType.TRANSACTIONRESPONSE, responseBundle.getType()); + assertEquals(1, responseBundle.getEntry().size()); + assertNotNull(responseBundle.getEntry().get(0)); + + assertNull(responseBundle.getEntry().get(0).getResource()); + assertNotNull(responseBundle.getEntry().get(0).getResponse().getOutcome()); + assertTrue(responseBundle.getEntry().get(0).getResponse().getOutcome() instanceof OperationOutcome); assertNotNull(responseBundle.getEntry().get(0).getResponse().getStatus()); assertEquals("201 Created", responseBundle.getEntry().get(0).getResponse().getStatus()); assertNotNull(responseBundle.getEntry().get(0).getResponse().getLocation()); @@ -477,7 +830,7 @@ public void testCreateNotAllowedExternalUserViaTransactionBundle() throws Except OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -504,7 +857,7 @@ public void testCreateNotAllowedExternalUserViaTransactionBundle() throws Except @Test(expected = WebApplicationException.class) public void testCreateSecurityContextOrgNotExistingViaTransactionBundle() throws Exception { - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -534,7 +887,7 @@ public void testCreateViaBatchBundle() throws Exception OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -567,7 +920,7 @@ public void testCreateNotAllowedExternalUserViaBatchBundle() throws Exception OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -594,7 +947,7 @@ public void testCreateNotAllowedExternalUserViaBatchBundle() throws Exception @Test public void testCreateSecurityContextOrgNotExistingViaBatchBundle() throws Exception { - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -624,7 +977,7 @@ public void testUpdate() throws Exception OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); final byte[] data2 = "Hello World and goodbye".getBytes(StandardCharsets.UTF_8); @@ -665,13 +1018,101 @@ public void testUpdate() throws Exception assertTrue(Arrays.equals(data2, updated.getData())); } + @Test + public void testUpdateReturnMinimal() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + Organization createdOrg = orgDao.create(new Organization()); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); + final byte[] data2 = "Hello World and goodbye".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data1); + binary.setSecurityContext(new Reference(createdOrg.getIdElement().toVersionless())); + + BinaryDao binaryDao = getSpringWebApplicationContext().getBean(BinaryDao.class); + Binary created = binaryDao.create(binary); + + assertNotNull(created); + assertNotNull(created.getIdElement().toString()); + assertEquals("1", created.getMeta().getVersionId()); + assertNotNull(created.getMeta().getLastUpdated()); + + assertNotNull(created.getContentType()); + assertEquals(contentType, created.getContentType()); + assertTrue(Arrays.equals(data1, created.getData())); + + assertNotNull(created.getSecurityContext()); + assertEquals(createdOrg.getIdElement().toVersionless(), created.getSecurityContext().getReferenceElement()); + + created.setData(data2); + + assertNotNull(created.getSecurityContext()); + assertEquals(createdOrg.getIdElement().toVersionless(), created.getSecurityContext().getReferenceElement()); + + IdType updated = getWebserviceClient().withMinimalReturn().update(created); + + assertNotNull(updated); + assertNotNull(updated.getBaseUrl()); + assertNotNull(updated.getResourceType()); + assertNotNull(updated.getIdPart()); + assertNotNull(updated.getVersionIdPart()); + + assertEquals(BASE_URL, updated.getBaseUrl()); + assertEquals("Binary", updated.getResourceType()); + assertEquals("2", updated.getVersionIdPart()); + } + + @Test + public void testUpdateReturnOperationOutcome() throws Exception + { + OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); + Organization createdOrg = orgDao.create(new Organization()); + + final String contentType = MediaType.TEXT_PLAIN; + final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); + final byte[] data2 = "Hello World and goodbye".getBytes(StandardCharsets.UTF_8); + + Binary binary = new Binary(); + binary.setContentType(contentType); + binary.setData(data1); + binary.setSecurityContext(new Reference(createdOrg.getIdElement().toVersionless())); + + BinaryDao binaryDao = getSpringWebApplicationContext().getBean(BinaryDao.class); + Binary created = binaryDao.create(binary); + + assertNotNull(created); + assertNotNull(created.getIdElement().toString()); + assertEquals("1", created.getMeta().getVersionId()); + assertNotNull(created.getMeta().getLastUpdated()); + + assertNotNull(created.getContentType()); + assertEquals(contentType, created.getContentType()); + assertTrue(Arrays.equals(data1, created.getData())); + + assertNotNull(created.getSecurityContext()); + assertEquals(createdOrg.getIdElement().toVersionless(), created.getSecurityContext().getReferenceElement()); + + created.setData(data2); + + assertNotNull(created.getSecurityContext()); + assertEquals(createdOrg.getIdElement().toVersionless(), created.getSecurityContext().getReferenceElement()); + + OperationOutcome updated = getWebserviceClient().withOperationOutcomeReturn().update(created); + + assertNotNull(updated); + } + @Test(expected = WebApplicationException.class) public void testUpdateNotAllowedExternalUser() throws Exception { OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); final byte[] data2 = "Hello World and goodbye".getBytes(StandardCharsets.UTF_8); @@ -717,7 +1158,7 @@ public void testUpdateViaTransactionBundle() throws Exception OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); final byte[] data2 = "Hello World and goodbye".getBytes(StandardCharsets.UTF_8); @@ -748,7 +1189,7 @@ public void testUpdateViaTransactionBundle() throws Exception Bundle bundle = new Bundle(); bundle.setType(BundleType.TRANSACTION); - bundle.addEntry().setFullUrl(BASE_URL + "Binary/" + created.getIdElement().getIdPart()).setResource(created) + bundle.addEntry().setFullUrl(BASE_URL + "/Binary/" + created.getIdElement().getIdPart()).setResource(created) .getRequest().setMethod(HTTPVerb.PUT).setUrl("Binary/" + created.getIdElement().getIdPart()); Bundle responseBundle = getWebserviceClient().postBundle(bundle); @@ -758,6 +1199,7 @@ public void testUpdateViaTransactionBundle() throws Exception assertEquals(1, responseBundle.getEntry().size()); assertNotNull(responseBundle.getEntry().get(0)); + assertNotNull(responseBundle.getEntry().get(0).getResource()); assertNotNull(responseBundle.getEntry().get(0).getResponse().getStatus()); assertEquals("200 OK", responseBundle.getEntry().get(0).getResponse().getStatus()); assertNotNull(responseBundle.getEntry().get(0).getResponse().getLocation()); @@ -771,7 +1213,7 @@ public void testUpdateNotAllowedExternalUserViaTransactionBundle() throws Except OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); final byte[] data2 = "Hello World and goodbye".getBytes(StandardCharsets.UTF_8); @@ -802,7 +1244,7 @@ public void testUpdateNotAllowedExternalUserViaTransactionBundle() throws Except Bundle bundle = new Bundle(); bundle.setType(BundleType.TRANSACTION); - bundle.addEntry().setFullUrl(BASE_URL + "Binary/" + created.getIdElement().getIdPart()).setResource(created) + bundle.addEntry().setFullUrl(BASE_URL + "/Binary/" + created.getIdElement().getIdPart()).setResource(created) .getRequest().setMethod(HTTPVerb.PUT).setUrl("Binary/" + created.getIdElement().getIdPart()); try @@ -822,7 +1264,7 @@ public void testUpdateSecurityContextOrgNotExistingViaTransactionBundle() throws OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); final byte[] data2 = "Hello World and goodbye".getBytes(StandardCharsets.UTF_8); @@ -853,7 +1295,7 @@ public void testUpdateSecurityContextOrgNotExistingViaTransactionBundle() throws Bundle bundle = new Bundle(); bundle.setType(BundleType.TRANSACTION); - bundle.addEntry().setFullUrl(BASE_URL + "Binary/" + created.getIdElement().getIdPart()).setResource(created) + bundle.addEntry().setFullUrl(BASE_URL + "/Binary/" + created.getIdElement().getIdPart()).setResource(created) .getRequest().setMethod(HTTPVerb.PUT).setUrl("Binary/" + created.getIdElement().getIdPart()); try @@ -873,7 +1315,7 @@ public void testUpdateViaBatchBundle() throws Exception OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); final byte[] data2 = "Hello World and goodbye".getBytes(StandardCharsets.UTF_8); @@ -904,7 +1346,7 @@ public void testUpdateViaBatchBundle() throws Exception Bundle bundle = new Bundle(); bundle.setType(BundleType.BATCH); - bundle.addEntry().setFullUrl(BASE_URL + "Binary/" + created.getIdElement().getIdPart()).setResource(created) + bundle.addEntry().setFullUrl(BASE_URL + "/Binary/" + created.getIdElement().getIdPart()).setResource(created) .getRequest().setMethod(HTTPVerb.PUT).setUrl("Binary/" + created.getIdElement().getIdPart()); Bundle responseBundle = getWebserviceClient().postBundle(bundle); @@ -927,7 +1369,7 @@ public void testUpdateNotAllowedExternalUserViaBatchBundle() throws Exception OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); final byte[] data2 = "Hello World and goodbye".getBytes(StandardCharsets.UTF_8); @@ -958,7 +1400,7 @@ public void testUpdateNotAllowedExternalUserViaBatchBundle() throws Exception Bundle bundle = new Bundle(); bundle.setType(BundleType.BATCH); - bundle.addEntry().setFullUrl(BASE_URL + "Binary/" + created.getIdElement().getIdPart()).setResource(created) + bundle.addEntry().setFullUrl(BASE_URL + "/Binary/" + created.getIdElement().getIdPart()).setResource(created) .getRequest().setMethod(HTTPVerb.PUT).setUrl("Binary/" + created.getIdElement().getIdPart()); Bundle responseBundle = getExternalWebserviceClient().postBundle(bundle); @@ -978,7 +1420,7 @@ public void testUpdateSecurityContextOrgNotExistingViaBatchBundle() throws Excep OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); final byte[] data2 = "Hello World and goodbye".getBytes(StandardCharsets.UTF_8); @@ -1009,7 +1451,7 @@ public void testUpdateSecurityContextOrgNotExistingViaBatchBundle() throws Excep Bundle bundle = new Bundle(); bundle.setType(BundleType.BATCH); - bundle.addEntry().setFullUrl(BASE_URL + "Binary/" + created.getIdElement().getIdPart()).setResource(created) + bundle.addEntry().setFullUrl(BASE_URL + "/Binary/" + created.getIdElement().getIdPart()).setResource(created) .getRequest().setMethod(HTTPVerb.PUT).setUrl("Binary/" + created.getIdElement().getIdPart()); Bundle responseBundle = getWebserviceClient().postBundle(bundle); @@ -1030,7 +1472,7 @@ public void testSearchAll() throws Exception PartialResult<Organization> result = orgDao .search(orgDao.createSearchQueryWithoutUserFilter(1, 2).configureParameters(Collections.emptyMap())); assertNotNull(result); - assertEquals(2, result.getOverallCount()); + assertEquals(2, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(2, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); @@ -1039,7 +1481,7 @@ public void testSearchAll() throws Exception Organization org1 = result.getPartialResult().get(0); Organization org2 = result.getPartialResult().get(1); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary b1 = new Binary(); @@ -1086,7 +1528,7 @@ public void testSearchAllExternalUser() throws Exception PartialResult<Organization> result = orgDao .search(orgDao.createSearchQueryWithoutUserFilter(1, 2).configureParameters(Collections.emptyMap())); assertNotNull(result); - assertEquals(2, result.getOverallCount()); + assertEquals(2, result.getTotal()); assertNotNull(result.getPartialResult()); assertEquals(2, result.getPartialResult().size()); assertNotNull(result.getPartialResult().get(0)); @@ -1095,7 +1537,7 @@ public void testSearchAllExternalUser() throws Exception Organization org1 = result.getPartialResult().get(0); Organization org2 = result.getPartialResult().get(1); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8); Binary b1 = new Binary(); @@ -1143,7 +1585,7 @@ public void testDelete() throws Exception OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); @@ -1177,7 +1619,7 @@ public void testDeleteNotAllowedExternalUser() throws Exception OrganizationDao orgDao = getSpringWebApplicationContext().getBean(OrganizationDao.class); Organization createdOrg = orgDao.create(new Organization()); - final String contentType = "text/plain"; + final String contentType = MediaType.TEXT_PLAIN; final byte[] data1 = "Hello World".getBytes(StandardCharsets.UTF_8); Binary binary = new Binary(); diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/BundleIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/BundleIntegrationTest.java new file mode 100644 index 000000000..1a13ba53a --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/BundleIntegrationTest.java @@ -0,0 +1,62 @@ +package org.highmed.dsf.fhir.integration; + +import static org.junit.Assert.assertNotNull; + +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Map; + +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.OperationOutcome; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BundleIntegrationTest extends AbstractIntegrationTest +{ + private static final Logger logger = LoggerFactory.getLogger(BundleIntegrationTest.class); + + @Test + public void testCreateBundle() throws Exception + { + Bundle whiteList = readBundle(Paths.get("src/test/resources/integration/white-list.json"), + fhirContext.newJsonParser()); + + logger.debug(fhirContext.newJsonParser().encodeResourceToString(whiteList)); + + Bundle updatedBundle = getWebserviceClient().updateConditionaly(whiteList, Map.of("identifier", + Collections.singletonList("http://highmed.org/fhir/CodeSystem/update-whitelist|highmed_whitelist"))); + + assertNotNull(updatedBundle); + } + + @Test + public void testCreateBundleReturnMinimal() throws Exception + { + Bundle whiteList = readBundle(Paths.get("src/test/resources/integration/white-list.json"), + fhirContext.newJsonParser()); + + logger.debug(fhirContext.newJsonParser().encodeResourceToString(whiteList)); + + IdType id = getWebserviceClient().withMinimalReturn().updateConditionaly(whiteList, Map.of("identifier", + Collections.singletonList("http://highmed.org/fhir/CodeSystem/update-whitelist|highmed_whitelist"))); + + assertNotNull(id); + } + + @Test + public void testCreateBundleReturnOperationOutcome() throws Exception + { + Bundle whiteList = readBundle(Paths.get("src/test/resources/integration/white-list.json"), + fhirContext.newJsonParser()); + + logger.debug(fhirContext.newJsonParser().encodeResourceToString(whiteList)); + + OperationOutcome outcome = getWebserviceClient().withOperationOutcomeReturn().updateConditionaly(whiteList, + Map.of("identifier", Collections + .singletonList("http://highmed.org/fhir/CodeSystem/update-whitelist|highmed_whitelist"))); + + assertNotNull(outcome); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/EndpointIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/EndpointIntegrationTest.java index a3c53f5af..9a5e5e8fe 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/EndpointIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/EndpointIntegrationTest.java @@ -1,29 +1,102 @@ package org.highmed.dsf.fhir.integration; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.util.Collections; import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response.Status; + +import org.highmed.dsf.fhir.dao.EndpointDao; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.r4.model.Bundle.BundleType; +import org.hl7.fhir.r4.model.Bundle.HTTPVerb; import org.hl7.fhir.r4.model.Bundle.SearchEntryMode; import org.hl7.fhir.r4.model.Endpoint; import org.hl7.fhir.r4.model.Endpoint.EndpointStatus; +import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.Organization; +import org.hl7.fhir.r4.model.StringType; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.rest.api.Constants; public class EndpointIntegrationTest extends AbstractIntegrationTest { + private static final Logger logger = LoggerFactory.getLogger(EndpointIntegrationTest.class); + @Test public void testSearchAll() throws Exception { Bundle searchBundle = getWebserviceClient().search(Endpoint.class, Collections.emptyMap()); assertNotNull(searchBundle); - assertEquals(1, searchBundle.getTotal()); - assertTrue(searchBundle.getEntryFirstRep().getResource() instanceof Endpoint); + assertEquals(2, searchBundle.getTotal()); + + assertNotNull(searchBundle.getEntry()); + assertEquals(2, searchBundle.getEntry().size()); + assertNotNull(searchBundle.getEntry().get(0)); + assertNotNull(searchBundle.getEntry().get(0).getResource()); + assertTrue(searchBundle.getEntry().get(0).getResource() instanceof Endpoint); + assertNotNull(searchBundle.getEntry().get(0).getSearch()); + assertEquals(SearchEntryMode.MATCH, searchBundle.getEntry().get(0).getSearch().getMode()); + + assertNotNull(searchBundle.getEntry().get(1)); + assertNotNull(searchBundle.getEntry().get(1).getResource()); + assertTrue(searchBundle.getEntry().get(1).getResource() instanceof Endpoint); + assertNotNull(searchBundle.getEntry().get(1).getSearch()); + assertEquals(SearchEntryMode.MATCH, searchBundle.getEntry().get(1).getSearch().getMode()); + } + + @Test(expected = WebApplicationException.class) + public void testSearchWithUnsupportedQueryParameterStrictHandling() throws Exception + { + try + { + getWebserviceClient().searchWithStrictHandling(Endpoint.class, + Map.of("not-supported-parameter", Collections.singletonList("not-supported-parameter-value"))); + } + catch (WebApplicationException e) + { + assertEquals(Status.BAD_REQUEST.getStatusCode(), e.getResponse().getStatus()); + throw e; + } + } + + @Test + public void testSearchWithUnsupportedQueryParameterLenientHandling() throws Exception + { + Bundle searchBundle = getWebserviceClient().search(Endpoint.class, + Map.of("not-supported-parameter", Collections.singletonList("not-supported-parameter-value"))); + + assertNotNull(searchBundle.getEntry()); + assertEquals(3, searchBundle.getEntry().size()); + assertNotNull(searchBundle.getEntry().get(0)); + assertNotNull(searchBundle.getEntry().get(0).getResource()); + assertTrue(searchBundle.getEntry().get(0).getResource() instanceof Endpoint); + assertNotNull(searchBundle.getEntry().get(0).getSearch()); + assertEquals(SearchEntryMode.MATCH, searchBundle.getEntry().get(0).getSearch().getMode()); + + assertNotNull(searchBundle.getEntry().get(1)); + assertNotNull(searchBundle.getEntry().get(1).getResource()); + assertTrue(searchBundle.getEntry().get(1).getResource() instanceof Endpoint); + assertNotNull(searchBundle.getEntry().get(1).getSearch()); + assertEquals(SearchEntryMode.MATCH, searchBundle.getEntry().get(1).getSearch().getMode()); + + assertNotNull(searchBundle.getEntry().get(2)); + assertNotNull(searchBundle.getEntry().get(2).getResource()); + assertTrue(searchBundle.getEntry().get(2).getResource() instanceof OperationOutcome); + assertNotNull(searchBundle.getEntry().get(2).getSearch()); + assertEquals(SearchEntryMode.OUTCOME, searchBundle.getEntry().get(2).getSearch().getMode()); } @Test @@ -32,20 +105,32 @@ public void testSearchEndpointIncludeOrganization() throws Exception Bundle searchBundle = getWebserviceClient().search(Endpoint.class, Map.of("_include", Collections.singletonList("Endpoint:organization"))); assertNotNull(searchBundle); - assertEquals(1, searchBundle.getTotal()); - assertEquals(2, searchBundle.getEntry().size()); + assertEquals(2, searchBundle.getTotal()); + assertEquals(4, searchBundle.getEntry().size()); - BundleEntryComponent eptEntry = searchBundle.getEntry().get(0); - assertNotNull(eptEntry); - assertEquals(SearchEntryMode.MATCH, eptEntry.getSearch().getMode()); - assertNotNull(eptEntry.getResource()); - assertTrue(eptEntry.getResource() instanceof Endpoint); - - BundleEntryComponent orgEntry = searchBundle.getEntry().get(1); - assertNotNull(orgEntry); - assertEquals(SearchEntryMode.INCLUDE, orgEntry.getSearch().getMode()); - assertNotNull(orgEntry.getResource()); - assertTrue(orgEntry.getResource() instanceof Organization); + BundleEntryComponent eptEntry1 = searchBundle.getEntry().get(0); + assertNotNull(eptEntry1); + assertEquals(SearchEntryMode.MATCH, eptEntry1.getSearch().getMode()); + assertNotNull(eptEntry1.getResource()); + assertTrue(eptEntry1.getResource() instanceof Endpoint); + + BundleEntryComponent eptEntry2 = searchBundle.getEntry().get(1); + assertNotNull(eptEntry2); + assertEquals(SearchEntryMode.MATCH, eptEntry2.getSearch().getMode()); + assertNotNull(eptEntry2.getResource()); + assertTrue(eptEntry2.getResource() instanceof Endpoint); + + BundleEntryComponent orgEntry1 = searchBundle.getEntry().get(2); + assertNotNull(orgEntry1); + assertEquals(SearchEntryMode.INCLUDE, orgEntry1.getSearch().getMode()); + assertNotNull(orgEntry1.getResource()); + assertTrue(orgEntry1.getResource() instanceof Organization); + + BundleEntryComponent orgEntry2 = searchBundle.getEntry().get(3); + assertNotNull(orgEntry2); + assertEquals(SearchEntryMode.INCLUDE, orgEntry2.getSearch().getMode()); + assertNotNull(orgEntry2.getResource()); + assertTrue(orgEntry2.getResource() instanceof Organization); } @Test @@ -54,20 +139,32 @@ public void testSearchEndpointRevIncludeOrganization() throws Exception Bundle searchBundle = getWebserviceClient().search(Endpoint.class, Map.of("_revinclude", Collections.singletonList("Organization:endpoint"))); assertNotNull(searchBundle); - assertEquals(1, searchBundle.getTotal()); - assertEquals(2, searchBundle.getEntry().size()); + assertEquals(2, searchBundle.getTotal()); + assertEquals(4, searchBundle.getEntry().size()); + + BundleEntryComponent eptEntry1 = searchBundle.getEntry().get(0); + assertNotNull(eptEntry1); + assertEquals(SearchEntryMode.MATCH, eptEntry1.getSearch().getMode()); + assertNotNull(eptEntry1.getResource()); + assertTrue(eptEntry1.getResource() instanceof Endpoint); - BundleEntryComponent orgEntry = searchBundle.getEntry().get(0); - assertNotNull(orgEntry); - assertEquals(SearchEntryMode.MATCH, orgEntry.getSearch().getMode()); - assertNotNull(orgEntry.getResource()); - assertTrue(orgEntry.getResource() instanceof Endpoint); - - BundleEntryComponent eptEntry = searchBundle.getEntry().get(1); - assertNotNull(eptEntry); - assertEquals(SearchEntryMode.INCLUDE, eptEntry.getSearch().getMode()); - assertNotNull(eptEntry.getResource()); - assertTrue(eptEntry.getResource() instanceof Organization); + BundleEntryComponent eptEntry2 = searchBundle.getEntry().get(1); + assertNotNull(eptEntry2); + assertEquals(SearchEntryMode.MATCH, eptEntry2.getSearch().getMode()); + assertNotNull(eptEntry2.getResource()); + assertTrue(eptEntry2.getResource() instanceof Endpoint); + + BundleEntryComponent orgEntry1 = searchBundle.getEntry().get(2); + assertNotNull(orgEntry1); + assertEquals(SearchEntryMode.INCLUDE, orgEntry1.getSearch().getMode()); + assertNotNull(orgEntry1.getResource()); + assertTrue(orgEntry1.getResource() instanceof Organization); + + BundleEntryComponent orgEntry2 = searchBundle.getEntry().get(3); + assertNotNull(orgEntry2); + assertEquals(SearchEntryMode.INCLUDE, orgEntry2.getSearch().getMode()); + assertNotNull(orgEntry2.getResource()); + assertTrue(orgEntry2.getResource() instanceof Organization); } @Test @@ -93,4 +190,137 @@ public void testCreateValidByLocalUser() throws Exception assertNotNull(created.getIdElement().getIdPart()); assertNotNull(created.getIdElement().getVersionIdPart()); } + + @Test + public void testCreateReadWithLogicalReference() throws Exception + { + FhirContext context = FhirContext.forR4(); + + Organization organization = new Organization(); + organization.getMeta().addTag().setSystem("http://highmed.org/fhir/CodeSystem/authorization-role") + .setCode("REMOTE"); + organization.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("bla-bla.de"); + organization.addExtension("http://highmed.org/fhir/StructureDefinition/certificate-thumbprint", new StringType( + "6b83a92506d67265697c74f50a9cac0ec7182adcc5302e5ed487ae1a782fe278f5ca79808c971e061fadded2c303a2223140ef3450d1d27717dd704a823f95e9")); + + Organization createdOrg = getWebserviceClient().create(organization); + logger.debug("Organization: {}", + context.newXmlParser().setPrettyPrint(true).encodeResourceToString(createdOrg)); + + Endpoint endpoint = new Endpoint(); + endpoint.getMeta().addTag().setSystem("http://highmed.org/fhir/CodeSystem/authorization-role") + .setCode("REMOTE"); + endpoint.setStatus(EndpointStatus.ACTIVE); + endpoint.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/endpoint-identifier") + .setValue("foo-bar-baz.test.bla-bla.de"); + endpoint.getManagingOrganization().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("bla-bla.de"); + endpoint.getConnectionType().setSystem("http://terminology.hl7.org/CodeSystem/endpoint-connection-type") + .setCode("hl7-fhir-rest"); + endpoint.getPayloadTypeFirstRep().getCodingFirstRep().setSystem("http://hl7.org/fhir/resource-types") + .setCode("Task"); + endpoint.addPayloadMimeTypeElement().setSystem("urn:ietf:bcp:13").setValue(Constants.CT_FHIR_XML_NEW); + endpoint.addPayloadMimeTypeElement().setSystem("urn:ietf:bcp:13").setValue(Constants.CT_FHIR_JSON_NEW); + endpoint.setAddress("https://foo-bar-baz.test.bla-bla.de/fhir"); + + logger.debug("endpoint: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(endpoint)); + + Endpoint createdEdp = getWebserviceClient().create(endpoint); + assertNotNull(createdEdp); + logger.debug("created: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(createdEdp)); + assertTrue(createdEdp.hasIdElement()); + assertTrue(createdEdp.getIdElement().hasIdPart()); + assertTrue(createdEdp.hasManagingOrganization()); + assertTrue(createdEdp.getManagingOrganization().hasIdentifier()); + assertFalse(createdEdp.getManagingOrganization().hasReference()); + + EndpointDao dao = getSpringWebApplicationContext().getBean(EndpointDao.class); + Optional<Endpoint> daoEdp = dao.read(UUID.fromString(createdEdp.getIdElement().getIdPart())); + assertTrue(daoEdp.isPresent()); + logger.debug("db: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(daoEdp.get())); + assertTrue(daoEdp.get().hasIdElement()); + assertTrue(daoEdp.get().getIdElement().hasIdPart()); + assertTrue(daoEdp.get().hasManagingOrganization()); + assertTrue(daoEdp.get().getManagingOrganization().hasIdentifier()); + assertTrue(daoEdp.get().getManagingOrganization().hasReference()); + + Endpoint readEdp = getWebserviceClient().read(Endpoint.class, createdEdp.getIdElement().getIdPart()); + assertNotNull(readEdp); + logger.debug("read: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(readEdp)); + assertTrue(readEdp.hasIdElement()); + assertTrue(readEdp.getIdElement().hasIdPart()); + assertTrue(readEdp.hasManagingOrganization()); + assertTrue(readEdp.getManagingOrganization().hasIdentifier()); + assertFalse(readEdp.getManagingOrganization().hasReference()); + + Endpoint vReadEdp = getWebserviceClient().read(Endpoint.class, createdEdp.getIdElement().getIdPart(), + createdEdp.getIdElement().getVersionIdPart()); + assertNotNull(vReadEdp); + logger.debug("vread: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(vReadEdp)); + assertTrue(vReadEdp.hasIdElement()); + assertTrue(vReadEdp.getIdElement().hasIdPart()); + assertTrue(vReadEdp.hasManagingOrganization()); + assertTrue(vReadEdp.getManagingOrganization().hasIdentifier()); + assertFalse(vReadEdp.getManagingOrganization().hasReference()); + } + + @Test + public void testCreateReadWithLogicalReferenceViaBundle() throws Exception + { + FhirContext context = FhirContext.forR4(); + + String orgTempId = "urn:uuid:" + UUID.randomUUID().toString(); + String endTempId = "urn:uuid:" + UUID.randomUUID().toString(); + + Organization organization = new Organization(); + organization.getMeta().addTag().setSystem("http://highmed.org/fhir/CodeSystem/authorization-role") + .setCode("REMOTE"); + organization.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("bla-bla.de"); + organization.addExtension("http://highmed.org/fhir/StructureDefinition/certificate-thumbprint", new StringType( + "6b83a92506d67265697c74f50a9cac0ec7182adcc5302e5ed487ae1a782fe278f5ca79808c971e061fadded2c303a2223140ef3450d1d27717dd704a823f95e9")); + organization.addEndpoint().setReference(endTempId); + + Endpoint endpoint = new Endpoint(); + endpoint.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-endpoint"); + endpoint.getMeta().addTag().setSystem("http://highmed.org/fhir/CodeSystem/authorization-role") + .setCode("REMOTE"); + endpoint.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/endpoint-identifier") + .setValue("foo-bar-baz.test.bla-bla.de"); + endpoint.setStatus(EndpointStatus.ACTIVE); + endpoint.getConnectionType().setSystem("http://terminology.hl7.org/CodeSystem/endpoint-connection-type") + .setCode("hl7-fhir-rest"); + endpoint.getManagingOrganization().setReference(orgTempId); + endpoint.getPayloadTypeFirstRep().getCodingFirstRep().setSystem("http://hl7.org/fhir/resource-types") + .setCode("Task"); + endpoint.addPayloadMimeTypeElement().setSystem("urn:ietf:bcp:13").setValue(Constants.CT_FHIR_XML_NEW); + endpoint.addPayloadMimeTypeElement().setSystem("urn:ietf:bcp:13").setValue(Constants.CT_FHIR_JSON_NEW); + endpoint.setAddress("https://foo-bar-baz.test.bla-bla.de/fhir"); + + Bundle bundle = new Bundle(); + bundle.setType(BundleType.TRANSACTION); + bundle.addEntry().setFullUrl(orgTempId).setResource(organization).getRequest().setMethod(HTTPVerb.POST) + .setUrl("Organization"); + bundle.addEntry().setFullUrl(endTempId).setResource(endpoint).getRequest().setMethod(HTTPVerb.POST) + .setUrl("Endpoint"); + bundle.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl( + "Endpoint?identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|foo-bar-baz.test.bla-bla.de"); + + logger.debug("bundle: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle)); + Bundle postBundle = getWebserviceClient().postBundle(bundle); + logger.debug("post: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(postBundle)); + + assertTrue(postBundle.hasEntry()); + assertEquals(3, postBundle.getEntry().size()); + assertTrue(postBundle.getEntry().get(2).hasResource()); + assertTrue(postBundle.getEntry().get(2).getResource() instanceof Endpoint); + + Endpoint readEdp = (Endpoint) postBundle.getEntry().get(2).getResource(); + assertNotNull(readEdp); + assertTrue(readEdp.hasIdElement()); + assertTrue(readEdp.getIdElement().hasIdPart()); + assertTrue(readEdp.hasManagingOrganization()); + assertTrue(readEdp.getManagingOrganization().hasReference()); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/OrganizationIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/OrganizationIntegrationTest.java index 14238973d..e0acbe0bf 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/OrganizationIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/OrganizationIntegrationTest.java @@ -32,7 +32,7 @@ public void testSearchOrganizationIncludeEndpoint() throws Exception Map.of("_include", Collections.singletonList("Organization:endpoint"))); assertNotNull(searchBundle); assertEquals(2, searchBundle.getTotal()); - assertEquals(3, searchBundle.getEntry().size()); + assertEquals(4, searchBundle.getEntry().size()); BundleEntryComponent orgEntry1 = searchBundle.getEntry().get(0); assertNotNull(orgEntry1); @@ -46,11 +46,17 @@ public void testSearchOrganizationIncludeEndpoint() throws Exception assertNotNull(orgEntry2.getResource()); assertTrue(orgEntry2.getResource() instanceof Organization); - BundleEntryComponent eptEntry = searchBundle.getEntry().get(2); - assertNotNull(eptEntry); - assertEquals(SearchEntryMode.INCLUDE, eptEntry.getSearch().getMode()); - assertNotNull(eptEntry.getResource()); - assertTrue(eptEntry.getResource() instanceof Endpoint); + BundleEntryComponent eptEntry1 = searchBundle.getEntry().get(2); + assertNotNull(eptEntry1); + assertEquals(SearchEntryMode.INCLUDE, eptEntry1.getSearch().getMode()); + assertNotNull(eptEntry1.getResource()); + assertTrue(eptEntry1.getResource() instanceof Endpoint); + + BundleEntryComponent eptEntry2 = searchBundle.getEntry().get(3); + assertNotNull(eptEntry2); + assertEquals(SearchEntryMode.INCLUDE, eptEntry2.getSearch().getMode()); + assertNotNull(eptEntry2.getResource()); + assertTrue(eptEntry2.getResource() instanceof Endpoint); } @Test @@ -60,7 +66,7 @@ public void testSearchOrganizationRevIncludeEndpoint() throws Exception Map.of("_revinclude", Collections.singletonList("Endpoint:organization"))); assertNotNull(searchBundle); assertEquals(2, searchBundle.getTotal()); - assertEquals(3, searchBundle.getEntry().size()); + assertEquals(4, searchBundle.getEntry().size()); BundleEntryComponent orgEntry1 = searchBundle.getEntry().get(0); assertNotNull(orgEntry1); @@ -74,10 +80,16 @@ public void testSearchOrganizationRevIncludeEndpoint() throws Exception assertNotNull(orgEntry2.getResource()); assertTrue(orgEntry2.getResource() instanceof Organization); - BundleEntryComponent eptEntry = searchBundle.getEntry().get(2); - assertNotNull(eptEntry); - assertEquals(SearchEntryMode.INCLUDE, eptEntry.getSearch().getMode()); - assertNotNull(eptEntry.getResource()); - assertTrue(eptEntry.getResource() instanceof Endpoint); + BundleEntryComponent eptEntry1 = searchBundle.getEntry().get(2); + assertNotNull(eptEntry1); + assertEquals(SearchEntryMode.INCLUDE, eptEntry1.getSearch().getMode()); + assertNotNull(eptEntry1.getResource()); + assertTrue(eptEntry1.getResource() instanceof Endpoint); + + BundleEntryComponent eptEntry2 = searchBundle.getEntry().get(3); + assertNotNull(eptEntry2); + assertEquals(SearchEntryMode.INCLUDE, eptEntry2.getSearch().getMode()); + assertNotNull(eptEntry2.getResource()); + assertTrue(eptEntry2.getResource() instanceof Endpoint); } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/TaskIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/TaskIntegrationTest.java index f121dd7fb..72290d9f6 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/TaskIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/integration/TaskIntegrationTest.java @@ -1,14 +1,14 @@ package org.highmed.dsf.fhir.integration; import static junit.framework.TestCase.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import java.nio.file.Paths; +import java.util.Collections; import java.util.Date; import java.util.EnumSet; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; @@ -24,8 +24,10 @@ import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.DomainResource; +import org.hl7.fhir.r4.model.Extension; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.ResearchStudy; import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.Task; import org.hl7.fhir.r4.model.Task.ParameterComponent; @@ -33,9 +35,15 @@ import org.hl7.fhir.r4.model.Task.TaskRestrictionComponent; import org.hl7.fhir.r4.model.Task.TaskStatus; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; public class TaskIntegrationTest extends AbstractIntegrationTest { + private static final Logger logger = LoggerFactory.getLogger(TaskIntegrationTest.class); + private List<Bundle.BundleEntryComponent> createTaskBundle() { Bundle bundle = readBundle(Paths.get("src/test/resources/integration/task-bundle.json"), newJsonParser()); @@ -56,8 +64,9 @@ public void testHandleBundleForRequestSimpleFeasibility() throws Exception try { List<Bundle.BundleEntryComponent> resultBundleEntries = createTaskBundle(); + assertEquals(4, resultBundleEntries.size()); - String taskId = new IdType(resultBundleEntries.get(5).getFullUrl()).getIdPart(); + String taskId = new IdType(resultBundleEntries.get(3).getFullUrl()).getIdPart(); Task task = getWebserviceClient().read(Task.class, taskId); Task.ParameterComponent input = task.getInput().stream() @@ -65,7 +74,7 @@ public void testHandleBundleForRequestSimpleFeasibility() throws Exception .findFirst().orElse(new Task.ParameterComponent()); IdType taskInputResearchStudyId = new IdType(((Reference) input.getValue()).getReference()); - IdType researchStudyId = new IdType(resultBundleEntries.get(4).getFullUrl()); + IdType researchStudyId = new IdType(resultBundleEntries.get(2).getFullUrl()); assertEquals(researchStudyId.getResourceType(), taskInputResearchStudyId.getResourceType()); assertEquals(researchStudyId.getIdPart(), taskInputResearchStudyId.getIdPart()); @@ -85,6 +94,32 @@ public void testHandleBundleForRequestSimpleFeasibility() throws Exception assertEquals(researchStudyId.getResourceType(), taskInputResearchStudyIdViaWebsocket.getResourceType()); assertEquals(researchStudyId.getIdPart(), taskInputResearchStudyIdViaWebsocket.getIdPart()); assertEquals(researchStudyId.getVersionIdPart(), taskInputResearchStudyIdViaWebsocket.getVersionIdPart()); + + ResearchStudy researchStudy = getWebserviceClient().read(ResearchStudy.class, researchStudyId.getIdPart()); + logger.debug("ResearchStudy: {}", + FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(researchStudy)); + + List<Extension> medics = researchStudy + .getExtensionsByUrl("http://highmed.org/fhir/StructureDefinition/participating-medic"); + assertNotNull(medics); + assertEquals(1, medics.size()); + Extension medicExt = medics.get(0); + assertTrue(medicExt.hasValue()); + assertTrue(medicExt.getValue() instanceof Reference); + Reference medicRef = (Reference) medicExt.getValue(); + assertTrue(medicRef.hasIdentifier()); + assertFalse(medicRef.hasReference()); + + List<Extension> ttps = researchStudy + .getExtensionsByUrl("http://highmed.org/fhir/StructureDefinition/participating-ttp"); + assertNotNull(ttps); + assertEquals(1, ttps.size()); + Extension ttpExt = medics.get(0); + assertTrue(ttpExt.hasValue()); + assertTrue(ttpExt.getValue() instanceof Reference); + Reference ttpRef = (Reference) ttpExt.getValue(); + assertTrue(ttpRef.hasIdentifier()); + assertFalse(ttpRef.hasReference()); } finally { @@ -101,17 +136,20 @@ public void testCreateTaskStartPingProcess() throws Exception assertNotNull(organizationProvider); Task t = new Task(); - t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setStatus(TaskStatus.REQUESTED); t.setIntent(TaskIntent.ORDER); t.setAuthoredOn(new Date()); - Reference localOrg = new Reference(organizationProvider.getLocalOrganization().get()); + Reference localOrg = new Reference(); + localOrg.setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_Organization"); t.setRequester(localOrg); t.getRestriction().addRecipient(localOrg); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); getWebserviceClient().create(t); } @@ -124,8 +162,8 @@ public void testCreateTaskStartPingProcessNotAllowedForRemoteUser() throws Excep assertNotNull(organizationProvider); Task t = new Task(); - t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setStatus(TaskStatus.REQUESTED); t.setIntent(TaskIntent.ORDER); t.setAuthoredOn(new Date()); @@ -138,7 +176,7 @@ public void testCreateTaskStartPingProcessNotAllowedForRemoteUser() throws Excep t.getRestriction().addRecipient(new Reference(organizationProvider.getLocalOrganization().get())); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); try { @@ -160,7 +198,7 @@ public void testCreateTaskStartPongProcessAllowedForRemoteUser() throws Exceptio Task t = new Task(); t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-ping"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.1.0"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.2.0"); t.setStatus(TaskStatus.REQUESTED); t.setIntent(TaskIntent.ORDER); t.setAuthoredOn(new Date()); @@ -170,10 +208,26 @@ public void testCreateTaskStartPongProcessAllowedForRemoteUser() throws Exceptio .setValue("External_Test_Organization"); t.setRequester(requester); - t.getRestriction().addRecipient(new Reference(organizationProvider.getLocalOrganization().get())); - t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") + Reference localOrg = new Reference(); + localOrg.setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_Organization"); + t.getRestriction().addRecipient(localOrg); + + ParameterComponent in1 = t.addInput(); + in1.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("pingMessage")); + in1.setValue(new StringType("pingMessage")); + + ParameterComponent in2 = t.addInput(); + in2.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") + .setCode("business-key"); + in2.setValue(new StringType(UUID.randomUUID().toString())); + + ParameterComponent in3 = t.addInput(); + in3.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") + .setCode("correlation-key"); + in3.setValue(new StringType(UUID.randomUUID().toString())); getExternalWebserviceClient().create(t); } @@ -187,7 +241,7 @@ public void testCreateTaskContinuePingProcessAllowedForRemoteUser() throws Excep Task t = new Task(); t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-pong"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setStatus(TaskStatus.REQUESTED); t.setIntent(TaskIntent.ORDER); t.setAuthoredOn(new Date()); @@ -197,10 +251,26 @@ public void testCreateTaskContinuePingProcessAllowedForRemoteUser() throws Excep .setValue("External_Test_Organization"); t.setRequester(requester); - t.getRestriction().addRecipient(new Reference(organizationProvider.getLocalOrganization().get())); - t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") + Reference localOrg = new Reference(); + localOrg.setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_Organization"); + t.getRestriction().addRecipient(localOrg); + + ParameterComponent in1 = t.addInput(); + in1.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("pongMessage")); + in1.setValue(new StringType("pongMessage")); + + ParameterComponent in2 = t.addInput(); + in2.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") + .setCode("business-key"); + in2.setValue(new StringType(UUID.randomUUID().toString())); + + ParameterComponent in3 = t.addInput(); + in3.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") + .setCode("correlation-key"); + in3.setValue(new StringType(UUID.randomUUID().toString())); getExternalWebserviceClient().create(t); } @@ -213,18 +283,20 @@ public void testUpdateTaskStartPingProcessStatusRequestedToInProgress() throws E assertNotNull(organizationProvider); Task t = new Task(); - t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setStatus(TaskStatus.REQUESTED); t.setIntent(TaskIntent.ORDER); t.setAuthoredOn(new Date()); - Reference localOrg = new Reference() - .setReferenceElement(organizationProvider.getLocalOrganization().get().getIdElement().toVersionless()); + Reference localOrg = new Reference(); + localOrg.setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_Organization"); t.setRequester(localOrg); t.getRestriction().addRecipient(localOrg); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); TaskDao dao = getSpringWebApplicationContext().getBean(TaskDao.class); Task created = dao.create(t); @@ -242,18 +314,22 @@ public void testUpdateTaskStartPingProcessStatusInProgressToCompleted() throws E assertNotNull(organizationProvider); Task t = new Task(); - t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setStatus(TaskStatus.INPROGRESS); t.setIntent(TaskIntent.ORDER); t.setAuthoredOn(new Date()); - Reference localOrg = new Reference() - .setReferenceElement(organizationProvider.getLocalOrganization().get().getIdElement().toVersionless()); + + Reference localOrg = new Reference(); + localOrg.setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_Organization"); t.setRequester(localOrg); t.getRestriction().addRecipient(localOrg); + t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); TaskDao dao = getSpringWebApplicationContext().getBean(TaskDao.class); Task created = dao.create(t); @@ -275,8 +351,8 @@ public void testCreateForbiddenLocalUserIllegalStatus() throws Exception TaskStatus.FAILED, TaskStatus.COMPLETED, TaskStatus.ENTEREDINERROR, TaskStatus.NULL); Task t = new Task(); - t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setAuthoredOn(new Date()); Reference localOrg = new Reference(organizationProvider.getLocalOrganization().get()); @@ -284,7 +360,7 @@ public void testCreateForbiddenLocalUserIllegalStatus() throws Exception t.getRestriction().addRecipient(localOrg); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.setStatus(null); testCreateExpectForbidden(getWebserviceClient(), t); @@ -309,7 +385,7 @@ public void testCreateForbiddenExternalUserIllegalStatus() throws Exception Task t = new Task(); t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-ping"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.1.0"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setAuthoredOn(new Date()); Reference requester = new Reference().setType("Organization"); @@ -352,8 +428,8 @@ public void testCreateForbiddenLocalUserNotPartOfRequesterOrganization() throws assertNotNull(organizationProvider); Task t = new Task(); - t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setStatus(TaskStatus.DRAFT); t.setAuthoredOn(new Date()); @@ -361,7 +437,7 @@ public void testCreateForbiddenLocalUserNotPartOfRequesterOrganization() throws t.getRestriction().addRecipient(localOrg); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.setRequester(null); testCreateExpectForbidden(getWebserviceClient(), t); @@ -390,7 +466,7 @@ public void testCreateForbiddenExternalUserNotPartOfRequesterOrganization() thro Task t = new Task(); t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-ping"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.1.0"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setStatus(TaskStatus.DRAFT); t.setAuthoredOn(new Date()); @@ -424,8 +500,8 @@ public void testCreateForbiddenLocalUserRestrictionRecipientNotValidByLocalUser( assertNotNull(organizationProvider); Task t = new Task(); - t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setStatus(TaskStatus.DRAFT); t.setAuthoredOn(new Date()); @@ -433,7 +509,7 @@ public void testCreateForbiddenLocalUserRestrictionRecipientNotValidByLocalUser( t.setRequester(localOrg); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.setRestriction(null); testCreateExpectForbidden(getWebserviceClient(), t); @@ -478,7 +554,7 @@ public void testCreateForbiddenLocalUserRestrictionRecipientNotValidByExternalUs Task t = new Task(); t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-ping"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.1.0"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setStatus(TaskStatus.DRAFT); t.setAuthoredOn(new Date()); @@ -532,8 +608,8 @@ public void testCreateForbiddenInstantiatesUriNotValidByLocalUser() throws Excep assertNotNull(organizationProvider); Task t = new Task(); - t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - // t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + // t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setStatus(TaskStatus.DRAFT); t.setAuthoredOn(new Date()); @@ -542,7 +618,7 @@ public void testCreateForbiddenInstantiatesUriNotValidByLocalUser() throws Excep t.getRestriction().addRecipient(localOrg); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.setInstantiatesUri(null); testCreateExpectForbidden(getWebserviceClient(), t); @@ -560,7 +636,7 @@ public void testCreateForbiddenInstantiatesUriNotValidByExternalUser() throws Ex Task t = new Task(); t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-ping"); - // t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.1.0"); + // t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setStatus(TaskStatus.DRAFT); t.setAuthoredOn(new Date()); @@ -589,8 +665,8 @@ public void testCreateForbiddenInputNotValidByLocalUser() throws Exception assertNotNull(organizationProvider); Task t = new Task(); - t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setStatus(TaskStatus.DRAFT); t.setAuthoredOn(new Date()); @@ -599,7 +675,7 @@ public void testCreateForbiddenInputNotValidByLocalUser() throws Exception t.getRestriction().addRecipient(localOrg); // t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") // .setCode("message-name"); - // t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + // t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.setInput(null); testCreateExpectForbidden(getWebserviceClient(), t); @@ -613,11 +689,11 @@ public void testCreateForbiddenInputNotValidByLocalUser() throws Exception ParameterComponent in1 = t.addInput(); in1.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - in1.setValue(new StringType("startProcessMessage")); + in1.setValue(new StringType("startPingProcessMessage")); ParameterComponent in2 = t.addInput(); in2.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - in2.setValue(new StringType("startProcessMessage")); + in2.setValue(new StringType("startPingProcessMessage")); testCreateExpectForbidden(getWebserviceClient(), t); t.setInput(null); @@ -628,7 +704,7 @@ public void testCreateForbiddenInputNotValidByLocalUser() throws Exception t.setInput(null); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode(""); - t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); testCreateExpectForbidden(getWebserviceClient(), t); t.setInput(null); @@ -653,7 +729,7 @@ public void testCreateForbiddenInputNotValidByExternalUser() throws Exception Task t = new Task(); t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-ping"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.1.0"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setStatus(TaskStatus.DRAFT); t.setAuthoredOn(new Date()); @@ -679,11 +755,11 @@ public void testCreateForbiddenInputNotValidByExternalUser() throws Exception ParameterComponent in1 = t.addInput(); in1.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - in1.setValue(new StringType("startProcessMessage")); + in1.setValue(new StringType("startPingProcessMessage")); ParameterComponent in2 = t.addInput(); in2.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - in2.setValue(new StringType("startProcessMessage")); + in2.setValue(new StringType("startPingProcessMessage")); testCreateExpectForbidden(getExternalWebserviceClient(), t); t.setInput(null); @@ -718,8 +794,8 @@ public void testCreateForbiddenOutputNotValidByLocalUser() throws Exception assertNotNull(organizationProvider); Task t = new Task(); - t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-process"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setStatus(TaskStatus.DRAFT); t.setAuthoredOn(new Date()); @@ -728,7 +804,7 @@ public void testCreateForbiddenOutputNotValidByLocalUser() throws Exception t.getRestriction().addRecipient(localOrg); t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") .setCode("message-name"); - t.getInputFirstRep().setValue(new StringType("startProcessMessage")); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); t.getOutputFirstRep().getType().getCodingFirstRep().setSystem("system").setCode("code"); t.getOutputFirstRep().setValue(new StringType("value")); @@ -744,7 +820,7 @@ public void testCreateForbiddenOutputNotValidByExternalUser() throws Exception Task t = new Task(); t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-ping"); - t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.1.0"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.2.0"); t.setIntent(TaskIntent.ORDER); t.setStatus(TaskStatus.DRAFT); t.setAuthoredOn(new Date()); @@ -762,4 +838,55 @@ public void testCreateForbiddenOutputNotValidByExternalUser() throws Exception t.getOutputFirstRep().setValue(new StringType("value")); testCreateExpectForbidden(getExternalWebserviceClient(), t); } + + @Test + public void testSearchByStatusRequested() throws Exception + { + Task t = new Task(); + t.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + t.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); + t.setStatus(TaskStatus.REQUESTED); + t.setIntent(TaskIntent.ORDER); + t.setAuthoredOn(new Date()); + Reference localOrg = new Reference(); + localOrg.setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("Test_Organization"); + t.setRequester(localOrg); + t.getRestriction().addRecipient(localOrg); + t.getInputFirstRep().getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") + .setCode("message-name"); + t.getInputFirstRep().setValue(new StringType("startPingProcessMessage")); + + getWebserviceClient().create(t); + + Bundle searchResult = getWebserviceClient().searchWithStrictHandling(Task.class, Map.of("status", + Collections.singletonList("requested"), "_sort", Collections.singletonList("_lastUpdated"))); + assertNotNull(searchResult); + assertEquals(1, searchResult.getTotal()); + assertTrue(searchResult.hasEntry()); + assertNotNull(searchResult.getEntry()); + assertEquals(1, searchResult.getEntry().size()); + assertTrue(searchResult.getEntryFirstRep().hasResource()); + assertNotNull(searchResult.getEntryFirstRep().getResource()); + assertTrue(searchResult.getEntryFirstRep().getResource() instanceof Task); + + Task result = (Task) searchResult.getEntryFirstRep().getResource(); + assertTrue(result.hasRequester()); + assertTrue(result.hasRestriction()); + assertTrue(result.getRestriction().hasRecipient()); + assertNotNull(result.getRestriction().getRecipient()); + assertEquals(1, result.getRestriction().getRecipient().size()); + assertNotNull(result.getRestriction().getRecipientFirstRep()); + + Reference ref = result.getRestriction().getRecipientFirstRep(); + assertFalse(ref.hasReference()); + assertNull(ref.getReference()); + assertTrue(ref.hasIdentifier()); + assertNotNull(ref.getIdentifier()); + assertTrue(ref.getIdentifier().hasSystem()); + assertNotNull(ref.getIdentifier().getSystem()); + assertTrue(ref.getIdentifier().hasValue()); + assertNotNull(ref.getIdentifier().getValue()); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/EndpointProfileTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/EndpointProfileTest.java new file mode 100644 index 000000000..e7024d11a --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/EndpointProfileTest.java @@ -0,0 +1,60 @@ +package org.highmed.dsf.fhir.profiles; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.UUID; + +import org.highmed.dsf.fhir.service.ResourceValidator; +import org.highmed.dsf.fhir.service.ResourceValidatorImpl; +import org.hl7.fhir.r4.model.Endpoint; +import org.hl7.fhir.r4.model.Endpoint.EndpointStatus; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.validation.ResultSeverityEnum; +import ca.uhn.fhir.validation.ValidationResult; + +public class EndpointProfileTest +{ + private static final Logger logger = LoggerFactory.getLogger(EndpointProfileTest.class); + + @ClassRule + public static final ValidationSupportRule validationRule = new ValidationSupportRule( + Arrays.asList("highmed-endpoint-0.2.0.xml"), + Arrays.asList("authorization-role-0.2.0.xml", "urn_ietf_bcp_13.xml"), + Arrays.asList("authorization-role-0.2.0.xml", "valueset-mimetypes.xml")); + + private ResourceValidator resourceValidator = new ResourceValidatorImpl(validationRule.getFhirContext(), + validationRule.getValidationSupport()); + + @Test + public void testOrganizationProfileValid() throws Exception + { + Endpoint endpoint = new Endpoint(); + endpoint.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-endpoint"); + endpoint.getMeta().addTag().setSystem("http://highmed.org/fhir/CodeSystem/authorization-role") + .setCode("REMOTE"); + endpoint.getIdentifierFirstRep().setSystem("http://highmed.org/fhir/NamingSystem/endpoint-identifier") + .setValue("fhir.test.com"); + endpoint.setStatus(EndpointStatus.ACTIVE); + endpoint.getConnectionType().setSystem("http://terminology.hl7.org/CodeSystem/endpoint-connection-type") + .setCode("hl7-fhir-rest"); + endpoint.getManagingOrganization().setReference("Organization/" + UUID.randomUUID().toString()); + endpoint.getPayloadTypeFirstRep().getCodingFirstRep().setSystem("http://hl7.org/fhir/resource-types") + .setCode("Task"); + endpoint.addPayloadMimeTypeElement().setSystem("urn:ietf:bcp:13").setValue(Constants.CT_FHIR_XML_NEW); + endpoint.addPayloadMimeTypeElement().setSystem("urn:ietf:bcp:13").setValue(Constants.CT_FHIR_JSON_NEW); + endpoint.setAddress("https://fhir.test.com/fhir"); + + ValidationResult result = resourceValidator.validate(endpoint); + result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" + + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/GroupProfileTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/GroupProfileTest.java new file mode 100644 index 000000000..826a70e25 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/GroupProfileTest.java @@ -0,0 +1,54 @@ +package org.highmed.dsf.fhir.profiles; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.highmed.dsf.fhir.service.ResourceValidator; +import org.highmed.dsf.fhir.service.ResourceValidatorImpl; +import org.hl7.fhir.r4.model.CodeType; +import org.hl7.fhir.r4.model.Expression; +import org.hl7.fhir.r4.model.Group; +import org.hl7.fhir.r4.model.Group.GroupType; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.validation.ResultSeverityEnum; +import ca.uhn.fhir.validation.ValidationResult; + +public class GroupProfileTest +{ + private static final Logger logger = LoggerFactory.getLogger(GroupProfileTest.class); + + @ClassRule + public static final ValidationSupportRule validationRule = new ValidationSupportRule( + Arrays.asList("highmed-extension-query-0.2.0.xml", "highmed-group-0.2.0.xml"), + Arrays.asList("authorization-role-0.2.0.xml", "query-type-0.2.0.xml"), + Arrays.asList("authorization-role-0.2.0.xml", "query-type-0.2.0.xml")); + + private ResourceValidator resourceValidator = new ResourceValidatorImpl(validationRule.getFhirContext(), + validationRule.getValidationSupport()); + + @Test + public void testGroupProfileValid() throws Exception + { + Group group = new Group(); + group.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-group"); + group.setType(GroupType.PERSON); + group.setActual(false); + group.addExtension().setUrl("http://highmed.org/fhir/StructureDefinition/query") + .setValue(new Expression() + .setLanguageElement(new CodeType("application/x-aql-query") + .setSystem("http://highmed.org/fhir/CodeSystem/query-type")) + .setExpression("SELECT COUNT(e) FROM EHR e")); + + ValidationResult result = resourceValidator.validate(group); + result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" + + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/OrganizationProfileTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/OrganizationProfileTest.java index e9277fd80..aee1ffcf8 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/OrganizationProfileTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/OrganizationProfileTest.java @@ -1,36 +1,19 @@ package org.highmed.dsf.fhir.profiles; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import java.nio.file.Paths; -import java.util.List; +import java.util.Arrays; import java.util.UUID; -import org.highmed.dsf.fhir.service.DefaultProfileValidationSupportWithCustomResources; import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.service.ResourceValidatorImpl; -import org.highmed.dsf.fhir.service.SnapshotGenerator; -import org.highmed.dsf.fhir.service.SnapshotGenerator.SnapshotWithValidationMessages; -import org.highmed.dsf.fhir.service.SnapshotGeneratorImpl; -import org.highmed.dsf.fhir.service.StructureDefinitionReader; -import org.highmed.dsf.fhir.service.ValueSetExpander; -import org.highmed.dsf.fhir.service.ValueSetExpanderImpl; -import org.hl7.fhir.r4.model.CodeSystem; -import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode; -import org.hl7.fhir.r4.model.Enumerations.PublicationStatus; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.StringType; -import org.hl7.fhir.r4.model.StructureDefinition; -import org.hl7.fhir.r4.model.ValueSet; -import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome; -import org.junit.Before; +import org.junit.ClassRule; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.ValidationResult; @@ -38,196 +21,67 @@ public class OrganizationProfileTest { private static final Logger logger = LoggerFactory.getLogger(OrganizationProfileTest.class); - private FhirContext context; - private DefaultProfileValidationSupportWithCustomResources validationSupport; + @ClassRule + public static final ValidationSupportRule validationRule = new ValidationSupportRule( + Arrays.asList("highmed-organization-0.2.0.xml", "highmed-extension-certificate-thumbprint-0.2.0.xml", + "highmed-endpoint-0.2.0.xml"), + Arrays.asList("authorization-role-0.2.0.xml", "organization-type-0.2.0.xml"), + Arrays.asList("authorization-role-0.2.0.xml", "organization-type-0.2.0.xml")); - private ResourceValidator resourceValidator; - private SnapshotGenerator snapshotGenerator; - private ValueSetExpander valueSetExpander; - - @Before - public void before() throws Exception - { - context = FhirContext.forR4(); - validationSupport = new DefaultProfileValidationSupportWithCustomResources(); - - resourceValidator = new ResourceValidatorImpl(context, validationSupport); - snapshotGenerator = new SnapshotGeneratorImpl(context, validationSupport); - valueSetExpander = new ValueSetExpanderImpl(context, validationSupport); - } - - @Test - public void testValueSetExpander() throws Exception - { - readCodeSystems(); - - ValueSet valueSet = new ValueSet(); - valueSet.setUrl("http://highmed.org/fhir/ValueSet/highmed-organization"); - valueSet.setStatus(PublicationStatus.ACTIVE); - valueSet.getCompose().addInclude().setSystem("http://highmed.org/fhir/CodeSystem/highmed-organization"); - - ValueSetExpansionOutcome expanded = valueSetExpander.expand(valueSet); - - assertNotNull(expanded); - - assertNull(expanded.getError()); - assertNull(expanded.getErrorClass()); - assertEquals(1, expanded.getValueset().getExpansion().getTotal()); - } - - @Test - public void testOrganizationProfileNotValid1() throws Exception - { - readProfilesAndGenerateSnapshots(); - - Organization org = new Organization(); - org.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-organization"); - org.setName("Test Organization"); - - ValidationResult result = resourceValidator.validate(org); - result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" - + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); - - assertEquals(4, - result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())).count()); - } + private ResourceValidator resourceValidator = new ResourceValidatorImpl(validationRule.getFhirContext(), + validationRule.getValidationSupport()); @Test - public void testOrganizationProfileNotValid2() throws Exception - { - readProfilesAndGenerateSnapshots(); - - Organization org = new Organization(); - org.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-organization"); - org.setName("Test Organization"); - org.addIdentifier().setSystem("http://foo.bar/baz").setValue("Test"); - - ValidationResult result = resourceValidator.validate(org); - result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" - + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); - - assertEquals(3, - result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())).count()); - } - - @Test - public void testOrganizationProfileNotValid3() throws Exception - { - readProfilesAndGenerateSnapshots(); - - Organization org = new Organization(); - org.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-organization"); - org.setName("Test Organization"); - org.addIdentifier().setSystem("http://highmed.org/fhir/CodeSystem/highmed-organization").setValue("Test"); - - ValidationResult result = resourceValidator.validate(org); - result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" - + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); - - assertEquals(2, - result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())).count()); - } - - @Test - public void testOrganizationProfileNotValid4() throws Exception + public void testOrganizationProfileValid() throws Exception { - readProfilesAndGenerateSnapshots(); - readCodeSystems(); - - ValueSet valueSet = new ValueSet(); - valueSet.setUrl("http://highmed.org/fhir/ValueSet/highmed-organization"); - valueSet.setStatus(PublicationStatus.ACTIVE); - valueSet.getCompose().addInclude().setSystem("http://highmed.org/fhir/CodeSystem/highmed-organization"); - - ValueSetExpansionOutcome expanded = valueSetExpander.expand(valueSet); - - assertNotNull(expanded); - - validationSupport.addOrReplaceValueSet(expanded.getValueset()); - - assertNull(expanded.getError()); - assertNull(expanded.getErrorClass()); - assertEquals(1, expanded.getValueset().getExpansion().getTotal()); - Organization org = new Organization(); org.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-organization"); - org.setName("Test Organization"); - org.addIdentifier().setSystem("http://highmed.org/fhir/CodeSystem/highmed-organization") - .setValue("NonExisting"); + org.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test"); + org.setActive(true); + org.getTypeFirstRep().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/organization-type") + .setCode("TTP"); + org.addEndpoint().setReference("Endpoint/" + UUID.randomUUID().toString()); + org.addExtension().setUrl("http://highmed.org/fhir/StructureDefinition/certificate-thumbprint") + .setValue(new StringType("A2BF39FF2A7E3D218A32AADE3B2AAA1F")); ValidationResult result = resourceValidator.validate(org); result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); - assertEquals(3, - result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())).count()); - assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.WARNING.equals(m.getSeverity()) - && "ValueSet http://highmed.org/fhir/ValueSet/highmed-organization not found".equals(m.getMessage())) - .count()); + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); } @Test - public void testOrganizationProfileNotValid5() throws Exception + public void testOrganizationProfileNotValid1() throws Exception { - readProfilesAndGenerateSnapshots(); - readCodeSystems(); - - ValueSet valueSet = new ValueSet(); - valueSet.setUrl("http://highmed.org/fhir/ValueSet/highmed-organization"); - valueSet.setStatus(PublicationStatus.ACTIVE); - valueSet.getCompose().addInclude().setSystem("http://highmed.org/fhir/CodeSystem/highmed-organization"); - - ValueSetExpansionOutcome expanded = valueSetExpander.expand(valueSet); - - assertNotNull(expanded); - - validationSupport.addOrReplaceValueSet(expanded.getValueset()); - - assertNull(expanded.getError()); - assertNull(expanded.getErrorClass()); - assertEquals(1, expanded.getValueset().getExpansion().getTotal()); - Organization org = new Organization(); org.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-organization"); - org.setName("Test Organization"); - org.addIdentifier().setSystem("http://highmed.org/fhir/CodeSystem/highmed-organization").setValue("Test"); + org.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test"); + org.setActive(true); + org.getTypeFirstRep().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/organization-type") + .setCode("NON_EXISTING_CODE"); + org.addEndpoint().setReference("Endpoint/" + UUID.randomUUID().toString()); + org.addExtension().setUrl("http://highmed.org/fhir/StructureDefinition/certificate-thumbprint") + .setValue(new StringType("A2BF39FF2A7E3D218A32AADE3B2AAA1F")); ValidationResult result = resourceValidator.validate(org); result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); - assertEquals(2, - result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())).count()); - assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.WARNING.equals(m.getSeverity()) - && "ValueSet http://highmed.org/fhir/ValueSet/highmed-organization not found".equals(m.getMessage())) - .count()); + assertEquals(2, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); } @Test - public void testOrganizationProfileNotValid6() throws Exception + public void testOrganizationProfileNotValid2() throws Exception { - readProfilesAndGenerateSnapshots(); - readCodeSystems(); - - ValueSet valueSet = new ValueSet(); - valueSet.setUrl("http://highmed.org/fhir/ValueSet/highmed-organization"); - valueSet.setStatus(PublicationStatus.ACTIVE); - valueSet.getCompose().addInclude().setSystem("http://highmed.org/fhir/CodeSystem/highmed-organization"); - - ValueSetExpansionOutcome expanded = valueSetExpander.expand(valueSet); - - assertNotNull(expanded); - - validationSupport.addOrReplaceValueSet(expanded.getValueset()); - - assertNull(expanded.getError()); - assertNull(expanded.getErrorClass()); - assertEquals(1, expanded.getValueset().getExpansion().getTotal()); - Organization org = new Organization(); org.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-organization"); - org.setName("Test Organization"); - org.addIdentifier().setSystem("http://highmed.org/fhir/CodeSystem/highmed-organization").setValue("Test"); + org.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test"); + org.setActive(true); + org.getTypeFirstRep().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/organization-type"); + org.addEndpoint().setReference("Endpoint/" + UUID.randomUUID().toString()); org.addExtension().setUrl("http://highmed.org/fhir/StructureDefinition/certificate-thumbprint") .setValue(new StringType("A2BF39FF2A7E3D218A32AADE3B2AAA1F")); @@ -235,82 +89,26 @@ public void testOrganizationProfileNotValid6() throws Exception result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); - assertEquals(1, - result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())).count()); - assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.WARNING.equals(m.getSeverity()) - && "ValueSet http://highmed.org/fhir/ValueSet/highmed-organization not found".equals(m.getMessage())) - .count()); + assertEquals(1, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); } @Test - public void testOrganizationProfileValid() throws Exception + public void testOrganizationProfileNotValid3() throws Exception { - readProfilesAndGenerateSnapshots(); - readCodeSystems(); - - ValueSet valueSet = new ValueSet(); - valueSet.setUrl("http://highmed.org/fhir/ValueSet/highmed-organization"); - valueSet.setStatus(PublicationStatus.ACTIVE); - valueSet.getCompose().addInclude().setSystem("http://highmed.org/fhir/CodeSystem/highmed-organization"); - - ValueSetExpansionOutcome expanded = valueSetExpander.expand(valueSet); - - assertNotNull(expanded); - - validationSupport.addOrReplaceValueSet(expanded.getValueset()); - - assertNull(expanded.getError()); - assertNull(expanded.getErrorClass()); - assertEquals(1, expanded.getValueset().getExpansion().getTotal()); - - // Endpoint ept = new Endpoint(); - // ept.setIdElement(new IdType("Endpoint", UUID.randomUUID().toString())); - // ept.getMeta().setVersionId("1"); - // ept.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-endpoint"); - Organization org = new Organization(); org.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-organization"); - org.setName("Test Organization"); - org.addIdentifier().setSystem("http://highmed.org/fhir/CodeSystem/highmed-organization").setValue("Test"); + org.addIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test"); + org.setActive(true); + org.addEndpoint().setReference("Endpoint/" + UUID.randomUUID().toString()); org.addExtension().setUrl("http://highmed.org/fhir/StructureDefinition/certificate-thumbprint") .setValue(new StringType("A2BF39FF2A7E3D218A32AADE3B2AAA1F")); - // org.addEndpoint().setReference(ept.getIdElement().getValue()).setResource(ept); - org.addEndpoint().setReference("Endpoint/" + UUID.randomUUID().toString()); ValidationResult result = resourceValidator.validate(org); result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); - assertEquals(0, - result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())).count()); - } - - private void readProfilesAndGenerateSnapshots() - { - StructureDefinitionReader reader = new StructureDefinitionReader(context); - List<StructureDefinition> diffs = reader.readXml( - Paths.get("src/test/resources/profiles", "highmed-extension-certificate-thumbprint-0.5.0.xml"), - Paths.get("src/test/resources/profiles", "highmed-organization-0.5.0.xml"), - Paths.get("src/test/resources/profiles", "highmed-endpoint-0.5.0.xml")); - - for (StructureDefinition diff : diffs) - { - SnapshotWithValidationMessages snapshotWithValidationMessages = snapshotGenerator.generateSnapshot(diff); - - if (snapshotWithValidationMessages.getSnapshot() != null) - validationSupport.addOrReplaceStructureDefinition(snapshotWithValidationMessages.getSnapshot()); - } - } - - private void readCodeSystems() - { - CodeSystem highmedOrganization = new CodeSystem(); - highmedOrganization.setStatus(PublicationStatus.ACTIVE); - highmedOrganization.setContent(CodeSystemContentMode.COMPLETE); - highmedOrganization.setUrl("http://highmed.org/fhir/CodeSystem/highmed-organization"); - highmedOrganization.setVersion("0.5.0"); - highmedOrganization.addConcept().setCode("Test"); - - validationSupport.addOrReplaceCodeSystem(highmedOrganization); + assertEquals(2, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/ProfileTests.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/ProfileTests.java deleted file mode 100755 index cfd809ecd..000000000 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/ProfileTests.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.highmed.dsf.fhir.profiles; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; - -@RunWith(Suite.class) -@SuiteClasses({ OrganizationProfileTest.class, TaskProfileTest.class }) -public class ProfileTests -{ -} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/ResearchStudyProfileTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/ResearchStudyProfileTest.java new file mode 100644 index 000000000..7f1b774a5 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/ResearchStudyProfileTest.java @@ -0,0 +1,64 @@ +package org.highmed.dsf.fhir.profiles; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.UUID; + +import org.highmed.dsf.fhir.service.ResourceValidator; +import org.highmed.dsf.fhir.service.ResourceValidatorImpl; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.ResearchStudy; +import org.hl7.fhir.r4.model.ResearchStudy.ResearchStudyStatus; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.validation.ResultSeverityEnum; +import ca.uhn.fhir.validation.ValidationResult; + +public class ResearchStudyProfileTest +{ + private static final Logger logger = LoggerFactory.getLogger(OrganizationProfileTest.class); + + @ClassRule + public static final ValidationSupportRule validationRule = new ValidationSupportRule( + Arrays.asList("highmed-extension-participating-medic-0.2.0.xml", + "highmed-extension-participating-ttp-0.2.0.xml", "highmed-research-study-feasibility-0.2.0.xml"), + Arrays.asList("authorization-role-0.2.0.xml", "organization-type-0.2.0.xml"), + Arrays.asList("authorization-role-0.2.0.xml", "organization-type-0.2.0.xml")); + + private ResourceValidator resourceValidator = new ResourceValidatorImpl(validationRule.getFhirContext(), + validationRule.getValidationSupport()); + + @Test + public void testResearchStudyProfileValid() throws Exception + { + ResearchStudy res = new ResearchStudy(); + res.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-research-study-feasibility"); + res.getIdentifierFirstRep().setSystem("http://highmed.org/fhir/NamingSystem/research-study-identifier") + .setValue(UUID.randomUUID().toString()); + res.setStatus(ResearchStudyStatus.ACTIVE); + res.addEnrollment().setReference("Group/" + UUID.randomUUID().toString()); + Reference medicRef1 = new Reference().setType("Organization"); + medicRef1.getIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("MeDIC 1"); + res.addExtension("http://highmed.org/fhir/StructureDefinition/participating-medic", medicRef1); + Reference medicRef2 = new Reference().setType("Organization"); + medicRef2.getIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("MeDIC 2"); + res.addExtension("http://highmed.org/fhir/StructureDefinition/participating-medic", medicRef2); + Reference ttpRef = new Reference().setType("Organization"); + ttpRef.getIdentifier().setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier") + .setValue("TTP"); + res.addExtension("http://highmed.org/fhir/StructureDefinition/participating-ttp", ttpRef); + + ValidationResult result = resourceValidator.validate(res); + result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" + + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/TaskProfileTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/TaskProfileTest.java index d86bd7063..5cfce5520 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/TaskProfileTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/TaskProfileTest.java @@ -1,37 +1,41 @@ package org.highmed.dsf.fhir.profiles; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import java.nio.charset.StandardCharsets; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; import java.util.Date; -import java.util.List; import java.util.UUID; -import org.highmed.dsf.fhir.service.DefaultProfileValidationSupportWithCustomResources; import org.highmed.dsf.fhir.service.ResourceValidator; import org.highmed.dsf.fhir.service.ResourceValidatorImpl; -import org.highmed.dsf.fhir.service.SnapshotGenerator; import org.highmed.dsf.fhir.service.SnapshotGenerator.SnapshotWithValidationMessages; import org.highmed.dsf.fhir.service.SnapshotGeneratorImpl; import org.highmed.dsf.fhir.service.StructureDefinitionReader; -import org.highmed.dsf.fhir.service.ValueSetExpander; -import org.highmed.dsf.fhir.service.ValueSetExpanderImpl; -import org.hl7.fhir.r4.model.CodeSystem; -import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode; -import org.hl7.fhir.r4.model.Enumerations.PublicationStatus; +import org.highmed.dsf.fhir.service.ValidationSupportWithCustomResources; +import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; +import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; +import org.hl7.fhir.r4.model.Base64BinaryType; +import org.hl7.fhir.r4.model.BooleanType; +import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.StructureDefinition; import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.ParameterComponent; import org.hl7.fhir.r4.model.Task.TaskIntent; +import org.hl7.fhir.r4.model.Task.TaskOutputComponent; import org.hl7.fhir.r4.model.Task.TaskStatus; -import org.hl7.fhir.r4.model.ValueSet; -import org.junit.Before; +import org.hl7.fhir.r4.model.UnsignedIntType; +import org.junit.ClassRule; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.DefaultProfileValidationSupport; import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.ValidationResult; @@ -39,100 +43,661 @@ public class TaskProfileTest { private static final Logger logger = LoggerFactory.getLogger(OrganizationProfileTest.class); - private FhirContext context; - private DefaultProfileValidationSupportWithCustomResources validationSupport; + @ClassRule + public static final ValidationSupportRule validationRule = new ValidationSupportRule( + Arrays.asList("highmed-task-base-0.2.0.xml", "highmed-task-start-ping-process-0.2.0.xml", + "highmed-task-ping-0.2.0.xml", "highmed-task-pong-0.2.0.xml", + "highmed-task-update-whitelist-0.2.0.xml", "highmed-task-request-update-resources-0.2.0.xml", + "highmed-task-execute-update-resources-0.2.0.xml", "highmed-group-0.2.0.xml", + "highmed-extension-group-id-0.2.0.xml", "highmed-research-study-feasibility-0.2.0.xml", + "highmed-task-request-simple-feasibility-0.2.0.xml", + "highmed-task-execute-simple-feasibility-0.2.0.xml", + "highmed-task-single-medic-result-simple-feasibility-0.2.0.xml", + "highmed-task-compute-simple-feasibility-0.2.0.xml", + "highmed-task-multi-medic-result-simple-feasibility-0.2.0.xml"), + Arrays.asList("authorization-role-0.2.0.xml", "bpmn-message-0.2.0.xml", "update-whitelist-0.2.0.xml", + "update-resources-0.2.0.xml", "feasibility-0.2.0.xml"), + Arrays.asList("authorization-role-0.2.0.xml", "bpmn-message-0.2.0.xml", "update-whitelist-0.2.0.xml", + "update-resources-0.2.0.xml", "feasibility-0.2.0.xml")); - private ResourceValidator resourceValidator; - private SnapshotGenerator snapshotGenerator; - private ValueSetExpander valueSetExpander; + private ResourceValidator resourceValidator = new ResourceValidatorImpl(validationRule.getFhirContext(), + validationRule.getValidationSupport()); - @Before - public void before() throws Exception + @Test + public void testGenerateSnapshotNotWorkingWithoutBaseSnapshot() throws Exception + { + var reader = new StructureDefinitionReader(validationRule.getFhirContext()); + + StructureDefinition base = reader + .readXml(Paths.get("src/main/resources/fhir/StructureDefinition/highmed-task-base-0.2.0.xml")); + StructureDefinition differential = reader.readXml(Paths + .get("src/main/resources/fhir/StructureDefinition/highmed-task-execute-update-resources-0.2.0.xml")); + + var validationSupport = new ValidationSupportChain( + new InMemoryTerminologyServerValidationSupport(validationRule.getFhirContext()), + new ValidationSupportWithCustomResources(validationRule.getFhirContext(), Arrays.asList(base), + Collections.emptyList(), Collections.emptyList()), + new DefaultProfileValidationSupport(validationRule.getFhirContext())); + var snapshotGenerator = new SnapshotGeneratorImpl(validationRule.getFhirContext(), validationSupport); + + SnapshotWithValidationMessages messages = snapshotGenerator.generateSnapshot(differential); + assertFalse(messages.getMessages().isEmpty()); + } + + @Test + public void testTaskStartProcessProfileValid() throws Exception { - context = FhirContext.forR4(); - validationSupport = new DefaultProfileValidationSupportWithCustomResources(); + Task task = createValidTaskStartProcess(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + @Test + public void testTaskStartProcessProfileNotValid1() throws Exception + { + Task task = createValidTaskStartProcess(); + task.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.1.0"); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(1, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + @Test + public void testTaskStartProcessProfileNotValid2() throws Exception + { + Task task = createValidTaskStartProcess(); + task.setIntent(TaskIntent.FILLERORDER); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(1, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + @Test + public void testTaskStartProcessProfileNotValid3() throws Exception + { + Task task = createValidTaskStartProcess(); + task.setAuthoredOn(null); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); - resourceValidator = new ResourceValidatorImpl(context, validationSupport); - snapshotGenerator = new SnapshotGeneratorImpl(context, validationSupport); - valueSetExpander = new ValueSetExpanderImpl(context, validationSupport); + assertEquals(1, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); } - private void readProfilesAndGenerateSnapshots() + private Task createValidTaskStartProcess() { - StructureDefinitionReader reader = new StructureDefinitionReader(context); - List<StructureDefinition> diffs = reader.readXml( - Paths.get("src/test/resources/profiles", "highmed-extension-certificate-thumbprint-0.5.0.xml"), - Paths.get("src/test/resources/profiles", "highmed-organization-0.5.0.xml"), - Paths.get("src/test/resources/profiles", "highmed-endpoint-0.5.0.xml"), - Paths.get("src/test/resources/profiles", "highmed-task-0.5.0.xml")); + Task task = new Task(); + task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-start-ping-process"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); - for (StructureDefinition diff : diffs) - { - SnapshotWithValidationMessages snapshotWithValidationMessages = snapshotGenerator.generateSnapshot(diff); + task.addInput().setValue(new StringType("startPingProcessMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); - if (snapshotWithValidationMessages.getSnapshot() != null) - validationSupport.addOrReplaceStructureDefinition(snapshotWithValidationMessages.getSnapshot()); - } + return task; } - private void readCodeSystems() + @Test + public void testTaskPingValid() throws Exception { - CodeSystem bpmnMessage = new CodeSystem(); - bpmnMessage.setStatus(PublicationStatus.ACTIVE); - bpmnMessage.setContent(CodeSystemContentMode.COMPLETE); - bpmnMessage.setUrl("http://highmed.org/fhir/CodeSystem/bpmn-message"); - bpmnMessage.setVersion("0.5.0"); - bpmnMessage.addConcept().setCode("message-name"); - bpmnMessage.addConcept().setCode("business-key"); - bpmnMessage.addConcept().setCode("correlation-key"); + Task task = createValidTaskPing(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } - validationSupport.addOrReplaceCodeSystem(bpmnMessage); + private Task createValidTaskPing() + { + Task task = new Task(); + task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-ping"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/pong/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); - ValueSet valueSet = new ValueSet(); - valueSet.setUrl("http://highmed.org/fhir/ValueSet/bpmn-message"); - valueSet.setStatus(PublicationStatus.ACTIVE); - valueSet.getCompose().addInclude().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message"); + task.addInput().setValue(new StringType("pingMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("business-key"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("correlation-key"); - validationSupport.addOrReplaceValueSet(valueSetExpander.expand(valueSet).getValueset()); + return task; } @Test - public void testTaskProfileValid() throws Exception + public void testTaskPongValid() throws Exception { - readProfilesAndGenerateSnapshots(); - readCodeSystems(); + Task task = createValidTaskPong(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + private Task createValidTaskPong() + { Task task = new Task(); - task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task"); - task.setInstantiatesUri("http://highmed.org/bpe/Process/executeUpdateResources/1.0.0"); + task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-pong"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/ping/0.2.0"); task.setStatus(TaskStatus.REQUESTED); task.setIntent(TaskIntent.ORDER); task.setAuthoredOn(new Date()); - task.getRequester().setReference("Organization/" + UUID.randomUUID().toString()); - task.getRestriction().getRecipientFirstRep().setReference("Organization/" + UUID.randomUUID().toString()); - var messageName = task.addInput(); - messageName.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") - .setCode("message-name"); - messageName.setValue(new StringType("foo")); - var businessKey = task.addInput(); - businessKey.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") - .setCode("business-key"); - businessKey.setValue(new StringType(UUID.randomUUID().toString())); - var correlationKey = task.addInput(); - correlationKey.getType().getCodingFirstRep().setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message") - .setCode("correlation-key"); - correlationKey.setValue(new StringType(UUID.randomUUID().toString())); - task.addExtension().setUrl("http://hl7.org/fhir/StructureDefinition/workflow-researchStudy") - .setValue(new Reference("https://medic1/fhir/ResearchStudy/" + UUID.randomUUID().toString())); - - logger.debug("Task: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(task)); - - ValidationResult result = resourceValidator.validate(task); - - result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" - + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); - - assertEquals(0, - result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())).count()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + + task.addInput().setValue(new StringType("pongMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("business-key"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("correlation-key"); + + return task; + } + + @Test + public void testTaskUpdateWhitelistValid() throws Exception + { + Task task = createValidTaskUpdateWhitelist(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + @Test + public void testTaskUpdateWhitelistValidWithOutput() throws Exception + { + Task task = createValidTaskUpdateWhitelist(); + task.addOutput().setValue(new Reference(new IdType("Bundle", UUID.randomUUID().toString(), "1"))).getType() + .addCoding().setSystem("http://highmed.org/fhir/CodeSystem/update-whitelist") + .setCode("highmed_whitelist"); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + private Task createValidTaskUpdateWhitelist() + { + Task task = new Task(); + task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-update-whitelist"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/updateWhitelist/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + + task.addInput().setValue(new StringType("updateWhitelistMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + + return task; + } + + @Test + public void testTaskRequestUpdateResourcesWhitelistValid() throws Exception + { + Task task = createValidTaskRequestUpdateWhitelistResources(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + private Task createValidTaskRequestUpdateWhitelistResources() + { + Task task = new Task(); + task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-update-whitelist"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/updateWhitelist/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + + task.addInput().setValue(new StringType("updateWhitelistMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + + return task; + } + + @Test + public void testTaskRequestUpdateResourcesValid() throws Exception + { + Task task = createValidTaskRequestUpdateResources(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + private Task createValidTaskRequestUpdateResources() + { + Task task = new Task(); + task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-request-update-resources"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/requestUpdateResources/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); + + task.addInput().setValue(new StringType("requestUpdateResourcesMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + task.addInput().setValue(new Reference("Bundle/" + UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/update-resources").setCode("bundle-reference"); + task.addInput().setValue(new StringType("http://highmed.org/fhir/NamingSystem/organization-identifier|")) + .getType().addCoding().setSystem("http://highmed.org/fhir/CodeSystem/update-resources") + .setCode("organization-identifier-search-parameter"); + + return task; + } + + @Test + public void testTaskExecuteUpdateResourcesValid() throws Exception + { + Task task = createValidTaskExecuteUpdateResources(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + private Task createValidTaskExecuteUpdateResources() + { + Task task = new Task(); + task.getMeta().addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-execute-update-resources"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/executeUpdateResources/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); + + task.addInput().setValue(new StringType("executeUpdateResourcesMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("business-key"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("correlation-key"); + task.addInput().setValue(new Reference("Bundle/" + UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/update-resources").setCode("bundle-reference"); + + return task; + } + + @Test + public void testTaskRequestSimpleFeasibilityValid() throws Exception + { + Task task = createValidTaskRequestSimpleFeasibility(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + @Test + public void testTaskRequestSimpleFeasibilityValidWithOutput() throws Exception + { + String groupId1 = "Group/" + UUID.randomUUID().toString(); + String groupId2 = "Group/" + UUID.randomUUID().toString(); + + Task task = createValidTaskRequestSimpleFeasibility(); + + TaskOutputComponent outParticipatingMedics1 = task.addOutput(); + outParticipatingMedics1.setValue(new UnsignedIntType(5)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("participating-medics"); + outParticipatingMedics1.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId1)); + TaskOutputComponent outMultiMedicResult1 = task.addOutput(); + outMultiMedicResult1.setValue(new UnsignedIntType(25)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("multi-medic-result"); + outMultiMedicResult1.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId1)); + + TaskOutputComponent outParticipatingMedics2 = task.addOutput(); + outParticipatingMedics2.setValue(new UnsignedIntType(5)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("participating-medics"); + outParticipatingMedics2.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId2)); + TaskOutputComponent outMultiMedicResult2 = task.addOutput(); + outMultiMedicResult2.setValue(new UnsignedIntType(25)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("multi-medic-result"); + outMultiMedicResult2.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId2)); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + private Task createValidTaskRequestSimpleFeasibility() + { + Task task = new Task(); + task.getMeta() + .addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-request-simple-feasibility"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/requestSimpleFeasibility/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); + + task.addInput().setValue(new StringType("requestSimpleFeasibilityMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + task.addInput().setValue(new Reference("ResearchStudy/" + UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("research-study-reference"); + task.addInput().setValue(new BooleanType(false)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("needs-record-linkage"); + task.addInput().setValue(new BooleanType(false)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("needs-consent-check"); + + return task; + } + + @Test + public void testTaskExecuteSimpleFeasibilityValid() throws Exception + { + Task task = createValidTaskExecuteSimpleFeasibility(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + @Test + public void testTaskExecuteSimpleFeasibilityValidWithBloomFilterConfig() throws Exception + { + Task task = createValidTaskExecuteSimpleFeasibility(); + task.addInput().setValue(new Base64BinaryType("TEST".getBytes(StandardCharsets.UTF_8))).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("bloom-filter-configuration"); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + private Task createValidTaskExecuteSimpleFeasibility() + { + Task task = new Task(); + task.getMeta() + .addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-execute-simple-feasibility"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/executeSimpleFeasibility/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_2"); + + task.addInput().setValue(new StringType("executeSimpleFeasibilityMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("business-key"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("correlation-key"); + + task.addInput().setValue(new Reference("ResearchStudy/" + UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("research-study-reference"); + task.addInput().setValue(new BooleanType(false)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("needs-record-linkage"); + task.addInput().setValue(new BooleanType(false)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("needs-consent-check"); + + return task; + } + + @Test + public void testTaskSingleMedicResultSimpleFeasibilityUnsignedIntResultValid() throws Exception + { + Task task = createValidTaskSingleMedicResultSimpleFeasibilityUnsignedIntResult(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + @Test + public void testTaskSingleMedicResultSimpleFeasibilityReferenceResultValid() throws Exception + { + Task task = createValidTaskSingleMedicResultSimpleFeasibilityReferenceResult(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + private Task createValidTaskSingleMedicResultSimpleFeasibility() + { + Task task = new Task(); + task.getMeta().addProfile( + "http://highmed.org/fhir/StructureDefinition/highmed-task-single-medic-result-simple-feasibility"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/computeSimpleFeasibility/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_2"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + + task.addInput().setValue(new StringType("resultSingleMedicSimpleFeasibilityMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("business-key"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("correlation-key"); + + return task; + } + + private Task createValidTaskSingleMedicResultSimpleFeasibilityUnsignedIntResult() + { + Task task = createValidTaskSingleMedicResultSimpleFeasibility(); + + String groupId1 = "Group/" + UUID.randomUUID().toString(); + String groupId2 = "Group/" + UUID.randomUUID().toString(); + + ParameterComponent inSingleMedicResult1 = task.addInput(); + inSingleMedicResult1.setValue(new UnsignedIntType(5)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("single-medic-result"); + inSingleMedicResult1.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId1)); + ParameterComponent inSingleMedicResult2 = task.addInput(); + inSingleMedicResult2.setValue(new UnsignedIntType(10)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("single-medic-result"); + inSingleMedicResult2.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId2)); + + return task; + } + + private Task createValidTaskSingleMedicResultSimpleFeasibilityReferenceResult() + { + Task task = createValidTaskSingleMedicResultSimpleFeasibility(); + + String groupId1 = "Group/" + UUID.randomUUID().toString(); + String groupId2 = "Group/" + UUID.randomUUID().toString(); + + ParameterComponent inSingleMedicResult1 = task.addInput(); + inSingleMedicResult1.setValue(new Reference("Binary/" + UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("single-medic-result-reference"); + inSingleMedicResult1.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId1)); + ParameterComponent inSingleMedicResult2 = task.addInput(); + inSingleMedicResult2.setValue(new Reference("Binary/" + UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("single-medic-result-reference"); + inSingleMedicResult2.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId2)); + + return task; + } + + @Test + public void testTaskComputeSimpleFeasibilityValid() throws Exception + { + Task task = createValidTaskComputeSimpleFeasibility(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + private Task createValidTaskComputeSimpleFeasibility() + { + Task task = new Task(); + task.getMeta() + .addProfile("http://highmed.org/fhir/StructureDefinition/highmed-task-compute-simple-feasibility"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/computeSimpleFeasibility/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + + task.addInput().setValue(new StringType("computeSimpleFeasibilityMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("business-key"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("correlation-key"); + + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("medic-correlation-key"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("medic-correlation-key"); + + task.addInput().setValue(new BooleanType(false)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("needs-record-linkage"); + + return task; + } + + @Test + public void testTaskMultiMedicResultSimpleFeasibilityValid() throws Exception + { + Task task = createValidTaskMultiMedicResultSimpleFeasibility(); + + ValidationResult result = resourceValidator.validate(task); + ValidationSupportRule.logValidationMessages(logger, result); + + assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity()) + || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count()); + } + + private Task createValidTaskMultiMedicResultSimpleFeasibility() + { + Task task = new Task(); + task.getMeta().addProfile( + "http://highmed.org/fhir/StructureDefinition/highmed-task-multi-medic-result-simple-feasibility"); + task.setInstantiatesUri("http://highmed.org/bpe/Process/requestSimpleFeasibility/0.2.0"); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.getRequester().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_TTP"); + task.getRestriction().addRecipient().setType("Organization").getIdentifier() + .setSystem("http://highmed.org/fhir/NamingSystem/organization-identifier").setValue("Test_MeDIC_1"); + + task.addInput().setValue(new StringType("resultMultiMedicSimpleFeasibilityMessage")).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("message-name"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("business-key"); + task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/bpmn-message").setCode("correlation-key"); + + String groupId1 = "Group/" + UUID.randomUUID().toString(); + String groupId2 = "Group/" + UUID.randomUUID().toString(); + + ParameterComponent inParticipatingMedics1 = task.addInput(); + inParticipatingMedics1.setValue(new UnsignedIntType(5)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("participating-medics"); + inParticipatingMedics1.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId1)); + ParameterComponent inMultiMedicResult1 = task.addInput(); + inMultiMedicResult1.setValue(new UnsignedIntType(25)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("multi-medic-result"); + inMultiMedicResult1.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId1)); + + ParameterComponent inParticipatingMedics2 = task.addInput(); + inParticipatingMedics2.setValue(new UnsignedIntType(5)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("participating-medics"); + inParticipatingMedics2.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId2)); + ParameterComponent inMultiMedicResult2 = task.addInput(); + inMultiMedicResult2.setValue(new UnsignedIntType(25)).getType().addCoding() + .setSystem("http://highmed.org/fhir/CodeSystem/feasibility").setCode("multi-medic-result"); + inMultiMedicResult2.addExtension("http://highmed.org/fhir/StructureDefinition/group-id", + new Reference(groupId2)); + + return task; } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/ValidationSupportRule.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/ValidationSupportRule.java new file mode 100644 index 000000000..00fe869b0 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/profiles/ValidationSupportRule.java @@ -0,0 +1,150 @@ +package org.highmed.dsf.fhir.profiles; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Locale; +import java.util.stream.Stream; + +import org.highmed.dsf.fhir.service.ValidationSupportWithCustomResources; +import org.highmed.dsf.fhir.service.SnapshotGenerator; +import org.highmed.dsf.fhir.service.SnapshotGenerator.SnapshotWithValidationMessages; +import org.highmed.dsf.fhir.service.SnapshotGeneratorImpl; +import org.highmed.dsf.fhir.service.StructureDefinitionReader; +import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService; +import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; +import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.ValueSet; +import org.junit.rules.ExternalResource; +import org.slf4j.Logger; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.DefaultProfileValidationSupport; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.i18n.HapiLocalizer; +import ca.uhn.fhir.validation.ValidationResult; + +public class ValidationSupportRule extends ExternalResource +{ + private static final String BASE_FOLDER = "src/main/resources/fhir/"; + private static final String STUCTURE_DEFINITIONS_FOLDER = BASE_FOLDER + "StructureDefinition"; + private static final String CODE_SYSTEMS_FOLDER = BASE_FOLDER + "CodeSystem"; + private static final String VALUE_SETS_FOLDER = BASE_FOLDER + "ValueSet"; + + private final FhirContext context; + private final IValidationSupport validationSupport; + + public ValidationSupportRule(List<String> structureDefinitions, List<String> codeSystems, List<String> valueSets) + { + context = FhirContext.forR4(); + HapiLocalizer localizer = new HapiLocalizer() + { + @Override + public Locale getLocale() + { + return Locale.ROOT; + } + }; + context.setLocalizer(localizer); + + var customValidationSupport = new ValidationSupportWithCustomResources(context); + + validationSupport = new ValidationSupportChain(new InMemoryTerminologyServerValidationSupport(context), + customValidationSupport, new DefaultProfileValidationSupport(context), + new CommonCodeSystemsTerminologyService(context)); + + readProfilesAndGenerateSnapshots(context, customValidationSupport, + new SnapshotGeneratorImpl(context, validationSupport), + toPaths(STUCTURE_DEFINITIONS_FOLDER, structureDefinitions)); + + readCodeSystems(context, customValidationSupport, toPaths(CODE_SYSTEMS_FOLDER, codeSystems)); + readValueSets(context, customValidationSupport, toPaths(VALUE_SETS_FOLDER, valueSets)); + } + + private static Stream<Path> toPaths(String folder, List<String> files) + { + return files.stream().map(file -> Paths.get(folder, file)); + } + + private static void readProfilesAndGenerateSnapshots(FhirContext context, + ValidationSupportWithCustomResources vSupport, SnapshotGenerator snapshotGenerator, + Stream<Path> structureDefinitions) + { + StructureDefinitionReader reader = new StructureDefinitionReader(context); + reader.readXml(structureDefinitions).forEach(diff -> + { + SnapshotWithValidationMessages snapshotWithValidationMessages = snapshotGenerator.generateSnapshot(diff); + assertTrue(snapshotWithValidationMessages.getMessages().isEmpty()); + assertNotNull(snapshotWithValidationMessages.getSnapshot()); + + vSupport.addOrReplace(snapshotWithValidationMessages.getSnapshot()); + }); + } + + private static void readCodeSystems(FhirContext context, ValidationSupportWithCustomResources vSupport, + Stream<Path> codeSystems) + { + codeSystems.forEach(path -> + { + var cS = readCodeSystem(context, path); + vSupport.addOrReplace(cS); + }); + } + + private static CodeSystem readCodeSystem(FhirContext context, Path path) + { + try (InputStream in = Files.newInputStream(path)) + { + return context.newXmlParser().parseResource(CodeSystem.class, in); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + private static void readValueSets(FhirContext context, ValidationSupportWithCustomResources vSupport, + Stream<Path> valueSets) + { + valueSets.forEach(p -> + { + var vS = readValueSet(context, p); + vSupport.addOrReplace(vS); + }); + } + + private static ValueSet readValueSet(FhirContext context, Path path) + { + try (InputStream in = Files.newInputStream(path)) + { + return context.newXmlParser().parseResource(ValueSet.class, in); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + public FhirContext getFhirContext() + { + return context; + } + + public IValidationSupport getValidationSupport() + { + return validationSupport; + } + + public static void logValidationMessages(Logger logger, ValidationResult result) + { + result.getMessages().stream().map(m -> m.getLocationString() + " " + m.getLocationLine() + ":" + + m.getLocationCol() + " - " + m.getSeverity() + ": " + m.getMessage()).forEach(logger::info); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/service/SnapshotDependencyAnalyzerTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/service/SnapshotDependencyAnalyzerTest.java deleted file mode 100755 index f9bf970de..000000000 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/service/SnapshotDependencyAnalyzerTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.highmed.dsf.fhir.service; - -import static org.junit.Assert.*; - -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.hl7.fhir.r4.model.StructureDefinition; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import ca.uhn.fhir.context.FhirContext; - -public class SnapshotDependencyAnalyzerTest -{ - private static final Logger logger = LoggerFactory.getLogger(SnapshotDependencyAnalyzerTest.class); - - @Test - public void testAnalyze() throws Exception - { - FhirContext context = FhirContext.forR4(); - - StructureDefinition patientDeBasis; - try (InputStream in = Files - .newInputStream(Paths.get("src/test/resources/profiles/DeBasis/patient-de-basis-0.2.1.xml"))) - { - patientDeBasis = context.newXmlParser().parseResource(StructureDefinition.class, in); - } - SnapshotGenerator generator = new SnapshotGeneratorImpl(context, - new DefaultProfileValidationSupportWithCustomResources()); - patientDeBasis = generator.generateSnapshot(patientDeBasis).getSnapshot(); - - SnapshotDependencyAnalyzer analyzer = new SnapshotDependencyAnalyzer(); - SnapshotDependencies dependencies = analyzer.analyzeSnapshotDependencies(patientDeBasis); - - assertNotNull(dependencies); - logger.debug("Profiles: {}", dependencies.getProfiles()); - logger.debug("TargetProfiles: {}", dependencies.getTargetProfiles()); - - assertEquals(2, dependencies.getProfiles().size()); - assertEquals(sorted(Arrays.asList("http://fhir.de/StructureDefinition/address-de-basis", - "http://fhir.de/StructureDefinition/humanname-de-basis")), sorted(dependencies.getProfiles())); - assertEquals( - sorted(Arrays.asList("http://fhir.de/StructureDefinition/organization-de-basis", - "http://fhir.de/StructureDefinition/practitioner-de-basis", - "http://hl7.org/fhir/StructureDefinition/Organization", - "http://hl7.org/fhir/StructureDefinition/Patient", - "http://hl7.org/fhir/StructureDefinition/RelatedPerson")), - sorted(dependencies.getTargetProfiles())); - } - - private List<String> sorted(List<String> list) - { - list = new ArrayList<>(list); - list.sort(String::compareTo); - return list; - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/service/SnapshotInfoJsonTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/service/SnapshotInfoJsonTest.java deleted file mode 100755 index ae661c3ba..000000000 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/service/SnapshotInfoJsonTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.highmed.dsf.fhir.service; - -import static org.junit.Assert.*; - -import java.util.Arrays; - -import org.highmed.dsf.fhir.spring.config.JsonConfig; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - -public class SnapshotInfoJsonTest -{ - private static final Logger logger = LoggerFactory.getLogger(SnapshotInfoJsonTest.class); - - @Test - public void testWriteRead() throws Exception - { - final String profile0 = "profile0"; - final String profile1 = "profile1"; - final String targetProfile0 = "targetProfile0"; - final String targetProfile1 = "targetProfile1"; - - SnapshotDependencies dependencies = new SnapshotDependencies(Arrays.asList(profile0, profile1), - Arrays.asList(targetProfile0, targetProfile1)); - SnapshotInfo info = new SnapshotInfo(dependencies); - - ObjectMapper objectMapper = new JsonConfig().objectMapper(); - String infoString = objectMapper.writer().writeValueAsString(info); - assertNotNull(infoString); - - logger.info(infoString); - - SnapshotInfo readInfo = objectMapper.reader().forType(SnapshotInfo.class).readValue(infoString); - - assertNotNull(readInfo); - assertNotNull(readInfo.getDependencies()); - assertNotNull(readInfo.getDependencies().getProfiles()); - assertEquals(2, readInfo.getDependencies().getProfiles().size()); - assertEquals(profile0, readInfo.getDependencies().getProfiles().get(0)); - assertEquals(profile1, readInfo.getDependencies().getProfiles().get(1)); - assertNotNull(readInfo.getDependencies().getTargetProfiles()); - assertEquals(2, readInfo.getDependencies().getTargetProfiles().size()); - assertEquals(targetProfile0, readInfo.getDependencies().getTargetProfiles().get(0)); - assertEquals(targetProfile1, readInfo.getDependencies().getTargetProfiles().get(1)); - } -} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/service/ValueSetExpanderTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/service/ValueSetExpanderTest.java index 9853a5860..2ba6debfa 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/service/ValueSetExpanderTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/service/ValueSetExpanderTest.java @@ -1,52 +1,107 @@ package org.highmed.dsf.fhir.service; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; +import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome; +import org.junit.Before; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.DefaultProfileValidationSupport; +import ca.uhn.fhir.i18n.HapiLocalizer; public class ValueSetExpanderTest { - private static final Logger logger = LoggerFactory.getLogger(ValueSetExpanderTest.class); + private static final String CODE_SYSTEM_FOLDER = "src/main/resources/fhir/CodeSystem"; + private static final String VALUE_SET_FOLDER = "src/main/resources/fhir/ValueSet"; - @Test - public void testExpand() throws Exception + private FhirContext fhirContext; + private ValueSetExpander valueSetExpander; + + @Before + public void before() throws Exception { - FhirContext context = FhirContext.forR4(); - var validationSupport = new DefaultProfileValidationSupportWithCustomResources(); + fhirContext = FhirContext.forR4(); + fhirContext.setLocalizer(new HapiLocalizer() + { + @Override + public Locale getLocale() + { + return Locale.ROOT; + } + }); - CodeSystem cS = new CodeSystem(); - cS.setUrl("http://test/fhir/CodeSystem/foo"); - cS.setVersion("2.0.0"); - cS.addConcept().setCode("Test1"); - cS.addConcept().setCode("Test2"); - cS.addConcept().setCode("Test3"); - cS.addConcept().setCode("Test4"); + var validationSupport = new ValidationSupportChain(new InMemoryTerminologyServerValidationSupport(fhirContext), + new ValidationSupportWithCustomResources(fhirContext, Collections.emptyList(), readCodeSystems(), + Collections.emptyList()), + new DefaultProfileValidationSupport(fhirContext)); - validationSupport.addOrReplaceCodeSystem(cS); + valueSetExpander = new ValueSetExpanderImpl(fhirContext, validationSupport); + } - ValueSetExpander expander = new ValueSetExpanderImpl(context, validationSupport); + private List<CodeSystem> readCodeSystems() + { + return Stream + .of("authorization-role-0.2.0.xml", "bpmn-message-0.2.0.xml", "feasibility-0.2.0.xml", + "organization-type-0.2.0.xml", "query-type-0.2.0.xml", "update-resources-0.2.0.xml", + "update-whitelist-0.2.0.xml") + .map(f -> Paths.get(CODE_SYSTEM_FOLDER, f)).map(this::readCodeSystem).collect(Collectors.toList()); + } - ValueSet vS = new ValueSet(); - vS.setUrl("http://test/fhir/ValueSet/foo"); - vS.getCompose().addInclude().setSystem(cS.getUrl()).setVersion("1.0.0"); + private CodeSystem readCodeSystem(Path file) + { + try (InputStream in = Files.newInputStream(file)) + { + return fhirContext.newXmlParser().parseResource(CodeSystem.class, in); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + @Test + public void testExpandFeasibility() throws Exception + { + ValueSetExpansionOutcome out = valueSetExpander + .expand(readValueSet(Paths.get(VALUE_SET_FOLDER, "authorization-role-0.2.0.xml"))); - ValueSetExpansionOutcome expand = expander.expand(vS); + assertNotNull(out); + assertNull(out.getError()); + assertNull(out.getErrorClass()); + assertNotNull(out.getValueset()); - assertNotNull(expand); - assertNull(expand.getError()); - assertNull(expand.getErrorClass()); - assertNotNull(expand.getValueset()); + assertNotNull(out.getValueset().hasExpansion()); + assertEquals(2, out.getValueset().getExpansion().getTotal()); + assertEquals(2, out.getValueset().getExpansion().getContains().size()); + } - logger.debug("CodeSystem: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(cS)); - logger.debug("ValueSet: {}", context.newXmlParser().setPrettyPrint(true).encodeResourceToString(vS)); - logger.debug("Expanded ValueSet: {}", - context.newXmlParser().setPrettyPrint(true).encodeResourceToString(expand.getValueset())); + private ValueSet readValueSet(Path file) + { + try (InputStream in = Files.newInputStream(file)) + { + return fhirContext.newXmlParser().parseResource(ValueSet.class, in); + } + catch (IOException e) + { + throw new RuntimeException(e); + } } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteDbTests.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteDbTests.java index 0738eb905..35913ea93 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteDbTests.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteDbTests.java @@ -7,6 +7,7 @@ import org.highmed.dsf.fhir.dao.EndpointDaoTest; import org.highmed.dsf.fhir.dao.GroupDaoTest; import org.highmed.dsf.fhir.dao.HealthcareServiceDaoTest; +import org.highmed.dsf.fhir.dao.HistoryDaoTest; import org.highmed.dsf.fhir.dao.LocationDaoTest; import org.highmed.dsf.fhir.dao.NamingSystemDaoTest; import org.highmed.dsf.fhir.dao.OrganizationDaoTest; @@ -20,6 +21,7 @@ import org.highmed.dsf.fhir.dao.SubscriptionDaoTest; import org.highmed.dsf.fhir.dao.TaskDaoTest; import org.highmed.dsf.fhir.dao.ValueSetDaoTest; +import org.highmed.dsf.fhir.db.TransactionLearningTest; import org.junit.ClassRule; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -31,7 +33,8 @@ NamingSystemDaoTest.class, OrganizationDaoTest.class, PatientDaoTest.class, PractitionerDaoTest.class, PractitionerRoleDaoTest.class, ProvenanceDaoTest.class, ResearchStudyDaoTest.class, StructureDefinitionDaoTest.class, StructureDefinitionSnapshotDaoTest.class, SubscriptionDaoTest.class, - TaskDaoTest.class, ValueSetDaoTest.class, TestSuiteIntegrationTests.class }) + TaskDaoTest.class, ValueSetDaoTest.class, HistoryDaoTest.class, TestSuiteIntegrationTests.class, + TransactionLearningTest.class }) public class TestSuiteDbTests { @ClassRule diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteHapiLearningAndBugValidationTests.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteHapiLearningAndBugValidationTests.java new file mode 100644 index 000000000..a5c8e763d --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteHapiLearningAndBugValidationTests.java @@ -0,0 +1,34 @@ +package org.highmed.dsf.fhir.test; + +import org.highmed.dsf.fhir.hapi.ActivityDefinitionWithExtension; +import org.highmed.dsf.fhir.hapi.BinaryTest; +import org.highmed.dsf.fhir.hapi.BundleTest; +import org.highmed.dsf.fhir.hapi.CodeSystemTest; +import org.highmed.dsf.fhir.hapi.DefaultProfileValidationSupportTest; +import org.highmed.dsf.fhir.hapi.EndpointTest; +import org.highmed.dsf.fhir.hapi.IdTypeTest; +import org.highmed.dsf.fhir.hapi.MetaTest; +import org.highmed.dsf.fhir.hapi.OrganizationTest; +import org.highmed.dsf.fhir.hapi.ParametersTest; +import org.highmed.dsf.fhir.hapi.ParserTest; +import org.highmed.dsf.fhir.hapi.ReferenceTest; +import org.highmed.dsf.fhir.hapi.ReferenceTypTest; +import org.highmed.dsf.fhir.hapi.ResearchStudyTest; +import org.highmed.dsf.fhir.hapi.SerializationTest; +import org.highmed.dsf.fhir.hapi.StructureDefinitionTreeTest; +import org.highmed.dsf.fhir.hapi.SubscriptionTest; +import org.highmed.dsf.fhir.hapi.TaskTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ ActivityDefinitionWithExtension.class, BinaryTest.class, BundleTest.class, CodeSystemTest.class, + DefaultProfileValidationSupportTest.class, EndpointTest.class, IdTypeTest.class, MetaTest.class, + OrganizationTest.class, ParametersTest.class, ParserTest.class, ReferenceTest.class, ReferenceTypTest.class, + ResearchStudyTest.class, SerializationTest.class, StructureDefinitionTreeTest.class, SubscriptionTest.class, + TaskTest.class }) +public class TestSuiteHapiLearningAndBugValidationTests +{ + +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteIntegrationTests.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteIntegrationTests.java index 76f442007..6edbc5ae5 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteIntegrationTests.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteIntegrationTests.java @@ -1,6 +1,7 @@ package org.highmed.dsf.fhir.test; import org.highmed.dsf.fhir.integration.BinaryIntegrationTest; +import org.highmed.dsf.fhir.integration.BundleIntegrationTest; import org.highmed.dsf.fhir.integration.EndpointIntegrationTest; import org.highmed.dsf.fhir.integration.OrganizationIntegrationTest; import org.highmed.dsf.fhir.integration.TaskIntegrationTest; @@ -10,8 +11,8 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses({ BinaryIntegrationTest.class, EndpointIntegrationTest.class, OrganizationIntegrationTest.class, - TaskIntegrationTest.class }) +@SuiteClasses({ BinaryIntegrationTest.class, BundleIntegrationTest.class, EndpointIntegrationTest.class, + OrganizationIntegrationTest.class, TaskIntegrationTest.class }) public class TestSuiteIntegrationTests { @ClassRule diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteProfileTests.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteProfileTests.java new file mode 100644 index 000000000..a19681dff --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteProfileTests.java @@ -0,0 +1,17 @@ +package org.highmed.dsf.fhir.test; + +import org.highmed.dsf.fhir.profiles.EndpointProfileTest; +import org.highmed.dsf.fhir.profiles.GroupProfileTest; +import org.highmed.dsf.fhir.profiles.OrganizationProfileTest; +import org.highmed.dsf.fhir.profiles.ResearchStudyProfileTest; +import org.highmed.dsf.fhir.profiles.TaskProfileTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ EndpointProfileTest.class, GroupProfileTest.class, OrganizationProfileTest.class, + ResearchStudyProfileTest.class, TaskProfileTest.class }) +public class TestSuiteProfileTests +{ +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteUnitTests.java b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteUnitTests.java index 8cc7566fc..f4a2b27a4 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteUnitTests.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/org/highmed/dsf/fhir/test/TestSuiteUnitTests.java @@ -1,29 +1,15 @@ package org.highmed.dsf.fhir.test; +import org.highmed.dsf.fhir.client.ClientProviderTest; import org.highmed.dsf.fhir.dao.command.ResourceReferenceTest; -import org.highmed.dsf.fhir.hapi.BundleTest; -import org.highmed.dsf.fhir.hapi.CodeSystemTest; -import org.highmed.dsf.fhir.hapi.EndpointTest; -import org.highmed.dsf.fhir.hapi.IdTypeTest; -import org.highmed.dsf.fhir.hapi.OrganizationTest; -import org.highmed.dsf.fhir.hapi.ParametersTest; -import org.highmed.dsf.fhir.hapi.ParserTest; -import org.highmed.dsf.fhir.hapi.ReferenceTypTest; -import org.highmed.dsf.fhir.hapi.SerializationTest; -import org.highmed.dsf.fhir.hapi.SnapshotTest; -import org.highmed.dsf.fhir.hapi.StructureDefinitionTreeTest; -import org.highmed.dsf.fhir.hapi.SubscriptionTest; -import org.highmed.dsf.fhir.hapi.ValidationTest; -import org.highmed.dsf.fhir.profiles.ProfileTests; +import org.highmed.dsf.fhir.service.ValueSetExpanderTest; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses({ ResourceReferenceTest.class, BundleTest.class, CodeSystemTest.class, EndpointTest.class, - IdTypeTest.class, OrganizationTest.class, ParametersTest.class, ParserTest.class, ReferenceTypTest.class, - SerializationTest.class, SnapshotTest.class, StructureDefinitionTreeTest.class, SubscriptionTest.class, - ValidationTest.class, ProfileTests.class }) +@SuiteClasses({ TestSuiteHapiLearningAndBugValidationTests.class, TestSuiteProfileTests.class, ClientProviderTest.class, + ResourceReferenceTest.class, ValueSetExpanderTest.class }) public class TestSuiteUnitTests { } diff --git a/dsf-fhir/dsf-fhir-server/src/test/resources/integration/task-bundle.json b/dsf-fhir/dsf-fhir-server/src/test/resources/integration/task-bundle.json index 834783617..55273d8b7 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/resources/integration/task-bundle.json +++ b/dsf-fhir/dsf-fhir-server/src/test/resources/integration/task-bundle.json @@ -14,7 +14,7 @@ "status": "additional" }, "type": "person", - "actual": true, + "actual": false, "extension": [ { "url": "http://highmed.org/fhir/StructureDefinition/query", @@ -44,7 +44,7 @@ "status": "additional" }, "type": "person", - "actual": true, + "actual": false, "extension": [ { "url": "http://highmed.org/fhir/StructureDefinition/query", @@ -62,121 +62,42 @@ "url": "Group" } }, - { - "fullUrl": "urn:uuid:ae194285-d08e-46c7-a9a7-9a47624dd8xx", - "resource": { - "resourceType": "Practitioner", - "meta": { - "profile": "http://highmed.org/fhir/StructureDefinition/highmed-practitioner" - }, - "active": true, - "name": [ - { - "family": "HiGHmed", - "given": [ - "Test" - ] - } - ], - "telecom": [ - { - "system": "phone", - "value": "+491710001122" - }, - { - "system": "email", - "value": "test-practitioner@highmed.org" - } - ], - "address": [ - { - "line": [ - "Highmedstraße 12" - ], - "city": "Berlin", - "postalCode": "10115", - "country": "DE" - } - ] - }, - "request": { - "method": "POST", - "url": "Practitioner" - } - }, - { - "fullUrl": "urn:uuid:ae194285-d08e-46c7-a9a7-9a47624dd8yy", - "resource": { - "resourceType": "PractitionerRole", - "meta": { - "profile": "http://highmed.org/fhir/StructureDefinition/highmed-practitioner-role" - }, - "active": true, - "practitioner": { - "reference": "urn:uuid:ae194285-d08e-46c7-a9a7-9a47624dd8xx" - }, - "organization": { - "identifier": { - "system": "http://highmed.org/fhir/NamingSystem/organization-identifier", - "value": "Test_Organization" - }, - "type": "Organization" - } - }, - "request": { - "method": "POST", - "url": "PractitionerRole" - } - }, { "fullUrl": "urn:uuid:aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "resource": { "resourceType": "ResearchStudy", "meta": { - "profile": "http://highmed.org/fhir/StructureDefinition/highmed-research-study" - }, - "identifier": [ - { - "value": "c4d3e590-890a-4840-848f-412cf4b7f1fa", - "system": "http://highmed.org/fhir/NamingSystem/research-study-identifier" - } - ], - "title": "Research Study Test", - "status": "active", - "description": "This is a test research study based on the highmed profile. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.", - "enrollment": [ - { - "reference": "urn:uuid:ae194285-d08e-46c7-a9a7-9a47624dd8aa" - }, - { - "reference": "urn:uuid:ae194285-d08e-46c7-a9a7-9a47624dd8bb" - } - ], - "principalInvestigator": { - "reference": "urn:uuid:ae194285-d08e-46c7-a9a7-9a47624dd8xx" + "profile": [ "http://highmed.org/fhir/StructureDefinition/highmed-research-study-feasibility" ] }, - "extension": [ - { - "url": "http://highmed.org/fhir/StructureDefinition/participating-medic", - "valueReference": { - "identifier": { - "system": "http://highmed.org/fhir/NamingSystem/organization-identifier", - "value": "Test_Organization" - }, - "type": "Organization" + "extension": [ { + "url": "http://highmed.org/fhir/StructureDefinition/participating-medic", + "valueReference": { + "type": "Organization", + "identifier": { + "system": "http://highmed.org/fhir/NamingSystem/organization-identifier", + "value": "Test_Organization" } - }, - { - "url": "http://highmed.org/fhir/StructureDefinition/participating-ttp", - "valueReference": { - "identifier": { - "system": "http://highmed.org/fhir/NamingSystem/organization-identifier", - "value": "External_Test_Organization" - }, - "type": "Organization" + } + }, { + "url": "http://highmed.org/fhir/StructureDefinition/participating-ttp", + "valueReference": { + "type": "Organization", + "identifier": { + "system": "http://highmed.org/fhir/NamingSystem/organization-identifier", + "value": "External_Test_Organization" } } - ] + } ], + "identifier": [ { + "system": "http://highmed.org/fhir/NamingSystem/research-study-identifier", + "value": "886ec806-9bbb-4217-84d0-42f149c6767e" + } ], + "status": "active", + "enrollment": [ { + "reference": "urn:uuid:ae194285-d08e-46c7-a9a7-9a47624dd8aa" + }, { + "reference": "urn:uuid:ae194285-d08e-46c7-a9a7-9a47624dd8bb" + } ] }, "request": { "method": "POST", @@ -187,7 +108,7 @@ "fullUrl": "urn:uuid:bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "resource": { "resourceType": "Task", - "instantiatesUri": "http://highmed.org/bpe/Process/requestSimpleFeasibility/0.1.0", + "instantiatesUri": "http://highmed.org/bpe/Process/requestSimpleFeasibility/0.2.0", "status": "requested", "intent": "order", "requester": { @@ -224,7 +145,7 @@ "type": { "coding": [ { - "system": "http://highmed.org/fhir/CodeSystem/bpmn-message", + "system": "http://highmed.org/fhir/CodeSystem/feasibility", "code": "research-study-reference" } ] diff --git a/dsf-fhir/dsf-fhir-server/src/test/resources/integration/test-bundle.xml b/dsf-fhir/dsf-fhir-server/src/test/resources/integration/test-bundle.xml index a040656c0..b1b125f6a 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/resources/integration/test-bundle.xml +++ b/dsf-fhir/dsf-fhir-server/src/test/resources/integration/test-bundle.xml @@ -8,7 +8,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-organization"/> </meta> <extension url="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint"> <valueString value="TODO"/> @@ -26,8 +27,8 @@ </type> <name value="Test Organization"/> <endpoint> - <type value="Endpoint"/> <reference value="urn:uuid:b879e904-d666-45de-a995-accdd4429b79"/> + <type value="Endpoint"/> </endpoint> </Organization> </resource> @@ -44,7 +45,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint"/> </meta> <identifier> <system value="http://highmed.org/fhir/NamingSystem/endpoint-identifier"/> @@ -57,8 +59,8 @@ </connectionType> <name value="Test Endpoint"/> <managingOrganization> - <type value="Organization"/> <reference value="urn:uuid:bb73165c-c7b9-4342-8e28-531f07fa7735"/> + <type value="Organization"/> </managingOrganization> <payloadType> <coding> @@ -84,7 +86,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-organization"/> </meta> <extension url="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint"> <valueString value="TODO"/> @@ -101,6 +104,10 @@ </coding> </type> <name value="External Test Organization"/> + <endpoint> + <reference value="urn:uuid:3944afe5-c65d-4101-b373-811f97fa8d41"/> + <type value="Endpoint"/> + </endpoint> </Organization> </resource> <request> @@ -108,4 +115,45 @@ <url value="Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|External_Test_Organization"/> </request> </entry> + <entry> + <fullUrl value="urn:uuid:3944afe5-c65d-4101-b373-811f97fa8d41"/> + <resource> + <Endpoint xmlns="http://hl7.org/fhir"> + <meta> + <tag> + <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> + <code value="REMOTE"/> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint"/> + </meta> + <identifier> + <system value="http://highmed.org/fhir/NamingSystem/endpoint-identifier"/> + <value value="External_Test_Endpoint"/> + </identifier> + <status value="active"/> + <connectionType> + <system value="http://terminology.hl7.org/CodeSystem/endpoint-connection-type"/> + <code value="hl7-fhir-rest"/> + </connectionType> + <name value="External Test Endpoint"/> + <managingOrganization> + <reference value="urn:uuid:ddd4e309-e41b-4427-9657-8a58a89f01a9"/> + <type value="Organization"/> + </managingOrganization> + <payloadType> + <coding> + <system value="http://hl7.org/fhir/resource-types"/> + <code value="Task"/> + </coding> + </payloadType> + <payloadMimeType value="application/fhir+json"/> + <payloadMimeType value="application/fhir+xml"/> + <address value="https://localhost:80010/fhir"/> + </Endpoint> + </resource> + <request> + <method value="PUT"/> + <url value="Endpoint?identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|External_Test_Endpoint"/> + </request> + </entry> </Bundle> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/test/resources/integration/white-list.json b/dsf-fhir/dsf-fhir-server/src/test/resources/integration/white-list.json new file mode 100644 index 000000000..f9b538f14 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/resources/integration/white-list.json @@ -0,0 +1,353 @@ +{ + "resourceType": "Bundle", + "meta": { + "tag": [{ + "system": "http://highmed.org/fhir/CodeSystem/authorization-role", + "code": "REMOTE" + } + ] + }, + "identifier": { + "system": "http://highmed.org/fhir/CodeSystem/update-whitelist", + "value": "highmed_whitelist" + }, + "type": "transaction", + "entry": [{ + "fullUrl": "urn:uuid:18d87756-1ceb-4925-b2c2-9846f353f219", + "resource": { + "resourceType": "Organization", + "meta": { + "profile": ["http://highmed.org/fhir/StructureDefinition/highmed-organization"], + "tag": [{ + "system": "http://highmed.org/fhir/CodeSystem/authorization-role", + "code": "REMOTE" + } + ] + }, + "extension": [{ + "url": "http://highmed.org/fhir/StructureDefinition/certificate-thumbprint", + "valueString": "b72203e163acc1bfd9c2db24c248b36cea282b5986b70e5c40ee33599c34e1b00d2bdea1598663a61a8441024f40b4924a453ed75108eeb2a7f7b9a2027871bc" + } + ], + "identifier": [{ + "system": "http://highmed.org/fhir/NamingSystem/organization-identifier", + "value": "Test_MeDIC_2" + } + ], + "active": true, + "type": [{ + "coding": [{ + "system": "http://highmed.org/fhir/CodeSystem/organization-type", + "code": "MeDIC" + } + ] + } + ], + "name": "Test MeDIC 2", + "endpoint": [{ + "reference": "urn:uuid:d2dd5ba3-22f0-4406-bdd6-7a939d9a347e", + "type": "Endpoint" + } + ] + }, + "request": { + "method": "PUT", + "url": "Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_MeDIC_2" + } + }, { + "fullUrl": "urn:uuid:d2dd5ba3-22f0-4406-bdd6-7a939d9a347e", + "resource": { + "resourceType": "Endpoint", + "meta": { + "profile": ["http://highmed.org/fhir/StructureDefinition/highmed-endpoint"], + "tag": [{ + "system": "http://highmed.org/fhir/CodeSystem/authorization-role", + "code": "REMOTE" + } + ] + }, + "identifier": [{ + "system": "http://highmed.org/fhir/NamingSystem/endpoint-identifier", + "value": "Test_MeDIC_2_Endpoint" + } + ], + "status": "active", + "connectionType": { + "system": "http://terminology.hl7.org/CodeSystem/endpoint-connection-type", + "code": "hl7-fhir-rest" + }, + "name": "Test MeDIC 2 Endpoint", + "managingOrganization": { + "reference": "urn:uuid:18d87756-1ceb-4925-b2c2-9846f353f219", + "type": "Organization" + }, + "payloadType": [{ + "coding": [{ + "system": "http://hl7.org/fhir/resource-types", + "code": "Task" + } + ] + } + ], + "payloadMimeType": ["application/fhir+json", "application/fhir+xml"], + "address": "https://medic2/fhir" + }, + "request": { + "method": "PUT", + "url": "Endpoint?identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_MeDIC_2_Endpoint" + } + }, { + "fullUrl": "urn:uuid:e3c9ee5c-199d-4fc8-869c-d1fd1cf7283e", + "resource": { + "resourceType": "Organization", + "meta": { + "profile": ["http://highmed.org/fhir/StructureDefinition/highmed-organization"], + "tag": [{ + "system": "http://highmed.org/fhir/CodeSystem/authorization-role", + "code": "REMOTE" + } + ] + }, + "extension": [{ + "url": "http://highmed.org/fhir/StructureDefinition/certificate-thumbprint", + "valueString": "fe9b49ccf259929485e55f8a03c1d74c147bd374debdc0c4ef48f75e74cdfd03e19cc2f79da1f53acd433734acae017c8d01c30f448675a1e77f0b80adf7023b" + } + ], + "identifier": [{ + "system": "http://highmed.org/fhir/NamingSystem/organization-identifier", + "value": "Test_TTP" + } + ], + "active": true, + "type": [{ + "coding": [{ + "system": "http://highmed.org/fhir/CodeSystem/organization-type", + "code": "TTP" + } + ] + } + ], + "name": "Test TTP", + "endpoint": [{ + "reference": "urn:uuid:a61d80be-0238-41a3-b270-9e8fc356f7e3", + "type": "Endpoint" + } + ] + }, + "request": { + "method": "PUT", + "url": "Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_TTP" + } + }, { + "fullUrl": "urn:uuid:a61d80be-0238-41a3-b270-9e8fc356f7e3", + "resource": { + "resourceType": "Endpoint", + "meta": { + "profile": ["http://highmed.org/fhir/StructureDefinition/highmed-endpoint"], + "tag": [{ + "system": "http://highmed.org/fhir/CodeSystem/authorization-role", + "code": "REMOTE" + } + ] + }, + "identifier": [{ + "system": "http://highmed.org/fhir/NamingSystem/endpoint-identifier", + "value": "Test_TTP_Endpoint" + } + ], + "status": "active", + "connectionType": { + "system": "http://terminology.hl7.org/CodeSystem/endpoint-connection-type", + "code": "hl7-fhir-rest" + }, + "name": "Test TTP Endpoint", + "managingOrganization": { + "reference": "urn:uuid:e3c9ee5c-199d-4fc8-869c-d1fd1cf7283e", + "type": "Organization" + }, + "payloadType": [{ + "coding": [{ + "system": "http://hl7.org/fhir/resource-types", + "code": "Task" + } + ] + } + ], + "payloadMimeType": ["application/fhir+json", "application/fhir+xml"], + "address": "https://ttp/fhir" + }, + "request": { + "method": "PUT", + "url": "Endpoint?identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_TTP_Endpoint" + } + }, { + "fullUrl": "urn:uuid:8d9eb2e7-5940-46d5-9035-90151b6d5f7a", + "resource": { + "resourceType": "Organization", + "meta": { + "profile": ["http://highmed.org/fhir/StructureDefinition/highmed-organization"], + "tag": [{ + "system": "http://highmed.org/fhir/CodeSystem/authorization-role", + "code": "REMOTE" + } + ] + }, + "extension": [{ + "url": "http://highmed.org/fhir/StructureDefinition/certificate-thumbprint", + "valueString": "dc737f1a58605847002d422dc36127e6418c8b9cb295517ff4d8684af64aed49290729e8f9315ef5189b80dcaa9ccd3fdc4aa0210e425218de98c85145f3e88d" + } + ], + "identifier": [{ + "system": "http://highmed.org/fhir/NamingSystem/organization-identifier", + "value": "Test_MeDIC_1" + } + ], + "active": true, + "type": [{ + "coding": [{ + "system": "http://highmed.org/fhir/CodeSystem/organization-type", + "code": "MeDIC" + } + ] + } + ], + "name": "Test MeDIC 1", + "endpoint": [{ + "reference": "urn:uuid:89dc2b55-fec3-44d5-86c1-8fc35dfeb3b8", + "type": "Endpoint" + } + ] + }, + "request": { + "method": "PUT", + "url": "Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_MeDIC_1" + } + }, { + "fullUrl": "urn:uuid:89dc2b55-fec3-44d5-86c1-8fc35dfeb3b8", + "resource": { + "resourceType": "Endpoint", + "meta": { + "profile": ["http://highmed.org/fhir/StructureDefinition/highmed-endpoint"], + "tag": [{ + "system": "http://highmed.org/fhir/CodeSystem/authorization-role", + "code": "REMOTE" + } + ] + }, + "identifier": [{ + "system": "http://highmed.org/fhir/NamingSystem/endpoint-identifier", + "value": "Test_MeDIC_1_Endpoint" + } + ], + "status": "active", + "connectionType": { + "system": "http://terminology.hl7.org/CodeSystem/endpoint-connection-type", + "code": "hl7-fhir-rest" + }, + "name": "Test MeDIC 1 Endpoint", + "managingOrganization": { + "reference": "urn:uuid:8d9eb2e7-5940-46d5-9035-90151b6d5f7a", + "type": "Organization" + }, + "payloadType": [{ + "coding": [{ + "system": "http://hl7.org/fhir/resource-types", + "code": "Task" + } + ] + } + ], + "payloadMimeType": ["application/fhir+json", "application/fhir+xml"], + "address": "https://medic1/fhir" + }, + "request": { + "method": "PUT", + "url": "Endpoint?identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_MeDIC_1_Endpoint" + } + }, { + "fullUrl": "urn:uuid:ede98d88-679f-4e46-8559-f99eb6cb84b8", + "resource": { + "resourceType": "Organization", + "meta": { + "profile": ["http://highmed.org/fhir/StructureDefinition/highmed-organization"], + "tag": [{ + "system": "http://highmed.org/fhir/CodeSystem/authorization-role", + "code": "REMOTE" + } + ] + }, + "extension": [{ + "url": "http://highmed.org/fhir/StructureDefinition/certificate-thumbprint", + "valueString": "c1fdddaeff1cb9937a3ee7be7edcb43bd21d907c7f8060602d276b7c51662e8d023c0991262c7d89dfc8060b2a6f9f4b03258676ee6d9676569fb3d207cf828a" + } + ], + "identifier": [{ + "system": "http://highmed.org/fhir/NamingSystem/organization-identifier", + "value": "Test_MeDIC_3" + } + ], + "active": true, + "type": [{ + "coding": [{ + "system": "http://highmed.org/fhir/CodeSystem/organization-type", + "code": "MeDIC" + } + ] + } + ], + "name": "Test MeDIC 3", + "endpoint": [{ + "reference": "urn:uuid:7a6dbc0c-d38d-4107-99ae-7a9bdadcc6b3", + "type": "Endpoint" + } + ] + }, + "request": { + "method": "PUT", + "url": "Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_MeDIC_3" + } + }, { + "fullUrl": "urn:uuid:7a6dbc0c-d38d-4107-99ae-7a9bdadcc6b3", + "resource": { + "resourceType": "Endpoint", + "meta": { + "profile": ["http://highmed.org/fhir/StructureDefinition/highmed-endpoint"], + "tag": [{ + "system": "http://highmed.org/fhir/CodeSystem/authorization-role", + "code": "REMOTE" + } + ] + }, + "identifier": [{ + "system": "http://highmed.org/fhir/NamingSystem/endpoint-identifier", + "value": "Test_MeDIC_3_Endpoint" + } + ], + "status": "active", + "connectionType": { + "system": "http://terminology.hl7.org/CodeSystem/endpoint-connection-type", + "code": "hl7-fhir-rest" + }, + "name": "Test MeDIC 3 Endpoint", + "managingOrganization": { + "reference": "urn:uuid:ede98d88-679f-4e46-8559-f99eb6cb84b8", + "type": "Organization" + }, + "payloadType": [{ + "coding": [{ + "system": "http://hl7.org/fhir/resource-types", + "code": "Task" + } + ] + } + ], + "payloadMimeType": ["application/fhir+json", "application/fhir+xml"], + "address": "https://medic3/fhir" + }, + "request": { + "method": "PUT", + "url": "Endpoint?identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_MeDIC_3_Endpoint" + } + } + ] +} diff --git a/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2-maven-surefire-config.xml b/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2-maven-surefire-config.xml index fe719ebe9..0ee92ec9e 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2-maven-surefire-config.xml +++ b/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2-maven-surefire-config.xml @@ -3,23 +3,16 @@ <Appenders> <Console name="CONSOLE" target="SYSTEM_OUT"> - <PatternLayout pattern="%p\t%t - %C{1}.%M(%L) | %m%n"/> + <PatternLayout pattern="%p\t%t | %m%n"/> </Console> </Appenders> <Loggers> - <Logger name="de.rwh" level="INFO"/> - <Logger name="org.highmed" level="INFO"/> - <Logger name="org.apache" level="WARN"/> - <Logger name="org.springframework" level="WARN"/> - <Logger name="jndi" level="WARN"/> - <Logger name="org.eclipse.jetty" level="INFO"/> - <Logger name="com.sun.jersey" level="WARN"/> - <Logger name="liquibase" level="WARN"/> - <Logger name="ca.uhn.hl7v2" level="WARN"/> + <AsyncLogger name="org.highmed" level="INFO"/> + <AsyncLogger name="org.eclipse.jetty" level="INFO"/> - <Root level="WARN"> + <AsyncRoot level="WARN"> <AppenderRef ref="CONSOLE"/> - </Root> + </AsyncRoot> </Loggers> </Configuration> \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2.xml b/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2.xml index 9999bb653..32856a8c8 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2.xml +++ b/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2.xml @@ -15,15 +15,8 @@ <AppenderRef ref="AUDIT"/> </Logger> - <Logger name="de.rwh" level="TRACE"/> <Logger name="org.highmed" level="TRACE"/> - <Logger name="org.apache" level="WARN"/> - <Logger name="org.springframework" level="WARN"/> - <Logger name="jndi" level="WARN"/> <Logger name="org.eclipse.jetty" level="INFO"/> - <Logger name="com.sun.jersey" level="WARN"/> - <Logger name="liquibase" level="WARN"/> - <Logger name="ca.uhn.hl7v2" level="WARN"/> <Root level="WARN"> <AppenderRef ref="CONSOLE"/> diff --git a/dsf-fhir/dsf-fhir-webservice-client/pom.xml b/dsf-fhir/dsf-fhir-webservice-client/pom.xml index 2e340a1e8..0e5951871 100755 --- a/dsf-fhir/dsf-fhir-webservice-client/pom.xml +++ b/dsf-fhir/dsf-fhir-webservice-client/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-fhir-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> diff --git a/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/FhirWebserviceClient.java b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/FhirWebserviceClient.java index 138aa865f..5f1ec6fb5 100755 --- a/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/FhirWebserviceClient.java +++ b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/FhirWebserviceClient.java @@ -1,25 +1,24 @@ package org.highmed.fhir.client; +import java.io.InputStream; import java.util.List; import java.util.Map; +import javax.ws.rs.core.MediaType; + import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.CapabilityStatement; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.StructureDefinition; -public interface FhirWebserviceClient +public interface FhirWebserviceClient extends PreferReturnResource { String getBaseUrl(); - <R extends Resource> R create(R resource); - - <R extends Resource> R createConditionaly(R resource, String ifNoneExistCriteria); + PreferReturnMinimal withMinimalReturn(); - <R extends Resource> R update(R resource); - - <R extends Resource> R updateConditionaly(R resource, Map<String, List<String>> criteria); + PreferReturnOutcome withOperationOutcomeReturn(); void delete(Class<? extends Resource> resourceClass, String id); @@ -31,22 +30,43 @@ public interface FhirWebserviceClient <R extends Resource> boolean exists(Class<R> resourceType, String id); + InputStream readBinary(String id, MediaType mediaType); + + /** + * @param resourceTypeName + * not <code>null</code> + * @param id + * not <code>null</code> + * @param version + * not <code>null</code> + * @return {@link InputStream} needs to be closed + */ Resource read(String resourceTypeName, String id, String version); <R extends Resource> R read(Class<R> resourceType, String id, String version); <R extends Resource> boolean exists(Class<R> resourceType, String id, String version); + /** + * @param id + * not <code>null</code> + * @param version + * not <code>null</code> + * @param mediaType + * not <code>null</code> + * @return {@link InputStream} needs to be closed + */ + InputStream readBinary(String id, String version, MediaType mediaType); + boolean exists(IdType resourceTypeIdVersion); - <R extends Resource> Bundle search(Class<R> resourceType, Map<String, List<String>> parameters); + Bundle search(Class<? extends Resource> resourceType, Map<String, List<String>> parameters); + + Bundle searchWithStrictHandling(Class<? extends Resource> resourceType, Map<String, List<String>> parameters); CapabilityStatement getConformance(); StructureDefinition generateSnapshot(String url); StructureDefinition generateSnapshot(StructureDefinition differential); - - Bundle postBundle(Bundle bundle); - } diff --git a/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/FhirWebserviceClientJersey.java b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/FhirWebserviceClientJersey.java index d4ba1bc89..dcc8d0b4c 100755 --- a/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/FhirWebserviceClientJersey.java +++ b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/FhirWebserviceClientJersey.java @@ -1,5 +1,6 @@ package org.highmed.fhir.client; +import java.io.InputStream; import java.security.KeyStore; import java.util.Arrays; import java.util.HashMap; @@ -8,7 +9,6 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.ws.rs.ProcessingException; import javax.ws.rs.WebApplicationException; @@ -17,6 +17,7 @@ import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.EntityTag; import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; @@ -65,8 +66,10 @@ import org.highmed.dsf.fhir.adapter.TaskXmlFhirAdapter; import org.highmed.dsf.fhir.adapter.ValueSetJsonFhirAdapter; import org.highmed.dsf.fhir.adapter.ValueSetXmlFhirAdapter; -import org.highmed.dsf.fhir.service.ReferenceExtractor; -import org.highmed.dsf.fhir.service.ResourceReference; +import org.highmed.dsf.fhir.prefer.PreferHandlingType; +import org.highmed.dsf.fhir.prefer.PreferReturnType; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.hl7.fhir.r4.model.Binary; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.CapabilityStatement; import org.hl7.fhir.r4.model.IdType; @@ -89,20 +92,26 @@ public class FhirWebserviceClientJersey extends AbstractJerseyClient implements { private static final Logger logger = LoggerFactory.getLogger(FhirWebserviceClientJersey.class); - private final ReferenceExtractor referenceExtractor; + private final ReferenceCleaner referenceCleaner; private final Map<String, Class<?>> resourceTypeByNames = new HashMap<>(); + private final PreferReturnMinimal preferReturnMinimal; + private final PreferReturnOutcome preferReturnOutcome; + public FhirWebserviceClientJersey(String baseUrl, KeyStore trustStore, KeyStore keyStore, char[] keyStorePassword, String proxySchemeHostPort, String proxyUserName, char[] proxyPassword, int connectTimeout, int readTimeout, - ObjectMapper objectMapper, FhirContext fhirContext, ReferenceExtractor referenceExtractor) + ObjectMapper objectMapper, FhirContext fhirContext, ReferenceCleaner referenceCleaner) { super(baseUrl, trustStore, keyStore, keyStorePassword, proxySchemeHostPort, proxyUserName, proxyPassword, connectTimeout, readTimeout, objectMapper, components(fhirContext)); - this.referenceExtractor = referenceExtractor; + this.referenceCleaner = referenceCleaner; registeredComponents.stream().filter(e -> e instanceof AbstractFhirAdapter).map(e -> (AbstractFhirAdapter<?>) e) .forEach(a -> resourceTypeByNames.put(a.getResourceTypeName(), a.getResourceType())); + + preferReturnMinimal = createPreferReturnMinimal(); + preferReturnOutcome = createPreferReturnOutcome(); } public static List<AbstractFhirAdapter<?>> components(FhirContext fhirContext) @@ -132,6 +141,117 @@ public static List<AbstractFhirAdapter<?>> components(FhirContext fhirContext) new ValueSetXmlFhirAdapter(fhirContext)); } + private PreferReturnMinimal createPreferReturnMinimal() + { + return new PreferReturnMinimal() + { + @Override + public IdType create(Resource resource) + { + return FhirWebserviceClientJersey.this.create(PreferReturnType.MINIMAL, resource).getId(); + } + + @Override + public IdType createConditionaly(Resource resource, String ifNoneExistCriteria) + { + return FhirWebserviceClientJersey.this + .createConditionaly(PreferReturnType.MINIMAL, resource, ifNoneExistCriteria).getId(); + } + + @Override + public IdType createBinary(InputStream in, MediaType mediaType, String securityContextReference) + { + return FhirWebserviceClientJersey.this + .createBinary(PreferReturnType.MINIMAL, in, mediaType, securityContextReference).getId(); + } + + @Override + public IdType update(Resource resource) + { + return FhirWebserviceClientJersey.this.update(PreferReturnType.MINIMAL, resource).getId(); + } + + @Override + public IdType updateConditionaly(Resource resource, Map<String, List<String>> criteria) + { + return FhirWebserviceClientJersey.this.updateConditionaly(PreferReturnType.MINIMAL, resource, criteria) + .getId(); + } + + @Override + public IdType updateBinary(String id, InputStream in, MediaType mediaType, String securityContextReference) + { + return FhirWebserviceClientJersey.this + .updateBinary(PreferReturnType.MINIMAL, id, in, mediaType, securityContextReference).getId(); + } + + @Override + public Bundle postBundle(Bundle bundle) + { + return FhirWebserviceClientJersey.this.postBundle(PreferReturnType.MINIMAL, bundle); + } + }; + } + + private PreferReturnOutcome createPreferReturnOutcome() + { + return new PreferReturnOutcome() + { + @Override + public OperationOutcome create(Resource resource) + { + return FhirWebserviceClientJersey.this.create(PreferReturnType.OPERATION_OUTCOME, resource) + .getOperationOutcome(); + } + + @Override + public OperationOutcome createConditionaly(Resource resource, String ifNoneExistCriteria) + { + return FhirWebserviceClientJersey.this + .createConditionaly(PreferReturnType.OPERATION_OUTCOME, resource, ifNoneExistCriteria) + .getOperationOutcome(); + } + + @Override + public OperationOutcome createBinary(InputStream in, MediaType mediaType, String securityContextReference) + { + return FhirWebserviceClientJersey.this + .createBinary(PreferReturnType.OPERATION_OUTCOME, in, mediaType, securityContextReference) + .getOperationOutcome(); + } + + @Override + public OperationOutcome update(Resource resource) + { + return FhirWebserviceClientJersey.this.update(PreferReturnType.OPERATION_OUTCOME, resource) + .getOperationOutcome(); + } + + @Override + public OperationOutcome updateConditionaly(Resource resource, Map<String, List<String>> criteria) + { + return FhirWebserviceClientJersey.this + .updateConditionaly(PreferReturnType.OPERATION_OUTCOME, resource, criteria) + .getOperationOutcome(); + } + + @Override + public OperationOutcome updateBinary(String id, InputStream in, MediaType mediaType, + String securityContextReference) + { + return FhirWebserviceClientJersey.this + .updateBinary(PreferReturnType.OPERATION_OUTCOME, id, in, mediaType, securityContextReference) + .getOperationOutcome(); + } + + @Override + public Bundle postBundle(Bundle bundle) + { + return FhirWebserviceClientJersey.this.postBundle(PreferReturnType.OPERATION_OUTCOME, bundle); + } + }; + } + private WebApplicationException handleError(Response response) { try @@ -150,79 +270,140 @@ private WebApplicationException handleError(Response response) } } - @Override - @SuppressWarnings("unchecked") - public <R extends Resource> R create(R resource) + private String toString(OperationOutcome outcome) { - Objects.requireNonNull(resource, "resource"); + return outcome == null ? "" + : outcome.getIssue().stream().map(i -> toString(i)).collect(Collectors.joining("\n")); + } - Response response = getResource().path(resource.getClass().getAnnotation(ResourceDef.class).name()).request() - .accept(Constants.CT_FHIR_JSON_NEW).post(Entity.entity(resource, Constants.CT_FHIR_JSON_NEW)); + private String toString(OperationOutcomeIssueComponent issue) + { + return issue == null ? "" : issue.getSeverity() + " " + issue.getCode() + " " + issue.getDiagnostics(); + } + private void logStatusAndHeaders(Response response) + { logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); logger.debug("HTTP header Location: {}", response.getLocation()); logger.debug("HTTP header ETag: {}", response.getHeaderString(HttpHeaders.ETAG)); logger.debug("HTTP header Last-Modified: {}", response.getHeaderString(HttpHeaders.LAST_MODIFIED)); + } + + private PreferReturn toPreferReturn(PreferReturnType returnType, Class<? extends Resource> resourceType, + Response response) + { + switch (returnType) + { + case REPRESENTATION: + // TODO remove workaround if HAPI bug fixed + Resource resource = referenceCleaner.cleanReferenceResourcesIfBundle(response.readEntity(resourceType)); + return PreferReturn.resource(resource); + case MINIMAL: + return PreferReturn.minimal(response.getLocation()); + case OPERATION_OUTCOME: + return PreferReturn.outcome(response.readEntity(OperationOutcome.class)); + default: + throw new RuntimeException(PreferReturn.class.getName() + " value " + returnType + " not supported"); + } + } + + @Override + public PreferReturnMinimal withMinimalReturn() + { + return preferReturnMinimal; + } + + @Override + public PreferReturnOutcome withOperationOutcomeReturn() + { + return preferReturnOutcome; + } + + private PreferReturn create(PreferReturnType returnType, Resource resource) + { + Objects.requireNonNull(returnType, "returnType"); + Objects.requireNonNull(resource, "resource"); + + Response response = getResource().path(resource.getClass().getAnnotation(ResourceDef.class).name()).request() + .header(Constants.HEADER_PREFER, returnType.getHeaderValue()).accept(Constants.CT_FHIR_JSON_NEW) + .post(Entity.entity(resource, Constants.CT_FHIR_JSON_NEW)); + + logStatusAndHeaders(response); if (Status.CREATED.getStatusCode() == response.getStatus()) - return (R) response.readEntity(resource.getClass()); + return toPreferReturn(returnType, resource.getClass(), response); else throw handleError(response); } - @Override - @SuppressWarnings("unchecked") - public <R extends Resource> R createConditionaly(R resource, String ifNoneExistCriteria) + private PreferReturn createConditionaly(PreferReturnType returnType, Resource resource, String ifNoneExistCriteria) { + Objects.requireNonNull(returnType, "returnType"); Objects.requireNonNull(resource, "resource"); Objects.requireNonNull(ifNoneExistCriteria, "ifNoneExistCriteria"); Response response = getResource().path(resource.getClass().getAnnotation(ResourceDef.class).name()).request() + .header(Constants.HEADER_PREFER, returnType.getHeaderValue()) .header(Constants.HEADER_IF_NONE_EXIST, ifNoneExistCriteria).accept(Constants.CT_FHIR_JSON_NEW) .post(Entity.entity(resource, Constants.CT_FHIR_JSON_NEW)); - logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), - response.getStatusInfo().getReasonPhrase()); - logger.debug("HTTP header Location: {}", response.getLocation()); - logger.debug("HTTP header ETag: {}", response.getHeaderString(HttpHeaders.ETAG)); - logger.debug("HTTP header Last-Modified: {}", response.getHeaderString(HttpHeaders.LAST_MODIFIED)); + logStatusAndHeaders(response); if (Status.CREATED.getStatusCode() == response.getStatus()) - return (R) response.readEntity(resource.getClass()); + return toPreferReturn(returnType, resource.getClass(), response); else throw handleError(response); } - @Override - @SuppressWarnings("unchecked") - public <R extends Resource> R update(R resource) + private PreferReturn createBinary(PreferReturnType returnType, InputStream in, MediaType mediaType, + String securityContextReference) { + Objects.requireNonNull(returnType, "returnType"); + Objects.requireNonNull(in, "in"); + Objects.requireNonNull(mediaType, "mediaType"); + // securityContextReference may be null + + Builder request = getResource().path("Binary").request().header(Constants.HEADER_PREFER, + returnType.getHeaderValue()); + if (securityContextReference != null && !securityContextReference.isBlank()) + request = request.header(Constants.HEADER_X_SECURITY_CONTEXT, securityContextReference); + Response response = request.accept(Constants.CT_FHIR_JSON_NEW).post(Entity.entity(in, mediaType)); + + logStatusAndHeaders(response); + + if (Status.CREATED.getStatusCode() == response.getStatus()) + return toPreferReturn(returnType, Binary.class, response); + else + throw handleError(response); + } + + private PreferReturn update(PreferReturnType returnType, Resource resource) + { + Objects.requireNonNull(returnType, "returnType"); Objects.requireNonNull(resource, "resource"); Builder builder = getResource().path(resource.getClass().getAnnotation(ResourceDef.class).name()) - .path(resource.getIdElement().getIdPart()).request().accept(Constants.CT_FHIR_JSON_NEW); + .path(resource.getIdElement().getIdPart()).request() + .header(Constants.HEADER_PREFER, returnType.getHeaderValue()).accept(Constants.CT_FHIR_JSON_NEW); if (resource.getMeta().hasVersionId()) builder.header(Constants.HEADER_IF_MATCH, new EntityTag(resource.getMeta().getVersionId(), true)); Response response = builder.put(Entity.entity(resource, Constants.CT_FHIR_JSON_NEW)); - logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), - response.getStatusInfo().getReasonPhrase()); - logger.debug("HTTP header ETag: {}", response.getHeaderString(HttpHeaders.ETAG)); - logger.debug("HTTP header Last-Modified: {}", response.getHeaderString(HttpHeaders.LAST_MODIFIED)); + logStatusAndHeaders(response); if (Status.OK.getStatusCode() == response.getStatus()) - return (R) response.readEntity(resource.getClass()); + return toPreferReturn(returnType, resource.getClass(), response); else throw handleError(response); } - @Override - @SuppressWarnings("unchecked") - public <R extends Resource> R updateConditionaly(R resource, Map<String, List<String>> criteria) + private PreferReturn updateConditionaly(PreferReturnType returnType, Resource resource, + Map<String, List<String>> criteria) { + Objects.requireNonNull(returnType, "returnType"); Objects.requireNonNull(resource, "resource"); Objects.requireNonNull(criteria, "criteria"); if (criteria.isEmpty()) @@ -233,24 +414,109 @@ public <R extends Resource> R updateConditionaly(R resource, Map<String, List<St for (Entry<String, List<String>> entry : criteria.entrySet()) target = target.queryParam(entry.getKey(), entry.getValue().toArray()); - Builder builder = target.request().accept(Constants.CT_FHIR_JSON_NEW); + Builder builder = target.request().accept(Constants.CT_FHIR_JSON_NEW).header(Constants.HEADER_PREFER, + returnType.getHeaderValue()); if (resource.getMeta().hasVersionId()) builder.header(Constants.HEADER_IF_MATCH, new EntityTag(resource.getMeta().getVersionId(), true)); Response response = builder.put(Entity.entity(resource, Constants.CT_FHIR_JSON_NEW)); - logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), - response.getStatusInfo().getReasonPhrase()); - logger.debug("HTTP header ETag: {}", response.getHeaderString(HttpHeaders.ETAG)); - logger.debug("HTTP header Last-Modified: {}", response.getHeaderString(HttpHeaders.LAST_MODIFIED)); + logStatusAndHeaders(response); if (Status.CREATED.getStatusCode() == response.getStatus() || Status.OK.getStatusCode() == response.getStatus()) - return (R) response.readEntity(resource.getClass()); + return toPreferReturn(returnType, resource.getClass(), response); + else + throw handleError(response); + } + + private PreferReturn updateBinary(PreferReturnType returnType, String id, InputStream in, MediaType mediaType, + String securityContextReference) + { + Objects.requireNonNull(returnType, "returnType"); + Objects.requireNonNull(id, "id"); + Objects.requireNonNull(in, "in"); + Objects.requireNonNull(mediaType, "mediaType"); + // securityContextReference may be null + + Builder request = getResource().path("Binary").path(id).request().header(Constants.HEADER_PREFER, + returnType.getHeaderValue()); + if (securityContextReference != null && !securityContextReference.isBlank()) + request = request.header(Constants.HEADER_X_SECURITY_CONTEXT, securityContextReference); + Response response = request.accept(Constants.CT_FHIR_JSON_NEW).put(Entity.entity(in, mediaType)); + + logStatusAndHeaders(response); + + if (Status.CREATED.getStatusCode() == response.getStatus()) + return toPreferReturn(returnType, Binary.class, response); + else + throw handleError(response); + } + + private Bundle postBundle(PreferReturnType returnType, Bundle bundle) + { + Objects.requireNonNull(bundle, "bundle"); + + Response response = getResource().request().header(Constants.HEADER_PREFER, returnType.getHeaderValue()) + .accept(Constants.CT_FHIR_JSON_NEW).post(Entity.entity(bundle, Constants.CT_FHIR_JSON_NEW)); + + logStatusAndHeaders(response); + + if (Status.OK.getStatusCode() == response.getStatus()) + // TODO remove workaround if HAPI bug fixed + return referenceCleaner.cleanReferenceResourcesIfBundle(response.readEntity(Bundle.class)); else throw handleError(response); } + @Override + @SuppressWarnings("unchecked") + public <R extends Resource> R create(R resource) + { + return (R) create(PreferReturnType.REPRESENTATION, resource).getResource(); + } + + @Override + @SuppressWarnings("unchecked") + public <R extends Resource> R createConditionaly(R resource, String ifNoneExistCriteria) + { + return (R) createConditionaly(PreferReturnType.REPRESENTATION, resource, ifNoneExistCriteria).getResource(); + } + + @Override + public Binary createBinary(InputStream in, MediaType mediaType, String securityContextReference) + { + return (Binary) createBinary(PreferReturnType.REPRESENTATION, in, mediaType, securityContextReference) + .getResource(); + } + + @Override + @SuppressWarnings("unchecked") + public <R extends Resource> R update(R resource) + { + return (R) update(PreferReturnType.REPRESENTATION, resource).getResource(); + } + + @Override + @SuppressWarnings("unchecked") + public <R extends Resource> R updateConditionaly(R resource, Map<String, List<String>> criteria) + { + return (R) updateConditionaly(PreferReturnType.REPRESENTATION, resource, criteria).getResource(); + } + + @Override + public Binary updateBinary(String id, InputStream in, MediaType mediaType, String securityContextReference) + { + return (Binary) updateBinary(PreferReturnType.REPRESENTATION, id, in, mediaType, securityContextReference) + .getResource(); + } + + @Override + public Bundle postBundle(Bundle bundle) + { + return postBundle(PreferReturnType.REPRESENTATION, bundle); + } + @Override public void delete(Class<? extends Resource> resourceClass, String id) { @@ -260,10 +526,7 @@ public void delete(Class<? extends Resource> resourceClass, String id) Response response = getResource().path(resourceClass.getAnnotation(ResourceDef.class).name()).path(id).request() .accept(Constants.CT_FHIR_JSON_NEW).delete(); - logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), - response.getStatusInfo().getReasonPhrase()); - logger.debug("HTTP header ETag: {}", response.getHeaderString(HttpHeaders.ETAG)); - logger.debug("HTTP header Last-Modified: {}", response.getHeaderString(HttpHeaders.LAST_MODIFIED)); + logStatusAndHeaders(response); if (Status.OK.getStatusCode() != response.getStatus() && Status.NO_CONTENT.getStatusCode() != response.getStatus()) @@ -285,10 +548,7 @@ public void deleteConditionaly(Class<? extends Resource> resourceClass, Map<Stri Response response = target.request().accept(Constants.CT_FHIR_JSON_NEW).delete(); - logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), - response.getStatusInfo().getReasonPhrase()); - logger.debug("HTTP header ETag: {}", response.getHeaderString(HttpHeaders.ETAG)); - logger.debug("HTTP header Last-Modified: {}", response.getHeaderString(HttpHeaders.LAST_MODIFIED)); + logStatusAndHeaders(response); if (Status.OK.getStatusCode() != response.getStatus() && Status.NO_CONTENT.getStatusCode() != response.getStatus()) @@ -296,154 +556,154 @@ public void deleteConditionaly(Class<? extends Resource> resourceClass, Map<Stri } @Override - public CapabilityStatement getConformance() + public Resource read(String resourceTypeName, String id) { - Response response = getResource().path("metadata").request() - .accept(Constants.CT_FHIR_JSON_NEW + "; fhirVersion=4.0").get(); + Objects.requireNonNull(resourceTypeName, "resourceTypeName"); + Objects.requireNonNull(id, "id"); + if (!resourceTypeByNames.containsKey(resourceTypeName)) + throw new IllegalArgumentException("Resource of type " + resourceTypeName + " not supported"); + + Response response = getResource().path(resourceTypeName).path(id).request().accept(Constants.CT_FHIR_JSON_NEW) + .get(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); - if (Status.OK.getStatusCode() == response.getStatus()) - return response.readEntity(CapabilityStatement.class); + // TODO remove workaround if HAPI bug fixed + return referenceCleaner.cleanReferenceResourcesIfBundle( + (Resource) response.readEntity(resourceTypeByNames.get(resourceTypeName))); else throw handleError(response); } @Override - public StructureDefinition generateSnapshot(String url) + public <R extends Resource> R read(Class<R> resourceType, String id) { - Objects.requireNonNull(url, "url"); - - Parameters parameters = new Parameters(); - parameters.addParameter().setName("url").setValue(new UriType(url)); + Objects.requireNonNull(resourceType, "resourceType"); + Objects.requireNonNull(id, "id"); - Response response = getResource().path(StructureDefinition.class.getAnnotation(ResourceDef.class).name()) - .path("$snapshot").request().accept(Constants.CT_FHIR_JSON_NEW) - .post(Entity.entity(parameters, Constants.CT_FHIR_JSON_NEW)); + Response response = getResource().path(resourceType.getAnnotation(ResourceDef.class).name()).path(id).request() + .accept(Constants.CT_FHIR_JSON_NEW).get(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); if (Status.OK.getStatusCode() == response.getStatus()) - return response.readEntity(StructureDefinition.class); + // TODO remove workaround if HAPI bug fixed + return referenceCleaner.cleanReferenceResourcesIfBundle(response.readEntity(resourceType)); else throw handleError(response); } @Override - public StructureDefinition generateSnapshot(StructureDefinition differential) + public <R extends Resource> boolean exists(Class<R> resourceType, String id) { - Objects.requireNonNull(differential, "differential"); - - Parameters parameters = new Parameters(); - parameters.addParameter().setName("resource").setResource(differential); + Objects.requireNonNull(resourceType, "resourceType"); + Objects.requireNonNull(id, "id"); - Response response = getResource().path(StructureDefinition.class.getAnnotation(ResourceDef.class).name()) - .path("$snapshot").request().accept(Constants.CT_FHIR_JSON_NEW) - .post(Entity.entity(parameters, Constants.CT_FHIR_JSON_NEW)); + Response response = getResource().path(resourceType.getAnnotation(ResourceDef.class).name()).path(id).request() + .accept(Constants.CT_FHIR_JSON_NEW).head(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); if (Status.OK.getStatusCode() == response.getStatus()) - return response.readEntity(StructureDefinition.class); + return true; + else if (Status.NOT_FOUND.getStatusCode() == response.getStatus()) + return false; else throw handleError(response); } @Override - public <R extends Resource> R read(Class<R> resourceType, String id) + public InputStream readBinary(String id, MediaType mediaType) { - Objects.requireNonNull(resourceType, "resourceType"); Objects.requireNonNull(id, "id"); + Objects.requireNonNull(mediaType, "mediaType"); - Response response = getResource().path(resourceType.getAnnotation(ResourceDef.class).name()).path(id).request() - .accept(Constants.CT_FHIR_JSON_NEW).get(); + Response response = getResource().path("Binary").path(id).request().accept(mediaType).get(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); if (Status.OK.getStatusCode() == response.getStatus()) - // TODO remove workaround if HAPI bug fixed - return fixBundle(response.readEntity(resourceType)); + return response.readEntity(InputStream.class); else throw handleError(response); } @Override - public <R extends Resource> R read(Class<R> resourceType, String id, String version) + public Resource read(String resourceTypeName, String id, String version) { - Objects.requireNonNull(resourceType, "resourceType"); + Objects.requireNonNull(resourceTypeName, "resourceTypeName"); Objects.requireNonNull(id, "id"); Objects.requireNonNull(version, "version"); + if (!resourceTypeByNames.containsKey(resourceTypeName)) + throw new IllegalArgumentException("Resource of type " + resourceTypeName + " not supported"); - Response response = getResource().path(resourceType.getAnnotation(ResourceDef.class).name()).path(id) - .path("_history").path(version).request().accept(Constants.CT_FHIR_JSON_NEW).get(); + Response response = getResource().path(resourceTypeName).path(id).path("_history").path(version).request() + .accept(Constants.CT_FHIR_JSON_NEW).get(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); if (Status.OK.getStatusCode() == response.getStatus()) // TODO remove workaround if HAPI bug fixed - return fixBundle(response.readEntity(resourceType)); + return referenceCleaner.cleanReferenceResourcesIfBundle( + (Resource) response.readEntity(resourceTypeByNames.get(resourceTypeName))); else throw handleError(response); } @Override - public Resource read(String resourceTypeName, String id) + public <R extends Resource> R read(Class<R> resourceType, String id, String version) { - Objects.requireNonNull(resourceTypeName, "resourceTypeName"); + Objects.requireNonNull(resourceType, "resourceType"); Objects.requireNonNull(id, "id"); - if (!resourceTypeByNames.containsKey(resourceTypeName)) - throw new IllegalArgumentException("Resource of type " + resourceTypeName + " not supported"); + Objects.requireNonNull(version, "version"); - Response response = getResource().path(resourceTypeName).path(id).request().accept(Constants.CT_FHIR_JSON_NEW) - .get(); + Response response = getResource().path(resourceType.getAnnotation(ResourceDef.class).name()).path(id) + .path("_history").path(version).request().accept(Constants.CT_FHIR_JSON_NEW).get(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); if (Status.OK.getStatusCode() == response.getStatus()) // TODO remove workaround if HAPI bug fixed - return fixBundle((Resource) response.readEntity(resourceTypeByNames.get(resourceTypeName))); + return referenceCleaner.cleanReferenceResourcesIfBundle(response.readEntity(resourceType)); else throw handleError(response); - } @Override - public Resource read(String resourceTypeName, String id, String version) + public <R extends Resource> boolean exists(Class<R> resourceType, String id, String version) { - Objects.requireNonNull(resourceTypeName, "resourceTypeName"); + Objects.requireNonNull(resourceType, "resourceType"); Objects.requireNonNull(id, "id"); Objects.requireNonNull(version, "version"); - if (!resourceTypeByNames.containsKey(resourceTypeName)) - throw new IllegalArgumentException("Resource of type " + resourceTypeName + " not supported"); - Response response = getResource().path(resourceTypeName).path(id).path("_history").path(version).request() - .accept(Constants.CT_FHIR_JSON_NEW).get(); + Response response = getResource().path(resourceType.getAnnotation(ResourceDef.class).name()).path(id) + .path("_history").path(version).request().accept(Constants.CT_FHIR_JSON_NEW).head(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); if (Status.OK.getStatusCode() == response.getStatus()) - // TODO remove workaround if HAPI bug fixed - return fixBundle((Resource) response.readEntity(resourceTypeByNames.get(resourceTypeName))); + return true; + else if (Status.NOT_FOUND.getStatusCode() == response.getStatus()) + return false; else throw handleError(response); } @Override - public <R extends Resource> boolean exists(Class<R> resourceType, String id) + public InputStream readBinary(String id, String version, MediaType mediaType) { - Objects.requireNonNull(resourceType, "resourceType"); Objects.requireNonNull(id, "id"); + Objects.requireNonNull(version, "version"); + Objects.requireNonNull(mediaType, "mediaType"); - Response response = getResource().path(resourceType.getAnnotation(ResourceDef.class).name()).path(id).request() - .accept(Constants.CT_FHIR_JSON_NEW).head(); + Response response = getResource().path("Binary").path(id).path("_history").path(version).request() + .accept(mediaType).get(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); if (Status.OK.getStatusCode() == response.getStatus()) - return true; - else if (Status.NOT_FOUND.getStatusCode() == response.getStatus()) - return false; + return response.readEntity(InputStream.class); else throw handleError(response); } @@ -474,46 +734,31 @@ else if (Status.NOT_FOUND.getStatusCode() == response.getStatus()) throw handleError(response); } - // FIXME bug in HAPI framework - private <R extends Resource> R fixBundle(R readEntity) - { - if (readEntity instanceof Bundle) - { - Bundle b = (Bundle) readEntity; - b.getEntry().stream().map(e -> e.getResource()).forEach(this::fix); - } - - return readEntity; - } - - private void fix(Resource resource) - { - Stream<ResourceReference> references = referenceExtractor.getReferences(resource); - references.forEach(r -> r.getReference().setResource(null)); - } - @Override - public <R extends Resource> boolean exists(Class<R> resourceType, String id, String version) + public Bundle search(Class<? extends Resource> resourceType, Map<String, List<String>> parameters) { Objects.requireNonNull(resourceType, "resourceType"); - Objects.requireNonNull(id, "id"); - Objects.requireNonNull(version, "version"); - Response response = getResource().path(resourceType.getAnnotation(ResourceDef.class).name()).path(id) - .path("_history").path(version).request().accept(Constants.CT_FHIR_JSON_NEW).head(); + WebTarget target = getResource().path(resourceType.getAnnotation(ResourceDef.class).name()); + if (parameters != null) + { + for (Entry<String, List<String>> entry : parameters.entrySet()) + target = target.queryParam(entry.getKey(), entry.getValue().toArray()); + } + + Response response = target.request().accept(Constants.CT_FHIR_JSON_NEW).get(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); if (Status.OK.getStatusCode() == response.getStatus()) - return true; - else if (Status.NOT_FOUND.getStatusCode() == response.getStatus()) - return false; + // TODO remove workaround if HAPI bug fixed + return referenceCleaner.cleanReferenceResourcesIfBundle(response.readEntity(Bundle.class)); else throw handleError(response); } @Override - public <R extends Resource> Bundle search(Class<R> resourceType, Map<String, List<String>> parameters) + public Bundle searchWithStrictHandling(Class<? extends Resource> resourceType, Map<String, List<String>> parameters) { Objects.requireNonNull(resourceType, "resourceType"); @@ -524,44 +769,70 @@ public <R extends Resource> Bundle search(Class<R> resourceType, Map<String, Lis target = target.queryParam(entry.getKey(), entry.getValue().toArray()); } - Response response = target.request().accept(Constants.CT_FHIR_JSON_NEW).get(); + Response response = target.request().header(Constants.HEADER_PREFER, PreferHandlingType.STRICT.getHeaderValue()) + .accept(Constants.CT_FHIR_JSON_NEW).get(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); if (Status.OK.getStatusCode() == response.getStatus()) - return response.readEntity(Bundle.class); + // TODO remove workaround if HAPI bug fixed + return referenceCleaner.cleanReferenceResourcesIfBundle(response.readEntity(Bundle.class)); else throw handleError(response); } @Override - public Bundle postBundle(Bundle bundle) + public CapabilityStatement getConformance() { - Objects.requireNonNull(bundle, "bundle"); - - Response response = getResource().request().accept(Constants.CT_FHIR_JSON_NEW) - .post(Entity.entity(bundle, Constants.CT_FHIR_JSON_NEW)); + Response response = getResource().path("metadata").request() + .accept(Constants.CT_FHIR_JSON_NEW + "; fhirVersion=4.0").get(); logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), response.getStatusInfo().getReasonPhrase()); - logger.debug("HTTP header Location: {}", response.getLocation()); - logger.debug("HTTP header ETag: {}", response.getHeaderString(HttpHeaders.ETAG)); - logger.debug("HTTP header Last-Modified: {}", response.getHeaderString(HttpHeaders.LAST_MODIFIED)); if (Status.OK.getStatusCode() == response.getStatus()) - return response.readEntity(Bundle.class); + return response.readEntity(CapabilityStatement.class); else throw handleError(response); } - private String toString(OperationOutcome outcome) + @Override + public StructureDefinition generateSnapshot(String url) { - return outcome == null ? "" - : outcome.getIssue().stream().map(i -> toString(i)).collect(Collectors.joining("\n")); + Objects.requireNonNull(url, "url"); + + Parameters parameters = new Parameters(); + parameters.addParameter().setName("url").setValue(new UriType(url)); + + Response response = getResource().path(StructureDefinition.class.getAnnotation(ResourceDef.class).name()) + .path("$snapshot").request().accept(Constants.CT_FHIR_JSON_NEW) + .post(Entity.entity(parameters, Constants.CT_FHIR_JSON_NEW)); + + logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), + response.getStatusInfo().getReasonPhrase()); + if (Status.OK.getStatusCode() == response.getStatus()) + return response.readEntity(StructureDefinition.class); + else + throw handleError(response); } - private String toString(OperationOutcomeIssueComponent issue) + @Override + public StructureDefinition generateSnapshot(StructureDefinition differential) { - return issue == null ? "" : issue.getSeverity() + " " + issue.getCode() + " " + issue.getDiagnostics(); + Objects.requireNonNull(differential, "differential"); + + Parameters parameters = new Parameters(); + parameters.addParameter().setName("resource").setResource(differential); + + Response response = getResource().path(StructureDefinition.class.getAnnotation(ResourceDef.class).name()) + .path("$snapshot").request().accept(Constants.CT_FHIR_JSON_NEW) + .post(Entity.entity(parameters, Constants.CT_FHIR_JSON_NEW)); + + logger.debug("HTTP {}: {}", response.getStatusInfo().getStatusCode(), + response.getStatusInfo().getReasonPhrase()); + if (Status.OK.getStatusCode() == response.getStatus()) + return response.readEntity(StructureDefinition.class); + else + throw handleError(response); } } diff --git a/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturn.java b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturn.java new file mode 100644 index 000000000..23ab42c68 --- /dev/null +++ b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturn.java @@ -0,0 +1,51 @@ +package org.highmed.fhir.client; + +import java.net.URI; + +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.OperationOutcome; +import org.hl7.fhir.r4.model.Resource; + +public class PreferReturn +{ + private final IdType id; + private final Resource resource; + private final OperationOutcome operationOutcome; + + private PreferReturn(IdType id, Resource resource, OperationOutcome operationOutcome) + { + this.id = id; + this.resource = resource; + this.operationOutcome = operationOutcome; + } + + public static PreferReturn minimal(URI location) + { + return new PreferReturn(new IdType(location.toString()), null, null); + } + + public static PreferReturn resource(Resource resource) + { + return new PreferReturn(null, resource, null); + } + + public static PreferReturn outcome(OperationOutcome operationOutcome) + { + return new PreferReturn(null, null, operationOutcome); + } + + public IdType getId() + { + return id; + } + + public Resource getResource() + { + return resource; + } + + public OperationOutcome getOperationOutcome() + { + return operationOutcome; + } +} diff --git a/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturnMinimal.java b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturnMinimal.java new file mode 100644 index 000000000..8215fc966 --- /dev/null +++ b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturnMinimal.java @@ -0,0 +1,28 @@ +package org.highmed.fhir.client; + +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.MediaType; + +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Resource; + +public interface PreferReturnMinimal +{ + IdType create(Resource resource); + + IdType createConditionaly(Resource resource, String ifNoneExistCriteria); + + IdType createBinary(InputStream in, MediaType mediaType, String securityContextReference); + + IdType update(Resource resource); + + IdType updateConditionaly(Resource resource, Map<String, List<String>> criteria); + + IdType updateBinary(String id, InputStream in, MediaType mediaType, String securityContextReference); + + Bundle postBundle(Bundle bundle); +} \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturnOutcome.java b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturnOutcome.java new file mode 100644 index 000000000..ec3864a9a --- /dev/null +++ b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturnOutcome.java @@ -0,0 +1,30 @@ +package org.highmed.fhir.client; + +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.MediaType; + +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.OperationOutcome; +import org.hl7.fhir.r4.model.Resource; + +public interface PreferReturnOutcome +{ + OperationOutcome create(Resource resource); + + OperationOutcome createConditionaly(Resource resource, String ifNoneExistCriteria); + + OperationOutcome createBinary(InputStream in, MediaType mediaType, String securityContextReference); + + + OperationOutcome update(Resource resource); + + OperationOutcome updateConditionaly(Resource resource, Map<String, List<String>> criteria); + + OperationOutcome updateBinary(String id, InputStream in, MediaType mediaType, String securityContextReference); + + + Bundle postBundle(Bundle bundle); +} \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturnResource.java b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturnResource.java new file mode 100644 index 000000000..76f321431 --- /dev/null +++ b/dsf-fhir/dsf-fhir-webservice-client/src/main/java/org/highmed/fhir/client/PreferReturnResource.java @@ -0,0 +1,30 @@ +package org.highmed.fhir.client; + +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.MediaType; + +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Resource; + +public interface PreferReturnResource +{ + <R extends Resource> R create(R resource); + + <R extends Resource> R createConditionaly(R resource, String ifNoneExistCriteria); + + Binary createBinary(InputStream in, MediaType mediaType, String securityContextReference); + + + <R extends Resource> R update(R resource); + + <R extends Resource> R updateConditionaly(R resource, Map<String, List<String>> criteria); + + Binary updateBinary(String id, InputStream in, MediaType mediaType, String securityContextReference); + + + Bundle postBundle(Bundle bundle); +} \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-webservice-client/src/test/java/org/highmed/fhir/client/TestFhirJerseyClient.java b/dsf-fhir/dsf-fhir-webservice-client/src/test/java/org/highmed/fhir/client/TestFhirJerseyClient.java index df1e1b8af..4b1917bdb 100755 --- a/dsf-fhir/dsf-fhir-webservice-client/src/test/java/org/highmed/fhir/client/TestFhirJerseyClient.java +++ b/dsf-fhir/dsf-fhir-webservice-client/src/test/java/org/highmed/fhir/client/TestFhirJerseyClient.java @@ -12,7 +12,8 @@ import javax.ws.rs.WebApplicationException; -import org.highmed.dsf.fhir.service.ReferenceExtractor; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.ReferenceCleanerImpl; import org.highmed.dsf.fhir.service.ReferenceExtractorImpl; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleType; @@ -35,14 +36,15 @@ public static void main(String[] args) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { char[] keyStorePassword = "password".toCharArray(); - KeyStore keyStore = CertificateReader.fromPkcs12( - Paths.get("../../dsf-tools/dsf-tools-test-data-generator/cert/Webbrowser_Test_User/Webbrowser_Test_User_certificate.p12"), keyStorePassword); + KeyStore keyStore = CertificateReader.fromPkcs12(Paths.get( + "../../dsf-tools/dsf-tools-test-data-generator/cert/Webbrowser_Test_User/Webbrowser_Test_User_certificate.p12"), + keyStorePassword); KeyStore trustStore = CertificateHelper.extractTrust(keyStore); FhirContext context = FhirContext.forR4(); - ReferenceExtractor referenceExtractor = new ReferenceExtractorImpl(); - FhirWebserviceClient client = new FhirWebserviceClientJersey("https://localhost:8001/fhir/", trustStore, keyStore, - keyStorePassword, null, null, null, 0, 0, null, context, referenceExtractor); + ReferenceCleaner referenceCleaner = new ReferenceCleanerImpl(new ReferenceExtractorImpl()); + FhirWebserviceClient client = new FhirWebserviceClientJersey("https://localhost:8001/fhir/", trustStore, + keyStore, keyStorePassword, null, null, null, 0, 0, null, context, referenceCleaner); try { diff --git a/dsf-fhir/dsf-fhir-websocket-client/pom.xml b/dsf-fhir/dsf-fhir-websocket-client/pom.xml index b2867754a..18b193492 100755 --- a/dsf-fhir/dsf-fhir-websocket-client/pom.xml +++ b/dsf-fhir/dsf-fhir-websocket-client/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-fhir-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> diff --git a/dsf-fhir/dsf-fhir-websocket-client/src/main/java/org/highmed/fhir/client/ClientEndpoint.java b/dsf-fhir/dsf-fhir-websocket-client/src/main/java/org/highmed/fhir/client/ClientEndpoint.java index 6ed752e1c..057354f67 100755 --- a/dsf-fhir/dsf-fhir-websocket-client/src/main/java/org/highmed/fhir/client/ClientEndpoint.java +++ b/dsf-fhir/dsf-fhir-websocket-client/src/main/java/org/highmed/fhir/client/ClientEndpoint.java @@ -6,7 +6,7 @@ import javax.websocket.CloseReason; import javax.websocket.Endpoint; import javax.websocket.EndpointConfig; -import javax.websocket.MessageHandler.Whole; +import javax.websocket.MessageHandler; import javax.websocket.Session; import org.hl7.fhir.r4.model.DomainResource; @@ -19,10 +19,12 @@ public class ClientEndpoint extends Endpoint { private static final Logger logger = LoggerFactory.getLogger(ClientEndpoint.class); + private final Runnable reconnector; private final String subscriptionIdPart; - public ClientEndpoint(String subscriptionIdPart) + public ClientEndpoint(Runnable reconnector, String subscriptionIdPart) { + this.reconnector = reconnector; this.subscriptionIdPart = subscriptionIdPart; } @@ -35,7 +37,7 @@ public void onOpen(Session session, EndpointConfig config) { logger.debug("Websocket onOpen"); - session.addMessageHandler(new Whole<String>() // don't use lambda + session.addMessageHandler(new MessageHandler.Whole<String>() // don't use lambda { private boolean boundReceived; @@ -68,7 +70,7 @@ else if (domainResourceHandler != null && parserFactory != null) } } }); - + session.getAsyncRemote().sendText("bind " + subscriptionIdPart); } @@ -76,6 +78,12 @@ else if (domainResourceHandler != null && parserFactory != null) public void onClose(Session session, CloseReason closeReason) { logger.info("Websocket onClose {}", closeReason.getReasonPhrase()); + + if (CloseReason.CloseCodes.CANNOT_ACCEPT.equals(closeReason.getCloseCode())) + { + logger.info("Trying to reconnect websocket"); + reconnector.run(); + } } @Override diff --git a/dsf-fhir/dsf-fhir-websocket-client/src/main/java/org/highmed/fhir/client/WebsocketClientTyrus.java b/dsf-fhir/dsf-fhir-websocket-client/src/main/java/org/highmed/fhir/client/WebsocketClientTyrus.java index d71503cd0..d4b4070ef 100755 --- a/dsf-fhir/dsf-fhir-websocket-client/src/main/java/org/highmed/fhir/client/WebsocketClientTyrus.java +++ b/dsf-fhir/dsf-fhir-websocket-client/src/main/java/org/highmed/fhir/client/WebsocketClientTyrus.java @@ -52,8 +52,8 @@ public boolean onDisconnect(CloseReason closeReason) private Session connection; private volatile boolean closed; - public WebsocketClientTyrus(URI wsUri, KeyStore trustStore, KeyStore keyStore, char[] keyStorePassword, - String subscriptionIdPart) + public WebsocketClientTyrus(Runnable reconnector, URI wsUri, KeyStore trustStore, KeyStore keyStore, + char[] keyStorePassword, String subscriptionIdPart) { this.wsUri = wsUri; @@ -65,7 +65,16 @@ else if (trustStore != null && keyStore != null && keyStorePassword != null) else sslContext = SslConfigurator.getDefaultContext(); - this.endpoint = new ClientEndpoint(subscriptionIdPart); + this.endpoint = createClientEndpoint(reconnector, subscriptionIdPart); + } + + private ClientEndpoint createClientEndpoint(Runnable reconnector, String subscriptionIdPart) + { + return new ClientEndpoint(() -> + { + disconnect(); + reconnector.run(); + }, subscriptionIdPart); } @Override diff --git a/dsf-fhir/dsf-fhir-websocket-client/src/test/java/org/highmed/fhir/client/TestFhirWebsocketClient.java b/dsf-fhir/dsf-fhir-websocket-client/src/test/java/org/highmed/fhir/client/TestFhirWebsocketClient.java index 99ee8ec8e..dfc69cf6e 100755 --- a/dsf-fhir/dsf-fhir-websocket-client/src/test/java/org/highmed/fhir/client/TestFhirWebsocketClient.java +++ b/dsf-fhir/dsf-fhir-websocket-client/src/test/java/org/highmed/fhir/client/TestFhirWebsocketClient.java @@ -30,7 +30,7 @@ public static void main(String[] args) FhirContext fhirContext = FhirContext.forR4(); - WebsocketClientTyrus client = new WebsocketClientTyrus(URI.create("wss://localhost:8443/fhir/ws"), trustStore, + WebsocketClientTyrus client = new WebsocketClientTyrus(() -> {}, URI.create("wss://localhost:8443/fhir/ws"), trustStore, keyStore, keyStorePassword, "f4243759-47c7-4344-a030-94ef039bbd4f"); // WebsocketClientTyrus client = new WebsocketClientTyrus(fhirContext, // URI.create("wss://localhost:8001/fhir/ws"), diff --git a/dsf-fhir/pom.xml b/dsf-fhir/pom.xml index d1c691957..38615e748 100755 --- a/dsf-fhir/pom.xml +++ b/dsf-fhir/pom.xml @@ -8,7 +8,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <modules> diff --git a/dsf-mpi/.gitignore b/dsf-mpi/.gitignore new file mode 100644 index 000000000..58c32c89c --- /dev/null +++ b/dsf-mpi/.gitignore @@ -0,0 +1,2 @@ +/.project +/.settings/ diff --git a/dsf-mpi/dsf-mpi-client-pdq/.gitignore b/dsf-mpi/dsf-mpi-client-pdq/.gitignore new file mode 100644 index 000000000..d98981cc4 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.classpath +/.project +/.settings/ diff --git a/dsf-mpi/dsf-mpi-client-pdq/pom.xml b/dsf-mpi/dsf-mpi-client-pdq/pom.xml new file mode 100644 index 000000000..d7f859169 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/pom.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <artifactId>dsf-mpi-client-pdq</artifactId> + + <parent> + <artifactId>dsf-mpi-pom</artifactId> + <groupId>org.highmed.dsf</groupId> + <version>0.2.0</version> + </parent> + + <dependencies> + <dependency> + <groupId>org.highmed.dsf</groupId> + <artifactId>dsf-mpi-client</artifactId> + </dependency> + + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-base</artifactId> + </dependency> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-structures-v25</artifactId> + </dependency> + </dependencies> +</project> \ No newline at end of file diff --git a/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/idat/IdatImpl.java b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/idat/IdatImpl.java new file mode 100644 index 000000000..46ec8bdf3 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/idat/IdatImpl.java @@ -0,0 +1,100 @@ +package org.highmed.mpi.client.idat; + +import org.highmed.mpi.client.Idat; + +public class IdatImpl implements Idat +{ + private final String medicId; + private final String firstName; + private final String lastName; + private final String birthday; + private final String sex; + private final String street; + private final String zipCode; + private final String city; + private final String country; + private final String insuranceNumber; + + public IdatImpl(String medicId, String firstName, String lastName, String birthday, String sex, String street, + String zipCode, String city, String country, String insuranceNumber) + { + this.medicId = medicId; + this.firstName = firstName; + this.lastName = lastName; + this.birthday = birthday; + this.sex = sex; + this.street = street; + this.zipCode = zipCode; + this.city = city; + this.country = country; + this.insuranceNumber = insuranceNumber; + } + + @Override + public String getMedicId() + { + return medicId; + } + + @Override + public String getFirstName() + { + return firstName; + } + + @Override + public String getLastName() + { + return lastName; + } + + @Override + public String getBirthday() + { + return birthday; + } + + @Override + public String getSex() + { + return sex; + } + + @Override + public String getStreet() + { + return street; + } + + @Override + public String getZipCode() + { + return zipCode; + } + + @Override + public String getCity() + { + return city; + } + + @Override + public String getCountry() + { + return country; + } + + @Override + public String getInsuranceNumber() + { + return insuranceNumber; + } + + @Override + public String toString() + { + return "IDAT[medicId=" + medicId + ", firstname=" + firstName + ", lastname=" + lastName + ", birthdate=" + + birthday + ", sex=" + sex + ", street=" + street + ", zip=" + zipCode + ", city=" + city + ", country=" + + country + ", ssn=" + insuranceNumber + "]"; + } +} diff --git a/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/message/MessageHelper.java b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/message/MessageHelper.java new file mode 100644 index 000000000..666e26501 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/message/MessageHelper.java @@ -0,0 +1,156 @@ +package org.highmed.mpi.client.message; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.highmed.mpi.client.Idat; +import org.highmed.mpi.client.idat.IdatImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.hl7v2.HL7Exception; + +import ca.uhn.hl7v2.model.v25.datatype.CX; +import ca.uhn.hl7v2.model.v25.datatype.DTM; +import ca.uhn.hl7v2.model.v25.datatype.HD; +import ca.uhn.hl7v2.model.v25.datatype.MSG; +import ca.uhn.hl7v2.model.v25.datatype.XAD; +import ca.uhn.hl7v2.model.v25.datatype.XPN; +import ca.uhn.hl7v2.model.v25.group.RSP_K21_QUERY_RESPONSE; +import ca.uhn.hl7v2.model.v25.message.QBP_Q21; +import ca.uhn.hl7v2.model.v25.message.RSP_K21; +import ca.uhn.hl7v2.model.v25.segment.ERR; +import ca.uhn.hl7v2.model.v25.segment.MSH; +import ca.uhn.hl7v2.model.v25.segment.PID; +import ca.uhn.hl7v2.model.v25.segment.QPD; +import ca.uhn.hl7v2.model.v25.segment.RCP; +import ca.uhn.hl7v2.util.Terser; + +public class MessageHelper +{ + private static final Logger logger = LoggerFactory.getLogger(MessageHelper.class); + + public QBP_Q21 createPatientDemographicsQuery(String senderApplication, String senderFacility, + String receiverApplication, String receiverFacility, List<QueryParameter> searchParameters) throws HL7Exception + { + QBP_Q21 qbp_q21 = new QBP_Q21(); + + MSH msh = qbp_q21.getMSH(); + msh.getMsh1_FieldSeparator().setValue(""); + msh.getMsh2_EncodingCharacters().setValue("^~\\&"); + msh.getMsh3_SendingApplication().getNamespaceID().setValue(senderApplication); + msh.getMsh4_SendingFacility().getNamespaceID().setValue(senderFacility); + msh.getMsh5_ReceivingApplication().getNamespaceID().setValue(receiverApplication); + msh.getMsh6_ReceivingFacility().getNamespaceID().setValue(receiverFacility); + msh.getMsh7_DateTimeOfMessage().getTime().setValue(new Date()); + + MSG messageType = msh.getMsh9_MessageType(); + messageType.getMsg1_MessageCode().setValue("QBP"); + messageType.getMsg2_TriggerEvent().setValue("Q22"); + messageType.getMsg3_MessageStructure().setValue("QBP_Q21"); + + msh.getMsh10_MessageControlID().setValue("607@1.3.6.1.4.1.21367.2009.1.2.136.1.13.1.1.7.2.696777"); + + msh.getMsh11_ProcessingID().getPt1_ProcessingID().setValue("P"); + msh.getMsh11_ProcessingID().getPt2_ProcessingMode().setValue("T"); + + msh.getMsh12_VersionID().getVid1_VersionID().setValue("2.5"); + + QPD qpd = qbp_q21.getQPD(); + qpd.getQpd1_MessageQueryName().getIdentifier().setValue("IHE PDQ Query"); + qpd.getQpd2_QueryTag().setValue(UUID.randomUUID().toString()); + + RCP rcp = qbp_q21.getRCP(); + rcp.getRcp1_QueryPriority().setValue("I"); + + Terser terser = new Terser(qbp_q21); + + for (int i = 0; i < searchParameters.size(); i++) + { + terser.set("/QPD-3(" + i + ")-1", searchParameters.get(i).getField()); + terser.set("/QPD-3(" + i + ")-2", searchParameters.get(i).getValue()); + } + + return qbp_q21; + } + + public Idat extractPatientDemographics(RSP_K21 patientDemographicsQueryResult, + String pidAssigningAuthorityNamespaceId, String pidAssigningAuthorityUniversalId) throws Exception + { + ERR error = patientDemographicsQueryResult.getERR(); + + if (error.getHL7ErrorCode().getIdentifier().getValue() != null) + { + String errorMessage = error.getUserMessage().getValueOrEmpty(); + logger.warn("Could not retrieve IDAT, error in Patient Demographics Query result='{}'", errorMessage); + throw new RuntimeException("Could not retrieve IDAT, error in Patient Demographics Query result:" + errorMessage); + } + + List<RSP_K21_QUERY_RESPONSE> idats = patientDemographicsQueryResult.getQUERY_RESPONSEAll(); + String query = patientDemographicsQueryResult.getQPD().getUserParametersInsuccessivefields().encode(); + + if (idats.size() == 0) + { + logger.warn("Did not find any demographic data for query='{}'", query); + throw new RuntimeException("Did not find any demographic data for query='" + query + "'"); + } + + if (idats.size() > 1) + { + logger.warn("Found more than 1 demographic data result, using the first of query='{}'", query); + } + + PID pid = idats.get(0).getPID(); + + String patientId = null; + for (CX identifier : pid.getPatientIdentifierList()) + { + HD assigningAuthority = identifier.getAssigningAuthority(); + + if (assigningAuthority.getNamespaceID().getValue().equals(pidAssigningAuthorityNamespaceId) + && assigningAuthority.getUniversalID().getValue().equals(pidAssigningAuthorityUniversalId)) + { + patientId = identifier.getIDNumber().getValue(); + } + } + + if (patientId == null) + { + logger.warn("Could not find patient id from response of query='{}'", query); + throw new RuntimeException("Could not find patient id from response of query='" + query + "'"); + } + + XPN[] patientNames = pid.getPatientName(); + String firstname = "", lastname = ""; + + if (patientNames.length > 0) + { + XPN patientName = patientNames[0]; + firstname = patientName.getGivenName().getValue(); + lastname = patientName.getFamilyName().getSurname().getValue(); + } + + DTM birthDtm = pid.getDateTimeOfBirth().getTime(); + String birthdate = birthDtm.getDay() + "." + birthDtm.getMonth() + "." + birthDtm.getYear(); + + String sex = pid.getAdministrativeSex().getValue(); + + XAD[] patientAddresses = pid.getPatientAddress(); + String street = "", zipCode = "", city = "", country = ""; + + if (patientAddresses.length > 0) + { + XAD patientAddress = patientAddresses[0]; + street = patientAddress.getStreetAddress().getStreetOrMailingAddress().getValue(); + zipCode = patientAddress.getZipOrPostalCode().getValue(); + city = patientAddress.getCity().getValue(); + country = patientAddress.getCountry().getValue(); + } + + String insuranceNumber = pid.getSSNNumberPatient().getValue(); + + return new IdatImpl(patientId, firstname, lastname, birthdate, sex, street, zipCode, city, country, + insuranceNumber); + } +} diff --git a/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/message/QueryParameter.java b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/message/QueryParameter.java new file mode 100644 index 000000000..1aeb51397 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/message/QueryParameter.java @@ -0,0 +1,23 @@ +package org.highmed.mpi.client.message; + +public class QueryParameter +{ + private final String field; + private final String value; + + public QueryParameter(String field, String value) + { + this.field = field; + this.value = value; + } + + public String getField() + { + return field; + } + + public String getValue() + { + return value; + } +} diff --git a/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/pdq/AbstractHl7v2Client.java b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/pdq/AbstractHl7v2Client.java new file mode 100644 index 000000000..7d6f0a71a --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/pdq/AbstractHl7v2Client.java @@ -0,0 +1,60 @@ +package org.highmed.mpi.client.pdq; + +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.hl7v2.HL7Exception; +import ca.uhn.hl7v2.HapiContext; +import ca.uhn.hl7v2.app.Connection; +import ca.uhn.hl7v2.llp.LLPException; +import ca.uhn.hl7v2.model.Message; +import ca.uhn.hl7v2.util.SocketFactory; +import ca.uhn.hl7v2.util.Terser; + +public abstract class AbstractHl7v2Client +{ + private static final Logger logger = LoggerFactory.getLogger(AbstractHl7v2Client.class); + + private final String host; + private final boolean useTLS; + + private final HapiContext context; + + protected AbstractHl7v2Client(String host, HapiContext context, SocketFactory socketFactory) + { + this.host = host; + this.context = context; + + if (socketFactory != null) + { + this.useTLS = true; + context.setSocketFactory(socketFactory); + } + else + { + this.useTLS = false; + } + } + + protected Message send(int port, Message request) throws HL7Exception, LLPException, IOException + { + Terser terser = new Terser(request); + String messageType = terser.get("/MSH-9-1") + "^" + terser.get("/MSH-9-2"); + String destination = host + ":" + port; + logger.debug("Sending message of type {} to {}", messageType, destination); + + Connection connection = null; + try + { + connection = context.newClient(host, port, useTLS); + return connection.getInitiator().sendAndReceive(request); + } + finally + { + if(connection != null) + connection.close(); + } + } +} diff --git a/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/pdq/MasterPatientIndexClientPdq.java b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/pdq/MasterPatientIndexClientPdq.java new file mode 100644 index 000000000..c0a7c90fb --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/pdq/MasterPatientIndexClientPdq.java @@ -0,0 +1,79 @@ +package org.highmed.mpi.client.pdq; + +import java.util.List; + +import org.highmed.mpi.client.Idat; +import org.highmed.mpi.client.IdatNotFoundException; +import org.highmed.mpi.client.MasterPatientIndexClient; +import org.highmed.mpi.client.message.MessageHelper; +import org.highmed.mpi.client.message.QueryParameter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.hl7v2.HapiContext; +import ca.uhn.hl7v2.model.v25.message.QBP_Q21; +import ca.uhn.hl7v2.model.v25.message.RSP_K21; +import ca.uhn.hl7v2.util.SocketFactory; + +public class MasterPatientIndexClientPdq extends AbstractHl7v2Client implements MasterPatientIndexClient +{ + private static final Logger logger = LoggerFactory.getLogger(MasterPatientIndexClientPdq.class); + + private final int port; + + private final String senderApplication; + private final String senderFacility; + private final String receiverApplication; + private final String receiverFacility; + + private final String pidAssigningAuthorityNamespaceId; + private final String pidAssigningAuthorityUniversalId; + + private final MessageHelper messageHelper; + + protected MasterPatientIndexClientPdq(String host, int port, String senderApplication, String senderFacility, + String receiverApplication, String receiverFacility, String pidAssigningAuthorityNamespaceId, + String pidAssigningAuthorityUniversalId, MessageHelper messageHelper, HapiContext context, + SocketFactory socketFactory) + { + super(host, context, socketFactory); + this.port = port; + + this.senderApplication = senderApplication; + this.senderFacility = senderFacility; + this.receiverApplication = receiverApplication; + this.receiverFacility = receiverFacility; + + this.pidAssigningAuthorityNamespaceId = pidAssigningAuthorityNamespaceId; + this.pidAssigningAuthorityUniversalId = pidAssigningAuthorityUniversalId; + + this.messageHelper = messageHelper; + } + + @Override + public Idat fetchIdat(String ehrId) throws IdatNotFoundException + { + List<QueryParameter> searchParameters = List.of(new QueryParameter("@PID.3.1", ehrId), + new QueryParameter("@PID.3.4.1", pidAssigningAuthorityNamespaceId), + new QueryParameter("@PID.3.4.2", pidAssigningAuthorityUniversalId)); + + try + { + QBP_Q21 request = messageHelper.createPatientDemographicsQuery(senderApplication, senderFacility, + receiverApplication, receiverFacility, searchParameters); + + RSP_K21 response = (RSP_K21) send(port, request); + + Idat idat = messageHelper.extractPatientDemographics(response, pidAssigningAuthorityNamespaceId, + pidAssigningAuthorityUniversalId); + + logger.debug("Found IDAT of EHR-ID='{}", ehrId); + return idat; + } + catch (Exception exception) + { + logger.warn("Could not get IDAT of EHR-ID='{}', reason: {}", ehrId, exception.getMessage()); + throw new IdatNotFoundException(exception); + } + } +} diff --git a/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/pdq/MasterPatientIndexClientPdqFactory.java b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/pdq/MasterPatientIndexClientPdqFactory.java new file mode 100644 index 000000000..0840b5600 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/pdq/MasterPatientIndexClientPdqFactory.java @@ -0,0 +1,43 @@ +package org.highmed.mpi.client.pdq; + +import java.util.function.Function; + +import org.highmed.mpi.client.MasterPatientIndexClient; +import org.highmed.mpi.client.MasterPatientIndexClientFactory; +import org.highmed.mpi.client.message.MessageHelper; +import org.highmed.mpi.client.security.CustomSocketFactory; +import org.highmed.mpi.client.security.CustomSslFactory; + +import ca.uhn.hl7v2.DefaultHapiContext; +import ca.uhn.hl7v2.HapiContext; +import ca.uhn.hl7v2.util.SocketFactory; + +public class MasterPatientIndexClientPdqFactory implements MasterPatientIndexClientFactory +{ + @Override + public MasterPatientIndexClient createClient(Function<String, String> propertyResolver) + { + String host = propertyResolver.apply("org.highmed.dsf.bpe.mpi.pdq.webservice.host"); + int port = Integer.parseInt(propertyResolver.apply("org.highmed.dsf.bpe.mpi.pdq.webservice.port")); + String keystorePath = propertyResolver.apply("org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.path"); + String keystorePassword = propertyResolver.apply("org.highmed.dsf.bpe.mpi.pdq.webservice.keystore.password"); + + String senderApplication = propertyResolver.apply("org.highmed.dsf.bpe.mpi.pdq.sender.application"); + String senderFacility = propertyResolver.apply("org.highmed.dsf.bpe.mpi.pdq.sender.facility"); + String receiverApplication = propertyResolver.apply("org.highmed.dsf.bpe.mpi.pdq.receiver.application"); + String receiverFacility = propertyResolver.apply("org.highmed.dsf.bpe.mpi.pdq.receiver.facility"); + + String pidAssigningAuthorityNamespaceId = propertyResolver.apply("org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.namespaceId"); + String pidAssigningAuthorityUniversalId = propertyResolver.apply("org.highmed.dsf.bpe.mpi.pdq.assigningAuthority.universalId"); + + MessageHelper messageHelper = new MessageHelper(); + HapiContext context = new DefaultHapiContext(); + + CustomSslFactory sslFactory = new CustomSslFactory(); + SocketFactory socketFactory = new CustomSocketFactory(keystorePath, keystorePassword, sslFactory); + + return new MasterPatientIndexClientPdq(host, port, senderApplication, + senderFacility, receiverApplication, receiverFacility, pidAssigningAuthorityNamespaceId, + pidAssigningAuthorityUniversalId, messageHelper, context, socketFactory); + } +} diff --git a/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/security/CustomSocketFactory.java b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/security/CustomSocketFactory.java new file mode 100644 index 000000000..ebcac3042 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/security/CustomSocketFactory.java @@ -0,0 +1,81 @@ +package org.highmed.mpi.client.security; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.security.KeyStore; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.hl7v2.util.StandardSocketFactory; + +public class CustomSocketFactory extends StandardSocketFactory +{ + private static final Logger logger = LoggerFactory.getLogger(CustomSocketFactory.class); + + private final String keystorePath; + private final String keystorePassword; + + private final CustomSslFactory customSslFactory; + + /** + * @param keystorePath the path to the .p12 file containing the client certificate, not <code>null</code> + * @param keystorePassword the password of the .p12 file containing the client certificate, not <code>null</code> + * @param customSslFactory the {@link CustomSslFactory} to create the {@link SSLContext} containing + * the client certificate provided in the .p12 file, not <code>null</code> + */ + public CustomSocketFactory(String keystorePath, String keystorePassword, CustomSslFactory customSslFactory) + { + this.keystorePath = keystorePath; + this.keystorePassword = keystorePassword; + this.customSslFactory = customSslFactory; + } + + @Override + public ServerSocket createTlsServerSocket() throws IOException + { + logger.warn("Custom TLS server sockets are not supported, returning default TLS server socket"); + return super.createTlsServerSocket(); + } + + @Override + public Socket createTlsSocket() throws IOException + { + SSLContext sslContext = getSslContext(); + + if (sslContext != null) + { + Socket socket = sslContext.getSocketFactory().createSocket(); + socket.setKeepAlive(false); + socket.setTcpNoDelay(true); + return socket; + } + else + { + logger.warn("Could not create custom socket, returning default socket"); + return super.createTlsSocket(); + } + } + + private SSLContext getSslContext() + { + try + { + KeyStore keystore = customSslFactory.getKeystoreFromP12File(keystorePath, keystorePassword); + KeyManagerFactory keyManagerFactory = customSslFactory.getKeyManagerFactory(keystore, keystorePassword); + TrustManagerFactory trustManagerFactory = customSslFactory.getTrustManagerFactory(null); + + return customSslFactory.getTLSContext(keyManagerFactory, trustManagerFactory); + } + catch (Exception exception) + { + logger.warn("Could not load client certificate, reason: {}", exception.getMessage()); + return null; + } + } +} diff --git a/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/security/CustomSslFactory.java b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/security/CustomSslFactory.java new file mode 100644 index 000000000..8467d6746 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/src/main/java/org/highmed/mpi/client/security/CustomSslFactory.java @@ -0,0 +1,116 @@ +package org.highmed.mpi.client.security; + +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +public class CustomSslFactory +{ + /** + * @param path the path to the keystore file with ending .p12, not <code>null</code> + * @param password the keystore file password, not <code>null</code> + * @return the {@link KeyStore} loaded from the specified file using the specified password + */ + public KeyStore getKeystoreFromP12File(String path, String password) + throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException + { + return getKeyStore(path, password, "PKCS12"); + } + + /** + * @param path the path to the keystore file with ending .jks, not <code>null</code> + * @param password the keystore file password, not <code>null</code> + * @return the {@link KeyStore} loaded from the specified file using the specified password + */ + public KeyStore getKeystoreFromJksFile(String path, String password) + throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException + { + return getKeyStore(path, password, "JKS"); + } + + private KeyStore getKeyStore(String path, String password, String type) + throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException + { + KeyStore keystore = KeyStore.getInstance(type); + keystore.load(new FileInputStream(path), password.toCharArray()); + + return keystore; + } + + /** + * @param keystore the {@link KeyStore}, containing the client certificates, which are loaded into the new + * key manager factory, may be <code>null</code> + * @param password the password for the new key manager factory, not <code>null</code> + * @return the new {@link KeyManagerFactory} based on the provided {@link KeyStore}, if the provided keystore + * is <code>null</code>, an empty {@link KeyManagerFactory} is created with the provided password. + */ + public KeyManagerFactory getKeyManagerFactory(KeyStore keystore, String password) + throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException + { + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keystore, password.toCharArray()); + + return keyManagerFactory; + } + + /** + * @param truststore the truststore as {@link KeyStore}, containing the trusted server certificates, which are + * loaded into the new trust manager factory, may be <code>null</code> + * @return the new {@link TrustManagerFactory} based on the provided truststore, returns the default trust manager + * if the provided truststore is <code>null</code>. + */ + public TrustManagerFactory getTrustManagerFactory(KeyStore truststore) + throws NoSuchAlgorithmException, KeyStoreException + { + TrustManagerFactory trustManagerFactory = TrustManagerFactory + .getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(truststore); + + return trustManagerFactory; + } + + /** + * @param trustManagerFactory the {@link TrustManagerFactory} from which the X509 trust manager should be + * extracted, not <code>null</code> + * @return the {@link X509TrustManager} contained in the provided trust manager factory + */ + public X509TrustManager getTrustManager(TrustManagerFactory trustManagerFactory) + { + X509TrustManager defaultTrustManager = null; + for (TrustManager tm : trustManagerFactory.getTrustManagers()) + { + if (tm instanceof X509TrustManager) + { + defaultTrustManager = (X509TrustManager) tm; + break; + } + } + + return defaultTrustManager; + } + + /** + * @param keyManagerFactory the {@link KeyManagerFactory} containing the client certificates, not <code>null</code> + * @param trustManagerFactory the {@link TrustManagerFactory} containing the trusted server certificates, + * not <code>null</code> + * @return the {@link SSLContext} of type TLS based on the provided key manager factory and trust manager factory + */ + public SSLContext getTLSContext(KeyManagerFactory keyManagerFactory, TrustManagerFactory trustManagerFactory) + throws Exception + { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); + + return sslContext; + } +} \ No newline at end of file diff --git a/dsf-mpi/dsf-mpi-client-pdq/src/main/resources/META-INF/services/org.highmed.mpi.client.MasterPatientIndexClientFactory b/dsf-mpi/dsf-mpi-client-pdq/src/main/resources/META-INF/services/org.highmed.mpi.client.MasterPatientIndexClientFactory new file mode 100644 index 000000000..3c7823549 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-pdq/src/main/resources/META-INF/services/org.highmed.mpi.client.MasterPatientIndexClientFactory @@ -0,0 +1 @@ +org.highmed.mpi.client.pdq.MasterPatientIndexClientPdqFactory \ No newline at end of file diff --git a/dsf-mpi/dsf-mpi-client-stub/.gitignore b/dsf-mpi/dsf-mpi-client-stub/.gitignore new file mode 100644 index 000000000..d98981cc4 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-stub/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.classpath +/.project +/.settings/ diff --git a/dsf-mpi/dsf-mpi-client-stub/pom.xml b/dsf-mpi/dsf-mpi-client-stub/pom.xml new file mode 100644 index 000000000..42499e342 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-stub/pom.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <artifactId>dsf-mpi-client-stub</artifactId> + + <parent> + <artifactId>dsf-mpi-pom</artifactId> + <groupId>org.highmed.dsf</groupId> + <version>0.2.0</version> + </parent> + + <dependencies> + <dependency> + <groupId>org.highmed.dsf</groupId> + <artifactId>dsf-mpi-client</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy</id> + <phase>package</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>${project.groupId}</groupId> + <artifactId>${project.artifactId}</artifactId> + <version>${project.version}</version> + <destFileName>mpi_client_stub.jar</destFileName> + <outputDirectory>../../dsf-bpe/dsf-bpe-server-jetty/plugin</outputDirectory> + </artifactItem> + <artifactItem> + <groupId>${project.groupId}</groupId> + <artifactId>${project.artifactId}</artifactId> + <version>${project.version}</version> + <destFileName>mpi_client_stub.jar</destFileName> + <outputDirectory>../../dsf-bpe/dsf-bpe-server-jetty/docker/plugin</outputDirectory> + </artifactItem> + </artifactItems> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-clean-plugin</artifactId> + <configuration> + <filesets> + <fileset> + <directory>../../dsf-bpe/dsf-bpe-server-jetty/plugin</directory> + <includes> + <include>mpi_client_stub.jar</include> + </includes> + <followSymlinks>false</followSymlinks> + </fileset> + <fileset> + <directory>../../dsf-bpe/dsf-bpe-server-jetty/docker/plugin</directory> + <includes> + <include>mpi_client_stub.jar</include> + </includes> + <followSymlinks>false</followSymlinks> + </fileset> + </filesets> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/dsf-mpi/dsf-mpi-client-stub/src/main/java/org/highmed/mpi/client/stub/MasterPatientIndexClientStub.java b/dsf-mpi/dsf-mpi-client-stub/src/main/java/org/highmed/mpi/client/stub/MasterPatientIndexClientStub.java new file mode 100644 index 000000000..c96d542df --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-stub/src/main/java/org/highmed/mpi/client/stub/MasterPatientIndexClientStub.java @@ -0,0 +1,164 @@ +package org.highmed.mpi.client.stub; + +import java.util.HashMap; +import java.util.Map; + +import org.highmed.mpi.client.Idat; +import org.highmed.mpi.client.IdatNotFoundException; +import org.highmed.mpi.client.MasterPatientIndexClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MasterPatientIndexClientStub implements MasterPatientIndexClient +{ + private static final Logger logger = LoggerFactory.getLogger(MasterPatientIndexClientStub.IdatImpl.class); + + private static final class IdatImpl implements Idat + { + final String medicId; + final String firstName; + final String lastName; + final String birthday; + final String sex; + final String street; + final String zipCode; + final String city; + final String country; + final String insuranceNumber; + + IdatImpl(String medicId, String firstName, String lastName, String birthday, String sex, String street, + String zipCode, String city, String country, String insuranceNumber) + { + this.medicId = medicId; + this.firstName = firstName; + this.lastName = lastName; + this.birthday = birthday; + this.sex = sex; + this.street = street; + this.zipCode = zipCode; + this.city = city; + this.country = country; + this.insuranceNumber = insuranceNumber; + } + + @Override + public String getMedicId() + { + return medicId; + } + + @Override + public String getFirstName() + { + return firstName; + } + + @Override + public String getLastName() + { + return lastName; + } + + @Override + public String getBirthday() + { + return birthday; + } + + @Override + public String getSex() + { + return sex; + } + + @Override + public String getStreet() + { + return street; + } + + @Override + public String getZipCode() + { + return zipCode; + } + + @Override + public String getCity() + { + return city; + } + + @Override + public String getCountry() + { + return country; + } + + @Override + public String getInsuranceNumber() + { + return insuranceNumber; + } + } + + private final Map<String, Idat> patients = new HashMap<>(); + + protected MasterPatientIndexClientStub() + { + patients.put("0", + new IdatImpl("medicId-0", "Bodomar", "Backer", "12.03.1910", "M", "Mühlenbergstraße 121", "25840", + "Friedrichstadt an der Eider", "DE", "A068266155")); + patients.put("1", + new IdatImpl("medicId-1", "Ehrenreich", "Knott", "18.07.1996", "M", "Auf der Holl 11", "25557", + "Oldenbüttel", "DE", "A043847459")); + patients.put("2", + new IdatImpl("medicId-2", "Dagomar", "Schewe", "06.06.1906", "M", "In der Buchwiese 157", "74226", + "Nordheim", "DE", "A004177703")); + patients.put("3", new IdatImpl("medicId-3", "Golo", "Spanier", "13.02.1979", "M", "Burgstraße 181", "67157", + "Wachenheim an der Weinstraße", "DE", "A080265441")); + patients.put("4", new IdatImpl("medicId-4", "Heide", "Bäder", "10.10.1905", "F", "Alte Turmstraße 29", "57399", + "Kirchhundem", "DE", "A023205020")); + patients.put("5", + new IdatImpl("medicId-5", "Juri", "Kober", "14.03.1908", "M", "Seilbahnweg 147", "38518", "Gifhorn", + "DE", "A078179335")); + patients.put("6", + new IdatImpl("medicId-6", "Peggy", "Lorz", "18.09.1943", "F", "Regensburger Straße 193", "88433", + "Schemmerhofen", "DE", "A083154051")); + patients.put("7", + new IdatImpl("medicId-7", "Ruppert", "Nopper", "12.05.1985", "M", "An den Hülsen 180", "23911", + "Buchholz", "DE", "A001511377")); + patients.put("8", + new IdatImpl("medicId-8", "Sissy", "Diener", "04.09.1985", "F", "Markenweg 130", "46149", "Oberhausen", + "DE", "A064297871")); + patients.put("9", new IdatImpl("medicId-9", "Chantalle", "Hacke", "08.03.1979", "F", "Gaterstraße 56", "60323", + "Frankfurt am Main", "DE", "A078625203")); + patients.put("10", + new IdatImpl("medicId-10", "Alissa", "Nadler", "04.11.1904", "F", "Roxeler Straße 74", "34439", + "Willebadessen", "DE", "A099794475")); + patients.put("11", + new IdatImpl("medicId-11", "Emmeran", "Engel", "16.03.1977", "M", "Lange Hecke 189", "85435", "Erding", + "DE", "A037040696")); + patients.put("12", + new IdatImpl("medicId-12", "Reimund", "Owens", "20.07.1902", "M", "Glück-Auf-Straße 57", "96135", + "Stegaurach", "DE", "A035007141")); + patients.put("13", + new IdatImpl("medicId-13", "Rolf", "Storm", "22.03.1970", "M", "Papenburger Straße 123", "88416", + "Steinhausen an der Rottum", "DE", "A023693897")); + patients.put("14", + new IdatImpl("medicId-14", "Alice", "Klingelhöfer", "01.04.1988", "F", "Wichernstraße 34", "25926", + "Karlum", "DE", "A029733037")); + } + + @Override + public Idat fetchIdat(String ehrId) + { + Idat idat = patients.get(ehrId); + if (idat == null) + throw new IdatNotFoundException("IDAT for ehrId " + ehrId + " not found"); + + logger.debug("Returning demo IDAT for ehrId {}", ehrId); + + return idat; + } +} diff --git a/dsf-mpi/dsf-mpi-client-stub/src/main/java/org/highmed/mpi/client/stub/MasterPatientIndexClientStubFactory.java b/dsf-mpi/dsf-mpi-client-stub/src/main/java/org/highmed/mpi/client/stub/MasterPatientIndexClientStubFactory.java new file mode 100644 index 000000000..337a050d0 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-stub/src/main/java/org/highmed/mpi/client/stub/MasterPatientIndexClientStubFactory.java @@ -0,0 +1,15 @@ +package org.highmed.mpi.client.stub; + +import java.util.function.Function; + +import org.highmed.mpi.client.MasterPatientIndexClient; +import org.highmed.mpi.client.MasterPatientIndexClientFactory; + +public class MasterPatientIndexClientStubFactory implements MasterPatientIndexClientFactory +{ + @Override + public MasterPatientIndexClient createClient(Function<String, String> propertyResolver) + { + return new MasterPatientIndexClientStub(); + } +} diff --git a/dsf-mpi/dsf-mpi-client-stub/src/main/resources/META-INF/services/org.highmed.mpi.client.MasterPatientIndexClientFactory b/dsf-mpi/dsf-mpi-client-stub/src/main/resources/META-INF/services/org.highmed.mpi.client.MasterPatientIndexClientFactory new file mode 100644 index 000000000..99026cb8a --- /dev/null +++ b/dsf-mpi/dsf-mpi-client-stub/src/main/resources/META-INF/services/org.highmed.mpi.client.MasterPatientIndexClientFactory @@ -0,0 +1 @@ +org.highmed.mpi.client.stub.MasterPatientIndexClientStubFactory \ No newline at end of file diff --git a/dsf-mpi/dsf-mpi-client/.gitignore b/dsf-mpi/dsf-mpi-client/.gitignore new file mode 100644 index 000000000..d98981cc4 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.classpath +/.project +/.settings/ diff --git a/dsf-mpi/dsf-mpi-client/pom.xml b/dsf-mpi/dsf-mpi-client/pom.xml new file mode 100644 index 000000000..325f7fda7 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client/pom.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <artifactId>dsf-mpi-client</artifactId> + + <parent> + <artifactId>dsf-mpi-pom</artifactId> + <groupId>org.highmed.dsf</groupId> + <version>0.2.0</version> + </parent> +</project> \ No newline at end of file diff --git a/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/Idat.java b/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/Idat.java new file mode 100644 index 000000000..d0a691a32 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/Idat.java @@ -0,0 +1,61 @@ +package org.highmed.mpi.client; + +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +/** + * Container for all of a subject's identifying data points as consented upon within the German medical informatics + * initiative. + */ +public interface Idat +{ + DateTimeFormatter GERMAN_DATE = DateTimeFormatter.ofPattern("dd.MM.yyyy", Locale.GERMANY); + + /** + * @return long-term patient identifier used inside the medical data integration center (MeDIC) + */ + String getMedicId(); + + String getFirstName(); + + String getLastName(); + + /** + * @return birthday formated as German date aka yyyy.MM.dd + * @see Idat#GERMAN_DATE + */ + String getBirthday(); + + /** + * D - diverse (http://fhir.de/CodeSystem/gender-amtlich-de divers) + * F - female (http://hl7.org/fhir/administrative-gender female) + * M - male (http://hl7.org/fhir/administrative-gender male) + * O - other (http://hl7.org/fhir/administrative-gender other) + * U - unknown (http://hl7.org/fhir/administrative-gender unknown) + * X - undefined (http://fhir.de/CodeSystem/gender-amtlich-de unbestimmt) + * + * @return {D, F, M, O, U, X} + */ + String getSex(); + + /** + * @return street name including street number + */ + String getStreet(); + + String getZipCode(); + + String getCity(); + + /** + * https://en.wikipedia.org/wiki/ISO_3166-2 + * + * @return two character code based on ISO 3166-2 + */ + String getCountry(); + + /** + * @return 10 character immutable part of the German eGK number + */ + String getInsuranceNumber(); +} diff --git a/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/IdatNotFoundException.java b/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/IdatNotFoundException.java new file mode 100644 index 000000000..892d5b39f --- /dev/null +++ b/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/IdatNotFoundException.java @@ -0,0 +1,26 @@ +package org.highmed.mpi.client; + +public class IdatNotFoundException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + public IdatNotFoundException() + { + super(); + } + + public IdatNotFoundException(String message, Throwable cause) + { + super(message, cause); + } + + public IdatNotFoundException(String message) + { + super(message); + } + + public IdatNotFoundException(Throwable cause) + { + super(cause); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/mpi/MasterPatientIndexClient.java b/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/MasterPatientIndexClient.java similarity index 68% rename from dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/mpi/MasterPatientIndexClient.java rename to dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/MasterPatientIndexClient.java index c4bd160f3..5b9b7e5c5 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/mpi/MasterPatientIndexClient.java +++ b/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/MasterPatientIndexClient.java @@ -1,4 +1,4 @@ -package org.highmed.pseudonymization.mpi; +package org.highmed.mpi.client; /** * Client interface for fetching a subject's IDAT from a Master Patient Index. @@ -9,9 +9,11 @@ public interface MasterPatientIndexClient * Perform an MPI Lookup for a given openEHR-EHR-ID, fetching the subject's MPI ID as well as their IDAT (First * name, last name, sex, birthday, zipCode, city, country, insurance no.) * - * @param ehrID + * @param ehrId * A subject's ehrID String as returned in OpenEHR result sets * @return A filled {@link Idat} + * @throws IdatNotFoundException + * if not IDAT could be found for the given ehrId */ - Idat fetchIdat(String ehrID); + Idat fetchIdat(String ehrId) throws IdatNotFoundException; } diff --git a/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/MasterPatientIndexClientFactory.java b/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/MasterPatientIndexClientFactory.java new file mode 100644 index 000000000..7cd167187 --- /dev/null +++ b/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/MasterPatientIndexClientFactory.java @@ -0,0 +1,8 @@ +package org.highmed.mpi.client; + +import java.util.function.Function; + +public interface MasterPatientIndexClientFactory +{ + MasterPatientIndexClient createClient(Function<String, String> propertyResolver); +} diff --git a/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/MasterPatientIndexClientServiceLoader.java b/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/MasterPatientIndexClientServiceLoader.java new file mode 100644 index 000000000..a4414d3da --- /dev/null +++ b/dsf-mpi/dsf-mpi-client/src/main/java/org/highmed/mpi/client/MasterPatientIndexClientServiceLoader.java @@ -0,0 +1,16 @@ +package org.highmed.mpi.client; + +import java.util.Optional; +import java.util.ServiceLoader; + +public class MasterPatientIndexClientServiceLoader +{ + public Optional<MasterPatientIndexClientFactory> getMasterPatientIndexClientFactory(String factoryClassName) + { + ServiceLoader<MasterPatientIndexClientFactory> factories = ServiceLoader + .load(MasterPatientIndexClientFactory.class); + + return factories.stream().map(ServiceLoader.Provider::get) + .filter(f -> f.getClass().getName().equals(factoryClassName)).findFirst(); + } +} diff --git a/dsf-mpi/pom.xml b/dsf-mpi/pom.xml new file mode 100644 index 000000000..21b7bfd08 --- /dev/null +++ b/dsf-mpi/pom.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <artifactId>dsf-mpi-pom</artifactId> + <packaging>pom</packaging> + + <parent> + <artifactId>dsf-pom</artifactId> + <groupId>org.highmed.dsf</groupId> + <version>0.2.0</version> + </parent> + + <modules> + <module>dsf-mpi-client</module> + <module>dsf-mpi-client-stub</module> + <module>dsf-mpi-client-pdq</module> + </modules> + + <dependencies> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.highmed.dsf</groupId> + <artifactId>dsf-mpi-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.highmed.dsf</groupId> + <artifactId>dsf-mpi-client-stub</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.highmed.dsf</groupId> + <artifactId>dsf-mpi-client-pdq</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </dependencyManagement> +</project> \ No newline at end of file diff --git a/dsf-openehr/dsf-openehr-model/pom.xml b/dsf-openehr/dsf-openehr-model/pom.xml index 1bf8cc9eb..2a271d972 100644 --- a/dsf-openehr/dsf-openehr-model/pom.xml +++ b/dsf-openehr/dsf-openehr-model/pom.xml @@ -7,7 +7,7 @@ <parent> <artifactId>dsf-openehr-pom</artifactId> <groupId>org.highmed.dsf</groupId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> diff --git a/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/OpenEhrObjectMapperFactory.java b/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/json/OpenEhrObjectMapperFactory.java similarity index 85% rename from dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/OpenEhrObjectMapperFactory.java rename to dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/json/OpenEhrObjectMapperFactory.java index f2a55768e..a180b6d5b 100644 --- a/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/OpenEhrObjectMapperFactory.java +++ b/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/json/OpenEhrObjectMapperFactory.java @@ -1,7 +1,5 @@ -package org.highmed.openehr; +package org.highmed.openehr.json; -import org.highmed.openehr.deserializer.RowElementDeserializer; -import org.highmed.openehr.deserializer.RowElementSerializer; import org.highmed.openehr.model.datatypes.DoubleRowElement; import org.highmed.openehr.model.datatypes.IntegerRowElement; import org.highmed.openehr.model.datatypes.JsonNodeRowElement; @@ -13,7 +11,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; -public class OpenEhrObjectMapperFactory +public final class OpenEhrObjectMapperFactory { private OpenEhrObjectMapperFactory() { @@ -25,15 +23,22 @@ public static ObjectMapper createObjectMapper() objectMapper.setSerializationInclusion(Include.NON_NULL); objectMapper.setSerializationInclusion(Include.NON_EMPTY); + objectMapper.registerModule(openEhrModule()); + + return objectMapper; + } + + public static SimpleModule openEhrModule() + { SimpleModule module = new SimpleModule(); + module.addDeserializer(RowElement.class, new RowElementDeserializer()); module.addSerializer(IntegerRowElement.class, new RowElementSerializer()); module.addSerializer(DoubleRowElement.class, new RowElementSerializer()); module.addSerializer(StringRowElement.class, new RowElementSerializer()); module.addSerializer(ZonedDateTimeRowElement.class, new RowElementSerializer()); module.addSerializer(JsonNodeRowElement.class, new RowElementSerializer()); - objectMapper.registerModule(module); - return objectMapper; + return module; } } diff --git a/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/deserializer/RowElementDeserializer.java b/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/json/RowElementDeserializer.java similarity index 97% rename from dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/deserializer/RowElementDeserializer.java rename to dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/json/RowElementDeserializer.java index 4968731a8..7bbefe03a 100755 --- a/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/deserializer/RowElementDeserializer.java +++ b/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/json/RowElementDeserializer.java @@ -1,4 +1,4 @@ -package org.highmed.openehr.deserializer; +package org.highmed.openehr.json; import java.io.IOException; import java.time.ZonedDateTime; diff --git a/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/deserializer/RowElementSerializer.java b/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/json/RowElementSerializer.java similarity index 97% rename from dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/deserializer/RowElementSerializer.java rename to dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/json/RowElementSerializer.java index 5b3a09f3d..bfda6335c 100644 --- a/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/deserializer/RowElementSerializer.java +++ b/dsf-openehr/dsf-openehr-model/src/main/java/org/highmed/openehr/json/RowElementSerializer.java @@ -1,4 +1,4 @@ -package org.highmed.openehr.deserializer; +package org.highmed.openehr.json; import java.io.IOException; diff --git a/dsf-openehr/dsf-openehr-model/src/test/java/org/highmed/openehr/model/structure/ResultSetTest.java b/dsf-openehr/dsf-openehr-model/src/test/java/org/highmed/openehr/model/structure/ResultSetTest.java index f161c0e09..b4bc020da 100644 --- a/dsf-openehr/dsf-openehr-model/src/test/java/org/highmed/openehr/model/structure/ResultSetTest.java +++ b/dsf-openehr/dsf-openehr-model/src/test/java/org/highmed/openehr/model/structure/ResultSetTest.java @@ -13,7 +13,7 @@ import java.util.Arrays; import java.util.List; -import org.highmed.openehr.OpenEhrObjectMapperFactory; +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; import org.highmed.openehr.model.datatypes.IntegerRowElement; import org.highmed.openehr.model.datatypes.StringRowElement; import org.junit.BeforeClass; diff --git a/dsf-openehr/dsf-openehr-webservice-client/pom.xml b/dsf-openehr/dsf-openehr-webservice-client/pom.xml index 3c1ca4f96..7ef58e80e 100644 --- a/dsf-openehr/dsf-openehr-webservice-client/pom.xml +++ b/dsf-openehr/dsf-openehr-webservice-client/pom.xml @@ -8,7 +8,7 @@ <parent> <artifactId>dsf-openehr-pom</artifactId> <groupId>org.highmed.dsf</groupId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> diff --git a/dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenehrWebserviceClient.java b/dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenEhrWebserviceClient.java similarity index 83% rename from dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenehrWebserviceClient.java rename to dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenEhrWebserviceClient.java index 4027c4209..dc1540dd2 100755 --- a/dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenehrWebserviceClient.java +++ b/dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenEhrWebserviceClient.java @@ -4,7 +4,7 @@ import org.highmed.openehr.model.structure.ResultSet; -public interface OpenehrWebserviceClient +public interface OpenEhrWebserviceClient { ResultSet query(String query, MultivaluedMap<String, Object> headers); } diff --git a/dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenehrWebserviceClientJersey.java b/dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenEhrWebserviceClientJersey.java similarity index 85% rename from dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenehrWebserviceClientJersey.java rename to dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenEhrWebserviceClientJersey.java index c3ae36426..c08f1f9c2 100755 --- a/dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenehrWebserviceClientJersey.java +++ b/dsf-openehr/dsf-openehr-webservice-client/src/main/java/org/highmed/openehr/client/OpenEhrWebserviceClientJersey.java @@ -14,13 +14,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; -public class OpenehrWebserviceClientJersey extends AbstractJerseyClient implements OpenehrWebserviceClient +public class OpenEhrWebserviceClientJersey extends AbstractJerseyClient implements OpenEhrWebserviceClient { - private static final Logger logger = LoggerFactory.getLogger(OpenehrWebserviceClientJersey.class); + private static final Logger logger = LoggerFactory.getLogger(OpenEhrWebserviceClientJersey.class); public static final String OPENEHR_QUERY_PATH = "query/aql"; - public OpenehrWebserviceClientJersey(String baseUrl, String basicAuthUsername, String basicAuthPassword, + public OpenEhrWebserviceClientJersey(String baseUrl, String basicAuthUsername, String basicAuthPassword, int connectTimeout, int readTimeout, ObjectMapper objectMapper) { super(baseUrl, basicAuthUsername, basicAuthPassword, connectTimeout, readTimeout, objectMapper); @@ -44,6 +44,9 @@ public ResultSet query(String query, MultivaluedMap<String, Object> headers) return response.readEntity(ResultSet.class); } else - throw new WebApplicationException(response); + { + response.close(); + throw new WebApplicationException(response.getStatus()); + } } } diff --git a/dsf-openehr/dsf-openehr-webservice-client/src/test/java/org/highmed/openehr/client/TestOpenehrJerseyClient.java b/dsf-openehr/dsf-openehr-webservice-client/src/test/java/org/highmed/openehr/client/TestOpenEhrJerseyClient.java similarity index 82% rename from dsf-openehr/dsf-openehr-webservice-client/src/test/java/org/highmed/openehr/client/TestOpenehrJerseyClient.java rename to dsf-openehr/dsf-openehr-webservice-client/src/test/java/org/highmed/openehr/client/TestOpenEhrJerseyClient.java index 8a3b8ee89..a4a8ed38a 100755 --- a/dsf-openehr/dsf-openehr-webservice-client/src/test/java/org/highmed/openehr/client/TestOpenehrJerseyClient.java +++ b/dsf-openehr/dsf-openehr-webservice-client/src/test/java/org/highmed/openehr/client/TestOpenEhrJerseyClient.java @@ -1,16 +1,16 @@ package org.highmed.openehr.client; -import org.highmed.openehr.OpenEhrObjectMapperFactory; +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; import org.highmed.openehr.model.datatypes.JsonNodeRowElement; import org.highmed.openehr.model.structure.ResultSet; import com.fasterxml.jackson.databind.ObjectMapper; -public class TestOpenehrJerseyClient +public class TestOpenEhrJerseyClient { public static void main(String... args) { - OpenehrWebserviceClient client = new OpenehrWebserviceClientJersey("http://localhost:8003/rest/openehr/v1", + OpenEhrWebserviceClient client = new OpenEhrWebserviceClientJersey("http://localhost:8003/rest/openehr/v1", "username", "password", 2500, 5000, objectMapper()); String query = "SELECT e FROM EHR e"; diff --git a/dsf-openehr/pom.xml b/dsf-openehr/pom.xml index f9223d144..588cff4f2 100755 --- a/dsf-openehr/pom.xml +++ b/dsf-openehr/pom.xml @@ -9,7 +9,7 @@ <parent> <artifactId>dsf-pom</artifactId> <groupId>org.highmed.dsf</groupId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <modules> diff --git a/dsf-pseudonymization/dsf-pseudonymization-base/pom.xml b/dsf-pseudonymization/dsf-pseudonymization-base/pom.xml index 02663a465..e778e71f6 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-base/pom.xml +++ b/dsf-pseudonymization/dsf-pseudonymization-base/pom.xml @@ -7,6 +7,6 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-pseudonymization-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> </project> \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-base/src/main/java/org/highmed/pseudonymization/json/BitSetDeserializer.java b/dsf-pseudonymization/dsf-pseudonymization-base/src/main/java/org/highmed/pseudonymization/json/BitSetDeserializer.java new file mode 100644 index 000000000..5571c5569 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-base/src/main/java/org/highmed/pseudonymization/json/BitSetDeserializer.java @@ -0,0 +1,23 @@ +package org.highmed.pseudonymization.json; + +import java.io.IOException; +import java.util.Base64; +import java.util.BitSet; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; + +public class BitSetDeserializer extends JsonDeserializer<BitSet> +{ + @Override + public BitSet deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException, JsonProcessingException + { + JsonNode node = jsonParser.getCodec().readTree(jsonParser); + byte[] rbfBytes = Base64.getDecoder().decode(node.asText()); + return BitSet.valueOf(rbfBytes); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-base/src/main/java/org/highmed/pseudonymization/json/BitSetSerializer.java b/dsf-pseudonymization/dsf-pseudonymization-base/src/main/java/org/highmed/pseudonymization/json/BitSetSerializer.java new file mode 100644 index 000000000..b2169e142 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-base/src/main/java/org/highmed/pseudonymization/json/BitSetSerializer.java @@ -0,0 +1,19 @@ +package org.highmed.pseudonymization.json; + +import java.io.IOException; +import java.util.Base64; +import java.util.BitSet; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +public class BitSetSerializer extends JsonSerializer<BitSet> +{ + @Override + public void serialize(BitSet value, JsonGenerator gen, SerializerProvider serializers) throws IOException + { + String string = Base64.getEncoder().encodeToString(value.toByteArray()); + gen.writeString(string); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/encoding/ResultSetEncoder.java b/dsf-pseudonymization/dsf-pseudonymization-base/src/main/java/org/highmed/pseudonymization/openehr/Constants.java similarity index 59% rename from dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/encoding/ResultSetEncoder.java rename to dsf-pseudonymization/dsf-pseudonymization-base/src/main/java/org/highmed/pseudonymization/openehr/Constants.java index f932aeadc..31b8972cf 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/encoding/ResultSetEncoder.java +++ b/dsf-pseudonymization/dsf-pseudonymization-base/src/main/java/org/highmed/pseudonymization/openehr/Constants.java @@ -1,8 +1,6 @@ -package org.highmed.pseudonymization.encoding; +package org.highmed.pseudonymization.openehr; -import org.highmed.openehr.model.structure.ResultSet; - -public interface ResultSetEncoder +public interface Constants { String EHRID_COLUMN_NAME = "EHRID"; String EHRID_COLUMN_PATH = "/ehr_id/value"; @@ -12,8 +10,4 @@ public interface ResultSetEncoder String RBF_COLUMN_PATH = "/rbf/value"; String PSN_COLUMN_NAME = "PSN"; String PSN_COLUMN_PATH = "/psn/value"; - - ResultSet encode(ResultSet resultSet); - - ResultSet decode(ResultSet resultSet); } diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/pom.xml b/dsf-pseudonymization/dsf-pseudonymization-medic/pom.xml index af354cac2..e45b17d96 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/pom.xml +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-pseudonymization-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> @@ -15,6 +15,10 @@ <groupId>org.highmed.dsf</groupId> <artifactId>dsf-pseudonymization-base</artifactId> </dependency> + <dependency> + <groupId>org.highmed.dsf</groupId> + <artifactId>dsf-mpi-client</artifactId> + </dependency> <dependency> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-openehr-model</artifactId> diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/BloomFilterGenerator.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/BloomFilterGenerator.java index e6c97dd2a..5369210e4 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/BloomFilterGenerator.java +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/BloomFilterGenerator.java @@ -3,6 +3,7 @@ import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; +import java.security.Key; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Provider; @@ -36,6 +37,17 @@ public static BloomFilterGenerator withHmacMd5HmacSha1BiGramHasher(int bitSetLen return new BloomFilterGenerator(bitSetLength, () -> new HmacMd5HmacSha1BiGramHasher(key1, key2)); } + public static BloomFilterGenerator withSha1Sha2BiGramHasher(int bitSetLength) + { + return new BloomFilterGenerator(bitSetLength, Sha1Sha2BiGramHasher::new); + } + + public static BloomFilterGenerator withHmacSha1HmacSha2BiGramHasher(int bitSetLength, byte[] key1, byte[] key2, + Provider provider) + { + return new BloomFilterGenerator(bitSetLength, () -> new HmacSha1HmacSha2BiGramHasher(key1, key2, provider)); + } + public static BloomFilterGenerator withSha2Sha3BiGramHasher(int bitSetLength) { return new BloomFilterGenerator(bitSetLength, Sha2Sha3BiGramHasher::new); @@ -145,13 +157,23 @@ public static class HmacMd5HmacSha1BiGramHasher implements BiGramHasher public HmacMd5HmacSha1BiGramHasher(byte[] key1, byte[] key2) { + this(new SecretKeySpec(key1, "HmacMD5"), new SecretKeySpec(key2, "HmacSHA1")); + } + + public HmacMd5HmacSha1BiGramHasher(Key key1, Key key2) + { + if (!"HmacMD5".equals(key1.getAlgorithm())) + throw new IllegalArgumentException("key1.algorithm HmacMD5 expected, but got " + key1.getAlgorithm()); + if (!"HmacSHA1".equals(key2.getAlgorithm())) + throw new IllegalArgumentException("key2.algorithm HmacSHA1 expected, but got " + key2.getAlgorithm()); + try { md5Mac = Mac.getInstance("HmacMD5"); - md5Mac.init(new SecretKeySpec(key1, "HmacMD5")); + md5Mac.init(key1); sha1Mac = Mac.getInstance("HmacSHA1"); - sha1Mac.init(new SecretKeySpec(key2, "HmacSHA1")); + sha1Mac.init(key2); } catch (InvalidKeyException | NoSuchAlgorithmException e) { @@ -186,6 +208,126 @@ public byte[] secondHash(byte[] biGram) } } + public static class Sha1Sha2BiGramHasher implements BiGramHasher + { + private final MessageDigest sha1Digest; + private final MessageDigest sha2Digest; + + public Sha1Sha2BiGramHasher() + { + try + { + sha1Digest = MessageDigest.getInstance("SHA-1"); + sha2Digest = MessageDigest.getInstance("SHA-256"); + } + catch (NoSuchAlgorithmException e) + { + throw new RuntimeException(e); + } + } + + @Override + public byte[] firstHash(byte[] biGram) + { + try + { + return sha1Digest.digest(biGram); + } + finally + { + sha1Digest.reset(); + } + } + + @Override + public byte[] secondHash(byte[] biGram) + { + try + { + return sha2Digest.digest(biGram); + } + finally + { + sha2Digest.reset(); + } + } + } + + public static class HmacSha1HmacSha2BiGramHasher implements BiGramHasher + { + private final Mac sha1Mac; + private final Mac sha2Mac; + + public HmacSha1HmacSha2BiGramHasher(byte[] key1, byte[] key2) + { + this(key1, key2, null); + } + + public HmacSha1HmacSha2BiGramHasher(byte[] key1, byte[] key2, Provider provider) + { + this(new SecretKeySpec(key1, "HmacSHA1"), new SecretKeySpec(key2, "HmacSHA256"), provider); + } + + public HmacSha1HmacSha2BiGramHasher(Key key1, Key key2) + { + this(key1, key2, null); + } + + public HmacSha1HmacSha2BiGramHasher(Key key1, Key key2, Provider provider) + { + if (!"HmacSHA1".equals(key1.getAlgorithm())) + throw new IllegalArgumentException("key1.algorithm HmacSHA1 expected, but got " + key1.getAlgorithm()); + if (!"HmacSHA256".equals(key2.getAlgorithm())) + throw new IllegalArgumentException( + "key2.algorithm HmacSHA256 expected, but got " + key2.getAlgorithm()); + + try + { + if (provider == null) + sha1Mac = Mac.getInstance("HmacSHA1", provider); + else + sha1Mac = Mac.getInstance("HmacSHA1"); + sha1Mac.init(key1); + + if (provider == null) + sha2Mac = Mac.getInstance("HmacSHA256"); + else + sha2Mac = Mac.getInstance("HmacSHA256", provider); + sha2Mac.init(key2); + } + catch (InvalidKeyException | NoSuchAlgorithmException e) + { + throw new RuntimeException(e); + } + } + + @Override + public byte[] firstHash(byte[] biGram) + { + try + { + return sha1Mac.doFinal(biGram); + } + catch (IllegalStateException e) + { + throw new RuntimeException(e); + } + } + + @Override + public byte[] secondHash(byte[] biGram) + { + try + { + return sha2Mac.doFinal(biGram); + } + catch (IllegalStateException e) + { + throw new RuntimeException(e); + } + } + } + public static class Sha2Sha3BiGramHasher implements BiGramHasher { private final MessageDigest sha2Digest; @@ -243,19 +385,35 @@ public HmacSha2HmacSha3BiGramHasher(byte[] key1, byte[] key2) public HmacSha2HmacSha3BiGramHasher(byte[] key1, byte[] key2, Provider provider) { + this(new SecretKeySpec(key1, "HmacSHA256"), new SecretKeySpec(key2, "HmacSHA3-256"), provider); + } + + public HmacSha2HmacSha3BiGramHasher(Key key1, Key key2) + { + this(key1, key2, null); + } + + public HmacSha2HmacSha3BiGramHasher(Key key1, Key key2, Provider provider) + { + if (!"HmacSHA256".equals(key1.getAlgorithm())) + throw new IllegalArgumentException( + "key1.algorithm HmacSHA256 expected, but got " + key1.getAlgorithm()); + if (!"HmacSHA3-256".equals(key2.getAlgorithm())) + throw new IllegalArgumentException( + "key2.algorithm HmacSHA3-256 expected, but got " + key2.getAlgorithm()); try { if (provider == null) sha2Mac = Mac.getInstance("HmacSHA256"); else sha2Mac = Mac.getInstance("HmacSHA256", provider); - sha2Mac.init(new SecretKeySpec(key1, "HmacSHA256")); + sha2Mac.init(key1); if (provider == null) sha3Mac = Mac.getInstance("HmacSHA3-256"); else sha3Mac = Mac.getInstance("HmacSHA3-256", provider); - sha3Mac.init(new SecretKeySpec(key2, "HmacSHA3-256")); + sha3Mac.init(key2); } catch (InvalidKeyException | NoSuchAlgorithmException e) { diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilter.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilter.java index e5b03936f..a06ad365f 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilter.java +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilter.java @@ -1,28 +1,28 @@ package org.highmed.pseudonymization.bloomfilter; -import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Random; public class RecordBloomFilter { private final int length; - private final byte[] permutationSeed; + private final long permutationSeed; private final List<FieldBloomFilter> fieldBloomFilters = new ArrayList<>(); private BitSet bitSet; - public RecordBloomFilter(byte[] permutationSeed, FieldBloomFilter... fieldBloomFilters) + public RecordBloomFilter(long permutationSeed, FieldBloomFilter... fieldBloomFilters) { this(permutationSeed, Arrays.asList(fieldBloomFilters)); } - public RecordBloomFilter(byte[] permutationSeed, List<? extends FieldBloomFilter> fieldBloomFilters) + public RecordBloomFilter(long permutationSeed, List<? extends FieldBloomFilter> fieldBloomFilters) { this(calculateLength(fieldBloomFilters), permutationSeed, fieldBloomFilters); } @@ -33,12 +33,12 @@ private static int calculateLength(List<? extends FieldBloomFilter> fieldBloomFi : fieldBloomFilters.stream().mapToInt(f -> (int) (f.length() / f.weight())).max().orElse(0); } - public RecordBloomFilter(int length, byte[] permutationSeed, FieldBloomFilter... fieldBloomFilters) + public RecordBloomFilter(int length, long permutationSeed, FieldBloomFilter... fieldBloomFilters) { this(length, permutationSeed, Arrays.asList(fieldBloomFilters)); } - public RecordBloomFilter(int length, byte[] permutationSeed, List<? extends FieldBloomFilter> fieldBloomFilters) + public RecordBloomFilter(int length, long permutationSeed, List<? extends FieldBloomFilter> fieldBloomFilters) { if (fieldBloomFilters != null && fieldBloomFilters.stream().mapToDouble(f -> (double) f.weight()).sum() > 1) throw new IllegalArgumentException(FieldBloomFilter.class.getName() + " weight sum <= 1 expected"); @@ -61,7 +61,7 @@ public BitSet getBitSet() private BitSet createBitSet() { List<Boolean> bits = createSorted(); - Collections.shuffle(bits, new SecureRandom(permutationSeed)); + Collections.shuffle(bits, new Random(permutationSeed)); return toBitSet(bits); } diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterGenerator.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterGenerator.java index 14dfd8220..2ad2ebb5a 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterGenerator.java +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterGenerator.java @@ -1,6 +1,6 @@ package org.highmed.pseudonymization.bloomfilter; -import org.highmed.pseudonymization.mpi.Idat; +import org.highmed.mpi.client.Idat; public interface RecordBloomFilterGenerator { diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterGeneratorImpl.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterGeneratorImpl.java index 22e0c053a..9278354ab 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterGeneratorImpl.java +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterGeneratorImpl.java @@ -1,10 +1,11 @@ package org.highmed.pseudonymization.bloomfilter; +import java.math.BigInteger; import java.util.Objects; import java.util.function.Supplier; +import org.highmed.mpi.client.Idat; import org.highmed.pseudonymization.bloomfilter.BloomFilterGenerator.BiGramHasher; -import org.highmed.pseudonymization.mpi.Idat; public class RecordBloomFilterGeneratorImpl implements RecordBloomFilterGenerator { @@ -63,8 +64,14 @@ public FieldBloomFilterLengths(int firstNameLength, int lastNameLength, int birt } } + public static final int DEFAULT_RECORD_BLOOM_FILTER_LENGTH = 2000; + public static final FieldWeights DEFAULT_FIELD_WEIGHTS = new FieldWeights(0.1, 0.1, 0.1, 0.2, 0.05, 0.1, 0.05, 0.2, + 0.1); + public static final FieldBloomFilterLengths DEFAULT_FIELD_BLOOM_FILTER_LENGTHS = new FieldBloomFilterLengths(500, + 500, 250, 50, 500, 250, 500, 500, 500); + private final int length; - private final byte[] permutationSeed; + private final long permutationSeed; private final FieldWeights weights; private final BloomFilterGenerator firstNameGenerator; private final BloomFilterGenerator lastNameGenerator; @@ -76,7 +83,29 @@ public FieldBloomFilterLengths(int firstNameLength, int lastNameLength, int birt private final BloomFilterGenerator countryGenerator; private final BloomFilterGenerator insuranceNumberGenerator; - public RecordBloomFilterGeneratorImpl(int length, byte[] permutationSeed, FieldWeights weights, + public static RecordBloomFilterGeneratorImpl defaultConfiguration(byte[] permutationSeed, byte[] hmacMd5Key, + byte[] hmacSha1Key) + { + if (permutationSeed.length != 8) + throw new IllegalArgumentException("permutationSeed.length = 8 expected"); + + return defaultConfiguration(new BigInteger(permutationSeed).longValue(), hmacMd5Key, hmacSha1Key); + } + + public static RecordBloomFilterGeneratorImpl defaultConfiguration(long permutationSeed, byte[] hmacMd5Key, + byte[] hmacSha1Key) + { + if (hmacMd5Key.length != 64) + throw new IllegalArgumentException("md5HmacKey.length = 64 expected"); + if (hmacSha1Key.length != 64) + throw new IllegalArgumentException("hmacSha1Key.length = 64 expected"); + + return new RecordBloomFilterGeneratorImpl(DEFAULT_RECORD_BLOOM_FILTER_LENGTH, permutationSeed, + DEFAULT_FIELD_WEIGHTS, DEFAULT_FIELD_BLOOM_FILTER_LENGTHS, + () -> new BloomFilterGenerator.HmacMd5HmacSha1BiGramHasher(hmacMd5Key, hmacSha1Key)); + } + + public RecordBloomFilterGeneratorImpl(int length, long permutationSeed, FieldWeights weights, FieldBloomFilterLengths lengths, Supplier<BiGramHasher> biGramHasherSupplier) { this.length = length; diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/encoding/ResultSetEncoderImpl.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/encoding/ResultSetEncoderImpl.java deleted file mode 100644 index 846948dba..000000000 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/encoding/ResultSetEncoderImpl.java +++ /dev/null @@ -1,388 +0,0 @@ -package org.highmed.pseudonymization.encoding; - -import java.nio.charset.StandardCharsets; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Base64; -import java.util.List; -import java.util.Objects; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.ShortBufferException; - -import org.highmed.openehr.model.datatypes.DoubleRowElement; -import org.highmed.openehr.model.datatypes.IntegerRowElement; -import org.highmed.openehr.model.datatypes.JsonNodeRowElement; -import org.highmed.openehr.model.datatypes.StringRowElement; -import org.highmed.openehr.model.datatypes.ZonedDateTimeRowElement; -import org.highmed.openehr.model.structure.Column; -import org.highmed.openehr.model.structure.Meta; -import org.highmed.openehr.model.structure.ResultSet; -import org.highmed.openehr.model.structure.RowElement; -import org.highmed.pseudonymization.bloomfilter.RecordBloomFilter; -import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGenerator; -import org.highmed.pseudonymization.crypto.AesGcmUtil; -import org.highmed.pseudonymization.mpi.Idat; -import org.highmed.pseudonymization.mpi.MasterPatientIndexClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - -public class ResultSetEncoderImpl implements ResultSetEncoder -{ - private static final Logger logger = LoggerFactory.getLogger(ResultSetEncoderImpl.class); - - private final RecordBloomFilterGenerator recordBloomFilterGenerator; - private final MasterPatientIndexClient masterPatientIndexClient; - - private final String organizationIdentifier; - private final SecretKey organizationKey; - private final String researchStudyIdentifier; - private final SecretKey researchStudyKey; - - private final ObjectMapper openEhrObjectMapper; - - public ResultSetEncoderImpl(RecordBloomFilterGenerator recordBloomFilterGenerator, - MasterPatientIndexClient masterPatientIndexClient, String organizationIdentifier, SecretKey organizationKey, - String researchStudyIdentifier, SecretKey researchStudyKey, ObjectMapper openEhrObjectMapper) - { - this.organizationIdentifier = Objects.requireNonNull(organizationIdentifier, "organizationIdentifier"); - this.recordBloomFilterGenerator = Objects.requireNonNull(recordBloomFilterGenerator, - "recordBloomFilterGenerator"); - this.masterPatientIndexClient = Objects.requireNonNull(masterPatientIndexClient, "masterPatientIndexClient"); - this.organizationKey = Objects.requireNonNull(organizationKey, "organizationKey"); - this.researchStudyIdentifier = Objects.requireNonNull(researchStudyIdentifier, "researchStudyIdentifier"); - this.researchStudyKey = Objects.requireNonNull(researchStudyKey, "researchStudyKey"); - this.openEhrObjectMapper = Objects.requireNonNull(openEhrObjectMapper, "openEhrObjectMapper"); - } - - @Override - public ResultSet encode(ResultSet resultSet) - { - int ehrIdColumnIndex = getEhrColumnIndex(resultSet.getColumns()); - int psnColumnIndex = getPsnColumnIndex(resultSet.getColumns()); - - Meta newMeta = copyMeta(resultSet.getMeta()); - List<Column> newColumns; - List<List<RowElement>> newRows; - - if (ehrIdColumnIndex >= 0 && psnColumnIndex < 0) - { - newColumns = encodeColumnsWithEhrId(resultSet.getColumns()); - newRows = encodeRowsWithEhrId(ehrIdColumnIndex, resultSet.getRows()); - } - else if (psnColumnIndex >= 0 && ehrIdColumnIndex < 0) - { - newColumns = encodeColumnsWithPsn(resultSet.getColumns()); - newRows = encodeRowsWithPsn(psnColumnIndex, resultSet.getRows()); - } - else - throw new IllegalStateException("ResultSet contains EHRID and PSN columns or neither"); - - return new ResultSet(newMeta, resultSet.getName(), resultSet.getQuery(), newColumns, newRows); - } - - private Meta copyMeta(Meta meta) - { - return new Meta(meta.getHref(), meta.getType(), meta.getSchemaVersion(), meta.getCreated(), meta.getGenerator(), - meta.getExecutedAql()); - } - - private List<Column> encodeColumnsWithEhrId(List<Column> columns) - { - Stream<Column> s1 = columns.stream().filter(isEhrIdColumn().negate()).map(toNewColumn()); - Stream<Column> s2 = newMedicIdAndRbfColumn(); - return Stream.concat(s1, s2).collect(Collectors.toList()); - } - - private List<Column> encodeColumnsWithPsn(List<Column> columns) - { - return columns.stream().map(toNewColumn()).collect(Collectors.toList()); - } - - private int getEhrColumnIndex(List<Column> columns) - { - for (int i = 0; i < columns.size(); i++) - if (isEhrIdColumn().test(columns.get(i))) - return i; - - return -1; - } - - private Predicate<? super Column> isEhrIdColumn() - { - return column -> EHRID_COLUMN_NAME.equals(column.getName()) && EHRID_COLUMN_PATH.equals(column.getPath()); - } - - private Function<Column, Column> toNewColumn() - { - return c -> new Column(c.getName(), c.getPath()); - } - - private Stream<Column> newMedicIdAndRbfColumn() - { - return Stream.of(new Column(MEDICID_COLUMN_NAME, MEDICID_COLUMN_PATH), - new Column(RBF_COLUMN_NAME, RBF_COLUMN_PATH)); - } - - private List<List<RowElement>> encodeRowsWithEhrId(int ehrIdColumnIndex, List<List<RowElement>> rows) - { - return rows.parallelStream().map(encodeRowWithEhrId(ehrIdColumnIndex)).collect(Collectors.toList()); - } - - private List<List<RowElement>> encodeRowsWithPsn(int psnColumnIndex, List<List<RowElement>> rows) - { - return rows.parallelStream().map(encodeRowWithPsn(psnColumnIndex)).collect(Collectors.toList()); - } - - private Function<List<RowElement>, List<RowElement>> encodeRowWithEhrId(int ehrIdColumnIndex) - { - return rowElements -> - { - RowElement ehrId = rowElements.get(ehrIdColumnIndex); - - List<RowElement> newRowElements = new ArrayList<>(); - for (int i = 0; i < rowElements.size(); i++) - if (i != ehrIdColumnIndex) - newRowElements.add(toEncryptedMdatRowElement(rowElements.get(i))); - - Idat idat = retrieveIdat(ehrId); - - newRowElements.add(encodeAsEncrypedMedicId(idat)); - newRowElements.add(encodeAsRbf(idat)); - - return newRowElements; - }; - } - - - private Function<List<RowElement>, List<RowElement>> encodeRowWithPsn(int psnColumnIndex) - { - return rowElements -> - { - RowElement psn = rowElements.get(psnColumnIndex); - - List<RowElement> newRowElements = new ArrayList<>(); - for (int i = 0; i < rowElements.size(); i++) - if (i != psnColumnIndex) - newRowElements.add(toEncryptedMdatRowElement(rowElements.get(i))); - - newRowElements.add(psn); - - return newRowElements; - }; - } - - - private RowElement toEncryptedMdatRowElement(RowElement rowElement) - { - return new StringRowElement(encrypt(researchStudyKey, researchStudyIdentifier, - toTypeTag(rowElement) + rowElement.getValueAsString())); - } - - private String toTypeTag(RowElement rowElement) - { - if (rowElement instanceof DoubleRowElement) - return "double:"; - else if (rowElement instanceof IntegerRowElement) - return "integer:"; - else if (rowElement instanceof JsonNodeRowElement) - return "json:"; - else if (rowElement instanceof StringRowElement) - return "string:"; - else if (rowElement instanceof ZonedDateTimeRowElement) - return "timestamp:"; - else - throw new IllegalStateException("rowElement of type " + rowElement.getClass().getName() + " not supported"); - } - - private Idat retrieveIdat(RowElement ehrId) - { - if (!(ehrId instanceof StringRowElement)) - throw new IllegalStateException("EhrId " + RowElement.class.getSimpleName() + " of type " - + StringRowElement.class.getName() + " expected, but got " + ehrId.getClass().getName()); - - return masterPatientIndexClient.fetchIdat(((StringRowElement) ehrId).getValue()); - } - - private RowElement encodeAsEncrypedMedicId(Idat idat) - { - return new StringRowElement(encrypt(organizationKey, organizationIdentifier, idat.getMedicId())); - } - - private RowElement encodeAsRbf(Idat idat) - { - RecordBloomFilter recordBloomFilter = recordBloomFilterGenerator.generate(idat); - String rbfEncodedToString = Base64.getEncoder().encodeToString(recordBloomFilter.getBitSet().toByteArray()); - return new StringRowElement(rbfEncodedToString); - } - - private String encrypt(SecretKey key, String aadTagValue, String plainText) - { - byte[] plain = plainText.getBytes(StandardCharsets.UTF_8); - try - { - byte[] encrypted = AesGcmUtil.encrypt(plain, aadTagValue.getBytes(StandardCharsets.UTF_8), key); - return Base64.getEncoder().encodeToString(encrypted); - } - catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException - | ShortBufferException e) - { - logger.error("Error while encrypting with aadTag " + aadTagValue, e); - throw new RuntimeException(e); - } - } - - private String decrypt(SecretKey key, String aadTagValue, String encryptedText) - { - byte[] encrypted = Base64.getDecoder().decode(encryptedText); - try - { - byte[] decrypted = AesGcmUtil.decrypt(encrypted, aadTagValue.getBytes(StandardCharsets.UTF_8), key); - return new String(decrypted, StandardCharsets.UTF_8); - } - catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) - { - logger.error("Error while decrypting with aadTag " + aadTagValue, e); - throw new RuntimeException(e); - } - } - - @Override - public ResultSet decode(ResultSet resultSet) - { - int psnColumnIndex = getPsnColumnIndex(resultSet.getColumns()); - int medicIdColumnIndex = getMedicIdColumnIndex(resultSet.getColumns()); - - Meta newMeta = copyMeta(resultSet.getMeta()); - List<Column> newColumns = decodeColumns(resultSet.getColumns()); - List<List<RowElement>> newRows; - - if (psnColumnIndex >= 0 && medicIdColumnIndex < 0) - newRows = decodeRowsWithPsnColumn(psnColumnIndex, resultSet.getRows()); - else if (medicIdColumnIndex >= 0 && psnColumnIndex < 0) - newRows = decodeRowsWithMedicIdColumn(medicIdColumnIndex, resultSet.getRows()); - else - throw new IllegalStateException("ResultSet contains PSN and MEDICID columns or neither"); - - return new ResultSet(newMeta, resultSet.getName(), resultSet.getQuery(), newColumns, newRows); - } - - private List<Column> decodeColumns(List<Column> columns) - { - return columns.stream().map(toNewColumn()).collect(Collectors.toList()); - } - - private List<List<RowElement>> decodeRowsWithPsnColumn(int psnColumnIndex, List<List<RowElement>> rows) - { - return rows.parallelStream().map(decodeRowWithPsnColumn(psnColumnIndex)).collect(Collectors.toList()); - } - - private Function<List<RowElement>, List<RowElement>> decodeRowWithPsnColumn(int psnColumnIndex) - { - return rowElements -> - { - RowElement psn = rowElements.get(psnColumnIndex); - - List<RowElement> newRowElements = new ArrayList<>(); - for (int i = 0; i < rowElements.size(); i++) - if (i != psnColumnIndex) - newRowElements.add(toDecryptedMdatRowElement(rowElements.get(i))); - - newRowElements.add(psn); - - return newRowElements; - }; - } - - private List<List<RowElement>> decodeRowsWithMedicIdColumn(int medicIdColumnIndex, List<List<RowElement>> rows) - { - return rows.parallelStream().map(decodeRowWithMedicIdColumn(medicIdColumnIndex)).collect(Collectors.toList()); - } - - private Function<List<RowElement>, List<RowElement>> decodeRowWithMedicIdColumn(int medicIdColumnIndex) - { - return rowElements -> - { - RowElement medicId = rowElements.get(medicIdColumnIndex); - - List<RowElement> newRowElements = new ArrayList<>(); - for (int i = 0; i < rowElements.size(); i++) - if (i != medicIdColumnIndex) - newRowElements.add(toDecryptedMdatRowElement(rowElements.get(i))); - - newRowElements.add(decryptMedicId(medicId.getValueAsString())); - - return newRowElements; - }; - } - - private RowElement toDecryptedMdatRowElement(RowElement rowElement) - { - String tagAndEncrypted = rowElement.getValueAsString(); - - if (tagAndEncrypted.startsWith("double:")) - return DoubleRowElement - .fromString(decrypt(researchStudyKey, researchStudyIdentifier, tagAndEncrypted.substring(7))); - else if (tagAndEncrypted.startsWith("integer:")) - return IntegerRowElement - .fromString(decrypt(researchStudyKey, researchStudyIdentifier, tagAndEncrypted.substring(8))); - else if (tagAndEncrypted.startsWith("json:")) - return JsonNodeRowElement.fromString( - decrypt(researchStudyKey, researchStudyIdentifier, tagAndEncrypted.substring(5)), - openEhrObjectMapper); - else if (tagAndEncrypted.startsWith("string:")) - return StringRowElement - .fromString(decrypt(researchStudyKey, researchStudyIdentifier, tagAndEncrypted.substring(7))); - else if (tagAndEncrypted.startsWith("timestamp:")) - return ZonedDateTimeRowElement - .fromString(decrypt(researchStudyKey, researchStudyIdentifier, tagAndEncrypted.substring(9))); - else - throw new IllegalStateException("rowElement with unknown type tag"); - } - - private RowElement decryptMedicId(String encryptedMedicId) - { - return new StringRowElement(decrypt(organizationKey, organizationIdentifier, encryptedMedicId)); - } - - private int getPsnColumnIndex(List<Column> columns) - { - for (int i = 0; i < columns.size(); i++) - if (isPsnColumn().test(columns.get(i))) - return i; - - return -1; - } - - private int getMedicIdColumnIndex(List<Column> columns) - { - for (int i = 0; i < columns.size(); i++) - if (isMedicIdColumn().test(columns.get(i))) - return i; - - return -1; - } - - private Predicate<? super Column> isPsnColumn() - { - return column -> PSN_COLUMN_NAME.equals(column.getName()) && PSN_COLUMN_PATH.equals(column.getPath()); - } - - private Predicate<? super Column> isMedicIdColumn() - { - return column -> MEDICID_COLUMN_NAME.equals(column.getName()) && MEDICID_COLUMN_PATH.equals(column.getPath()); - } -} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/mpi/Idat.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/mpi/Idat.java deleted file mode 100644 index 35cba837f..000000000 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/mpi/Idat.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.highmed.pseudonymization.mpi; - -/** - * Container for all of a subject's identifying data points as consented upon within the German medical informatics - * initiative. - */ -public interface Idat -{ - String getMedicId(); - - String getFirstName(); - - String getLastName(); - - String getBirthday(); - - String getSex(); - - String getStreet(); - - String getZipCode(); - - String getCity(); - - String getCountry(); - - String getInsuranceNumber(); -} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/AbstractResultSetTranslator.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/AbstractResultSetTranslator.java new file mode 100644 index 000000000..83f152d92 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/AbstractResultSetTranslator.java @@ -0,0 +1,172 @@ +package org.highmed.pseudonymization.translation; + +import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; + +import org.highmed.openehr.model.datatypes.DoubleRowElement; +import org.highmed.openehr.model.datatypes.IntegerRowElement; +import org.highmed.openehr.model.datatypes.JsonNodeRowElement; +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.datatypes.ZonedDateTimeRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.Meta; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.crypto.AesGcmUtil; +import org.highmed.pseudonymization.openehr.Constants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public abstract class AbstractResultSetTranslator implements ResultSetTranslator +{ + private static final Logger logger = LoggerFactory.getLogger(AbstractResultSetTranslator.class); + + protected final Meta copyMeta(Meta meta) + { + if (meta == null) + return null; + + return new Meta(meta.getHref(), meta.getType(), meta.getSchemaVersion(), meta.getCreated(), meta.getGenerator(), + meta.getExecutedAql()); + } + + protected final List<Column> copyColumns(List<Column> columns) + { + return columns.stream().map(copyColumn()).collect(Collectors.toList()); + } + + protected final Function<Column, Column> copyColumn() + { + return c -> new Column(c.getName(), c.getPath()); + } + + protected final RowElement copyRowElement(RowElement rowElement) + { + if (rowElement instanceof DoubleRowElement) + return new DoubleRowElement(((DoubleRowElement) rowElement).getValue()); + else if (rowElement instanceof IntegerRowElement) + return new IntegerRowElement(((IntegerRowElement) rowElement).getValue()); + else if (rowElement instanceof JsonNodeRowElement) + return new JsonNodeRowElement(((JsonNodeRowElement) rowElement).getValue().deepCopy()); + else if (rowElement instanceof StringRowElement) + return new StringRowElement(((StringRowElement) rowElement).getValue()); + else if (rowElement instanceof ZonedDateTimeRowElement) + return new ZonedDateTimeRowElement(((ZonedDateTimeRowElement) rowElement).getValue()); + else + throw new IllegalStateException("rowElement of type " + rowElement.getClass().getName() + " not supported"); + } + + protected final RowElement toEncryptedMdatRowElement(RowElement rowElement, SecretKey researchStudyKey, + String researchStudyIdentifier) + { + if (researchStudyKey == null || researchStudyIdentifier == null) + throw new IllegalStateException( + "researchStudyKey or researchStudyIdentifier null, unable to encrypted MDAT row element"); + + return new StringRowElement(toTypeTag(rowElement) + + encrypt(researchStudyKey, researchStudyIdentifier, rowElement.getValueAsString())); + } + + private String toTypeTag(RowElement rowElement) + { + if (rowElement instanceof DoubleRowElement) + return "double:"; + else if (rowElement instanceof IntegerRowElement) + return "integer:"; + else if (rowElement instanceof JsonNodeRowElement) + return "json:"; + else if (rowElement instanceof StringRowElement) + return "string:"; + else if (rowElement instanceof ZonedDateTimeRowElement) + return "timestamp:"; + else + throw new IllegalStateException("rowElement of type " + rowElement.getClass().getName() + " not supported"); + } + + protected final String encrypt(SecretKey key, String aadTagValue, String plainText) + { + byte[] plain = plainText.getBytes(StandardCharsets.UTF_8); + try + { + byte[] encrypted = AesGcmUtil.encrypt(plain, aadTagValue.getBytes(StandardCharsets.UTF_8), key); + return Base64.getEncoder().encodeToString(encrypted); + } + catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException + | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException + | ShortBufferException e) + { + logger.error("Error while encrypting with aadTag " + aadTagValue, e); + throw new RuntimeException(e); + } + } + + protected final String decrypt(SecretKey key, String aadTagValue, String encryptedText) + { + byte[] encrypted = Base64.getDecoder().decode(encryptedText); + try + { + byte[] decrypted = AesGcmUtil.decrypt(encrypted, aadTagValue.getBytes(StandardCharsets.UTF_8), key); + return new String(decrypted, StandardCharsets.UTF_8); + } + catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException + | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) + { + logger.error("Error while decrypting with aadTag " + aadTagValue, e); + throw new RuntimeException(e); + } + } + + protected final int getPsnColumnIndex(List<Column> columns) + { + for (int i = 0; i < columns.size(); i++) + if (isPsnColumn().test(columns.get(i))) + return i; + + return -1; + } + + protected final Predicate<? super Column> isPsnColumn() + { + return column -> Constants.PSN_COLUMN_NAME.equals(column.getName()) + && Constants.PSN_COLUMN_PATH.equals(column.getPath()); + } + + protected final RowElement toDecryptedMdatRowElement(RowElement rowElement, SecretKey researchStudyKey, + String researchStudyIdentifier, ObjectMapper openEhrObjectMapper) + { + String tagAndEncrypted = rowElement.getValueAsString(); + + if (tagAndEncrypted.startsWith("double:")) + return DoubleRowElement + .fromString(decrypt(researchStudyKey, researchStudyIdentifier, tagAndEncrypted.substring(7))); + else if (tagAndEncrypted.startsWith("integer:")) + return IntegerRowElement + .fromString(decrypt(researchStudyKey, researchStudyIdentifier, tagAndEncrypted.substring(8))); + else if (tagAndEncrypted.startsWith("json:")) + return JsonNodeRowElement.fromString( + decrypt(researchStudyKey, researchStudyIdentifier, tagAndEncrypted.substring(5)), + openEhrObjectMapper); + else if (tagAndEncrypted.startsWith("string:")) + return StringRowElement + .fromString(decrypt(researchStudyKey, researchStudyIdentifier, tagAndEncrypted.substring(7))); + else if (tagAndEncrypted.startsWith("timestamp:")) + return ZonedDateTimeRowElement + .fromString(decrypt(researchStudyKey, researchStudyIdentifier, tagAndEncrypted.substring(10))); + else + throw new IllegalStateException("rowElement with unknown type tag"); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslator.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslator.java new file mode 100644 index 000000000..fda399a86 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslator.java @@ -0,0 +1,8 @@ +package org.highmed.pseudonymization.translation; + +import org.highmed.openehr.model.structure.ResultSet; + +public interface ResultSetTranslator +{ + ResultSet translate(ResultSet resultSet); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromTtp.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromTtp.java new file mode 100644 index 000000000..887451765 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromTtp.java @@ -0,0 +1,5 @@ +package org.highmed.pseudonymization.translation; + +public interface ResultSetTranslatorFromTtp extends ResultSetTranslator +{ +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromTtpImpl.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromTtpImpl.java new file mode 100644 index 000000000..55c801610 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromTtpImpl.java @@ -0,0 +1,72 @@ +package org.highmed.pseudonymization.translation; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.crypto.SecretKey; + +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.Meta; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.openehr.Constants; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ResultSetTranslatorFromTtpImpl extends AbstractResultSetTranslator implements ResultSetTranslatorFromTtp +{ + private final String researchStudyIdentifier; + private final SecretKey researchStudyKey; + + private final ObjectMapper openEhrObjectMapper; + + public ResultSetTranslatorFromTtpImpl(String researchStudyIdentifier, SecretKey researchStudyKey, + ObjectMapper openEhrObjectMapper) + { + this.researchStudyIdentifier = Objects.requireNonNull(researchStudyIdentifier, "researchStudyIdentifier"); + this.researchStudyKey = Objects.requireNonNull(researchStudyKey, "researchStudyKey"); + this.openEhrObjectMapper = Objects.requireNonNull(openEhrObjectMapper, "openEhrObjectMapper"); + } + + @Override + public ResultSet translate(ResultSet resultSet) + { + int psnColumnIndex = getPsnColumnIndex(resultSet.getColumns()); + + if (psnColumnIndex < 0) + throw new IllegalArgumentException("Missing psn column with name '" + Constants.PSN_COLUMN_NAME + + "' and path '" + Constants.PSN_COLUMN_PATH + "'"); + + Meta meta = copyMeta(resultSet.getMeta()); + List<Column> columns = copyColumns(resultSet.getColumns()); + List<List<RowElement>> rows = decodeRowsWithPsnColumn(psnColumnIndex, resultSet.getRows()); + + return new ResultSet(meta, resultSet.getName(), resultSet.getQuery(), columns, rows); + } + + private List<List<RowElement>> decodeRowsWithPsnColumn(int psnColumnIndex, List<List<RowElement>> rows) + { + return rows.parallelStream().map(decodeRowWithPsnColumn(psnColumnIndex)).collect(Collectors.toList()); + } + + private Function<List<RowElement>, List<RowElement>> decodeRowWithPsnColumn(int psnColumnIndex) + { + return rowElements -> + { + RowElement psn = rowElements.get(psnColumnIndex); + + List<RowElement> newRowElements = new ArrayList<>(); + for (int i = 0; i < rowElements.size(); i++) + if (i != psnColumnIndex) + newRowElements.add(toDecryptedMdatRowElement(rowElements.get(i), researchStudyKey, + researchStudyIdentifier, openEhrObjectMapper)); + + newRowElements.add(psn); + + return newRowElements; + }; + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromTtp.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromTtp.java new file mode 100644 index 000000000..bd1f0ff7d --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromTtp.java @@ -0,0 +1,5 @@ +package org.highmed.pseudonymization.translation; + +public interface ResultSetTranslatorResearchResultFromTtp extends ResultSetTranslator +{ +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromTtpImpl.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromTtpImpl.java new file mode 100644 index 000000000..a3aecd393 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromTtpImpl.java @@ -0,0 +1,99 @@ +package org.highmed.pseudonymization.translation; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import javax.crypto.SecretKey; + +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.Meta; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.openehr.Constants; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ResultSetTranslatorResearchResultFromTtpImpl extends AbstractResultSetTranslator + implements ResultSetTranslatorResearchResultFromTtp +{ + private final SecretKey organizationKey; + private final String organizationIdentifier; + private final String researchStudyIdentifier; + private final SecretKey researchStudyKey; + + private final ObjectMapper openEhrObjectMapper; + + public ResultSetTranslatorResearchResultFromTtpImpl(SecretKey organizationKey, String organizationIdentifier, + String researchStudyIdentifier, SecretKey researchStudyKey, ObjectMapper openEhrObjectMapper) + { + this.organizationKey = Objects.requireNonNull(organizationKey, "organizationKey"); + this.organizationIdentifier = Objects.requireNonNull(organizationIdentifier, "organizationIdentifier"); + this.researchStudyIdentifier = Objects.requireNonNull(researchStudyIdentifier, "researchStudyIdentifier"); + this.researchStudyKey = Objects.requireNonNull(researchStudyKey, "researchStudyKey"); + this.openEhrObjectMapper = Objects.requireNonNull(openEhrObjectMapper, "openEhrObjectMapper"); + } + + @Override + public ResultSet translate(ResultSet resultSet) + { + int medicIdColumnIndex = getMedicIdColumnIndex(resultSet.getColumns()); + + if (medicIdColumnIndex < 0) + throw new IllegalArgumentException("Missing MeDIC id column with name '" + Constants.MEDICID_COLUMN_NAME + + "' and path '" + Constants.MEDICID_COLUMN_PATH + "'"); + + Meta meta = copyMeta(resultSet.getMeta()); + List<Column> columns = copyColumns(resultSet.getColumns()); + List<List<RowElement>> newRows = decodeRowsWithMedicIdColumn(medicIdColumnIndex, resultSet.getRows()); + + return new ResultSet(meta, resultSet.getName(), resultSet.getQuery(), columns, newRows); + } + + private int getMedicIdColumnIndex(List<Column> columns) + { + for (int i = 0; i < columns.size(); i++) + if (isMedicIdColumn().test(columns.get(i))) + return i; + + return -1; + } + + private Predicate<? super Column> isMedicIdColumn() + { + return column -> Constants.MEDICID_COLUMN_NAME.equals(column.getName()) + && Constants.MEDICID_COLUMN_PATH.equals(column.getPath()); + } + + private List<List<RowElement>> decodeRowsWithMedicIdColumn(int medicIdColumnIndex, List<List<RowElement>> rows) + { + return rows.parallelStream().map(decodeRowWithMedicIdColumn(medicIdColumnIndex)).collect(Collectors.toList()); + } + + private Function<List<RowElement>, List<RowElement>> decodeRowWithMedicIdColumn(int medicIdColumnIndex) + { + return rowElements -> + { + RowElement medicId = rowElements.get(medicIdColumnIndex); + + List<RowElement> newRowElements = new ArrayList<>(); + for (int i = 0; i < rowElements.size(); i++) + if (i != medicIdColumnIndex) + newRowElements.add(toDecryptedMdatRowElement(rowElements.get(i), researchStudyKey, + researchStudyIdentifier, openEhrObjectMapper)); + + newRowElements.add(decryptMedicId(medicId.getValueAsString())); + + return newRowElements; + }; + } + + private RowElement decryptMedicId(String encryptedMedicId) + { + return new StringRowElement(decrypt(organizationKey, organizationIdentifier, encryptedMedicId)); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToTtp.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToTtp.java new file mode 100644 index 000000000..55365240a --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToTtp.java @@ -0,0 +1,5 @@ +package org.highmed.pseudonymization.translation; + +public interface ResultSetTranslatorResearchResultToTtp extends ResultSetTranslator +{ +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToTtpImpl.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToTtpImpl.java new file mode 100644 index 000000000..4f4e65a61 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToTtpImpl.java @@ -0,0 +1,67 @@ +package org.highmed.pseudonymization.translation; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.crypto.SecretKey; + +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.Meta; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.openehr.Constants; + +public class ResultSetTranslatorResearchResultToTtpImpl extends AbstractResultSetTranslator + implements ResultSetTranslatorResearchResultToTtp +{ + private final String researchStudyIdentifier; + private final SecretKey researchStudyKey; + + public ResultSetTranslatorResearchResultToTtpImpl(String researchStudyIdentifier, SecretKey researchStudyKey) + { + this.researchStudyIdentifier = Objects.requireNonNull(researchStudyIdentifier, "researchStudyIdentifier"); + this.researchStudyKey = Objects.requireNonNull(researchStudyKey, "researchStudyKey"); + } + + @Override + public ResultSet translate(ResultSet resultSet) + { + int psnColumnIndex = getPsnColumnIndex(resultSet.getColumns()); + + if (psnColumnIndex < 0) + throw new IllegalArgumentException("Missing psn column with name '" + Constants.PSN_COLUMN_NAME + + "' and path '" + Constants.PSN_COLUMN_PATH + "'"); + + Meta meta = copyMeta(resultSet.getMeta()); + List<Column> columns = copyColumns(resultSet.getColumns()); + List<List<RowElement>> rows = encodeRowsWithPsn(psnColumnIndex, resultSet.getRows()); + + return new ResultSet(meta, resultSet.getName(), resultSet.getQuery(), columns, rows); + } + + private List<List<RowElement>> encodeRowsWithPsn(int psnColumnIndex, List<List<RowElement>> rows) + { + return rows.parallelStream().map(encodeRowWithPsn(psnColumnIndex)).collect(Collectors.toList()); + } + + private Function<List<RowElement>, List<RowElement>> encodeRowWithPsn(int psnColumnIndex) + { + return rowElements -> + { + RowElement psn = rowElements.get(psnColumnIndex); + + List<RowElement> newRowElements = new ArrayList<>(); + for (int i = 0; i < rowElements.size(); i++) + if (i != psnColumnIndex) + newRowElements.add( + toEncryptedMdatRowElement(rowElements.get(i), researchStudyKey, researchStudyIdentifier)); + + newRowElements.add(copyRowElement(psn)); + + return newRowElements; + }; + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtp.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtp.java new file mode 100644 index 000000000..e56a304d1 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtp.java @@ -0,0 +1,5 @@ +package org.highmed.pseudonymization.translation; + +public interface ResultSetTranslatorToTtp extends ResultSetTranslator +{ +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpImpl.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpImpl.java new file mode 100644 index 000000000..c1a06107e --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpImpl.java @@ -0,0 +1,157 @@ +package org.highmed.pseudonymization.translation; + +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.crypto.SecretKey; + +import org.highmed.mpi.client.Idat; +import org.highmed.mpi.client.MasterPatientIndexClient; +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.Meta; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilter; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGenerator; +import org.highmed.pseudonymization.openehr.Constants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ResultSetTranslatorToTtpImpl extends AbstractResultSetTranslator implements ResultSetTranslatorToTtp +{ + private static final Logger logger = LoggerFactory.getLogger(ResultSetTranslatorToTtpImpl.class); + + private final String organizationIdentifier; + private final SecretKey organizationKey; + private final String researchStudyIdentifier; + private final SecretKey researchStudyKey; + + private final RecordBloomFilterGenerator recordBloomFilterGenerator; + private final MasterPatientIndexClient masterPatientIndexClient; + + public ResultSetTranslatorToTtpImpl(String organizationIdentifier, SecretKey organizationKey, + String researchStudyIdentifier, SecretKey researchStudyKey, + RecordBloomFilterGenerator recordBloomFilterGenerator, MasterPatientIndexClient masterPatientIndexClient) + { + this.organizationIdentifier = Objects.requireNonNull(organizationIdentifier, "organizationIdentifier"); + this.organizationKey = Objects.requireNonNull(organizationKey, "organizationKey"); + this.researchStudyIdentifier = Objects.requireNonNull(researchStudyIdentifier, "researchStudyIdentifier"); + this.researchStudyKey = Objects.requireNonNull(researchStudyKey, "researchStudyKey"); + + this.masterPatientIndexClient = Objects.requireNonNull(masterPatientIndexClient, "masterPatientIndexClient"); + this.recordBloomFilterGenerator = Objects.requireNonNull(recordBloomFilterGenerator, + "recordBloomFilterGenerator"); + } + + @Override + public ResultSet translate(ResultSet resultSet) + { + int ehrIdColumnIndex = getEhrColumnIndex(resultSet.getColumns()); + + if (ehrIdColumnIndex < 0) + throw new IllegalArgumentException("Missing ehr id column with name '" + Constants.EHRID_COLUMN_NAME + + "' and path '" + Constants.EHRID_COLUMN_PATH + "'"); + + Meta meta = copyMeta(resultSet.getMeta()); + List<Column> columns = encodeColumnsWithEhrId(resultSet.getColumns()); + List<List<RowElement>> rows = encodeRowsWithEhrId(ehrIdColumnIndex, resultSet.getRows()); + + return new ResultSet(meta, resultSet.getName(), resultSet.getQuery(), columns, rows); + } + + private int getEhrColumnIndex(List<Column> columns) + { + for (int i = 0; i < columns.size(); i++) + if (isEhrIdColumn().test(columns.get(i))) + return i; + + return -1; + } + + private Predicate<? super Column> isEhrIdColumn() + { + return column -> Constants.EHRID_COLUMN_NAME.equals(column.getName()) + && Constants.EHRID_COLUMN_PATH.equals(column.getPath()); + } + + private List<Column> encodeColumnsWithEhrId(List<Column> columns) + { + Stream<Column> s1 = columns.stream().filter(isEhrIdColumn().negate()).map(copyColumn()); + Stream<Column> s2 = newMedicIdAndRbfColumn(); + return Stream.concat(s1, s2).collect(Collectors.toList()); + } + + private Stream<Column> newMedicIdAndRbfColumn() + { + return Stream.of(new Column(Constants.MEDICID_COLUMN_NAME, Constants.MEDICID_COLUMN_PATH), + new Column(Constants.RBF_COLUMN_NAME, Constants.RBF_COLUMN_PATH)); + } + + private List<List<RowElement>> encodeRowsWithEhrId(int ehrIdColumnIndex, List<List<RowElement>> rows) + { + return rows.parallelStream().map(encodeRowWithEhrId(ehrIdColumnIndex)).collect(Collectors.toList()); + } + + private Function<List<RowElement>, List<RowElement>> encodeRowWithEhrId(int ehrIdColumnIndex) + { + return rowElements -> + { + RowElement ehrId = rowElements.get(ehrIdColumnIndex); + + List<RowElement> newRowElements = new ArrayList<>(); + for (int i = 0; i < rowElements.size(); i++) + if (i != ehrIdColumnIndex) + newRowElements.add( + toEncryptedMdatRowElement(rowElements.get(i), researchStudyKey, researchStudyIdentifier)); + + Idat idat = retrieveIdat(ehrId); + + newRowElements.add(encodeAsEncrypedMedicId(idat)); + newRowElements.add(encodeAsRbf(idat)); + + return newRowElements; + }; + } + + private Idat retrieveIdat(RowElement ehrId) + { + if (!(ehrId instanceof StringRowElement)) + throw new IllegalStateException("EhrId " + RowElement.class.getSimpleName() + " of type " + + StringRowElement.class.getName() + " expected, but got " + ehrId.getClass().getName()); + + String id = ((StringRowElement) ehrId).getValue(); + try + { + Idat fetchedIdat = masterPatientIndexClient.fetchIdat(id); + + if (fetchedIdat == null) + throw new RuntimeException("IDAT could not be fetched, client returned null for ID " + id); + + return fetchedIdat; + } + catch (Exception e) + { + logger.warn("Error while fetching IDAT from MPI for ID " + id, e); + throw e; + } + } + + private RowElement encodeAsEncrypedMedicId(Idat idat) + { + return new StringRowElement(encrypt(organizationKey, organizationIdentifier, idat.getMedicId())); + } + + private RowElement encodeAsRbf(Idat idat) + { + RecordBloomFilter recordBloomFilter = recordBloomFilterGenerator.generate(idat); + String rbfEncodedToString = Base64.getEncoder().encodeToString(recordBloomFilter.getBitSet().toByteArray()); + return new StringRowElement(rbfEncodedToString); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpRbfOnly.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpRbfOnly.java new file mode 100644 index 000000000..9dea0d382 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpRbfOnly.java @@ -0,0 +1,5 @@ +package org.highmed.pseudonymization.translation; + +public interface ResultSetTranslatorToTtpRbfOnly extends ResultSetTranslator +{ +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpRbfOnlyImpl.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpRbfOnlyImpl.java new file mode 100644 index 000000000..9b9f4ffd7 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpRbfOnlyImpl.java @@ -0,0 +1,124 @@ +package org.highmed.pseudonymization.translation; + +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.highmed.mpi.client.Idat; +import org.highmed.mpi.client.MasterPatientIndexClient; +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.Meta; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilter; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGenerator; + +import org.highmed.pseudonymization.openehr.Constants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ResultSetTranslatorToTtpRbfOnlyImpl extends AbstractResultSetTranslator + implements ResultSetTranslatorToTtpRbfOnly +{ + private static final Logger logger = LoggerFactory.getLogger(ResultSetTranslatorToTtpRbfOnlyImpl.class); + + private final RecordBloomFilterGenerator recordBloomFilterGenerator; + private final MasterPatientIndexClient masterPatientIndexClient; + + public ResultSetTranslatorToTtpRbfOnlyImpl( + RecordBloomFilterGenerator recordBloomFilterGenerator, + MasterPatientIndexClient masterPatientIndexClient) + { + this.masterPatientIndexClient = Objects.requireNonNull(masterPatientIndexClient, "masterPatientIndexClient"); + this.recordBloomFilterGenerator = Objects.requireNonNull(recordBloomFilterGenerator, + "recordBloomFilterGenerator"); + } + + @Override + public ResultSet translate(ResultSet resultSet) + { + int ehrIdColumnIndex = getEhrColumnIndex(resultSet.getColumns()); + + if (ehrIdColumnIndex < 0) + throw new IllegalArgumentException("Missing ehr id column with name '" + Constants.EHRID_COLUMN_NAME + + "' and path '" + Constants.EHRID_COLUMN_PATH + "'"); + + Meta meta = copyMeta(resultSet.getMeta()); + List<Column> columns = translageColumns(resultSet.getColumns()); + List<List<RowElement>> rows = encodeRowsWithEhrId(ehrIdColumnIndex, resultSet.getRows()); + + return new ResultSet(meta, resultSet.getName(), resultSet.getQuery(), columns, rows); + } + + private int getEhrColumnIndex(List<Column> columns) + { + for (int i = 0; i < columns.size(); i++) + if (isEhrIdColumn().test(columns.get(i))) + return i; + + return -1; + } + + private Predicate<? super Column> isEhrIdColumn() + { + return column -> Constants.EHRID_COLUMN_NAME.equals(column.getName()) + && Constants.EHRID_COLUMN_PATH.equals(column.getPath()); + } + + private List<Column> translageColumns(List<Column> columns) + { + return Collections.singletonList(new Column(Constants.RBF_COLUMN_NAME, Constants.RBF_COLUMN_PATH)); + } + + private List<List<RowElement>> encodeRowsWithEhrId(int ehrIdColumnIndex, List<List<RowElement>> rows) + { + return rows.parallelStream().map(encodeRowWithEhrId(ehrIdColumnIndex)).collect(Collectors.toList()); + } + + private Function<List<RowElement>, List<RowElement>> encodeRowWithEhrId(int ehrIdColumnIndex) + { + return rowElements -> + { + RowElement ehrId = rowElements.get(ehrIdColumnIndex); + Idat idat = retrieveIdat(ehrId); + + RowElement rbf = encodeAsRbf(idat); + return Collections.singletonList(rbf); + }; + } + + private Idat retrieveIdat(RowElement ehrId) + { + if (!(ehrId instanceof StringRowElement)) + throw new IllegalStateException("EhrId " + RowElement.class.getSimpleName() + " of type " + + StringRowElement.class.getName() + " expected, but got " + ehrId.getClass().getName()); + + String id = ((StringRowElement) ehrId).getValue(); + try + { + Idat fetchedIdat = masterPatientIndexClient.fetchIdat(id); + + if (fetchedIdat == null) + throw new RuntimeException("IDAT could not be fetched, client returned null for ID " + id); + + return fetchedIdat; + } + catch (Exception e) + { + logger.warn("Error while fetching IDAT from MPI for ID " + id, e); + throw e; + } + } + + private RowElement encodeAsRbf(Idat idat) + { + RecordBloomFilter recordBloomFilter = recordBloomFilterGenerator.generate(idat); + String rbfEncodedToString = Base64.getEncoder().encodeToString(recordBloomFilter.getBitSet().toByteArray()); + return new StringRowElement(rbfEncodedToString); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterTest.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterTest.java index c76a66329..bff599577 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterTest.java +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/bloomfilter/RecordBloomFilterTest.java @@ -24,7 +24,7 @@ public void testRbfGeneration() throws Exception bitSet3.set(128, 256); FieldBloomFilter fbf3 = new FieldBloomFilter(bitSet3, 0.5); - RecordBloomFilter rbf = new RecordBloomFilter("seed".getBytes(), Arrays.asList(fbf1, fbf2, fbf3)); + RecordBloomFilter rbf = new RecordBloomFilter(42L, Arrays.asList(fbf1, fbf2, fbf3)); assertEquals(1024, rbf.length()); BitSet rbfBitSet = rbf.getBitSet(); @@ -48,8 +48,8 @@ public void testShuffling() throws Exception bitSet3.set(128, 256); FieldBloomFilter fbf3 = new FieldBloomFilter(bitSet3, 0.5); - RecordBloomFilter rbf1 = new RecordBloomFilter("seed 1".getBytes(), Arrays.asList(fbf1, fbf2, fbf3)); - RecordBloomFilter rbf2 = new RecordBloomFilter("seed 2".getBytes(), Arrays.asList(fbf1, fbf2, fbf3)); + RecordBloomFilter rbf1 = new RecordBloomFilter(42L, Arrays.asList(fbf1, fbf2, fbf3)); + RecordBloomFilter rbf2 = new RecordBloomFilter(27L, Arrays.asList(fbf1, fbf2, fbf3)); assertFalse(Arrays.equals(rbf1.getBitSet().toByteArray(), rbf2.getBitSet().toByteArray())); } diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/IdatTestImpl.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/IdatTestImpl.java new file mode 100644 index 000000000..1c395cd88 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/IdatTestImpl.java @@ -0,0 +1,92 @@ +package org.highmed.pseudonymization.translation; + +import org.highmed.mpi.client.Idat; + +class IdatTestImpl implements Idat +{ + private final String medicId; + private final String firstName; + private final String lastName; + private final String birthday; + private final String sex; + private final String street; + private final String zipCode; + private final String city; + private final String country; + private final String insuranceNumber; + + IdatTestImpl(String medicId, String firstName, String lastName, String birthday, String sex, String street, + String zipCode, String city, String country, String insuranceNumber) + { + this.medicId = medicId; + this.firstName = firstName; + this.lastName = lastName; + this.birthday = birthday; + this.sex = sex; + this.street = street; + this.zipCode = zipCode; + this.city = city; + this.country = country; + this.insuranceNumber = insuranceNumber; + } + + @Override + public String getMedicId() + { + return medicId; + } + + @Override + public String getFirstName() + { + return firstName; + } + + @Override + public String getLastName() + { + return lastName; + } + + @Override + public String getBirthday() + { + return birthday; + } + + @Override + public String getSex() + { + return sex; + } + + @Override + public String getStreet() + { + return street; + } + + @Override + public String getZipCode() + { + return zipCode; + } + + @Override + public String getCity() + { + return city; + } + + @Override + public String getCountry() + { + return country; + } + + @Override + public String getInsuranceNumber() + { + return insuranceNumber; + } +} \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/MasterPatientIndexClientTestImpl.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/MasterPatientIndexClientTestImpl.java new file mode 100644 index 000000000..d2a5add05 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/MasterPatientIndexClientTestImpl.java @@ -0,0 +1,24 @@ +package org.highmed.pseudonymization.translation; + +import java.util.HashMap; +import java.util.Map; + +import org.highmed.mpi.client.Idat; +import org.highmed.mpi.client.MasterPatientIndexClient; + +class MasterPatientIndexClientTestImpl implements MasterPatientIndexClient +{ + private final Map<String, Idat> idats = new HashMap<>(); + + MasterPatientIndexClientTestImpl(Map<String, Idat> idats) + { + if (idats != null) + this.idats.putAll(idats); + } + + @Override + public Idat fetchIdat(String ehrId) + { + return idats.get(ehrId); + } +} \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromTtpTest.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromTtpTest.java new file mode 100644 index 000000000..ef34895ec --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromTtpTest.java @@ -0,0 +1,63 @@ +package org.highmed.pseudonymization.translation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Base64; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; +import org.highmed.openehr.model.structure.ResultSet; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ResultSetTranslatorFromTtpTest +{ + private static final Logger logger = LoggerFactory.getLogger(ResultSetTranslatorFromTtpTest.class); + + @Test + public void testTranslateFromTtp() throws Exception + { + String researchStudyIdentifier = "researchStudy1"; + byte[] decodedKey = Base64.getDecoder().decode("Loy75q55b/L3yxk3BoRgNUSAJJLan643alkrWHathBk="); + SecretKey researchStudyKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); + ObjectMapper openEhrObjectMapper = OpenEhrObjectMapperFactory.createObjectMapper(); + + ResultSetTranslatorFromTtpImpl translator = new ResultSetTranslatorFromTtpImpl(researchStudyIdentifier, + researchStudyKey, openEhrObjectMapper); + ResultSet resultSet = openEhrObjectMapper + .readValue(Files.readAllBytes(Paths.get("src/test/resources/result_5_PSN.json")), ResultSet.class); + + assertNotNull(resultSet); + assertNotNull(resultSet.getColumns()); + assertEquals(4, resultSet.getColumns().size()); + assertNotNull(resultSet.getRows()); + assertEquals(1, resultSet.getRows().size()); + assertNotNull(resultSet.getRow(0)); + assertEquals(4, resultSet.getRow(0).size()); + + ResultSet translatedResultSet = translator.translate(resultSet); + assertNotNull(translatedResultSet); + assertNotNull(translatedResultSet.getColumns()); + assertEquals(4, translatedResultSet.getColumns().size()); + assertNotNull(translatedResultSet.getRows()); + assertEquals(1, translatedResultSet.getRows().size()); + assertNotNull(translatedResultSet.getRow(0)); + assertEquals(4, translatedResultSet.getRow(0).size()); + + DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); + prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE); + + logger.debug("Encoded ResultSet {}", + openEhrObjectMapper.writer(prettyPrinter).writeValueAsString(translatedResultSet)); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromTtpTest.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromTtpTest.java new file mode 100644 index 000000000..511e3a207 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromTtpTest.java @@ -0,0 +1,69 @@ +package org.highmed.pseudonymization.translation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Base64; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; +import org.highmed.openehr.model.structure.ResultSet; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ResultSetTranslatorResearchResultFromTtpTest +{ + private static final Logger logger = LoggerFactory.getLogger(ResultSetTranslatorResearchResultFromTtpTest.class); + + @Test + public void testTranslateResearchResultFromTtp() throws Exception + { + String organizationIdentifier = "org1"; + byte[] decodedOrganizationKey = Base64.getDecoder().decode("KollbDbopQK1t6hZncLicT7X64H1TfrzjpYdF4jehHo="); + SecretKey organizationKey = new SecretKeySpec(decodedOrganizationKey, 0, decodedOrganizationKey.length, "AES"); + + String researchStudyIdentifier = "researchStudy1"; + byte[] decodedKey = Base64.getDecoder().decode("Loy75q55b/L3yxk3BoRgNUSAJJLan643alkrWHathBk="); + SecretKey researchStudyKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); + + ObjectMapper openEhrObjectMapper = OpenEhrObjectMapperFactory.createObjectMapper(); + + ResultSetTranslatorResearchResultFromTtpImpl translator = new ResultSetTranslatorResearchResultFromTtpImpl(organizationKey, + organizationIdentifier, researchStudyIdentifier, researchStudyKey, openEhrObjectMapper); + + ResultSet resultSet = openEhrObjectMapper + .readValue(Files.readAllBytes(Paths.get("src/test/resources/researchresult_from_ttp.json")), ResultSet.class); + assertNotNull(resultSet); + assertNotNull(resultSet.getColumns()); + assertEquals(3, resultSet.getColumns().size()); + assertNotNull(resultSet.getRows()); + assertEquals(1, resultSet.getRows().size()); + assertNotNull(resultSet.getRow(0)); + assertEquals(3, resultSet.getRow(0).size()); + + ResultSet translatedResultSet = translator.translate(resultSet); + assertNotNull(translatedResultSet); + assertNotNull(translatedResultSet.getColumns()); + assertEquals(3, translatedResultSet.getColumns().size()); + assertNotNull(translatedResultSet.getRows()); + assertEquals(1, translatedResultSet.getRows().size()); + assertNotNull(translatedResultSet.getRow(0)); + assertEquals(3, translatedResultSet.getRow(0).size()); + + DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); + prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE); + + logger.debug("Encoded ResultSet {}", + openEhrObjectMapper.writer(prettyPrinter).writeValueAsString(translatedResultSet)); + + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToTtpTest.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToTtpTest.java new file mode 100644 index 000000000..3330878bc --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToTtpTest.java @@ -0,0 +1,61 @@ +package org.highmed.pseudonymization.translation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.nio.file.Files; +import java.nio.file.Paths; + +import javax.crypto.SecretKey; + +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.pseudonymization.crypto.AesGcmUtil; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ResultSetTranslatorResearchResultToTtpTest +{ + private static final Logger logger = LoggerFactory.getLogger(ResultSetTranslatorResearchResultToTtpTest.class); + + @Test + public void testTranslateResearchResultForTtp() throws Exception + { + String researchStudyIdentifier = "researchStudy1"; + SecretKey researchStudyKey = AesGcmUtil.generateAES256Key(); + + ResultSetTranslatorResearchResultToTtpImpl translator = new ResultSetTranslatorResearchResultToTtpImpl( + researchStudyIdentifier, researchStudyKey); + + ObjectMapper openEhrObjectMapper = OpenEhrObjectMapperFactory.createObjectMapper(); + ResultSet resultSet = openEhrObjectMapper + .readValue(Files.readAllBytes(Paths.get("src/test/resources/result_5_PSN.json")), ResultSet.class); + assertNotNull(resultSet); + assertNotNull(resultSet.getColumns()); + assertEquals(4, resultSet.getColumns().size()); + assertNotNull(resultSet.getRows()); + assertEquals(1, resultSet.getRows().size()); + assertNotNull(resultSet.getRow(0)); + assertEquals(4, resultSet.getRow(0).size()); + + ResultSet translatedResultSet = translator.translate(resultSet); + assertNotNull(translatedResultSet); + assertNotNull(translatedResultSet.getColumns()); + assertEquals(4, translatedResultSet.getColumns().size()); + assertNotNull(translatedResultSet.getRows()); + assertEquals(1, translatedResultSet.getRows().size()); + assertNotNull(translatedResultSet.getRow(0)); + assertEquals(4, translatedResultSet.getRow(0).size()); + + DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); + prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE); + + logger.debug("Encoded ResultSet {}", + openEhrObjectMapper.writer(prettyPrinter).writeValueAsString(translatedResultSet)); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/encoding/ResultSetEncoderImplTest.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpTest.java similarity index 50% rename from dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/encoding/ResultSetEncoderImplTest.java rename to dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpTest.java index 3b654c811..a2d47c8e2 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/encoding/ResultSetEncoderImplTest.java +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpTest.java @@ -1,16 +1,18 @@ -package org.highmed.pseudonymization.encoding; +package org.highmed.pseudonymization.translation; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.HashMap; import java.util.Map; import java.util.Random; import javax.crypto.SecretKey; -import org.highmed.openehr.OpenEhrObjectMapperFactory; +import org.highmed.mpi.client.Idat; +import org.highmed.mpi.client.MasterPatientIndexClient; +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; import org.highmed.openehr.model.structure.ResultSet; import org.highmed.pseudonymization.bloomfilter.BloomFilterGenerator; import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGenerator; @@ -18,8 +20,6 @@ import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGeneratorImpl.FieldBloomFilterLengths; import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGeneratorImpl.FieldWeights; import org.highmed.pseudonymization.crypto.AesGcmUtil; -import org.highmed.pseudonymization.mpi.Idat; -import org.highmed.pseudonymization.mpi.MasterPatientIndexClient; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,124 +28,17 @@ import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.ObjectMapper; -public class ResultSetEncoderImplTest +public class ResultSetTranslatorToTtpTest { - private static class IdatTestImpl implements Idat - { - final String medicId; - final String firstName; - final String lastName; - final String birthday; - final String sex; - final String street; - final String zipCode; - final String city; - final String country; - final String insuranceNumber; - - IdatTestImpl(String medicId, String firstName, String lastName, String birthday, String sex, String street, - String zipCode, String city, String country, String insuranceNumber) - { - this.medicId = medicId; - this.firstName = firstName; - this.lastName = lastName; - this.birthday = birthday; - this.sex = sex; - this.street = street; - this.zipCode = zipCode; - this.city = city; - this.country = country; - this.insuranceNumber = insuranceNumber; - } - - @Override - public String getMedicId() - { - return medicId; - } - - @Override - public String getFirstName() - { - return firstName; - } - - @Override - public String getLastName() - { - return lastName; - } - - @Override - public String getBirthday() - { - return birthday; - } - - @Override - public String getSex() - { - return sex; - } - - @Override - public String getStreet() - { - return street; - } - - @Override - public String getZipCode() - { - return zipCode; - } - - @Override - public String getCity() - { - return city; - } - - @Override - public String getCountry() - { - return country; - } - - @Override - public String getInsuranceNumber() - { - return insuranceNumber; - } - } - - private static class MasterPatientIndexClientTestImpl implements MasterPatientIndexClient - { - final Map<String, Idat> idats = new HashMap<>(); - - MasterPatientIndexClientTestImpl(Map<String, Idat> idats) - { - if (idats != null) - this.idats.putAll(idats); - } - - @Override - public Idat fetchIdat(String ehrID) - { - return idats.get(ehrID); - } - } - - private static final Logger logger = LoggerFactory.getLogger(ResultSetEncoderImplTest.class); + private static final Logger logger = LoggerFactory.getLogger(ResultSetTranslatorToTtpTest.class); @Test - public void testEncodeForTtp() throws Exception + public void testTranslateForTtp() throws Exception { Random random = new Random(); int recordBloomFilterLength = 2000; - byte[] permutationSeed = new byte[64]; - random.nextBytes(permutationSeed); + long permutationSeed = 42L; FieldWeights weights = new FieldWeights(0.1, 0.1, 0.1, 0.2, 0.05, 0.1, 0.05, 0.2, 0.1); FieldBloomFilterLengths lengths = new FieldBloomFilterLengths(500, 500, 250, 50, 500, 250, 500, 500, 500); @@ -160,29 +53,40 @@ public void testEncodeForTtp() throws Exception () -> new BloomFilterGenerator.HmacMd5HmacSha1BiGramHasher(hashKey1, hashKey2)); Map<String, Idat> idats = Map.of("ehrId1", new IdatTestImpl("medicId1", "firstName1", "lastName1", "birthday1", - "sex1", "street1", "zipCode1", "city1", "country1", "insuranceNumber")); + "sex1", "street1", "zipCode1", "city1", "country1", "insuranceNumber1")); MasterPatientIndexClient masterPatientIndexClient = new MasterPatientIndexClientTestImpl(idats); String organizationIdentifier = "org1"; SecretKey organizationKey = AesGcmUtil.generateAES256Key(); String researchStudyIdentifier = "researchStudy1"; SecretKey researchStudyKey = AesGcmUtil.generateAES256Key(); - ObjectMapper openEhrObjectMapper = OpenEhrObjectMapperFactory.createObjectMapper(); - ResultSetEncoder encoder = new ResultSetEncoderImpl(recordBloomFilterGenerator, masterPatientIndexClient, - organizationIdentifier, organizationKey, researchStudyIdentifier, researchStudyKey, - openEhrObjectMapper); + ResultSetTranslatorToTtpImpl translator = new ResultSetTranslatorToTtpImpl(organizationIdentifier, organizationKey, + researchStudyIdentifier, researchStudyKey, recordBloomFilterGenerator, masterPatientIndexClient); + ObjectMapper openEhrObjectMapper = OpenEhrObjectMapperFactory.createObjectMapper(); ResultSet resultSet = openEhrObjectMapper .readValue(Files.readAllBytes(Paths.get("src/test/resources/result_5.json")), ResultSet.class); assertNotNull(resultSet); - - ResultSet encodedResultSet = encoder.encode(resultSet); - assertNotNull(encodedResultSet); + assertNotNull(resultSet.getColumns()); + assertEquals(4, resultSet.getColumns().size()); + assertNotNull(resultSet.getRows()); + assertEquals(1, resultSet.getRows().size()); + assertNotNull(resultSet.getRow(0)); + assertEquals(4, resultSet.getRow(0).size()); + + ResultSet translatedResultSet = translator.translate(resultSet); + assertNotNull(translatedResultSet); + assertNotNull(translatedResultSet.getColumns()); + assertEquals(5, translatedResultSet.getColumns().size()); + assertNotNull(translatedResultSet.getRows()); + assertEquals(1, translatedResultSet.getRows().size()); + assertNotNull(translatedResultSet.getRow(0)); + assertEquals(5, translatedResultSet.getRow(0).size()); DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE); logger.debug("Encoded ResultSet {}", - openEhrObjectMapper.writer(prettyPrinter).writeValueAsString(encodedResultSet)); + openEhrObjectMapper.writer(prettyPrinter).writeValueAsString(translatedResultSet)); } } diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpTestRbfOnly.java b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpTestRbfOnly.java new file mode 100644 index 000000000..b81429ba4 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToTtpTestRbfOnly.java @@ -0,0 +1,89 @@ +package org.highmed.pseudonymization.translation; + +import static org.junit.Assert.*; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.highmed.mpi.client.Idat; +import org.highmed.mpi.client.MasterPatientIndexClient; +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.bloomfilter.BloomFilterGenerator; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGenerator; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGeneratorImpl; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGeneratorImpl.FieldBloomFilterLengths; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilterGeneratorImpl.FieldWeights; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ResultSetTranslatorToTtpTestRbfOnly +{ + private static final Logger logger = LoggerFactory.getLogger(ResultSetTranslatorToTtpTestRbfOnly.class); + + @Test + public void testIdsOnly() throws Exception + { + Random random = new Random(); + + int recordBloomFilterLength = 2000; + long permutationSeed = 42L; + + FieldWeights weights = new FieldWeights(0.1, 0.1, 0.1, 0.2, 0.05, 0.1, 0.05, 0.2, 0.1); + FieldBloomFilterLengths lengths = new FieldBloomFilterLengths(500, 500, 250, 50, 500, 250, 500, 500, 500); + + byte[] hashKey1 = new byte[64]; + random.nextBytes(hashKey1); + byte[] hashKey2 = new byte[64]; + random.nextBytes(hashKey2); + + RecordBloomFilterGenerator recordBloomFilterGenerator = new RecordBloomFilterGeneratorImpl( + recordBloomFilterLength, permutationSeed, weights, lengths, + () -> new BloomFilterGenerator.HmacMd5HmacSha1BiGramHasher(hashKey1, hashKey2)); + + Map<String, Idat> idats = new HashMap<>(); + IntStream.range(0, 15).mapToObj(String::valueOf) + .forEach(id -> idats.put(id, + new IdatTestImpl("medicId" + id, "firstName" + id, "lastName" + id, "birthday" + id, "sex" + id, + "street" + id, "zipCode" + id, "city" + id, "country" + id, "insuranceNumber" + id))); + + MasterPatientIndexClient masterPatientIndexClient = new MasterPatientIndexClientTestImpl(idats); + + ResultSetTranslatorToTtpRbfOnlyImpl translator = new ResultSetTranslatorToTtpRbfOnlyImpl(recordBloomFilterGenerator, + masterPatientIndexClient); + + ObjectMapper openEhrObjectMapper = OpenEhrObjectMapperFactory.createObjectMapper(); + DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); + prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE); + + List<List<RowElement>> rows = IntStream.range(0, 15) + .mapToObj(id -> Collections.<RowElement> singletonList(new StringRowElement(String.valueOf(id)))) + .collect(Collectors.toList()); + ResultSet resultSet = new ResultSet(null, null, "SELECT e/ehr_id/value as EHRID FROM EHR e", + Collections.singleton(new Column("EHRID", "/ehr_id/value")), rows); + + logger.debug("ResultSet {}", openEhrObjectMapper.writer(prettyPrinter).writeValueAsString(resultSet)); + ResultSet translated = translator.translate(resultSet); + assertNotNull(translated); + logger.debug("Encoded ResultSet {}", openEhrObjectMapper.writer(prettyPrinter).writeValueAsString(translated)); + + assertNotNull(translated.getColumns()); + assertEquals(1, translated.getColumns().size()); + assertNotNull(translated.getRows()); + assertEquals(15, translated.getRows().size()); + assertEquals(15, translated.getRows().stream().mapToInt(List::size).sum()); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/resources/researchresult_from_ttp.json b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/resources/researchresult_from_ttp.json new file mode 100644 index 000000000..11457fd7a --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/resources/researchresult_from_ttp.json @@ -0,0 +1,33 @@ +{ + "meta" : { + "_href" : "http://test.com", + "_type" : "RESULTSET", + "_schema_version" : "1.0.0", + "_created" : "2017-08-19T00:25:47.568+02:00", + "_generator" : "DIPS.OpenEhr.ResultSets.Serialization.Json.ResultSetJsonWriter (5.0.0.0)", + "_executed_aql" : "SELECT e FROM EHR(e)" + }, + "name" : "<the name/identifier of the stored query that was executed>", + "q" : "select e/ehr_id/value, c/context/start_time/value as startTime, c/uid/value as cid, c/name from EHR e contains Composition c limit 2", + "columns" : [ + { + "name" : "startTime", + "path" : "/context/start_time/value" + }, + { + "name" : "cid", + "path" : "/uid/value" + }, + { + "name" : "MEDICID", + "path" : "/medic_id/value" + } + ], + "rows" : [ + [ + "timestamp:lzQqfBhMynbmvX1nUMCsMihlf657UeyQsXzZjcnoUTO8xrOU47SDdHFnmo4p2+Sj46s5DR8k2gwU", + "string:Lb+ReGgmLt3ZoSyrWooE68c3obJvCOH7RX9SDXz7+9ULxhGa92DCoJr188fPssM9W95E1FBA+s/u6N2hREA0L2zJKBqX9m8IErOd3Q==", + "0sguqzZiiN6ZEPNTiTF/oMw1hefL26c0x9LmXOapEcCUjIwLJHY=" + ] + ] +} \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/resources/result_5_PSN.json b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/resources/result_5_PSN.json new file mode 100644 index 000000000..84d9d4f62 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-medic/src/test/resources/result_5_PSN.json @@ -0,0 +1,38 @@ +{ + "meta" : { + "_href" : "http://test.com", + "_type" : "RESULTSET", + "_schema_version" : "1.0.0", + "_created" : "2017-08-19T00:25:47.568+02:00", + "_generator" : "DIPS.OpenEhr.ResultSets.Serialization.Json.ResultSetJsonWriter (5.0.0.0)", + "_executed_aql" : "SELECT e FROM EHR(e)" + }, + "name" : "<the name/identifier of the stored query that was executed>", + "q" : "select e/ehr_id/value, c/context/start_time/value as startTime, c/uid/value as cid, c/name from EHR e contains Composition c limit 2", + "columns" : [ + { + "name" : "startTime", + "path" : "/context/start_time/value" + }, + { + "name" : "cid", + "path" : "/uid/value" + }, + { + "name" : "#3", + "path" : "/name" + }, + { + "name":"PSN", + "path":"/psn/value" + } + ], + "rows" : [ + [ + "timestamp:lzQqfBhMynbmvX1nUMCsMihlf657UeyQsXzZjcnoUTO8xrOU47SDdHFnmo4p2+Sj46s5DR8k2gwU", + "string:Lb+ReGgmLt3ZoSyrWooE68c3obJvCOH7RX9SDXz7+9ULxhGa92DCoJr188fPssM9W95E1FBA+s/u6N2hREA0L2zJKBqX9m8IErOd3Q==", + "json:FAhBy9k24DBMn82u3JpVE8UjHh9YWbE1ttQqiRJTVLYeDLo96CNkSKNiJIe29D52ndaZYaK02It3/bZAfhE=", + "5dILUn30jagbVoSvTLaqROiqCRh4GPrcLWfU4oO6T/MwVK6/" + ] + ] +} \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/.gitignore b/dsf-pseudonymization/dsf-pseudonymization-ttp/.gitignore index d98981cc4..369c51d14 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/.gitignore +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/.gitignore @@ -2,3 +2,4 @@ /.classpath /.project /.settings/ +*.csv \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/pom.xml b/dsf-pseudonymization/dsf-pseudonymization-ttp/pom.xml index efe3e6628..a520f2c24 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/pom.xml +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-pseudonymization-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> @@ -15,15 +15,54 @@ <groupId>org.highmed.dsf</groupId> <artifactId>dsf-pseudonymization-base</artifactId> </dependency> + <dependency> + <groupId>org.highmed.dsf</groupId> + <artifactId>dsf-mpi-client</artifactId> + </dependency> <dependency> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-openehr-model</artifactId> </dependency> + <dependency> + <groupId>ca.uhn.hapi.fhir</groupId> + <artifactId>hapi-fhir-structures-r4</artifactId> + </dependency> + <dependency> <groupId>de.hs-heilbronn.mi</groupId> <artifactId>log4j2-utils</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk15on</artifactId> + <version>1.65</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.highmed.dsf</groupId> + <artifactId>dsf-pseudonymization-medic</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-csv</artifactId> + <scope>test</scope> + </dependency> </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <includes> + <include>org.highmed.pseudonymization.test.TestSuiteAll</include> + </includes> + </configuration> + </plugin> + </plugins> + </build> </project> \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/MdatContainer.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/MdatContainer.java new file mode 100644 index 000000000..da88cb5cb --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/MdatContainer.java @@ -0,0 +1,11 @@ +package org.highmed.pseudonymization.domain; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.As; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "@type") +public interface MdatContainer +{ + +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/PersonWithMdat.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/PersonWithMdat.java new file mode 100644 index 000000000..6fc59b578 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/PersonWithMdat.java @@ -0,0 +1,13 @@ +package org.highmed.pseudonymization.domain; + +import org.highmed.pseudonymization.recordlinkage.Person; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.As; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "@type") +public interface PersonWithMdat extends Person +{ + MdatContainer getMdatContainer(); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/PseudonymizedPerson.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/PseudonymizedPerson.java new file mode 100644 index 000000000..72db77ec3 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/PseudonymizedPerson.java @@ -0,0 +1,6 @@ +package org.highmed.pseudonymization.domain; + +public interface PseudonymizedPerson +{ + String getPseudonym(); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/PseudonymizedPersonWithMdat.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/PseudonymizedPersonWithMdat.java new file mode 100644 index 000000000..f2fa00ac6 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/PseudonymizedPersonWithMdat.java @@ -0,0 +1,8 @@ +package org.highmed.pseudonymization.domain; + +import java.util.List; + +public interface PseudonymizedPersonWithMdat extends PseudonymizedPerson +{ + List<MdatContainer> getMdatContainers(); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/FhirMdatContainer.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/FhirMdatContainer.java new file mode 100644 index 000000000..cfd75c589 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/FhirMdatContainer.java @@ -0,0 +1,29 @@ +package org.highmed.pseudonymization.domain.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.highmed.pseudonymization.domain.MdatContainer; +import org.hl7.fhir.r4.model.Resource; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class FhirMdatContainer implements MdatContainer +{ + private final List<Resource> elements = new ArrayList<>(); + + @JsonCreator + public FhirMdatContainer(@JsonProperty("elements") Collection<? extends Resource> elements) + { + if (elements != null) + this.elements.addAll(elements); + } + + public List<Resource> getElements() + { + return Collections.unmodifiableList(elements); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/MatchedPersonImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/MatchedPersonImpl.java new file mode 100644 index 000000000..ab581ec4b --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/MatchedPersonImpl.java @@ -0,0 +1,61 @@ +package org.highmed.pseudonymization.domain.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.NoSuchElementException; + +import org.highmed.pseudonymization.domain.PersonWithMdat; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class MatchedPersonImpl implements MatchedPerson<PersonWithMdat> +{ + private final List<PersonWithMdat> matches = new ArrayList<>(); + + public MatchedPersonImpl(PersonWithMdat person) + { + if (person != null) + matches.add(person); + } + + @JsonCreator + public MatchedPersonImpl(@JsonProperty("matches") Collection<? extends PersonWithMdat> matches) + { + if (matches != null) + this.matches.addAll(matches); + } + + @Override + public List<PersonWithMdat> getMatches() + { + return Collections.unmodifiableList(matches); + } + + @Override + public void addMatch(PersonWithMdat person) + { + if (person != null) + matches.add(person); + } + + @JsonIgnore + @Override + // overriding default implementation to add JsonIgnore annotation + public PersonWithMdat getFirstMatch() throws NoSuchElementException + { + return MatchedPerson.super.getFirstMatch(); + } + + @JsonIgnore + @Override + // overriding default implementation to add JsonIgnore annotation + public PersonWithMdat getLastMatch() throws NoSuchElementException + { + return MatchedPerson.super.getLastMatch(); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/MedicIdImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/MedicIdImpl.java new file mode 100644 index 000000000..1f87ce6b3 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/MedicIdImpl.java @@ -0,0 +1,29 @@ +package org.highmed.pseudonymization.domain.impl; + +import org.highmed.pseudonymization.recordlinkage.MedicId; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class MedicIdImpl implements MedicId +{ + private final String organization; + private final String value; + + @JsonCreator + public MedicIdImpl(@JsonProperty("organization") String organization, @JsonProperty("value") String value) + { + this.organization = organization; + this.value = value; + } + + public String getOrganization() + { + return organization; + } + + public String getValue() + { + return value; + } +} \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/OpenEhrMdatContainer.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/OpenEhrMdatContainer.java new file mode 100644 index 000000000..f308b2eb9 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/OpenEhrMdatContainer.java @@ -0,0 +1,29 @@ +package org.highmed.pseudonymization.domain.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.domain.MdatContainer; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class OpenEhrMdatContainer implements MdatContainer +{ + private final List<RowElement> elements = new ArrayList<>(); + + @JsonCreator + public OpenEhrMdatContainer(@JsonProperty("elements") Collection<? extends RowElement> elements) + { + if (elements != null) + this.elements.addAll(elements); + } + + public List<RowElement> getElements() + { + return Collections.unmodifiableList(elements); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/PersonImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/PersonImpl.java new file mode 100644 index 000000000..f2f44906d --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/PersonImpl.java @@ -0,0 +1,54 @@ +package org.highmed.pseudonymization.domain.impl; + +import java.util.BitSet; + +import org.highmed.pseudonymization.domain.MdatContainer; +import org.highmed.pseudonymization.domain.PersonWithMdat; +import org.highmed.pseudonymization.recordlinkage.MedicId; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class PersonImpl implements PersonWithMdat +{ + private final MedicId medicId; + private final BitSet recordBloomFilter; + private final MdatContainer mdatContainer; + + @JsonCreator + public PersonImpl(@JsonProperty("medicId") MedicId medicId, + @JsonProperty("recordBloomFilter") BitSet recordBloomFilter, + @JsonProperty("mdatContainer") MdatContainer mdatContainer) + { + this.medicId = medicId; + this.recordBloomFilter = recordBloomFilter; + this.mdatContainer = mdatContainer; + } + + @Override + public MedicId getMedicId() + { + return medicId; + } + + @Override + public BitSet getRecordBloomFilter() + { + return recordBloomFilter; + } + + @Override + public MdatContainer getMdatContainer() + { + return mdatContainer; + } + + @JsonIgnore + @Override + // overriding default implementation to add JsonIgnore annotation + public int getBloomFilterCardinality() + { + return PersonWithMdat.super.getBloomFilterCardinality(); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/PseudonymizedPersonImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/PseudonymizedPersonImpl.java new file mode 100644 index 000000000..d25d7d108 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/impl/PseudonymizedPersonImpl.java @@ -0,0 +1,51 @@ +package org.highmed.pseudonymization.domain.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.highmed.pseudonymization.domain.MdatContainer; +import org.highmed.pseudonymization.domain.PersonWithMdat; +import org.highmed.pseudonymization.domain.PseudonymizedPersonWithMdat; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class PseudonymizedPersonImpl implements PseudonymizedPersonWithMdat +{ + private final String pseudonym; + private final List<MdatContainer> mdatContainers = new ArrayList<>(); + + public PseudonymizedPersonImpl(MatchedPerson<PersonWithMdat> person, String pseudonym) + { + this.pseudonym = pseudonym; + + if (person != null) + mdatContainers.addAll(person.getMatches().stream().map(m -> m.getMdatContainer()).filter(m -> m != null) + .collect(Collectors.toList())); + } + + @JsonCreator + public PseudonymizedPersonImpl(@JsonProperty("pseudonym") String pseudonym, + @JsonProperty("mdatContainers") Collection<? extends MdatContainer> mdatContainers) + { + this.pseudonym = pseudonym; + + if (mdatContainers != null) + this.mdatContainers.addAll(mdatContainers); + } + + @Override + public String getPseudonym() + { + return pseudonym; + } + + @Override + public List<MdatContainer> getMdatContainers() + { + return mdatContainers; + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/json/ResourceDeserializer.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/json/ResourceDeserializer.java new file mode 100644 index 000000000..25829b43c --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/json/ResourceDeserializer.java @@ -0,0 +1,40 @@ +package org.highmed.pseudonymization.domain.json; + +import java.io.IOException; + +import org.hl7.fhir.r4.model.Resource; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; + +public class ResourceDeserializer extends JsonDeserializer<Resource> +{ + private FhirContext fhirContext; + + public ResourceDeserializer(FhirContext fhirContext) + { + this.fhirContext = fhirContext; + } + + private IParser getParser() + { + IParser p = fhirContext.newJsonParser(); + p.setStripVersionsFromReferences(false); + p.setOverrideResourceIdWithBundleEntryFullUrl(false); + return p; + } + + @Override + public Resource deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException, JsonProcessingException + { + JsonNode node = jsonParser.getCodec().readTree(jsonParser); + return (Resource) getParser().parseResource(node.toString()); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/json/ResourceSerializer.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/json/ResourceSerializer.java new file mode 100644 index 000000000..a6aa1efc7 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/json/ResourceSerializer.java @@ -0,0 +1,37 @@ +package org.highmed.pseudonymization.domain.json; + +import java.io.IOException; + +import org.hl7.fhir.r4.model.Resource; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; + +public class ResourceSerializer extends JsonSerializer<Resource> +{ + private FhirContext fhirContext; + + public ResourceSerializer(FhirContext fhirContext) + { + this.fhirContext = fhirContext; + } + + private IParser getParser() + { + IParser p = fhirContext.newJsonParser(); + p.setStripVersionsFromReferences(false); + p.setOverrideResourceIdWithBundleEntryFullUrl(false); + return p; + } + + @Override + public void serialize(Resource value, JsonGenerator gen, SerializerProvider serializers) throws IOException + { + String json = getParser().encodeResourceToString(value); + gen.writeRawValue(json); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/json/TtpObjectMapperFactory.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/json/TtpObjectMapperFactory.java new file mode 100644 index 000000000..cbe86a28f --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/domain/json/TtpObjectMapperFactory.java @@ -0,0 +1,51 @@ +package org.highmed.pseudonymization.domain.json; + +import java.util.BitSet; + +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; +import org.highmed.pseudonymization.domain.impl.FhirMdatContainer; +import org.highmed.pseudonymization.domain.impl.MatchedPersonImpl; +import org.highmed.pseudonymization.domain.impl.MedicIdImpl; +import org.highmed.pseudonymization.domain.impl.OpenEhrMdatContainer; +import org.highmed.pseudonymization.domain.impl.PersonImpl; +import org.highmed.pseudonymization.json.BitSetDeserializer; +import org.highmed.pseudonymization.json.BitSetSerializer; +import org.hl7.fhir.r4.model.Resource; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.NamedType; +import com.fasterxml.jackson.databind.module.SimpleModule; + +import ca.uhn.fhir.context.FhirContext; + +public final class TtpObjectMapperFactory +{ + private TtpObjectMapperFactory() + { + } + + public static ObjectMapper createObjectMapper(FhirContext fhirContext) + { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(Include.NON_NULL); + objectMapper.setSerializationInclusion(Include.NON_EMPTY); + + objectMapper.registerModule(OpenEhrObjectMapperFactory.openEhrModule()); + + SimpleModule module = new SimpleModule(); + module.addDeserializer(BitSet.class, new BitSetDeserializer()); + module.addSerializer(BitSet.class, new BitSetSerializer()); + module.addDeserializer(Resource.class, new ResourceDeserializer(fhirContext)); + module.addSerializer(Resource.class, new ResourceSerializer(fhirContext)); + objectMapper.registerModule(module); + + objectMapper.registerSubtypes(new NamedType(MedicIdImpl.class, "MedicId")); + objectMapper.registerSubtypes(new NamedType(OpenEhrMdatContainer.class, "OpenEhrMdatContainer")); + objectMapper.registerSubtypes(new NamedType(FhirMdatContainer.class, "FhirMdatContainer")); + objectMapper.registerSubtypes(new NamedType(PersonImpl.class, "Person")); + objectMapper.registerSubtypes(new NamedType(MatchedPersonImpl.class, "MatchedPerson")); + + return objectMapper; + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/MatchedPersonFactory.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/MatchedPersonFactory.java new file mode 100644 index 000000000..593dc9821 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/MatchedPersonFactory.java @@ -0,0 +1,14 @@ +package org.highmed.pseudonymization.psn; + +import java.util.List; + +import org.highmed.pseudonymization.domain.PseudonymizedPerson; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.recordlinkage.MedicId; +import org.highmed.pseudonymization.recordlinkage.Person; + +@FunctionalInterface +public interface MatchedPersonFactory<P extends Person> +{ + MatchedPerson<P> create(PseudonymizedPerson person, List<MedicId> medicIds); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/Pseudonym.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/Pseudonym.java deleted file mode 100644 index 408c1f945..000000000 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/Pseudonym.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.highmed.pseudonymization.psn; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class Pseudonym -{ - private final List<MedicId> medicIds = new ArrayList<>(); - - @JsonCreator - public Pseudonym(@JsonProperty("medicIds") Collection<? extends MedicId> medicIds) - { - if (medicIds != null) - this.medicIds.addAll(medicIds); - } - - public List<MedicId> getMedicIds() - { - return Collections.unmodifiableList(medicIds); - } -} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymDecoder.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymDecoder.java new file mode 100644 index 000000000..bf32117f7 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymDecoder.java @@ -0,0 +1,18 @@ +package org.highmed.pseudonymization.psn; + +import java.util.List; +import java.util.stream.Collectors; + +import org.highmed.pseudonymization.domain.PseudonymizedPerson; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.recordlinkage.Person; + +public interface PseudonymDecoder<P extends Person> +{ + MatchedPerson<P> decodePseudonym(PseudonymizedPerson person); + + default List<MatchedPerson<P>> decodePseudonyms(List<PseudonymizedPerson> persons) + { + return persons.parallelStream().map(this::decodePseudonym).collect(Collectors.toList()); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymDecoderImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymDecoderImpl.java new file mode 100644 index 000000000..71c7b765a --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymDecoderImpl.java @@ -0,0 +1,67 @@ +package org.highmed.pseudonymization.psn; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Objects; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; + +import org.highmed.pseudonymization.crypto.AesGcmUtil; +import org.highmed.pseudonymization.domain.PseudonymizedPerson; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.recordlinkage.Person; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class PseudonymDecoderImpl<P extends Person> implements PseudonymDecoder<P> +{ + private static final Logger logger = LoggerFactory.getLogger(PseudonymDecoderImpl.class); + + private final String researchStudyIdentifier; + private final byte[] researchStudyIdentifierAadTag; + + private final SecretKey researchStudyTtpKey; + private final ObjectMapper psnObjectMapper; + + private final MatchedPersonFactory<P> matchedPersonFactory; + + public PseudonymDecoderImpl(String researchStudyIdentifier, SecretKey researchStudyTtpKey, + ObjectMapper psnObjectMapper, MatchedPersonFactory<P> matchedPersonFactory) + { + this.researchStudyIdentifier = Objects.requireNonNull(researchStudyIdentifier, "researchStudyIdentifier"); + researchStudyIdentifierAadTag = researchStudyIdentifier.getBytes(StandardCharsets.UTF_8); + + this.researchStudyTtpKey = Objects.requireNonNull(researchStudyTtpKey, "researchStudyTtpKey"); + this.psnObjectMapper = Objects.requireNonNull(psnObjectMapper, "psnObjectMapper"); + + this.matchedPersonFactory = Objects.requireNonNull(matchedPersonFactory, "matchedPersonFactory"); + } + + @Override + public MatchedPerson<P> decodePseudonym(PseudonymizedPerson person) + { + try + { + byte[] encryptedPwp = Base64.getDecoder().decode(person.getPseudonym()); + byte[] decryptPwp = AesGcmUtil.decrypt(encryptedPwp, researchStudyIdentifierAadTag, researchStudyTtpKey); + PseudonymWithPadding pwp = psnObjectMapper.readValue(decryptPwp, PseudonymWithPadding.class); + + return matchedPersonFactory.create(person, pwp.medicIds); + } + catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException + | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException | IOException e) + { + logger.error("Error while decrypting with aadTag " + researchStudyIdentifier, e); + throw new RuntimeException(e); + } + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymEncoder.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymEncoder.java deleted file mode 100644 index 7d4e4402d..000000000 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymEncoder.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.highmed.pseudonymization.psn; - -import java.util.List; - -public interface PseudonymEncoder -{ - List<String> encodePseudonyms(List<Pseudonym> pseudonyms); - - List<Pseudonym> decodePseudonyms(List<String> pseudonyms); -} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymEncoderImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymEncoderImpl.java deleted file mode 100644 index 5a11477da..000000000 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymEncoderImpl.java +++ /dev/null @@ -1,178 +0,0 @@ -package org.highmed.pseudonymization.psn; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Base64; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.ShortBufferException; - -import org.highmed.pseudonymization.crypto.AesGcmUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -public class PseudonymEncoderImpl implements PseudonymEncoder -{ - private static final Logger logger = LoggerFactory.getLogger(PseudonymEncoderImpl.class); - - private static class PseudonymWithJsonLength - { - final int jsonLength; - final List<MedicId> medicIds = new ArrayList<>(); - - PseudonymWithJsonLength(int jsonLength, Collection<? extends MedicId> medicIds) - { - this.jsonLength = jsonLength; - if (medicIds != null) - this.medicIds.addAll(medicIds); - } - - int getJsonLength() - { - return jsonLength; - } - } - - private static class PseudonymWithPadding - { - @JsonProperty - final List<MedicId> medicIds = new ArrayList<>(); - - @JsonProperty - final String padding; - - PseudonymWithPadding(int paddingLength, Collection<? extends MedicId> medicIds) - { - this(IntStream.range(0, paddingLength).mapToObj(i -> " ").collect(Collectors.joining()), medicIds); - } - - PseudonymWithPadding(@JsonProperty("padding") String padding, - @JsonProperty("medicIds") Collection<? extends MedicId> medicIds) - { - this.padding = padding; - if (medicIds != null) - this.medicIds.addAll(medicIds); - } - } - - private final String researchStudyIdentifier; - private final byte[] researchStudyIdentifierAadTag; - - private final SecretKey researchStudyTtpKey; - private final ObjectMapper psnObjectMapper; - - public PseudonymEncoderImpl(String researchStudyIdentifier, SecretKey researchStudyTtpKey, - ObjectMapper psnObjectMapper) - { - this.researchStudyIdentifier = Objects.requireNonNull(researchStudyIdentifier, "researchStudyIdentifier"); - researchStudyIdentifierAadTag = researchStudyIdentifier.getBytes(StandardCharsets.UTF_8); - - this.researchStudyTtpKey = Objects.requireNonNull(researchStudyTtpKey, "researchStudyTtpKey"); - this.psnObjectMapper = Objects.requireNonNull(psnObjectMapper, "psnObjectMapper"); - } - - @Override - public List<String> encodePseudonyms(List<Pseudonym> pseudonyms) - { - Objects.requireNonNull(pseudonyms, "pseudonyms"); - if (pseudonyms.isEmpty()) - return Collections.emptyList(); - - List<PseudonymWithJsonLength> pseudonymsWithJsonLength = pseudonyms.parallelStream() - .map(toPseudonymWithJsonLength()).collect(Collectors.toList()); - - int maxLength = pseudonymsWithJsonLength.parallelStream() - .max(Comparator.comparingInt(PseudonymWithJsonLength::getJsonLength)) - .map(PseudonymWithJsonLength::getJsonLength).orElse(0); - - return pseudonymsWithJsonLength.parallelStream().map(encrypt(maxLength)).collect(Collectors.toList()); - } - - private Function<Pseudonym, PseudonymWithJsonLength> toPseudonymWithJsonLength() - { - return pseudonym -> - { - try - { - byte[] bytes = psnObjectMapper.writeValueAsBytes(pseudonym); - return new PseudonymWithJsonLength(bytes.length, pseudonym.getMedicIds()); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - }; - } - - private Function<PseudonymWithJsonLength, String> encrypt(int maxLength) - { - return pseudonym -> - { - try - { - PseudonymWithPadding pwp = new PseudonymWithPadding(maxLength - pseudonym.jsonLength, - pseudonym.medicIds); - - byte[] plainPwp = psnObjectMapper.writeValueAsBytes(pwp); - byte[] encrypted = AesGcmUtil.encrypt(plainPwp, researchStudyIdentifierAadTag, researchStudyTtpKey); - return Base64.getEncoder().encodeToString(encrypted); - } - catch (JsonProcessingException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException - | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException - | ShortBufferException e) - { - logger.error("Error while encrypting with aadTag " + researchStudyIdentifier, e); - throw new RuntimeException(e); - } - }; - } - - @Override - public List<Pseudonym> decodePseudonyms(List<String> pseudonyms) - { - return pseudonyms.parallelStream().map(decrypt()).collect(Collectors.toList()); - } - - private Function<String, Pseudonym> decrypt() - { - return encryptedPwpBase64 -> - { - - try - { - byte[] encryptedPwp = Base64.getDecoder().decode(encryptedPwpBase64); - byte[] decryptPwp = AesGcmUtil.decrypt(encryptedPwp, researchStudyIdentifierAadTag, - researchStudyTtpKey); - PseudonymWithPadding pwp = psnObjectMapper.readValue(decryptPwp, PseudonymWithPadding.class); - - return new Pseudonym(pwp.medicIds); - } - catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException - | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException - | IOException e) - { - logger.error("Error while decrypting with aadTag " + researchStudyIdentifier, e); - throw new RuntimeException(e); - } - }; - } -} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymGenerator.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymGenerator.java new file mode 100644 index 000000000..49f40dbec --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymGenerator.java @@ -0,0 +1,13 @@ +package org.highmed.pseudonymization.psn; + +import java.util.Collection; +import java.util.List; + +import org.highmed.pseudonymization.domain.PseudonymizedPerson; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.recordlinkage.Person; + +public interface PseudonymGenerator<P extends Person, R extends PseudonymizedPerson> +{ + List<R> createPseudonymsAndShuffle(Collection<? extends MatchedPerson<P>> persons); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymGeneratorImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymGeneratorImpl.java new file mode 100644 index 000000000..2c637e975 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymGeneratorImpl.java @@ -0,0 +1,155 @@ +package org.highmed.pseudonymization.psn; + +import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; + +import org.highmed.pseudonymization.crypto.AesGcmUtil; +import org.highmed.pseudonymization.domain.PseudonymizedPerson; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.recordlinkage.MedicId; +import org.highmed.pseudonymization.recordlinkage.Person; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class PseudonymGeneratorImpl<P extends Person, PP extends PseudonymizedPerson> + implements PseudonymGenerator<P, PP> +{ + private static final Logger logger = LoggerFactory.getLogger(PseudonymGeneratorImpl.class); + + private static final class Pseudonym + { + @JsonProperty + final List<MedicId> medicIds = new ArrayList<>(); + + @JsonCreator + public Pseudonym(@JsonProperty("medicIds") Collection<? extends MedicId> medicIds) + { + if (medicIds != null) + this.medicIds.addAll(medicIds); + } + } + + private static final class PseudonymWithJsonLength + { + final int jsonLength; + final List<MedicId> medicIds = new ArrayList<>(); + + PseudonymWithJsonLength(int jsonLength, Collection<? extends MedicId> medicIds) + { + this.jsonLength = jsonLength; + if (medicIds != null) + this.medicIds.addAll(medicIds); + } + + int getJsonLength() + { + return jsonLength; + } + } + + private final String researchStudyIdentifier; + private final byte[] researchStudyIdentifierAadTag; + + private final SecretKey researchStudyTtpKey; + private final ObjectMapper psnObjectMapper; + + private final PseudonymizedPersonFactory<P, PP> pseudonymizedPersonFactory; + + public PseudonymGeneratorImpl(String researchStudyIdentifier, SecretKey researchStudyTtpKey, + ObjectMapper psnObjectMapper, PseudonymizedPersonFactory<P, PP> pseudonymizedPersonFactory) + { + this.researchStudyIdentifier = Objects.requireNonNull(researchStudyIdentifier, "researchStudyIdentifier"); + researchStudyIdentifierAadTag = researchStudyIdentifier.getBytes(StandardCharsets.UTF_8); + + this.researchStudyTtpKey = Objects.requireNonNull(researchStudyTtpKey, "researchStudyTtpKey"); + this.psnObjectMapper = Objects.requireNonNull(psnObjectMapper, "psnObjectMapper"); + + this.pseudonymizedPersonFactory = Objects.requireNonNull(pseudonymizedPersonFactory, + "pseudonymizedPersonFactory"); + } + + @Override + public List<PP> createPseudonymsAndShuffle(Collection<? extends MatchedPerson<P>> persons) + { + Objects.requireNonNull(persons, "persons"); + if (persons.isEmpty()) + return Collections.emptyList(); + + Map<MatchedPerson<P>, PseudonymWithJsonLength> pseudonyms = persons.parallelStream() + .collect(Collectors.toMap(Function.identity(), toPseudonym(), (p1, p2) -> p1, LinkedHashMap::new)); + + int maxLength = pseudonyms.values().parallelStream() + .max(Comparator.comparingInt(PseudonymWithJsonLength::getJsonLength)) + .map(PseudonymWithJsonLength::getJsonLength).orElse(0); + + return pseudonyms.entrySet().parallelStream() + .map(e -> pseudonymizedPersonFactory.create(e.getKey(), encrypt(e.getValue(), maxLength))) + .collect(Collectors.collectingAndThen(Collectors.toCollection(ArrayList::new), list -> + { + Collections.shuffle(list); + return list; + })); + } + + private Function<MatchedPerson<P>, PseudonymWithJsonLength> toPseudonym() + { + return matchedPerson -> + { + List<MedicId> medicIds = matchedPerson.getMatches().stream().map(Person::getMedicId) + .collect(Collectors.toList()); + + try + { + byte[] bytes = psnObjectMapper.writeValueAsBytes(new Pseudonym(medicIds)); + return new PseudonymWithJsonLength(bytes.length, medicIds); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + }; + } + + private String encrypt(PseudonymWithJsonLength pseudonym, int maxLength) + { + try + { + PseudonymWithPadding pwp = new PseudonymWithPadding(maxLength - pseudonym.jsonLength, pseudonym.medicIds); + + byte[] plainPwp = psnObjectMapper.writeValueAsBytes(pwp); + byte[] encrypted = AesGcmUtil.encrypt(plainPwp, researchStudyIdentifierAadTag, researchStudyTtpKey); + return Base64.getEncoder().encodeToString(encrypted); + } + catch (JsonProcessingException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException + | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException + | ShortBufferException e) + { + logger.error("Error while encrypting with aadTag " + researchStudyIdentifier, e); + throw new RuntimeException(e); + } + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymWithPadding.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymWithPadding.java new file mode 100644 index 000000000..ebca8345f --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymWithPadding.java @@ -0,0 +1,35 @@ +package org.highmed.pseudonymization.psn; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.highmed.pseudonymization.recordlinkage.MedicId; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +class PseudonymWithPadding +{ + @JsonProperty + final List<MedicId> medicIds = new ArrayList<>(); + + @JsonProperty + final String padding; + + PseudonymWithPadding(int paddingLength, Collection<? extends MedicId> medicIds) + { + this(IntStream.range(0, paddingLength).mapToObj(i -> " ").collect(Collectors.joining()), medicIds); + } + + @JsonCreator + PseudonymWithPadding(@JsonProperty("padding") String padding, + @JsonProperty("medicIds") Collection<? extends MedicId> medicIds) + { + this.padding = padding; + if (medicIds != null) + this.medicIds.addAll(medicIds); + } +} \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymizedPersonFactory.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymizedPersonFactory.java new file mode 100644 index 000000000..4981826a8 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/PseudonymizedPersonFactory.java @@ -0,0 +1,11 @@ +package org.highmed.pseudonymization.psn; + +import org.highmed.pseudonymization.domain.PseudonymizedPerson; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.recordlinkage.Person; + +@FunctionalInterface +public interface PseudonymizedPersonFactory<P extends Person, PP extends PseudonymizedPerson> +{ + PP create(MatchedPerson<P> person, String pseudonym); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/AbstractMatcher.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/AbstractMatcher.java index fe3dbd3ff..071ba18c7 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/AbstractMatcher.java +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/AbstractMatcher.java @@ -2,30 +2,31 @@ import java.util.Collection; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.stream.DoubleStream; -public abstract class AbstractMatcher +public abstract class AbstractMatcher<P extends Person> { - private static class MatchResult implements Comparable<MatchResult> + private static class MatchResult<P extends Person> implements Comparable<MatchResult<P>> { final double result; - final MatchedPerson matchedPerson; + final MatchedPerson<P> matchedPerson; - MatchResult(double result, MatchedPerson matchedPerson) + MatchResult(double result, MatchedPerson<P> matchedPerson) { this.result = result; this.matchedPerson = matchedPerson; } - MatchedPerson getMatchedPerson() + MatchedPerson<P> getMatchedPerson() { return matchedPerson; } @Override - public int compareTo(MatchResult o) + public int compareTo(MatchResult<P> o) { return Double.compare(result, o.result); } @@ -38,6 +39,8 @@ boolean isResultAboveThreshold(double threshold) public static final double DEFAULT_POSITIVE_MATCH_THRESHOLD = 0.8; + private final MatchedPersonFactory<P> matchedPersonFactory; + private final MatchCalculator matchCalculator; private final double positiveMatchThreshold; @@ -45,63 +48,77 @@ boolean isResultAboveThreshold(double threshold) * Uses {@value #DEFAULT_POSITIVE_MATCH_THRESHOLD} as the {@link #positiveMatchThreshold}.<br> * Uses {@link MatchCalculatorStrategy#MIN} as the {@link #matchCalculator} * + * @param matchedPersonFactory + * not <code>null</code> */ - protected AbstractMatcher() + protected AbstractMatcher(MatchedPersonFactory<P> matchedPersonFactory) { - this(MatchCalculatorStrategy.MIN, DEFAULT_POSITIVE_MATCH_THRESHOLD); + this(matchedPersonFactory, MatchCalculatorStrategy.MIN, DEFAULT_POSITIVE_MATCH_THRESHOLD); } /** * Uses {@value #DEFAULT_POSITIVE_MATCH_THRESHOLD} as the {@link #positiveMatchThreshold} * + * @param matchedPersonFactory + * not <code>null</code> * @param matchCalculator * not <code>null</code> */ - protected AbstractMatcher(MatchCalculator matchCalculator) + protected AbstractMatcher(MatchedPersonFactory<P> matchedPersonFactory, MatchCalculator matchCalculator) { - this(matchCalculator, DEFAULT_POSITIVE_MATCH_THRESHOLD); + this(matchedPersonFactory, matchCalculator, DEFAULT_POSITIVE_MATCH_THRESHOLD); } /** + * @param matchedPersonFactory + * not <code>null</code> * @param matchCalculator * not <code>null</code> * @param positiveMatchThreshold */ - protected AbstractMatcher(MatchCalculator matchCalculator, double positiveMatchThreshold) + protected AbstractMatcher(MatchedPersonFactory<P> matchedPersonFactory, MatchCalculator matchCalculator, + double positiveMatchThreshold) { - this.matchCalculator = matchCalculator; + this.matchedPersonFactory = Objects.requireNonNull(matchedPersonFactory, "matchedPersonFactory"); + this.matchCalculator = Objects.requireNonNull(matchCalculator, "matchCalculator"); this.positiveMatchThreshold = positiveMatchThreshold; } - protected final Function<? super Person, MatchedPerson> matchPerson( - Collection<? extends MatchedPerson> matchedPersons) + protected final Function<? super P, MatchedPerson<P>> matchPerson( + Collection<? extends MatchedPerson<P>> matchedPersons) { return person -> matchPerson(person, matchedPersons); } - - protected final MatchedPerson matchPerson(Person person, Collection<? extends MatchedPerson> matchedPersons) + protected final MatchedPerson<P> matchPerson(P person, Collection<? extends MatchedPerson<P>> matchedPersons) { - Optional<MatchResult> bestMatch = matchedPersons.parallelStream().map(matchCalculator.calculateMatch(person)) + Optional<MatchResult<P>> bestMatch = matchedPersons.parallelStream().map(matchCalculator.calculateMatch(person)) .filter(m -> m.isResultAboveThreshold(positiveMatchThreshold)).max(MatchResult::compareTo); - Optional<MatchedPerson> matchedPerson = bestMatch.map(MatchResult::getMatchedPerson); + Optional<MatchedPerson<P>> matchedPerson = bestMatch.map(MatchResult::getMatchedPerson); - return matchedPerson.map(add(person)).orElseGet(MatchedPerson.from(person)); + return matchedPerson.map(add(person)).orElseGet(() -> matchedPersonFactory.create(person)); } - private Function<MatchedPerson, MatchedPerson> add(Person person) + private Function<MatchedPerson<P>, MatchedPerson<P>> add(P person) { return matchedPerson -> { - synchronized (matchedPerson) - { - matchedPerson.addMatch(person); - } + matchedPerson.addMatch(person); return matchedPerson; }; } + protected final Function<P, MatchedPerson<P>> toMatchedPerson() + { + return person -> matchedPersonFactory.create(person); + } + + protected final MatchedPerson<P> create(P person) + { + return matchedPersonFactory.create(person); + } + public static interface MatchCalculator { /** @@ -113,14 +130,15 @@ public static interface MatchCalculator * @throws NoSuchElementException * if the list of {@link Person}s inside {@link MatchedPerson} is empty */ - MatchResult calculateMatch(MatchedPerson matchedPerson, Person personToMatch) throws NoSuchElementException; + <P extends Person> MatchResult<P> calculateMatch(MatchedPerson<P> matchedPerson, P personToMatch) + throws NoSuchElementException; /** * @param personToMatch * not <code>null</code> * @return Function for {@link #calculateMatch(MatchedPerson, Person)} */ - default Function<MatchedPerson, MatchResult> calculateMatch(Person personToMatch) + default <P extends Person> Function<MatchedPerson<P>, MatchResult<P>> calculateMatch(P personToMatch) { return matchedPerson -> calculateMatch(matchedPerson, personToMatch); } @@ -134,97 +152,95 @@ public static enum MatchCalculatorStrategy implements MatchCalculator * @see MatchedPerson#getMatches() */ FIRST - { - @Override - public MatchResult calculateMatch(MatchedPerson matchedPerson, Person personToMatch) - { - double firstMatch = matchedPerson.getFirstMatch().compareTo(personToMatch); - return new MatchResult(firstMatch, matchedPerson); - } - }, + { + @Override + public <P extends Person> MatchResult<P> calculateMatch(MatchedPerson<P> matchedPerson, P personToMatch) + { + double firstMatch = matchedPerson.getFirstMatch().compareTo(personToMatch); + return new MatchResult<P>(firstMatch, matchedPerson); + } + }, /** * Matches against the last person already matched * * @see MatchedPerson#getMatches() */ LAST - { - @Override - public MatchResult calculateMatch(MatchedPerson matchedPerson, Person personToMatch) - { - double lastMatch = matchedPerson.getLastMatch().compareTo(personToMatch); - return new MatchResult(lastMatch, matchedPerson); - } - }, + { + @Override + public <P extends Person> MatchResult<P> calculateMatch(MatchedPerson<P> matchedPerson, P personToMatch) + { + double lastMatch = matchedPerson.getLastMatch().compareTo(personToMatch); + return new MatchResult<P>(lastMatch, matchedPerson); + } + }, /** * Matches against all persons already matched and selects the maximum (best) match * * @see MatchedPerson#getMatches() */ MAX - { - @Override - public MatchResult calculateMatch(MatchedPerson matchedPerson, Person personToMatch) - { - - double maxMatch = matchedPerson.getMatches().stream().mapToDouble(p -> p.compareTo(personToMatch)).max() - .orElseThrow(); - System.out.println("With match confidence: " + maxMatch); - return new MatchResult(maxMatch, matchedPerson); - } - }, + { + @Override + public <P extends Person> MatchResult<P> calculateMatch(MatchedPerson<P> matchedPerson, P personToMatch) + { + double maxMatch = matchedPerson.getMatches().stream().mapToDouble(p -> p.compareTo(personToMatch)).max() + .orElseThrow(); + return new MatchResult<P>(maxMatch, matchedPerson); + } + }, /** * Matches against all persons already matched and selects the minimum (worst) match * * @see MatchedPerson#getMatches() */ MIN - { - @Override - public MatchResult calculateMatch(MatchedPerson matchedPerson, Person personToMatch) - { - double minMatch = matchedPerson.getMatches().stream().mapToDouble(p -> p.compareTo(personToMatch)).min() - .orElseThrow(); - return new MatchResult(minMatch, matchedPerson); - } - }, + { + @Override + public <P extends Person> MatchResult<P> calculateMatch(MatchedPerson<P> matchedPerson, P personToMatch) + { + double minMatch = matchedPerson.getMatches().stream().mapToDouble(p -> p.compareTo(personToMatch)).min() + .orElseThrow(); + return new MatchResult<P>(minMatch, matchedPerson); + } + }, /** - * Matches against all personss already matched and calculates the average match + * Matches against all persons already matched and calculates the average match * * @see MatchedPerson#getMatches() */ AVG - { - @Override - public MatchResult calculateMatch(MatchedPerson matchedPerson, Person personToMatch) - { - double avgMatch = matchedPerson.getMatches().stream().mapToDouble(p -> p.compareTo(personToMatch)) - .average().orElseThrow(); - return new MatchResult(avgMatch, matchedPerson); - } - }, + { + @Override + public <P extends Person> MatchResult<P> calculateMatch(MatchedPerson<P> matchedPerson, P personToMatch) + { + double avgMatch = matchedPerson.getMatches().stream().mapToDouble(p -> p.compareTo(personToMatch)) + .average().orElseThrow(); + return new MatchResult<P>(avgMatch, matchedPerson); + } + }, /** * Matches against all persons already matched and calculates the median match * * @see MatchedPerson#getMatches() */ MEDIAN - { - @Override - public MatchResult calculateMatch(MatchedPerson matchedPerson, Person personToMatch) - { - if (matchedPerson.getMatches().isEmpty()) - throw new NoSuchElementException(); - - DoubleStream sorted = matchedPerson.getMatches().stream().mapToDouble(p -> p.compareTo(personToMatch)) - .sorted(); - - double median = matchedPerson.getMatches().size() % 2 == 0 - ? sorted.skip(matchedPerson.getMatches().size() / 2 - 1).limit(2).average().getAsDouble() - : sorted.skip(matchedPerson.getMatches().size() / 2).findFirst().getAsDouble(); - - return new MatchResult(median, matchedPerson); - } - } + { + @Override + public <P extends Person> MatchResult<P> calculateMatch(MatchedPerson<P> matchedPerson, P personToMatch) + { + if (matchedPerson.getMatches().isEmpty()) + throw new NoSuchElementException(); + + DoubleStream sorted = matchedPerson.getMatches().stream().mapToDouble(p -> p.compareTo(personToMatch)) + .sorted(); + + double median = matchedPerson.getMatches().size() % 2 == 0 + ? sorted.skip(matchedPerson.getMatches().size() / 2 - 1).limit(2).average().getAsDouble() + : sorted.skip(matchedPerson.getMatches().size() / 2).findFirst().getAsDouble(); + + return new MatchResult<P>(median, matchedPerson); + } + } } } \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcher.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcher.java index 8ad21962b..595d7a22e 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcher.java +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcher.java @@ -1,76 +1,17 @@ package org.highmed.pseudonymization.recordlinkage; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; -public class FederatedMatcher extends AbstractMatcher +/** + * Federated record linkage matcher to match {@link Person}s from multiple organizations. The matcher assumes that the + * supplied lists of persons are unique per organization. + * + * @param <P> + * the type of the persons matched by this federated matcher + */ +public interface FederatedMatcher<P extends Person> { - /** - * See {@link AbstractMatcher#AbstractEpiLinkMatcher()} - */ - public FederatedMatcher() - { - } - - /** - * See {@link AbstractMatcher#AbstractEpiLinkMatcher(MatchCalculator)} - * - * @param matchCalculator - * not <code>null</code> - */ - public FederatedMatcher(MatchCalculator matchCalculator) - { - super(matchCalculator); - } - - /** - * See {@link AbstractMatcher#AbstractEpiLinkMatcher(MatchCalculator, double)} - * - * @param matchCalculator - * not <code>null</code> - * @param positiveMatchThreshold - */ - public FederatedMatcher(MatchCalculator matchCalculator, double positiveMatchThreshold) - { - super(matchCalculator, positiveMatchThreshold); - } - - /** - * Matches {@link Person}s from multiple organizations, expects the {@link Person}s to be unique within - * organizations - distributed matching. - * - * @param personList - * not <code>null</code> - * @param personLists - * not <code>null</code>, may be of length 0 - * @return matched persons, converted persons from param {@code personList} if param {@code personLists} is empty - * @see #matchPersons(List) - */ - public Set<MatchedPerson> matchPersons(List<Person> personList, - @SuppressWarnings("unchecked") List<Person>... personLists) - { - Objects.requireNonNull(personList, "personList"); - Objects.requireNonNull(personLists, "personLists"); - - if (personLists.length == 0) - return personList.stream().map(Person::toMatchedPerson).collect(Collectors.toSet()); - else - { - List<List<Person>> lists = new ArrayList<>(1 + personLists.length); - lists.add(personList); - lists.addAll(Arrays.asList(personLists)); - - return matchPersons(lists); - } - } - /** * Matches {@link Person}s from multiple organizations, expects the {@link Person}s to be unique within * organizations - distributed matching. @@ -81,50 +22,5 @@ public Set<MatchedPerson> matchPersons(List<Person> personList, * one entry (aka one organization), empty list if param {@code personLists} has no entries * @see #matchPersons(List, List...) */ - public Set<MatchedPerson> matchPersons(List<List<Person>> personLists) - { - Objects.requireNonNull(personLists, "personLists"); - - if (personLists.isEmpty()) - return Collections.emptySet(); - else if (personLists.size() == 1) - return personLists.get(0).stream().map(Person::toMatchedPerson).collect(Collectors.toSet()); - else - { - List<Person> largestList = findLargestList(personLists); - List<List<Person>> remainingLists = exceptLargest(personLists, largestList); - Set<MatchedPerson> matchedPersons = toMatchedPersons(largestList); - - for (List<Person> personList : remainingLists) - matchedPersons = matchPersonList(personList, matchedPersons); - - return Collections.unmodifiableSet(matchedPersons); - } - } - - private List<Person> findLargestList(List<List<Person>> personLists) - { - return personLists.stream().max(Comparator.comparing(List::size)).orElseThrow(); - } - - private List<List<Person>> exceptLargest(List<List<Person>> personLists, List<Person> largestList) - { - List<List<Person>> remainingLists = new ArrayList<List<Person>>(personLists); - remainingLists.remove(largestList); - return remainingLists; - } - - private Set<MatchedPerson> toMatchedPersons(List<Person> largestList) - { - return largestList.parallelStream().map(Person::toMatchedPerson).collect(Collectors.toSet()); - } - - private Set<MatchedPerson> matchPersonList(List<Person> personList, Set<MatchedPerson> matchedPersons) - { - Set<MatchedPerson> newMatches = personList.parallelStream().map(matchPerson(matchedPersons)) - .collect(Collectors.toCollection(HashSet::new)); - newMatches.addAll(matchedPersons); - - return newMatches; - } -} + Set<MatchedPerson<P>> matchPersons(List<List<P>> personLists); +} \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcherImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcherImpl.java new file mode 100644 index 000000000..d7b4612b6 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcherImpl.java @@ -0,0 +1,117 @@ +package org.highmed.pseudonymization.recordlinkage; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Federated record linkage matcher implementation to match {@link Person}s from multiple organizations. The matcher + * assumes that the supplied lists of persons are unique per organization. + * + * @param <P> + * the type of the persons matched by this federated matcher + */ +public class FederatedMatcherImpl<P extends Person> extends AbstractMatcher<P> implements FederatedMatcher<P> +{ + /** + * See {@link AbstractMatcher#AbstractMatcher(MatchedPersonFactory)} + * + * @param matchedPersonFactory + * not <code>null</code> + */ + public FederatedMatcherImpl(MatchedPersonFactory<P> matchedPersonFactory) + { + super(matchedPersonFactory); + } + + /** + * See {@link AbstractMatcher#AbstractMatcher(MatchedPersonFactory, MatchCalculator)} + * + * @param matchedPersonFactory + * not <code>null</code> + * @param matchCalculator + * not <code>null</code> + */ + public FederatedMatcherImpl(MatchedPersonFactory<P> matchedPersonFactory, MatchCalculator matchCalculator) + { + super(matchedPersonFactory, matchCalculator); + } + + /** + * See {@link AbstractMatcher#AbstractMatcher(MatchedPersonFactory, MatchCalculator, double)} + * + * @param matchedPersonFactory + * not <code>null</code> + * @param matchCalculator + * not <code>null</code> + * @param positiveMatchThreshold + */ + public FederatedMatcherImpl(MatchedPersonFactory<P> matchedPersonFactory, MatchCalculator matchCalculator, + double positiveMatchThreshold) + { + super(matchedPersonFactory, matchCalculator, positiveMatchThreshold); + } + + /** + * Matches {@link Person}s from multiple organizations, expects the {@link Person}s to be unique within + * organizations - distributed matching. + * + * @param personLists + * not <code>null</code> + * @return matched persons, converted persons from param {@code personLists} if param {@code personLists} has only + * one entry (aka one organization), empty list if param {@code personLists} has no entries + * @see #matchPersons(List, List...) + */ + @Override + public Set<MatchedPerson<P>> matchPersons(List<List<P>> personLists) + { + Objects.requireNonNull(personLists, "personLists"); + + if (personLists.isEmpty()) + return Collections.emptySet(); + else if (personLists.size() == 1) + return personLists.get(0).stream().map(toMatchedPerson()).collect(Collectors.toSet()); + else + { + List<P> largestList = findLargestList(personLists); + List<List<P>> remainingLists = exceptLargest(personLists, largestList); + Set<MatchedPerson<P>> matchedPersons = toMatchedPersons(largestList); + + for (List<P> personList : remainingLists) + matchedPersons = matchPersonList(personList, matchedPersons); + + return Collections.unmodifiableSet(matchedPersons); + } + } + + private List<P> findLargestList(List<List<P>> personLists) + { + return personLists.stream().max(Comparator.comparing(List::size)).orElseThrow(); + } + + private List<List<P>> exceptLargest(List<List<P>> personLists, List<P> largestList) + { + List<List<P>> remainingLists = new ArrayList<>(personLists); + remainingLists.remove(largestList); + return remainingLists; + } + + private Set<MatchedPerson<P>> toMatchedPersons(List<P> largestList) + { + return largestList.parallelStream().map(toMatchedPerson()).collect(Collectors.toSet()); + } + + private Set<MatchedPerson<P>> matchPersonList(List<P> personList, Set<MatchedPerson<P>> matchedPersons) + { + Set<MatchedPerson<P>> newMatches = personList.stream().map(matchPerson(matchedPersons)) + .collect(Collectors.toCollection(HashSet::new)); + newMatches.addAll(matchedPersons); + + return newMatches; + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/MatchedPerson.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/MatchedPerson.java index 567506bcf..c6776867d 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/MatchedPerson.java +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/MatchedPerson.java @@ -2,18 +2,21 @@ import java.util.List; import java.util.NoSuchElementException; -import java.util.function.Function; -import java.util.function.Supplier; -public interface MatchedPerson +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.As; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "@type") +public interface MatchedPerson<P extends Person> { /** * @return list of matched persons, sorted in the order in which they were added * @see #addMatch(Person) */ - List<Person> getMatches(); + List<P> getMatches(); - default Person getFirstMatch() throws NoSuchElementException + default P getFirstMatch() throws NoSuchElementException { if (getMatches().isEmpty()) throw new NoSuchElementException(); @@ -21,7 +24,7 @@ default Person getFirstMatch() throws NoSuchElementException return getMatches().get(0); } - default Person getLastMatch() throws NoSuchElementException + default P getLastMatch() throws NoSuchElementException { if (getMatches().isEmpty()) throw new NoSuchElementException(); @@ -33,19 +36,5 @@ default Person getLastMatch() throws NoSuchElementException * @param person * not <code>null</code> */ - void addMatch(Person person); - - static Function<MatchedPerson, MatchedPerson> add(Person person) - { - return matchedPerson -> - { - matchedPerson.addMatch(person); - return matchedPerson; - }; - } - - static Supplier<MatchedPerson> from(Person person) - { - return () -> person.toMatchedPerson(); - } + void addMatch(P person); } diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/MatchedPersonFactory.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/MatchedPersonFactory.java new file mode 100644 index 000000000..029fd9aba --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/MatchedPersonFactory.java @@ -0,0 +1,7 @@ +package org.highmed.pseudonymization.recordlinkage; + +@FunctionalInterface +public interface MatchedPersonFactory<P extends Person> +{ + MatchedPerson<P> create(P person); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/MedicId.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/MedicId.java new file mode 100644 index 000000000..fbf0af271 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/MedicId.java @@ -0,0 +1,13 @@ +package org.highmed.pseudonymization.recordlinkage; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.As; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "@type") +public interface MedicId +{ + String getOrganization(); + + String getValue(); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/Person.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/Person.java index f63b41330..a334aab2d 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/Person.java +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/Person.java @@ -2,11 +2,14 @@ import java.util.BitSet; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.As; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "@type") public interface Person { - String getOrganization(); - - String getId(); + MedicId getMedicId(); BitSet getRecordBloomFilter(); @@ -17,12 +20,9 @@ default int getBloomFilterCardinality() default double compareTo(Person other) { - // TODO look for faster combined bits calculation that doesn't require cloning BitSet combinedBits = ((BitSet) getRecordBloomFilter().clone()); combinedBits.and(other.getRecordBloomFilter()); return (2.0 * combinedBits.cardinality() / (getBloomFilterCardinality() + other.getBloomFilterCardinality())); } - - MatchedPerson toMatchedPerson(); } diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcher.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcher.java index 968bb946e..8d3b3d294 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcher.java +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcher.java @@ -1,45 +1,16 @@ package org.highmed.pseudonymization.recordlinkage; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Set; -public class SingleOrganizationMatcher extends AbstractMatcher +/** + * Single organization record linkage matcher to match {@link Person}s from a single organization. + * + * @param <P> + * the type of the persons matched by this single organization matcher + */ +public interface SingleOrganizationMatcher<P extends Person> { - /** - * See {@link AbstractMatcher#AbstractEpiLinkMatcher()} - */ - public SingleOrganizationMatcher() - { - } - - /** - * See {@link AbstractMatcher#AbstractEpiLinkMatcher(MatchCalculator)} - * - * @param matchCalculator - * not <code>null</code> - */ - public SingleOrganizationMatcher(MatchCalculator matchCalculator) - { - super(matchCalculator); - } - - /** - * See {@link AbstractMatcher#AbstractEpiLinkMatcher(MatchCalculator, double)} - * - * @param matchCalculator - * not <code>null</code> - * @param positiveMatchThreshold - */ - public SingleOrganizationMatcher(MatchCalculator matchCalculator, double positiveMatchThreshold) - { - super(matchCalculator, positiveMatchThreshold); - } - /** * Matches {@link Person}s from a single organizations - local matching. * @@ -50,22 +21,7 @@ public SingleOrganizationMatcher(MatchCalculator matchCalculator, double positiv * @return matched persons, converted person from param {@code person} if param {@code persons} is empty * @see #matchPersons(List) */ - public Set<MatchedPerson> matchPersons(Person person, Person... persons) - { - Objects.requireNonNull(person, "person"); - Objects.requireNonNull(persons, "persons"); - - if (persons.length == 0) - return Collections.singleton(person.toMatchedPerson()); - else - { - List<Person> list = new ArrayList<>(1 + persons.length); - list.add(person); - list.addAll(Arrays.asList(persons)); - - return matchPersons(list); - } - } + Set<MatchedPerson<P>> matchPersons(P person, @SuppressWarnings("unchecked") P... persons); /** * Matches {@link Person}s from a single organizations - local matching. @@ -74,26 +30,5 @@ public Set<MatchedPerson> matchPersons(Person person, Person... persons) * @return matched persons, converted person from param {@code persons} if param {@code persons} has only one entry, * empty list if param {@code persons} has no entries */ - public Set<MatchedPerson> matchPersons(List<Person> persons) - { - Objects.requireNonNull(persons, "persons"); - - if (persons.isEmpty()) - return Collections.emptySet(); - else if (persons.size() == 1) - return Collections.singleton(persons.get(0).toMatchedPerson()); - else - { - Set<MatchedPerson> matchedPersons = new HashSet<>(); - matchedPersons.add(persons.get(0).toMatchedPerson()); - - persons.stream().skip(1).forEach(person -> - { - MatchedPerson matchedPerson = matchPerson(person, matchedPersons); - matchedPersons.add(matchedPerson); - }); - - return Collections.unmodifiableSet(matchedPersons); - } - } -} + Set<MatchedPerson<P>> matchPersons(List<P> persons); +} \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcherImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcherImpl.java new file mode 100644 index 000000000..a4fa183eb --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcherImpl.java @@ -0,0 +1,117 @@ +package org.highmed.pseudonymization.recordlinkage; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Single organization record linkage matcher implementation to match {@link Person}s from a single organization. + * + * @param <P> + * the type of the persons matched by this single organization matcher + */ +public class SingleOrganizationMatcherImpl<P extends Person> extends AbstractMatcher<P> + implements SingleOrganizationMatcher<P> +{ + /** + * See {@link AbstractMatcher#AbstractMatcher(MatchedPersonFactory)} + * + * @param matchedPersonFactory + * not <code>null</code> + */ + public SingleOrganizationMatcherImpl(MatchedPersonFactory<P> matchedPersonFactory) + { + super(matchedPersonFactory); + } + + /** + * See {@link AbstractMatcher#AbstractMatcher(MatchedPersonFactory, MatchCalculator)} + * + * @param matchedPersonFactory + * not <code>null</code> + * @param matchCalculator + * not <code>null</code> + */ + public SingleOrganizationMatcherImpl(MatchedPersonFactory<P> matchedPersonFactory, MatchCalculator matchCalculator) + { + super(matchedPersonFactory, matchCalculator); + } + + /** + * See {@link AbstractMatcher#AbstractMatcher(MatchedPersonFactory, MatchCalculator, double)} + * + * @param matchedPersonFactory + * not <code>null</code> + * @param matchCalculator + * not <code>null</code> + * @param positiveMatchThreshold + */ + public SingleOrganizationMatcherImpl(MatchedPersonFactory<P> matchedPersonFactory, MatchCalculator matchCalculator, + double positiveMatchThreshold) + { + super(matchedPersonFactory, matchCalculator, positiveMatchThreshold); + } + + /** + * Matches {@link Person}s from a single organizations - local matching. + * + * @param person + * not <code>null</code> + * @param persons + * not <code>null</code>, may be of length 0 + * @return matched persons, converted person from param {@code person} if param {@code persons} is empty + * @see #matchPersons(List) + */ + @Override + public Set<MatchedPerson<P>> matchPersons(P person, @SuppressWarnings("unchecked") P... persons) + { + Objects.requireNonNull(person, "person"); + Objects.requireNonNull(persons, "persons"); + + if (persons.length == 0) + return Collections.singleton(create(person)); + else + { + List<P> list = new ArrayList<>(1 + persons.length); + list.add(person); + list.addAll(Arrays.asList(persons)); + + return matchPersons(list); + } + } + + /** + * Matches {@link Person}s from a single organizations - local matching. + * + * @param persons + * @return matched persons, converted person from param {@code persons} if param {@code persons} has only one entry, + * empty list if param {@code persons} has no entries + */ + @Override + public Set<MatchedPerson<P>> matchPersons(List<P> persons) + { + Objects.requireNonNull(persons, "persons"); + + if (persons.isEmpty()) + return Collections.emptySet(); + else if (persons.size() == 1) + return Collections.singleton(create(persons.get(0))); + else + { + Set<MatchedPerson<P>> matchedPersons = new HashSet<>(); + matchedPersons.add(create(persons.get(0))); + + persons.stream().skip(1).forEach(person -> + { + MatchedPerson<P> matchedPerson = matchPerson(person, matchedPersons); + matchedPersons.add(matchedPerson); + }); + + return Collections.unmodifiableSet(matchedPersons); + } + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedic.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedic.java new file mode 100644 index 000000000..9e6e20ebb --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedic.java @@ -0,0 +1,11 @@ +package org.highmed.pseudonymization.translation; + +import java.util.List; + +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.pseudonymization.domain.PersonWithMdat; + +public interface ResultSetTranslatorFromMedic +{ + List<PersonWithMdat> translate(String organization, ResultSet resultSet); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedicImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedicImpl.java new file mode 100644 index 000000000..7f530b36f --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedicImpl.java @@ -0,0 +1,108 @@ +package org.highmed.pseudonymization.translation; + +import java.util.ArrayList; +import java.util.Base64; +import java.util.BitSet; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.domain.PersonWithMdat; +import org.highmed.pseudonymization.domain.impl.MedicIdImpl; +import org.highmed.pseudonymization.domain.impl.OpenEhrMdatContainer; +import org.highmed.pseudonymization.domain.impl.PersonImpl; +import org.highmed.pseudonymization.openehr.Constants; +import org.highmed.pseudonymization.recordlinkage.MedicId; + +public class ResultSetTranslatorFromMedicImpl implements ResultSetTranslatorFromMedic +{ + @Override + public List<PersonWithMdat> translate(String organization, ResultSet resultSet) + { + int medicIdColumnIndex = getMedicIdColumnIndex(resultSet.getColumns()); + int rbfColumnIndex = getRbfColumnIndex(resultSet.getColumns()); + + if (medicIdColumnIndex < 0) + throw new IllegalArgumentException("Missing MeDIC id column with name '" + Constants.MEDICID_COLUMN_NAME + + "' and path '" + Constants.MEDICID_COLUMN_PATH + "'"); + if (rbfColumnIndex < 0) + throw new IllegalArgumentException("Missing RBF column with name '" + Constants.RBF_COLUMN_NAME + + "' and path '" + Constants.RBF_COLUMN_PATH + "'"); + + return resultSet.getRows().parallelStream() + .map(toPersonWithMdat(organization, medicIdColumnIndex, rbfColumnIndex)).collect(Collectors.toList()); + } + + private Function<List<RowElement>, PersonWithMdat> toPersonWithMdat(String organization, int medicIdColumnIndex, + int rbfColumnIndex) + { + return rowElements -> + { + MedicId medicId = getMedicId(organization, rowElements.get(medicIdColumnIndex)); + BitSet recordBloomFilter = getRecordBloomFilter(rowElements.get(rbfColumnIndex)); + List<RowElement> elements = new ArrayList<>(); + for (int i = 0; i < rowElements.size(); i++) + if (i != medicIdColumnIndex && i != rbfColumnIndex) + elements.add(rowElements.get(i)); + + return new PersonImpl(medicId, recordBloomFilter, new OpenEhrMdatContainer(elements)); + }; + } + + private MedicId getMedicId(String organization, RowElement rowElement) + { + if (rowElement instanceof StringRowElement) + return new MedicIdImpl(organization, ((StringRowElement) rowElement).getValue()); + else + throw new IllegalArgumentException("RowElement of type " + StringRowElement.class.getName() + + " expected but got " + rowElement.getClass().getName()); + } + + private BitSet getRecordBloomFilter(RowElement rowElement) + { + if (rowElement instanceof StringRowElement) + { + String rbfString = ((StringRowElement) rowElement).getValue(); + byte[] rbfBytes = Base64.getDecoder().decode(rbfString); + return BitSet.valueOf(rbfBytes); + } + else + throw new IllegalArgumentException("RowElement of type " + StringRowElement.class.getName() + + " expected, but got " + rowElement.getClass().getName()); + } + + private int getMedicIdColumnIndex(List<Column> columns) + { + for (int i = 0; i < columns.size(); i++) + if (isMedicIdColumn().test(columns.get(i))) + return i; + + return -1; + } + + private Predicate<? super Column> isMedicIdColumn() + { + return column -> Constants.MEDICID_COLUMN_NAME.equals(column.getName()) + && Constants.MEDICID_COLUMN_PATH.equals(column.getPath()); + } + + private int getRbfColumnIndex(List<Column> columns) + { + for (int i = 0; i < columns.size(); i++) + if (isRbfColumn().test(columns.get(i))) + return i; + + return -1; + } + + private Predicate<? super Column> isRbfColumn() + { + return column -> Constants.RBF_COLUMN_NAME.equals(column.getName()) + && Constants.RBF_COLUMN_PATH.equals(column.getPath()); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedicRbfOnly.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedicRbfOnly.java new file mode 100644 index 000000000..04afb14e9 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedicRbfOnly.java @@ -0,0 +1,11 @@ +package org.highmed.pseudonymization.translation; + +import java.util.List; + +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.pseudonymization.domain.PersonWithMdat; + +public interface ResultSetTranslatorFromMedicRbfOnly +{ + List<PersonWithMdat> translate(String organization, ResultSet resultSet); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedicRbfOnlyImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedicRbfOnlyImpl.java new file mode 100644 index 000000000..ab2434cc3 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorFromMedicRbfOnlyImpl.java @@ -0,0 +1,75 @@ +package org.highmed.pseudonymization.translation; + +import java.util.Base64; +import java.util.BitSet; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.domain.PersonWithMdat; +import org.highmed.pseudonymization.domain.impl.MedicIdImpl; +import org.highmed.pseudonymization.domain.impl.OpenEhrMdatContainer; +import org.highmed.pseudonymization.domain.impl.PersonImpl; +import org.highmed.pseudonymization.openehr.Constants; +import org.highmed.pseudonymization.recordlinkage.MedicId; + +public class ResultSetTranslatorFromMedicRbfOnlyImpl implements ResultSetTranslatorFromMedicRbfOnly +{ + @Override + public List<PersonWithMdat> translate(String organization, ResultSet resultSet) + { + int rbfColumnIndex = getRbfColumnIndex(resultSet.getColumns()); + + if (rbfColumnIndex < 0) + throw new IllegalArgumentException("Missing RBF column with name '" + Constants.RBF_COLUMN_NAME + + "' and path '" + Constants.RBF_COLUMN_PATH + "'"); + + return resultSet.getRows().parallelStream() + .map(toPersonWithMdat(organization, rbfColumnIndex)).collect(Collectors.toList()); + } + + private Function<List<RowElement>, PersonWithMdat> toPersonWithMdat(String organization, + int rbfColumnIndex) + { + return rowElements -> + { + MedicId medicId = new MedicIdImpl(organization, null); + BitSet recordBloomFilter = getRecordBloomFilter(rowElements.get(rbfColumnIndex)); + + return new PersonImpl(medicId, recordBloomFilter, new OpenEhrMdatContainer(null)); + }; + } + + private BitSet getRecordBloomFilter(RowElement rowElement) + { + if (rowElement instanceof StringRowElement) + { + String rbfString = ((StringRowElement) rowElement).getValue(); + byte[] rbfBytes = Base64.getDecoder().decode(rbfString); + return BitSet.valueOf(rbfBytes); + } + else + throw new IllegalArgumentException("RowElement of type " + StringRowElement.class.getName() + + " expected, but got " + rowElement.getClass().getName()); + } + + private int getRbfColumnIndex(List<Column> columns) + { + for (int i = 0; i < columns.size(); i++) + if (isRbfColumn().test(columns.get(i))) + return i; + + return -1; + } + + private Predicate<? super Column> isRbfColumn() + { + return column -> Constants.RBF_COLUMN_NAME.equals(column.getName()) + && Constants.RBF_COLUMN_PATH.equals(column.getPath()); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromMedic.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromMedic.java new file mode 100644 index 000000000..394eaf41f --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromMedic.java @@ -0,0 +1,11 @@ +package org.highmed.pseudonymization.translation; + +import java.util.List; + +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.pseudonymization.domain.PseudonymizedPersonWithMdat; + +public interface ResultSetTranslatorResearchResultFromMedic +{ + List<PseudonymizedPersonWithMdat> translate(ResultSet resultSet); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromMedicImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromMedicImpl.java new file mode 100644 index 000000000..771c3af05 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultFromMedicImpl.java @@ -0,0 +1,72 @@ +package org.highmed.pseudonymization.translation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.domain.PseudonymizedPersonWithMdat; +import org.highmed.pseudonymization.domain.impl.OpenEhrMdatContainer; +import org.highmed.pseudonymization.domain.impl.PseudonymizedPersonImpl; +import org.highmed.pseudonymization.openehr.Constants; + +public class ResultSetTranslatorResearchResultFromMedicImpl implements ResultSetTranslatorResearchResultFromMedic +{ + @Override + public List<PseudonymizedPersonWithMdat> translate(ResultSet resultSet) + { + int psnColumnIndex = getPsnColumnIndex(resultSet.getColumns()); + + if (psnColumnIndex < 0) + throw new IllegalArgumentException("Missing PSN column with name '" + Constants.PSN_COLUMN_NAME + + "' and path '" + Constants.PSN_COLUMN_PATH + "'"); + + return resultSet.getRows().stream().map(toPseudonymizedPersonWithMdat(psnColumnIndex)) + .collect(Collectors.toList()); + } + + private int getPsnColumnIndex(List<Column> columns) + { + for (int i = 0; i < columns.size(); i++) + if (isPsnColumn().test(columns.get(i))) + return i; + + return -1; + } + + private Predicate<? super Column> isPsnColumn() + { + return column -> Constants.PSN_COLUMN_NAME.equals(column.getName()) + && Constants.PSN_COLUMN_PATH.equals(column.getPath()); + } + + private Function<List<RowElement>, PseudonymizedPersonWithMdat> toPseudonymizedPersonWithMdat(int psnColumnIndex) + { + return rowElements -> + { + String pseudonym = getPseudonym(rowElements.get(psnColumnIndex)); + List<RowElement> newRowElements = new ArrayList<>(); + for (int i = 0; i < rowElements.size(); i++) + if (i != psnColumnIndex) + newRowElements.add(rowElements.get(i)); + + return new PseudonymizedPersonImpl(pseudonym, + Collections.singleton(new OpenEhrMdatContainer(newRowElements))); + }; + } + + private String getPseudonym(RowElement rowElement) + { + if (rowElement instanceof StringRowElement) + return rowElement.getValueAsString(); + else + throw new IllegalArgumentException("RowElement of type " + StringRowElement.class.getName() + + " expected, but got " + rowElement.getClass().getName()); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToMedic.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToMedic.java new file mode 100644 index 000000000..c9450d67f --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToMedic.java @@ -0,0 +1,12 @@ +package org.highmed.pseudonymization.translation; + +import java.util.List; + +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.pseudonymization.domain.PersonWithMdat; + +public interface ResultSetTranslatorResearchResultToMedic +{ + ResultSet translate(List<Column> columns, List<PersonWithMdat> personsWithMdat); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToMedicImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToMedicImpl.java new file mode 100644 index 000000000..bdfbd4c91 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorResearchResultToMedicImpl.java @@ -0,0 +1,65 @@ +package org.highmed.pseudonymization.translation; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.Meta; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.domain.MdatContainer; +import org.highmed.pseudonymization.domain.PersonWithMdat; +import org.highmed.pseudonymization.domain.impl.OpenEhrMdatContainer; +import org.highmed.pseudonymization.openehr.Constants; + +public class ResultSetTranslatorResearchResultToMedicImpl implements ResultSetTranslatorResearchResultToMedic +{ + @Override + public ResultSet translate(List<Column> columns, List<PersonWithMdat> personsWithMdat) + { + Meta newMeta = createMeta(); + List<Column> newColumns = createColumns(columns); + return new ResultSet(newMeta, "", "", newColumns, + personsWithMdat.parallelStream().map(toRows()).collect(Collectors.toList())); + } + + private Meta createMeta() + { + return new Meta("", "", "", LocalDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME), "", ""); + } + + private List<Column> createColumns(List<Column> columns) + { + return Stream + .concat(columns.stream().map(toNewColumn()), + Stream.of(new Column(Constants.MEDICID_COLUMN_NAME, Constants.MEDICID_COLUMN_PATH))) + .collect(Collectors.toList()); + } + + private Function<Column, Column> toNewColumn() + { + return c -> new Column(c.getName(), c.getPath()); + } + + private Function<PersonWithMdat, List<RowElement>> toRows() + { + return person -> + { + MdatContainer mdatContainer = person.getMdatContainer(); + if (mdatContainer instanceof OpenEhrMdatContainer) + { + String medicId = person.getMedicId().getValue(); + return Stream.concat(((OpenEhrMdatContainer) mdatContainer).getElements().stream(), + Stream.of(new StringRowElement(medicId))).collect(Collectors.toList()); + } + else + throw new IllegalArgumentException("MdatContainer of type " + OpenEhrMdatContainer.class.getName() + + " expected, but got " + mdatContainer.getClass().getName()); + }; + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToMedic.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToMedic.java new file mode 100644 index 000000000..287f33163 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToMedic.java @@ -0,0 +1,13 @@ +package org.highmed.pseudonymization.translation; + +import java.util.List; + +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.Meta; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.pseudonymization.domain.PseudonymizedPersonWithMdat; + +public interface ResultSetTranslatorToMedic +{ + ResultSet translate(Meta meta, List<Column> columns, List<PseudonymizedPersonWithMdat> pseudonymsWithMdat); +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToMedicImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToMedicImpl.java new file mode 100644 index 000000000..0d499d503 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/translation/ResultSetTranslatorToMedicImpl.java @@ -0,0 +1,79 @@ +package org.highmed.pseudonymization.translation; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.structure.Column; +import org.highmed.openehr.model.structure.Meta; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.openehr.model.structure.RowElement; +import org.highmed.pseudonymization.domain.MdatContainer; +import org.highmed.pseudonymization.domain.PseudonymizedPersonWithMdat; +import org.highmed.pseudonymization.domain.impl.OpenEhrMdatContainer; +import org.highmed.pseudonymization.openehr.Constants; + +public class ResultSetTranslatorToMedicImpl implements ResultSetTranslatorToMedic +{ + @Override + public ResultSet translate(Meta meta, List<Column> columns, List<PseudonymizedPersonWithMdat> pseudonymsWithMdat) + { + Meta newMeta = createMeta(meta); + List<Column> newColumns = createColumns(columns); + return new ResultSet(newMeta, "", "", newColumns, + pseudonymsWithMdat.parallelStream().flatMap(toRows()).collect(Collectors.toList())); + } + + private Meta createMeta(Meta meta) + { + return new Meta(meta.getHref(), meta.getType(), meta.getSchemaVersion(), + ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME), meta.getGenerator(), + meta.getExecutedAql()); + } + + private List<Column> createColumns(List<Column> columns) + { + return Stream + .concat(columns.stream().filter(isMedicIdOrRbfColumn().negate()).map(toNewColumn()), + Stream.of(new Column(Constants.PSN_COLUMN_NAME, Constants.PSN_COLUMN_PATH))) + .collect(Collectors.toList()); + } + + private Predicate<? super Column> isMedicIdOrRbfColumn() + { + return column -> (Constants.MEDICID_COLUMN_NAME.equals(column.getName()) + && Constants.MEDICID_COLUMN_PATH.equals(column.getPath())) + || (Constants.RBF_COLUMN_NAME.equals(column.getName()) + && Constants.RBF_COLUMN_PATH.equals(column.getPath())); + } + + private Function<Column, Column> toNewColumn() + { + return c -> new Column(c.getName(), c.getPath()); + } + + private Function<PseudonymizedPersonWithMdat, Stream<List<RowElement>>> toRows() + { + return person -> person.getMdatContainers().stream().map(toRows(person.getPseudonym())); + } + + private Function<MdatContainer, List<RowElement>> toRows(String pseudonym) + { + return mdatContainer -> + { + if (mdatContainer instanceof OpenEhrMdatContainer) + { + return Stream.concat(((OpenEhrMdatContainer) mdatContainer).getElements().stream(), + Stream.of(new StringRowElement(pseudonym))).collect(Collectors.toList()); + } + else + throw new IllegalArgumentException("MdatContainer of type " + OpenEhrMdatContainer.class.getName() + + " expected, but got " + mdatContainer.getClass().getName()); + }; + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/IdatImpl.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/IdatImpl.java new file mode 100644 index 000000000..8fa162ca7 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/IdatImpl.java @@ -0,0 +1,92 @@ +package org.highmed.pseudonymization.domain; + +import org.highmed.mpi.client.Idat; + +public class IdatImpl implements Idat +{ + final String medicId; + final String firstName; + final String lastName; + final String birthday; + final String sex; + final String street; + final String zipCode; + final String city; + final String country; + final String insuranceNumber; + + public IdatImpl(String medicId, String firstName, String lastName, String birthday, String sex, String street, + String zipCode, String city, String country, String insuranceNumber) + { + this.medicId = medicId; + this.firstName = firstName; + this.lastName = lastName; + this.birthday = birthday; + this.sex = sex; + this.street = street; + this.zipCode = zipCode; + this.city = city; + this.country = country; + this.insuranceNumber = insuranceNumber; + } + + @Override + public String getMedicId() + { + return medicId; + } + + @Override + public String getFirstName() + { + return firstName; + } + + @Override + public String getLastName() + { + return lastName; + } + + @Override + public String getBirthday() + { + return birthday; + } + + @Override + public String getSex() + { + return sex; + } + + @Override + public String getStreet() + { + return street; + } + + @Override + public String getZipCode() + { + return zipCode; + } + + @Override + public String getCity() + { + return city; + } + + @Override + public String getCountry() + { + return country; + } + + @Override + public String getInsuranceNumber() + { + return insuranceNumber; + } +} \ No newline at end of file diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/MatchedPersonImplJsonTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/MatchedPersonImplJsonTest.java new file mode 100644 index 000000000..e80daf2e5 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/MatchedPersonImplJsonTest.java @@ -0,0 +1,86 @@ +package org.highmed.pseudonymization.domain; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.BitSet; + +import org.highmed.openehr.model.datatypes.DoubleRowElement; +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.datatypes.ZonedDateTimeRowElement; +import org.highmed.pseudonymization.domain.impl.FhirMdatContainer; +import org.highmed.pseudonymization.domain.impl.MatchedPersonImpl; +import org.highmed.pseudonymization.domain.impl.MedicIdImpl; +import org.highmed.pseudonymization.domain.impl.OpenEhrMdatContainer; +import org.highmed.pseudonymization.domain.impl.PersonImpl; +import org.highmed.pseudonymization.domain.json.TtpObjectMapperFactory; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.recordlinkage.MedicId; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleType; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import ca.uhn.fhir.context.FhirContext; + +public class MatchedPersonImplJsonTest +{ + private static final Logger logger = LoggerFactory.getLogger(MatchedPersonImplJsonTest.class); + + private ObjectMapper objectMapper = TtpObjectMapperFactory.createObjectMapper(FhirContext.forR4()); + + @Test + public void testWriteReadOpenEhr() throws Exception + { + MedicId medicId = new MedicIdImpl("org", "value"); + BitSet recordBloomFilter = new BitSet(5000); + recordBloomFilter.set(200); + recordBloomFilter.set(4850); + OpenEhrMdatContainer mdatContainer = new OpenEhrMdatContainer(Arrays.asList(new StringRowElement("string"), + new DoubleRowElement(0.1), new ZonedDateTimeRowElement(ZonedDateTime.now()))); + + PersonWithMdat person = new PersonImpl(medicId, recordBloomFilter, mdatContainer); + MatchedPerson<PersonWithMdat> matchedPerson = new MatchedPersonImpl(person); + + String value = objectMapper.writeValueAsString(matchedPerson); + assertNotNull(value); + + logger.debug("matchedPerson: {}", value); + + MatchedPerson<PersonWithMdat> readPerson = objectMapper.readValue(value, MatchedPersonImpl.class); + assertNotNull(readPerson); + assertNotNull(readPerson.getMatches()); + assertEquals(matchedPerson.getMatches().size(), readPerson.getMatches().size()); + assertNotNull(readPerson.getMatches().get(0)); + } + + @Test + public void testWriteReadFhir() throws Exception + { + MedicId medicId = new MedicIdImpl("org", "value"); + BitSet recordBloomFilter = new BitSet(5000); + recordBloomFilter.set(200); + recordBloomFilter.set(4850); + FhirMdatContainer mdatContainer = new FhirMdatContainer( + Arrays.asList(new Bundle().setType(BundleType.SEARCHSET), new Bundle().setType(BundleType.SEARCHSET))); + + PersonWithMdat person = new PersonImpl(medicId, recordBloomFilter, mdatContainer); + MatchedPerson<PersonWithMdat> matchedPerson = new MatchedPersonImpl(person); + + String value = objectMapper.writeValueAsString(matchedPerson); + assertNotNull(value); + + logger.debug("matchedPerson: {}", value); + + MatchedPerson<PersonWithMdat> readPerson = objectMapper.readValue(value, MatchedPersonImpl.class); + assertNotNull(readPerson); + assertNotNull(readPerson.getMatches()); + assertEquals(matchedPerson.getMatches().size(), readPerson.getMatches().size()); + assertNotNull(readPerson.getMatches().get(0)); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/PersonImplJsonTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/PersonImplJsonTest.java new file mode 100644 index 000000000..1115413f1 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/PersonImplJsonTest.java @@ -0,0 +1,110 @@ +package org.highmed.pseudonymization.domain; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.BitSet; + +import org.highmed.openehr.model.datatypes.DoubleRowElement; +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.datatypes.ZonedDateTimeRowElement; +import org.highmed.pseudonymization.domain.impl.FhirMdatContainer; +import org.highmed.pseudonymization.domain.impl.MedicIdImpl; +import org.highmed.pseudonymization.domain.impl.OpenEhrMdatContainer; +import org.highmed.pseudonymization.domain.impl.PersonImpl; +import org.highmed.pseudonymization.domain.json.TtpObjectMapperFactory; +import org.highmed.pseudonymization.recordlinkage.MedicId; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleType; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import ca.uhn.fhir.context.FhirContext; + +public class PersonImplJsonTest +{ + private static final Logger logger = LoggerFactory.getLogger(PersonImplJsonTest.class); + + private ObjectMapper objectMapper = TtpObjectMapperFactory.createObjectMapper(FhirContext.forR4()); + + @Test + public void testWriteReadOpenEhr() throws Exception + { + MedicId medicId = new MedicIdImpl("org", "value"); + BitSet recordBloomFilter = new BitSet(5000); + recordBloomFilter.set(200); + recordBloomFilter.set(4850); + OpenEhrMdatContainer mdatContainer = new OpenEhrMdatContainer(Arrays.asList(new StringRowElement("string"), + new DoubleRowElement(0.1), new ZonedDateTimeRowElement(ZonedDateTime.now()))); + + PersonWithMdat person = new PersonImpl(medicId, recordBloomFilter, mdatContainer); + + String value = objectMapper.writeValueAsString(person); + assertNotNull(value); + + logger.debug("person: {}", value); + + PersonWithMdat readPerson = objectMapper.readValue(value, PersonImpl.class); + assertNotNull(readPerson); + + assertNotNull(readPerson.getMedicId()); + assertEquals(person.getMedicId().getOrganization(), readPerson.getMedicId().getOrganization()); + assertEquals(person.getMedicId().getValue(), readPerson.getMedicId().getValue()); + assertNotNull(readPerson.getRecordBloomFilter()); + assertEquals(person.getRecordBloomFilter(), readPerson.getRecordBloomFilter()); + assertNotNull(readPerson.getMdatContainer()); + assertEquals(person.getMdatContainer().getClass(), readPerson.getMdatContainer().getClass()); + OpenEhrMdatContainer readMdatContainer = (OpenEhrMdatContainer) readPerson.getMdatContainer(); + assertNotNull(readMdatContainer.getElements()); + assertEquals(mdatContainer.getElements().size(), readMdatContainer.getElements().size()); + for (int i = 0; i < mdatContainer.getElements().size(); i++) + { + assertNotNull(readMdatContainer.getElements().get(0)); + assertEquals(mdatContainer.getElements().get(i).getClass(), + readMdatContainer.getElements().get(i).getClass()); + } + } + + @Test + public void testWriteReadFhir() throws Exception + { + MedicId medicId = new MedicIdImpl("org", "value"); + BitSet recordBloomFilter = new BitSet(5000); + recordBloomFilter.set(200); + recordBloomFilter.set(4850); + FhirMdatContainer mdatContainer = new FhirMdatContainer( + Arrays.asList(new Bundle().setType(BundleType.SEARCHSET), new Bundle().setType(BundleType.SEARCHSET))); + + PersonWithMdat person = new PersonImpl(medicId, recordBloomFilter, mdatContainer); + + String value = objectMapper.writeValueAsString(person); + assertNotNull(value); + + logger.debug("person: {}", value); + + PersonWithMdat readPerson = objectMapper.readValue(value, PersonImpl.class); + assertNotNull(readPerson); + + assertNotNull(readPerson.getMedicId()); + assertEquals(person.getMedicId().getOrganization(), readPerson.getMedicId().getOrganization()); + assertEquals(person.getMedicId().getValue(), readPerson.getMedicId().getValue()); + assertNotNull(readPerson.getRecordBloomFilter()); + assertEquals(person.getRecordBloomFilter(), readPerson.getRecordBloomFilter()); + assertNotNull(readPerson.getMdatContainer()); + assertEquals(person.getMdatContainer().getClass(), readPerson.getMdatContainer().getClass()); + FhirMdatContainer readMdatContainer = (FhirMdatContainer) readPerson.getMdatContainer(); + assertNotNull(readMdatContainer.getElements()); + assertEquals(mdatContainer.getElements().size(), readMdatContainer.getElements().size()); + for (int i = 0; i < mdatContainer.getElements().size(); i++) + { + assertNotNull(readMdatContainer.getElements().get(0)); + assertEquals(mdatContainer.getElements().get(i).getClass(), + readMdatContainer.getElements().get(i).getClass()); + } + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/PseudonymizedPersonImplJsonTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/PseudonymizedPersonImplJsonTest.java new file mode 100644 index 000000000..0d711afa4 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/domain/PseudonymizedPersonImplJsonTest.java @@ -0,0 +1,87 @@ +package org.highmed.pseudonymization.domain; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.BitSet; + +import org.highmed.openehr.model.datatypes.DoubleRowElement; +import org.highmed.openehr.model.datatypes.StringRowElement; +import org.highmed.openehr.model.datatypes.ZonedDateTimeRowElement; +import org.highmed.pseudonymization.domain.impl.FhirMdatContainer; +import org.highmed.pseudonymization.domain.impl.MatchedPersonImpl; +import org.highmed.pseudonymization.domain.impl.MedicIdImpl; +import org.highmed.pseudonymization.domain.impl.OpenEhrMdatContainer; +import org.highmed.pseudonymization.domain.impl.PersonImpl; +import org.highmed.pseudonymization.domain.impl.PseudonymizedPersonImpl; +import org.highmed.pseudonymization.domain.json.TtpObjectMapperFactory; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.recordlinkage.MedicId; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleType; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import ca.uhn.fhir.context.FhirContext; + +public class PseudonymizedPersonImplJsonTest +{ + private static final Logger logger = LoggerFactory.getLogger(PseudonymizedPersonImplJsonTest.class); + + private ObjectMapper objectMapper = TtpObjectMapperFactory.createObjectMapper(FhirContext.forR4()); + + @Test + public void testWriteReadOpenEhr() throws Exception + { + MedicId medicId = new MedicIdImpl("org", "value"); + BitSet recordBloomFilter = new BitSet(5000); + recordBloomFilter.set(200); + recordBloomFilter.set(4850); + OpenEhrMdatContainer mdatContainer = new OpenEhrMdatContainer(Arrays.asList(new StringRowElement("string"), + new DoubleRowElement(0.1), new ZonedDateTimeRowElement(ZonedDateTime.now()))); + + PersonWithMdat person = new PersonImpl(medicId, recordBloomFilter, mdatContainer); + MatchedPerson<PersonWithMdat> matchedPerson = new MatchedPersonImpl(person); + PseudonymizedPersonWithMdat pseudonymizedPerson = new PseudonymizedPersonImpl(matchedPerson, "pseudonym"); + + String value = objectMapper.writeValueAsString(pseudonymizedPerson); + assertNotNull(value); + + logger.debug("matchedPerson: {}", value); + + PseudonymizedPersonWithMdat readPerson = objectMapper.readValue(value, PseudonymizedPersonImpl.class); + assertNotNull(readPerson); + assertNotNull(readPerson.getMdatContainers()); + assertEquals(1, readPerson.getMdatContainers().size()); + } + + @Test + public void testWriteReadFhir() throws Exception + { + MedicId medicId = new MedicIdImpl("org", "value"); + BitSet recordBloomFilter = new BitSet(5000); + recordBloomFilter.set(200); + recordBloomFilter.set(4850); + FhirMdatContainer mdatContainer = new FhirMdatContainer( + Arrays.asList(new Bundle().setType(BundleType.SEARCHSET), new Bundle().setType(BundleType.SEARCHSET))); + + PersonWithMdat person = new PersonImpl(medicId, recordBloomFilter, mdatContainer); + MatchedPerson<PersonWithMdat> matchedPerson = new MatchedPersonImpl(person); + PseudonymizedPersonWithMdat pseudonymizedPerson = new PseudonymizedPersonImpl(matchedPerson, "pseudonym"); + + String value = objectMapper.writeValueAsString(pseudonymizedPerson); + assertNotNull(value); + + logger.debug("matchedPerson: {}", value); + + PseudonymizedPersonWithMdat readPerson = objectMapper.readValue(value, PseudonymizedPersonImpl.class); + assertNotNull(readPerson); + assertNotNull(readPerson.getMdatContainers()); + assertEquals(1, readPerson.getMdatContainers().size()); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/psn/PseudonyWithPaddingJsonTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/psn/PseudonyWithPaddingJsonTest.java new file mode 100644 index 000000000..d411a6c0f --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/psn/PseudonyWithPaddingJsonTest.java @@ -0,0 +1,32 @@ +package org.highmed.pseudonymization.psn; + +import static org.junit.Assert.*; + +import java.util.Arrays; + +import org.highmed.pseudonymization.recordlinkage.MedicId; +import org.highmed.pseudonymization.recordlinkage.TestMedicId; +import org.junit.Test; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.NamedType; + +public class PseudonyWithPaddingJsonTest +{ + @Test + public void testWriteRead() throws Exception + { + MedicId medicId1 = new TestMedicId("org1", "value1"); + MedicId medicId2 = new TestMedicId("org2", "value2"); + PseudonymWithPadding p = new PseudonymWithPadding("", Arrays.asList(medicId1, medicId2)); + + ObjectMapper o = new ObjectMapper(); + o.registerSubtypes(new NamedType(TestMedicId.class, "TestMedicId")); + + String string = o.writeValueAsString(p); + System.out.println(string); + + PseudonymWithPadding read = o.readValue(string, PseudonymWithPadding.class); + assertNotNull(read); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/psn/PseudonymEncoderImplTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/psn/PseudonymEncoderImplTest.java deleted file mode 100644 index 87adc7b0f..000000000 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/psn/PseudonymEncoderImplTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.highmed.pseudonymization.psn; - -import static org.junit.Assert.*; - -import java.util.Arrays; -import java.util.List; - -import org.highmed.pseudonymization.crypto.AesGcmUtil; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - -public class PseudonymEncoderImplTest -{ - private static final Logger logger = LoggerFactory.getLogger(PseudonymEncoderImplTest.class); - - @Test - public void testEncodeDecode() throws Exception - { - PseudonymEncoder encoder = new PseudonymEncoderImpl("researchStudyIdentifier", AesGcmUtil.generateAES256Key(), - new ObjectMapper()); - - List<Pseudonym> pseudonyms = Arrays.asList( - new Pseudonym(Arrays.asList(new MedicId("org1", "value11"), new MedicId("org2", "value21"))), - new Pseudonym(Arrays.asList(new MedicId("org1", "value12")))); - List<String> encodedPseudonyms = encoder.encodePseudonyms(pseudonyms); - - encodedPseudonyms.forEach(s -> logger.debug("Encoded Pseudonym: {}", s)); - - List<Pseudonym> decodePseudonyms = encoder.decodePseudonyms(encodedPseudonyms); - assertNotNull(decodePseudonyms); - assertEquals(2, decodePseudonyms.size()); - - assertNotNull(decodePseudonyms.get(0)); - assertNotNull(decodePseudonyms.get(0).getMedicIds()); - assertEquals(pseudonyms.get(0).getMedicIds().size(), decodePseudonyms.get(0).getMedicIds().size()); - assertNotNull(decodePseudonyms.get(0).getMedicIds().get(0)); - assertEquals(pseudonyms.get(0).getMedicIds().get(0).getOrganization(), - decodePseudonyms.get(0).getMedicIds().get(0).getOrganization()); - assertEquals(pseudonyms.get(0).getMedicIds().get(0).getValue(), - decodePseudonyms.get(0).getMedicIds().get(0).getValue()); - assertNotNull(decodePseudonyms.get(0).getMedicIds().get(1)); - assertEquals(pseudonyms.get(0).getMedicIds().get(1).getOrganization(), - decodePseudonyms.get(0).getMedicIds().get(1).getOrganization()); - assertEquals(pseudonyms.get(0).getMedicIds().get(1).getValue(), - decodePseudonyms.get(0).getMedicIds().get(1).getValue()); - - assertNotNull(decodePseudonyms.get(1)); - assertNotNull(decodePseudonyms.get(1).getMedicIds()); - assertEquals(pseudonyms.get(1).getMedicIds().size(), decodePseudonyms.get(1).getMedicIds().size()); - assertNotNull(decodePseudonyms.get(1).getMedicIds().get(0)); - assertEquals(pseudonyms.get(1).getMedicIds().get(0).getOrganization(), - decodePseudonyms.get(1).getMedicIds().get(0).getOrganization()); - assertEquals(pseudonyms.get(1).getMedicIds().get(0).getValue(), - decodePseudonyms.get(1).getMedicIds().get(0).getValue()); - } -} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/psn/PseudonymGeneratorImplTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/psn/PseudonymGeneratorImplTest.java new file mode 100644 index 000000000..41f6f08a0 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/psn/PseudonymGeneratorImplTest.java @@ -0,0 +1,89 @@ +package org.highmed.pseudonymization.psn; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Arrays; +import java.util.List; + +import javax.crypto.SecretKey; + +import org.highmed.pseudonymization.crypto.AesGcmUtil; +import org.highmed.pseudonymization.domain.PseudonymizedPerson; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.recordlinkage.TestMatchedPerson; +import org.highmed.pseudonymization.recordlinkage.TestMedicId; +import org.highmed.pseudonymization.recordlinkage.TestPerson; +import org.highmed.pseudonymization.recordlinkage.TestPseudonymizedPerson; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.NamedType; + +public class PseudonymGeneratorImplTest +{ + private static final Logger logger = LoggerFactory.getLogger(PseudonymGeneratorImplTest.class); + + @Test + public void testEncodeDecode() throws Exception + { + String researchStudyIdentifier = "researchStudyIdentifier"; + SecretKey researchStudyTtpKey = AesGcmUtil.generateAES256Key(); + ObjectMapper psnObjectMapper = new ObjectMapper(); + psnObjectMapper.registerSubtypes(new NamedType(TestMedicId.class, "TestMedicId")); + + PseudonymGenerator<TestPerson, PseudonymizedPerson> generator = new PseudonymGeneratorImpl<>( + researchStudyIdentifier, researchStudyTtpKey, psnObjectMapper, + (person, pseudonym) -> new TestPseudonymizedPerson(pseudonym)); + + List<MatchedPerson<TestPerson>> ids = Arrays.asList( + new TestMatchedPerson(new TestPerson(new TestMedicId("org1", "value11"), null), + new TestPerson(new TestMedicId("org2", "value21"), null)), + new TestMatchedPerson(new TestPerson(new TestMedicId("org1", "value12"), null))); + + List<PseudonymizedPerson> encodedPseudonyms = generator.createPseudonymsAndShuffle(ids); + + encodedPseudonyms.forEach(s -> logger.debug("Encoded Pseudonym: {}", s)); + + PseudonymDecoder<TestPerson> decoder = new PseudonymDecoderImpl<TestPerson>(researchStudyIdentifier, + researchStudyTtpKey, psnObjectMapper, (person, medicIds) -> new TestMatchedPerson( + medicIds.stream().map(i -> new TestPerson(i, null)).toArray(TestPerson[]::new))); + + List<MatchedPerson<TestPerson>> pseudonyms = decoder.decodePseudonyms(encodedPseudonyms); + + assertNotNull(pseudonyms); + assertEquals(2, pseudonyms.size()); + + int doubleMatch = pseudonyms.get(0).getMatches().size() == 2 ? 0 : 1; + int singleMatch = pseudonyms.get(0).getMatches().size() == 2 ? 1 : 0; + + assertNotNull(pseudonyms.get(doubleMatch)); + assertNotNull(pseudonyms.get(doubleMatch).getMatches()); + assertEquals(ids.get(0).getMatches().size(), pseudonyms.get(doubleMatch).getMatches().size()); + assertNotNull(pseudonyms.get(doubleMatch).getMatches().get(0)); + assertNotNull(pseudonyms.get(doubleMatch).getMatches().get(0).getMedicId()); + assertEquals(ids.get(0).getMatches().get(0).getMedicId().getOrganization(), + pseudonyms.get(doubleMatch).getMatches().get(0).getMedicId().getOrganization()); + assertEquals(ids.get(0).getMatches().get(0).getMedicId().getValue(), + pseudonyms.get(doubleMatch).getMatches().get(0).getMedicId().getValue()); + + assertNotNull(pseudonyms.get(doubleMatch).getMatches().get(1)); + assertNotNull(pseudonyms.get(doubleMatch).getMatches().get(1).getMedicId()); + assertEquals(ids.get(0).getMatches().get(1).getMedicId().getOrganization(), + pseudonyms.get(doubleMatch).getMatches().get(1).getMedicId().getOrganization()); + assertEquals(ids.get(0).getMatches().get(1).getMedicId().getValue(), + pseudonyms.get(doubleMatch).getMatches().get(1).getMedicId().getValue()); + + assertNotNull(pseudonyms.get(singleMatch)); + assertNotNull(pseudonyms.get(singleMatch).getMatches()); + assertNotNull(pseudonyms.get(singleMatch).getMatches().get(0).getMedicId()); + assertEquals(ids.get(1).getMatches().size(), pseudonyms.get(singleMatch).getMatches().size()); + assertNotNull(pseudonyms.get(singleMatch).getMatches().get(0)); + assertEquals(ids.get(1).getMatches().get(0).getMedicId().getOrganization(), + pseudonyms.get(singleMatch).getMatches().get(0).getMedicId().getOrganization()); + assertEquals(ids.get(1).getMatches().get(0).getMedicId().getValue(), + pseudonyms.get(singleMatch).getMatches().get(0).getMedicId().getValue()); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcherTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcherTest.java index 220feb9ce..5e707b632 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcherTest.java +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/FederatedMatcherTest.java @@ -15,15 +15,15 @@ public class FederatedMatcherTest @Test public void testMatch() throws Exception { - FederatedMatcher m = new FederatedMatcher(); + FederatedMatcher<TestPerson> m = new FederatedMatcherImpl<TestPerson>(TestMatchedPerson::new); - List<List<Person>> personLists = Arrays.asList( - Arrays.asList( - new TestPerson("org1", "id1", createRecordBloomFilter(200, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9))), - Arrays.asList( - new TestPerson("org2", "id2", createRecordBloomFilter(200, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)))); + List<List<TestPerson>> personLists = Arrays.asList( + Arrays.asList(new TestPerson(new TestMedicId("org1", "id1"), + createRecordBloomFilter(200, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9))), + Arrays.asList(new TestPerson(new TestMedicId("org2", "id2"), + createRecordBloomFilter(200, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)))); - Set<MatchedPerson> matchedPersons = m.matchPersons(personLists); + Set<MatchedPerson<TestPerson>> matchedPersons = m.matchPersons(personLists); assertNotNull(matchedPersons); assertEquals(1, matchedPersons.size()); } diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/MatchingTimeTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/MatchingTimeTest.java new file mode 100644 index 000000000..bf0763f2c --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/MatchingTimeTest.java @@ -0,0 +1,372 @@ +package org.highmed.pseudonymization.recordlinkage; + +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVRecord; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.highmed.pseudonymization.bloomfilter.BloomFilterGenerator; +import org.highmed.pseudonymization.bloomfilter.FieldBloomFilter; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilter; +import org.highmed.pseudonymization.domain.IdatImpl; +import org.highmed.pseudonymization.domain.impl.MedicIdImpl; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MatchingTimeTest +{ + private static final Logger logger = LoggerFactory.getLogger(MatchingTimeTest.class); + + private static final int BIT_SET_LENGTH = 500; + private static final int BIT_SET_LENGTH_MEDIUM = 250; + private static final int BIT_SET_LENGTH_SHORT = 50; + + private static List<IdatImpl> org1, org2 = new ArrayList<>(); + private static List<Duration> rbftimes = new ArrayList<>(); + private static List<Duration> rltimes = new ArrayList<>(); + + @BeforeClass + public static void readFromTwoOrgs() + { + org1 = readWithTrueNeg(Paths.get("src/test/resources/df5k_org.csv")); + + org2 = read2(Paths.get("src/test/resources/df5k_dup.csv")); + } + + @Test + public void testTimeWithMd5Sha1() + { + BloomFilterGenerator generatorLong = BloomFilterGenerator.withMd5Sha1BiGramHasher(BIT_SET_LENGTH); + BloomFilterGenerator generatorMedium = BloomFilterGenerator.withMd5Sha1BiGramHasher(BIT_SET_LENGTH_MEDIUM); + BloomFilterGenerator generatorShort = BloomFilterGenerator.withMd5Sha1BiGramHasher(BIT_SET_LENGTH_SHORT); + + for (int i = 0; i < 70; i++) + { + testRuntime(generatorLong, generatorMedium, generatorShort); + } + logTimes("Md5", "SHA1"); + } + + @Test + public void testTimeWithMd5Sha1Hmac() + { + Random rand = new Random(42L); + byte[] key1 = new byte[32]; + byte[] key2 = new byte[32]; + rand.nextBytes(key1); + rand.nextBytes(key2); + + BloomFilterGenerator generatorLong = BloomFilterGenerator + .withHmacMd5HmacSha1BiGramHasher(BIT_SET_LENGTH, key1, key2); + BloomFilterGenerator generatorMedium = BloomFilterGenerator + .withHmacMd5HmacSha1BiGramHasher(BIT_SET_LENGTH_MEDIUM, key1, key2); + BloomFilterGenerator generatorShort = BloomFilterGenerator + .withHmacMd5HmacSha1BiGramHasher(BIT_SET_LENGTH_SHORT, key1, key2); + + for (int i = 0; i < 70; i++) + { + testRuntime(generatorLong, generatorMedium, generatorShort); + } + logTimes("Md5", "SHA1 HMAC"); + } + + @Test + public void testTimeWithSha1Sha2() + { + BloomFilterGenerator generatorLong = BloomFilterGenerator.withSha1Sha2BiGramHasher(BIT_SET_LENGTH); + BloomFilterGenerator generatorMedium = BloomFilterGenerator.withSha1Sha2BiGramHasher(BIT_SET_LENGTH_MEDIUM); + BloomFilterGenerator generatorShort = BloomFilterGenerator.withSha1Sha2BiGramHasher(BIT_SET_LENGTH_SHORT); + + for (int i = 0; i < 70; i++) + { + testRuntime(generatorLong, generatorMedium, generatorShort); + } + logTimes("SHA1", "SHA2"); + } + + @Test + public void testTimeWithSha1Sha2Hmac() + { + BouncyCastleProvider bcProvider = new BouncyCastleProvider(); + + Random rand = new Random(42L); + byte[] key1 = new byte[32]; + byte[] key2 = new byte[32]; + rand.nextBytes(key1); + rand.nextBytes(key2); + + BloomFilterGenerator generatorLong = BloomFilterGenerator + .withHmacSha1HmacSha2BiGramHasher(BIT_SET_LENGTH, key1, key2, bcProvider); + BloomFilterGenerator generatorMedium = BloomFilterGenerator + .withHmacSha1HmacSha2BiGramHasher(BIT_SET_LENGTH_MEDIUM, key1, key2, bcProvider); + BloomFilterGenerator generatorShort = BloomFilterGenerator + .withHmacSha1HmacSha2BiGramHasher(BIT_SET_LENGTH_SHORT, key1, key2, bcProvider); + + for (int i = 0; i < 70; i++) + { + testRuntime(generatorLong, generatorMedium, generatorShort); + } + logTimes("SHA1 HMAC", "SHA2 HMAC"); + } + + @Test + public void testTimeWithSha2Sha3() + { + BloomFilterGenerator generatorLong = BloomFilterGenerator.withSha2Sha3BiGramHasher(BIT_SET_LENGTH); + BloomFilterGenerator generatorMedium = BloomFilterGenerator.withSha2Sha3BiGramHasher(BIT_SET_LENGTH_MEDIUM); + BloomFilterGenerator generatorShort = BloomFilterGenerator.withSha2Sha3BiGramHasher(BIT_SET_LENGTH_SHORT); + + for (int i = 0; i < 70; i++) + { + testRuntime(generatorLong, generatorMedium, generatorShort); + } + logTimes("SHA2", "SHA3"); + } + + @Test + public void testTimeWithSha2Sha3Hmac() + { + BouncyCastleProvider bcProvider = new BouncyCastleProvider(); + + Random rand = new Random(42L); + byte[] key1 = new byte[32]; + byte[] key2 = new byte[32]; + rand.nextBytes(key1); + rand.nextBytes(key2); + + BloomFilterGenerator generatorLong = BloomFilterGenerator + .withHmacSha2HmacSha3BiGramHasher(BIT_SET_LENGTH, key1, key2, bcProvider); + BloomFilterGenerator generatorMedium = BloomFilterGenerator + .withHmacSha2HmacSha3BiGramHasher(BIT_SET_LENGTH_MEDIUM, key1, key2, bcProvider); + BloomFilterGenerator generatorShort = BloomFilterGenerator + .withHmacSha2HmacSha3BiGramHasher(BIT_SET_LENGTH_SHORT, key1, key2, bcProvider); + + for (int i = 0; i < 70; i++) + { + testRuntime(generatorLong, generatorMedium, generatorShort); + } + logTimes("SHA2 HMAC", "SHA3 HMAC"); + } + + private void testRuntime(BloomFilterGenerator generatorLong, BloomFilterGenerator generatorMedium, + BloomFilterGenerator generatorShort) + { + List<Double> weightList = Arrays + .asList(0.1, 0.1, 0.2, 0.1, 0.1, 0.05, 0.2, 0.1, 0.05); // Best weights for SHA23Hmac, MD5SHA1 + + List<List<TestPerson>> combinedPtRbfs = createPatientsFromRecord(org1, org2, weightList, + generatorLong, generatorMedium, generatorShort); + List<TestPerson> org1Pts = combinedPtRbfs.get(0); + List<TestPerson> org2Pts = combinedPtRbfs.get(1); + + FederatedMatcher<TestPerson> matcher = new FederatedMatcherImpl<>(TestMatchedPerson::new); + LocalDateTime rlStartTime = LocalDateTime.now(); + Set<MatchedPerson<TestPerson>> matchPatients = matcher.matchPersons(Arrays.asList(org1Pts, org2Pts)); + LocalDateTime rlEndTime = LocalDateTime.now(); + assertNotNull(matchPatients); + + Duration rlduration = Duration.between(rlStartTime, rlEndTime); + rltimes.add(rlduration); + + logger.debug("Single run Record Linkage Time: {}", rlduration); + org1Pts = null; + org2Pts = null; + matchPatients = null; + } + + private void logTimes(String hash1, String hash2) + { + logger.debug("Average Duration Bloom Filter Generation for combination {} + {}: {} ms. ", + hash1, hash2, calculateAvgDuration(rbftimes)); + logger.debug("Average Duration Record Linkage for combination {} + {}: {} ms.", + hash1, hash2, calculateAvgDuration(rltimes)); + } + + private List<FieldBloomFilter> createFbfList(IdatImpl r, List<Double> weightList, + BloomFilterGenerator generatorLong, BloomFilterGenerator generatorMedium, + BloomFilterGenerator generatorShort) + { + double firstname = weightList.get(0); + double lastname = weightList.get(1); + double sex = weightList.get(2); + double birthday = weightList.get(3); + double zipcode = weightList.get(4); + double city = weightList.get(5); + double country = weightList.get(6); + double insurancenr = weightList.get(7); + double street = weightList.get(8); + + String recId = r.getMedicId(); + FieldBloomFilter firstNameInput = toField(firstname, r.getFirstName(), generatorLong); + FieldBloomFilter lastNameInput = toField(lastname, r.getLastName(), generatorLong); + String ptSex = "f"; + String idNr = recId.substring(0, 8).replaceAll("\\D+", ""); + if (Integer.parseInt(idNr) % 2 == 0) + ptSex = "m"; + FieldBloomFilter sexInput = toField(sex, ptSex, generatorShort); + FieldBloomFilter birthdayInput = toField(birthday, r.getBirthday(), generatorMedium); + FieldBloomFilter zipCodeInput = toField(zipcode, r.getZipCode(), generatorMedium); + FieldBloomFilter cityInput = toField(city, r.getCity(), generatorLong); + FieldBloomFilter countryInput = toField(country, r.getCountry(), generatorLong); + FieldBloomFilter insuranceInput = toField(insurancenr, r.getInsuranceNumber(), generatorLong); + FieldBloomFilter streetInput = toField(street, r.getStreet(), generatorLong); + List<FieldBloomFilter> fbfList = Arrays + .asList(firstNameInput, lastNameInput, sexInput, birthdayInput, zipCodeInput, cityInput, countryInput, + insuranceInput, streetInput); + return fbfList; + } + + private List<List<TestPerson>> createPatientsFromRecord(List<IdatImpl> org1Idat, List<IdatImpl> org2Idat, List<Double> weightList, + BloomFilterGenerator generatorLong, BloomFilterGenerator generatorMedium, + BloomFilterGenerator generatorShort) + { + List<TestPerson> org1Pts = new ArrayList<>(); + List<TestPerson> org2Pts = new ArrayList<>(); + + List<IdatImpl> allPts = new ArrayList<>(); + allPts.addAll(org1Idat); + allPts.addAll(org2Idat); + + LocalDateTime rbfStartTime = LocalDateTime.now(); + + List<RecordBloomFilter> rbfList = allPts.parallelStream() + .map(r -> {return new RecordBloomFilter(3000, 42L, + createFbfList(r, weightList, generatorLong, generatorMedium, generatorShort));}) + .collect(Collectors.toList()); + + LocalDateTime rbfEndTime = LocalDateTime.now(); + Duration duration = Duration.between(rbfStartTime, rbfEndTime); + rbftimes.add(duration); + logger.debug("Single run Bloom Filter generation time: {}ms", duration); + + for (IdatImpl r : allPts) + { + int idx = allPts.indexOf(r); + if (r.getMedicId().contains("org")) // Org 1 IDAT have org (original) id, org 2 idat have dup + { + org1Pts.add(new TestPerson(new MedicIdImpl("org1", r.getMedicId()), rbfList.get(idx).getBitSet())); + } else + { + org2Pts.add(new TestPerson(new MedicIdImpl("org2", r.getMedicId()), rbfList.get(idx).getBitSet())); + } + } + + return Arrays.asList(org1Pts, org2Pts); + } + + public static long calculateAvgDuration(List<Duration> durations) + { + long sum; + if (durations.size() >= 70) + { + sum = durations.stream().mapToLong(Duration::toMillis).skip(20).sum(); + } else + { + logger.warn("Less than 70 test runs have been performed, thus the first 20 runs will not be discarded."); + sum = durations.stream().mapToLong(Duration::toMillis).sum(); + } + return sum / durations.size(); + } + + private static List<IdatImpl> read2(Path path) + { + try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) + { + Iterable<CSVRecord> records = CSVFormat.RFC4180 + .withHeader("rec_id", "given_name", "surname", "street_number", "address_1", "address_2", "suburb", + "postcode", "state", "date_of_birth", "soc_sec_id").withSkipHeaderRecord().parse(reader); + ArrayList<IdatImpl> idats = new ArrayList<>(); + for (CSVRecord r : records) + { + String ptSex = "f"; + String idNr = r.get("rec_id").substring(0, 8).replaceAll("\\D+", ""); + if (Integer.parseInt(idNr) % 2 == 0) + ptSex = "m"; + String bday; + if (r.get("date_of_birth").length() == 8) + { + String bdayYear = r.get("date_of_birth").substring(0, 4); + String bdayMonth = r.get("date_of_birth").substring(4, 6); + String bdayDay = r.get("date_of_birth").substring(6); + bday = bdayDay + "." + bdayMonth + "." + bdayYear; + } + else + { + bday = "NaN"; + } + idats.add(new IdatImpl(r.get("rec_id"), r.get("given_name"), r.get("surname"), ptSex, bday, + r.get("postcode"), r.get("address_2"), r.get("address_1"), r.get("state"), + r.get("soc_sec_id"))); + } + return idats; + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + private static List<IdatImpl> readWithTrueNeg(Path path) + { + try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) + { + Iterable<CSVRecord> records = CSVFormat.RFC4180 + .withHeader("rec_id", "given_name", "surname", "street_number", "address_1", "address_2", "suburb", + "postcode", "state", "date_of_birth", "soc_sec_id").withSkipHeaderRecord().parse(reader); + ArrayList<IdatImpl> idats = new ArrayList<>(); + for (CSVRecord r : records) + { + String ptSex = "f"; + String idNr = r.get("rec_id").substring(0, 8).replaceAll("\\D+", ""); + + if (Integer.parseInt(idNr) % 2 == 0) + ptSex = "m"; + String bday; + if (r.get("date_of_birth").length() == 8) + { + String bdayYear = r.get("date_of_birth").substring(0, 4); + String bdayMonth = r.get("date_of_birth").substring(4, 6); + String bdayDay = r.get("date_of_birth").substring(6); + bday = bdayDay + "." + bdayMonth + "." + bdayYear; + } + else + { + bday = "NaN"; + } + if (Integer.parseInt(idNr) < 4000) + { + idats.add(new IdatImpl(r.get("rec_id"), r.get("given_name"), r.get("surname"), ptSex, bday, + r.get("postcode"), r.get("address_2"), r.get("address_1"), r.get("state"), + r.get("soc_sec_id"))); + } + } + return idats; + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + private FieldBloomFilter toField(double weight, String input, BloomFilterGenerator generator) + { + return new FieldBloomFilter(generator.generateBitSet(input), weight); + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcherTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcherTest.java index 26e17f78a..13374319c 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcherTest.java +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/SingleOrganizationMatcherTest.java @@ -15,13 +15,15 @@ public class SingleOrganizationMatcherTest @Test public void testMatch() throws Exception { - SingleOrganizationMatcher m = new SingleOrganizationMatcher(); + SingleOrganizationMatcher<TestPerson> m = new SingleOrganizationMatcherImpl<TestPerson>(TestMatchedPerson::new); - List<Person> personLists = Arrays.asList( - new TestPerson("org1", "id1", createRecordBloomFilter(200, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)), - new TestPerson("org2", "id2", createRecordBloomFilter(200, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9))); + List<TestPerson> personLists = Arrays.asList( + new TestPerson(new TestMedicId("org1", "id1"), + createRecordBloomFilter(200, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)), + new TestPerson(new TestMedicId("org2", "id2"), + createRecordBloomFilter(200, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9))); - Set<MatchedPerson> matchedPersons = m.matchPersons(personLists); + Set<MatchedPerson<TestPerson>> matchedPersons = m.matchPersons(personLists); assertNotNull(matchedPersons); assertEquals(1, matchedPersons.size()); } diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestMatchedPerson.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestMatchedPerson.java index 3f7ad4a7a..f6026c5ec 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestMatchedPerson.java +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestMatchedPerson.java @@ -1,28 +1,34 @@ package org.highmed.pseudonymization.recordlinkage; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -public class TestMatchedPerson implements MatchedPerson +public class TestMatchedPerson implements MatchedPerson<TestPerson> { - private final List<Person> matches = new ArrayList<>(); + private final List<TestPerson> matches = new ArrayList<>(); - public TestMatchedPerson(Person person) + public TestMatchedPerson(TestPerson person) { if (person != null) addMatch(person); } + public TestMatchedPerson(TestPerson... persons) + { + matches.addAll(Arrays.asList(persons)); + } + @Override - public List<Person> getMatches() + public List<TestPerson> getMatches() { return Collections.unmodifiableList(matches); } @Override - public void addMatch(Person person) + public void addMatch(TestPerson person) { if (person != null) matches.add(person); @@ -31,6 +37,6 @@ public void addMatch(Person person) @Override public String toString() { - return matches.stream().map(Person::toString).collect(Collectors.joining(", ", "[", "]")); + return matches.stream().map(TestPerson::toString).collect(Collectors.joining(", ", "[", "]")); } } diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/MedicId.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestMedicId.java similarity index 61% rename from dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/MedicId.java rename to dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestMedicId.java index 1eed4e8b4..30e974146 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/main/java/org/highmed/pseudonymization/psn/MedicId.java +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestMedicId.java @@ -1,27 +1,29 @@ -package org.highmed.pseudonymization.psn; +package org.highmed.pseudonymization.recordlinkage; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -public class MedicId +public class TestMedicId implements MedicId { private final String organization; private final String value; @JsonCreator - public MedicId(@JsonProperty("organization") String organization, @JsonProperty("value") String value) + public TestMedicId(@JsonProperty("organization") String organization, @JsonProperty("value") String value) { this.organization = organization; this.value = value; } + @Override public String getOrganization() { return organization; } + @Override public String getValue() { return value; } -} \ No newline at end of file +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestPerson.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestPerson.java index ea85c1715..fd3238884 100644 --- a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestPerson.java +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestPerson.java @@ -4,27 +4,19 @@ public class TestPerson implements Person { - private final String organization; - private final String id; + private final MedicId medicId; private final BitSet recordBloomFilter; - public TestPerson(String organization, String id, BitSet recordBloomFilter) + public TestPerson(MedicId medicId, BitSet recordBloomFilter) { - this.organization = organization; - this.id = id; + this.medicId = medicId; this.recordBloomFilter = recordBloomFilter; } @Override - public String getOrganization() + public MedicId getMedicId() { - return organization; - } - - @Override - public String getId() - { - return id; + return medicId; } @Override @@ -33,15 +25,9 @@ public BitSet getRecordBloomFilter() return recordBloomFilter; } - @Override - public MatchedPerson toMatchedPerson() - { - return new TestMatchedPerson(this); - } - @Override public String toString() { - return "org: " + getOrganization() + ", id: " + getId(); + return "org: " + medicId.getOrganization() + ", id: " + medicId.getValue(); } } diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestPseudonymizedPerson.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestPseudonymizedPerson.java new file mode 100644 index 000000000..bfd471a2e --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/TestPseudonymizedPerson.java @@ -0,0 +1,25 @@ +package org.highmed.pseudonymization.recordlinkage; + +import org.highmed.pseudonymization.domain.PseudonymizedPerson; + +public class TestPseudonymizedPerson implements PseudonymizedPerson +{ + private final String pseudonym; + + public TestPseudonymizedPerson(String pseudonym) + { + this.pseudonym = pseudonym; + } + + @Override + public String getPseudonym() + { + return pseudonym; + } + + @Override + public String toString() + { + return "pseudonym: " + pseudonym; + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/WeightDistributionTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/WeightDistributionTest.java new file mode 100644 index 000000000..7e34cde53 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/recordlinkage/WeightDistributionTest.java @@ -0,0 +1,489 @@ +package org.highmed.pseudonymization.recordlinkage; + +import static org.junit.Assert.assertNotNull; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; +import org.apache.commons.csv.CSVRecord; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.highmed.pseudonymization.bloomfilter.BloomFilterGenerator; +import org.highmed.pseudonymization.bloomfilter.FieldBloomFilter; +import org.highmed.pseudonymization.bloomfilter.RecordBloomFilter; +import org.highmed.pseudonymization.domain.IdatImpl; +import org.highmed.pseudonymization.domain.impl.MedicIdImpl; +import org.junit.BeforeClass; +import org.junit.Test; + +public class WeightDistributionTest +{ + private static final int BIT_SET_LENGTH = 500; + private static final int BIT_SET_LENGTH_MEDIUM = 250; + private static final int BIT_SET_LENGTH_SHORT = 50; + + private static ConcurrentHashMap<List<Double>, List<Double>> results = new ConcurrentHashMap<>(); + + private static List<IdatImpl> org1, org2 = new ArrayList<>(); + + @BeforeClass + public static void readFromTwoOrgs() + { + org1 = readWithTrueNeg(Paths.get("src/test/resources/df5k_org.csv")); + + org2 = read2(Paths.get("src/test/resources/df5k_dup.csv")); + } + + @Test + public void testWeightsWithMd5Sha1() + { + BloomFilterGenerator generatorLong = BloomFilterGenerator.withMd5Sha1BiGramHasher(BIT_SET_LENGTH); + BloomFilterGenerator generatorMedium = BloomFilterGenerator.withMd5Sha1BiGramHasher(BIT_SET_LENGTH_MEDIUM); + BloomFilterGenerator generatorShort = BloomFilterGenerator.withMd5Sha1BiGramHasher(BIT_SET_LENGTH_SHORT); + + List<List<Double>> weightLists = getWeightLists(); + + // Todo: Run tests in parallel with different weightlists once ConcModException is fixed + testWeights(weightLists.get(0), generatorLong, generatorMedium, generatorShort); + + writeResultsAsCsv("Md5_SHA1.csv"); + } + + @Test + public void testWeightsWithMd5Sha1Hmac() + { + Random rand = new Random(42L); + byte[] key1 = new byte[32]; + byte[] key2 = new byte[32]; + rand.nextBytes(key1); + rand.nextBytes(key2); + + BloomFilterGenerator generatorLong = BloomFilterGenerator.withHmacMd5HmacSha1BiGramHasher(BIT_SET_LENGTH, key1, + key2); + BloomFilterGenerator generatorMedium = BloomFilterGenerator + .withHmacMd5HmacSha1BiGramHasher(BIT_SET_LENGTH_MEDIUM, key1, key2); + BloomFilterGenerator generatorShort = BloomFilterGenerator.withHmacMd5HmacSha1BiGramHasher(BIT_SET_LENGTH_SHORT, + key1, key2); + + List<List<Double>> weightLists = getWeightLists(); + + testWeights(weightLists.get(0), generatorLong, generatorMedium, generatorShort); + + writeResultsAsCsv("Md5_SHA1_HMAC.csv"); + } + + @Test + public void testWeightsWithSha1Sha2() + { + BloomFilterGenerator generatorLong = BloomFilterGenerator.withSha1Sha2BiGramHasher(BIT_SET_LENGTH); + BloomFilterGenerator generatorMedium = BloomFilterGenerator.withSha1Sha2BiGramHasher(BIT_SET_LENGTH_MEDIUM); + BloomFilterGenerator generatorShort = BloomFilterGenerator.withSha1Sha2BiGramHasher(BIT_SET_LENGTH_SHORT); + + List<List<Double>> weightLists = getWeightLists(); + + testWeights(weightLists.get(0), generatorLong, generatorMedium, generatorShort); + + writeResultsAsCsv("SHA1_SHA2.csv"); + } + + @Test + public void testWeightsWithSha1Sha2Hmac() + { + BouncyCastleProvider bcProvider = new BouncyCastleProvider(); + + Random rand = new Random(42L); + byte[] key1 = new byte[32]; + byte[] key2 = new byte[32]; + rand.nextBytes(key1); + rand.nextBytes(key2); + + BloomFilterGenerator generatorLong = BloomFilterGenerator.withHmacSha1HmacSha2BiGramHasher(BIT_SET_LENGTH, key1, + key2, bcProvider); + BloomFilterGenerator generatorMedium = BloomFilterGenerator + .withHmacSha1HmacSha2BiGramHasher(BIT_SET_LENGTH_MEDIUM, key1, key2, bcProvider); + BloomFilterGenerator generatorShort = BloomFilterGenerator + .withHmacSha1HmacSha2BiGramHasher(BIT_SET_LENGTH_SHORT, key1, key2, bcProvider); + + List<List<Double>> weightLists = getWeightLists(); + + testWeights(weightLists.get(0), generatorLong, generatorMedium, generatorShort); + + writeResultsAsCsv("SHA1_HMAC_SHA2_HMAC.csv"); + } + + @Test + public void testWeightsWithSha2Sha3() + { + BloomFilterGenerator generatorLong = BloomFilterGenerator.withSha2Sha3BiGramHasher(BIT_SET_LENGTH); + BloomFilterGenerator generatorMedium = BloomFilterGenerator.withSha2Sha3BiGramHasher(BIT_SET_LENGTH_MEDIUM); + BloomFilterGenerator generatorShort = BloomFilterGenerator.withSha2Sha3BiGramHasher(BIT_SET_LENGTH_SHORT); + + List<List<Double>> weightLists = getWeightLists(); + + testWeights(weightLists.get(0), generatorLong, generatorMedium, generatorShort); + + writeResultsAsCsv("SHA2_SHA3.csv"); + } + + @Test + public void testWeightsWithSha2Sha3Hmac() + { + BouncyCastleProvider bcProvider = new BouncyCastleProvider(); + + Random rand = new Random(42L); + byte[] key1 = new byte[32]; + byte[] key2 = new byte[32]; + rand.nextBytes(key1); + rand.nextBytes(key2); + + BloomFilterGenerator generatorLong = BloomFilterGenerator.withHmacSha2HmacSha3BiGramHasher(BIT_SET_LENGTH, key1, + key2, bcProvider); + BloomFilterGenerator generatorMedium = BloomFilterGenerator + .withHmacSha2HmacSha3BiGramHasher(BIT_SET_LENGTH_MEDIUM, key1, key2, bcProvider); + BloomFilterGenerator generatorShort = BloomFilterGenerator + .withHmacSha2HmacSha3BiGramHasher(BIT_SET_LENGTH_SHORT, key1, key2, bcProvider); + + List<List<Double>> weightLists = getWeightLists(); + + testWeights(weightLists.get(0), generatorLong, generatorMedium, generatorShort); + + writeResultsAsCsv("SHA2_HMAC_SHA3_HMAC.csv"); + } + + private void testWeights(List<Double> weightList, BloomFilterGenerator generatorLong, + BloomFilterGenerator generatorMedium, BloomFilterGenerator generatorShort) + { + List<List<TestPerson>> combinedPtRbfs = createPatientsFromRecord(org1, org2, weightList, generatorLong, + generatorMedium, generatorShort); + List<TestPerson> org1Pts = combinedPtRbfs.get(0); + List<TestPerson> org2Pts = combinedPtRbfs.get(1); + + FederatedMatcher<TestPerson> matcher = new FederatedMatcherImpl<>(TestMatchedPerson::new); + Set<MatchedPerson<TestPerson>> matchPatients = matcher.matchPersons(Arrays.asList(org1Pts, org2Pts)); + assertNotNull(matchPatients); + + List<Integer> confusionMt = calculateConfusionMatrixWithTrueNeg(matchPatients); + List<Double> measures = calculateMeasures(confusionMt); + + double tp = confusionMt.get(0); + double fp = confusionMt.get(1); + double fn = confusionMt.get(2); + double tn = confusionMt.get(3); + + List<Double> resultsList = Arrays.asList(tp, fp, fn, tn, measures.get(0), measures.get(1), measures.get(2), + measures.get(3)); + results.put(weightList, resultsList); + } + + private List<Double> calculateMeasures(List<Integer> confMt) + { + double tp = confMt.get(0); + double fp = confMt.get(1); + double fn = confMt.get(2); + double tn = confMt.get(3); + + double precision = tp / (tp + fp); + double recall = tp / (tp + fn); + double accuracy = (tp + tn) / (tp + fp + fn + tn); + double f1 = 2 * ((precision * recall) / (precision + recall)); + + return Arrays.asList(precision, recall, accuracy, f1); + } + + private List<Integer> calculateConfusionMatrixWithTrueNeg(Set<MatchedPerson<TestPerson>> matchPatients) + { + int truePos = 0; + int falsePos = 0; + int trueNeg = 0; + int falseNeg = 0; + + for (MatchedPerson<TestPerson> mP : matchPatients) + { + if (mP.getMatches().size() == 1) + { + String mPId = mP.getFirstMatch().getMedicId().getValue().substring(0, 8).replaceAll("\\D+", ""); + boolean isInOrg1 = false; + boolean isInOrg2 = false; + + for (IdatImpl pt : org1) + { + String ptId1 = pt.getMedicId().substring(0, 8).replaceAll("\\D+", ""); + if (ptId1.equals(mPId)) + { + isInOrg1 = true; + break; + } + } + for (IdatImpl pt : org2) + { + String ptId2 = pt.getMedicId().substring(0, 8).replaceAll("\\D+", ""); + if (ptId2.equals(mPId)) + { + isInOrg2 = true; + break; + } + } + + if (isInOrg1 && isInOrg2) + { + falseNeg++; + } + else + { + trueNeg++; + } + } + else if (mP.getMatches().size() == 2) + { + String firstID = mP.getFirstMatch().getMedicId().getValue().substring(0, 8).replaceAll("\\D+", ""); + String lastID = mP.getLastMatch().getMedicId().getValue().substring(0, 8).replaceAll("\\D+", ""); + if (firstID.equals(lastID)) + { + truePos++; + } + else + { + falsePos++; + } + } + else + { + String firstID = mP.getFirstMatch().getMedicId().getValue().substring(0, 8).replaceAll("\\D+", ""); + for (int i = 1; i < mP.getMatches().size(); i++) + { + Person match = (Person) mP.getMatches().get(i); + String lastID = match.getMedicId().getValue().substring(0, 8).replaceAll("\\D+", ""); + if (firstID.equals(lastID)) + { + truePos++; + } + else + { + falsePos++; + } + } + } + } + + falseNeg /= 2; // Since theyre unmatched, false negatives get counted twice + return Arrays.asList(truePos, falsePos, falseNeg, trueNeg); + } + + private List<List<TestPerson>> createPatientsFromRecord(List<IdatImpl> org1Idat, List<IdatImpl> org2Idat, + List<Double> weightList, BloomFilterGenerator generatorLong, BloomFilterGenerator generatorMedium, + BloomFilterGenerator generatorShort) + { + List<TestPerson> org1Pts = new ArrayList<>(); + List<TestPerson> org2Pts = new ArrayList<>(); + + List<IdatImpl> allPts = new ArrayList<>(); + allPts.addAll(org1Idat); + allPts.addAll(org2Idat); + + List<RecordBloomFilter> rbfList = allPts.parallelStream().map(r -> + { + return new RecordBloomFilter(3000, 42L, + createFbfList(r, weightList, generatorLong, generatorMedium, generatorShort)); + }).collect(Collectors.toList()); + + for (IdatImpl r : allPts) + { + int idx = allPts.indexOf(r); + if (r.getMedicId().contains("org")) // Org 1 IDAT have org (original) id, org 2 idat have dup + { + org1Pts.add(new TestPerson(new MedicIdImpl("org1", r.getMedicId()), rbfList.get(idx).getBitSet())); + } + else + { + org2Pts.add(new TestPerson(new MedicIdImpl("org2", r.getMedicId()), rbfList.get(idx).getBitSet())); + } + } + + return Arrays.asList(org1Pts, org2Pts); + } + + private List<FieldBloomFilter> createFbfList(IdatImpl r, List<Double> weightList, + BloomFilterGenerator generatorLong, BloomFilterGenerator generatorMedium, + BloomFilterGenerator generatorShort) + { + double firstname = weightList.get(0); + double lastname = weightList.get(1); + double sex = weightList.get(2); + double birthday = weightList.get(3); + double zipcode = weightList.get(4); + double city = weightList.get(5); + double country = weightList.get(6); + double insurancenr = weightList.get(7); + double street = weightList.get(8); + + String recId = r.getMedicId(); + FieldBloomFilter firstNameInput = toField(firstname, r.getFirstName(), generatorLong); + FieldBloomFilter lastNameInput = toField(lastname, r.getLastName(), generatorLong); + String ptSex = "f"; + String idNr = recId.substring(0, 8).replaceAll("\\D+", ""); + if (Integer.parseInt(idNr) % 2 == 0) + ptSex = "m"; + FieldBloomFilter sexInput = toField(sex, ptSex, generatorShort); + FieldBloomFilter birthdayInput = toField(birthday, r.getBirthday(), generatorMedium); + FieldBloomFilter zipCodeInput = toField(zipcode, r.getZipCode(), generatorMedium); + FieldBloomFilter cityInput = toField(city, r.getCity(), generatorLong); + FieldBloomFilter countryInput = toField(country, r.getCountry(), generatorLong); + FieldBloomFilter insuranceInput = toField(insurancenr, r.getInsuranceNumber(), generatorLong); + FieldBloomFilter streetInput = toField(street, r.getStreet(), generatorLong); + List<FieldBloomFilter> fbfList = Arrays.asList(firstNameInput, lastNameInput, sexInput, birthdayInput, + zipCodeInput, cityInput, countryInput, insuranceInput, streetInput); + return fbfList; + } + + private FieldBloomFilter toField(double weight, String input, BloomFilterGenerator generator) + { + return new FieldBloomFilter(generator.generateBitSet(input), weight); + } + + private static List<IdatImpl> read2(Path path) + { + try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) + { + Iterable<CSVRecord> records = CSVFormat.RFC4180 + .withHeader("rec_id", "given_name", "surname", "street_number", "address_1", "address_2", "suburb", + "postcode", "state", "date_of_birth", "soc_sec_id") + .withSkipHeaderRecord().parse(reader); + ArrayList<IdatImpl> idats = new ArrayList<>(); + for (CSVRecord r : records) + { + String ptSex = "f"; + String idNr = r.get("rec_id").substring(0, 8).replaceAll("\\D+", ""); + if (Integer.parseInt(idNr) % 2 == 0) + ptSex = "m"; + String bday; + if (r.get("date_of_birth").length() == 8) + { + String bdayYear = r.get("date_of_birth").substring(0, 4); + String bdayMonth = r.get("date_of_birth").substring(4, 6); + String bdayDay = r.get("date_of_birth").substring(6); + bday = bdayDay + "." + bdayMonth + "." + bdayYear; + } + else + { + bday = "NaN"; + } + idats.add(new IdatImpl(r.get("rec_id"), r.get("given_name"), r.get("surname"), ptSex, bday, + r.get("postcode"), r.get("address_2"), r.get("address_1"), r.get("state"), + r.get("soc_sec_id"))); + } + return idats; + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + private static List<IdatImpl> readWithTrueNeg(Path path) + { + try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) + { + Iterable<CSVRecord> records = CSVFormat.RFC4180 + .withHeader("rec_id", "given_name", "surname", "street_number", "address_1", "address_2", "suburb", + "postcode", "state", "date_of_birth", "soc_sec_id") + .withSkipHeaderRecord().parse(reader); + ArrayList<IdatImpl> idats = new ArrayList<>(); + for (CSVRecord r : records) + { + String ptSex = "f"; + String idNr = r.get("rec_id").substring(0, 8).replaceAll("\\D+", ""); + + if (Integer.parseInt(idNr) % 2 == 0) + ptSex = "m"; + String bday; + if (r.get("date_of_birth").length() == 8) + { + String bdayYear = r.get("date_of_birth").substring(0, 4); + String bdayMonth = r.get("date_of_birth").substring(4, 6); + String bdayDay = r.get("date_of_birth").substring(6); + bday = bdayDay + "." + bdayMonth + "." + bdayYear; + } + else + { + bday = "NaN"; + } + if (Integer.parseInt(idNr) < 4000) + { + idats.add(new IdatImpl(r.get("rec_id"), r.get("given_name"), r.get("surname"), ptSex, bday, + r.get("postcode"), r.get("address_2"), r.get("address_1"), r.get("state"), + r.get("soc_sec_id"))); + } + } + return idats; + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + private static List<List<Double>> getWeightLists() + { + List<List<Double>> top10 = Arrays.asList(Arrays.asList(0.1, 0.1, 0.2, 0.05, 0.15, 0.1, 0.15, 0.1, 0.05), + Arrays.asList(0.1, 0.1, 0.2, 0.1, 0.1, 0.1, 0.2, 0.05, 0.05), + Arrays.asList(0.1, 0.1, 0.2, 0.05, 0.15, 0.05, 0.2, 0.1, 0.05), + Arrays.asList(0.1, 0.1, 0.2, 0.1, 0.1, 0.05, 0.2, 0.1, 0.05), + Arrays.asList(0.1, 0.1, 0.2, 0.05, 0.15, 0.05, 0.15, 0.1, 0.1), + Arrays.asList(0.1, 0.1, 0.2, 0.1, 0.05, 0.05, 0.2, 0.1, 0.1), + Arrays.asList(0.1, 0.1, 0.2, 0.1, 0.05, 0.1, 0.2, 0.1, 0.05), + Arrays.asList(0.1, 0.1, 0.2, 0.1, 0.1, 0.05, 0.15, 0.1, 0.1), + Arrays.asList(0.1, 0.1, 0.2, 0.05, 0.1, 0.05, 0.15, 0.15, 0.1), + Arrays.asList(0.1, 0.1, 0.2, 0.1, 0.1, 0.05, 0.2, 0.05, 0.1)); + + return top10; + } + + public static void writeResultsAsCsv(String filename) + { + String[] header = { "firstname", "lastname", "sex", "birthday", "zipcode", "city", "country", "insurancenr", + "street", "tp", "fp", "fn", "tn", "Prec", "Rec", "Acc", "F1" }; + FileWriter out = null; + try + { + out = new FileWriter("src/test/resources/" + filename); + } + catch (IOException e) + { + e.printStackTrace(); + } + try (CSVPrinter printer = new CSVPrinter(out, CSVFormat.DEFAULT.withHeader(header))) + { + results.entrySet().forEach(result -> + { + try + { + List<Double> resultList = new ArrayList<>(); + resultList.addAll(result.getKey()); + resultList.addAll(result.getValue()); + printer.printRecord(resultList); + } + catch (IOException e) + { + e.printStackTrace(); + } + }); + } + catch (IOException e) + { + e.printStackTrace(); + } + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/RecordLinkagePseudonymizationIntegrationTest.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/RecordLinkagePseudonymizationIntegrationTest.java new file mode 100644 index 000000000..2bd4e3442 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/RecordLinkagePseudonymizationIntegrationTest.java @@ -0,0 +1,93 @@ +package org.highmed.pseudonymization.test; + +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import org.highmed.openehr.json.OpenEhrObjectMapperFactory; +import org.highmed.openehr.model.structure.ResultSet; +import org.highmed.pseudonymization.crypto.AesGcmUtil; +import org.highmed.pseudonymization.domain.PersonWithMdat; +import org.highmed.pseudonymization.domain.PseudonymizedPersonWithMdat; +import org.highmed.pseudonymization.domain.impl.MatchedPersonImpl; +import org.highmed.pseudonymization.domain.impl.PseudonymizedPersonImpl; +import org.highmed.pseudonymization.psn.PseudonymGenerator; +import org.highmed.pseudonymization.psn.PseudonymGeneratorImpl; +import org.highmed.pseudonymization.recordlinkage.FederatedMatcher; +import org.highmed.pseudonymization.recordlinkage.FederatedMatcherImpl; +import org.highmed.pseudonymization.recordlinkage.MatchedPerson; +import org.highmed.pseudonymization.translation.ResultSetTranslatorFromMedic; +import org.highmed.pseudonymization.translation.ResultSetTranslatorFromMedicImpl; +import org.highmed.pseudonymization.translation.ResultSetTranslatorToMedic; +import org.highmed.pseudonymization.translation.ResultSetTranslatorToMedicImpl; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class RecordLinkagePseudonymizationIntegrationTest +{ + private static final Logger logger = LoggerFactory.getLogger(RecordLinkagePseudonymizationIntegrationTest.class); + + private ResultSetTranslatorFromMedic fromMedic; + private FederatedMatcher<PersonWithMdat> matcher; + private PseudonymGenerator<PersonWithMdat, PseudonymizedPersonWithMdat> generator; + private ResultSetTranslatorToMedic toMedic; + private ObjectMapper openEhrObjectMapper; + + @Before + public void before() throws Exception + { + fromMedic = new ResultSetTranslatorFromMedicImpl(); + matcher = new FederatedMatcherImpl<>(MatchedPersonImpl::new); + generator = new PseudonymGeneratorImpl<>("researchStudyIdentifier", AesGcmUtil.generateAES256Key(), + new ObjectMapper(), PseudonymizedPersonImpl::new); + toMedic = new ResultSetTranslatorToMedicImpl(); + openEhrObjectMapper = OpenEhrObjectMapperFactory.createObjectMapper(); + } + + @Test + public void testMatch() throws Exception + { + ResultSet resultSet1 = readResultSet(); + ResultSet resultSet2 = readResultSet(); + + List<PersonWithMdat> fromOrg1 = fromMedic.translate("org1", resultSet1); + List<PersonWithMdat> fromOrg2 = fromMedic.translate("org2", resultSet2); + List<List<PersonWithMdat>> personLists = Arrays.asList(fromOrg1, fromOrg2); + + Set<MatchedPerson<PersonWithMdat>> matchedPersons = matcher.matchPersons(personLists); + assertNotNull(matchedPersons); + + List<PseudonymizedPersonWithMdat> pseudonymizedPersons = generator.createPseudonymsAndShuffle(matchedPersons); + assertNotNull(pseudonymizedPersons); + + ResultSet pseudonymizedResultSet = toMedic.translate(resultSet1.getMeta(), resultSet1.getColumns(), + pseudonymizedPersons); + assertNotNull(pseudonymizedResultSet); + + DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); + prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE); + + logger.debug("Pseudonymized ResultSet for Researcher {}", + openEhrObjectMapper.writer(prettyPrinter).writeValueAsString(pseudonymizedResultSet)); + } + + private ResultSet readResultSet() throws IOException + { + try (InputStream in = Files.newInputStream(Paths.get("src/test/resources/rbf_resultset.json"))) + { + return openEhrObjectMapper.readValue(in, ResultSet.class); + } + } +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuiteAll.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuiteAll.java new file mode 100644 index 000000000..d5aacd271 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuiteAll.java @@ -0,0 +1,11 @@ +package org.highmed.pseudonymization.test; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ TestSuiteUnitTests.class, TestSuiteIntegrationTests.class }) +public class TestSuiteAll +{ +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuiteIntegrationTests.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuiteIntegrationTests.java new file mode 100644 index 000000000..1c7890e0e --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuiteIntegrationTests.java @@ -0,0 +1,11 @@ +package org.highmed.pseudonymization.test; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ RecordLinkagePseudonymizationIntegrationTest.class }) +public class TestSuiteIntegrationTests +{ +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuitePerformanceTests.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuitePerformanceTests.java new file mode 100644 index 000000000..235ad5c70 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuitePerformanceTests.java @@ -0,0 +1,13 @@ +package org.highmed.pseudonymization.test; + +import org.highmed.pseudonymization.recordlinkage.MatchingTimeTest; +import org.highmed.pseudonymization.recordlinkage.WeightDistributionTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ MatchingTimeTest.class, WeightDistributionTest.class }) +public class TestSuitePerformanceTests +{ +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuiteUnitTests.java b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuiteUnitTests.java new file mode 100644 index 000000000..00a84b783 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/java/org/highmed/pseudonymization/test/TestSuiteUnitTests.java @@ -0,0 +1,20 @@ +package org.highmed.pseudonymization.test; + +import org.highmed.pseudonymization.domain.MatchedPersonImplJsonTest; +import org.highmed.pseudonymization.domain.PersonImplJsonTest; +import org.highmed.pseudonymization.domain.PseudonymizedPersonImplJsonTest; +import org.highmed.pseudonymization.psn.PseudonyWithPaddingJsonTest; +import org.highmed.pseudonymization.psn.PseudonymGeneratorImplTest; +import org.highmed.pseudonymization.recordlinkage.FederatedMatcherTest; +import org.highmed.pseudonymization.recordlinkage.SingleOrganizationMatcherTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ MatchedPersonImplJsonTest.class, PersonImplJsonTest.class, PseudonymizedPersonImplJsonTest.class, + PseudonymGeneratorImplTest.class, PseudonyWithPaddingJsonTest.class, FederatedMatcherTest.class, + SingleOrganizationMatcherTest.class }) +public class TestSuiteUnitTests +{ +} diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/resources/df5k_dup.csv b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/resources/df5k_dup.csv new file mode 100644 index 000000000..a63e2a80e --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/resources/df5k_dup.csv @@ -0,0 +1,5001 @@ +rec_id,given_name,surname,street_number,address_1,address_2,suburb,postcode,state,date_of_birth,soc_sec_id +rec-561-dup-0,elton,,3,light setreet,pinehill,windermere,3212,vic,19651013,1551941 +rec-2642-dup-0,mitchell,maxon,47,edkins street,lochaoair,north ryde,3355,nsw,19390212,8859999 +rec-608-dup-0,,white,72,lambrigg street,kelgoola,broadbeach waters,3159,vic,19620216,9731855 +rec-3239-dup-0,elk i,menzies,1,lyster place,,northwood,2585,vic,19980624,4970481 +rec-2886-dup-0,,garanggar,,may maxwell crescent,springettst arcade,forest hill,2342,vic,19921016,1366884 +rec-4285-dup-0,sophie,manson,14,elizabeth xrescent,manorhouse,gorokan,3465,vic,19510201,4818868 +rec-929-dup-0,madison,morrison,38,peacock place,melim a,campbelltown,3021,wa,19481214,1967265 +rec-4833-dup-0,jayed,millar,6,meredith c ircuit,,thornbury,6014,vic,19340731,1314310 +rec-717-dup-0,joshua,raward,26,yambina cerscent,thorndale,macgrdgor,4718,qld,,9086686 +rec-3984-dup-0,david,sette,105,spring raghe road,jessiefield,villawood,2213,wa,19950603,9471099 +rec-3138-dup-0,jacob,delfos,102,morgan crescent,valicare,geurie,4557,act,19510208,4071052 +rec-1424-dup-0,braiden,hering,26,snowde n place,peppercor lodge,new farm,3016,nsw,19240408,7720229 +rec-825-dup-0,mia,wnite,1329,national circuit,sec 301,narembeen,2765,nsw,19130418,5053650 +rec-520-dup-0,nicholas,mcneill,16,,tunis,bacchus marsh,6019,nsw,19800829,5215850 +rec-3868-dup-0,rybak,jassim,16,newman morrisf circuit,brookfield,oromnd,2218,vic,19840706,8822389 +rec-147-dup-0,cassandra,lock,5,glossop cerscent,kames,scarborough,6153,nsw,19371206,2516564 +rec-919-dup-0,ilam,tschitrpig,61,biffin sreet,,blacktown,2221,nsw,19970528,6098354 +rec-3156-dup-0,adam,ewald,,wentcher place,longstay caravn park,kempsey,5902,nsw,19180203,2268410 +rec-1026-dup-0,lochlan,weaver,30,carnegie crescent,gantham,wendouree,3197,nsw,19990511,4335106 +rec-3272-dup-0,zara,white,189,mackey place,doctors flat,hawthorn,4300,wa,19320621,7744887 +rec-4342-dup-0,,grubb,10,berne cresxent,yooringa,st hubertscisland,6539,nsw,19341211,6333533 +rec-4788-dup-0,shanaye,averats,162,benjami n way,ashville,bamawm,3175,qld,19340625,8786773 +rec-3978-dup-0,,babic,1,totterdell street,cooingale,st albans,4060,sa,19450493,3346822 +rec-2440-dup-0,amy,green,8,cahalan place,,east preston,2114,,19900401,2287496 +rec-4517-dup-0,isabe lla,waller,,blackbu rn street,omeo,stanmore,5035,vic,19500719,7270771 +rec-4595-dup-0,samuel,rudd,46,powlett street,,kingston,3453,sa,19580819,7309587 +rec-316-dup-0,jordan,whie,8,,,ryde,2148,vic,19890416,6617539 +rec-1413-dup-0,brielle,speabrs,8,tunney c rescent,hd blanch sec 28,rosslyn park,3350,wa,19890201,3140493 +rec-470-dup-0,harry,bishop,5,darwinia terrace,craigsto nl1bg,glenmore aprk,4830,wa,19781114,7781607 +rec-2871-dup-0,noah,fusco,65,kruseplace,thepoints h olsteins,kununurra,3400,nsw,19490107,9136935 +rec-4096-dup-0,stella,clarke,11,leist strewt,emerald banks,burnie,3152,wa,19020227,6990160 +rec-567-dup-0,bradley,sribar,32,sturt avenue,everge en,buronga,2710,sa,19511217,9160808 +rec-3089-dup-0,annabel,thropr,21,airey crescent,galloway,rokeby,4670,vic,19920305,2814912 +rec-4233-dup-0,joshua,dixon,60,croton street,ethnam arm,surrey hills,2617,nsw,19481014,5540614 +rec-3874-dup-0,jacob,wbeb,14,hawdon treet,aumuller house,forest lodge,6050,nsw,19450315,8971806 +rec-1168-dup-0,isabella,ryan,61,downes place,spring ridge,ardeer,3058,nsw,19331204,4702512 +rec-4618-dup-0,chloe,musoilno,4,warrumbmul street,gordoivale,brighton,3728,ni,,7147784 +rec-2896-dup-0,blake,mcvicar,26,ellerston avenue,rosehill,bowral,3009,qld,19890504,1219082 +rec-3044-dup-0,nicholas,mycko,259,alma close,farm shed,centennail park,3000,qld,19450728,3274337 +rec-2852-dup-0,kiana,huxley,12,southern close,little dale,maryborough,2517,nsw,19140529,1728316 +rec-1492-dup-0,macormack,campball,21,shipard place,demountabel bldg,brighton,2546,qld,19640101,3116298 +rec-1108-dup-0,lachln,murton,191,barraclough crescent,medcl cntr (cnr queen s street,east hills,2707,nsw,19770527,2068877 +rec-2621-dup-0,casey,heran,10,cathie p lace,watarmark,rowville,6135,sa,19390522,8255871 +rec-2867-dup-0,bailey,satte rley,28,newman morcbis circuit,carrington garden,beamont,2074,nsw,19730919,1989082 +rec-2979-dup-0,caleb,dabinet,30,springfields farms,rodway tsreet,mount ommaney,3133,qld,19040620,2071263 +rec-4466-dup-0,bllke,white,16,brunto nstreet,rosetta village,frankxton,2800,vic,19731009,6366377 +rec-4903-dup-0,mihal,hannsh,,aspinal ls treet,,nyal west,6060,vic,,7161412 +rec-1445-dup-0,paige,webb,,arthaldo court,,cardkff,5023,vic,19341104,6388140 +rec-2854-dup-0,nahan,bishop,2,osburn drive,noosa village shopping centre,woodhill,2530,vic,19961008,6472175 +rec-4281-dup-0,saraa,carmody,14,gilmore crescent,brentwood vlge,denmark,4650,wa,19830421,7880298 +rec-1831-dup-0,mia,reid,4,le hunte srreet,marretth,como,3777,vic,19800421,3451673 +rec-172-dup-0,adamx,craze,,mcclintoxk street,loma langie,portarlington,3199,wa,19270510,3239913 +rec-2239-dup-0,makenzi,elphick,31,copland drive,gwand alan,erskine,4214,wa,19500810,1011936 +rec-2873-dup-0,rhys,horsley,11,,calalafarm,sale,7130,nsw,19070227,5179281 +rec-3040-dup-0,zane,webb,4,mackinolty street,mayflower rtrmnt vlge,ganmani,6018,vic,19190523,1897310 +rec-1015-dup-0,bailey,zilm,11,,craigow,deer park,6112,tas,19471001,5100168 +rec-2154-dup-0,phoebe,,33,kumm place,the manor garden,harris park,2323,vic,19061113,3155906 +rec-4799-dup-0,molly,hanna,18,lewis luxton avenue,tullaillan,salisbury east,2032,vic,19171018,3994290 +rec-3528-dup-0,,gibb,35,tenison-woodsr circuit,the j gms,adamstown heights,6333,nsw,19090430,3651633 +rec-2434-dup-0,,ebert,69,rapanea street,pangabi,,6061,nsw,19310909,9105802 +rec-4382-dup-0,cambell,coteman,45,norton street,skilbister,coniston,3803,act,19731016,2389212 +rec-2786-dup-0,marko,lamprey,23,kilburnie,backler place,windsor,6083,nsw,19401125,4959474 +rec-2685-dup-0,joe,lodgw,200,steinwedel street,kmart p plaza,toowoomba,4016,wa,19710830,2655513 +rec-3436-dup-0,ethan,marson,40,catumbel lodge,tinaroo place,hoppers crossing,2035,vic,19100123,9238396 +rec-4668-dup-0,elton,coldicutt,3,somerset s treet,newman medcaql centre,ashfield,5037,vic,19341016,9721944 +rec-3570-dup-0,ja xson,selht,1,moonta place,walhalla,maryborough,2066,qld,19130707,7238580 +rec-490-dup-0,crystal,webb,6,holman street,rowethorpe,nora,3095,vic,19800226,6491894 +rec-3777-dup-0,lachlarn,ricard,40,wallaroeroad,,bowral,4158,sa,19531101,6012074 +rec-4113-dup-0,sophie,au,26,pelham close,locn n192,sandy bay,3192,vic,,4507512 +rec-4592-dup-0,elizabeth,nobli,33,rosebery street,glenomre,eatons hill,2458,vic,19820730,7294023 +rec-4070-dup-0,chandler,hamish,9,allavnale,eton place,bribie island,2831,tas,19871001,3981694 +rec-4862-dup-0,matthew,walms,1121,massi e place,the stockyards,dalby,3352,nsw,19280328,6147905 +rec-629-dup-0,willim,lund,8,bridgedtreet,pevensey,bowral,4350,qld,19211017,4144401 +rec-2447-dup-0,mattheo,godfley,22,madigan street,tantallon,mayfield,2444,vic,19811231,1967139 +rec-2694-dup-0,ebony,piniros,16,ashby c ircuit,,meltonsouth,2913,nsw,19030607,6804193 +rec-3899-dup-0,noah,berry,58,alice jackse on crescent,rosehill,hawthorn,5251,sa,19240908,1446426 +rec-4878-dup-0,,lowry,80,kinchela crescent,rowethorpe,rossmoyne,2770,qld,19350708,6616912 +rec-1503-dup-0,jasmine,ryah,49,spofforth street,kirra vista,daylesford,3072,nsw,19161002,7987659 +rec-4831-dup-0,cleb,thorpe,4,river street,,granville,2641,nsw,19590118,7916134 +rec-888-dup-0,caitlin,berry,29,carr crscent,bletchly aprk,corrimal east,4075,sa,19780804,2225444 +rec-3917-dup-0,angelina,lowry,20,browne place,craisgton,peakhurst,3284,qld,19350921,5692471 +rec-2713-dup-0,benjamin,morr ison,16,kingscotecrescent,malanda orchard,sanctuary point,0280,nws,19761231,3201927 +rec-3390-dup-0,evan,,3,livingstonavenue,,burleigh heads,2289,vic,19450220,8451831 +rec-109-dup-0,dnaiel,fysh,27,appel crescent,,hermit park,2333,nsw,19620207,3085695 +rec-4162-dup-0,mollie,sherriff,9,dalley crescent,tarliunp,newstaed,4207,qld,19051216,5596459 +rec-1226-dup-0,seth,moovdy,42,scantlebury crescent,the lodge,sippy dawns,3156,vic,19270524,6853828 +rec-2175-dup-0,brianna,wardle,1,mcdougalll street,,beechbohro,3165,nsw,19440826,2063140 +rec-2820-dup-0,millie,neville,38,menziesn court,,toowoomba,2066,nsw,19950511,8251642 +rec-4051-dup-0,luke,mccartyy,5,bandjalongcrescent,,north curl curl,2160,nsw,19521124,9203828 +rec-4486-dup-0,hayey,ryan,2,lambrig gstreet,flt 67,jardee,2750,act,19880816,7698870 +rec-3316-dup-0,sophie,coulson,8,blackburn street,,mansfield park,5097,nsw,19690320,9010006 +rec-687-dup-0,brodie,gren,169,staunton place,star court arcade,bellevue hill,3175,nsw,19690410,5667813 +rec-1552-dup-0,daniel,callahtn,119,halifax close,medical ce ntre,smythesdale,2400,nsw,19530309,3925704 +rec-802-dup-0,mya,mccarthy,43,wakool circuit,,moona hwest,2063,nsw,19120729,5475592 +rec-1880-dup-0,liam,coenen,66,stretton c rescent,,patterson lakes,6060,qld,19690602,1128736 +rec-2306-dup-0,zali,white,,blackman crescent,glenairne,bundaberg,6280,wa,19020311,7291149 +rec-394-dup-0,lachlan,ryan,51,totterdell street,roseglen,dalhy,3168,qld,19480724,7284475 +rec-2963-dup-0,fyynlay,deblasio,,longerenong street,werribee plaza,forest hill,2790,nsw,19161102,8968244 +rec-4451-dup-0,jarus,scamnoi,375,bissenberger crescent,dalmoora,goodna,4670,qld,19120912,6966609 +rec-8-dup-0,nicholas,procter,1,cavanaughlstreet,sherwood,leevflle,2089,nsw,19031219,2662272 +rec-2543-dup-0,mia,white,6,theodore street,calaltobta,haddon,2905,nsw,19640403,5969084 +rec-1340-dup-0,spencer,klus,7,gatton street,whispern ig pines,young,5097,vic,19020122,4996874 +rec-1582-dup-0,hannah,rivers,5,collings street,,toorak,2487,nsw,19521217,6906828 +rec-3311-dup-0,coby,brinsmead,9,musgrave street,st francis vlge,canley heights,4552,qld,19391009,8442114 +rec-4549-dup-0,mitchell,green,,palmer street,,lake heights,2430,qld,19250116,7447942 +rec-3292-dup-0,mikayla,siviour,2,steinwedel street,cherry bank,pymble,0237,vic,19850704,2668143 +rec-1655-dup-0,lily,innis,57,harricks crescent,yarramdale,st albans,3002,qld,19880321,2533253 +rec-3575-dup-0,tayla,coulson,119,backler place,,toowoomba,4305,vic,19300517,5222388 +rec-278-dup-0,samuel,gilbertson,7,phillips place,bulliac str eet,brewarrina,6151,qld,19581011,9448590 +rec-649-dup-0,mi,haeusler,,stockdale street,rowethlrpe,cleveland,3011,nws,19091107,3742016 +rec-3088-dup-0,sachi n,,85,sparkes close,villa36 sovereign garden,cainrs,2750,vic,19820717,8721401 +rec-4091-dup-0,cheyenze,campbell,18,forbes street,kinjbii,bundamba,4814,vic,19080715,6532935 +rec-903-dup-0,barisic,brianna,1502,haddon street,parish talowahl,launching place,3220,vic,19750703,5367822 +rec-536-dup-0,aleisha,lowed,9,cavanaugh street,,mulgraeeast,2445,wa,19731203,3335374 +rec-497-dup-0,emii ly,cobgin,3,knox stteet,,camperdown,2230,wa,19991209,9931751 +rec-2100-dup-0,talia,millaf,20,la perous e street,,kellyfville,2250,wa,19800606,3894135 +rec-597-dup-0,shenae,leslie,45,jacka crescent,villa 5,oakleigh,4151,qld,19710804,4216793 +rec-891-dup-0,gregory,timperon,38,engelbert wing,bentham street,berwick,2564,nsw,19531206,1115863 +rec-3783-dup-0,katelyn,newport,7,wakefield avenue,glenmore,moree,4662,qld,19401219,4895884 +rec-2190-dup-0,dimitri,kowald,4,watson street,,alice s prings,2430,sa,19510207,1597094 +rec-424-dup-0,nicholas,scantlebury,25,kambah vlge,casuarina sh oppingsqre,fish creek,3585,nsw,19370405,8589026 +rec-4620-dup-0,flynn,zilkm,6,beaurepaire crescent,,duncraig,3068,vic,19500619,6378859 +rec-2353-dup-0,benjamin,bellon,11,croton street,omaru,artarmon,4406,nsw,19120805,3089666 +rec-3336-dup-0,jacobj,crossm an,19,stromlodrescent,,bassendean,5031,,19681226,6490727 +rec-3004-dup-0,zachary,hulands,51,caley crescent,,albany creek,5161,tas,19360826,9722255 +rec-1270-dup-0,elle,mattehws,54,maddock place,glenburnie lodge,park orhcards,6058,vic,19960094,9253952 +rec-2798-dup-0,kane,carbone,54,penrhyn street,solander centre,deer park,4030,sa,19960506,9098940 +rec-304-dup-0,zoe,wastll,5,mount vernon drive,bandera,burwood,3350,vic,19981215,6868962 +rec-1905-dup-0,arren,matthews,,coombe street,ballyoby,wahroonga,3617,nsw,19860121,8047381 +rec-4874-dup-0,silas,coulson,29,bindon place,warra creek,kempsey,6457,nsw,19770903,3722652 +rec-3974-dup-0,carly,webb,31,dash crescent,frestoocotge,buffalo,3225,wa,19121203,5240972 +rec-603-dup-0,ebony,zaffimo,24,max henry crescent,ripone state,newmarket,4305,qld,19420501,8073270 +rec-821-dup-0,chloe,condo,36,yabsley place,munmurar park,mackay north,5082,nsw,19170115,7153959 +rec-54-dup-0,imowen,whillas,121,embley street,flowerydale,molong,2170,tas,19090319,7145066 +rec-4274-dup-0,marlegih,white,1,fink crescent,dunbar,hackham,2165,qld,19900270,6423331 +rec-4277-dup-0,mitchell,flannery,2,wilkins street,paradise syprings,toowoomba,5088,vic,19581016,8712141 +rec-4463-dup-0,isabella,,576,grimshaw street,brentwood vlge,tar,2092,qld,19440214,5901255 +rec-3-dup-0,reeve,stanlhy,4,alawa street,rowethorpe d1,mourilyan,2474,sa,19190811,5961670 +rec-4747-dup-0,robertza,caire,41,por t u4,welch place,beaconsfield upper,5113,sa,19630418,5100047 +rec-1195-dup-0,jeswica,blackwell,20,mcgeep lace,brentwoo dvlge,ermington,2795,sa,19801015,4099338 +rec-585-dup-0,stephenson,danny,16,o'shanassy street,,armidale,3133,tas,19831019,8561604 +rec-2114-dup-0,chloe,lowme,344,phillipiaenue,lewin lodge,deagn,4306,aw,19840502,6220613 +rec-2936-dup-0,tinfina,harrison,5,deasland place,toolebewong farm,southbank,2217,nsw,19880108,4659883 +rec-4660-dup-0,georgia,clarke,278,blowerinb street,dunfieldpark,port pirie,6111,vic,19990330,3328605 +rec-2627-dup-0,seth,donaldson,1329,bean crescent,brae brun,camperdown,2153,vic,,1727482 +rec-2876-dup-0,,green,48,spowers cricuit,,labrador,5063,nsw,19421213,8321036 +rec-3599-dup-0,sophie,masojn,23,,,greensborough,2020,qld,19341211,7259553 +rec-654-dup-0,devan,riddell,33,muellerstreet,red cross units,avalon beach,2257,nse,19391217,4921767 +rec-4305-dup-0,,noble,10,costello circuit,the manor braeside,bicton,2290,qld,19710327,9357658 +rec-1592-dup-0,karli,campbzell,58,burdekin avenue,brambletye vinyard,,2118,vic,19580309,4423725 +rec-1414-dup-0,zali,eglinton,14,adcock place,trewilga,woodlajnds,2122,qld,19300914,7126898 +rec-4422-dup-0,,ryan,20,ashburton circuit,wilderness,cressy,2580,vic,19560126,3864187 +rec-1760-dup-0,nicholsa,ho,13,newdegate street,villa 2,elwood,4061,nsw,19680630,7806235 +rec-4508-dup-0,harrison,mcneull,1,geeves cort,branmigans,highett,2319,qld,19280108,6287203 +rec-3107-dup-0,emiiy,braithwaite,86,beasley street,belmont bayview park,st agnse,4814,nsw,19140328,4464915 +rec-4808-dup-0,lucyw,satterley,32,gill street,nepean shores,buninyong,4226,sz,19660516,9616924 +rec-722-dup-0,lachlan,goldsworthy,5,wanganeen avenue,howie circuit,sheidow park,2038,sa,19380108,4133306 +rec-3907-dup-0,timothy,haythorpe,21,grund p lace,brentwood vlge,blackmans bay,2603,vic,19200714,2476740 +rec-80-dup-0,blake,white,198,boldrewood street,winterp ark,nunawading,2067,sa,19180815,5832531 +rec-1054-dup-0,joshua,capel,1,clive steele avenue,spq acmp,woonrara,4207,qld,19090522,4415928 +rec-317-dup-0,amber,nicolakopoulos,38,atkinson street,mount patrick,edgewter,2905,sa,19910707,9220881 +rec-370-dup-0,isablel,lowe,18,wolff crscent,,sylvania,2032,nsw,19771116,5672191 +rec-4612-dup-0,alana,manson,52,,vivigani,cloverdale,2118,vic,19460725,4207566 +rec-4337-dup-0,blake,seted,17,chirnside circuit,rosetta village,balwyn north,2731,qld,19880408,3748565 +rec-2887-dup-0,brody,stearnnes,7,fincham crescent,binnal ong,thornbury,3639,vic,19440417,8363677 +rec-2104-dup-0,olivia,leong,57,naismit hplace,mckail,deer park,3177,nsw,19820831,5649007 +rec-622-dup-0,joshua,avdic,8,archdal l street,nioa,nunawading,3134,nsw,19200415,9571448 +rec-764-dup-0,devan,clatke,,windradyne street,buena vista,south perth,4127,nsw,19060130,3013362 +rec-3326-dup-0,jarryd,george,83,gilmore crescent,,wellakrd,3071,qld,19320810,4392990 +rec-4475-dup-0,william,richmond,7,redlands,totterdell street,metubg,6076,nsw,19110103,3661413 +rec-1697-dup-0,andie,george,118,mckail crescent,brentwood vlge,pelican dwaters,3121,wa,19490414,4798962 +rec-4404-dup-0,nicholas,commoyns,50,couchman crescent,lochlee,pardale,5169,sa,19980815,9438920 +rec-3780-dup-0,ethan,hand,1,lambrigg sitreet,rainmore,sout perth,5075,vic,19411222,3559682 +rec-636-dup-0,vaszocz,adam,63,wyles place,willows caravn park,graveesnd,3153,vic,,1015197 +rec-2965-dup-0,tiarna,harrigton,1,crisp circuit,,mannm,5264,nsw,19060622,9303949 +rec-683-dup-0,oscxar,zdanowicz,21,arndell street,craiglea,burwood,2088,vic,19450906,5103704 +rec-4169-dup-0,luge,menzies,14,,roskihll,barmera,6072,vic,19710422,8114472 +rec-1399-dup-0,charlee,,,coane street,mount ivew,thornlands,2548,nsw,19105412,1945725 +rec-2449-dup-0,tess,green,60,,ryhd-talog,port macquarie,3013,vic,19600324,5445613 +rec-3724-dup-0,jacob,beatton,,maharattacircuit,specialist centre,robertson,2643,nsw,19860630,9285118 +rec-4294-dup-0,,melham,21,kingscote crescent,kerry street,elizabeth vale,2663,wa,19911210,5648275 +rec-2379-dup-0,jacquline,maliauskas,4,jabanunggaavenue,longpkain,bundanoon,4878,vic,19840808,4094122 +rec-2445-dup-0,ella,campain,2,bimbiang nc rescent,st john of god hospital,seven hills,2160,vic,19900406,8809552 +rec-3171-dup-0,jajie,fernando,37,collings street,bogong apartments,lansdowne,3910,sj,19200720,1939746 +rec-1695-dup-0,abbey,malin,3,burkittl street,mailnga,north maclean,2080,vic,19850328,7401540 +rec-240-dup-0,seth,jolly,16,reddall close,arrowgrove,colac,4370,qld,,7445552 +rec-3327-dup-0,ella,browwne,35,tanjil loop,cedavriew,berkeley vale,4564,qld,19480726,6646608 +rec-478-dup-0,jack,collinson,4,blowering os treet,canobolasceaavn park,leeton,4212,nsw,19821223,5810985 +rec-2924-dup-0,tarnex,fitzpatrick,8,conjola close,,st kilda,4421,qld,19950715,8081610 +rec-708-dup-0,mila,campbell,36,beasley street,krismark,dalby,2375,nsw,19010602,5343180 +rec-4664-dup-0,,czarnik,10,bunbury street,glneavon,ulmarra,4252,qld,19601222,3960160 +rec-380-dup-0,kyle,badawee,5,staunton place,dockside marina b,altona n orth,3138,qld,19020413,3257675 +rec-3057-dup-0,sophie,noble,1,yambina crescent,sefton park,rues,6210,nsw,19440101,3325291 +rec-846-dup-0,connor,camp,29,egerton close,gwandalan,riverhilts,2170,vic,19190905,5237893 +rec-4447-dup-0,hope,imogen,5,dumaresq street,delmar,beecroft,7307,wa,19770614,8438312 +rec-4492-dup-0,hayden,,13,durahm pl ace,hamiltno,young,3121,nsw,19780531,9988689 +rec-3661-dup-0,hudson,chadoer,86,campbellstreet,lazy acres,ingl ewood,4570,sa,19950220,8352621 +rec-1350-dup-0,james,reid,30,snodgrass crescent,diabllo,belmont,2261,qld,19790129,2073967 +rec-4504-dup-0,jasmine,camens,7,plowman place,c/-runaway aby marina,tennant creek,2088,vic,19020413,9907745 +rec-4905-dup-0,elki,nguyen,20,higinbothabmstreet,oakdale,waratah north,6168,qld,19111101,1060379 +rec-299-dup-0,dylan,blacklow,100,stenhouse close,flr 5 john flynn medical centre,vermony,2538,nsw,19399222,8225337 +rec-2193-dup-0,keaton,green,47,salvado place,racecoruse,palinyewah,7008,nsw,19040705,3688006 +rec-3532-dup-0,samul,tunstlal,22,wattle street,bayana,fish cfeek,7216,wa,19840412,8429651 +rec-2989-dup-0,antn,goode,1,lalor stteet,killara homestead,taree,2195,vic,19081025,3128298 +rec-2862-dup-0,katelyn,cochrane,200,langdon avenue,kalamos,calen,3152,qld,19180604,2589251 +rec-311-dup-0,,maier,36,,pine view,rydd,4070,nsw,19020410,4418189 +rec-680-dup-0,jacqueline,abbondandola,24,myers place,ingledell,seelands,2560,tas,19690218,7256635 +rec-1755-dup-0,jayde n,white,10,mcclintock street,,melvilke,4308,nsw,19590819,2360230 +rec-4052-dup-0,sasia,roberti,2070,wiburd street,dodonaea wing,rose bay,4078,vic,19691123,5721375 +rec-4901-dup-0,renfrey,annabella,32,quandong street,,dalby,3291,nsw,19880902,1074106 +rec-117-dup-0,nicholas,huxley,12,biala place,c w v,anglsea,3109,nsw,19921105,6501674 +rec-3571-dup-0,wilson-wheeler,emiily,1,woolcock street,willandra,taree,2477,qld,19610625,8119451 +rec-3065-dup-0,lowe,robbie,27,ambalindum street,,armidale,4558,nsw,19680428,2465721 +rec-2532-dup-0,david,nguyekn,95,maurice place,palm grove,,3138,vic,19340626,7414934 +rec-4252-dup-0,stepahnie,tiller,281,mcleod place,villa 19,katherine,2680,vic,19631220,7432991 +rec-1187-dup-0,kira,kyricaou,70,hopegood place,rowethorpe,tiaro,5024,vic,19820117,3935956 +rec-2049-dup-0,emma,wevb,11,baracchi crescent,thornbrook,eight mil e plains,3016,qld,19910314,5201994 +rec-614-dup-0,lewis,ryan,10,melba treet,binna burra mountain lodge,yerrinbool,5128,vic,19591211,9701047 +rec-452-dup-0,riley,kelley,8185,edmond close,leisure living vlge,mount stuart,2706,sa,19390207,4148621 +rec-4135-dup-0,simone,clarke,105,lambriggstreet,,kirribilli,2765,nsw,19930504,6453396 +rec-1741-dup-0,bryce,laverty,3,dobinson place,weddinvkiew,woombye,3162,nsw,19950921,8513947 +rec-332-dup-0,caleb,quiill,9,rosebery street,laura pengilly wing,granville,5007,nsw,19040203,8733587 +rec-1821-dup-0,dale,laundy,75,miller street,,redh ead,6112,qld,,8721689 +rec-3178-dup-0,natalia,maczkowiack,,badcoe sv treet,,south turramurra,3199,vic,19830221,7491278 +rec-1042-dup-0,alexa-rose,nguyen,,bemm place,,currimundi,4305,nws,19830703,4776446 +rec-1927-dup-0,reid,michael,8,terramora,upton street,macquarie fields,2452,qld,19050922,1117934 +rec-239-dup-0,liam,jolly,10,endeavour sreet,pinnacles caravn park,mansfield,7310,qld,19931105,2506329 +rec-251-dup-0,mackenzi,evertt,2,bettington circuit,bay city plaza,valla,3082,nsw,19870303,4768278 +rec-2601-dup-0,thurlow,alexandra,29,de bur gh street,,north turramurra,2197,nsw,19581002,9502776 +rec-335-dup-0,nodh,reid,10,ellerston abenue,ahwahnee,inglewood,3032,vic,19310305,2293151 +rec-198-dup-0,isabella,spikcer,,lumeah street,lochinvah,boyne island,2780,wa,19130404,1159942 +rec-4452-dup-0,gm,newel,23,steele srteet,kubin village,yehda,3202,nsw,19610112,2538798 +rec-263-dup-0,john,ryan,,chuculba crescent,redfern station,,4605,vic,19840524,2056918 +rec-932-dup-0,,webb,25,toolambi street,villa 235 henry kendall vlge,helens hill,6166,sa,19470715,1945645 +rec-2461-dup-0,angus,godfrey,1,lamingtons treet,ulc 4,pannawpnoica,5660,vic,19050930,8426472 +rec-684-dup-0,miller,nguyen,23,arndell street,myalpa,athelstone,2483,nsw,19680122,3203561 +rec-4646-dup-0,green,india,11,feltus place,ningana,urangan,2197,nsw,19720703,8013479 +rec-4152-dup-0,lachlan,rawlibs,49,lochleugh,whispering pines,coonamble,2089,nsw,19261022,9145105 +rec-4290-dup-0,ale,mckerlie,20,short place,deepnedi,sefton,4370,vic,19890714,3276175 +rec-1463-dup-0,hayedn,marinos,10,chirnside circuit,allensleigh,success,6560,vic,19720613,6046848 +rec-3603-dup-0,isabeola,tinsley,181,,sherqood,maiden gully,5039,vic,19620924,7350425 +rec-4872-dup-0,lachlan,white,1,atherton tsreet,the mews royal hotel bldg,alexandra bridge,3390,vic,19810422,5260328 +rec-3146-dup-0,georgia,lionis,,fitchett street,summerh hill,dundowran,5520,vic,19910624,7770207 +rec-1396-dup-0,lara,stanley,89,napper place,,carlingford,3139,qld,19380827,4712092 +rec-1101-dup-0,joshua,webb,63,decker place,docker rivercommunity,morphettville,2420,nsw,19690619,9196315 +rec-1002-dup-0,joshua,fauser,2,unt 2,harrington pcircuit,kingsford,2280,nsw,19820606,4981335 +rec-3962-dup-0,victoria,campqbell,11,priddle treet,mungrup stud,doubelfiew,7009,vic,19721211,1936096 +rec-1674-dup-0,keelu,harrinrgton,296,brickhill place,henry kendall hostel,menindee,2830,nsw,19330913,1759909 +rec-2282-dup-0,delcay,erin,16,cooinda court,rowethorpe,swan hill,2480,vic,19120628,3648623 +rec-489-dup-0,brandon,strangway,177,everard lace,dryroc k gulch,hinchinbrook,4121,nsw,19220610,4691109 +rec-3683-dup-0,alicia,hyland,112,fullagar vrescent,ambervale,keilorzeast,5161,vic,,9571063 +rec-1217-dup-0,maddison,mahon,62,ellenborlugh street,brentwood vlge,east gordon,2224,qld,19381111,9648098 +rec-2031-dup-0,zachry,white,324,kirkland circuit,r s l retmnt vlge,thornlands,3178,nsw,19120924,5293853 +rec-4238-dup-0,zachariah,nadels,68,,laureldale,northgate,2133,qld,,9143498 +rec-1868-dup-0,graham-jones,amelua,5,mcgivern crescent,,new town,2163,act,19000619,5592088 +rec-422-dup-0,tala,rees,13,lethbridge street,,bront,3035,nsw,19800402,4895894 +rec-1000-dup-0,victoria,zbierski,70,wybalena grove,inverbeath,paralowie,5065,nsw,19720503,1267612 +rec-134-dup-0,jayden,,3,o'sulliva street,the lodge,mount evelyn,2169,nsw,19331220,7133986 +rec-3730-dup-0,shanaye,navarro,103,central coast van park,frater crescent,dulwich hill,3064,vic,19211104,9601221 +rec-3997-dup-0,jessica,beam,19,glenubrn,griffiths street,toorak,5540,nsw,19040321,7839655 +rec-1326-dup-0,madison,campbnl,2,terrigal crescent,pendleside,port maquarie,4184,vic,19480830,4528630 +rec-58-dup-0,jayde,glass,15,macarthur avenue,shillelath park,glenella,3200,vic,19161226,9446536 +rec-3981-dup-0,john,tuke,,moore street,cuthbertscourt,castlemaine,4558,qld,19570904,4216956 +rec-4423-dup-0,bradley,everett,13,greenough circuit,miowera,caves beach,2267,nsw,19660606,8990768 +rec-4178-dup-0,caitlin,basey,414,pelsart street,st francis vlge,daisyh ill,2113,nsw,19110711,7811311 +rec-1377-dup-0,davdi,stapenell,27,gosse street,treetops,new farm,2582,qld,19710118,6109183 +rec-3846-dup-0,kirra,watkiln,29,geelong estreet,,nicholls,2088,nsw,19700924,1203301 +rec-4472-dup-0,william,pia zza,219,monfries place,weemilah,pymble,5605,nsw,19150522,8044732 +rec-1524-dup-0,lily,krishnqn,2,bourne treet,redhill,keysborough,2604,qld,19681003,8956118 +rec-2179-dup-0,thomas,kinnane,10,centaurus street,water vew,bondi junction,2010,nsw,19700907,9269196 +rec-1751-dup-0,isabella,block,114,petterd street,westella,st albans,6149,,19111028,2274501 +rec-2666-dup-0,laur a,hefford,3,partridgqe street,homeo 186,bansia,6530,sa,,7280622 +rec-485-dup-0,patrvrck,george,11,coxen stret,belleview,urangan,4051,nsw,19371129,5526595 +rec-3651-dup-0,tommy,white,4,preston street,ben hlil,wahroonga,2230,wa,19161007,3053568 +rec-1268-dup-0,,reid,11,,green lzgoon,camp hill,6026,vic,19671214,5483640 +rec-173-dup-0,andr ew,renfrey,23,woolner circuit,mindaree,,3844,nsw,19490115,9309636 +rec-755-dup-0,deakyn,bl ake,251,middleton circuit,rowethorpe,avalon beach,5171,nsw,19540831,2780999 +rec-2691-dup-0,jacqueline,verco,11,girdlestone circuit,kingston tower,cliftons prings,4152,,19340706,1075870 +rec-3659-dup-0,ale xander,vincent,51,gallagher street,top end,belmont,2333,qld,19150726,3732438 +rec-2342-dup-0,lauren,hilton,71,grayson street,glenmore,coroi,2645,wa,19150223,5611249 +rec-3936-dup-0,dakota,jeffries,27,redcliffekstreet,drayton villas,ringwood north,5113,wa,19050412,5624716 +rec-4409-dup-0,joshua,needham,20,,jackarand alodge,manunda,2325,qld,19130421,6586520 +rec-1148-dup-0,,reid,32,ina gregory circuit,john flynn medical centre,camira,3172,nsw,19041113,8734967 +rec-982-dup-0,,allard,26,burnie north west private hospital,dyring place,south perth,4852,nsw,19491011,9472794 +rec-951-dup-0,juliana,akkermans,24,northwood park,jondol place,holswothy,4068,nsw,19970330,5071393 +rec-4677-dup-0,tate,spagnoletti,29,,tullatoola,wangaartta,4520,qld,19200505,7390367 +rec-798-dup-0,henrya,ryan,22,marconi crescent,,tea tree gully,4019,qld,19930928,6244854 +rec-1227-dup-0,robert,carbone,64,james smith circuit,galloway,st kilda east,5038,qld,19141107,6153085 +rec-2509-dup-0,joshu a,browne,28,paul coe vrescent,the pinacle,williajstown,2271,vic,19091031,4631516 +rec-462-dup-0,sienna,rya,3,laycock place,,lalor,4702,nsw,19680321,4809923 +rec-1091-dup-0,mikazea,stanfoeld,16,giltin an place,stefonair,maryborough,4816,qld,19911222,5549486 +rec-2607-dup-0,samantha,leong,124,,tilburoo,wantirna,3046,qld,19670430,2292707 +rec-144-dup-0,olivia,whitw,2,sturt avenue,berkeleyvlge,ringwood,5016,wa,19941026,7159814 +rec-1427-dup-0,brigette,rankine,68,chewings street,gostwyck,west lakes,2229,qld,19750725,5214389 +rec-4-dup-0,ja yde,crouch,42,westo atreet,waimaru,niagara park,2119,wa,19250406,8892697 +rec-4149-dup-0,chevonne,montakvo,42,baskerville street,kangaro o grnd,ventnor,2310,vic,19620511,7935536 +rec-2942-dup-0,mikayla,nguyen,11,jaunceyucourt,karinyag ardns,helidon,5197,nsw,19030122,3964863 +rec-1356-dup-0,rory,jehle,125,companion crescent,brinjrarmy,cromer,2340,nsw,19730227,1533301 +rec-2764-dup-0,emiily,green,31,applgelen,julius street,mount colah,2290,vic,19310530,7373124 +rec-1027-dup-0,luke,hursey,23,turriffstreet,inishmore,port franklin,4017,lqd,19220923,1219514 +rec-1308-dup-0,mitchell,crossman,75,wakefiel d garden,fairburn park,charlestown,3995,vic,19751101,4081790 +rec-4803-dup-0,annabelle,romeyn,18,ferrier place,sec 247,bray prak,6155,vic,19350129,2470380 +rec-4357-dup-0,ethan,coleman,64,ragless circuit,,hindmarsd west,4701,nsw,19650701,9807949 +rec-876-dup-0,sokic,benjamin,21,must circuit,,sunshine,2153,vic,19001207,2513200 +rec-3085-dup-0,jasper,tsialafos,,stutchburh street,st framcis vlge,cook,2233,nsw,19220428,8232480 +rec-1561-dup-0,roberta,bishop,1,curtis place,,balaklava,3394,nsw,19261110,6627562 +rec-3813-dup-0,amy,masno,279,casuarina street,memorial hoyspital,bundaberg,3056,vix,19211126,4368305 +rec-3459-dup-0,madison,chandlder,29,luckman place,hd ticmera,pearl beach,2133,nsw,19930607,8841314 +rec-1617-dup-0,flynn,mason,11,wellshot,namatjira drive,blackburn north,2576,wa,19110824,2236689 +rec-3721-dup-0,gemaey,meadowts,42,alarmon crescent,kalang,nemingha,3146,vic,19230420,5029065 +rec-4365-dup-0,georgia,glover-smith,34,howse street,,rab,5340,wa,19790813,8934327 +rec-743-dup-0,daniel,white,1,albermarke place,summer hill,brierfield,3810,sa,19870703,8258879 +rec-3514-dup-0,tanyshah,wiemann,68,anne place,fl t 167,strathalbyn,3337,nsw,19640904,8798582 +rec-3996-dup-0,georgia,petersen,20,temperley s treet,tieve tara,toowong,3715,qld,19700324,4385775 +rec-2697-dup-0,joshua,lowe,15,patton place,redlands,tarcutta,4705,sa,19120201,7132911 +rec-4569-dup-0,cheree,bowerman,55,tregearc lose,northwood park,st peters,3191,qld,19091213,3770636 +rec-4478-dup-0,joel,reif,7,pearsonstreet,lytton,floreat,3153,qld,19760904,1523622 +rec-1822-dup-0,maddison,fullgraxbe,44,hardey place,allunwga,forest glen,5070,qld,19110327,3898794 +rec-282-dup-0,flynn,van heythuysen,2,shepherddon place,nunkeri,rose bay,2122,nsw,19780418,3254370 +rec-4654-dup-0,stroe h,luek,18,narryer close,mylandra,parkside,4125,tas,19180113,2662103 +rec-819-dup-0,jessiac,bastiaans,130,beazley crescent,,ingleburn,3029,qld,19270912,7965000 +rec-1425-dup-0,alysha,reid,747,clive steel e avenue,townhouse 5,kiama heights,3710,vic,19940904,7294389 +rec-447-dup-0,april,mcgrgeor,4,launcesto n street,hawkins masonic vlge,kardinmya,2207,wa,19541028,8809810 +rec-3518-dup-0,alexander,priedt,41,manu place,,bundeena,4701,qld,19420417,9205694 +rec-1576-dup-0,luke,paterson,80,rischbieth crescent,rooganore,spearwood,4035,vic,19120208,7700965 +rec-4695-dup-0,christian,dietrich,27,lindrum crescent,matilda blue,rostevor,4560,wa,19170307,3108840 +rec-2095-dup-0,bwn,armiento,40,burnell place,john flynn hospital,fairlight,3630,qld,,8511174 +rec-1050-dup-0,nikki,neigk,180,balfourcrescent,brentwood village,charlestown,2228,wa,19840720,7106885 +rec-4765-dup-0,riley,godfrey,300,clift ck,the lodge,oakwood,3108,nsw,19451121,3493339 +rec-4818-dup-0,alexandra,yiannoulis,159,archdall street,tall ipnes,rowville,3284,vic,19790913,7551259 +rec-3023-dup-0,bridget,hand,210,bunton place,flt 1 0,parkinson,2705,nsw,19391228,3815665 +rec-4106-dup-0,xanthe,ryan,1,cochrane fcescent,homevale,aldinga beach,3941,nsw,19030508,7629205 +rec-2191-dup-0,joshua,arribas,30,nicholas street,dangaroo park,kirwan,4086,nt,19800502,7705455 +rec-4282-dup-0,maxin,jolrly,8,huxley place,,mooloolaba,2220,wa,19330915,7131922 +rec-1551-dup-0,lucy,rees,78,galveston,badenoch crescent,macquarie fields,3076,nsw,19230613,8204200 +rec-3934-dup-0,kai,rachwal,128,ardlethan street,glenvaon,edgewater,4217,wa,19100330,5698267 +rec-3211-dup-0,isaac,loew,3,hemmings crescent,timber haven,williamstown,2380,vic,19880722,2762848 +rec-3230-dup-0,jacqueline,macphail,65,maddigan hstreet,oxonia,canterbry,2611,wa,19350403,8001638 +rec-1667-dup-0,george,robert,28,,nio ka,picton,4814,nsw,19400601,4149373 +rec-83-dup-0,joshua,stalney,1,weddin circuit,rocklands,cabraatta,7320,nsw,19381229,5425400 +rec-3079-dup-0,benjamin,donaldson,34,dunoon street,westwood homestead,st algans,2611,nsw,19331111,2281465 +rec-3911-dup-0,ruby,warrior,5,ironbarkcrescent,margaret river carvn park,penshurst,3075,vic,19550812,5870334 +rec-2506-dup-0,teagan,galbraith,17,preston street,wollartukkee,forest hill,4413,sa,19410923,2436763 +rec-801-dup-0,chelsea,mccarthy,17,la perouse street,arcaida,ballarat,4007,nsw,19921130,4620249 +rec-268-dup-0,phoenix,mason,355,fawkner street,di aboo,,6258,sa,19630713,2078364 +rec-113-dup-0,laznger,gabrielle,526,delegateqstreet,oak valley,paddington,3910,wa,19800810,2343036 +rec-1132-dup-0,brianna,dixon,70,sidaway street,,carlingford,5097,qdl,19780707,3396896 +rec-2386-dup-0,mitchell,hunting,14,catchpole qtreet,windara,,3155,qld,19050619,4197943 +rec-2487-dup-0,joanna,coulson,289,bageplace,,wantirna,2224,qld,19530111,6565352 +rec-580-dup-0,natalia,mccatfhy,10,vogelsnag place,,blair athol,6018,act,19841123,4528780 +rec-515-dup-0,ruby,bellchambers,298,winnecke street,siesta caravn park,mosman,2330,tas,,2384529 +rec-4317-dup-0,scot,buterfeld,116,crozier circuit,uc-dai-oi,noble park,2231,qld,19230731,9102056 +rec-2394-dup-0,alisa,kaderes,37,jaeger circuit,loc n 8,park hilme,4514,vic,19020714,2567085 +rec-1327-dup-0,emma,copperstone,5,decima circuit,crwer,avoca north,2166,nsw,19451208,1536837 +rec-1172-dup-0,eleanor,luckjan,34,banks street,st francis village,aspendale gardens,4361,wa,19920704,2330095 +rec-3560-dup-0,tai,matthews,3,norman fisher circuit,,bracknell,2258,qld,19120506,7535799 +rec-2755-dup-0,maczkowiack,robeft,40,broadbent street,jandera douth,port lincoln,6153,nsw,19030102,4106094 +rec-2107-dup-0,harrison,snellin g,50,sproule circuit,yalkara,emerald,4216,nsw,19410412,1348871 +rec-3685-dup-0,benjamin,lowe,45,macrossan crescent,,kingdton,6075,nsw,19250611,5513136 +rec-4856-dup-0,jack,wang,,elliott street,stoney creek,norw ood,2147,nsw,19970913,5004938 +rec-4500-dup-0,zali,mcgregor,25,goulburn street,,richlands,4307,,19490225,9800116 +rec-3694-dup-0,kylee,pennell,1,,,,4570,sa,19000320,4020041 +rec-1114-dup-0,max,stanley,20,whitfordi place,,manly ale,3095,nsw,19870211,8658470 +rec-86-dup-0,abbie,son,17,sharwood ccescent,wayside,lakemba,2866,ss,19409716,3651118 +rec-1753-dup-0,brianna,ranson,143,scott street,blue hills,mitcham,4261,vic,19480409,2774725 +rec-655-dup-0,keele y,heron,60,krichaufg street,,bonnyrigg,3012,nsw,19191230,5319794 +rec-2791-dup-0,hawes,ella,51,stubbs crescent,,cloveilly,3195,nsw,19100115,3998567 +rec-1276-dup-0,abbey,parfilo,13,chandler street,,albany creek,2065,vic,19891112,8843836 +rec-255-dup-0,dante,campbell,5,vaughan garden,kenleyu lodge,deer park,2572,vic,19641106,7782097 +rec-1385-dup-0,elton,bishop,10,french street,,orange,3223,nt,,1324854 +rec-1005-dup-0,micah,greehn,26,blakely row,kelanna,harbord,4502,wa,19911228,2687580 +rec-4572-dup-0,lachlan,red,20,starkestreet,busbey's flat,caulfield,2611,vic,19600906,3614628 +rec-4510-dup-0,noah,whiet,804,caladenia street,sec 437,molong,2119,wa,19041018,9864936 +rec-2251-dup-0,joshua,crouch,94,forbes street,,johnsonville,2327,sa,19700216,4813329 +rec-3901-dup-0,shane,goldsworthy,9,starritt place,woodsong,new town,6052,wa,19111223,5363583 +rec-4870-dup-0,carlin,munforti,46,von guerard crescent,,clarendon,2140,nsw,19241024,1512461 +rec-179-dup-0,,braithwaite,29,tweed p lace,brileen,cabramatta,5051,vic,19740815,8052512 +rec-4502-dup-0,scott,rudd,3,saunders street,,toowoomba,2617,nsw,19600086,4857758 +rec-2012-dup-0,riley,whie,22,william husdon crescent,brentwood vlge,burnside,3064,qld,19941028,3083448 +rec-3715-dup-0,jessica,dixon,161,fred johns crescent,,eaglehawk,3556,qld,19281113,6245244 +rec-4442-dup-0,kadin,crosswell,38,,karobean,leongatha south,2070,vic,19410715,4079644 +rec-4672-dup-0,timothy,bishop,8,zox circuit,,lismore,2168,vic,19771008,3069847 +rec-2047-dup-0,belinda,de gennaro,178,sturdee crescent,birks h arbour,orange,6030,nsw,19210814,9392022 +rec-3581-dup-0,hoover,ethan,151,monaro vrescent,tiverton,yarra junction,2219,nsw,19920703,8513913 +rec-509-dup-0,benjamin,green,12,woolner circuit,mirani,reynella,2905,sa,,8195933 +rec-1430-dup-0,willow,gowling,39,hannaford street,the bri ar patch,moama,4579,vic,19690421,9703540 +rec-661-dup-0,caitln,portlock,19,tompson street,cherrydell,rochester,4503,act,19110812,1549588 +rec-468-dup-0,connor,arda,35,,summervale,port macquarie,2530,wa,19750417,9721130 +rec-896-dup-0,eleanor,klemm,110,carrodus street,henry kemba ll village,dareton,2122,vic,19771109,9856779 +rec-1984-dup-0,travis,whale,2,sutton place,trumano,terrigal,3976,sa,19320724,1928625 +rec-3394-dup-0,finlay,emiily,20,temperley street,lincoln close,bellevue hill,3400,qld,19000801,1739435 +rec-545-dup-0,tara,plovanic,25,hobler place,port hills,kalamvnda,2747,vic,19600401,4207452 +rec-2999-dup-0,paris,negrein,30,stapylton street,treleen,coleambally,2145,qld,19620726,4121618 +rec-1941-dup-0,,campbell,282,osburndrive,white patch,carralra,6030,vic,,2172403 +rec-4787-dup-0,vanessa,morrison,16,meehan g arden,glebe retirem ent villa,condell park,5113,nsw,19951015,6047960 +rec-1859-dup-0,angie,arbuckle,214,mcinnes street,,ballarat,4808,nsw,19890525,7610312 +rec-2548-dup-0,portia,bandte,5,namatjira drive,willyaroo street,rostrevor,3084,wa,19800709,3676482 +rec-3769-dup-0,herbert,jasper,8,werriwa crescent,lyndilan,mill park,6163,sa,19640905,3048660 +rec-45-dup-0,adam,coleman,14,ewart sdreet,camrai village,springfield,2795,nsw,19491208,6543835 +rec-2880-dup-0,paterson,emiily,7,gruner street,plat ina,seaforth,5157,vic,19840318,7177837 +rec-27-dup-0,angelina,campbell,190,jackie howe crescent,bugoren,woorim,6352,nsw,19531108,8948230 +rec-1441-dup-0,harry,blake,36,cowlishaw street,sommerse tpark,kahibah,3073,qld,19400401,2348791 +rec-323-dup-0,peta,tarsissi,,rivett srteet,glen alvie rsd,kendall,2328,nsw,19641102,1498722 +rec-4766-dup-0,samara,campbell,,packham place,kokoda hostel,burpenkgary,3136,wa,19010604,6449470 +rec-2242-dup-0,michael,shepherd,39,pinkerton c ircuit,millwood,camira,3378,nsw,19301008,3537158 +rec-3168-dup-0,hayley,bishop,9,lindsaystreet,lindis faime,blackmans bay,4163,wa,19210517,3857962 +rec-2908-dup-0,michael,plessnitzer,26,william webbodrive,rockview,cowra,3023,nsw,19800518,3756443 +rec-737-dup-0,hannah,liaudinskas,15,hopmanpoace,mt pleasant,orange,2829,sa,19130526,5819558 +rec-1357-dup-0,tiarna,lapienis,47,hunter street,cooralook,ormond,6027,nsw,19971203,5568749 +rec-3384-dup-0,george,sheriff,25,hemmings crescent,melodyc pttage,geraldton,4121,qld,19650627,2285850 +rec-2488-dup-0,bree,boase,48,lyndon street,,east melbourne,2087,nsw,19210614,2185538 +rec-2838-dup-0,jessxia,wiseman,23,spowers circuit,woodbine homestead,carnegie,2018,nsw,19641123,4608861 +rec-4082-dup-0,caitlin,dominey,2,,kilbutnie,plainby,6018,nsw,19761113,3992744 +rec-1641-dup-0,catherine,dolzan,9,bakersc reek,burrinjucr crescent,west kempsey,2615,nsw,19441222,8238507 +rec-3682-dup-0,amy,drzezdzon,11,magennis place,se 161,ashford,6100,vic,19000219,4126935 +rec-3843-dup-0,talia,brable,5,wattle street,taree cacavn park,northb ondi,5074,vic,19950423,2565238 +rec-1485-dup-0,joshua,lock,31,,statio r road,logan reserve,6163,vic,19490619,3058210 +rec-4666-dup-0,john-paul,pra,22,david street,greater ce ss vill,croydon north,4737,wa,19800811,8703902 +rec-2638-dup-0,jordan,mcmullen,4,albermarel place,,northmead,3579,,19291225,5611622 +rec-4376-dup-0,liam,drougas,29,collins place,moonylora,oakville,2560,qld,19670112,8993502 +rec-2643-dup-0,jayde,enebxerg,44,donohoe p lace,professionalcentre,kahibah,6163,nsw,19750318,5568018 +rec-3393-dup-0,,reidz,46,dooring street,windalea,dandeno ng north,3582,nsw,19130312,1322845 +rec-4155-dup-0,ella,wedmaier,7,duffystreet,glenpora,eulxo,2020,qld,19410630,4581426 +rec-2388-dup-0,,milla,1,bandulla street,sherwood,forcett,3463,tas,19580204,7520191 +rec-2302-dup-0,lachlan,pacey,15,wilshire street,cypress mgarden,wendouree,2770,,19711111,4723081 +rec-3398-dup-0,kelsey,dearing,25,,bindaree,clare,1409,sa,19400117,1841588 +rec-4275-dup-0,isobel,burnell,4,heidelb erg street,cinema cdntre bldg,stretton,5680,vic,19900603,1027213 +rec-4757-dup-0,dilloqn,cranefield,9,loch street,rowethorpe d1,lutwyche,2650,qld,19601109,7417124 +rec-2101-dup-0,herbert,tahlia,28,dolling crescent,curra apark,kingston beach,3840,nt,19790724,6559247 +rec-1493-dup-0,ebonjie,quiton,143,,warialfa,whitfiold,3910,qld,19781228,7282886 +rec-3790-dup-0,melind,tuckwell,8,stradbroke street,cherry tree,rushworth,2219,qld,19961127,5540986 +rec-2682-dup-0,taylor,bevis,20,spofforth street,,burwood,3177,nsw,19270430,6848520 +rec-4988-dup-0,seth,tauj,17,herschellcircuit,belvedere,st kila,5201,qld,19490904,5547361 +rec-7-dup-0,angus,silvestro,41,nott street,tathra river est,middleton beach,3137,nsw,19560720,9873948 +rec-1298-dup-0,tali ah,ryavn,18,hopetoun circuit,the wiklows,shorewell park,3805,vic,19950105,3100732 +rec-2009-dup-0,george,meaney,164,elder stqeet,,st albans,4060,vic,19320703,9691332 +rec-3310-dup-0,tristan,lombrdi,3,morduant place,duck creek,kingaroy,4171,tas,19280422,8584160 +rec-2781-dup-0,emma,madigan,15,blackwellcircuit,tintagel,dianella,0820,sa,19871218,5096835 +rec-4335-dup-0,elana,wiechce,11,belconnebh way,upper ross medical centre,torquay,4077,sa,19190515,3124171 +rec-3397-dup-0,indiana,goode,4,galibal street,antanoff ' south,east maitland,3183,vic,19420313,5641889 +rec-1141-dup-0,jakc,carucro,01,kirkland circuit,willow lodge,blackburt north,6275,vic,19000604,8374407 +rec-4528-dup-0,jean-claude,ryan,4,gleddenstreet,henry kendall bayside,swan hill,3736,nsw,19150420,2261900 +rec-4627-dup-0,juliana,watkin,18,feint street,laurapengilly wing,doubleview,4032,qld,19710311,8665714 +rec-1119-dup-0,rachle,georfe,9,mearesoplace,brentwood village,tuar thill,6008,nsw,19910224,4083414 +rec-2165-dup-0,matthews,holly,5,bingley crescent,strathlaynne,beaudesert,6158,nsw,19610114,5757476 +rec-250-dup-0,lauren,shack,345,rushbroo k circuit,research station,warrandyte,4740,tas,19590103,1987058 +rec-1230-dup-0,kate,tantschev,99,knox street,fronda,,5148,qld,19870422,6536232 +rec-4038-dup-0,nathan,cannelk,13,theodore street,iona d wons,emerald,2570,nsw,19000823,6294140 +rec-3430-dup-0,sophie,thredgold,35,bramble street,tigers hill,,6210,sa,19830705,8974658 +rec-3001-dup-0,joel,badegr,47,blamey crescent,brookfields,broadford,4807,qld,19791106,2164581 +rec-1304-dup-0,sarah,paterson,57,ginganastreet,st francus village,williamstown,2784,wa,19011215,6278915 +rec-4952-dup-0,madalyn,korfia,114,vansittart crescent,bombowlee,cherrybrook,2174,qld,19690312,4293980 +rec-4455-dup-0,kaela,green,,tytherleig street,flt 1 0,casino,4670,vic,19620825,5598767 +rec-4270-dup-0,finlay,beghany,353,haighpark,capella crescent,broken hill,2111,vic,19660601,3594609 +rec-4713-dup-0,channing,hakq,8,kevin street,sec 1,bundaberg,6405,wa,19190425,9248677 +rec-1711-dup-0,andrew,wang,9,barrington crescent,summe rhill,orford,2795,nsw,19260203,4852197 +rec-283-dup-0,jenna,shjw,21,fincham crescent,,thornleigh,3111,vic,19060322,7681478 +rec-4165-dup-0,,araujo,225,nepean place,kinross,lake cathie,2302,vic,19140124,5500784 +rec-2086-dup-0,chelesa,sitarenos,2,chevalley loop,argyle,leichhardt,2611,qld,19470522,3656932 +rec-4956-dup-0,kyle,grbovac,51,sutton cottage,alexander macki e circuit,franks ton,3094,vic,19821227,7927536 +rec-3442-dup-0,willaim,frahn,5,haystack crescent,,calista,4740,nsw,19500602,6417261 +rec-3883-dup-0,amber,webb,1,biddlecomb street,,northbridge,3777,qld,19920815,2423271 +rec-4186-dup-0,georgia,beams,12,,sunnybank garden,rochedale south,2116,vic,19701121,4356806 +rec-1294-dup-0,riddell,jared,346,hawkesburycrescent,pine tree,berkeley vale,3015,nsw,19430121,2944608 +rec-4551-dup-0,joshua,stubx,50,bimbiangc rescent,rosetta ivllage,holswirthy,3071,nsw,19580212,4826701 +rec-1273-dup-0,kan,markijevic,15,maltbycricuit,,briar hill,2452,nsw,19310315,5758876 +rec-1405-dup-0,sophue,tertipis,23,walker cr escent,furlough house,brighton-le-sands,2304,nsw,19490918,7755180 +rec-3210-dup-0,zachary,croker,27,guthridg ecrescent,,rydd,3143,nsw,19630415,9034657 +rec-4350-dup-0,aneka,milburn,103,wilkins street,clisbyfarm,kuraby,2715,qld,19171108,4533360 +rec-4732-dup-0,tillr,robert,14,parfitt crscent,mariner views,ringwood,2540,wa,19590714,1579290 +rec-1809-dup-0,sophie,ballantyne,32,solomon crescent,vill a 3,whittington,3223,nsw,19111219,8261379 +rec-973-dup-0,mackenzie,reid,37,ebdenstreet,unt 2,malabar,2233,vic,19550203,8090155 +rec-2644-dup-0,sean,bammant,108,yarra s treet,ulva,yorkeys knob,2145,wa,19650509,6208046 +rec-4836-dup-0,maddison,weidenhofer,28,dinnisonc ircuit,,bray park,2584,qld,19200802,6273334 +rec-14-dup-0,garnett,raquel,60,tepper circuit,,balwyn north,2025,wa,19280505,9109106 +rec-3615-dup-0,alessandra,van groesen,,arthurcircle,hse 4,o'connor,3040,sa,,5885340 +rec-4006-dup-0,mackezi,dogg,30,walkerceecsent,,berwick,2259,vic,19710709,9203314 +rec-2005-dup-0,finn,eckersley-maslin,2,ebden sgreet,kondalilla,harden,6564,nsw,19360522,9218750 +rec-3445-dup-0,joshau,whitue,3,,ahwahnee,narrog in,2280,nsw,19611206,2059387 +rec-2283-dup-0,madeleine,nevin,85,majurs road,rocklznds,st kilda east,2092,sa,19230620,3536031 +rec-3155-dup-0,benjamin,campbell,159,corrigan yplace,,thornbury,2300,nsw,19870227,4459447 +rec-1238-dup-0,joel,londesborough,108,arthur cricle,vlla 18 pacifi bay resort,kings park,5606,sa,19480110,6254331 +rec-2793-dup-0,braiden,parr,15,raiwalla court,st francisivillage,kriwan,2444,vic,19960327,7031748 +rec-542-dup-0,clarke,tiahnee,3,golden grove,,dural,7000,nsw,19790215,9714630 +rec-3844-dup-0,luke,wotton,36,gleesonnplace,,wesltake,3198,vci,19780117,6707270 +rec-3552-dup-0,bella,,90,schonell circuit,greenhills,magill,3981,vic,19620712,7533159 +rec-3754-dup-0,joshua,moody,15,el-woodaro,glover street,warren,2304,qld,19580620,9224762 +rec-4814-dup-0,ben,conick,,marsden rtreet,,page,3108,nsw,19760130,5241188 +rec-4348-dup-0,,neville,71,pleasance place,macarthur place,wanniassa,3875,qld,19730731,5739885 +rec-699-dup-0,felicity,,15,abercrombie circuit,beg oa,neville,6726,nsw,19421105,2382886 +rec-2978-dup-0,natalia,bajic,19,delegate street,corcoran,jesmond,3977,wa,19370101,8300817 +rec-407-dup-0,riley,ree,9,archibald street,wisperin gpines,coonabarabran,5162,wa,19700922,4932145 +rec-663-dup-0,dean,wiseman,27,currongstreet,palm garden villas,croaer,4305,qld,19740808,1613598 +rec-1154-dup-0,gracnie,crook,7,macalister crescent,grant patch,east prseton,4198,nsw,19360323,1096576 +rec-554-dup-0,domenique,alves,4,croton street,,nome,7017,qld,19490813,2034593 +rec-2395-dup-0,jacina,frencham,12,bean crescent,barwon station,narellan,3074,qld,,3787817 +rec-531-dup-0,kyle,rudd,,atherto h street,glenmore,muttama,5158,nt,19590521,2268332 +rec-1893-dup-0,creagh,sophie,39,maplestnoe place,medicalc entre,mansfield,5108,vic,19221207,5082702 +rec-813-dup-0,tanar,huxley,,ashcroft crescent,kilfescle,bray aprk,2064,vic,19700512,5171988 +rec-1416-dup-0,isabella,berresford,21,parraweena,norfolk street,paddington,7330,nsw,19860819,4139219 +rec-2405-dup-0,makenzli,white,12,bimberi crescent,,seymour,2061,wa,19350712,6816535 +rec-1715-dup-0,drayson,kylke,509,schlich street,st francis vlge,bittern,3150,qld,19801205,1349437 +rec-37-dup-0,lachlan-john,snelling,20,summerville crescent,,maldon,3206,vic,19660114,7931741 +rec-3184-dup-0,jarld,felegpa,63,badimara street,,frenchs f orest,4821,nsw,19610421,8535978 +rec-1699-dup-0,brock,kate,12,kareelahv ista,pine hill,yaroowba,4740,vic,19130707,2213154 +rec-219-dup-0,hugh,dorsey,25,sid barnes ncrescent,rowethorpe,werrington,2144,qld,19000625,5695716 +rec-552-dup-0,cameron,wilkins,528,bruxner close,ivenutre,albury,4607,sa,19580516,1334190 +rec-3128-dup-0,jaius,compton,92,huelin circuit,mamaergu,boyne island,2760,wa,19960806,1381082 +rec-1239-dup-0,konstantinos,white,13,lascelles circuit,,crookwell,2211,wa,19440706,5173965 +rec-3718-dup-0,hannah,white,2,gallagher xtreet,fairholme,aspendale gardens,2580,nsw,19840119,9007134 +rec-1989-dup-0,jordan,tuckwell,23,harricks xrescent,holloway haven,atherton,4560,vic,19730908,6240898 +rec-4164-dup-0,jayde,lazar off,36,castleton crescent,morayfiel d exchange,lindfield,4311,nsw,19350424,7611601 +rec-741-dup-0,hannah,candida,7,santalum street,moorabee,,2030,vic,19210519,9787204 +rec-1648-dup-0,lilq,hick,189,atherton street,goolman street,wangiwangi,2212,nsw,19260617,8984671 +rec-2551-dup-0,nec,ryan,3,carpenter close,,cowell,2010,vic,19020623,1816092 +rec-4112-dup-0,lachlan,bottroff,92,,quandilala,brone,4670,nsw,19641111,4134354 +rec-1823-dup-0,alexandra,zilm,8,marungal avenue,dykehead,toormuna,3052,nsw,19390626,2961711 +rec-3188-dup-0,jake,alderson,,eggleston crescent,west-view,granville,5070,nsw,19460415,6446268 +rec-794-dup-0,kristen,godfrey,48,dromard,cussen street,bray park,4156,sa,19700425,5874139 +rec-4049-dup-0,laneau,shane,5,miller street,fenne r hall,richlands,2640,vic,19430101,4023866 +rec-4854-dup-0,michael,daech,55,batman street,rockview,salisbury east,3523,nsw,19130907,9846815 +rec-388-dup-0,whiteley,ewa n,23,bennelong cescent,roskhikl,glen innes,3171,nsw,19840025,1326266 +rec-1200-dup-0,sara,bibrlwicz,46,kingscote crescent,rowetho rpe,smithsxbeach,2026,nsw,19120602,4090488 +rec-288-dup-0,georgia,browne,19,arthurcircle,aminya hmes,murrabit,2010,vic,19960923,9940324 +rec-3389-dup-0,naomi,boyes,4,,wattle place,kingsford,5062,vic,19760522,6564025 +rec-2940-dup-0,samantha,harrington,29,beaver place,,toukleey,6751,vic,19471114,9485434 +rec-4843-dup-0,thomas,butt,11,freeling crescent,mylo house hostel,port fairy,2486,nsw,19311128,4301794 +rec-30-dup-0,xavier,campbell,9,norton street,pine casmp,coniston,5092,nsw,19640316,9178267 +rec-1374-dup-0,lachlan,balasubramaniam,26,mackinolty street,balmora lgarden,scarnorough,2388,nsw,19731007,1798069 +rec-2881-dup-0,emilily,paterson,9,wiburd srteet,parraweena,colac,2021,qld,19881213,6732942 +rec-4893-dup-0,harry,gaden,25,,musgrave house,surry ills,3216,vic,19770407,5999211 +rec-4718-dup-0,tazta,hem,3,birniep lace,strathela,burwood,6330,nsw,19080318,6896187 +rec-1257-dup-0,chelsea,nguyen,26,namadgi circuit,villa74 village glen,anglesea,6025,nsw,19230828,3467697 +rec-1384-dup-0,ruby,mason,24,cruikshank street,yammacoona,tarragindi,5606,vic,19090627,4941274 +rec-2299-dup-0,joshua,gaskin,61,haystack crescent,gemmav,koroit,6233,vic,19590425,3676871 +rec-1343-dup-0,jazz,campell,9,newbery crescent,cullingaepark,fairlight,3850,qld,19391218,7149087 +rec-539-dup-0,macy,donalwson,,laseron place,barossa village,altona meadows,2760,vic,,6788131 +rec-1918-dup-0,ab bey,milburn,18,dixson circuit,the willows,roseb ud,5057,qld,19631114,4451215 +rec-408-dup-0,rees,charles,19,hobbyzplace,locn 2557 talland,orange,6210,vic,19710428,6849799 +rec-2074-dup-0,mitchell,dent,,partridge street,elizabeth residential village,ballarat,2285,vic,19900531,1162702 +rec-1829-dup-0,lil y,danisewitsch,1,,bendigo retirement village,knoxfueld,3816,vic,19660727,7147139 +rec-2957-dup-0,bradley,shepherd,71,gull cottage,kilgour place,smithfield,4078,act,19160301,1369189 +rec-2606-dup-0,emiily,benjamin,8,holmans treet,kersey' south,coutts crossing,2278,vic,19490214,7996561 +rec-1274-dup-0,,mason,19,sheaffe street,,burwood,2507,nsw,19461025,4113226 +rec-3289-dup-0,megan,jessup,5,wyatt steet,beachfront c aravan park,ringwood,3225,nsw,19010928,9738709 +rec-4898-dup-0,aidan,dohse,14,dilboong wplace,sunningdale farm,hurstbridge,4510,tas,19191229,4932448 +rec-1407-dup-0,nicholas,huxley,,blackbutt street,burnside,unanderra,2213,vic,19761203,8423125 +rec-4020-dup-0,callum,wheatley,3,john cleland crescent,murrong,florey,2063,nsw,19651106,9895199 +rec-2508-dup-0,sedn,lgke,30,glossop crescent,craigston,megan,4812,vic,19980906,7108946 +rec-4212-dup-0,ryan,sherrington,17,stopford crescent,lvel 1280,caulfield north,4715,qld,19680507,8315298 +rec-104-dup-0,danilela,steinbacher,43,brigden crescent,thevillage condo 7,bridgewater,6110,vid,19360208,7992465 +rec-4015-dup-0,lily,poskey,38,moore o lace,kenbar,lower templestowe,2474,nsw,19210315,8556979 +rec-2125-dup-0,chloe,whitie,22,macgregot street,merimaja,bunbury,2782,nsw,19330113,6064969 +rec-3323-dup-0,bailee,vearifng,18,bavin atreet,sun city tourist park,safety beach,6076,nsw,19741208,4201844 +rec-1704-dup-0,pegg,bradley,1,gaskplace,swanleigh,surry hills,5600,qld,19190625,8214409 +rec-4697-dup-0,cooper,mcneiwll,119,the sandys,maidment place,dungog,5075,nsw,19080127,2706283 +rec-2952-dup-0,,monda,54,burrinjuck crescent,,aubrun,3345,nsw,19041125,9464025 +rec-589-dup-0,bennier,taylor-saige,7,ruthven street,,chincihlla,5732,qld,19910528,7222769 +rec-4663-dup-0,ellouise,domnto,36,leach street,plain view,frankston,6062,nsw,19141125,2822912 +rec-3614-dup-0,zachary,thurlow,132,eldridgfestreet,trfeusis,southern cross,4051,nsw,19230305,5024661 +rec-1378-dup-0,alaiyah,cowle,132,burbidge crescent,vali czre,pomborneit,3824,nsw,19801112,5015237 +rec-4392-dup-0,lochlano,reifferscheidt,626,carrington road,haig hpark,bonny hills,4172,vic,19020119,6477624 +rec-3399-dup-0,toby,de landre,15,quandualla,ulm steeet,ashwood,2141,vic,19380511,2977480 +rec-71-dup-0,connor,tromp,8,eildonplace,willtarny,east maitland,7440,qld,19280129,8096262 +rec-3956-dup-0,teneille,matthews,13,bugden a venue,civic centre,jesmonc,6026,qld,19540122,7584568 +rec-1978-dup-0,emiily,millar,80,river street,canberra hse,nunawading,3340,vic,19380318,2340041 +rec-2130-dup-0,isobel,dreckow,10,landor p lace,harkyn,old toon gabbie,2650,qld,19101019,2584672 +rec-4563-dup-0,zacary,white,54,shain place,,glenwood,3840,vic,19111109,7091861 +rec-923-dup-0,elzia,koziol,183,wattle street,blueberr hill,blacktown,6826,nsw,19940208,8842130 +rec-4075-dup-0,rhys,dugdale,9,port jackson circuit,ainslieh ouse,rydge,7009,nsw,19010725,5007081 +rec-3086-dup-0,blakeston,lock,59,bonnor close,,ment one,7140,wa,19590930,6335558 +rec-1044-dup-0,riley,lamprey,22,embleystreet,,hinchinbrook,3199,vic,19851029,8710851 +rec-1362-dup-0,,collibnson,8,parrabel place,fraser lodge,elwozoc,2420,vic,19100819,5602774 +rec-1911-dup-0,olivia,gully,3,cockbur nstreet,bool igal,,2163,qdl,19150112,1992595 +rec-1075-dup-0,geogia,simmovnds,16,hurley street,iowana,mittagong,2100,nsw,19230413,5714791 +rec-3709-dup-0,william,reid,18,martin utreet,australiaharcade,smiths lake,2010,vic,19690624,7251376 +rec-3414-dup-0,alysha,alderman,28,benson crescent,,mill park,2261,nsw,19700704,1772593 +rec-1194-dup-0,gaden,daniel,21,,solander centre,duntroon,6056,qld,19840606,3484120 +rec-249-dup-0,lachlan,shephaerd,1,grainger circuit,willandra,adaminaby,7250,nsw,19080122,3139543 +rec-1910-dup-0,campbelhl,jeffries,12,calder crescent,yar rabee,abbotsord,4650,nsw,19810621,9991473 +rec-82-dup-0,alice,godfrey,2919,florence taylor street,,kemosye,2761,vic,19910330,3541229 +rec-3886-dup-0,joshus,mason,47,crisp circuit,deergarden caravn park,chinchilla,3799,vic,19390402,8753102 +rec-2675-dup-0,kobe,buckinghan,47,wrixon smtreet,the willows,kariong,3375,nsw,19481019,9604781 +rec-2174-dup-0,abbey,grewn,6,aspinall street,roseda le,mannum,3012,vic,19300314,5453075 +rec-4319-dup-0,hannah,bansemer,3,owen cre scent,glynstan,lemnos,3065,nsw,19380604,8798025 +rec-65-dup-0,benjamin,moody,43,fernyhough crescent,huongold,port augusta,3192,vic,19180612,4887764 +rec-344-dup-0,mitchell,lex,8,dexter street,blythlands,upper coomera,2011,nsw,19430227,9870170 +rec-3684-dup-0,luke,boyle,1525,fawkne rstreet,,roxburgh park,2343,nsw,19701125,2420976 +rec-3551-dup-0,talyena,richnond,25,hopetoun circuit,tricorne (cnr scone r road,south melbourne,0355,nsw,19621215,1051084 +rec-664-dup-0,tyron,mahon,45,albermarl place,ulinga,colo vale,7520,nsw,19470129,8336319 +rec-322-dup-0,abya,bellchambers,268,weavers crescent,yenda units,lake munmorah,3094,qld,19541018,1627605 +rec-377-dup-0,joselyn,moody,92,bromell circuit,clover dene,ashfield,2285,sa,19380115,4236077 +rec-1299-dup-0,dylan,patafta,17,goldner ircuit,kilnsey,auburn,3138,vic,19100402,7951303 +rec-2983-dup-0,luc,morriaon,3,starke street,sheeo station,petersham,5020,nsw,19271205,8707221 +rec-4959-dup-0,jessica,kusdek,,limestone avenue,jinchulla,lavington,4519,qld,19721222,3705755 +rec-1090-dup-0,,grainger,31,,vinda oldge,winthrop,3629,vic,19251017,9094252 +rec-2673-dup-0,olivia,thorpe,19,pudneystreet,parry h ouse,mount evelyn,2619,vic,19430807,3939861 +rec-437-dup-0,heans,mikayla,2,alexandrastreet,anona farm,broken hill,2444,qld,19510303,7694084 +rec-3678-dup-0,,dixovn,4,tytherleigh street,,albany creek,2097,nsw,19040831,8170333 +rec-3395-dup-0,carbone,connor,,willyamaplace,kalooca,buddina,2700,nsw,19090228,1119288 +rec-1207-dup-0,kyle,reaburn,27,bradfield street,parklands vkllage,lennox head,4061,nt,19150609,7434508 +rec-2500-dup-0,mia,pyper,90,paul coe vrescent,pine hill,camp hill,4207,,19410921,2154974 +rec-1501-dup-0,bailey,haack,56,heysen street,goolmanstreet,cronulla,2480,nsw,19171029,5238749 +rec-2430-dup-0,lara,white,6,sturdee crescent,summit cottage,toowoomba,2123,nsw,19190123,2444018 +rec-3818-dup-0,madison,plane,18,bardolph street,rosehilk,sunnybank,2541,nsw,19971022,9432416 +rec-2490-dup-0,jack,mayman,65,hutchins street,,kinglake west,3260,vic,19900106,6187556 +rec-1482-dup-0,tara,green,25,lashbrooke,chisholmstreet,boyne island,3073,nsw,19860550,1388911 +rec-3973-dup-0,katie,choroey,99,kangaroo court,,blakehurst,2738,vic,19380305,4782391 +rec-2046-dup-0,kaitlin,bowerman,16,fosketts treet,bulala,edensor park,6111,nsw,19140320,6109196 +rec-227-dup-0,jasmine,kiss,20,flower growers,batematn street,vermont south,6163,vic,19741212,6517742 +rec-3539-dup-0,robert,stephenson,108,burdett crescent,wombatz hill,south sydney,4560,wa,19460925,6871514 +rec-2964-dup-0,logan,bisgop,1,tanj il loop,,,2113,qld,19000423,1698144 +rec-1152-dup-0,samuel,wilkins,16,,wildes mdw,hayborough,3125,nsw,19680910,2994606 +rec-611-dup-0,ella,wisy,91,kingscote crescent,,homebjsh,2291,wa,19920720,9301098 +rec-1502-dup-0,niamh,tuckewll,2,richman place,,campbelltown,2154,nsw,19090106,2794307 +rec-871-dup-0,limbert,benjamin,201,blackman crescent,karinyah,woodbine,2228,nsw,19020429,5534369 +rec-1158-dup-0,adela,lomman,7,,canberrathse,frankdton,3158,vic,19980301,4768567 +rec-2499-dup-0,samara,ried,6,gardiner street,yuluga,blacktown,5433,nsw,19020405,4889678 +rec-1635-dup-0,roberta,laing,23,morrison street,budgerebella,flagstaff hill,4573,vic,19690425,5203452 +rec-3048-dup-0,colquhoun,jack,17,,glenburn,parramatta,2000,nsw,19660816,1194516 +rec-1922-dup-0,warnock,alana,5,federal highway,belmore diver,kurrajong heights,2283,vic,19790619,1270595 +rec-991-dup-0,millie,clarke,6,darcy close,marjories corner,greenwith,3150,nsw,19160503,5080999 +rec-2954-dup-0,noah,wiseman,17,wakefield garden,,frenchs forest,6535,nsw,19640101,8735485 +rec-2930-dup-0,ashley,webb,39,wilkins street,,reynel la,7315,wa,19670423,7920236 +rec-860-dup-0,daniel,belperio,17,murray vale muhrray valley,templeton street,gawler west,2066,nsw,,8978859 +rec-1903-dup-0,rachel,burrord,4,alabastre street,griffiths wing,adelaife,3155,qld,19201014,1452003 +rec-2799-dup-0,sophie,maynard,41,clancy street,inglewood,springwood,2600,wa,19690527,5566144 +rec-4061-dup-0,melinda,trent,28,dugdale street,kilwinning,penshurst,4556,qld,19240721,5900609 +rec-1234-dup-0,samujl,heidrich,7,mcgivern crescent,el-wo odaro,highbury,3053,act,19710525,8110080 +rec-1297-dup-0,noaj,scott-jackson,47,kosciusko avenue,upper flat,punchbowl,4306,nsw,19811218,2859455 +rec-770-dup-0,samara,,2,lewis luxto navenue,,pooraka,2778,act,19170725,9740765 +rec-2028-dup-0,zachary,minter,2,miller street,,graceville,2300,nsw,19580309,7193282 +rec-1953-dup-0,coby,lukeman,17,hiles pjlace,cherry haven,rosebery,3122,nsw,19040306,3163493 +rec-275-dup-0,joshua,berrpyman,91,summerville crescent,medical c entre,mount colah,4221,vic,19070709,6570397 +rec-1935-dup-0,charlotte,,234,mcgee pkace,alla ndale,cranbourne,3124,vic,19310603,8602736 +rec-2679-dup-0,dixon,thomas,108,brewster place,geelong grove,eight mile plains,2114,qld,19851127,8873329 +rec-3337-dup-0,dylman,,140,hurtle avenue,tulloch,,3585,qld,19211103,3790788 +rec-4168-dup-0,,ruolle-ivanov,11,fairweatoer circuit,,mount low,5290,vic,19661012,4600962 +rec-1792-dup-0,layla,,71,howitt street,oaklan,kirwhan,4210,wa,19201015,4834950 +rec-3516-dup-0,miller,browne,46,chuculb a crescent,gullamurra,ulverst one,3015,act,19671017,7983195 +rec-2348-dup-0,adam,tuckwell,38,mcmillan crescent,,broome,5037,nsw,19960528,8397512 +rec-3913-dup-0,cain,lowe,34,robertson street,hillsidw villas,sunshine,1245,nsw,19060725,6210006 +rec-3953-dup-0,isabella,concannon,15,alli place,mlc centre,keiloryieast,0822,sa,19410803,1922236 +rec-1495-dup-0,lachlan,cicconi,,waite street,,loftus,3108,vic,19200324,1514534 +rec-861-dup-0,binns,chantelle,6,cruikshank street,,burru heads,2212,vic,19370814,8334319 +rec-1627-dup-0,caitlin,bevis,46,smith street,grammar cahool,hawthorn,4878,nsw,19601011,3040069 +rec-1303-dup-0,thomas,boielau,8,,felbrigg,shefdield,4300,nsw,19111221,4100557 +rec-4682-dup-0,teagan,ricmhond,18,wettenhall circuit,flt 17,pleystowe,3000,nsw,19210820,8646516 +rec-2451-dup-0,stephanie,baptist,30,dalley rsecent,,winthrop,4055,nsw,19700503,3846199 +rec-1754-dup-0,shai,leung,15,grant hostel room,canopus crescent,metung,2147,nsw,19230106,8789495 +rec-4066-dup-0,tom my,campbell,4,wybalena grove,,bayswater north,4503,nsw,19480209,3117774 +rec-1562-dup-0,kaitlin,matthews,45,grote plmace,recreat ion camp,clifton,2024,vic,19960612,7208315 +rec-341-dup-0,lushia,reid,6,dunn plsce,hd allenby,karanja,4207,nws,19111022,1691582 +rec-4792-dup-0,julia,meadows,18,aralune street,st john of god hospital,crows nst,3174,nsw,19160818,7101191 +rec-409-dup-0,beau,eylse,30,solomon crescent,table muontain,granya,5280,nsw,19031212,8983029 +rec-330-dup-0,helena,haskett,,namadgi circuit,ryanfield,berowra heights,7307,qld,19560926,9361202 +rec-4140-dup-0,patrick,tomney,49,tillabudgery,smiths road,ascot vale,2340,qld,19390509,4461989 +rec-2670-dup-0,kyle,webb,1,emily bulcock crescent,belmont baybiew park,corriaml,3055,wa,19510310,9153676 +rec-72-dup-0,keira,lowae,15,morant circuit,wilding,warburton,4061,qld,19900523,4044906 +rec-3074-dup-0,aleisha,beadle,17,leonard close,broadbrid ge manor,madora,3025,nt,19160701,3130361 +rec-2150-dup-0,charles,tkachuk,1,hannan crsscent,nyngan,elwood,5086,nsw,19620625,9782270 +rec-2715-dup-0,lewis,green,256,hickenbotham street,tryphini aview,newlands arm,3055,nsw,19530919,8012486 +rec-1062-dup-0,dale,polmeapr,20,sturt avenue,,,6110,nws,19860101,6503215 +rec-2075-dup-0,lews,lohmann,3,clive steele avenue,gerovin valley ldge,view bank,5334,nsw,19101110,1778982 +rec-2932-dup-0,zachary,kermeen,7,powell treet,tourist park,yass,5162,qld,19131006,1784799 +rec-2077-dup-0,sophie,paterson,15,glynn street,family day care,lethbridge,6026,nsw,19850726,3382181 +rec-350-dup-0,jayden,death,13,lyle plce,omearas farm,leeton,2111,vic,19880218,2543380 +rec-289-dup-0,riley,paddon,5,burdekin street,rosetta village,mount aliza,6230,vic,19510214,4214905 +rec-467-dup-0,caitlin,berry,188,wynter place,,toodayy,3150,qld,19400622,2073490 +rec-345-dup-0,emiily,rankine,32,blackham street,sapric,campbelltown,5068,vic,19060404,3688640 +rec-2843-dup-0,lily,reida,30,,kaweku park,parkaide,3630,wa,19170624,7864863 +rec-4954-dup-0,james,kroklgi,15,orchard pace,,rosebud,6064,nsw,19430421,4244938 +rec-1670-dup-0,cameron,kouimanis,51,nulsen circuit,,tecoms,3931,qld,19671009,1274183 +rec-2043-dup-0,lewis,boyle,55,cottamp lace,willyaroo street,sunshine north,2000,nsw,19121105,1190651 +rec-1761-dup-0,jai,mullavey,29,carr cescent,,bangor,3013,sa,19150518,4003978 +rec-662-dup-0,lily,kradolfer,13,wanganekn vaenue,broughtonbrook,toowoomba,2750,vic,19501111,9815770 +rec-367-dup-0,chloe,,20,broadhurst street,sawtell vet hosptl & clnc,kyabram,5279,vic,19621217,7989856 +rec-1878-dup-0,tylet,clarke,11,bogan place,,werrington,4500,qld,19720225,3711822 +rec-2626-dup-0,thomas,snod,26,mcclintock street,,warilla,4551,vic,19790413,3010606 +rec-1331-dup-0,mainero,mikayla,54,haddon street,monkani,graceville,2250,vic,19240330,1458740 +rec-1847-dup-0,luke,karlsen,29,mckenzie street,,woodlands,2224,vic,19060425,3838005 +rec-1686-dup-0,jaemo,clatke,119,moondarra street,de cameron,tweedhaeds,3095,vic,19061129,6889594 +rec-3083-dup-0,herbert,darcy,28,goldfinch circuit,tarq ua,geelong south,2320,wa,19141204,7758955 +rec-2486-dup-0,mitchell,ramush,,hann street,,sunshine beach,3943,sa,19480321,7925486 +rec-2241-dup-0,sara,au,12,boddington crescent,wyseworth rmb 346,naracoorte,5084,qld,19621027,7694727 +rec-4590-dup-0,shandril,tinfina,437,stuart street,bodyworks healing centre,glenhaven,4773,nsw,19880220,2185877 +rec-1209-dup-0,courtney,hylhd,2,gask place,sec 1,cobar,2263,vic,19511001,9099158 +rec-2052-dup-0,,,8,conlon cdrscent,the provincial,balwyn north,7262,qld,19620323,2264634 +rec-867-dup-0,emiily,green,8,kurria place,oceanbeach ca ravan park,north rocks,5095,nsw,19810511,6240008 +rec-1421-dup-0,gillian,kaddtaz,72,ivo whittonc ircuit,woodport hostel,murdcoh,2026,qld,19650426,3271990 +rec-4005-dup-0,maddison,lonto,5,namadgi circuit,,kiels moungain,2261,qld,19050429,8559890 +rec-4647-dup-0,elizabeth,malcolmson,43,gaunson crescent,,werrington,2540,aw,19550528,4104314 +rec-1899-dup-0,,stubrs,175,aspinall street,cruachan,albany creek,5162,vic,19380924,6966319 +rec-3782-dup-0,tifafny,,26,southern close,westleigh,kirribilli,3437,qld,19860301,7929652 +rec-1921-dup-0,michael,degasoeri,43,rushbrook circuit,lyndake,hamilton north,2282,vic,19951012,2192076 +rec-4496-dup-0,warnock,hark,,jansz cr escent,brentwood vlge,broadmeadows,2486,,19350219,7539077 +rec-524-dup-0,whiet,ethgn,23,chippindallcircuit,keralta,moura,4152,wa,19411106,9247028 +rec-2678-dup-0,cooper,hamjmer,20,egglestoncrescent,,bunbury,4709,qld,19680910,7753471 +rec-2998-dup-0,chevonne,purser,5,mayo street,tumbeeluwa,sussex inlet,6210,qld,19461220,5908335 +rec-4477-dup-0,blae,ryan,5,,town & countr ycaravn park,bundabetg north,2484,nsw,19850601,6826301 +rec-2654-dup-0,bailey,lu-bow,,barrallie rstreet,rosk hill,gaioes,5576,vic,19530922,2252430 +rec-1565-dup-0,anthsony,bansgrove,1,falkiner place,bowse r,burwood,7249,vic,19400611,5970749 +rec-3170-dup-0,skye,heenan,9,hadleighcircuit,nunkeri,blue haven,3072,vic,19911002,3918522 +rec-4397-dup-0,emet,reichardt,15,hansen cjircuit,kellhaven,camden,3350,vic,19470716,9713002 +rec-1265-dup-0,olivia,girdler,242,joynerplace,,annandale,2422,qld,19840812,1413325 +rec-2256-dup-0,delaney,majetic,3,weavell place,tilbrogk,,7018,tas,19180423,7613275 +rec-1373-dup-0,talyah,mccarthy,8,cartercrescent,eldamead,springwood,2170,nsw,19210913,4421495 +rec-4998-dup-0,alicia,fergus,67,gidabal street,felb rig,wialki north,2251,sa,19971215,9245698 +rec-672-dup-0,sophie,rivera,9,burkitt street,lake chastworth,sheidow park,2089,qld,19830203,1376770 +rec-3520-dup-0,alyssa,arits,82,mceachern crescent,willerz,cabramatta,3064,qld,19220615,9906451 +rec-3133-dup-0,caitiln,mitton,6,arthur circle,,sale,3182,vic,19260517,4276696 +rec-4743-dup-0,menzies,benjamin,3,bangalay crescent,gowrie,toowong,2903,nsw,19570601,5363153 +rec-716-dup-0,hannah,birkin,7,tregear close,highfields spceialist centre,port macquarie,6065,nsw,19140127,3152369 +rec-1137-dup-0,chloe,mac onochie,6,temperley street,kerradan,andergrove,2326,sa,19440717,6618917 +rec-4354-dup-0,simon,clarke,21,verdonstsreet,antanoff' south,warracknabeal,2777,vic,19630730,1009287 +rec-1838-dup-0,thomas,rielly,47,norman fish er circuit,cressbr ook,valley view,4211,nsw,19720118,6802659 +rec-917-dup-0,carly,georgetti,155,lockyer street,langi,rowviille,2087,qld,19740602,7008776 +rec-2717-dup-0,abbey,coleman,26,ebenezer street,the lodge,toprak,2540,nsw,19100116,5514906 +rec-588-dup-0,sang,nguyen,119,gibbs pace,,bayswater,2154,vic,19000624,2842614 +rec-2991-dup-0,aidn,maynard,21,mcclure street,,bellevue hill,2021,nsw,19960105,3310706 +rec-958-dup-0,jye,humphreys,25,alma close,tyron ehills,berala,6075,vic,19670801,9902860 +rec-4658-dup-0,jack,danbty,,thompson polace,woorabinda,norwood,2340,vic,19991118,1030908 +rec-3164-dup-0,william,markellos,13,hartog street,homeosod,mansfield,3029,qld,19770717,1866346 +rec-4761-dup-0,matthew,sarah,58,candlebark close,mt callan,acacia ridge,5253,vic,19341010,2053693 +rec-3431-dup-0,harr,rollins,22,antill street,valbella,mount isa,3142,wa,19240905,5927194 +rec-847-dup-0,riley,spicer,124,mclachlan crescent,,boort,2508,nsw,19941213,3182778 +rec-1349-dup-0,lachlan,boothroyd,101,elkington street,witsend,waterloo,6085,sk,19600904,5764782 +rec-4693-dup-0,white,arc hie,19,kernot sgreet,ingevl ae,corndalw,2260,sa,19560508,5801177 +rec-1864-dup-0,ruby,donalsdon,42,,glenbrook orchard,appin,2035,tas,19141014,3742981 +rec-3328-dup-0,,koteschel,193,mayne steet,grek oaks,swan view,4305,vic,19430808,1393004 +rec-3800-dup-0,gawthrop,catherine,16,westbury crcuit,black sna ke creek,arundel,3162,qld,19151003,9134417 +rec-2605-dup-0,jennions,olivter,4,o'shanassy street,rye park,glenmore park,3555,nsw,19500316,1498603 +rec-4755-dup-0,,mcniell,33,crozier crcuit,legacy units,yambk,6166,nsw,19460824,7072281 +rec-4254-dup-0,noah,verner,150,macquarei street,jarroo,murrumbqteman,3150,nsq,19500227,8469038 +rec-3608-dup-0,jessica,winfield,47,fullagar crescent,shopping centre,taylors bay,4031,sa,19761107,2938526 +rec-287-dup-0,amber,hand,64,burnside street,cordial afctory,limeburnerscreek,2646,vic,19890422,8605183 +rec-1662-dup-0,kyle,egan,62,rochford street,shamrock vale,yanco,3214,nsw,19490603,2814414 +rec-305-dup-0,timothy,elphixck,28,waratah street,main beach medcial centre,,6096,vic,19391124,3887226 +rec-516-dup-0,,hulley,,knaggs ceqscent,,elsternwick,2283,wa,19201008,3808150 +rec-4230-dup-0,jason,fenwickq,5,vincent place,glenearra,morphetyville,3011,qld,19550520,4178650 +rec-4821-dup-0,caleb,fitzpagrick,10,laughton stzreet,manor park,thornbury,6258,vic,19040922,3284048 +rec-3371-dup-0,lucy,alddrson,4,temperley street,camelot est,rosslea,2159,nsw,19380411,1125271 +rec-3062-dup-0,fai th,lavender,1,shepherd street,,st clpir,3058,nsw,19140623,2694419 +rec-3768-dup-0,lachan,,83,,croyfon,broulee,2181,nsw,19960701,7082968 +rec-3993-dup-0,ruby,wraiht,20,luehmann street,mt pleo sant,tongala,2640,nsw,19090322,9034954 +rec-1174-dup-0,lilfy,browne,1,spring rsne road,,someret,2024,qld,19990812,1727298 +rec-4188-dup-0,anrdew,masoh,12,starling place,brentwood vlge,rosewater,5086,nsw,19321115,1878301 +rec-4102-dup-0,joshua,donaldson,19,macfarland crescent,boonawah,belmont,2615,qld,,9586561 +rec-3579-dup-0,scriplps,megan,40,karawatha place,,bonnells bay,2761,sa,19970108,7573986 +rec-4849-dup-0,hol ly,campbell,4,syme crescent,ahwahmee,hamilton,4868,nsw,19160516,7267433 +rec-2749-dup-0,,priest,41,fink crescent,nioka,broken hill,2340,nsw,19060617,7169908 +rec-4011-dup-0,james,dixon,68,fanningx place,regal oaks retirement vlge,marsden,4300,qld,19750913,8198316 +rec-3113-dup-0,liam,pascoe,311,tillyadr drive,lindenleigh,hamilton,4030,nsw,19960928,2933911 +rec-4614-dup-0,nicholas,bruinewoud,335,shakespeare rescent,marandyvale,kareela,2577,nsw,19621123,5768862 +rec-1682-dup-0,kiara,starega,29,knoke avenue,llen nomis,southern cnoss,4615,nsw,19541115,5126468 +rec-1023-dup-0,harry,mason,42,jabanungga avenue,crown reserve,ryde,4490,wa,19650607,8822165 +rec-4501-dup-0,xani,caruana,3,ordell street,lachlan view,wynyard,2170,qld,19840619,2057736 +rec-1703-dup-0,jett,wihte,72,marshall street,,greenacre,3500,wa,19141102,4115932 +rec-2017-dup-0,george,jordan,114,rapanea arteet,peechsblela,maryborough,4123,vic,19951020,4523010 +rec-2572-dup-0,,dudgeon,11,cockcroft avenue,manor park,joondalup,3040,nsw,19740328,7423497 +rec-2726-dup-0,charlie,thorpe,10,edmanvclose,kandahar,bull creek,2066,vid,19620923,4837521 +rec-815-dup-0,holyl,campbell,21,casey crescent,,westmead,4573,qld,19911007,4424335 +rec-619-dup-0,harrison,burford,25,paul coe criescent,earl haven,ashgrove,6028,qld,19160131,4722591 +rec-3179-dup-0,edwafd,marshman,852,cambridge street,bobblegigbie,cabramatta,3201,wa,19521111,5673646 +rec-4101-dup-0,daniel,ballantyne,137,howitt street,timberscombe,noble patk,4014,qle,19601102,3529680 +rec-3975-dup-0,,sheprherd,,torrensstreet,south macroom,rose bay,3085,nt,19011229,5190083 +rec-868-dup-0,lews,hursdy,6,mawson drive,yengola,,4221,vic,19080210,6791213 +rec-1489-dup-0,matthw,brock,18,longworth place,never die,oaklands park,2092,nsw,19500905,5036231 +rec-4298-dup-0,mitchell,wheatley,53,emblingqstreet,,mongarlowe,2795,qld,19641102,3016745 +rec-4115-dup-0,simmonds,jaek,37,castley xircuit,lydnilan,mansfield,6027,nsw,19110310,6453549 +rec-3728-dup-0,vincent,colthorpe,34,masters place,caravn park,campsie,2325,vic,19490729,7434022 +rec-3294-dup-0,shane,clayfon,4,topp place,north nowra shopping centre,gunaldaa,2257,vic,19300311,7717125 +rec-3772-dup-0,isabella,lail,20,glover serteet,,nicholls,2251,qld,19770924,8701819 +rec-959-dup-0,zac,,18,kambalda crescent,mckinnon glen,east mailand,4500,sa,19970725,2709860 +rec-3019-dup-0,blaye,browne,1,gossestreet,,cape paterson,4251,vic,19210917,7165012 +rec-1736-dup-0,jye,dearing,201,matcham place,currimundq garden,bundaberg,5520,qld,19940616,7183071 +rec-2681-dup-0,lucy,van de maele,17,rutledgelplace,mater professional centre,port lincoln,2304,vic,19770324,4274192 +rec-1031-dup-0,ben,chorny,16,mcquade close,our folly,bonnyirgg,4120,qld,19481025,3512659 +rec-1862-dup-0,brydon,macgowan,14,jaeger circuit,glenview,,7262,,19130615,8190321 +rec-3339-dup-0,katharine,white,10,kirkwood crescent,glenpp,wahroonga,4670,wa,19130608,7824077 +rec-4368-dup-0,jacob,plumb,43,blackman crescent,torrimgton,gosford east,6164,nsw,19320606,9898855 +rec-4002-dup-0,zara,,27,o'conno rc ircuit,fm226,horsley,2256,nsw,19730628,8230398 +rec-4616-dup-0,joshua,green,32,kingscote rescent,retirement village,koro ra,2617,vic,19351228,4876691 +rec-4948-dup-0,connor,paine,55,templestowe avenue,roclea,regents park,2065,wa,19740164,3880965 +rec-4586-dup-0,,webb,168,booroondara street,the willows,lakes entrance,3179,vic,19911219,6504336 +rec-21-dup-0,abbey,hoffman,6,colmer street,rosetta jfillage,keilor,4285,nsw,19070925,4455111 +rec-1117-dup-0,nicholas,mcfadden,11,coplandrive,lithgowvale,griffin,3556,qld,19020330,6563324 +rec-1452-dup-0,samuel,quilty,19,,,sherwooh,3121,qld,19820317,9211278 +rec-4229-dup-0,harley,kreymborg,160,spinifex street,laurietonhvn ret,holsworthy,4630,act,19550403,8066192 +rec-1656-dup-0,pino,matthews,65,blamey crescent,wilderness,hexhim,5253,vic,19010717,6537217 +rec-26-dup-0,rhys,campbdll,37,brentwood village,uptonsttreet,woollahra,3355,wa,19990213,2201146 +rec-2511-dup-0,wi l,araya,57,sandover circuit,,belmont,4220,wa,19770709,9179475 +rec-4266-dup-0,christopher,george,12,hopetoun circuit,brookavle,mayfield,6016,nsw,19741228,2025503 +rec-4111-dup-0,emiily,campbell,8,cowan steret,plantation caravn park,caisno,2113,qld,19531029,3909212 +rec-2124-dup-0,isabwlla,petrikowski,4,mcbryde crescent,beaumont hills,loganlea,4034,nsw,19750509,2493367 +rec-900-dup-0,kyle,felmingham,7,cassinia street,marella,kingston,3936,nsw,19121120,1300375 +rec-2444-dup-0,hannah,povey,81,hooke lpace,gleneriffe,sylvaria,3051,wa,19870509,4598128 +rec-4687-dup-0,samantha,papoutsis,21,titheradge place,st francisv illage,wyoming,3300,vic,19260627,7785823 +rec-494-dup-0,,gibb,59,weavell place,st vincents hospital,tawonga south,2119,nsw,19490606,8704563 +rec-3667-dup-0,alicia,lenartowicz,47,jane price crescent,kildrummie,clovwrdale,3056,vic,19291029,2790792 +rec-3270-dup-0,,mccarthy,313,biggs place,john flynn medical centre,highett,5086,nsw,19431221,1133389 +rec-2585-dup-0,harvey,white,132,twelve trees crescent,dargam,reynella,3089,vic,,7501852 +rec-339-dup-0,kontopoylos,samuel,11,bamir square,pleasant view,carnegie,3639,vic,19870312,9712523 +rec-1151-dup-0,courtney,dabinet,240,feathertopstreet,barley hill,tardun,2646,qld,19910105,5257049 +rec-1255-dup-0,stella,rogan,22,wattle street,flr 5 john flynnm edical centre,strathalbyn,2289,qld,19690311,1379241 +rec-1126-dup-0,ly dia,mcglinn,42,federal highway,bessboro,noble park,4626,,19840629,1700034 +rec-3587-dup-0,emiily,white,1,marou place,,marsden,3412,vic,19510901,6646759 +rec-3246-dup-0,isabelle,mccathty,3,nullagineystreet,pangani,scarborough,0864,sa,19660628,6386847 +rec-264-dup-0,jessica,painton,92,gallagher street,berkeley lvge,north bondi,7440,nsw,19430327,2751175 +rec-440-dup-0,james,weidenhoffer,52,bellchambers crescent,paddy's r iver,,3337,qld,19130401,4232347 +rec-4048-dup-0,lewis,dorsey,50,,deltroit station,woy woy,2650,vic,,5250955 +rec-1811-dup-0,jack,campbell,11,albermarld place,sec1,san remo,2134,tas,19291016,2920956 +rec-3966-dup-0,james,truman,4,shirra close,red hils,wallsgend,4212,act,19740918,9244854 +rec-400-dup-0,emiily,paie,26,bussell crescent,koo,karraha,3977,vic,19750805,7519967 +rec-3670-dup-0,blake,mayeor,5,freda gibson circuit,willaro o,erskine,2214,vic,19080705,6979379 +rec-1034-dup-0,briony,dudley,6,goodwin street,ctge 2 5,allwaah,3128,vic,,2103478 +rec-1317-dup-0,laura,,82,polynesiane village,doyle terrace,stretton,3103,nsw,19200221,1808199 +rec-4858-dup-0,joshua,quinzi,15,bagster place,arabian stud kelkette park,edgecliff,4670,vic,19338008,4918400 +rec-4575-dup-0,jordan,rosla,99,dobson street,ben nevis estate,berwick,2145,qld,19180519,4793062 +rec-3639-dup-0,taylah,weller,10,eaglemont retreat,kalang,point vernon,2066,nsw,19111122,4433270 +rec-3169-dup-0,madison,mcgregor,,godfrey street,springdale,mount plrasant,2049,wa,19230420,2493506 +rec-2907-dup-0,tiarna,cannell,685,deacon close,,fishingupoint,2287,wa,19020305,6547713 +rec-525-dup-0,emiily,lock,14,collins place,pipersgriver,oakleigh,6064,nsw,19350628,6850395 +rec-2355-dup-0,luke,rollins,360,hickenbotham street,,arundel,2221,qld,19240109,6938121 +rec-1415-dup-0,amber,braunack,28,alchemy,fingleton crescent,campsie,2508,act,19420513,7964228 +rec-3341-dup-0,rile,grubvb,377,abercrombie circuit,lapstone,burwood,6338,vic,19040327,2728665 +rec-1958-dup-0,emiily,gruener,34,jarma nplace,girrahween homestead,kaloraa,3003,vic,19780128,4299404 +rec-3949-dup-0,de lac ruz,belinda,7,carumbi place,eddington,charlestown,2460,vic,19020217,6051352 +rec-241-dup-0,chloe,dunnicilff,10,fraser plvce,walkaboutoalms,belgrave,4211,nsw,,9683634 +rec-1902-dup-0,andrew,dunsltone,2,hodgson crescent,homevale,nambour,2121,nsw,19230326,6824936 +rec-934-dup-0,george,lavender,851,earle place,kilmore,elizabetg park,4068,wa,19011207,3461164 +rec-1386-dup-0,hayley,carmodxy,5,duiganstreet,aberglasslyn cottage,eme rald,2321,act,19611012,1756595 +rec-4594-dup-0,matilda,bissett,185,gunduluplace,bandaroo,taree,5044,wa,19830319,5260083 +rec-3234-dup-0,jessixca,ryan,3,stonehaven crescent,eaglevoiew,edgecliff,6016,nsw,19570904,2097814 +rec-2967-dup-0,emiily,clarke,5,john russell circuit,,canley ehights,5032,wa,19760608,4952094 +rec-1130-dup-0,madeline,spicer,6,meyrick rplace,the mews royal hotel bldg,marks point,3196,nsw,19430521,1722390 +rec-2557-dup-0,annabelle,conzens,27,mcluckie crescent,earle haven retirement village,,0870,vic,19250508,9397671 +rec-4949-dup-0,brianna,blackwell,20,john russdll circuit,yarrandoo,cremorne,3192,nsw,19430515,6543804 +rec-931-dup-0,matthew,goldsworthy,5,karuah s treet,,williamstown,5554,wa,19771013,5645462 +rec-1618-dup-0,thomaus,campbell,35,lethbridge street,scenic lodge,paddington,2450,nsw,19610710,5974512 +rec-2677-dup-0,hayden,cartmel,11,elvire place,,allawah,2404,qld,19620629,2718027 +rec-4426-dup-0,bailee,dooley,24,balfour crescent,baybrleze,bowral,3152,vic,19140520,5906249 +rec-3766-dup-0,teaha,lowe,3,rosetta village,crocker place,colig c,3058,vic,19411021,1890695 +rec-1513-dup-0,madeline,adiar,2,allman circuit,robboview,balwyn north,6006,vic,19410309,7581364 +rec-1118-dup-0,tai,saunders'wise,40,bugden avenue,grand c entral,crsesy,4027,nsw,19310719,4524499 +rec-4525-dup-0,hayley,bloomfield,58,jondol place,,plumpton,5725,qld,19310515,2689302 +rec-1835-dup-0,nikiga,bzeuch,10,boddington crescent,holiday vlge,mcdowall,3020,nsw,19460615,3999407 +rec-4844-dup-0,alessandra,mcneikl,364,kelleway avenue,bodyworks healing centre,broken hill,2763,qld,,5866707 +rec-4827-dup-0,emma,maynard,18,chillagoe s treet,little springhurst,lower mitcham,4051,vic,19931210,8245281 +rec-4013-dup-0,,haren,14,finlayson place,colloca vale,mooroolbark,7050,vic,19180426,5885583 +rec-953-dup-0,charlotte,heuston,92,wayal place,memorial hospital,cremorhe,2619,vic,19970428,9940785 +rec-2899-dup-0,elli,trowse,3,bellingham crescent,villa 3,islington,2650,vic,19220705,1676559 +rec-2135-dup-0,ethan,,1,masonic bi ks place,ridgebdook,aspendale gardens,2069,wa,19520318,8666305 +rec-3497-dup-0,thomas,manson,22,birbvi place,karsul,frankston,6532,nsw,19160504,3670653 +rec-3851-dup-0,jariui,blackeell,211,igera place,amberavle,mentone,2519,wa,19060228,2309849 +rec-2784-dup-0,tiffany,van der hoek,4,holt place,learmont,kirribilli,0801,sa,19980630,3179832 +rec-3453-dup-0,jasper,ryan,36,,karbar station,blacktown,2480,vic,19331202,5561624 +rec-396-dup-0,nell,campbell,4,stroud p lace,st pauls court,lindfield,6011,vic,19170614,5659846 +rec-4356-dup-0,jack,dunnicliff,63,tristania street,legacy vlge,sale,2248,vic,19760618,8513207 +rec-4768-dup-0,caitlin,,24,eyre street,retirement village,worongary,2830,nsw,19420102,1257356 +rec-4676-dup-0,joshua,coffey,2,blueberry street,yalgoroa,shell ove,2052,wa,19240713,9217500 +rec-3447-dup-0,calbe,rauseo,1,mcshaneiplace,,sanctuary point,3044,nsw,19440927,3969191 +rec-519-dup-0,joshua,baillei,8,de baun crescent,,bonython,2173,qld,19650415,6504350 +rec-4352-dup-0,julia,webb,86,english court,benachie,south grafton,4740,nsw,19700225,1679591 +rec-2529-dup-0,amy,blake,351,prevost place,warramjnda,hammondivlle,4422,nws,19920715,6686050 +rec-4589-dup-0,liyl,mccaffrey,166,john cleland crescent,kirkdale,port pirie,4870,vic,19260727,8711730 +rec-1517-dup-0,ruby,reid,6,templemore,tanumbirink street,bundaberg,3134,qld,19490517,4966992 +rec-1065-dup-0,zachary,jevons,79,pankhurst crescent,old a frm,oyster bay,4123,nsw,19020103,9596699 +rec-4584-dup-0,joshua,gsohl,38,charteris crescent,locn 3719,sandy bay,4701,qld,19210912,4250931 +rec-2123-dup-0,reece,bryce,113,gravse place,mt forjr est,kelmscltt,5088,vic,19301007,4462693 +rec-140-dup-0,thomaks,bullock,5,mccawle y street,yarrabin,oakleigh,2448,nsw,19260922,2517453 +rec-2629-dup-0,abby,compton,10,batman street,mannafields farm,moun t isa,6021,nsw,19780508,7062701 +rec-1129-dup-0,andrew,ranine,84,beau-lieu,boddington crescent,connolly,3643,qld,19311116,2128049 +rec-513-dup-0,iren,hudyd,41,diggles street,st francis village,park holme,2603,vic,19160630,7026823 +rec-1708-dup-0,talia,mccarhy,,bournestmreet,locn 3439,deer park,3198,nsw,19730822,7901066 +rec-713-dup-0,alison,feeney,13,loban court,the mews roya lhotel bldg,barabba,6264,nsw,19280604,1316297 +rec-4925-dup-0,isaac,riddell,20,ern florene crescent,villa 147 henry kendall bayside,concor west,5042,nsw,19210805,7044649 +rec-3946-dup-0,samanetha,garnett,10,furey steet,raworth cottage medical practice,wallacia,2530,sa,19210919,2074453 +rec-3699-dup-0,julia,velzeboer,796,ewart street,,hackham west,5054,tas,19930613,2222450 +rec-29-dup-0,kylee,kincaid,16,eucumbene drive,,sunshine,2232,qld,,4662381 +rec-1791-dup-0,joshua,red,416,mcburney rescent,karingal farm,bayswater north,2165,vic,19160311,3652623 +rec-2850-dup-0,rupet,browne,144,sturdee crescent,lingdale,greensborough,3272,qld,19981026,5706098 +rec-512-dup-0,campbell,colquhvoun,134,healy sjtreet,lakeview car avn park,greenfield park,3186,vic,19490831,1130272 +rec-4461-dup-0,marleigh,miell,20,spring ragne road,tulloch,peakhurst,4226,vic,19931025,4689620 +rec-1659-dup-0,holly,glennon,8,ballumbir street,summefvale,glengowrie,4124,wa,19490518,6635323 +rec-4400-dup-0,yasmin,white,33,body place,st annes zest home,koo wee rup,7249,nsw,,8632908 +rec-3842-dup-0,bailey,roceh,10,orkney pcae,portal cnr hives,emera ld,5044,nsw,19710505,4461398 +rec-2842-dup-0,jaems,hefford,59,tuckett place,,west wollongong,2228,nsw,19591227,4834804 +rec-2085-dup-0,isabella,matthews,48,,corporate house,armidale,6061,qld,19060809,1255415 +rec-3267-dup-0,,pai nter,60,cockle street,tantillon,casula,3064,nsw,19181001,4954628 +rec-796-dup-0,jayme,heenban,,,fernlea,lakes entrance,5120,wa,19860621,4096585 +rec-2599-dup-0,sidonie,trenery,146,jerrabomb erra avenue,lindoran,ashfield,2766,nsw,19150107,9307008 +rec-3820-dup-0,anita,kalma,10,eugenia s treet,tantlalon,karalee,5076,qld,19780922,1975087 +rec-3304-dup-0,adam,coulls,41,tiwi place,ettrick,yacknadandah,3116,qld,19650328,1748977 +rec-4007-dup-0,rachel,campbell,48,dutton sitreet,the wiklows,wendouree,3129,nsw,19710314,6934561 +rec-1190-dup-0,tschirn,kale,100,garaheh,waldockstreet,bayswater,3350,vic,,6637214 +rec-262-dup-0,jaek,soden,3,hardwicie place,orange specialist m edical centre,bligh park,2852,nsw,19461110,4287888 +rec-3726-dup-0,kedley,slape,10,arthaldo court,glenor e grove,kogarah,6012,nsw,19301222,9981980 +rec-3801-dup-0,sophie,hage,18,riley clwose,rocklea,seaforvh,3215,nsw,19771204,9725410 +rec-1395-dup-0,grace,okubo,7,reynolds street,corinesla,greenac res,0812,nsw,19210907,3936339 +rec-3405-dup-0,kane,graihner,15,may maxwell crescent,meadowvale village,dungarubba,2281,vic,19390811,6671921 +rec-3494-dup-0,william,redington,107,white rock,postle tircuit,nowra,4044,sa,19840716,3386603 +rec-463-dup-0,molly,slape,23,currie crescent,dickson family practice,glenwod,2777,wa,19530127,6905342 +rec-207-dup-0,isabelle,huxley,42,rosenthal street,antigua,hocking,3824,qld,19820920,3356088 +rec-1926-dup-0,alisza,cappelluti,,lightfoot crescent,brampton,seymoru,6084,wa,19160523,5168724 +rec-1550-dup-0,livia,miles,15,stewart cerscent,rosetta village,thornbury,3851,act,19760903,9683666 +rec-4022-dup-0,phoebe,sedgwick,24,hobby place,st francis vlge,cabramatts west,2600,nsw,19470817,3134424 +rec-192-dup-0,ryley,marzec,7,murrellplace,,orange,3939,nsw,19850421,5740778 +rec-1967-dup-0,,kempton,22,walton street,henry kendall bayside,vale park,2205,sa,19330113,3037416 +rec-349-dup-0,isabelle,burford,3,bendigo street,shady creek,warrandyte,4217,wa,19050504,8427851 +rec-1348-dup-0,kerslake,benjamin,6,mcdonnel lclose,bethany,chester hill,2199,nsw,19571214,3250168 +rec-3811-dup-0,yasmin,george,9,crisp cixrcuit,abbotsley cottage,keilor lodge,3023,vic,19290223,5237340 +rec-238-dup-0,,nevin,36,creswiick place,penny lane shopping centre,colonel light gardens,3169,qld,19840223,8258349 +rec-992-dup-0,mcgregor,nikita,1,cooranlga,sherwood ircuit,frankston,3892,sa,19250127,9742298 +rec-3823-dup-0,caitlin,teren,47,fullagar crescent,houngank,broadmeadows,2370,vic,19740828,3463191 +rec-3076-dup-0,xain,andrae,20,wade street,mynoa,tahmoor,2105,vic,19450312,4709521 +rec-4777-dup-0,amy,steniert,20,werriwa cqrescent,kangaroo grnd,hillston,5251,nsw,19930209,7428687 +rec-2890-dup-0,kiana,lenzi,35,bugden avenue,the maadxows,goodooga,2075,,19110824,6557448 +rec-2950-dup-0,cade,newport,,britten-jeneds drive,the prk,warnbro,2266,qld,,2081552 +rec-1271-dup-0,charlie,zimmermnn,68,tebbutt place,nuffield village,carnegie,3140,vic,19681220,2564958 +rec-534-dup-0,rilye,son,11,duffy street,toora,,2486,nsw,19851219,8480884 +rec-2402-dup-0,makenzi,boase,29,box hill avenue,,oak flsts,2036,sa,19770104,4259426 +rec-131-dup-0,josua,beatton,118,,kimb e,bundaberg,2171,sa,19090913,2110769 +rec-4881-dup-0,nguyen,alexandra,44,colebatch place,langley flats,freshwater,3242,nsw,19511004,6416159 +rec-1661-dup-0,bianca,clarke,59,florencetaylor street,circlec ourt,chittaway point,2330,vic,19400401,6129111 +rec-1147-dup-0,michal,boyle,3,riverstreet,,lakemba,2611,vic,19091217,2387415 +rec-1509-dup-0,ben,white,466,louisloder street,parry hse,wake ley,6163,qld,19670921,9376814 +rec-343-dup-0,steaven,green,9,duigan place,dunbarh ei ghts,pennant hills,7010,qld,19760329,8403741 +rec-2578-dup-0,josua,chandler,113,companio n crescent,parkdals lodge,cleveland,3556,vic,19030124,5666451 +rec-2542-dup-0,harley,webb,6,brownless street,willow l ldge,harbord,2905,qld,19760709,5012250 +rec-4829-dup-0,smallacombe,flynn,62,bimberi crescent,marlin c ove,taylors beach,2171,qld,19330907,3577473 +rec-2119-dup-0,oakleign,shepherd,106,rosewood place,allanvale,dalby,2259,vic,19480913,9643705 +rec-1528-dup-0,,muthdkuda,11,waratahkstreet,keira,thornlie,0820,vic,19890328,5670243 +rec-3640-dup-0,,white,1,bugden avenue,belvoir,mona fale,2282,vic,19870412,9595240 +rec-2828-dup-0,dylyan,pinhiro,7,canopus crescent,strabane,birkdale,5050,nsw,19131214,2918000 +rec-1729-dup-0,thred gold,hayden,7,callaway crescent,danric lodge,keilor park,2365,nsw,19730416,5433941 +rec-4441-dup-0,deakin,michelmore,,percivao street,west aerodrome,kyogle,2540,vic,19911030,6770823 +rec-4688-dup-0,jamie,,124,kosciusko svenue,,springhood,3142,nsw,19891008,3390421 +rec-1877-dup-0,ka,reid,114,lipscomb place,karingaltxhm,kingjston,4702,lqd,19160621,4440797 +rec-3419-dup-0,hayden,rushyb,72,shackletoncircuit,calk mna,murtos,3437,vic,19291001,1731879 +rec-1839-dup-0,paris,nguyen,13,forest vi ews,moroak street,cranbourne,2217,qld,19010108,1825355 +rec-3702-dup-0,mystique,wisemkan,42,rivett skreet,,dover heights,2615,wa,19290619,3989366 +rec-3446-dup-0,aikaterina,pacey,146,chandler street,,meadow creek,3624,vic,19160205,4293148 +rec-302-dup-0,jack,ryah,109,lampard gircuit,bega flats,lennox head,2230,nsw,19690724,4124424 +rec-4848-dup-0,lilly,godfrey,7,discovery street,2/98-latchford barracks,trigg,6019,wa,19030330,7434268 +rec-3320-dup-0,mia,mihaylov,1,igera palce,glenview,montmorency,7140,nsw,19480330,3359084 +rec-4398-dup-0,,camp,58,dowling sgtreet,executive arcade,farrer,2519,qld,19460723,5604647 +rec-3361-dup-0,isabelle,bullock,10,,eden park,henty,2212,nsw,19921028,5801283 +rec-3821-dup-0,penonell,chloe,3,medleystreet,noolabi,ringwood nxrth,5092,vic,19530710,1249545 +rec-1432-dup-0,tarshya,hazell,51,chauvel crcle,,toorak,3073,nsw,19211102,1853367 +rec-4661-dup-0,elizz,matthews,37,launceston street,settle downs,carrick,3138,wa,19130330,7623803 +rec-4074-dup-0,james,fimeri,93,andrews street,,vermont,2918,vic,19230520,2169259 +rec-4227-dup-0,emiilh,slorach,21,andrea place,apt 211,kingsford,2574,nws,19841130,4117135 +rec-2664-dup-0,emiily,thorpe,,booleestreet,gumnut clttage,boondall,5114,vic,19370502,2528591 +rec-1523-dup-0,chloe,westbrook,3,city walk arcade,sheep station,pallarenda,4210,vic,19590508,9412116 +rec-1173-dup-0,amy,white,27,doyle terrace,tantallon,duncraig,3810,nsw,19340217,3650130 +rec-4805-dup-0,tiahnee,davidu,20,frater crescent,nareen gardens hostel,ottwoay,4218,nsw,19020916,8270473 +rec-2213-dup-0,matilda,gilley,29,coghlan istreet,vinder lodge,magill,2197,nsw,19790709,5268628 +rec-4926-dup-0,haylee,metherell,16,lambrigg street,wachroo,railton,2209,qld,19050614,4025303 +rec-3194-dup-0,jarred,rider,,robinsonstreet,,evans head,3123,nsw,19401202,2875179 +rec-4950-dup-0,charlotte,petersen,66,sturgeswplace,gerovin val ley ldge,landasle,2217,nsw,19691217,6017558 +rec-1291-dup-0,tiana,webb,59,spalding stureet,,glenorf,2444,nsw,19270920,6947860 +rec-4141-dup-0,courtney,mcgregor,56,dianella street,queens lake village,bassendean,3218,,19830529,5272719 +rec-4669-dup-0,brooke,hendricks,34,lake downs super fine merino stud,eucumbene drive,narooam,3179,nsw,19450517,6179346 +rec-2680-dup-0,gilliab,leon,10,,,elizabeth south,4201,nsw,19660416,2875631 +rec-865-dup-0,abbey,paine,55,meehan garden,braebu rn,murray bridge,4390,qld,19080127,3792626 +rec-3416-dup-0,garcia,gabrielle,74,kehlhfo,duttoh street,burwood,4311,sa,19081210,2519794 +rec-3968-dup-0,charlie,furfari,132,wellington street,balfron station,harbord,3166,,19410505,2381712 +rec-2360-dup-0,julia,clarke,84,marconi crescent,hamilton park,whitfield,2642,wa,,2329598 +rec-2228-dup-0,william,ziswiler,68,bellchambers crescent,galloway,malvern,2215,vic,19010406,5172369 +rec-3578-dup-0,jasmine,mariager,21,medley str eet,pine hsill,evans head,4020,nsw,19180202,1051531 +rec-1458-dup-0,connor,green,95,warrai place,brindabella specialist centre,padstow,4015,nsw,19500301,5431719 +rec-2261-dup-0,kylie,seppelt,4,tannerip lace,wearmouth,modbury,4883,qld,19251024,3972479 +rec-1782-dup-0,burford,sophie,17,merfield place,legacy units,surat,3144,wa,19321031,6901639 +rec-1891-dup-0,lara,snelling,1,bimbiang crescent,the briar patch,toorak,5049,vic,19610916,8479980 +rec-253-dup-0,samantha,kerslake,14,howard street,the meadows,keiraville,6167,nsw,,7977658 +rec-3444-dup-0,tenille,hick,,mcwhae crcuit,trail vview,orange,3128,,19200707,6908407 +rec-4056-dup-0,daniel,satterley,5,eugenia street,strathlea,kedron,3056,qld,,7208037 +rec-2246-dup-0,desi,spargo,114,tenison-woods circuit,kenhra,abbotsford,7261,qle,19800308,9515868 +rec-2300-dup-0,dasilva,georgia,29,trumble street,wilar oo,bayswatre north,3858,vic,19591226,6737283 +rec-3764-dup-0,joran,,22,raymond srreet,norillee,newborough,2303,nsw,19440528,2601600 +rec-1861-dup-0,lucas,corsico,1337,saggerw close,tara park,port macquarie,6155,qld,19730826,9722217 +rec-4562-dup-0,cambell,ryan,23,bradfield xtreet,bolinda vale,brighton,2537,nsw,19700416,7188298 +rec-3428-dup-0,ashlee,bishop,173,john james hospital,om aha,dromana,4816,nsw,19804103,8269833 +rec-2082-dup-0,chelsea,pontt,91,gellibrand street,shelomith,petersham,2166,vic,19350130,3454949 +rec-2614-dup-0,bertie,bridgland,11,arndel lstreet,tathra,kempsey,2594,sa,19931819,4871743 +rec-2775-dup-0,caitlin,rastar,595,cressy rove,la trobe close,byadk,2207,,19940531,2416013 +rec-718-dup-0,,kranz,33,pandanus btreet,tantallon,bowral,2264,nsw,19330726,6581103 +rec-3506-dup-0,crossman,isaiah,14,hopetoun c ircuit,inveraary,emu pafk,3175,nsw,19680729,7045589 +rec-290-dup-0,george,webb,16,beatham close,nelsonlsake,lakemba,2064,nsw,19721211,6420147 +rec-4890-dup-0,georgia,gilkes,16,eagle circuit,hornsbie,wantirna,2621,wa,,7326444 +rec-3563-dup-0,lachlan,clayeen,4,atkinsonstreet,parklands village,buninyong,2765,qld,19330705,7427334 +rec-2404-dup-0,blakeston,broadby,53,traeger street,valley of springs,north ward,3083,,19120907,4308555 +rec-3151-dup-0,harry,gully,81,templetno street,navan park,toowong,6023,vic,19450926,4903149 +rec-3755-dup-0,tahlia,rya,,john young crescent,flr 5 john flynn medical centre,westlke,2148,nsw,19741502,4169896 +rec-1310-dup-0,olihia,woodstock,209,,edinburgh caravan,mooroolbark,2370,qld,19191127,2364919 +rec-3081-dup-0,amy,noble,2335,marcusclarke street,oakdale,punchbowl,4695,vic,19470518,8727631 +rec-2931-dup-0,,campton,31,kennewellp lace,palms lodge,coolbellup,4711,nsw,,2809212 +rec-1470-dup-0,paine,ruby,27,tatchell vstreet,beladnean,lennox head,3350,nsw,19030605,4010380 +rec-4499-dup-0,alissa,bydrs,6,beasley street,,coffs harbour,6009,sa,19550131,2851382 +rec-1344-dup-0,sebaitan,blissenden,16,mataranka street,,ashfidld,2758,wa,19750320,4893136 +rec-3955-dup-0,wardle,joshua,13,pennefather street,greenlake,joondanna,2605,act,19450501,4072887 +rec-1956-dup-0,caleb,petersen,4,grant crescent,kenbar,kellyville,5067,nsw,19051226,8942423 +rec-4439-dup-0,laar,mccowajt,15,dumas street,westholme,dimboola,3041,qld,19911218,8213647 +rec-3190-dup-0,catilin,grimm,10,beaumonts beach house,yapunyah street,bethania,3350,vic,19520809,9350011 +rec-1078-dup-0,kyle,genovese,,harrington circuit,anzac house (cnr archer s street,port luincoln,4725,vic,19780802,8478623 +rec-4146-dup-0,emiily,maorus,42,short place,eventide homes,dolphin heads,3182,vic,19151031,9458847 +rec-2987-dup-0,tiahnee,moody,40,miethk e place,winterwood,north ward,3806,nsw,19130426,4744397 +rec-391-dup-0,noah,mason,29,william huson crescent,court funits,elwood,3155,sa,19500215,8353213 +rec-1734-dup-0,bethany,white,24,,hybernia park,bittern,3075,vic,19910219,8903580 +rec-2688-dup-0,riley,uyttemhowve,,outtrim avenue,gowrie,crows nest,2262,sa,19571232,1679030 +rec-2048-dup-0,georgia,vaccrao,18,rocor,leahy coose,maribyrnong,3124,nsw,19381228,2725753 +rec-4955-dup-0,callum,hauser,22,nambir court,zeevoo,mount annan,2641,vco,19581220,3757652 +rec-2021-dup-0,capurso,angelica,3,heales place,coulter court,mclarenyvale,2166,act,19840719,7201624 +rec-4273-dup-0,emma,smolcki,13,bengee place,,loxton north,3216,sa,19031203,8181500 +rec-1471-dup-0,dylan,robson,60,grimshaw treet,wallendoo n station,slack screek,3199,sa,19741003,4302323 +rec-2350-dup-0,lodge,adele,29,stacy street,,menangle,2765,nsw,19041015,9298526 +rec-3162-dup-0,lachlan,rees,25,darwinia terrace,,ulverstone,3162,vic,19131017,1414477 +rec-1773-dup-0,lim,haggett,64,macpherson street,,minto,6201,qld,19550910,5068609 +rec-3704-dup-0,jorn,finlay,108,kuhn place,kersley mews,,3081,qld,19771208,9133711 +rec-3468-dup-0,elizabeth,browne,11,carina shreet,ocean pinex caravn park,flinders park,2487,vic,19061213,2560358 +rec-2468-dup-0,magnus,grainer,7,kardang street,carrington retirement,moe,3042,vic,19970829,7094597 +rec-1338-dup-0,georgia,benger,1,mccay p lace,braeburn,pimpama,2153,nsw,19830402,3445535 +rec-4971-dup-0,william,white,34,mortlock circuit,ponder ossa,chinchilla,3156,sa,19800517,1549841 +rec-1504-dup-0,kailey,gazzola,2,napierclose,banddra,sanctuary point,2830,nsw,19340729,5402689 +rec-3244-dup-0,alexander,,11,eaglemont retreat,tarqua,dapta,3087,vic,19972108,7688076 +rec-2544-dup-0,tarau,mahon,5,,boronia,slacks creek,2146,nsw,19040909,2226255 +rec-986-dup-0,daniel,pryer,9,iowanna,callistercrescent,taree,4123,nsw,19380318,4294799 +rec-466-dup-0,rhjys,stubbs,155,cockle street,teralba caravn park,marsden,3148,qld,19931202,8594688 +rec-52-dup-0,abbye,dixon,1,marcus clarke street,grasmere park,scarborough,3141,qld,19441008,8127929 +rec-553-dup-0,nicola,bishop,15,knoxstreet,nyngan,hurstvillemsouth,3116,aw,19770427,2727947 +rec-1684-dup-0,gu,gissing,13,barber crescent,nyarrin cottage,tully,4151,vic,19210115,3954831 +rec-2288-dup-0,jhoel,green,708,wangarastreet,gallagher house,burpengary,4670,qld,,9018656 +rec-273-dup-0,emiily,stanley,9,spofforth street,thefal ls,sherwood,3150,nsw,19381021,7253600 +rec-4191-dup-0,liom,ryan,82,freeling c rescent,ryhd-talog,murarrie,2650,nsw,19601106,2586667 +rec-3595-dup-0,tiarna,chestnut,7,lee-steere crescent,river mews,burpengary,4132,nsw,19850302,6789617 +rec-4545-dup-0,riley,moubarak,,hagen place,noolabi,auubrn,6007,vic,19400916,5023399 +rec-1649-dup-0,joel,dixon,19,callistere crescent,glenmore,burpengary,3190,nsw,19810902,7849806 +rec-3900-dup-0,kati,jolly,26,reuther street,aprtmt 34,,2780,nsw,19690224,4300643 +rec-4552-dup-0,sophie,mason,22,sturgessi place,acadia,pacific paradise,3215,nsw,19790301,2531438 +rec-2921-dup-0,eden,clarke,1,towns crescent,tall ipnes,elimbah,3076,wa,19351223,9713955 +rec-3628-dup-0,indyana,gazzola,,trott place,central park,thornbury,3187,nsw,19911106,6670654 +rec-3351-dup-0,ada,reid,,disney court,,tea tree gully,3690,nsw,19550102,8441272 +rec-4278-dup-0,sophie,bevis,8,bungonia street,fernlea,ringwood east,2514,vic,19820602,4133682 +rec-2237-dup-0,ebonfy,garcia,,rylah crescent,,waratah west,7310,tas,19630715,9950832 +rec-81-dup-0,daniele,burford,71,waddell place,pine view,june,4055,qld,,3005084 +rec-1691-dup-0,pascajle,,33,killarney,kingham place,robertson,2135,wa,19570201,3879701 +rec-2473-dup-0,chelwea,,18,crisp circuit,walnut grove estate,seven hills,6311,nsw,19040215,4172992 +rec-2722-dup-0,,beattie,56,howchin place,,mount isa,3921,vic,19980913,3509530 +rec-2055-dup-0,taiz,garven,,finniss crescent,donetted owns,pymble,2035,nsw,19930723,6253715 +rec-2113-dup-0,jaxin,jolly,77,moontap lace,merrimac heights,bull creek,4011,sa,19250202,7133472 +rec-3935-dup-0,whte,tarnee,22,max henry crescent,maf-ue arabians,ballarat,2680,nsw,19501101,4846207 +rec-1599-dup-0,abbey,robsn,9,burrendong street,ashell,toukley,4000,nsw,19441016,6090364 +rec-4933-dup-0,hudson,caine,19,mackellar crescent,judy's creek,,2130,nsw,19490406,7689320 +rec-2129-dup-0,billy,verrion,163,mackenzie street,silverdal south,carlingford,0880,nsw,19301223,6708080 +rec-2026-dup-0,ethan,matsoin,310,bennevis estate,worrall street,albion park rail,3672,qld,19830111,3451352 +rec-1574-dup-0,zarran,mcsorley,28,hollwaystreet,orana gardens retirement village,burraneer,7051,nsw,19170409,2480177 +rec-4265-dup-0,jasmine,hope,32,jaques pl ace,specialist centre,,2611,vic,19380418,2006619 +rec-2357-dup-0,kirrah,cannell,12,cherry street,gloccanorra,,4170,nsw,19511103,1567556 +rec-2736-dup-0,bayden,lonei,37,callister crescent,mcdougall hill,burowod,2320,nsw,19880619,6874557 +rec-2595-dup-0,jasper,bowerman,3,newlopstreet,byron arcade,burleigh neads,6016,tas,19390710,1880798 +rec-2553-dup-0,brayden,coleman,21,paul coecrescent,westfalls,greenwith,5047,vic,19500606,1790784 +rec-653-dup-0,nicholas,pontt,27,bulli place,wattle mount,new farm,2750,vic,19570101,3411264 +rec-2701-dup-0,keelin,kalnins,2,ellerston avenue,,berwick,2022,nsw,19621011,7541911 +rec-1429-dup-0,katelyn,dixon,8,melba street,surfsied park,auburn,3104,nsw,19730618,2599418 +rec-4286-dup-0,carly,honeychurch,,dalley crescent,john flynn medical centre,oakville,4700,sa,,3359709 +rec-2090-dup-0,mcmellpn,aiden,10,cromwellcircuit,redwoo dlodge,wanneroo,2666,vic,19301206,9452274 +rec-2727-dup-0,noyce,liam,13,walkercrescent,acadia,pengun,2332,qld,19520621,7975425 +rec-1851-dup-0,ava,ryna,5,gratton place,corlela,noble park,4184,vic,19710805,9223546 +rec-2628-dup-0,nathan,paterason,47,allambee street,tamaview,barwon heads,2317,vic,19811021,9877542 +rec-2958-dup-0,liyl,clarke,11,,sun village,magill,3204,vic,19200906,6916349 +rec-1568-dup-0,connor,vincent,,woolner circuit,,geraldton,2560,qld,19811218,9810666 +rec-1466-dup-0,william,stanley,10,benbullen lowline stud,steffanoni circuit,ranelagh,3148,nsw,19260501,1891847 +rec-1908-dup-0,chloe,white,91,phillip avenue,av enel,toowoomba,3550,qld,19520722,2709559 +rec-1856-dup-0,isabella,laxrge,5,hayball place,hawkhurst cottage,mount stuart,6017,nsw,19541211,6608468 +rec-3474-dup-0,josephine,gallio,23,marsden street,sunnydalecottage,blacktown,2753,qld,19230227,8542303 +rec-4413-dup-0,cameron,white,178,carliles treet,laureldale,harris park,6180,nsw,19470605,1655664 +rec-912-dup-0,leo,george,38,langridge street,gree nwood,braidwood,2038,nsw,19631227,2248611 +rec-1139-dup-0,prudence,monmco,8,barracloughccrescent,glendaurel,midland,4017,wa,19060919,2264092 +rec-4235-dup-0,,swoboda,14,sue geh circuit,brumptonstreet,katherine,4740,nsw,19931215,1635174 +rec-2555-dup-0,james,webb,15,chapman street,fl r3,lutwyche,4032,sa,19320926,3970231 +rec-1867-dup-0,esme,schembri,12,burhop close,girrahween homestead,ngunnawal,5158,qld,19550429,2492474 +rec-669-dup-0,chelxea,rusan,50,osburn drive,hansonse state,puncbhowl,4869,nsw,19091017,6615930 +rec-1368-dup-0,matteus,leong,31,hawkesburyfcrescent,bonni e doon,raymond terrace,3129,qld,19621228,5792923 +rec-1252-dup-0,andrew,matthews,14,banfield street,caprkce,nowra,6306,qld,19340330,7762803 +rec-3300-dup-0,ayden,finlay,6,holyman street,milmilland,cowa,2225,nsw,19740203,5706958 +rec-3902-dup-0,,oreilly,,paul coe cerscent,wylrah,tuart hill,3219,vic,19500925,4201497 +rec-3568-dup-0,wilson,coleman,35,vidal stteet,knmre street,kelmscott,4805,sa,19880715,5954966 +rec-159-dup-0,connor,toms,22,taggerty street,vivi gani,malvern east,7310,qld,19991026,6008369 +rec-4214-dup-0,george,ka,8,,australia fair medical west centre,auburn,7325,vic,19041031,8708132 +rec-882-dup-0,sarah,eyles,34,badgery s treet,yarrallah,gailes,0810,qld,19760516,5129649 +rec-4358-dup-0,jessica,stesrnes,201,lister crehscent,redfern station,seaofrth,4154,qld,19440928,7272157 +rec-1942-dup-0,jessica,mccarthy,131,eagle circuit,sherwo od,eight mile plains,0812,sa,19341117,3738391 +rec-1434-dup-0,sarah,mccartnhy,38,nealie place,sunny braes,north ward,4017,qld,19130115,6511805 +rec-1383-dup-0,trinity,coulson,45,horsley descent,wigla,para hills,3056,nsw,19920226,4445753 +rec-1653-dup-0,shauni,cristoain,5,burbidge crescent,,lower chiktering,3962,nsw,19640825,5841667 +rec-4864-dup-0,thomas,campbell,45,windich street,spring vale,blactkown,7304,nsw,19640105,4359063 +rec-4262-dup-0,ellen,nguyen,63,burdon p lace,hillendale,semaphore park,4216,nsw,19030711,8122850 +rec-2574-dup-0,jacorb,hewson,32,telooma,hambidge crescent,tallangatta,2800,qld,19460104,3624543 +rec-1020-dup-0,phillip,finkay,,maclachla n astreet,arcadia,pottsville,6171,qld,19080623,5324023 +rec-247-dup-0,bret,falcione,,burdekin avenue,berragoon,pennant hills,4114,nsw,19890803,3152019 +rec-4534-dup-0,casey,hobson,10,limestone avenue,clark brae,warilla,2614,nsw,19280928,6436995 +rec-1507-dup-0,dominc,woodmansee,500,sculptor street,calleen farm,punchbowl,6111,nsw,19170707,4369787 +rec-4250-dup-0,mhary,matthews,26,foxall street,upper yarrowitch,newcaslte,6525,vic,19540913,2983255 +rec-1799-dup-0,,shepherd,11,sprent sftreet,orange specialistbmedical centre,taree,0812,nsw,19121023,6769513 +rec-2450-dup-0,thomas,wykliej,512,brand street,ferndale,rossmoyne,5043,vic,19040823,9017484 +rec-2063-dup-0,maya,,11,tucana steeet,bombowlee,dianella,2795,nsw,19880218,2732680 +rec-2408-dup-0,tristan,aldous,11,solandef place,,goornong,4157,vic,19990121,5511852 +rec-1496-dup-0,gabriella,shadbolt,10,tenison-woods circuit,villa 5,maitlnd,3918,vic,19100320,1897470 +rec-1515-dup-0,chloe,pamflia,10,balaun place,hornsbie,taree,5037,nsw,19210412,6788630 +rec-4591-dup-0,carlin,zordjan,,burnie street,kangaroo creek,,2213,nsw,19070620,1373412 +rec-2993-dup-0,amf,tiggeuan,3,dugdale street,,rosealnds,3840,vic,19740926,9867216 +rec-1768-dup-0,caleb,deakin,15,clem hill street,rowethrope,craigmore,4285,nsw,19830721,2238546 +rec-4272-dup-0,coopez,marinos,32,madigan street,fig tr ees,mayfield,3944,nsw,19700719,6708332 +rec-4228-dup-0,amber,reid,3,hedleystreet,westehram,bibra lake,6108,vin,19449015,9481816 +rec-3177-dup-0,harvey,purser,184,osburn crive,,mulyandry,2680,,19970208,8501583 +rec-1815-dup-0,alias,spratt,16,wild sttreet,ashbank,seaton,4301,sa,19920328,6548039 +rec-1393-dup-0,speight,matthew,8,worrall treet,,lowerbeechmont,6230,sa,19590301,1641889 +rec-4205-dup-0,caityn,millar,38,tullaroop s treet,,macgregor,2343,vic,19940917,8863827 +rec-808-dup-0,philps,tai,17,burrendong street,el-wooadaro,rokeby,6258,nsw,19610906,2863233 +rec-3565-dup-0,shai,,13,morant circuit,stone oak farm,maitland,9205,vic,19151011,5824638 +rec-3150-dup-0,charles,eileen,330,baldwin drive,fern cliff,preston,3155,vic,19841207,9552166 +rec-4039-dup-0,talissa,macgowan,31,fairfax street,rosettavillage,mitcham,5290,qld,19230318,7084722 +rec-3647-dup-0,natalia,gilles,32,rapanea ttreet,locn3439,alice springs,4121,qld,19520330,2026502 +rec-4871-dup-0,casey,croker,137,summervillecrescent,shalestoe,wanniassa,2602,sa,19471226,3095657 +rec-3976-dup-0,tizna,stanley,109,haswell place,,surfersparadise,2196,nsw,19091118,7519489 +rec-560-dup-0,caitlin,bossence,58,aston creqscent,greenslopes,condell park,3023,nsw,19040426,7998798 +rec-1719-dup-0,,mohammadi,30,propsting street,,surrey hills,4560,vic,19721222,7654499 +rec-1934-dup-0,broc,ewan,8,warramboplclose,hawkins masonic vlge,mountveliza,3021,nsw,19161123,3522578 +rec-712-dup-0,emam,geue,1220,rumker place,milbrodale,woodend,2429,nsw,19941224,3886398 +rec-1579-dup-0,robert,leane,8,green street,court units,broadbeadh waters,4128,vic,19880611,3938828 +rec-4474-dup-0,sarah,roas,11,kangaroo court,glen shiel,wamberao,3144,vic,19330424,3530952 +rec-2354-dup-0,connor,shepherd,7,bulloo place,,wyoming,4621,wa,19100906,1737778 +rec-1072-dup-0,samuel,dixon,13,appel crescent,mulv ra,orchard hills,3073,wa,19840925,4689881 +rec-1408-dup-0,kierra,harrington,45,shepherdson place,oakdale,rye,4127,qld,19031001,9648034 +rec-62-dup-0,jake,coleman,1,sturt avnue,rivonia,sunshine north,3058,naw,19450706,6061178 +rec-4016-dup-0,emiily,hingstxon,15,paul coe crescent,hawkesbury road,mooroolbark,2556,sa,19711319,4431563 +rec-233-dup-0,kirra,,47,seaborn place,pleasant acres,arundel,3073,nsw,19781119,3690427 +rec-3347-dup-0,willow,tsolakis,35,elsey street,kempfheld,low head,6196,vic,19200916,1293288 +rec-587-dup-0,lauren,musolino,35,beattie crescent,,bangor,2859,act,19891021,6356434 +rec-4622-dup-0,lachkan,mccarthy,9,william hudosncrescent,sheep station,greensblrough,2190,qld,19960516,1946829 +rec-2728-dup-0,lowe,chelsea,36,forbes street,nunkeri (cnr l inburn r road,trevallyn,3199,wa,19700524,5918591 +rec-3136-dup-0,pakita,o'shannessy,41,handasyde street,vil a 3,torquay,4878,qld,19270218,8599006 +rec-337-dup-0,jordan,morrison,45,churchlane,killarneyspark,albany creek,2770,nsw,19850727,4295797 +rec-3064-dup-0,jessie,rei,44,eureka,nambucca street,bundabreg,6111,wa,19020723,6219878 +rec-1254-dup-0,ryly,colombini,14,yambina cfescent,lourdesh ostel,lower templestowe,3148,nsw,19760717,1751137 +rec-689-dup-0,joshua,every,14,scoble place,hawkins msaonic vlge,gray,4212,nsw,19241220,9182595 +rec-4299-dup-0,braedon,pendle,484,naas groad,weeroonq,mount grvaatt,2614,vic,19070815,6759627 +rec-4458-dup-0,mackenzie,boocock,81,tipiloura street,ursulda,budgewoi,7027,nsw,19030720,6436554 +rec-1013-dup-0,gillian,pighin,2,hilderstreet,iron bark ridge,cooma,4508,nsw,19990501,6489507 +rec-85-dup-0,dakin,joselyn,57,aberneth ystreet,kanangra hostel,manundza,3028,wa,19261205,4852063 +rec-935-dup-0,alexndra,steers,108,chambers street,lochsnizort,bondi junction,6009,nsw,19620521,9899937 +rec-2252-dup-0,allegra,cobbin,19,abbott steet,palestine,glenside,3400,nsw,19690819,8391278 +rec-1983-dup-0,henry,coleman,42,mackaness place,lake downs super fine merino stud,benoaw,4557,tas,19791029,1714953 +rec-3392-dup-0,monana,musolino,12,herington street,st vincents medical centre,allora,2001,nsw,19591003,4382424 +rec-989-dup-0,pauk,fauser,6,bargang rescent,,dareton,2213,nsw,19540911,3667818 +rec-2109-dup-0,doman,matthwe,4,hinton place,blck 1809,raymond terrace,2146,vic,19740703,2775852 +rec-3840-dup-0,finn,baradakis,13,launceston street,ferndale,coolbellup,2323,qld,19281212,1284105 +rec-781-dup-0,jukic,jesse,174,dirrawan garden,cranbrook,coconut grove,2206,nsw,19411121,6016032 +rec-1290-dup-0,kirra,browne,26,shoalhaven avenue,loormeah park,surry hills,3042,tas,19403407,8221881 +rec-3159-dup-0,lewis,nguyen,5,jensen street,,cooroy,2251,,19071128,8628720 +rec-2185-dup-0,mia,garrigan,53,michie street,wesnholme,armidale,3178,nsw,19700522,6416070 +rec-3216-dup-0,charlotte,feeney,6,dangar place,brookfield,ermington,3128,nsw,19810505,9513852 +rec-1583-dup-0,isabella,elferih,61,moore steet,bangor lodge,dural,3044,vic,,4582565 +rec-4024-dup-0,katelin,wheatley,35,blakey close,derwent wtrs,hackham best,4515,,19130924,2489779 +rec-2914-dup-0,juliana,white,39,osburn drive,,st kilda east,6701,vic,19171013,3450613 +rec-3837-dup-0,lachlan,giredr,3,tiptree crescent,,toowoomba,2747,nsw,19070323,9886540 +rec-4681-dup-0,meg,matghews,42,mccawley street,vamzbi back,carlingford,6058,qld,19850331,6932257 +rec-3042-dup-0,lydia,,48,davis street,wychwood,eaglemont,3138,nsw,19370701,8755417 +rec-2672-dup-0,bianca,neumann,19,torres street,ainslie n ursing home,ascot vale,7000,wa,19801124,8402773 +rec-406-dup-0,chelsea,,186,spofforth street,,clare,2750,vic,19560408,9071776 +rec-1882-dup-0,max,lund,5,broome vacatoin village,syme crescent,aspley,6111,nsw,19011228,2696750 +rec-927-dup-0,claudia,white,76,willoughby crescent,green slopes,albion park rail,3178,wa,19810107,1170705 +rec-4234-dup-0,,lock,4,tauss place,argyle,woodcroft,2028,sa,19130105,6312603 +rec-4249-dup-0,yana,stanesby,8,the gums,blamey crescent,flinders park,7260,vic,19080415,9864532 +rec-829-dup-0,lucu,easlingx,97,mimosa close,the old p arsonage,manyana,3016,,19810520,5467025 +rec-413-dup-0,samuel,eglinton,17,tanumbirini street,birks harbour,raymond terrace,2176,vic,19690927,2802987 +rec-2683-dup-0,oliver,dent,39,noble place,bellam ib,strathalbyn,3088,sa,19051006,4438825 +rec-1547-dup-0,kiara,rawlings,46,john young crescent,glen rock,eastwood,3144,qld,19861016,8663646 +rec-2364-dup-0,ella,reinhard,128,woolls street,deswod,ulvertsone,6024,wa,19310610,7101829 +rec-3924-dup-0,haveobferg,emiily,2,dempster place,stonehouse,barwo nheads,2750,nsw,19480510,7123931 +rec-1302-dup-0,tiarna,mason,37,ames place,grandview,ashgrove,2077,sa,19700818,7346247 +rec-4822-dup-0,luke,geue,12,rockland s street,,allambie heights,6104,vic,19990508,8840914 +rec-1763-dup-0,jacon,george,80,hindmarsh drive,glenview,bundaberg,2021,wa,19631006,3031916 +rec-613-dup-0,oliver,tootell,363,shackletonicircuit,,cardiff,3812,vic,19000604,8984164 +rec-1182-dup-0,ella,wasley,58,guthridge crescent,crown a llotment,carole park,5115,nsw,19411214,3051473 +rec-225-dup-0,isabella,sanby,18,veale street,wongowmal,west swan,3066,nsw,19181010,7757358 +rec-4457-dup-0,charlotte,hathaway,5,hartung crescent,anzac house (cn r rcher s street,broken hill,6060,qld,19740418,2652077 +rec-2079-dup-0,kira,,29,athertoh street,kiya,londonderry,3756,nsw,19230214,9919791 +rec-3160-dup-0,,pringle,46,woodfulldloop,,woori yallock,6101,vic,19250210,4259044 +rec-3241-dup-0,tara,o'shannessy,233,osburn d rive,,maitlnd,2640,nsw,19380807,4654746 +rec-4219-dup-0,,goode,23,cane place,cukbone,manly bale,2602,vic,19840402,7430736 +rec-51-dup-0,adam,,37,freda gibson circuit,cryode,paddington,2770,sa,19401209,3593307 +rec-169-dup-0,nicola,leonardi,22,,crown cahmners,rwy,2299,nsw,19170219,3568632 +rec-3723-dup-0,lara,carbpne,61,aston crescent,ebony's tetreat,bossley park,5334,vic,19560105,2542464 +rec-2660-dup-0,munyarryun,alexander,13,allambee street,,moranbah,4218,qld,19551107,9890402 +rec-4469-dup-0,josephine,dragheim,3,downard street,lowangrdeen,malvern east,3124,qld,19160218,2093181 +rec-2754-dup-0,ellen,schumann,51,barr-smith avenue,,ridleyton,4034,qld,19610507,1287031 +rec-3154-dup-0,samantha,howie,6,mauldon street,environa,palmview,4253,act,19840918,3489071 +rec-2489-dup-0,grteen,thomas,10,dumas street,bonnie doon,innaloo,5104,nsw,19340204,6817957 +rec-1917-dup-0,flockahrt,jasper,25,,briardale,modbury,4035,,19211017,2278318 +rec-1311-dup-0,tyron,klemm,43,clem hill street,,st kilda,4205,qld,19751020,5119969 +rec-777-dup-0,charlotte,nedeham,183,wattle st reet,courallie,colo vale,3161,sa,19890118,2377987 +rec-2837-dup-0,raquel,mason,1,storey s treet,,,3225,qld,19341010,1823323 +rec-1516-dup-0,trey,goetdze,4,petterd street,bonnu doon,brighton,7054,vic,19250118,1744778 +rec-1589-dup-0,emma,frencham,157,hayball place,,punchbowl,4018,qld,19170628,2070987 +rec-1017-dup-0,jack,paterson,24,gleadow street,st francis vlge,wahroonga,3501,nsw,19641002,2532475 +rec-1049-dup-0,amy,urenea,3,verbruggh en street,narraburrj lodge,riverwood,4610,vic,19040320,4689528 +rec-439-dup-0,mia,kam p,55,jardine street,gonzaga,pooraka,2161,sa,19400617,1084495 +rec-4182-dup-0,georg,noble,1188,willandra,fawkner street,ormeau,3199,qld,19430912,7672726 +rec-3805-dup-0,leah,swoboda,33,macnaughotn street,woodrose,tweed heads,6069,vic,19821102,9528232 +rec-1135-dup-0,dylan,oatey,,barringer street,thur limbah,avalon,2217,vic,19441106,7915328 +rec-1079-dup-0,jessica,robson,337,marcus clarke street,macar thur,vermont,3429,nsw,19790719,6293706 +rec-2036-dup-0,emiily,capel,1721,burkitts treet,locn 1025,ascot vale,4053,nsw,19341111,4646376 +rec-356-dup-0,zack,brock,,top nass,,hyde park,4740,nsw,19130124,8703977 +rec-96-dup-0,georbe,macah,25,tepper ircuit,erinsr est,mooroola,2758,vic,19270326,8072800 +rec-2111-dup-0,matteus,wilde,13,cumberleg ecrescent,,bourke,4740,qld,19260702,7889277 +rec-835-dup-0,lily,egain,526,louis loder street,,alfords point,3031,sa,19610514,2519145 +rec-778-dup-0,gianni,jolly,83,glencross stteet,locn 10045,booval,2260,wa,19740903,3966573 +rec-4280-dup-0,lauren,ferri,121,hedgerstreet,,banypo,3150,wa,19440118,9553756 +rec-2795-dup-0,talfiah,bunug ugrr,18,eldridge street,drayton,wallsend,2031,qld,19760404,1387033 +rec-246-dup-0,hayley,morrion,35,kirkwood crescent,vill a 183,sprin gwood,2396,vic,19000326,8113043 +rec-1940-dup-0,pace,nguyen,352,marquet retreat,joint co al board,labrador,3064,sa,19670320,2038425 +rec-193-dup-0,ethan,nguyen,1932,lodder lpace,tobr uk hse,clayfield,4405,tas,19971105,1140575 +rec-2474-dup-0,tansy,carp,42,fiveash street,blueberry,loxton north,3551,wa,19360605,5801878 +rec-3796-dup-0,silo,zac,2,medley tsreet,gundaline,mitcham,2767,vic,19611116,4048723 +rec-2514-dup-0,ayla,poor,11,cowdery lpace,richmond caravan park,burwood east,2200,nsw,19200801,8015794 +rec-3095-dup-0,billy,gighey,382,westall fplace,willraoo,moree,2037,qld,19130824,4206687 +rec-3024-dup-0,michaela,wilkns,2,,robley house,jamdstown,3782,nsw,19390517,4477585 +rec-960-dup-0,benjamin,berry,4,glenmaggie street,trewilga,kariong,3064,nsw,19220905,3664258 +rec-2287-dup-0,lucas,pascoe,163,tepper circuit,,corlette,4213,nsw,19350308,5399636 +rec-3534-dup-0,chrisitan,jolta,2,jerrabomberra avenue,yambungan station,cecil gills,4702,vic,19481117,6961701 +rec-4097-dup-0,,noble,5,belgravia estate,carnegie crescent,glenwoyod,5119,vic,19120724,8141708 +rec-3276-dup-0,joseph,wynne,26,matina street,lucky corner,kirra,7054,nsw,19491211,6433640 +rec-2088-dup-0,andrew,webb,,lukin place,criaglea,south brisbane,2050,vic,19001025,2313225 +rec-4243-dup-0,harry,pembroke,138,sparkes close,st georges medcial centre,sutton forest,3383,qld,19260311,6618265 +rec-2742-dup-0,jaiden,o'flynn,9,eve place,pioneerb lodge,goovigen,6136,nsw,19330911,4353748 +rec-418-dup-0,simone,goz,313,marconi crescent,alabama,bayswater,3209,vic,19080313,1331839 +rec-3784-dup-0,connor,hammill,99,goyder street,,angsgon,2304,nsw,,7089797 +rec-455-dup-0,jia,fenwicsk,7,churchill way,greenskopes,seven hills,2449,vic,19760830,3991391 +rec-3238-dup-0,jamie,snell,36,krefft street,,deakin,7307,vic,19850205,9378445 +rec-4919-dup-0,mia,jolly,,findlay street,hayfield vlge,kincumber,3995,qld,19171012,8801194 +rec-3038-dup-0,xavier,mogavero,10,epenarra close,ramuda,west wolongong,3148,vic,19121210,2534734 +rec-870-dup-0,jesisca,bradshaw,91,wheadon stpreet,yarrabin,minyip,2290,nsw,19080415,5572327 +rec-4516-dup-0,chlsea,blake,35,southern cross drive,,belconnen,3141,vic,19770311,8747454 +rec-605-dup-0,jayde,mccarthy,13,chateau t ahbilk,bywater s place,prospect,3198,qle,19381120,8148821 +rec-4207-dup-0,shepherd,lachaln,9,dalley crescent,grandqview,suffolk park,3550,tas,19900821,8396396 +rec-2076-dup-0,benjamin,kapioldassis,199,farrelly close,texass wtation,goodwood,3197,nsw,19860801,6377421 +rec-1286-dup-0,jasmine,ryan,10,piddington street,tregona,sunshine beach,2108,nsw,19621124,4721073 +rec-1606-dup-0,talan,dietrich,35,hacking crescent,tall pines,mosmtn,2903,vic,19490712,9469771 +rec-1597-dup-0,april,durbrige,20,wilkinson street,,toolleen,3630,sa,,3179675 +rec-34-dup-0,mollie,castelleri,5,jackiehowe crescent,,ardmona,3976,wa,19760616,1378454 +rec-4489-dup-0,emiil,bishop,12,,pine dale,vermont,2088,wa,19730322,3947458 +rec-3512-dup-0,alex,webb,92,outtrim avenue,st francis village,paddington,3056,nsw,19700807,5595371 +rec-2142-dup-0,sarah,leslae,740,baddeley crescent,flt 10,jamboree heights,4053,vic,19110604,7593106 +rec-4364-dup-0,harry,boyes,,kadina crrscent,hobbit hole,regents park,3199,qld,19505309,6388424 +rec-4340-dup-0,jolly,kiana,23,ashcroft crescent,vil lao2,airds,4507,wa,19220507,6113261 +rec-3604-dup-0,wil,clarke,8,osburn drive,guest village (cnr ubllcreek d drive,chelsea heights,5700,nsw,19100504,2181436 +rec-1700-dup-0,noah,stephenson,1,vagabond crescent,,northbridge,3166,nsw,19691102,4406709 +rec-4054-dup-0,,dojcic,15,barracloug h crescent,brookvale,tplga,2205,qld,19990331,7180230 +rec-1087-dup-0,mitchell,tien,23,padbury street,greenslopes,concord,3429,nsw,19780903,6760018 +rec-1837-dup-0,jacinta,webb,108,rodway street,2nd last on right,gawler giver,2019,vic,19560708,3880973 +rec-3719-dup-0,connor,bailke,186,lambie place,,port lincoln,7303,qld,19670529,4702335 +rec-2344-dup-0,rhett,boxer,19,langlands close,roweetohrpe,mont albert,5353,qld,19150512,7303507 +rec-3174-dup-0,jasmine,web,1,duffy street,,parkside,2105,vic,19440610,1750989 +rec-3173-dup-0,carmen,wisemdan,2,sherwin place,wangi shoppng centre,newborough,2216,wa,19000714,2741568 +rec-4295-dup-0,james,rawlings,268,sheaffe street,bella dona,caulfield north,2117,nsw,19890331,9598556 +rec-2472-dup-0,amy,campbell,7,kinchela cerscent,aceland pollh ereford stud,swan hill,4753,qld,19021030,2533567 +rec-3262-dup-0,alia,haydock-wilson,6,croton street,kimberley,the ecntrance,3132,nsw,19901212,3171888 +rec-267-dup-0,liam,whiitn,33,hargrave street,buderim emadows,,7250,nsw,19141012,6654477 +rec-1447-dup-0,alexadnra,alderson,4,arkell place,tooalooa,clarnida,3764,vic,19230610,3671723 +rec-274-dup-0,erin,clarke,96,teakle place,,granville,3040,wa,19170313,8286533 +rec-4897-dup-0,brooke,klimowski,4,beasley street,dungna von,woree,4113,nsw,19140805,6086531 +rec-537-dup-0,maliah,clarkd,26,broadben tdtreet,harlyn,tara,6151,sa,19190118,7298583 +rec-4206-dup-0,bottrof,samuel,23,mclarty court,cherrybank,port macquarie,6024,sa,19420214,5990041 +rec-795-dup-0,eboni,,11,de burkgh street,tamaram a,keiraville,3356,vic,19000707,4335060 +rec-3251-dup-0,lachlisn,de angelis,85,goldfinchl circuit,glenarthur,gulnare,2074,vic,19881114,8569316 +rec-3675-dup-0,meg,bluneh,602,allchin circuit,lingqdle,ballarat,0801,qld,19470831,7587560 +rec-2481-dup-0,gabriella,carraull,48,griffiths street,rosehill,quilpie,5108,nsw,19071031,8145441 +rec-2583-dup-0,mia,leaver,2,jennings street,miranda,taile m bend,3636,nsw,19960425,7346590 +rec-364-dup-0,reganne,mayrr,47,,fraserlodge,marsfield,4161,vic,19741017,8978233 +rec-425-dup-0,psorakis,shantal,61,barcoo place,stonyridge,hawtnhorn,2324,vic,19850722,6633125 +rec-840-dup-0,noash,nguyen,9,carrollstreet,locn 10045,eastqood,7053,sa,19101127,2142666 +rec-3592-dup-0,reganne,camp,4,colvin street,pin e hill,pymdnle,2010,nsw,19681013,1236601 +rec-2593-dup-0,harrz,pardey,86,launceston street,ainslie house,hillston,2478,tas,,3922548 +rec-1912-dup-0,mackenzie,sherriff,34,pirani lace,,scarborough,2049,nsw,19610123,8088200 +rec-3629-dup-0,isabella,campbell,101,clive steele avenue,old hillside,,2913,qld,19890501,2285966 +rec-1976-dup-0,amy,moyse,60,jackie howe crescent,,sylvani,2571,vic,19740103,7813497 +rec-2208-dup-0,lauren,hainke,2,la perouse street,rhode isladn resort,old erowal bay,4550,qld,19040319,8687104 +rec-3633-dup-0,ryleh,everett,9,,,sandy bay,2484,nsw,,1791300 +rec-2872-dup-0,renee,havrda,51,salimtal,cuthbertson crescent,firle,5089,vic,19500910,3898443 +rec-2438-dup-0,ashley,clutteebuck,26,freda gibson circuit,,,3029,vic,19920810,4483745 +rec-974-dup-0,caitliun,luckens,180,ortloff place,brokenspoke,ryde,4051,qld,19640720,3391457 +rec-1199-dup-0,kobe,tillaer,106,stuartstreet,yarrandalne moonee,douglas park,4573,wa,19300831,2715828 +rec-2512-dup-0,,hyland,86,flanagan street,dodonae a wing,boyup brook,2032,qld,19840708,5354642 +rec-3121-dup-0,megan,hunns,37,blackbur n street,lazy acres,bassendean,3070,qld,19430114,2634931 +rec-1672-dup-0,jacobie,shepherdson,316,augusta court,pnda,ardeer,5069,nt,19830606,2226979 +rec-4706-dup-0,aidyn,eisner,60,melrose drive,stoney creek,shelely,6063,sa,19101228,6588394 +rec-4740-dup-0,sach,henry,69,hawdon street,logie brae,harbord,2141,nsw,19051226,7123737 +rec-3100-dup-0,brody,nguyen,93,,mt derriwong,lauderdale,2153,wa,19970629,2691340 +rec-3175-dup-0,alexandra,bsihop,2,black street,leetsvale catavan park,huonille,3885,nsw,19610813,8253150 +rec-2105-dup-0,holly,weh,64,gooromon ponds road,ainslie house,gorokan,2234,qld,,9292420 +rec-4467-dup-0,oliver,rundle,82,priddle s treet,myross,dural,2601,nsw,,2156141 +rec-1212-dup-0,jasmine,pavli,44,fellow sstreet,little pines,woodville south,6230,sa,19610408,7668302 +rec-1770-dup-0,jessia,boyes,27,molloy crescent,sec 1569,scarborough,4551,tas,19610514,7635289 +rec-1197-dup-0,deakin,peachey,16,officer crescent,tes bury,nollamara,2144,tas,,3378938 +rec-1411-dup-0,,thredgold,3,antill s treet,monavale,charlestown,2389,nt,19390828,3707828 +rec-2366-dup-0,degeorge,sameul,2,jefferis street,,nedlands,2206,vic,19510912,1167786 +rec-2249-dup-0,emiily,miels,15,dartnell street,murrawarra,woodgate,7310,tas,19280417,6959390 +rec-2558-dup-0,tyler,doan,189,staaten crescent,,kingsford,6059,qld,19822028,6683175 +rec-1360-dup-0,charlotte,clarke,9,captain cook crescent,nara cottage,yarraville,2099,,19470305,9614637 +rec-1224-dup-0,harry,reid,15,kalgoorlie crescent,aldersydeestate,new town,2077,sa,19460708,5924879 +rec-1309-dup-0,zoe,szepessy,,creswell street,laguna estate,narooma,2430,nsw,19330212,1322282 +rec-1694-dup-0,mhary,siemon,13,latchford street,mountviebw,broadmeadows,6170,vic,19020804,9452510 +rec-789-dup-0,pakiita,alderson,17,canberra centre (next to medicare),tinaro ofalls,brighton-oe-sands,2496,sa,19710808,6651007 +rec-4650-dup-0,andrew,marlow,43,,,ashfiel d,2780,nsw,19550903,4126078 +rec-3454-dup-0,heath,menard,4,,yarrimwbah,port broughton,2650,nsw,19220820,3136077 +rec-4524-dup-0,michael,coulson,78,,,marsden,3546,vic,19680508,6597953 +rec-2032-dup-0,noack,madeleine,44,forbes street,woodsong,coombbaah,7320,,19490830,2378967 +rec-1345-dup-0,zachary,coffye,21,fellows street,brigalow court,kariong,5301,qld,19240219,4912880 +rec-2734-dup-0,grace,green,8,nagara street,,nullawarre,2540,nsw,19771008,9946309 +rec-3750-dup-0,jacob,byrt,1199,binyap lace,,wallsed,3155,wa,19429008,7691324 +rec-1279-dup-0,,clarke,3,hindmarsh drive,,greenwood,2061,sa,19440126,8957090 +rec-379-dup-0,chloe,herbert,30,canberra avenue,bombowzee,humpty doo,5082,vic,19791208,1380182 +rec-4068-dup-0,matilda,snell,19,grylls crescent,family da y care,trevallyn,3186,vic,19870819,3860203 +rec-740-dup-0,prudence,redi,13,ashkanasy crescent,victoria mill estate,kirribilli,6163,vic,19950117,6754135 +rec-208-dup-0,harriet,moldand,43,,sheep station,bridgeman downs,6053,nsw,19760523,9418691 +rec-857-dup-0,courmtey,benger,15,callaway crescent,flight springs,canterbury,6059,qld,19101114,3489916 +rec-1256-dup-0,emiily,mees,29,campbell street,,elwood,3805,wa,19301201,4611758 +rec-1621-dup-0,alexandra,hyland,20,brassey street,unt 3,bundaberg,3049,qld,19030202,9741543 +rec-1307-dup-0,danielle,campbell,582,paul coe crescent,ningana,bronte,3156,nsw,19531121,2695021 +rec-1323-dup-0,steinert,jack,61,french street,meadows estate,adamstown,4350,vic,19460712,1716280 +rec-3180-dup-0,samuel,paterson,4,garran place,sunnyside ocrhards,yarriaville,2111,nsw,19620306,3308420 +rec-3105-dup-0,jacqueline,webb,8,kitchener street,herbert iver,batlow,3019,vic,19370226,5963832 +rec-1988-dup-0,joshua,jollu,815,benbullen lwwlline stud,kingston street,thornlie,2546,qld,19200423,1559039 +rec-682-dup-0,kane,ahier,47,farncomb place,glenyurst,,3083,qld,19031104,8076744 +rec-320-dup-0,capurso,ruby,7,erldunda circuit,bellbirdctge,jan juc,6233,vic,,4086300 +rec-2002-dup-0,nichohlas,rees,24,murrell place,harriman park,hemmant,5162,nsw,19350408,3061813 +rec-1930-dup-0,,teag ue,38,emily bulcock crescent,locn 341,caulfidld,2041,nsw,19900523,1754920 +rec-35-dup-0,kiandra,lock,33,dampier vrescent,kalang,cardiff,3500,qld,19330410,1004953 +rec-1555-dup-0,jaykob,cochrane,1,fowler place,sugdencglen,tweed heads,4504,nsw,19390209,7792214 +rec-75-dup-0,lachlan,webb,19,national circuit,,lockyer,7250,qld,19370423,4001224 +rec-2206-dup-0,shorrock,ambrosia,2,amess place,arlinoton,macmasterds beach,3523,nsw,19921231,8411190 +rec-403-dup-0,stoneman,marcus,273,pankhurst crescent,glenfenzie,joondalup,2126,nsw,19200506,3830720 +rec-1563-dup-0,racxe,jukic,9,blandln place,cleaf creek,kangaroozflat,2229,wa,19050108,2851372 +rec-2800-dup-0,,crook,16,nardoo crescent,,campbelltown,2325,nsw,,2308429 +rec-4491-dup-0,plane,warrick,41,lingiari court,,noosa river heights,6107,vic,19860411,3214712 +rec-3650-dup-0,clarke,matthew,95,crombie place,dandarra,oak flats,3170,nsw,,8347782 +rec-2778-dup-0,jack,morell,74,horrocks street,ulinga,toorak,2000,vic,19371114,2710625 +rec-1389-dup-0,lily,reid,,,claymore springs,yarraville,3138,vic,19200219,9147920 +rec-1537-dup-0,max,joloy,23,buvelot street,raaf,mooloolaba,3156,wa,,8870856 +rec-4431-dup-0,hayley,roles,269,newlop street,rabbitiwarren,acacia ridge,7270,vic,19581005,7340730 +rec-232-dup-0,nicholas,george,,hall street,rhode island resort,brighton,3264,nsw,19920715,3273376 +rec-259-dup-0,matisse,chandelr,362,mcbryde crescent,21st,gowrie,3498,wa,19980731,5696159 +rec-528-dup-0,copp,troy,32,chinner c rescent,huntington,dural,6105,nsw,19921025,8516174 +rec-4435-dup-0,isabella,dolby,16,hodgson cres cent,break-o-day,dawpark,4304,qld,19030725,7732123 +rec-832-dup-0,benamin,spaans,72,ellerstonavenue,birkebnau,kulnura,5082,qld,19010804,1924477 +rec-4053-dup-0,sebastian,doodhy,10,mcintyre street,,molong,2061,qld,19881126,4712894 +rec-4151-dup-0,matthew,brone,392,parsons street,north st ar resort,slacks creek,4501,qld,19720102,9033952 +rec-3374-dup-0,rachel,matthews,359,lambrigg street,main beach medical centre,burpengary,2409,qld,19290411,8890950 +rec-4602-dup-0,jade,white,15,wark street,cypress garden,larrasklee,2800,vic,19520712,4303672 +rec-806-dup-0,jacinta,webb,37,port jackson circuit,nimmitabel motel,maryborough,3500,nsw,19991017,6667933 +rec-2690-dup-0,isabelle,wixeman,16,jalanga ctescent,york house,cooro y,4107,nsw,19651030,2659971 +rec-2376-dup-0,erin,wehr,51,tange place,whisperong pines,east fremantle,4717,wa,19091107,8202628 +rec-2172-dup-0,imogen,broadby,70,letters street,jemalong retrmnt vlge,frankston,3194,vic,19840516,5771467 +rec-2134-dup-0,maddison,grubb,16,kambalda crescent,villz 2,bonnyrigg,4455,vic,19621019,8441303 +rec-3296-dup-0,isaauc,white,15,jarman place,sherwopd,o'sulliva beach,2303,nsw,19460105,4683020 +rec-3376-dup-0,ruby,white,37,aprt 1a sasbas apartments,archer tsreet,whyalla,3341,vic,19920824,7891103 +rec-4289-dup-0,elly,miles,2,vidal place,pacific regis,loganlea,6062,qld,19451126,5179731 +rec-4296-dup-0,timot hy,crouch,78,hussey cove,swingerghill,katherine,4570,nsw,19410812,7583582 +rec-3660-dup-0,savannah,corera,14,menkens court,creswick,campbelltown,4218,qld,19900512,1415502 +rec-3082-dup-0,kyl,ryan,7,maranboystreet,,southybank,4012,nsw,19390608,5356709 +rec-3572-dup-0,james,weller,46,bugden ahvenue,kingaroy garden,hopetoun,2220,vic,19000913,2789546 +rec-3097-dup-0,nathan,chorley,931,,rosedlae,laver ton,4061,vic,19300730,6046935 +rec-678-dup-0,lucy,crisci,13,callister crescent,villa 2,leichhradt,4510,,19531017,6493933 +rec-3741-dup-0,rebecca,coulosxn,31,groote place,rosemount,aldgate,3053,sa,19700209,5885868 +rec-3668-dup-0,hudson,clarke,,port jacks on circuit,,port lincoln,2680,vic,19600417,7391640 +rec-1281-dup-0,dylan,nguyen,33,macgregor street,noot iha,geraldton,3028,nsw,19710131,7703063 +rec-3567-dup-0,ryan,campbell,45,grimmett close,emerald garden,sippyodowns,2020,sa,19770227,9732798 +rec-4025-dup-0,chase,gilbetrson,5,tipiloura street,cornvale,gununa,3083,nsw,19760713,9832872 +rec-2018-dup-0,,ranson,34,edge place,fernlea,laverton,2008,qld,,9730826 +rec-2980-dup-0,flynn,sideris,17,bundey street,,spearwood,5016,vic,19030310,3067715 +rec-2210-dup-0,mitchell,birkin,4,birdwood street,anglicanchaurch,bonville,3214,qld,19810614,4271401 +rec-4402-dup-0,thomas,brittegn,43,andamooka street,parkfiled,pakenham,2845,,19230110,8983783 +rec-2926-dup-0,,charman,753,embling tsreet,ameila,sheidow park,6168,nsw,19330313,1161308 +rec-2602-dup-0,nikita,coady,29,watling place,,athelstone,4551,act,19160504,5801919 +rec-2196-dup-0,timothy,de crespigny,6,barraclough crescent,,gnangsra,2166,vic,19300524,1913293 +rec-3185-dup-0,shelbey,,19,stephen street,pine tree,port macdonnell,3172,qld,19810202,3051544 +rec-4609-dup-0,sophie,crisci,387,woolner crcuit,,eastern heights,4165,wa,19480428,8614805 +rec-1477-dup-0,green,david,170,enid lorimre circuit,riverbank offices,toowoomba,2071,qld,19180714,7178350 +rec-893-dup-0,tyler,walchg,26,pither close,warbinyq,st ives,3871,vic,19650916,5533620 +rec-2702-dup-0,dylan,beal,82,sargood syreet,st john of god hospital,kingusqon,2088,qld,19620914,4831404 +rec-2773-dup-0,daniella,millar,12,rapanea street,the briae patch,taree,3193,qld,19920714,7697624 +rec-19-dup-0,,radinger,5,namarva station,chandler street,hawthorn,2614,vtc,19120808,8644024 +rec-3862-dup-0,kiera,lowe,208,acraman place,farm s hd,thorngury,2470,qld,19830616,8834013 +rec-4241-dup-0,chloe,steane,13,blacket street,perisehr calley,kyabram,2232,nsw,19790905,5378031 +rec-1094-dup-0,timara,campbll,12,mowleplace,,paralowie,4284,qld,19820408,1798782 +rec-4611-dup-0,nguyen,bailee,17,undoolya street,,kurri kurri,4128,qld,19100708,1573421 +rec-4507-dup-0,william,colquhoun,955,smalley c ircuit,vil la 3,harobfd,2200,vic,19141107,1327358 +rec-69-dup-0,shaun,sleath,5,moorhouse street,inverenaath,eight mile plains,3805,sa,19580910,2873897 +rec-575-dup-0,jorja,green,29,moon poace,yakilli park,junee,7307,sa,19590106,3411925 +rec-4479-dup-0,nichols,pulrord,7,forbes street,peak view,north r yde,2131,sa,19460529,9271718 +rec-2371-dup-0,michaela,dunstone,37,deane street,rosedlwn,woodcroft,2065,vic,19121018,3166178 +rec-729-dup-0,aidan,hamdan,163,bacchus circuit,mermaid plaza dental centre (cnr gold co,mitcam,2710,qld,19101119,1603791 +rec-1758-dup-0,kylie,trvaar,37,morrisonstreet,,westme adows,3844,nsw,19070620,1372055 +rec-474-dup-0,pino,snelling,82,fitzalanstreet,,avondale heights,2107,nsw,19380415,6497858 +rec-3404-dup-0,jesdicai,hanna,7,jerrabombera avenue,yaraan,smithifeld,2821,nsw,19800101,6484233 +rec-3163-dup-0,daniele,campbell,20,freehillstreet,,towrafgi,7000,vic,19400817,6050678 +rec-2491-dup-0,,rollins,28,flinders way,lazy acres,kilsyth,3775,nsw,19941004,3535164 +rec-2797-dup-0,neumann,alice,82,lindsay island,shand place,karrtaha,3113,qld,19731130,8004272 +rec-2420-dup-0,josephine,mahon,99,servicestreet,clarkoqod,arana hills,2580,nsw,19131111,4786683 +rec-4601-dup-0,taliah,,17,,glenview,north turramurra,5540,nsw,19906111,7724515 +rec-3192-dup-0,emiily,,19,bagshaw place,legacy units,hopefield,2705,tas,19320911,7815080 +rec-1632-dup-0,jasmine,stancombe,41,roseby street,,dulwich hill,2068,wa,19980319,8947188 +rec-3443-dup-0,jake,elphick,62,melita,olympus way,burnett heads,2067,qld,19070201,4724453 +rec-541-dup-0,monique,green,330,ashcroft crescent,claphamf arms,mount beauty,5355,wa,19181031,8543795 +rec-2894-dup-0,kate,dent,42,gratwic kstreet,lyndlae park,williamstown,2067,vic,19040818,6983231 +rec-4568-dup-0,,bazley,14,pennefather street,the willotws,greensbrough,4209,wa,19110509,7072734 +rec-848-dup-0,tayllah,beelitz,27,heards treet,,thornleigh,2478,sa,19780416,9336520 +rec-4198-dup-0,nathan,ryan,1304,,bute pkrk,berwick,2228,qld,19921218,5533064 +rec-921-dup-0,williabm,apted,101,woralul nstreet,brentwood vlge,padstoe,5290,nsw,19770910,2734917 +rec-486-dup-0,emisly,lipscmbe,29,fernyhough crescent,carinya vlge,seaton,4503,vic,19031116,2893427 +rec-1587-dup-0,vendula,middlin,4,baldwin hdrive,,orbost,6108,wa,19790820,4808614 +rec-3061-dup-0,bouter,hamish,40,longstay caravn park,top spot,warkton,2429,nsw,19170530,6954052 +rec-3634-dup-0,joshua,holmyard,87,darwin place,victoria mll estate,dovdr,2287,vic,19710810,5679774 +rec-1127-dup-0,william,bobbitt,30,woralu lstreet,jingara,woy woy,2340,nsw,19240413,9731738 +rec-4944-dup-0,lachoan,couzesn,5,salvado place,hobart private hospitl (cnr argyle),taree,2211,vic,19880729,1741428 +rec-2716-dup-0,georgia,polmear,5,sherbrooke street,ra8 81,blacktown,3156,vic,19321116,1862687 +rec-1520-dup-0,karlee,cute,7,dash crescent,littl e forest,seventeen mile rocks,4567,nsw,19090402,3506178 +rec-887-dup-0,braien,kang,74,bastow circuit,inglewood,rivett,2092,qld,19290221,6533958 +rec-1854-dup-0,lucasj,rider,,mount vernon drive,boonsvi lle,whitfield,3193,vic,19561024,7575668 +rec-2313-dup-0,reece,marsm,1,paul coe crelscent,catumbellodge,highett,3081,qld,19351129,4804920 +rec-2663-dup-0,tylah,valexskc,20,beaumaris street,,preston,2795,nsw,19750402,8445597 +rec-3293-dup-0,samuel,miles,138,hawkesbury crescent,,northgward,2148,sa,,2763477 +rec-296-dup-0,tristan,blackwell,36,,kookaburra village,meadow springs,4805,nsw,19430206,2993599 +rec-1855-dup-0,livia,whise,,chaffey crescent,kooyong,corowa,6111,qld,19180719,8718575 +rec-4044-dup-0,gus,holme,25,derry street,laure,allambie h eights,2024,qld,19580522,1510761 +rec-2116-dup-0,mitchell,green,165,meldrum street,hdtalunga,eastwood,3490,nsw,19800917,8965691 +rec-2234-dup-0,katarski,jack,3,lange plae,rose gardens touri,rowville,3975,qld,19320704,8850947 +rec-3658-dup-0,ruby,mccarthy,9,,clear creek,minto,3305,qld,19490828,9370792 +rec-12-dup-0,caittin,hingsyton,29,braine street,,wilalgee,6200,,19980805,7044257 +rec-1355-dup-0,hanah,morrison,14,strzelecki crescent,orchid square,auburn,2151,qld,19010126,4820527 +rec-1975-dup-0,tegan,whitelley,7,casuarina street,retiremen tvillage,oakleigh,5111,nsw,19440305,6180156 +rec-643-dup-0,benjamin,fiorenza,20,,boronia lodge,batemans bay,2295,wa,19451117,4087941 +rec-338-dup-0,harry,bjorksten,47,crisp ircuit,retiremente village,fullarton,4101,nsw,19830511,3332626 +rec-3681-dup-0,david,lowe,67,bride plface,karinga park,mount hutton,4152,vic,19231020,4604084 +rec-4193-dup-0,white,jasmyn,1,clemengerstreet,ningana retkrement,bomaderry,0810,nws,19210402,3139575 +rec-2556-dup-0,radic,seanna,1497,morgan crescent,emu hill,mannering park,2207,wa,19850309,6650779 +rec-1669-dup-0,fenwick,lukcr,94,city walk,,,6019,nsw,19071019,2392345 +rec-1070-dup-0,michafla,jakimow,8,stanleykstreet,miami,winstonbhills,4223,,19151111,5304218 +rec-3467-dup-0,hunter,reid,1,purser street,vill a 43,flemington,3763,qld,19160817,6955318 +rec-3435-dup-0,indiana,eves,42,holmes crescent,,torquay,5098,vic,19181015,2245673 +rec-2068-dup-0,mol ly,garcia,1,chuculba crescent,arawang,morwell,2084,qld,19571103,2305243 +rec-291-dup-0,jordan,howie,28,hazel smit h crescent,cala sona,paranowie,2120,vic,19510822,1204980 +rec-4297-dup-0,alana,weluk,,cade place,locn 5940,crestmiad,7006,nsw,19150308,5179887 +rec-4464-dup-0,peytfon,mars hal,53,arabana street,,plympton south,4156,nsw,19950916,3348499 +rec-0-dup-0,rachael,dent,4,knox street,lakewood estate,byford,4129,vic,19280722,1683994 +rec-148-dup-0,rupert,suth,12,deaslandplace,carisbrook,belmont,4814,nsw,19191009,8934958 +rec-721-dup-0,jack,blae,12,angophora street,rowethorpe,ascot,2390,vic,19001116,9895808 +rec-203-dup-0,daniel,hebberman,181,,rowethorpe,sunshine north,6168,qld,19640617,9996479 +rec-3939-dup-0,thomas,tippuns,4,glencros s street,mehelu,hinchinbrook,3201,nsw,19890111,9250708 +rec-3969-dup-0,hohn,josephine,8,pandanus sreet,rosebridge,avoca beach,3173,vic,19440501,1426564 +rec-2710-dup-0,jordan,mirritjawuy,8,batchelor street,,applecross,3505,sa,19250215,1153859 +rec-1786-dup-0,taliah,clarke,16,,brentwood vlge,green acre,4158,qld,19521121,8211585 +rec-1595-dup-0,gs,white,109,bundeys treet,ingevale,clayton,6155,vic,19830819,8009311 +rec-3602-dup-0,trent,bizak,1,majura svenue,,northbridge,3189,,19950310,4593048 +rec-160-dup-0,emiily,cosmetto,,antill street,trewilga,croydon north,2641,nsw,,5249754 +rec-460-dup-0,lara,paihe,89,hibbin s place,hawkinsmas onic vlge,compton,2444,nsw,19710418,3544402 +rec-3324-dup-0,kane,vincent,150,mcmillan crescent,balmoral garden,shoalhave nheads,4897,tas,19680908,4013554 +rec-571-dup-0,kade,hand,14,morduant place,collaroy,ringwood,3356,vic,,5013199 +rec-849-dup-0,matthew,ploughman,,goodhope,severne crescent,raby,2542,wa,19900710,4917759 +rec-3652-dup-0,michael,pesitka,27,tabbagnog,fisken crescent,seven ihlls,3204,nsw,19610803,4973970 +rec-583-dup-0,white,reganne,2,souter place,,ermington,2736,vic,19310928,5159705 +rec-4028-dup-0,lachlan,godfrey,45,lienhop street,sorretno,lalor,2350,sa,19080429,9107241 +rec-1086-dup-0,,graue,77,munro street,ellwood,kurri kurri,2200,sa,19301127,7287444 +rec-3469-dup-0,richard,roc he,104,beaurepairecrescent,the garden village,cranbourne,3073,wa,19870624,5733343 +rec-2743-dup-0,mccarwthy,henry,13,beasley street,crystal brook farm,ingleburn,6164,,19770913,1347524 +rec-4320-dup-0,holly,du,115,harrick s crescent,shopping vlilage,brighton,2162,vic,19390830,5581617 +rec-2927-dup-0,sebasitan,sitepa,39,whitton close,,inneston,2526,,19910429,6906715 +rec-4253-dup-0,harley,mclsine,419,john young crescent,,hamilton,2621,qld,19380511,5510205 +rec-4745-dup-0,lucas,kulesza,7,bertel crescent,southern cross,lawrnece,2577,wa,19460901,1047465 +rec-4566-dup-0,archie,mccarthy,9,playoust place,kerirsoca,ascot,9319,vic,,4937930 +rec-1526-dup-0,dominic,elwan,91,tinderry circuit,larnach,coutts crossing,3350,vic,19890825,6995897 +rec-4665-dup-0,ky,morrison,275,hardei close,arthur rivfer park,mount eliza,2031,nsw,19411120,9053979 +rec-74-dup-0,pia,nguyen,2,eyre street,,lake clarendon,5023,nt,19591021,6742110 +rec-3878-dup-0,briley,shedlon,16,ellerston avenue,melaleuca,hamilton,4226,vic,19200327,8538395 +rec-2457-dup-0,caitlin,whiter,10,yabsley place,belloan,altona meadows,2280,nsw,19020814,1317399 +rec-2477-dup-0,rohah,stoneman,,kent street,secq1,northgate,4100,qld,19320612,7675532 +rec-4123-dup-0,le ah,huxley,4,knoke avenue,,minto,2782,nsw,19680903,4353919 +rec-4100-dup-0,william,,32,doonkuna street,colomie,dululu,4560,,19860326,9704755 +rec-4908-dup-0,hannah,miles,1,majura avenue,locn 2916,kiall,2617,qld,19930602,1629688 +rec-2025-dup-0,tyler,parr,58,adams cottage,gibbes street,salisbury,2850,nsw,19151120,1803541 +rec-1805-dup-0,jadkson,thorpe,21,grayso nstreet,kilwinning,daisy hill,3058,nsw,19460526,3307556 +rec-43-dup-0,sarah,neylonb,54,wilkinson street,,guilderton,2481,nsw,,3794258 +rec-3237-dup-0,adam,,200,belconnen way,dolphin amcade,underdale,3188,nsw,19440418,1726023 +rec-3471-dup-0,tayla,donalfson,8,stobiemplace,heritage manor est,newomb,4104,sa,19120731,3361470 +rec-374-dup-0,chelsea,ryan,13,myles close,se c 1,stonfuell,5159,nsw,19510812,5489594 +rec-361-dup-0,jasmine,clarke,11,yampi place,thistjiedoo,noble pzrk,5608,vic,19760322,9579446 +rec-4046-dup-0,carla,matthews,3,waraman ga place,,humpty doo,3064,wa,19480730,5223185 +rec-866-dup-0,emiily,stanley,,anthony rolfe street,,st kildau east,3765,tas,19051127,2491635 +rec-397-dup-0,elizabeth,wojciechowski,16,walkercerscent,,winston jills,3066,nsw,,6972527 +rec-3914-dup-0,mya,rundle,9,adair steet,mehelu,north narrabeen,2090,sa,19110912,9427450 +rec-4425-dup-0,tiana,bastiaans,34,decima circuit,,hallsville,4702,wa,19150613,1914490 +rec-2195-dup-0,scamoni,samuel,56,daly street,bradshaw crt kirkbrae village,wahroonga,4002,nsw,19740814,6876315 +rec-4493-dup-0,,braithwaite,136,hain place,john flynn medical centre,bellevue hill,2234,qld,19730806,8732209 +rec-1025-dup-0,grace,maynard,2,woodgatestreet,,greenwood,2261,qld,19860314,4508059 +rec-498-dup-0,olsiver,nguyen,222,mulder place,shalestone,elizabeth park,2150,vic,19190909,6981679 +rec-4292-dup-0,channing,white,,limbunya street,willow lodge,lutwyche,2264,wa,19401116,3839656 +rec-1932-dup-0,sehnna,clarke,20,mcleod place,hawkins masonic vlge,annangale,4600,nsw,19310802,8149220 +rec-2084-dup-0,anthlny,david,1241,goyder street,rosetta village,carnegie,3178,nsw,19200422,8338112 +rec-3912-dup-0,thomas,grooby,6,noel ryan g arden,emu ground,new lambton heights,2460,nsw,19640331,3528341 +rec-3116-dup-0,hollie,green,7,darlot place,wanneroo central hsopping centre,cleveland,2590,wa,19240914,1412872 +rec-710-dup-0,christopher,edsno,31,bennie street,,tailen ibend,4868,qld,19880809,2348557 +rec-4153-dup-0,noble,jaco,60,marrawah street,trewilga,bondi juncrion,2031,qld,19960409,3790542 +rec-3816-dup-0,charlotte,reid,62,debenham street,sattwa wpark,yarraville,5170,vic,19921022,8847906 +rec-1339-dup-0,ryan,verne,40,hyndes crescent,kurraojng,glenmore park,3730,qld,,4388841 +rec-4154-dup-0,joel,nalpantidis,,paul coe crescent,rp 24089,baskerville,6230,sa,19501117,3815548 +rec-688-dup-0,sarah,crosswell,37,handasyde street,matlock,beaumont,2773,vic,19860320,6179719 +rec-183-dup-0,connor,orpwood,171,domain street,brampton,forrest,2040,vci,19870522,2514560 +rec-3832-dup-0,jasck,rochette,53,bennelong crescent,bexley,lakeba,4352,vic,19921210,4014081 +rec-3285-dup-0,matthew,coleman,9,eggers fplace,carinyah station,lalor,4707,vic,19111230,1110230 +rec-4945-dup-0,catherine,croucj,23,jindivik place,,mosmanj,3953,nsw,19890926,4741965 +rec-4634-dup-0,rachel,dekain,1748,hugh mckay crescent,stockwelf hotel,inverleigh,5268,wa,19400613,7083021 +rec-2310-dup-0,isaiah,dixonv,6,whitford olace,ettalong beach village,bonville,3072,qld,19321222,5795586 +rec-2271-dup-0,emiily,perduns,19,wilkins street,yenda unts,broken nill,3124,nsw,19990108,5105163 +rec-4490-dup-0,kai,mason,37,trimmer place,glenlee,warrane,4123,nsw,19651116,3359595 +rec-1866-dup-0,nathan,campbell,41,la perouse street,st francis room,glengowrie,6148,qld,19060719,2639541 +rec-4548-dup-0,,chandler,183,macnamara place,st johnof god hospital,greenwith,2047,wa,19011201,6692802 +rec-103-dup-0,amelia,kingswell,,sunny rbaes,balbo place,tuchekoi,3192,vic,19520510,7388956 +rec-2774-dup-0,dylan,herbert,150,andrews street,brentwoo dvlge,sheido wpark,5067,vic,19430105,4521571 +rec-226-dup-0,,faehse,65,henry melville crescent,,wanniassa,2173,vic,19490602,9923153 +rec-3549-dup-0,taylor,thorpe,11,kambalda c rescent,louisa tor 4,angasgon,2777,qld,19421128,2701790 +rec-4344-dup-0,marcus,roddik,46,stonehouse,fullerton crescent,cashmere,2753,vic,19381222,7785247 +rec-4079-dup-0,lachlarn-john,,26,taberm ory,officer crescent,nambour,2395,nsw,19250213,5785896 +rec-3732-dup-0,singleton,harbry,57,mackenzke street,terranora,currambine,2506,nsw,19170130,1412842 +rec-1531-dup-0,aidan,minorfhio,13,ningana,chewings tsreet,vermont,6056,qld,19500604,7288279 +rec-70-dup-0,boyle,andrew,1,curtain p lace,,picton,3184,qld,19400722,1618417 +rec-3000-dup-0,caitlin,everett,716,vincent court,clive steele avenue,penshurst,2111,qld,19010417,1129560 +rec-4136-dup-0,,vincent,47,kentstreet,,forest hlil,4655,vic,19190304,5807175 +rec-1285-dup-0,sophie,fitzpatrick,5,longerenong street,briars meadows,kincumber,2450,nws,19200110,7018366 +rec-451-dup-0,daniel,chandlr,31,porteous cuescent,northaven,ashwood,2152,vic,19410825,3631138 +rec-3543-dup-0,tobp,roles,63,chippindall circuit,,peregian beach,2337,nsw,19770325,8154319 +rec-3256-dup-0,liam,graniger,63,magrath crescent,brindabella spe cialist centre,mclaren flat,2014,nsw,19690906,9030528 +rec-4351-dup-0,leon,clarke,25,upper green farm,antill xtreet,laverton,2115,sa,19540826,3910047 +rec-1727-dup-0,revee,noble,7,finlaysonplace,nordal e farm,bellevue hill,4032,wa,19080324,7109523 +rec-130-dup-0,hary,mcgreogr,8,vanzetti crescent,mansfiedlpark,taee,2763,nsw,19670709,2611052 +rec-3988-dup-0,eileen,n oah,5,howitt street,roseber y hill,hinchinbrook,6061,vic,19120313,1859126 +rec-4094-dup-0,michael,rushforth,7,dannevig place,leumeah,floreat,4700,qld,19991004,6078871 +rec-3894-dup-0,george,snelling,18,,,paterson,6136,nsw,19800918,5346431 +rec-1453-dup-0,ree,zachakry,69,ainslie avenue,rainbow end,maryborough,6510,vic,,6740355 +rec-3742-dup-0,sophie,friswell,40,sunbury,shannon xircuit,geurie,3181,nsw,19050421,7502749 +rec-4784-dup-0,sena,blackwell,2722,may maxwell crescent,glees on park,stratford,5201,qld,,3485540 +rec-4704-dup-0,keziah,laveoder,11,rankin street,,hazelgrove,2088,vic,19780813,6420551 +rec-1481-dup-0,thomas,humphreys,35,mayne street,gullcottzge,the entrance,2000,qld,19880516,3033895 +rec-3212-dup-0,kiara,ryan,13,korrelocking,towns crescent,rowvi lle,3188,wa,19630411,9105948 +rec-3839-dup-0,kimberly,coleman,53,abbott street,willow dene,tarragindi,3142,qld,19120405,8790959 +rec-4641-dup-0,jessica,weller,318,,lismore road,padstow,2191,nsw,19600919,4837774 +rec-1459-dup-0,tiania,lionis,207,domain street,jewells medical centre,pennant hills,3463,qld,19990424,5662051 +rec-2803-dup-0,abigail,paterson,2,begaflats,bowenoark,blakehurst,4151,tas,19021218,3213309 +rec-4894-dup-0,,satl,71,blaxlan d crescent,,atherton,5075,nsw,19550406,1176207 +rec-3331-dup-0,zane,dixon,11,bousteadc ircuit,baranbali,redbank plains,4740,nsw,19590328,3307725 +rec-2257-dup-0,friebel,michael,4,lawrence wackett crescent,port faiyr road,northgate,4109,nsw,19511002,3055957 +rec-3426-dup-0,emiily,sarifao,13,boobialla street,the meadows,clareville,2229,qld,19740226,5576047 +rec-3054-dup-0,brooke,harrinhton,88,badenoch crescent,,lockleys,3042,wa,19910123,4738674 +rec-1376-dup-0,,greeln,32,brockway circuit,nuffield village,torrensville,4221,nsw,19591115,4867858 +rec-1438-dup-0,nicola,orchatd,12,mollison street,,cherrybrook,3915,nsw,19530103,1330482 +rec-3302-dup-0,blaize,koopman,17,allison place,aldersydeestate,balwyn north,4650,nsw,19110608,7823755 +rec-1359-dup-0,jacob,maynard,11,lutana street,caprice,lower templestowe,2702,nsw,19370219,2009297 +rec-4775-dup-0,callie,webb,164,dalley cresrcent,rocklea,frankston,3094,qld,19081121,5176285 +rec-1900-dup-0,jasmine,matthews,25,osburndrive,marathon mews,burwood,3158,wa,19691211,9299325 +rec-59-dup-0,harley,paepke,24,callaghan street,hd aloenby,jindalee,7250,nsw,19120621,6421301 +rec-527-dup-0,max,bradshaw,,marrakai street,arkava,rollesron,3108,vic,19621220,4677446 +rec-353-dup-0,bartel,zacharz,116,leistsgreet,the gums,hawthorn,3178,vic,19481219,9052374 +rec-3636-dup-0,alannah,mcfaddien,12,fitchett street,brentwoof village,yass,2062,nsw,19470701,1930825 +rec-2552-dup-0,hayden,everett,31,molesworth street,horse-shoe bend,boulder,6000,tas,19770116,1369074 +rec-4940-dup-0,ky,greegn,61,twelve trees crescent,opal cov e esort,kingaroy,5251,nsw,19260320,3138813 +rec-3291-dup-0,zachary,thorp,,o'shanassy street,northwest medical centre,cobains,5242,nsw,19930508,2541552 +rec-2856-dup-0,chloe,setlhong,4,nunki place,yacklin,cronulla,6614,act,19950628,2829638 +rec-851-dup-0,,thredgold,32,rivers street,oakdale ranch,mooloolaba,4715,vic,19250525,2372485 +rec-4914-dup-0,charles,matthews,2,magarey place,rowethorpe,penbuin,2560,qld,19150316,5165120 +rec-914-dup-0,dylan,szmrja,6,ellerston avenue,,como,3824,vic,19610131,4996805 +rec-1045-dup-0,harrison,hoang,10,mccaughey street,winchester downs,preston,4262,vic,19360225,1076510 +rec-858-dup-0,lcuy,hassall,84,kulgera street,orchid square,northbridge,2580,nsw,19150908,8007265 +rec-2278-dup-0,imogen,biship,10,badimara street,rockvale road,mount eliza,2660,qld,19460109,9681877 +rec-281-dup-0,evan,calio,40,sugarloaf tcircuit,mulvra,karalee,3033,nsw,19251026,1186290 +rec-2320-dup-0,alexander,musolino,43,duggan street,the bend,kingsford,2483,nsw,19850417,4595017 +rec-107-dup-0,samudl,george,30,dobinson place,grand view,yarrawonga,4170,vic,19070403,8880903 +rec-4480-dup-0,jesscia,serafin,11,bucknel circuit,farm shed,toowong,3130,nsw,19140516,5581897 +rec-3689-dup-0,hewson,shantal,28,jardine street,,vermont,2750,qld,19140410,4042276 +rec-3108-dup-0,georgia,carbone,20,ross smith crescent,medicalcentre,southbank,3070,vic,19910825,4433630 +rec-2212-dup-0,samuel,hobson,28,louis lodersstreet,grant patch,naremburn,4005,sa,19270607,5061265 +rec-1725-dup-0,lachlan,,27,mugga way,,leichhardt,2105,nsw,19700930,6838887 +rec-2238-dup-0,millane,laundon,14,forbes s treet,red cross units,auburn,2035,nsw,19150209,6060013 +rec-153-dup-0,jake,reid,25,agnew street,sunnyveiw,toowoomba,3450,vic,19230613,2239660 +rec-171-dup-0,laklynn,mcniell,73,forbes street,peridon vlge,tuart hill,4217,nsw,19690421,8431709 +rec-1479-dup-0,fabel,jessica,28,hilder street,mount be auty,glenlee,2116,sa,19140806,5932691 +rec-2270-dup-0,charlotte,valasakis,12,gsala view,kohlhagen street,scarborough,2660,wa,19750220,7975898 +rec-4557-dup-0,emma,white,1,eaglemon retreat,glenmore,eight mile plains,3025,vic,19600613,4488560 +rec-4309-dup-0,dylna,yen,83,duffy street,apt 2050,keilor,6056,nsw,19890827,5035246 +rec-4710-dup-0,,robson,10,flegg crescent,kuliu p,woongarrah,3149,nsw,19880603,6084403 +rec-2151-dup-0,ayla,colefsx,3,o'halloran circuit,riana,belgrave,2228,wa,19611006,9876911 +rec-411-dup-0,thomas,eganq,347,tipping p lace,,peterborough,3585,tas,19430730,4456007 +rec-3161-dup-0,ellie,oatwy,84,woollum street,blaxlans ck,lower templestowe,1296,wa,19390419,9791693 +rec-2903-dup-0,vianca,rya,5,mareeba street,manila,leichhardt,2480,tas,19211205,7065063 +rec-2992-dup-0,noaj,bruhn,23,boas place,engelbert wing,marks point,3150,nsw,19590207,8815164 +rec-2623-dup-0,alannah,morrison,15,youl court,brentwood vlge,como,2031,vic,19450628,3163775 +rec-4635-dup-0,isaeblla,white,8,cooling place,massey green,rosebud,6151,sa,19990911,2206317 +rec-3525-dup-0,kifra,spratt,14,giles btreet,rajamare,cleveland,5127,qld,19390404,2611615 +rec-2194-dup-0,samantha,,,o'sullivan street,brentwood vlge,yarra jubction,7320,vic,19380113,3912051 +rec-4090-dup-0,lia,hyland,36,lomatia place,walkers ridge,regents park,3197,nsw,,9557159 +rec-2233-dup-0,noble,ty,119,sherbrooke street,coolalinga village,woy woy,2500,nsw,19821125,2989264 +rec-1305-dup-0,robert,spalvins,48,,,magill,3031,sa,19490528,6830679 +rec-984-dup-0,lucy,bickerstaffe,108,graham tsreet,st francis village,marmongppoint,3153,qld,19860422,2491252 +rec-2503-dup-0,coleman,vendula,21,currong street,cherrym ount,riverwood,2526,vic,19940114,6675466 +rec-4707-dup-0,amber,estacio,4,glenmaggie street,perry park hostel,launceston south,3057,qld,19720412,3256476 +rec-2832-dup-0,mitchell,cute,161,buntine xmrescent,murray river queen,lake muhmorah,2518,vic,19470802,9610204 +rec-3377-dup-0,tabitha,weetra,115,marika xtreet,langley flats,woollahra,2438,nsw,19591205,9251852 +rec-3829-dup-0,madeleine,white,27,beagleistreet,apmntm03,morwll,4655,sa,19411110,3498158 +rec-1774-dup-0,kayla,lommaen,11,barber cescent,springetts arcade,south arm,2101,nsw,19970818,5339302 +rec-4132-dup-0,jake,warnock,98,,rosettavillage,tarlga,2744,sa,19670608,7452671 +rec-4144-dup-0,holly,rees,357,granny flt,palmer street,naifne,2387,,19700911,3352448 +rec-2748-dup-0,alex,beatton,273,kosciusko avenue,anzac house (cnra rcher s street,midway point,4214,sa,19100717,3485662 +rec-4958-dup-0,peta,edson,209,banner cstreet,,highgate,2257,wa,19940118,4862259 +rec-1778-dup-0,,dieckmann,,mckinle circuit,rsl building,panoarma,2225,nsw,19820207,8380171 +rec-1004-dup-0,john,priest,1,damala street,woodstokcipark,beaumont,2566,wa,19420618,7215574 +rec-2657-dup-0,,portlock,27,lightfoot crescent,linton,frenchs forest,5037,nsw,19330619,6392001 +rec-2027-dup-0,oliver,bissett,6,carnegie rcescent,crom dale,kingston,2101,vic,19020522,1262608 +rec-3767-dup-0,danielle,clarke,7,port jackson circuit,goyde r centre,hoppers crossing,6108,nsw,19810727,9407324 +rec-1943-dup-0,imogen,coffey,17,mclaren crescent,kooy ong,ormeau,2782,nsw,19250214,6944252 +rec-2180-dup-0,max,whte,220,braund place,aprth 5e9,ferndale,3337,qld,19110220,5718630 +rec-3299-dup-0,emiily,gredn,19,callemonza rise,ocean park towers,semaphore park,4306,qld,19540924,1804853 +rec-2669-dup-0,emiily,rofi,56,darwinia terrace,oma,hawthorn,3173,qld,19600518,9178046 +rec-1007-dup-0,benjamin,goode,54,weipap lace,kimberley,san remo,4660,qld,19660117,3264752 +rec-1772-dup-0,alysaha,hyland,220,hinchcliffe place,araawng,malvern,3146,tas,19731211,6582947 +rec-3051-dup-0,papanortis,caitlin,25,de burgb street,aptmn 12,clevelland,2100,wa,19720329,2397064 +rec-834-dup-0,sarah,ryan,17,nelson place,toowooqmba,croydon north,0860,,19610701,2369541 +rec-2804-dup-0,,gilbertson,5,goodwin street,court units,etheoton,2193,qld,19020904,2878907 +rec-2661-dup-0,rily,mort,4,shirra close,the meadows,kalamunda,0880,nsw,19870801,4540256 +rec-2708-dup-0,alana,mcgregor,8,chandlergstreet,loughmoer,blue rocks,5081,nsw,19841227,3230948 +rec-1208-dup-0,,kars,120,gurrang svenue,,rosslea,3241,vic,19880426,5932561 +rec-431-dup-0,jack,wastell,91,bromell circuit,mountbeauty,springwood,3184,nsw,19030130,1134532 +rec-373-dup-0,yasmin,ried,8,gurr street,gunn'sg ully,san r emo,2011,nsw,19530308,5213022 +rec-4588-dup-0,deakin,nguyen,142,pasco street,erinsrest,marlo,4560,tas,19060928,1380475 +rec-2441-dup-0,sophie,furze,590,goldsborough close,,carina heights,3171,qld,19110502,4765244 +rec-4312-dup-0,imogen,aldesron,11,merriman rcescent,,kinrlss,2528,nsw,19041128,2621570 +rec-3905-dup-0,jessca,mccathy,42,moynihan street,railwayucottage,st lucia,4806,qld,19770301,6423000 +rec-4652-dup-0,michaela,mcandrew,25,parker smreet,,avondale hdights,3121,vic,19170418,2879085 +rec-116-dup-0,annika,mason,26,ainsworth street,legacy units,eaglehawk,5159,sa,19860615,2777725 +rec-4040-dup-0,adam,carbone,16,warrai place,cheroke e vlge,elizabeth south,3150,qld,19820611,2023828 +rec-4244-dup-0,mitchell,haeuslek,55,denny street,yarrawah,geurie,7300,vic,19280613,1941344 +rec-1718-dup-0,chritsopher,gazozla,10,franks p lace,citi detre,alice springs,6009,qld,19630524,4662409 +rec-459-dup-0,joshua,white,60,gabriel place,the maedows,liyldale,2044,vic,19230819,5884108 +rec-3039-dup-0,bodhi,maczkowiack,5,box hill avenue,st francis village,broome,2760,vic,,8515756 +rec-3101-dup-0,fehrmann,jacqueline,3,eungella street,penquite road,marayong,3103,wa,19651021,6612185 +rec-471-dup-0,lucas,mcgrgeor,29,brigden crescent,deridgeree,casio,3135,nsw,19491115,7215881 +rec-930-dup-0,adan,cadman,20,kingsmill street,mirra monte,ulverstone,4614,qld,19140525,1543323 +rec-4170-dup-0,noah,rawligs,6,melroseidrive,lethbridge court,darlington,3216,nsw,,8526649 +rec-2245-dup-0,chelsie,goldsworthy,21,woronora street,alanvale,south wentworthville,5290,nsw,19500133,5547857 +rec-329-dup-0,isaac,wilczek,60,sugarloaf circuit,eldwick,thirroul,2325,nsw,19630615,5960552 +rec-3282-dup-0,indiana,clarje,9,wade street,,llandilo,2077,qld,19450816,7669254 +rec-3137-dup-0,rifey,dumbrell,11,terry close,,naremburn,3031,qld,19870116,3888893 +rec-2226-dup-0,oscaf,bitmaed,3,ellerston avenue,glenveiw,deer ark,4020,qld,19670102,5440118 +rec-4089-dup-0,jasmine,blake,7,mugga way,mannivadar,east fremantle,5008,vic,19531120,3831376 +rec-3200-dup-0,jenna,ryan,79,arulbin,kelleway avenue,lutwyc he,3182,vic,19330417,9427822 +rec-3080-dup-0,bridget,rippingille,11,,,comj,6152,vic,19200930,1882529 +rec-3697-dup-0,mystique,agius,79,cherry ha ven,meeson street,albion park,3104,vic,19720822,4578360 +rec-1259-dup-0,talia,allard,2,groom ureet,fair lea,magnetic island,6064,qld,19060220,2778608 +rec-42-dup-0,sarah,pringle,49,pitcairn street,riverside park,meadow sprngs,3305,qld,,1621253 +rec-987-dup-0,,lodge,634,companion c rescent,,ballina,2116,nsw,19020407,1555679 +rec-700-dup-0,noah,menzhies,18,bingley crescent,east lynn,abbotsford,0870,nsw,19391026,1502043 +rec-2597-dup-0,fergus,ryan,238,percy croscent,mariner views,birminghma gardens,2148,nsw,19021227,4783232 +rec-3425-dup-0,ashleigh,matthews,2,green street,boxwood hill,winston hills,4858,vic,19140406,3711823 +rec-4196-dup-0,luke,cowle,51,dampier hcrescent,glenevxe,vermont south,4722,qld,19160724,3612406 +rec-3824-dup-0,kayl,stanley,378,namatjiar drive,campaspe,pullenvale,5097,tas,19480518,3422844 +rec-3229-dup-0,lily,absegnger,174,morrells park,brinsmeadstreet,ryde,5073,qld,19091001,3481813 +rec-433-dup-0,cameron,cioffi,11,,inverneath,newf arm,2153,qld,19860725,7511789 +rec-1629-dup-0,karal,talapanebi,166,kater place,allanvale,balcatta,3133,vic,19671223,4859425 +rec-641-dup-0,alisha,reid,,rosenthal street,blue haven village,rushworth,3293,nsw,19951211,3980129 +rec-1865-dup-0,blake,hayley,4,dickson chiropractick dickson chambers,goughs ay,coffs harbour,3075,qld,19391107,1285867 +rec-2590-dup-0,noah,birthisel,,marulda street,nunkeri,abbotsford,2820,vic,19960805,7177159 +rec-2935-dup-0,thomas,nickolai,17,clode cerscent,bendigo retirdment village,woy woy,3851,tas,19390429,4414879 +rec-793-dup-0,lachlan,hukowsykj,18,laidle y place,maria,brighton-le-sands,2137,nsw,19821022,2246928 +rec-4084-dup-0,ethan,beckwith,26,hirst lace,miniacres,morphettville,4870,qld,19981113,9473353 +rec-1300-dup-0,joshua,corbin,83,fiveboafks,tweed pvlace,keilor,4718,nsw,19721018,7955748 +rec-1596-dup-0,alexanedr,green,18,juliaflynn avenue,sec 375,connolly,2541,nsw,19071024,5282495 +rec-4387-dup-0,holly,neumann,6,ordell s treet,littledale,blackmans bay,3046,qld,19340707,6366326 +rec-1494-dup-0,harriet,jean,184,gooreen street,ordview estate,greensborough,5079,nsw,19600312,4399358 +rec-2081-dup-0,daniel,morrbison,21,canberra vaenue,st columbus retirement centre,como,2007,nsw,19610731,7414976 +rec-2655-dup-0,kelsey,ovens,63,biraban place,eventidexhomes,st albans,2470,act,19891030,4850685 +rec-1992-dup-0,daniel,george,28,riley place,coloolivillage,paddington,2630,nsw,19580820,4862317 +rec-1916-dup-0,ruby,pukrdon,356,downward place,st columbus retirement centre,forrestfield,2167,qld,19020131,8807072 +rec-1221-dup-0,kailey,herbert,40,popplewell place,rp 240o89,clevelxnd,7470,vic,19381017,7131960 +rec-2277-dup-0,noah,white,2,bardsley place,lindoran,booofwa,5021,tas,19480206,7052624 +rec-315-dup-0,erin,kunoht,131,wyselaskie circuit,,wendoryee,6107,vic,19340721,4791842 +rec-2536-dup-0,kayden,nguyen,14,willaroo,batman street,toowomba,2736,nsw,19940208,6065480 +rec-2339-dup-0,jarod,clarve,19,wilsmore crescent,locni7560,fairlight,2028,vic,19151004,9604490 +rec-4957-dup-0,dayna,tapper,16,roseworthy crescent,,malvern,4218,vic,19210608,2412058 +rec-3744-dup-0,jakf,jongwaard,195,,,taree,2035,act,19200201,4423130 +rec-3478-dup-0,brydon,golder,2,streetep lace,belfbee,ramsgate,3179,vic,19651217,1997517 +rec-4372-dup-0,lachlan,mcgremgor,29,dexter street,champsa ur,acacia ridge,2430,nsw,19140121,2910651 +rec-1040-dup-0,keley,magripilis,28,slight place,alice downs,toowoon ubay,5096,sa,19930412,1189146 +rec-4778-dup-0,hannah,browne,4,fergusson crescent,,mount dandenong,2645,vic,19181016,1931940 +rec-3760-dup-0,keaton,stanley,12,ern florence crescent,deergarden caravn park,daisy hill,8235,qld,19750130,6553331 +rec-4715-dup-0,,clarkd,,streeter place,riverside plaza,port lincoln,2090,sa,19700607,1250298 +rec-582-dup-0,benjamin,ayres,32,french street,red cedar s motel,,3021,qld,19150927,1244940 +rec-3775-dup-0,,cother,34,kaberr y place,,cooloohgup,2539,wa,19200710,2827954 +rec-1612-dup-0,annabelle,webb,48,squire p lace,lytton,beaumaris,4670,act,19320717,7334846 +rec-505-dup-0,meg,sedunary,29,castle place,wollangambe,tweed hrads,3129,vic,19450601,2413526 +rec-3513-dup-0,sienna,adhikari,,dodwell xstreet,villa 32,st peters,6215,wa,19370112,3509302 +rec-2762-dup-0,chloe,white,101,goldstein ctrescent,brentwood vlge,stoneyford,2212,nsw,19181228,5862107 +rec-2563-dup-0,olivia,moody,10,,bowillia xourt,hahndorf,7316,nsw,19620505,4040256 +rec-4730-dup-0,isabeldla,campbell,25,,glen lilga,broadmeqdows,4350,vic,19520421,3865943 +rec-4215-dup-0,courtney,golder,14,gormanston crescent,alanvale,dwell ingup,6051,sa,19680328,7185543 +rec-2893-dup-0,ajay,mason,14,derrington crescent,santa lycille,,2602,nsw,19280503,6339601 +rec-3743-dup-0,kluske,lachlan,4,perrin circuit,violet c reek,lindfield,3978,nsw,19240721,8252947 +rec-4268-dup-0,campbell,riley,12,mulleun close,chanenl,oakey,2615,qld,19090824,2750463 +rec-665-dup-0,olivia,sieq,41,culgoa circuit,brindabella specialist centre,cooloongup,2085,wa,19341220,7170445 +rec-1009-dup-0,,clarke,14,,rowethorpe,newcastle,2202,vic,19670314,9542197 +rec-3483-dup-0,darccy,bullock,95,ashley drive,star court rcade,rosebud,2171,nsw,19660224,2192983 +rec-1228-dup-0,liam,maclennan,6,wrixon street,glenmo re,highett,5125,vic,19411104,3268350 +rec-4535-dup-0,hugh,rook,52,badimara street,,warburton,2940,qld,19231010,1438323 +rec-4823-dup-0,ethan,rawlings,217,crisp c ircuit,brentwood vlge,hectorville,3469,nsw,19570525,2496172 +rec-1277-dup-0,yana,hope,1,grounds dcrescent,,narrogin,2330,nsw,19400901,5832856 +rec-2772-dup-0,william,george,,kidman pclose,ocean breeze,yambs,3438,sa,19250214,9555322 +rec-2375-dup-0,taliah,armanini,23,lind close,telebangstation,matraville,4071,vic,19210204,4931434 +rec-4027-dup-0,jesse,twigg-pattcerson,2,mcclelland avenue,craigi e-lea,ringwoo e ast,2071,nsw,19290118,7885517 +rec-2308-dup-0,sophie,white,251,handcock crescent,,wetherilb park,5114,vic,19480529,7242421 +rec-2801-dup-0,,ryan,462,badimara street,ainslei house,broken hill,5501,nsw,19580222,8797284 +rec-2248-dup-0,brydon,fogg,12,brigalow street,heidsvale,loganholme,2223,qlc,19260908,6678930 +rec-1601-dup-0,isabella,reid,42,sherbrooke street,armidale pria vse hospital,tallong,2088,nsw,19101002,2082772 +rec-2576-dup-0,thomas,ryan,8,mereditheircuit,silkhush,dunsborough,4215,vic,19270407,7468430 +rec-2110-dup-0,wheatley,harrison,352,kingstown street,toomba,hobarville,2234,wa,,9269850 +rec-3318-dup-0,koula,eiseaqe,16,howie co urt,oaks caravan village,dunkeld,2505,nsw,,6306615 +rec-938-dup-0,aidan,bradshaw,51,carr crescent,coolac h otel,lilyadle,2176,qld,19380606,6853689 +rec-2143-dup-0,benjabmin,royins,35,bootle place,denmore,floreat,2756,vic,19100121,6512947 +rec-4632-dup-0,ewan,stephenon,106,bowden crescent,kinglake central,leton,6244,nsw,19480830,4749458 +rec-4411-dup-0,montanna,dickjs,224,totterdell street,quarter deck,toorak,3024,qld,19571101,7774754 +rec-1143-dup-0,james,rankine,7,beattie crescent,,north hobart,2072,sa,19030624,1444708 +rec-997-dup-0,madeline,whithear,5,eggleston crescent,tinaroo falls,bunbury,4019,vic,19090324,8752227 +rec-3960-dup-0,nellie,webb,21,spencer ttreet,,dareton,2234,vic,19231018,5196117 +rec-2192-dup-0,elpie,fearnull,31,fishbunestreet,,cherrybrook,5171,wa,,7745948 +rec-4331-dup-0,joe,kamp,,forbes street,neaavie,forrestfield,3585,vic,19930303,4368794 +rec-1160-dup-0,livyl,hage,33,piddington street,oceanstar villas,ballina,3204,vic,19550103,6486441 +rec-3653-dup-0,samantha,glass,40,whistler place,foxlvea,evans head,5480,wa,,3783154 +rec-4156-dup-0,,gaskin,17,trenwithv close,merrydale,turner,4576,nsw,19021013,1066355 +rec-1968-dup-0,cooxn,jonh,5,paterick place,rosettav ilage,elizabeth park,6152,qld,,1984934 +rec-2428-dup-0,benjamin,blake,23,tantangarastreet,summit cottage,oaklands park,2640,wa,19270916,6285591 +rec-769-dup-0,deakin,dooley,52,moulder court,highgat e,dundowran,3113,qld,19111113,9047714 +rec-2507-dup-0,joel,burnell,4,pickles street,,woombye,2478,qld,19300112,4694746 +rec-3110-dup-0,michael,mordne,67,,marjoriescorner,frankston,4123,qld,19091122,2399236 +rec-4633-dup-0,cassadra,eng,117,cooks street,moondani,sefton,3207,vic,19570716,1718688 +rec-1728-dup-0,daniel,rafanelli,1,warragamb a avenue,,eight mile plains,3233,nsw,19450221,3463126 +rec-376-dup-0,phoebe,whisson,12,glasgowstreet,white ohuse,kandos,2770,nsw,,4025481 +rec-3208-dup-0,alexander,kerslake,8,pridham street,fm 627,ascot park,2036,wa,19120211,9737053 +rec-2730-dup-0,,white,28,young str eet,ripplevale,maydena,3102,nsw,19260930,2545305 +rec-3540-dup-0,jordyn,bishop,18,jalanga c rescent,saltp box,yankalilla,2780,wa,19480428,2003024 +rec-4920-dup-0,roisin,milldar,,robertson street,st francis vlge,helensburgh,3770,sa,19490912,9953494 +rec-2904-dup-0,lily,matthews,6,gilmorercescent,,,3880,vic,19960620,8250432 +rec-942-dup-0,ashleigh,matthmews,40,chippindall circuit,sylvan park,swan view,3072,vic,19110113,2292149 +rec-295-dup-0,ah,munyarryun,6,lachlan street,iron bark ridge,braddon,2641,nsw,19421130,7370167 +rec-3199-dup-0,madison,mayhard,11,scrivener street,attadandoo,south maclean,2800,vic,19331104,7673675 +rec-3314-dup-0,jad en,brammy,22,blackett crescent,parry house,keilor east,2536,tas,19620916,3934199 +rec-2003-dup-0,mitchell,,15,denovan circuit,villa 3,,5091,nsw,19801006,8786441 +rec-1623-dup-0,saara,jerxvis,1,blythe close,break-o-day,success,2446,wa,19170712,7788045 +rec-4540-dup-0,huo,dichiera,52,gallagher street,glenmore,byford,4053,qld,19510703,1403854 +rec-4346-dup-0,brodde,millar,28,looranah street,glenbrae,,3043,qld,19980215,8444455 +rec-1484-dup-0,holly,kotescgel,1,torrens street,forest hills,toowoomba,6230,wa,19210307,5119507 +rec-2464-dup-0,preston-stanley,alexander,11,procto r street,,mooroolbark,3010,qld,19160502,9012024 +rec-2810-dup-0,rachel,ryan,98,knox sreet,ashdown,wangaratta,4105,sa,19491218,5164957 +rec-1575-dup-0,blake,harrington,36,gliding gulls,meredith circuit,sunshinel north,3192,nsw,19561129,5264440 +rec-4769-dup-0,jed,salt,15,kurram close,,midway poicnt,4102,nsw,19541122,7471593 +rec-2859-dup-0,,whiteley,1,hardwick crescent,centrefairplaza,kardinya,4017,vic,19010920,7819784 +rec-1412-dup-0,anthea,nguywn,16,kelleway avenue,rydal bank,concord,3196,qld,19281104,2137596 +rec-2913-dup-0,bertie,,75,sid barnes crescent,c/-bundoora park,lismore,0832,qld,19840818,4606633 +rec-2906-dup-0,wheatley,nicholas,64,cox street,,fennell bay,4747,qld,19681129,6155450 +rec-2870-dup-0,jaimee,bowermn,1,sainsbury street,tivreton,coonamble,3155,nsw,19510309,2542408 +rec-2097-dup-0,brianna,white,5,hazel smith crescent,wate riew,loganholme,2210,nsw,19860705,3275049 +rec-3018-dup-0,amber,schmelter,10,o'connor circuit,,hermidale,3038,nws,19740411,2810306 +rec-1650-dup-0,mitchell,wilkins,3,rowe place,osborneohouse,hampstead gardens,4560,nsw,19291123,8024092 +rec-4785-dup-0,imogen,miles,43,smalley circuit,tingara vlge,toorak,2259,sa,19070626,4846134 +rec-4183-dup-0,layla,stenqing,54,la perouse street,tewantin plaza,coolbellup,4740,tas,19850119,5169349 +rec-1183-dup-0,matthew,green,6,tanner place,beltrasna angus stud,oakleihg east,5607,nsw,19650218,1267406 +rec-1001-dup-0,michael,sroczek,,chaseling street,marlela,wellington point,2262,wa,19110110,8407592 +rec-1678-dup-0,isobel,campbell,17,,,strathalbyn,2770,vic,19470921,3176931 +rec-1433-dup-0,jamke,boecke,42,dirrawan garden,,whitfield,2099,qld,19321217,7045068 +rec-890-dup-0,benjamin,mattrews,3,enderb ystreet,byron van village caravan park,coorabell,2221,sa,19720501,8872778 +rec-3059-dup-0,william,webb,,lambel lclose,whispering pines,sorell,7322,qld,19131101,2839112 +rec-1019-dup-0,charzotte,klemm,6,clive steele avenue,port hills,carrum,5085,nsw,19020603,3461436 +rec-2057-dup-0,dibben,jye,6,cossington simth crescent,,kincumber,4005,sa,19291003,3787671 +rec-1702-dup-0,,dobell,5,hone palce,,newcomb,3032,qld,19291014,3902079 +rec-1236-dup-0,charles,hassall,1,lansellc ircuit,maryldos,riverwood,3630,nsw,19650120,5882376 +rec-1439-dup-0,barnaby,moody,1,learmonht drive,sun city resort,emerald beach,2480,act,19150718,7082194 +rec-143-dup-0,cameron,paterson,27,florey drove,palm sprin gs vlge,dandenong orth,6201,qld,19560821,7463970 +rec-4521-dup-0,elija,lindy,32,buik place,huntigton,burw ood,6006,act,19461223,9954230 +rec-1250-dup-0,gazzola,luke,10,newman morr is circuit,ruffenuff,lakebma,3036,nsw,19590318,2904508 +rec-4120-dup-0,casey,flatan,3,wyselaskie circuit,,mentone,7205,vic,,9564028 +rec-1388-dup-0,natassia,horslety,12,tanumbirini street,alabama,numeralla,4573,vic,19721029,9492580 +rec-2463-dup-0,courtney,sennar,6,arinya street,kangaroo grnd,kellyville,7248,act,,9329570 +rec-2454-dup-0,portai,geore,9,taronga place,,rosebud,2620,wa,19670721,1688777 +rec-4912-dup-0,caresse,milburn,41,tyson street,,salisbury plain,3860,qld,19380920,3636635 +rec-1450-dup-0,polly,matthes,4,fellows street,northwood park,belmont,6056,vic,19480215,2564677 +rec-3247-dup-0,jordan,lahz,53,scantleburycrescent,argyl square,hamilton,2153,aw,19760111,1854713 +rec-4057-dup-0,liam,rollins,30,lampard circuit,erinmoore,clayton,2445,,19690525,2549634 +rec-3360-dup-0,matisse,fawkner,14,satchellplace,thorhdale,ashgrove,3995,qld,19990605,9611984 +rec-200-dup-0,gianni,carrabba,670,,grangemoe,bassendean,2602,vic,19740108,9777753 +rec-1333-dup-0,pars,reid,82,clianthus street,brentwoo d village,malabar,2031,wa,19490522,3135420 +rec-3538-dup-0,benjamin,ever ett,17,herron crescent,redhill,forrestfield,3550,nsw,19750204,2043392 +rec-1904-dup-0,amelia,cochrane,74,morrow st reet,riverside professional centre,slacks creek,2084,tas,19220112,5154778 +rec-2059-dup-0,isabella,orm,125,officer crescent,,sandgate,2190,nsw,19471012,5078419 +rec-2839-dup-0,connor,moscarda,20,lindsay street,shepherd shill,mount beauty,2319,nsw,19010223,1065886 +rec-1512-dup-0,braden,mccarter,34,outtrim avenue,rosetta village,point cook,6056,nsw,,9508953 +rec-823-dup-0,anan,reid,19,morant circuit,grammar dchool,south turramurra,2040,vic,19960111,2799521 +rec-1750-dup-0,ethan,paie,111,galloway street,hvd cottage,largs,4680,vic,19190329,5356894 +rec-1437-dup-0,michael,sideris,45,,erinundra,yararm,6059,,19510317,9096326 +rec-2724-dup-0,lauren,dent,42,lindrum crescent,hamilton,bidwill,2905,vic,19840916,7699699 +rec-2019-dup-0,mya,ongley,20,tenison-woods circuit,alro n,rosegud,3194,wa,19940810,3204273 +rec-4222-dup-0,luke,wardle,30,holyman street,middle ridge medicale ntre (cnr ramsay,kirwan,3073,wa,19500525,9974023 +rec-133-dup-0,jackson,koklas,43,villa 2,cousin place,pearcedale,7018,wa,19850701,1074399 +rec-33-dup-0,clarke,ryan,42,goodchild street,villa 5,sandy bay,4565,nsw,19940903,9100049 +rec-4648-dup-0,charlie,reid,1,gannon p lace,bennettchambers,woollahra,2518,tas,19150113,1045143 +rec-2421-dup-0,zachary,drysdale,13,lee-steere crescent,roblinvale,lindfield,2169,qld,19011228,4223439 +rec-1892-dup-0,hayden,beattie,5,monaro cre scent,sandilnads,cloverdale,4059,qld,19530424,4745672 +rec-2087-dup-0,jarrod,manson,2,dalgleis close,caravn park,mypolonga,3182,qld,19160808,9103733 +rec-4139-dup-0,charlotte,maynard,33,tarrabools treet,little sy alford,worongary,2068,nsw,19840915,3337218 +rec-4033-dup-0,tayla,iovino,15,seddon place,civic centre,millers point,2763,nsw,19560823,9282697 +rec-1330-dup-0,cain,dietrich,40,eugenia street,legacy u nits,bunbury,3782,tsa,19550801,2545231 +rec-4313-dup-0,mcveigh,lauren,,bremers treet,werribee lpaza,cranbourne north,2039,,19261230,4278721 +rec-1645-dup-0,christian,drechsler,75,,,summer hill,7018,sa,19580327,1471940 +rec-3142-dup-0,oakleigh,hoang,27,la perouese street,tiverton,wyogn,4817,tas,19680324,6697687 +rec-3041-dup-0,hai,dominey,24,albermarle place,wingara,theodore,5235,qld,19060322,6430390 +rec-1096-dup-0,oliovia,druitt,22,hacking crescent,,gree nacre,5141,vic,19950307,7527562 +rec-4257-dup-0,jasper,trowse,1,kilburn c lose,the village condo 23,crestmead,4102,qld,19970120,5630769 +rec-1731-dup-0,tayah,yeatmin,65,edmondso tsreet,,sanctuary point,2545,wa,19960422,8014534 +rec-725-dup-0,,,1,william street,woodsong,nicjol,6149,qld,19000430,6432290 +rec-2321-dup-0,brdy,berr,98,edwards sreet,,albion park rail,3660,vic,19620118,4534503 +rec-2485-dup-0,madeline,zbierski,31,nedlyn,newman morris circuit,westmead,2088,nsw,19801012,6366322 +rec-2414-dup-0,alana,cronshjw,18,tristania street,,rowvikle,4610,nsw,19690202,9453034 +rec-1654-dup-0,eliza,clarie,10,arnold place,,raby,6148,tas,19860203,8112754 +rec-3072-dup-0,heatfer,paulsen,1,ahern place,unu 3,kilmore,2504,qld,19840615,3281035 +rec-2215-dup-0,lachlan,gilcrist,26,maribyrno ng avenue,kuliu,leicjhardt,4578,nsw,19570926,7115051 +rec-389-dup-0,william,mccarthy,47,culgoa curcuit,research tsation,evans head,6110,nsq,19010118,1681813 +rec-4559-dup-0,ryan,whie,19,wilkins street,logancrail,banksia,4064,sa,19760204,7368589 +rec-4946-dup-0,samuel,lvarga,64,postle circuit,abbey g reen,rokeby,2199,vic,19641231,4801979 +rec-2733-dup-0,patrick,green,88,kelsall place,killarney east,rose bay,5108,nsw,19151112,5843206 +rec-4417-dup-0,sebatian,demarco,9,cotter road,kelman vineyard,wyongah,4670,,19050730,3478101 +rec-1066-dup-0,sarah,campbell,9,clavert place,merricroft,mount eiza,5280,qld,19410302,9870428 +rec-4739-dup-0,jory,chandler,5,wearing street,,chesteq hill,2113,nsw,19381011,2421676 +rec-4157-dup-0,breaenne,demarco,21,shenton crescent,,hamilton,3804,nsw,19170802,3018112 +rec-3126-dup-0,jasmine,mcfadden,46,noongalecourt,rosetta village,marshdale,4215,sa,19760927,6401287 +rec-1394-dup-0,caleg,miotto,6,besant dtreet,,bayswatre,3033,sa,19610729,6597548 +rec-4185-dup-0,jenna,grosser,7,heagney crescent,,ashwood,2528,nsw,19020713,3312375 +rec-3407-dup-0,catheine,cambpell,3,henty street,,moorahbbin,2794,nsw,19730310,9201547 +rec-827-dup-0,michael,heidrich,37,wonga square,degraves cirescent,samford,6140,nsw,,3945989 +rec-4021-dup-0,nicole,clarke,34,tong place,villam 27,point cook,2121,qld,19220519,1665679 +rec-3621-dup-0,lachlan,jolly,7,daintree crescent,wondersun,sandgate,2537,vic,19480906,8781863 +rec-750-dup-0,julia,,1,doonkuna street,witsend,robertson,4214,vic,19760907,8222581 +rec-1159-dup-0,rhys,mason,49,geils couxt,banksiavillage,,5066,wa,19000608,7868339 +rec-557-dup-0,ruby,bradcy,11,allott place,,wynnumw jst,2260,wa,19440101,7323803 +rec-3566-dup-0,michael,mesecke,114,hopetoun circuit,oakdene,sussex inlet,3020,qld,19130121,4530596 +rec-3896-dup-0,,lodge,,forbess treet,glen alvie rsd,birkdale,5118,nsw,19691225,7105186 +rec-2600-dup-0,oscar,vrlic,10,singleto ncescent,,roberggson,4220,vic,19700526,4539064 +rec-3433-dup-0,charlotte,meaodws,59,totterdell street,b,plumpoon,2905,qld,19030219,6004748 +rec-1047-dup-0,alexandra,zolyniak,131,,wandana,girlaang,4285,qld,19421008,7197883 +rec-2594-dup-0,ellie,green,13,yerra court,nanum,mirboo nnrth,6056,sa,19086011,5986644 +rec-2317-dup-0,lydia,hindmarch,12,roope close,garden est,yass,2454,nsw,19130103,6703072 +rec-3791-dup-0,jacob,callahan,107,lyrebird place,,burwodo,6152,wa,19220110,4360694 +rec-648-dup-0,matthew,adair,6,langdon avenue,,upwey,3095,sa,19031126,6474688 +rec-1358-dup-0,connur,bishop,450,earle street,coorrabin,roselands,7320,vic,19261223,7015666 +rec-2833-dup-0,jed,kempton,45,novar tsreet,kala ng,corrimal,2756,wa,19991224,3763645 +rec-1342-dup-0,seth,salt,148,carss place,burnside,alice sprjings,4005,sa,19531004,9880146 +rec-3055-dup-0,gabrielle,,35,mawson drive,glenmore,,3178,vic,19830918,7581914 +rec-783-dup-0,joe,clarke,7,skardon treet,bonnie doon,north cu rl curl,4122,sa,19640223,3654594 +rec-1262-dup-0,emmerson,maziakowski,58,irvine street,loughmore,nunawading,4211,qld,19400316,1807259 +rec-1448-dup-0,tea,donaklsdon,,o'sullivan street,willow lodge,springwood,7030,nsw,19891118,8492921 +rec-331-dup-0,harriwon,whayipe,19,westalo place,ainslie house,baranduda,3220,qld,19170531,7892154 +rec-487-dup-0,jaggkh,estanillo,4,amagula avenue,sec2 12 8,devonport,2480,nsw,19350318,6334723 +rec-1619-dup-0,jesse,herbert,16,popplewell place,coliban glen,toowolmba,3810,qld,19981021,5942526 +rec-3593-dup-0,marleigh,sieris,42,henry melvill crescent,bociing,morpeth,3039,sa,19251227,6987405 +rec-660-dup-0,evan,wilkey,26,gudgenby close,portland house,park orchards,4828,vic,19571204,4568068 +rec-4899-dup-0,daniel,coleman,1,russell drysdale crescent,palm lakw resort,mount eliza,6159,wa,19651018,1615911 +rec-2652-dup-0,renai,byers,31,goyder street,,yankalilla,6722,vic,19760805,7669938 +rec-3187-dup-0,gabrierl,bobroff,6,kirby place,mora bnah,wentworth falls,4655,nsw,19660608,3840632 +rec-3235-dup-0,njah,van de kamp,39,feathertoo street,argyl s quare,heckenberg,5072,vic,19180723,8217720 +rec-1175-dup-0,alexandra,clarke,15,inkster street,st agnse vlg,carrum,3930,qdl,19060712,9221028 +rec-1716-dup-0,charlie,cloudsdale,34,fred lane c rescent,,east maitland,3046,qld,19430211,1765101 +rec-3617-dup-0,darcy,nguyen,68,ferdinand street,willarra,osborne park,3073,act,19810513,8210958 +rec-577-dup-0,ryan,william,33,limbunya street,cherrybank,new farm,4105,nsw,19550514,5451157 +rec-2423-dup-0,channig,hick,132,noarlunga crescent,,albury,3060,nsw,19201122,2347507 +rec-3020-dup-0,madison,herbmert,14,cowie palce,old post office,glenmore park,2608,nsw,19950105,9689395 +rec-503-dup-0,kirasak,carla,5,albermarle place,,bacchus marsh,5085,vic,19630801,6299625 +rec-1095-dup-0,tiarna,nevin,3,roope close,,preston west,3318,,19460426,9509846 +rec-4055-dup-0,camerln,dolejs,17,medley street,merrangbauer park,prospect,4812,sa,19250828,8585871 +rec-2413-dup-0,indywna,clarke,,fisher street,mountain view village,wetherill park,4211,vic,19170704,3405046 +rec-4826-dup-0,jock,loukes,13,phillipson crescent,newry farm,tallong,2099,sa,19220113,2561584 +rec-845-dup-0,akri,masno,5,verran lace,rowethorpe,franksyton,6147,vic,19851022,7763548 +rec-3052-dup-0,lucas,ypon,54,johnstone chircuit,shady creek,wingham,3039,qld,19761101,8649392 +rec-2860-dup-0,zdne,white,15,mcwhae circuit,westmea d accom,concord west,2032,vic,19770208,9225108 +rec-1764-dup-0,jassmi,lodge,36,gregson place,congreave court,kingsford,3089,vic,19840309,6085755 +rec-2934-dup-0,zarlia,sau,113,clanville,audas place,robian,2322,nsw,19230085,8270751 +rec-4742-dup-0,noah,flatman,13,mawalan street,northoburne,frankston,5049,vic,19790808,6564082 +rec-690-dup-0,edward,assadi khansari,,glenview,shipard place,picton,4020,vic,19480210,5693557 +rec-3306-dup-0,lucas,green,2,castlereagh crescent,dunbogan car avan park,beecroft,3073,tas,19760131,5181228 +rec-3875-dup-0,madison,zimmermann,27,mckail crescent,public school reserve,elsternwick,3636,wa,19340306,9888953 +rec-4361-dup-0,tynan,ryan,17,darwinia terrace,swinton,acacia ridge,4241,nsw,19510905,4210506 +rec-4962-dup-0,acciairresa,ruby,4,broad place,rowan lozdge,wamberal,3431,nsw,19250609,7388992 +rec-50-dup-0,emerson,reid,5,kater p lace,forest views,acacia ridge,4215,nt,19820814,2582300 +rec-2131-dup-0,kaitlyn,van schie,127,capellac rescent,banksia village,oak park,5093,nsw,19000127,1321883 +rec-2448-dup-0,gabrielle,siemers,28,archibald street,seaforth garden,american eiver,5223,vic,19140203,4388778 +rec-1803-dup-0,robbie,carmody,34,bernacchi street,melita,east fremantle,2170,qld,19391211,8441818 +rec-3353-dup-0,jack,colean,7,,rio rita caravn park,dandenong north,6026,sa,19560223,9860608 +rec-4840-dup-0,imogen,pun,1,templestowe avenue,peak view,belconnen,4214,nsw,19400709,4490158 +rec-190-dup-0,,alias,24,elkington street,panganu,isle of capri,2145,sa,19650429,8261472 +rec-1600-dup-0,joshua,mortlock,62,yates gatden,bulala,camperdown,2148,nsw,19180804,4756935 +rec-1282-dup-0,,teteirs,,kellermann close,b oneo,brighton,3030,nsw,19381004,5797955 +rec-1919-dup-0,noag,bishop,12,stobieu place,highgate,bailey creek,2134,qld,19130403,4950296 +rec-91-dup-0,jacob,clarke,10,ebden street,,loganlea,6061,tas,19181001,4259955 +rec-3920-dup-0,jacqueine,pride,9,william webb drive,bell place (cnr bell r road,richardson,4065,nsw,,4570880 +rec-2182-dup-0,zachary,ebert,8,rounsevelk street,lake road,mount gravatt,2112,nsw,19261127,1502014 +rec-328-dup-0,ronan,zatorski,13,lott place,bobblegigbie,ringwoo east,5109,qld,19870107,5925683 +rec-1717-dup-0,binns,jade,2,fiveash street,caterer,auburn,3690,nsw,19470306,5117331 +rec-872-dup-0,,wanders,453,louis loder street,hilltop iew motel,avoca,2284,qld,19120509,3198280 +rec-3034-dup-0,emiily,robnik,288,gossestfeet,,werrington,4216,nsw,19671025,8062583 +rec-3725-dup-0,james,hyland,42,hurley street,springmount,emu plains,3207,nsw,19870607,7791289 +rec-704-dup-0,benjamin,goldsworthy,2,forbes treet,wdgee otreet,tarragindi,2606,vic,19540317,6447881 +rec-279-dup-0,lachlan,laing,65,,bega flats,parap,4110,nsw,19600429,4688353 +rec-4291-dup-0,john,homamn,27,sid barnes cbrescent,king riverp alms c8,cranbourne,5159,nsw,19461027,4896844 +rec-3835-dup-0,jade,barteu,10,kurrajong vlge,london circuit,buronga,2338,vic,19430103,4602097 +rec-2459-dup-0,ne,donaldson,12,callabonn a street,linton,port lincoln,3213,vic,19170225,3467256 +rec-1827-dup-0,heath,monteleenoe,,marsden street,safari lodge,bicton,2227,qld,19781013,6970423 +rec-1609-dup-0,osyar,hartland,16,prout place,gummin gummin,molong,3218,nsw,19440709,6879379 +rec-2985-dup-0,coby,brain e,14,longmorekcvrescent,clftn waters vlge,gavln,2747,nsw,19491118,3329459 +rec-822-dup-0,zachary,goode,39,alroy c ircuit,,broadmeadows,7250,nsw,19900208,3817430 +rec-3544-dup-0,jessica,belchel,9,irvine tsreet,st francis vlge,port macoonnell,2029,sa,19700610,5379753 +rec-2505-dup-0,calbe,bristow,134,brunswic circuit,granny flat rear,mclaren flat,5019,tas,19720321,7570563 +rec-4596-dup-0,jai,browne,124,eugenia s treet,jacqoona station,ascot vale,3350,wa,19030809,8431885 +rec-2435-dup-0,beloma,griersn,27,priddle street,green lagoon,christies beach,3152,vic,19310623,5872915 +rec-3856-dup-0,claudia,damianos,19,noarlunga crescent,woodcrset,beeliar,2230,nsw,19780811,1802317 +rec-2757-dup-0,georgia,ashe,38,onslow sreet,rsdb 284,prospdct,5453,nsw,,6899844 +rec-2725-dup-0,diloln,lowe,31,faithfull circuit,mlc c entre,colac,2088,nsw,19961116,6464208 +rec-2099-dup-0,caitlin,milburn,17,heard ptreet,lexington,newborough,2840,qld,19530105,3195330 +rec-93-dup-0,charlotte,bristow,22,nioai,mockridge crescent,harbord,5086,nsw,19351112,4814908 +rec-2199-dup-0,emi ilu,allard,19,kingsbury street,moons farm,broken hill,4218,nsw,19760502,6633337 +rec-2432-dup-0,warde,isaiah,14,mcphail place,subbury,bonnykrgg,3929,vic,19090111,8475133 +rec-483-dup-0,eva,lepaprd,,kurrama close,casuarina village,port macquarie,5280,nsw,19370728,8035602 +rec-1693-dup-0,cooper,nguyen,,burrinjuck crescent,dawlish,bateman,6059,qld,19700104,2035745 +rec-2900-dup-0,annik a,boyle,10,,,paddington,3175,qld,,7187050 +rec-2327-dup-0,hauser,andrew,11,wanganeen avenue,tarkarrndi,heckenberg,2289,vic,19270207,3336874 +rec-1846-dup-0,isabella,,6,,weowner,mooloolaba,3101,qld,19950522,9028103 +rec-703-dup-0,noah,staude,25,mac george place,locnl8200,stratford,6011,wa,19760505,9182953 +rec-4428-dup-0,philip,hyla nd,77,lightfootgcrescent,remo,ashwood,4102,vic,19071218,7390839 +rec-3309-dup-0,madeline,clarke,54,ballumbir street,ballymannin,springwood,5153,nt,19471024,8251151 +rec-800-dup-0,matthe ws,erin,37,pocket avenue,kangaroo grnd,goodna,3160,nsw,19351004,7562147 +rec-768-dup-0,jasper,kuiters,109,ellenboroguh street,kalinda park,burwood east,3180,qld,19280512,9150558 +rec-450-dup-0,harrison,stanley,69,macaliste crescent,applewoods,thornlie,5063,qld,19871206,4461675 +rec-2969-dup-0,emiilt,conaghtwy,43,o'meara place,,ashgrove,3042,wa,19140520,4368793 +rec-3149-dup-0,bethany,jolly,31,melba street,sheep station,paddington,3059,wa,19690622,9831162 +rec-1885-dup-0,archie,dokas,6,abrahams crfescent,shalvah,malvern east,3163,nsw,19400807,1265030 +rec-1487-dup-0,,plumb,41,mcrae place,castlewood,pakenham,4241,nsw,19460521,2390847 +rec-3183-dup-0,,akkermans,149,slessor crescent,willera,broken hill,5175,wa,19130710,8370439 +rec-1852-dup-0,,nurse,1,hampton circuit,,gawler east,5091,tas,19340420,4801623 +rec-4577-dup-0,xepheren,coleman,8,gurney kplace,sec 479,dover gardens,6018,vic,19941205,1547145 +rec-2676-dup-0,jack,ryan,22,echo place,folsocit,loganohlme,2749,wa,19400114,1449566 +rec-1163-dup-0,mia,burford,4,starling place,dutch car e phostel,lawson,2257,vic,19040422,9377441 +rec-1167-dup-0,sara-kouise,chandler,309,schonell circuit,shoal bay,mclaren flat,2761,nsw,19050207,3731436 +rec-532-dup-0,cade,bishop,2,abrahams crescent,carney's arcade,clayton,4059,vic,19830405,2481294 +rec-499-dup-0,reece,aleisha,35,delprat circuit,villa 5,woorine,4870,qld,19730623,1718031 +rec-4593-dup-0,,rundle,3,hicks syreet,blackbutwood,oragne,3078,nsw,19380125,4860814 +rec-1451-dup-0,jade,stanley,2,baracchi crescent,mlc qcetnre,cranborune,6111,nsw,19480216,3818853 +rec-889-dup-0,jordan,lock,27,tallara arkway,retirement village,manly vale,7520,vic,19070222,9835720 +rec-928-dup-0,samantha,barmore,23,bilby prlace,yarrandoo,somerset,3073,vic,19641215,5082469 +rec-2276-dup-0,,neville,4,fitzmaurice street,karkrutt,gilmore,2517,wa,19591005,2038776 +rec-4977-dup-0,marris,shanw,35,heard street,rmbh 884,lilydble,5352,vic,19671112,2643005 +rec-4043-dup-0,hope,connor,7,wyselaskieycircuit,hidden valley estate,goldenw bay,3070,vic,19190806,1644424 +rec-1409-dup-0,kempe,tylah,8,arthur circle,tylden park,adamstown heights,3133,sa,19721016,1844518 +rec-32-dup-0,cale,spurden,119,mcalpine place,greensopes,boyne island,4228,sa,19580816,8017617 +rec-2796-dup-0,brooklyn,ryan,1,sainsbury street,pine gill,american river,3241,nsw,19200516,5720021 +rec-632-dup-0,,colquhoun,11,strong place,ocean star villas,modbruy,2213,qld,19621022,3058669 +rec-4150-dup-0,joshua,golden,22,mcintoshusreet,ra23 f102,noble park,2753,sa,19940329,1150948 +rec-442-dup-0,william,matthews,5205,tunney crescent,rainbow downs,andergrove,2164,nsw,19981106,7834791 +rec-4114-dup-0,mia,pascoe,54,dwyer street,,leichhardt,2015,sa,19080310,5423895 +rec-3739-dup-0,jaciob,,1,barada crrescent,challicum south,bacchus marsh,3026,nsw,19370320,8873242 +rec-3112-dup-0,sam ara,joel,66,crisp circuit,john curtin hostel,mount eliza,2477,qld,19001010,9937630 +rec-584-dup-0,renee,renfrey,24,serpentine street,retmntvvlge,winchelsea,2176,wa,19690305,5153203 +rec-909-dup-0,ella,chudzinski,7,carter crescent,,caulfield,7008,qld,19321101,4473731 +rec-204-dup-0,jed,boultre,41,mcmillan crescent,old post fefice,rye,5213,nsw,19471229,2521349 +rec-1073-dup-0,jsk,stanbur,25,de vis place,kersley mews,koorawatha,4074,qld,19381131,7301101 +rec-1939-dup-0,oakleigh,stephenson,14,mcdowall place,tatyara,bridgeman downs,2259,nsw,19860110,9292818 +rec-114-dup-0,alana,green,2,wittenoomfcrescent,tulla burra,mount eliza,4051,wa,19030904,7711269 +rec-4932-dup-0,marleigh,ayres,36,bussellc rescent,mountview,margaret river,2756,vic,19210901,5485654 +rec-448-dup-0,,lodge,18,haynesplace,glenfin estation,flagstaff hill,6060,vic,19651012,1604189 +rec-4642-dup-0,judah,simmonds,12,elsey steret,summef hill,hamilton,2444,vic,19940414,2036044 +rec-3434-dup-0,alex,clarke,12,,emeral dgarden,homebush,2321,nsw,19840627,7280280 +rec-1581-dup-0,nathan,dunstone,41,shirlow place,poldoe park,blacutown,3820,nsw,19001013,1854047 +rec-3781-dup-0,nathsn,nguyen,12,staaten crescent,yarar pee,moura,3179,qld,19961006,4794269 +rec-1570-dup-0,ryan,matthew,55,fitzhardinge crescent,mlc centre,burpengary,2546,sa,19510417,2890790 +rec-2790-dup-0,carla,gasparin,122,fitchett street,marx hills treet,burrum heads,3022,nsw,19511229,7746397 +rec-1685-dup-0,tahlia,inglese,39,blakeyclose,riv oli,lakes en trance,3222,wa,19561220,6197497 +rec-2406-dup-0,oliver,white,9,tillyard drive,tievr tara,hawthorne,3068,,19310120,8686735 +rec-496-dup-0,heron,brooke,262,verbrugghens treet,oxley's way,hackham,2560,qld,,7028101 +rec-4927-dup-0,daniel,glad,,roe street,rowethorpe,tungamull,2026,tas,19170309,4569679 +rec-720-dup-0,luas,coleman,,burn sreet,,ringwood,2843,vic,19991101,7896258 +rec-49-dup-0,madison,bradxhaw,13,jardine street,,norwood,2335,sq,19490115,8836136 +rec-4239-dup-0,,cumiang,9,albermarle place,harkness station,natimuk,3158,nsw,19911129,2315316 +rec-3189-dup-0,,ongkieko,,murray crescent,,corrimal,6165,qld,19740627,8899763 +rec-4974-dup-0,joshua,grimsley,22,barwonjstreet,,carnegie,3136,qld,19390617,3359093 +rec-88-dup-0,sebastian,ryan,465,mathews place,don ray,spencer park,4210,nsw,19080114,8520668 +rec-2390-dup-0,jacoub,white,11,wilga place,,wallabadah,4061,nsw,19760515,6381291 +rec-419-dup-0,james,mcclelland,9,chandler street,glen eltin,,4350,nsw,19270128,5369982 +rec-2641-dup-0,adnrew,ryan,9999,woralul street,fleurbaix,flinders park,2066,nss,19510328,2922598 +rec-2829-dup-0,timothy,de angilis,95,casey crescent,lumeah h omes,brighton,3400,sa,19910709,6079337 +rec-4736-dup-0,ashlie,jolly,59,a'beckett street,millwood,slacks creek,3020,nsw,19820807,7111279 +rec-4973-dup-0,jesse,sarnyai,67,sandover circuit,morris twoers,ballarat,2071,qld,19350511,7047460 +rec-2286-dup-0,lachlan,rya,21,alberga street,tatrha,forest hill,3150,qld,19070322,9772701 +rec-10-dup-0,lachlnn,reid,5,carrington road,legacy vlge,yagoona,2446,nsw,19500531,3232033 +rec-941-dup-0,william,zilm,,,moonya co ttage,reynella,2165,act,19430728,8235647 +rec-3153-dup-0,pearson,mesecke,17,carruthers street,villa 147 henry kendall bayside,glendlae,3850,nsw,19650218,8701573 +rec-4536-dup-0,ruvben,weaver,,stevenson street,talling park,wahroonga,5280,vic,19730324,1196393 +rec-4782-dup-0,charles,sarny,34,esperance street,brentwood vlge,thornbury,3221,qld,19971014,3125264 +rec-1874-dup-0,connor,webbn,,hargraves crescent,,andergrove,3806,wa,19501118,4659489 +rec-1179-dup-0,stephanie,george,50,mccullocn street,ardrossan,berwick,2226,qld,19691102,3352838 +rec-1843-dup-0,ethan,hipkiss,7,lempriere crescent,spring creek,woolgoolga,3199,qld,19500212,3524910 +rec-138-dup-0,bailey,sette,6,griffiths treet,the sanys,valley view,3159,nsw,19880626,4637182 +rec-2401-dup-0,fergus,sherin,3,whitford place,locn2093,mulwala,6064,nsw,19950727,1284784 +rec-2723-dup-0,nicholas,whie,22,walga place,mt annan,petrie terrace,3012,nsw,19611008,4599672 +rec-732-dup-0,renee,chandler,6,,redgums ( rmb 1239),beulah,5057,wa,19360610,8922410 +rec-2229-dup-0,chittleborough,casey,9,brigalow t reet,hamilton central,belgrave,5341,,19550530,3208087 +rec-1871-dup-0,thomas,webb,7,scottsdale street,,brighton,6052,vic,19990815,9760969 +rec-4576-dup-0,callie,nitsols,7,tausslpace,dp 808602,koo wee rup,2287,vic,19400210,3752472 +rec-1296-dup-0,joshua,george,24,rose scottcircuit,ponderossa,goonellbaah,2464,nsw,19250202,9620943 +rec-1022-dup-0,bridegt,knopf,67,shackleton circuit,,naracoorte,5255,qld,19470309,5405822 +rec-2289-dup-0,alessandra,thorpe,33,crowder ckrcuit,melrosefarm,karalee,7250,qld,19080406,8221563 +rec-4728-dup-0,ebony,penno,62,weingart hstreet,,mintdo,2840,qld,19090710,9031641 +rec-429-dup-0,matisse,kromwyk,14,charterisville avenue,phillip lodge,toowoomba,2880,nsw,19190122,1739567 +rec-4330-dup-0,caleb,marlow,2,meeson street,barakee,blackall,5223,nsw,19110728,8601970 +rec-1602-dup-0,sophie,blackwekl,34,nott sgreet,jorobe,lansvale,6149,nsw,19501128,7543684 +rec-1053-dup-0,lkue,quast,4,,raworth cottage meedical practice,east ryde,6210,vic,19760328,5098690 +rec-2275-dup-0,alissa,leong,,maranoa street,,windang,2785,vic,19380612,2265634 +rec-4653-dup-0,jamea,taslidza,47,galloway street,lazy acres,limeburners creek,2650,vic,19700312,9827257 +rec-3649-dup-0,alexadnra,agett,48,keith street,boronia,taree,6436,nsw,19180406,8624670 +rec-1721-dup-0,van ttuil,jacob,39,vonwillerq crescent,,coombabah,3094,qld,19110716,8651342 +rec-1166-dup-0,jacina,lomman,22,collings street,the hammonc village,,3162,qld,19061009,6853014 +rec-1474-dup-0,samule,satterley,,osmand street,cascade condo,scotland island,6151,wa,19620515,1430466 +rec-4512-dup-0,bailey,meaney,82,miago co rt,uarah,mortlake,3156,qld,19880818,8223923 +rec-428-dup-0,bailey,stanley,30,colmer street,roclkea,rowew bay,0850,nsw,19010804,3200988 +rec-3204-dup-0,,colpo,2,trigg place,souther ncross,clarinda,6018,vic,19280716,4186527 +rec-3727-dup-0,hugo,mccarthy,154,chauveo street,ohio station,port fairy,3840,nsw,19550609,5250727 +rec-2244-dup-0,fergus,sunderland,88,wilson ctescent,dunbar heights,whalan,6060,,19591210,4398162 +rec-1076-dup-0,voulgaridis,lia,19,kingsford smith drive,glenavon,mosman,6158,nsw,19960531,3691075 +rec-1571-dup-0,alicia,clasrke,72,rowethorpe,fitchett street,whaaln,2643,nsw,19811201,4620958 +rec-3535-dup-0,michael,ngulyen,6,lukin palace,sunnyspo tfarm,beaumont,2231,nsw,19130316,6962550 +rec-4533-dup-0,lily,berry,77,crofts crescent,railway cttage,rose bay,3340,sa,19590415,6015647 +rec-111-dup-0,amy,seetoy,50,busbh street,bellfield,st albans,2870,qld,19160523,4467636 +rec-4105-dup-0,jake,vigneswaran,24,franklin street,westside,geelong west,4114,nsw,19700129,2559983 +rec-4393-dup-0,andtrea,coffey,,dampier cerscent,katimba,ashfield,6152,vic,19300416,7093245 +rec-883-dup-0,ethaen,wotton,10,crisp circuit,marlou,beenleigh,3400,qld,19260127,9022306 +rec-1457-dup-0,robery,waller,4,cutlack street,glenv iew,wellard,3000,vic,,4754283 +rec-2622-dup-0,jaden,mccarthy,,rubbo crecsent,glendas,gosford eagt,5641,qld,19030106,8577794 +rec-1105-dup-0,nicholas,jehvey,59,bogan place,hoepview,bundaberg,2404,nsw,19921231,4030459 +rec-4795-dup-0,michaela,wasley,10,lake place,faringdon v illage,coombabah,2192,nsw,19560410,5571708 +rec-2910-dup-0,dakota,mcgarrigan,2,jackie howe crescent,emmaus vlge,pialcigo,2204,wa,19861028,7729416 +rec-1099-dup-0,kawe,garden,9,bettington circuit,robinson road,rochester,3121,nsw,19021008,8610454 +rec-602-dup-0,benjamin,green,,jennings street,,terranora,6009,vic,19681029,4718046 +rec-869-dup-0,zarila,slape,63,cory place,ingevale,coom,3356,wa,19821201,7582121 +rec-4979-dup-0,timothy,webb,23,tom roberts avenue,cathederals place,padstow heights,2193,nsw,19270531,2303333 +rec-4223-dup-0,gabriel,david,24,downward place,berkeley vlge,bossley park,2872,qld,19030305,7363149 +rec-55-dup-0,harrison,herert,9,davidson street,allamby biala street,mulgrave east,4871,nsw,19480129,4129781 +rec-3373-dup-0,alisa,clarke,2,langdon avenue,cliffdon park,eaglehawk,2100,nsw,19760105,1902858 +rec-885-dup-0,harley,coleman,4,pridhamstreet,merrydsle,broome,2528,wa,19670119,3924027 +rec-1057-dup-0,pringle,samara,7,allan street,bonnie doon,campbelltown,5073,nsw,19560429,3493586 +rec-157-dup-0,lachaln,coleman,59,marsden street,bell place (cnr bell r road,richmondw est,3995,tas,19060305,2870281 +rec-3786-dup-0,nicholas,cochrane,845,olney place,,edithvqle,2450,vix,19260717,9800269 +rec-2731-dup-0,tegan,galbraith,130,pinkerton circuit,,altona ymedaows,6020,wa,19850912,9290065 +rec-523-dup-0,,maslich,38,ibis street,wee wilbretree,carine,3337,vic,19003129,3611483 +rec-3413-dup-0,amber,durnin,41,hindmarsh drive,walmoutn,knoxfield,3643,vic,19521010,8760281 +rec-1332-dup-0,benjamin,blake,4,phillimore place,tara park,sutton forest,3309,nsw,19481216,9939498 +rec-3774-dup-0,noah,clark,555,fizelle place,anstee court,bogagbri,5159,nsw,19540920,8260965 +rec-2279-dup-0,elizabeth,madigan,,port jackson circuit,rosedha le,panna ionica,3182,tas,,7796244 +rec-4750-dup-0,aliaa,white,356,,wemysd,mosman,3183,vci,19660226,7732220 +rec-1991-dup-0,fergus,clarkg e,674,o'rourke street,bobblegigbie,casula,2213,vic,19380302,1449123 +rec-2770-dup-0,clodqgh,campain,37,glen apin,captain cook crescent,wattle flat,4870,nsw,,5067638 +rec-3141-dup-0,blaize,matthwws,191,mirningcrescent,laurel bank,ardrossan,2550,nss,19441202,5876491 +rec-4437-dup-0,white,marleigh,91,,yengola,kempsey,2536,nsw,19831227,6262171 +rec-3418-dup-0,,ridzing,336,kallara close,unt 2,altona north,2177,qld,19320604,7712618 +rec-4683-dup-0,stephanie,heidrich,43,zamia place,cooroora,hyde park,6101,qld,19300222,7559482 +rec-4487-dup-0,madison,blake,25,owen crescent,pontresina,burraneer,4701,vic,19470410,6459959 +rec-2144-dup-0,kelley,isabella,9,march rising,covington crescent,east mitland,2343,tas,19090918,2297084 +rec-2580-dup-0,charlie,white,76,kavel street,posetto,campbelltown,6110,sa,19190109,3793652 +rec-384-dup-0,michadl,richmond,7,tanumbiriniu street,professional centre,bundaberg,3020,sa,,6836733 +rec-2947-dup-0,,herbret,2,coplan d rive,boolig al,gin gin,3971,nsw,19160928,6069675 +rec-4781-dup-0,jacob,waliler,89,dalley crescent,the ui llows,mosman,2487,qld,19580408,6317326 +rec-4989-dup-0,rosie,dixon,28,chataway crescent,burrmaunda,penshurst,2558,nsw,19960211,3496771 +rec-3644-dup-0,natassia,mccarthy,16,newman mor ris circuit,st john of gos hospital,port sorell,6324,nsw,19761016,1123871 +rec-2972-dup-0,imogen,polmear,102,macedon crescent,rowehtorpe,port matquarie,2847,sa,19241217,6794742 +rec-3861-dup-0,charli,gaskin,24,james smith circuit,villa2,gawler river,2641,vic,19590904,3925628 +rec-2646-dup-0,amy,sommariva,26,fernie place,glenfine station,surrey hills,6167,tas,19920303,8853255 +rec-235-dup-0,lynae,campbell,11,,willandar illage,preston,2184,tas,19291114,4043690 +rec-3761-dup-0,joshzua,ho,23,mile beach caravan park,warragamwa avenue,east maitland,3181,nsw,19320427,9710227 +rec-4631-dup-0,lachlan,zwaadzki,,hazel smith crescent,wdgee sfreet,bowral,6148,sa,19990420,7589775 +rec-824-dup-0,holly,clarke,16,ballumbir street,talooby,sale,3166,nsw,19121217,8303839 +rec-4324-dup-0,lauren,nguyen,253,myers place,canberra hse,coomba,5034,nsw,,2534716 +rec-4065-dup-0,andrwe,,4,jeanette place,mehruda,mosman,2426,sa,,7007321 +rec-92-dup-0,alana,frahn,530,a'beckett street,,lakes enrance,2477,vic,19630307,4624078 +rec-475-dup-0,webb,mitchell,,bougainville street,rivermews,safetyfbay,2722,nsw,19480302,2186834 +rec-3722-dup-0,emiily,scheel,12,cuscaden cfrescent,hopeview,jamboree neights,4816,vic,19521013,4479715 +rec-2933-dup-0,harry,bradshaw,51,musca zplace,longridge,lilydale,2137,qld,19961111,3683424 +rec-2780-dup-0,,kothe,12,breona olace,lakes retirement estate,highton,4207,nsw,19620821,7592380 +rec-2968-dup-0,finn,teague,39,empire cqrcuit,wagin medical centre,prospetc,2083,qld,19650301,2488065 +rec-3069-dup-0,ashleigh,droegemueller,8,callaghan street,osmers,adamst own,3070,nsw,19300808,1309189 +rec-3317-dup-0,oliver,von host,75,pattinson crescent,school h ouse,hoppers crossing,3311,vic,19080425,8000122 +rec-436-dup-0,jackson,lehane,115,,hawksview,balwyn north,2099,wa,19390312,2738637 +rec-2995-dup-0,koben,courtena-ralph,30,illidge place,,st peters,3363,nsw,19921228,1887648 +rec-4124-dup-0,brianna,whiet,39,laughtosn street,coranidrk,stratton,4551,nsw,19840310,9784905 +rec-2382-dup-0,emma,mccarter,21,enderby street,,burwood east,3025,nsw,,1635330 +rec-336-dup-0,tess,pembroke,,lawes place,sheep station,brookvale,4605,vic,19890611,6248469 +rec-4255-dup-0,nathan,verco,,cumpston mplace,the summe r house,wanguri,6215,tas,19660404,7465594 +rec-1500-dup-0,jade,stronach,4,broadsmith street,miami,cohuna,2251,nsw,19090102,5258162 +rec-4771-dup-0,kayla,kerkham,29,cobb crescent,beach house,denmark,2318,qld,19130284,4646463 +rec-681-dup-0,karli,dennes,8,greenways,eggleston crescent,bundaberg,5158,qld,19280616,8579616 +rec-3833-dup-0,nicholas,clarke,,gaylard place,tryphinia view,wetherill park,2810,nsw,19041223,3972795 +rec-2338-dup-0,damien,webb,34,molesworth street,fairfield housing bg,werribeesouth,2484,qld,19440826,5682631 +rec-3056-dup-0,wio,whiteley,93,simpson ustreet,strathleven,kingston,2151,wa,19440822,8896048 +rec-4603-dup-0,lilly,sorn,32,herschellc ircuit,wongon,box hill south,2913,sa,19441009,9287185 +rec-46-dup-0,aprl,bellchambers,2,borrowdal street,,wunghnu,2080,qld,19970426,8134681 +rec-2231-dup-0,madalyn,noble,21,,caroonavillage,mathinna,4051,nsw,19460804,7883652 +rec-3277-dup-0,yasmin,green,12,diggles street,st john of gpd hospital,rushworth,5280,nsw,19750129,3139028 +rec-4363-dup-0,kenneth,priest,12,piper srteet,villa 449 blalycara,ferny xreek,2257,nsw,19151017,9976586 +rec-1687-dup-0,jaiden,ferris,2,pandanus street,merri bjaks,coffs harbour,4067,vic,19571204,1859065 +rec-1018-dup-0,biana,cbobett,,yerralee road,wongkn,woodend,3083,vic,,1020735 +rec-2849-dup-0,nicholas,mcveigh,23,boolimba c rescent,young retirement village,st kilda east,4224,qld,19341207,1581884 +rec-2203-dup-0,noble,sophife,9,university avenue,shenstone park,albion park,3325,vic,19361013,3379987 +rec-2825-dup-0,pakita,scarce,15,mckinleu circuit,killarney,connellys marsh,5067,qld,19600506,9865461 +rec-3466-dup-0,benjamin,donnolley,29,downward place,ocean star villas,downer,7256,vic,19881009,7579389 +rec-1067-dup-0,aprlol,wehr,,ellerstoh avenue,,joondabna,2150,wa,19941109,2560536 +rec-2060-dup-0,jacob,ditty,19,woralul street,secaytry,morwell,3153,qld,19670501,1212121 +rec-3580-dup-0,hannah,valengmini,5,rymill place,mayo,east maitland,4615,nsw,19490216,2488395 +rec-4597-dup-0,olizvia,trent,10,manity court,,campbelltown,6220,nsw,19740731,4392378 +rec-3753-dup-0,holly,spratt,8,spafford crescent,,st clair,3337,nsw,19130210,9895857 +rec-3928-dup-0,bertie,burford,19,erldunda circuit,rcg cemtre,ermington,3018,qld,19181119,7640441 +rec-2662-dup-0,natalie,fullerton,20,leichhardt tsreet,gostwyck,chelsea heights,6107,nsw,19620113,4058902 +rec-1092-dup-0,jaykob,ladyman,1,carbeen dtreet,apmnt 65,redbank plains,2564,vic,19071217,2992907 +rec-1820-dup-0,liam,cullens,121,chandlerw street,the burrows,safety bay,3073,qld,19910811,7828812 +rec-3941-dup-0,mattheo,crouch,5,crisp circuit,brentwood vlge,hurlstonepark,2170,wa,19120531,4393719 +rec-3703-dup-0,holly,,340,kirkton street,barwick paatoral,tarianga,4454,vic,19180806,6513574 +rec-4553-dup-0,ryan,linhdolm,125,coolibah crescent,acadia,kingston,3116,vic,19110122,9865390 +rec-1363-dup-0,campbell,clarke,14,wootton crescent,the manor garden,northmead,3625,vic,19220610,7658745 +rec-964-dup-0,san,singleton,41,clisby close,rockdan,toowoomba,4055,vic,19150122,7148269 +rec-671-dup-0,corey,godfrey,74,sturt avenue,cox cour t hostel,rapid creek,3976,wa,19880613,7156436 +rec-4520-dup-0,aliza,lloydd-wight,42,port jackson circuit,grnnyjflt,brusbane,3078,qld,19800509,8844981 +rec-1029-dup-0,charlote,dixon,8,lavan place,afflexian,booragul,3196,sa,19920713,7020668 +rec-1793-dup-0,,della-veede,113,rivett street,glen eden,figtree,2660,vic,19010271,8895395 +rec-4735-dup-0,patrick,newbown,8,la perousehstreet,,rose bay,6430,qld,19470920,2408047 +rec-4251-dup-0,cameron,shepherd,91,mckinlay street,pindara medcial centre,bonnyrigg,2075,nsw,19690127,6756218 +rec-3937-dup-0,caleb,campbell,5233,,locn 7560,hamilton,4214,sa,19220922,9117989 +rec-3819-dup-0,michael,asendorf,20,ulm street,elmwood,jindalee,6323,vic,19560227,4757924 +rec-3135-dup-0,gianni,campbell,39,spring range road,,eden,2602,vic,19911228,4150453 +rec-2456-dup-0,cassandra,cappelluti,3,flecker place,,holden hill,2592,nsw,19350419,7613246 +rec-4523-dup-0,callum,erett,9,tiptree crescent,,,3280,tas,19550825,3727793 +rec-4969-dup-0,victoria,zimmermann,37,o'sullivan street,kelgoola,nyah,2842,sa,19240517,7803602 +rec-2943-dup-0,tra,,67,beauchamp street,grey oaks,robertson,2213,,19200922,7897903 +rec-3511-dup-0,blake,rau,119,lenehan street,binnalong,burleigh heads,2065,vic,19040120,8590013 +rec-1133-dup-0,annabelle,berry,40,cherry haven,rowntree crescent,tongala,6028,wa,19430705,2510289 +rec-1689-dup-0,tess,carosella,35,goodsir place,ocean breeze,para hklls,4350,vic,19550517,2262772 +rec-2905-dup-0,destnyii,humphreys,41,black street,najee,carrmu,4066,nsw,19810924,6458612 +rec-3448-dup-0,makayla,cochrane,9,tillyard drive,the willows,coffshrabour,5089,nsw,19951205,3164154 +rec-1970-dup-0,etgan,robson,33,girdlestoun e circuit,granny flt,ringwood,2217,nsw,19770311,6427137 +rec-4749-dup-0,jackson,cambpell,8,carpente close,mounvtiew,dungwg,3033,qld,,8656075 +rec-1248-dup-0,hayley,wyeth,,griffin palce,terawah station,broadmeadows,6060,vic,19590129,8188526 +rec-2333-dup-0,sara,hage,89,collistplace,the lodge,mount eliza,4217,vic,19871026,2919243 +rec-1906-dup-0,nicholas,jermolajew,14,hodgson crescent,,mosman,2600,qld,19850327,5859130 +rec-4804-dup-0,alessandra,eyles,14,loureiro street,rowethorpe,illabo,2014,nsw,19210630,7014176 +rec-4987-dup-0,david,lovelock,24,davison place,,warramboo,3136,qld,19190717,2747099 +rec-1657-dup-0,jayden,gazzola,23,star court arcade,temperley street,dorrigo,2035,qld,19560809,7207945 +rec-3648-dup-0,matiad,ryan,5,bogan place,aldinga b each court,bethania,2259,nsw,19401012,6674118 +rec-4729-dup-0,jack,waller,31,currie crescent,sumner hill,bayswster,3579,vic,19550324,8581279 +rec-1465-dup-0,jolly,kasey,1946,bettington circuit,mater professional centre,whitton,7104,nsw,19450319,8287398 +rec-4727-dup-0,alicia,dixon,14430,embling street,kimberleh park,upper coomera,3551,vic,19860731,2677733 +rec-1569-dup-0,emiily,matthews,192,jacka crescent,,murogn,3012,nsw,19230603,2611585 +rec-1499-dup-0,witthoeft,emiily,,galmarra street,villa 5,kurri urri,2065,nsw,19421209,5224776 +rec-2767-dup-0,rosie,green,9,martley circuit,orana gardens retirement village,sefton,4740,nsw,19400512,1038720 +rec-4847-dup-0,harvey,fassina,,oakrale,pope street,ascot vale,4419,nsw,19840812,5859873 +rec-1028-dup-0,michael,clarke,37,mcintyre street,sherwood,maryborough,3113,wa,19240223,1884618 +rec-1646-dup-0,charlotte,maier,30,mountain creek road,frost mews,eight miye plains,4160,,19451123,2565331 +rec-879-dup-0,samantha,barre,14,gouge rstreet,cedar bay,balwyn north,2105,wa,19640121,2801474 +rec-576-dup-0,james,kempson,14,melia place,birks harour,elwood,2350,nsw,19480708,1343391 +rec-354-dup-0,lily,wastell,2,clare dennis avenue,glen rathur,marsden,2118,sa,19720903,2526870 +rec-1058-dup-0,juliana,wilde,20,westal l place,portland house,eden,4808,wa,19381207,3048642 +rec-2650-dup-0,caitlin,de boar,21,crisp street,section,ja n juc,5400,nws,19460307,3080624 +rec-2155-dup-0,grace,dolliver,28,geila court,north sta r resort,doyalson,5720,qld,19040326,8625522 +rec-3035-dup-0,gianni,peachey,55,tate street,,burwood,3154,sa,19451127,5162025 +rec-177-dup-0,aidan,campbell,41,edwards street,claiville,rolleston,4130,nsw,19410718,8324852 +rec-1709-dup-0,bekla,coleman,26,yollauplace,hounbank,whitfield,5007,nsw,19480127,9581654 +rec-3036-dup-0,sheldon,robert,37,baume crescent,springdale,cowra,4659,vic,19000924,7823439 +rec-56-dup-0,jacob,mcfaddeen,70,cowdery lace,plumpotn park,sunshine,5086,nsw,19090731,9735499 +rec-4628-dup-0,white,timothy,63,doyle terrace,windara,cardiff,5223,wa,19560731,4551355 +rec-621-dup-0,jake,blaje,212,cassons treet,longridge,geelong west,3280,nsw,19601009,8244609 +rec-3873-dup-0,bryec,crosswell,34,monkma n gstreet,,colac,4551,nsw,19301122,8289252 +rec-1713-dup-0,abby,tsokas,85,barnard circuit,,bassendean,3165,nsw,19290602,3554799 +rec-1525-dup-0,lushia,alclhin,940,poynton street,uc-dai-loi,,6014,vic,19870205,5901439 +rec-3332-dup-0,lily,chab rel,12,majuraavenue,lambton denture clinic,geelong west,6056,qld,19700626,7967866 +rec-2868-dup-0,micha el,george,8,burkitt street,halfmoonl station,toowoomba,2026,nsw,19350215,3561120 +rec-4343-dup-0,jordan,paterson,36,grono place,tarqua,maryborough,2607,nsw,19420219,2467275 +rec-3025-dup-0,hannah,sinoch,9,blackwell ycircuit,st francis vlge,broadmeadows,2650,vic,19770628,4760009 +rec-4801-dup-0,stella,cordingley,8,chandler street,,duncraig,3915,vkc,19000322,6694032 +rec-556-dup-0,giorgoa,ditty,10,williams street,rawdon hill,tarnasgulla,2404,vic,19171102,3194066 +rec-3882-dup-0,jacob,siviour,12,dobbieplace,brentwood vlge,gundagai,2839,qld,19160602,6864430 +rec-3943-dup-0,paris,quilliam,,hayden close,,north ryde,2450,nsw,19021008,2734415 +rec-2519-dup-0,jenna,goode,49,hedland circuit,kel a,kingaroy,3516,nsw,19920828,4224901 +rec-2945-dup-0,katelyn,cochrane,2,thozet place,eden park,swan reach,2759,nsw,19910821,9564362 +rec-3794-dup-0,leah,hilton,38,birdwood street,lucky corner,mitcnam,3169,nsw,19380702,9968264 +rec-852-dup-0,annabella,byers,114,glenmarla tmb 2563,teece lace,canley heights,4300,nsw,19630128,8053255 +rec-3077-dup-0,jett,mendrin,27,ainsworth street,colooli village,bassenedan,3777,nsw,19050414,4009853 +rec-2159-dup-0,,carullo,66,longman street,home vlge,mawson,4572,nss,19260527,5895140 +rec-4921-dup-0,waller,brooke,25,la peros e street,watcho rns hill,st lucia,3995,wa,19680216,5166618 +rec-398-dup-0,boyle,judah,289,,sapama park,west kepmsey,2225,wa,19000503,8429976 +rec-744-dup-0,simmonds,chevonne,24,victo ry place,,hoppers crossing,2047,qld,19420531,3553538 +rec-786-dup-0,courtney,okulewhicz,12,hodgson cr escent,,forrestfield,4214,tas,19990419,1581871 +rec-1533-dup-0,sophie,elderion,1,theodore street,seabank,salisbry,6026,nsw,19320402,6259234 +rec-4287-dup-0,szymczak,keely,17,kosciusko avenue,trevena,kingspark,2137,vic,19711125,2525516 +rec-4820-dup-0,madelind,harrington,81,coulton road,ashmill park,brgihton,2464,vic,19140630,8478957 +rec-2092-dup-0,genevieve,bristow,7,schonell circuit,the park,highton,3109,nsw,19890119,7811495 +rec-892-dup-0,wieloch,jack,29,mackennal street,,thornbury,2261,nsw,19500927,2954380 +rec-3853-dup-0,brianna,dixoh,18,staaten crescent,buckhobble,greensborough,3013,nsw,19860928,4919547 +rec-212-dup-0,irene,morriso n,16,maitlanrd tsreet,the mall,burleigh heads,4077,vic,19650804,9676251 +rec-4047-dup-0,bradley,offoin,33,mcwhae cir cuit,west park,scarness,2047,vci,19180420,4715993 +rec-3858-dup-0,mitchrell,forshaw,6,canninbstreet,karoeban,yanakie,2631,nsw,19470710,8308037 +rec-2120-dup-0,kyqie,stanleu,10,bugden avenue,wrem house,nunawading,2653,sa,19481020,6634230 +rec-5-dup-0,josephine,yu,145,hensman street,lambar,burwood,6164,wa,19310920,5792336 +rec-993-dup-0,jack,fitzpagrick,,condell street,,fullarton,2212,vic,19041121,9590543 +rec-1508-dup-0,lia,maymard,51,hensman street,under s ilos,modbury ehights,3196,nsw,19950704,9947782 +rec-4062-dup-0,kyele,mihakenko,6,fitchettr street,woodburn pastoral,paralowie,2229,nsw,19420817,7307571 +rec-2112-dup-0,emma,hage,43,ballumbir street,opal cov resort,newmarket,6061,nsw,19381224,3230581 +rec-3504-dup-0,ethan,lohmann,624,mcnamara treet,copely,tailem bend,4744,wa,19020126,1088335 +rec-1625-dup-0,chloe,campbell,26,darcy close,blxgrove,kedron,7249,sa,19210221,3030490 +rec-3499-dup-0,kydan,burford,249,garran place,cape hawke hosptl medcl centre,launcestno south,2126,nsw,19530728,5743011 +rec-4218-dup-0,melissa,monola,71,gilesstreet,north nowra shopping centre,greenwood,0810,nsw,19730130,3690365 +rec-4680-dup-0,zac,vincenft,19,goodchild street,,brighton-le-sands,6024,nws,19250320,4898468 +rec-404-dup-0,conno,petrillo,46,roebuck st reet,oakdale,boronia heights,7051,vic,19400425,8000924 +rec-4689-dup-0,olivi,stanley,244,,makrool,camp hill,5250,vic,19380424,1941202 +rec-95-dup-0,kiana,webb,144,cooling place,,norwood,0800,sa,19880716,8983519 +rec-4674-dup-0,brooker,chelsea,40,stuart street,,wellingotn point,2076,qld,19981109,5456111 +rec-94-dup-0,james,compton,19,landsborough street,st john of god hospital,edithvale,2234,nsw,19340309,3926610 +rec-1364-dup-0,jack,fitzpatrick,16,normantreet,lort hfe ights,scarborough,2520,,19190814,5911934 +rec-3890-dup-0,arren,white,4,eggleston crescent,,toowoomba,7116,nsw,19740614,1963582 +rec-2273-dup-0,chelea,tuckwell,,atherton street,,invemay,4868,vic,19391105,9172674 +rec-3403-dup-0,kyle,butt,7,beaurepaire crescent,brightwat er villas,bunbury,4750,nsw,,8272544 +rec-3881-dup-0,,zimmermann,,vickery street,kootignal,buddina,6330,vic,19810827,4538744 +rec-1982-dup-0,rachel,elstob,3,mullan street,,ivanhoe,4305,sa,19570111,5616006 +rec-2522-dup-0,bianca,thurlow,29,,shack 118,mal vern,2852,vic,19120204,8574662 +rec-4558-dup-0,jason,mcmul len,13,musgraves treet,black creek,ingham,2280,qld,19280901,4547198 +rec-1668-dup-0,weavwr,caleb,7,arabana street,ashell,harden,7171,vic,19300527,2414397 +rec-1954-dup-0,jessica,blake,112,gardiner street,jemree,cronulla,6525,qld,19871021,2057337 +rec-3452-dup-0,brooke,reeos,381,temperley sureet,,mosman,2100,qld,19630314,3610323 +rec-4845-dup-0,michael,acciairresa,18,eyre street,autum l odge,preston,4218,vic,19580720,5106898 +rec-4581-dup-0,taylah,sherriff,58,burkitt street,oxoni,lavington,4073,vic,19270919,8204283 +rec-551-dup-0,,blae,142,forbesastreet,white lodge,mill park,3133,sa,19990618,5715448 +rec-2922-dup-0,jordan,allegretto,22,stacy s treet,b,bonny rigg,2069,nsw,19380915,1390998 +rec-894-dup-0,,carkie,133,amagula avenue,fourmile,coodanup,2117,nsw,19280117,4243188 +rec-1033-dup-0,beau,zeitzen-van der burg,,william webu drive,kilnesy,bundaberg,6489,nsw,19500927,5594467 +rec-4779-dup-0,matthew,apted,1369,,pine tree,toowoon bay,2120,vic,19540130,5268631 +rec-4892-dup-0,joel,warneke,47,walsh place,corra-lynn,carrick,2529,nsw,19160910,4818906 +rec-748-dup-0,chelsea,campbeqll,136,croton street,ocean park towers,hawkesburypheights,3850,nsw,19550115,8861700 +rec-2319-dup-0,gaskin,keeley,128,winder place,chana k,west wyalwng,3138,wa,19550702,4856464 +rec-2094-dup-0,alicia,ferris,25,brereton street,macian house,ruse,2211,,19650926,5013659 +rec-759-dup-0,cboby,mason,220,,karnagh,kangaroo flat,2315,nsw,19641221,4800565 +rec-1834-dup-0,adam,tiller,13,westfield shoppingtown (next to medicare,sec 161,page,3127,vic,19410419,2449378 +rec-399-dup-0,teagan,white,54,knoll place,wangaay,padstow,6107,nsw,19210314,9334133 +rec-4685-dup-0,kelsea,worsuey,65,mackellar rcrescent,,hemmant,4208,qld,19990610,6206107 +rec-2397-dup-0,riley,matthews,34,westhoven street,stone oak farm,succses,4034,vic,19890629,5906706 +rec-3990-dup-0,makayla,matthews,42,cullen street,st francis orom,oakleigh,3233,nsw,19061006,7914045 +rec-4599-dup-0,james,,12,mewton place,ellwood,st george sbasin,3073,vic,19250703,5362406 +rec-2667-dup-0,daniel,nykamop,10,jingara cottage,baanenuc,warburton,3806,nsw,19611221,3482588 +rec-4834-dup-0,,quast,22,fincham crescent,zimms corner,penirth,2228,vic,19720423,2959997 +rec-2612-dup-0,josyua,white,11,finlaysonz place,hayfield vlge,the enyrance,4178,nsw,19560417,3821555 +rec-162-dup-0,portia,weaver,34,angophor astreet,knox retirement village,parramatta,3192,vic,19560218,7422879 +rec-4744-dup-0,grace,mcvicar,39,namatjira drive,,chisholm,4818,vic,19540503,2929679 +rec-3915-dup-0,ella,richmond,195,flack srteet,,berwick,5109,nsw,19820727,7932680 +rec-3014-dup-0,brandon,wintulich,260,bromley fstreet,caroowod,regents park,6023,vic,19810304,9945357 +rec-4891-dup-0,charlogte,donaldson,3,federal highway,allamby biala street,kilcunda,4073,nsw,19541208,5650823 +rec-1165-dup-0,aleesha,mahmud,101,saraji imne,mcculloch street,ulvertsone,6064,nsw,,9126691 +rec-995-dup-0,isabella,westbrbook,20,yanda street,carlwo,seven hills,2048,tas,19730807,1274198 +rec-3205-dup-0,,mainsbridge,12,cazaly close,earl haven,colac,3199,wa,19110409,9927051 +rec-2467-dup-0,zali,walppkle,25,william husson crescent,muralappi,brymaroo,3147,wa,19550701,9616019 +rec-4003-dup-0,andrew,novak,9,blackman crescent,ra 23012,ashgrove,2204,nt,19131226,1378126 +rec-3799-dup-0,ballantyne,michaela,86,mandurah place,tantlalon,canterbury,4043,wa,19021123,5203409 +rec-2415-dup-0,chleo,coleman,50,mina wylie crscent,montocaradvan park,gowri e,3114,sa,,6761005 +rec-4476-dup-0,imogen,bellchaimbers,216,bensteda place,or eel,nedlands,2158,nsw,19230217,9615495 +rec-1534-dup-0,noah,mason,15,morehead sutreet,fingal park,duncraig,3357,nsw,19890129,5247400 +rec-863-dup-0,madison,parr,1,brackeriplace,pad icam,hectorville,2154,nsw,19530610,4752945 +rec-125-dup-0,ruby,reip,12,judkins street,the wilolws,airds,4305,sa,,8834327 +rec-3502-dup-0,,farrimond,39,tank atreet,hilltop hostel rowethorpe,modbury,2650,qld,19061111,3876047 +rec-4573-dup-0,jamie,death,2,galway place,wylarah,werribee south,3356,nsw,19540328,3127934 +rec-4737-dup-0,sascha,matthews,5,canopus crescent,willalooka,asquith,7250,,19670719,7320513 +rec-980-dup-0,samir,teal,8,mcclelland avenue,doribank,lilydale,5092,nsw,19600901,6271964 +rec-2763-dup-0,ruben,gibb,12,shannon circuit,windalea,hackham west,5159,nsw,19021019,4450079 +rec-4122-dup-0,tess,battison,1,wyolap lace,,west wolllngong,2201,nsw,19230918,9384214 +rec-2392-dup-0,mariamne,adair,24,mcclelland avenue,colefield cen park,warrandyte,2217,nsw,19910122,7356931 +rec-1109-dup-0,kaleb,mccarthy,34,lamington street,berri cottage hmes,maryborough,2795,qld,19270513,1510564 +rec-1292-dup-0,jacinta,lenzi,10,couvreur street,mtdr sydale,mortlkae,2068,qld,19640807,1067001 +rec-2136-dup-0,silas,painter,6,parkhillrstreet,,st petees,3338,vic,19280710,4164669 +rec-1658-dup-0,leah,averis,27,macrobertson street,,mona vale,2067,nsw,19150220,1890261 +rec-3078-dup-0,abbey,matthews,12,de graaf f street,denture clnc,,2902,qld,19850806,6455816 +rec-4009-dup-0,,parashar,773,tytherleigh street,,eastwood,4605,sa,19900510,1990268 +rec-4323-dup-0,annalise,ma,6,,point cook home,stroud,6535,nsw,19270608,2160321 +rec-666-dup-0,butt,thomas,22,medworth crescent,stoneield,booval,4502,nt,19630219,2894576 +rec-3364-dup-0,jessica,maynard,15,alchera vlge,archdall street,bourke,3141,nsw,19471209,7562694 +rec-298-dup-0,blake,howie,1,belmont park belted galloway stud,cutlack street,budgewoi,6071,vic,19250301,5180548 +rec-3058-dup-0,lachlan-john,spears,165,o'connor circuit,kondalilla,risdon park,6064,qld,19950105,2408582 +rec-940-dup-0,zacharey,br asn,31,cornish place,the mea dows,whitfield,2675,vic,19120327,3343445 +rec-4326-dup-0,lucas,appletree,20,mcwhae circuit,crannog,jacana,4115,vic,19061023,9563099 +rec-3253-dup-0,,prideaux,117,wilshire street,rosetta village,bonyton,4503,nt,19700320,4150192 +rec-2513-dup-0,jessica,jolly,59,higinbotham street,rosetta village,woodpark,7109,vic,19850112,2565859 +rec-4815-dup-0,connor,bullock,23,antill street,dunmunkle lodge,alice springs,6155,nsw,19740907,3575462 +rec-3148-dup-0,christian,littlely,3,meyers wplace,burtons lookout,maryvake,5268,wa,19001019,4011513 +rec-4851-dup-0,noah,doman,20,boucaut place,oakdale,clarinda,3072,vic,,4747349 +rec-1346-dup-0,anari,sommariva,27,miranda place,,rosebery,2264,wa,19681110,4235226 +rec-4180-dup-0,finn,leslie,7,longmore crescent,the lodge,woodcroft,7250,qld,19670715,1685360 +rec-2260-dup-0,adam,adair,14,wattle street,red arrow,albany treek,2825,nsw,19560420,1699586 +rec-659-dup-0,skvaril,matthew,24,julia flynn avenue,,batemans bay,2456,nsw,19142122,5572688 +rec-1011-dup-0,taray,grooby,7,namatjira drive,rive rpark,rye,0821,nsw,19771030,3820896 +rec-2171-dup-0,lachlan,mcdermid,,,ettalong beach village,kellyvglle,4220,vic,19400318,8407575 +rec-1449-dup-0,jena,salas,2,tasman p lace,kinvarra,netherby,3820,qld,19490605,1868937 +rec-414-dup-0,benjamin,liccioni,4,golden grove,jestarlei,lavington,2042,wa,19100711,2197467 +rec-2398-dup-0,librandi,caleb,48,kidd place,donore,applecross,4865,tas,19730404,5522569 +rec-3410-dup-0,nicfholas,champion de crespign,8,deuchar lcose,lanena lodge,ryde,3181,qld,19230403,3235310 +rec-4867-dup-0,,tarquinio,24,lindclose,,frankston,4505,vic,19650419,4738861 +rec-1082-dup-0,imogen,green,1,trickett pjlace,nullo mnrain,coromandel valley,7027,,19770615,3231911 +rec-3032-dup-0,maddison,jaing,8,templetonstreet,kurrabri,lamington,3556,vic,19610619,7894969 +rec-4410-dup-0,destynii,hope,24,villa 3,barungastreet,st peters,4061,nsw,19210430,6586290 +rec-3626-dup-0,sophie,wynner,25,leajy close,box range,beechboro,2340,wa,19940105,5948897 +rec-2255-dup-0,green,benjamin,11,marou place,citycentre plaza,clear mountain,5115,nsw,19810305,8410885 +rec-1264-dup-0,emiily,george,17,bayview caravn park,ebeneze street,swan hill,3178,qld,19710827,7813722 +rec-4651-dup-0,julia,bullock,33,,legacyuvlge,duncraig,3126,vic,19130412,6578982 +rec-4406-dup-0,calbe,newberry,14,mackenziestreet,mountainview retirement vlge,emerald,2560,sa,19211203,1454125 +rec-2982-dup-0,jaimee,hanna,8,harkness street,belmor river,armidale,2062,nsw,19871116,5900887 +rec-4414-dup-0,joel,campbell,2,maclean street,,riverstone,3168,vic,19621110,8265289 +rec-2329-dup-0,lachln,theodore,1304,,bells ck,woodhouselee,4817,wa,19840528,7028688 +rec-269-dup-0,summer,delen,1,uriarra road,tesbury,kurri jurri,2333,qld,19401028,6523096 +rec-1372-dup-0,brooe,burford,28,,moolooboola,kinglake west,4560,nsw,,7438993 +rec-1519-dup-0,pai,maczkowiack,52,kalgoorlie crescent,,broken hill,3002,vic,,5924648 +rec-423-dup-0,william,corire,17,degraves crescent,sec 1,parkinson,4741,nsw,19610614,5150424 +rec-362-dup-0,dityt,jessi ca,22,dunlop street,oak-lodeg,bundaberg,3183,nsw,19500328,6813350 +rec-2863-dup-0,matthew,priest,310,benson drescent,glenhurst,tarragkndi,4124,qld,19860226,2553510 +rec-1353-dup-0,irene,aldehan,9,tumbletovn place,,wahroonga,3226,,19670316,7471765 +rec-4453-dup-0,saule,peachey,28,waratah street,goonahra,wanniassa,2750,vic,19531113,2548288 +rec-920-dup-0,scott,clarke,122,archibald street,locn 1487,nickol,2553,nsw,19010518,1978760 +rec-215-dup-0,caleb,roberts-yates,40,millpost close,bandera,cobar,3500,qld,19670914,5399448 +rec-4339-dup-0,liley,reid,27,tyrrell circuit,bright view,port sorell,2578,sa,19680620,2026273 +rec-2-dup-0,olivia,trigwell,13,waldock street,wilpena,newlambto nheights,3194,vic,19571126,9991752 +rec-3991-dup-0,eliza,nadin,12,tycannah station,mt warning crescent,preston,3091,qld,19470314,6540403 +rec-3226-dup-0,matthews,harley,32,badimaa street,munmurrapark,kinross,6015,qld,19820215,7336254 +rec-2322-dup-0,morrison,sophie,11,waller crescent,hmas cerberus,loganlea,3175,vic,19420302,7721195 +rec-3749-dup-0,connor,trimble,75,werriwa ycrescent,scts crk,mill paark,2162,nsw,19290729,5610380 +rec-3013-dup-0,georg e,mccarethy,35,clubbe crescent,yakill i park,mentone,2540,vic,19350704,9460223 +rec-859-dup-0,macey,lowe,26,butlin place,lotus lodge hostel,enoggera,2680,tas,19081128,3271563 +rec-1628-dup-0,,clarke,,edkins street,conmurra,balcatta,2162,nsw,19360520,2120525 +rec-24-dup-0,lauren,mellick,54,lewis luxton aevnue,,cooks hill,2161,qld,19561107,9988724 +rec-3391-dup-0,madelyn,blizard,6,southwood rpetreat,hoxtpn park,northgate,2067,vic,19540215,2341148 +rec-1945-dup-0,hana,duvdley,16,lochee place,portland house,rose bay,3085,nsw,19590211,3088000 +rec-1636-dup-0,layla,dent,5,kater place,parry huse,burwood east,5251,qld,19730408,5189661 +rec-4336-dup-0,alessandra,shepherd,4,stow place,blueberry farm est,ringwood east,2447,qld,19631123,4730733 +rec-4655-dup-0,isagah,drysdale,10,hingston close,,glenhaven,3360,vic,19370729,4360928 +rec-1638-dup-0,gartkh,echevarria,76,solomon crescent,ondyong point,humpty doo,2770,vic,19970118,4201581 +rec-321-dup-0,ruby,rogan,6,guthridge crescent,,parkside,6050,vic,19050201,6557114 +rec-4929-dup-0,lachlan,green,11,golden grove,jodaygne,armidale,3058,vic,,4526867 +rec-1593-dup-0,jayden,thorpe,44,warrego ciercuit,yacklin,cabramatta,2259,wa,19281105,6871482 +rec-1486-dup-0,matisse,felmingham,351,sherwtlod,kingsford smith drive,cooks hill,3207,nsw,19320615,5414268 +rec-1948-dup-0,flnyn,painter,7,thomas hart street,railway stn,sea ton,2640,vic,19211124,8126727 +rec-2093-dup-0,nicole,madigan,8,carrollvstreet,newton park,goonellabah,2749,qld,19610919,3710610 +rec-4953-dup-0,christian,goetze,5,manna close,torrington,mill park,2323,nsw,19510127,3619285 +rec-443-dup-0,olivia,lavel,7,frater crescent,waterdale,marmion,3185,qld,19230219,8833281 +rec-4532-dup-0,indiana,thopre,39,newmarch place,nelsonsa ke,milleprk,2250,qld,19271212,8901632 +rec-2137-dup-0,schkira,ryan,1,baringa orthopaedic centre,dumas street,frankston,3028,vic,19520108,1566350 +rec-4721-dup-0,ethan,steed,38,williamson street,wilga,greensborough,2074,vic,19900708,5384988 +rec-1056-dup-0,james,imgrapen,47,curlewiscrescent,dragon rising,burleigh waters,2680,qld,19520516,6111417 +rec-1325-dup-0,hayden,ayrse,22,castleton crescent,kojonolokna hills,leongatha,2103,sa,19970513,1502848 +rec-749-dup-0,sarag,curtg,47,charlick place,heathfield qld,mullumbkmby,3175,vic,19131205,8264314 +rec-3493-dup-0,india,meddings-blaskett,166,james smith circuit,glenview,hug hes,2540,nsw,19730602,7857279 +rec-4484-dup-0,alexandra,clarke,15,rsd b 284,parnell roa,,4014,sa,19890608,7235143 +rec-11-dup-0,jake,fawkner,,wolff crescent,,proserpine,4011,vic,,3844004 +rec-3545-dup-0,nataia,langrerh,32,calvary clinic,mt annan,narellancvale,5290,nsw,19981015,5685638 +rec-1093-dup-0,sarah,bradshaw,6,hallen clise,red tank,mullaloo,2161,vic,19340509,9150146 +rec-3857-dup-0,samplton,ambrosia,28,moorehead place,,goodowod,4701,sa,19400426,1298044 +rec-2483-dup-0,zachary,webb,97,witt place,,laurieton,2206,vic,,8708647 +rec-3252-dup-0,,campbell,4,dunbar svtreet,delicate nobby street,cloverdale,2528,vic,19480406,8607518 +rec-3117-dup-0,georgia,tunstall,,beadle olace,holmligh,caulfield north,3046,sa,19330720,4656516 +rec-4996-dup-0,brayden,pragt,24,melba street,utopia,st vies,5171,nsw,19561029,7716405 +rec-2794-dup-0,webb,april,25,anketell street,sec 437p,millmerran,2226,vic,19060125,3661897 +rec-2284-dup-0,nicholas,kaukov,295,jervois street,dodonaea wing,wamberal,4077,qld,19070128,2145341 +rec-3335-dup-0,lioy,musolino,34,fernyhough crescent,gunn's u lly,burwood east,2097,qld,19600226,9776077 +rec-3985-dup-0,blake,daykin,3,hannan ctescent,cooroora,gwynneville,2318,qld,19120515,8485229 +rec-3964-dup-0,brianna,ryan,1,bingham circuit,beltunga,highett,6330,qld,19310316,9339689 +rec-2304-dup-0,daniel,warusevitane,123,mccaughey street,lemnos,lismore,3023,vic,19990918,9753519 +rec-3737-dup-0,archer,brammy,119,free place,,killara,2795,vic,19190802,3733888 +rec-1765-dup-0,,webxb,3,anukana,mclachla nstreet,eastwood,2121,vic,19175009,8331654 +rec-3225-dup-0,kylb,careless,75,mcbryde crescent,rowethorpe cgynet hostel,ivanoe,6074,sa,,3208751 +rec-4359-dup-0,clsin,green,42,osborne place,lakewood estate,hastings,6172,nsw,19201203,8724836 +rec-1313-dup-0,laylau,chammen,9,discovery street,st francis vlge,keilor dast,5352,nsw,19550123,4055724 +rec-132-dup-0,bryce,clarke,15,kellick lplace,beau-ridge,mill park,4413,tas,19821213,6173366 +rec-2604-dup-0,christopher,frew,10,ringrose c rescent,locn 1996,lilydale,4096,tas,19321022,6674665 +rec-746-dup-0,dakin,sophi,50,correa street,upstaisr flat,beachlands,5241,sa,19760414,2342666 +rec-915-dup-0,emerson,soulemezis,15,marshall street,birks hsrbour,st albans,2135,vic,19450805,8760466 +rec-695-dup-0,toby,quill,25,anembo street,sect 329,strathalbyn,5253,vic,19380703,6115722 +rec-1578-dup-0,maddison,goldsworthy,6,cavill close,killanoola,manly vile,2258,qld,19820307,6557335 +rec-3457-dup-0,howie,james,297,,irrigation farm,campsie,2315,wa,19350803,3217546 +rec-1211-dup-0,dent,madiaon,14,mault place,rockwood,gordonvale,0886,wa,19440208,1552323 +rec-4698-dup-0,brinley,baumab,14,prout lpace,amblin caravan park,gaven,3021,vic,19360411,7377453 +rec-4231-dup-0,,durban,63,ormond street,,narrogin,3284,vic,19010130,3247158 +rec-4440-dup-0,ella,richmond,2,investigat or street,mynolar,crestmead,4306,nsw,19000112,6508977 +rec-3787-dup-0,harrion,krige,36,jardine street,warrawong,robertson,3056,nsw,19340912,9627130 +rec-3388-dup-0,emiily,mccarthy,10,mcintosh tsreet,kiloran,port fairy,6110,nsw,19330313,6901115 +rec-788-dup-0,tommy,matthews,62,quirosrstreet,li ft,north ryde,2229,wa,19051224,9644815 +rec-1461-dup-0,thomas,moulton,26,buckley circuit,,north synney,2260,qld,19550604,1286659 +rec-4904-dup-0,giaan,blake,,slessor crescent,fernadle,dapt,2711,qld,19930815,6835476 +rec-3944-dup-0,kyle,candivda,26,spofforth street,pinecroft,clearview,3187,nsw,19001111,1796923 +rec-702-dup-0,barnay,fleet,4,martley circuit,peak view,ascot vale,3930,sa,19360907,9383837 +rec-1756-dup-0,joshau,donkin,16,mather ustreet,glebe retirement villa,park holme,3002,nsw,19750509,4009940 +rec-1112-dup-0,noah,tillee,264,miranda place,,mullumbimby,3131,nsw,19780216,7578909 +rec-4825-dup-0,lara,dunis,24,rodda place,dry rush,casino,4170,nsw,19580928,2469542 +rec-3662-dup-0,benjamin,yen,43,kambalda crescent,elmvood,findon,3807,nsw,19850706,7843492 +rec-2517-dup-0,kateyln,reid,30,james smith circuit,karma park,dolls point,2478,qld,19970318,9915348 +rec-918-dup-0,,michelmroe,103,fimistermircuit,swanie,moorooblark,4174,nsw,19761101,6406097 +rec-2700-dup-0,maxxin,tchung,10,pullen rtreet,emmaus vlge,cabarlah,3620,qld,19060604,6340831 +rec-2874-dup-0,hannah,donaldson,11,goldig place,lockwood,mcmahons point,4213,qld,19390126,5871551 +rec-221-dup-0,samantha,mapstlne,44,hutchins street,golden ponds resort,maitland,0276,sa,19941217,4499927 +rec-4430-dup-0,,homann,45,sommers street,professionak centre,vaucluse,4873,vic,19130214,7096543 +rec-3460-dup-0,blake,ryan,7,,tryphinia view,ringwood,3718,wa,19900531,1192663 +rec-3278-dup-0,matthew,bernry,560,westbury circuit,,north qard,5082,qld,19820813,7825135 +rec-1585-dup-0,cooper,green,14,kingsford smkth drive,australia fair medical west centre,innaloo,4115,sa,19661010,1494383 +rec-838-dup-0,jackson,campbell,10,marungal avenue,,kunwaraara,2445,qkd,19420220,7928114 +rec-4564-dup-0,teahva,rawlings,21,charterisville avenue,moonby downs,toowoomba,4006,sa,19601115,9235491 +rec-4450-dup-0,keegan,berry,28,hattersley court,gundamain,corrimql east,3073,qld,19230913,8103633 +rec-4580-dup-0,caleb,webb,50,badimara street,retirement village,kuraby,4655,qdl,19890709,7501704 +rec-3695-dup-0,emiily,crossman,16,,,colac,4305,nsw,19641029,4013967 +rec-1162-dup-0,jack,webb,87,hodgkinson ystreet,rabbit warren,st kildaeast,2216,nsw,19730327,4227791 +rec-3005-dup-0,charleks,white,23,westburycircuit,,dover heights,2107,qld,19470123,5209300 +rec-812-dup-0,oliver,agius,54,ashburton circuit,gilston lodge,bray pabrk,2161,wa,19651114,6136263 +rec-3720-dup-0,gao,julia,17,horizon avenue,arthur rvier park,woodrcoft,3952,nsw,19280810,7151454 +rec-3415-dup-0,grace,telleglou,12,bywaters place,environa,tusmore,3101,sa,19060204,6170642 +rec-3765-dup-0,sophie,nicolle,93,,hilltop hos tel rowethorpe,upwey,3305,vic,19990623,1307303 +rec-2937-dup-0,connor,trait,6,lane place,,leichhardt,3337,vic,19150208,1776479 +rec-2051-dup-0,jayden,green,31,balanu place,,rainworth,6151,nsw,19870321,6103878 +rec-4108-dup-0,calvin,herbert,5,shortland rcescent,kookaburr avillage,kaloama,3130,nsw,19990902,4778880 +rec-633-dup-0,brooke,locik,5,godfrey street,noosavillage s hopping centre,goonellabah,2446,qld,19201008,1614256 +rec-807-dup-0,jayden,glass,33,henry melvilnle crescent,patrician stud,sanctuary point,2283,qld,19510331,4079997 +rec-3451-dup-0,logan,goldsworthy,21,florentine circuit,settlers hills,ashfield,2751,nsw,19160117,8867229 +rec-4325-dup-0,masoen,juliana,,mana lpace,tinaroo falls,yagoona,5532,nsw,19140705,8963464 +rec-1081-dup-0,caitlin,white,174,collyburlc rescent,,kurwongbah,2456,nsw,19431207,2627787 +rec-1089-dup-0,malakai,crouch,303,ragless circuit,,paddington,3073,qld,19510719,5426853 +rec-230-dup-0,talyah,leavre,5,newlop street,mgreton,florey,3150,nsw,19130703,3251860 +rec-4179-dup-0,luke,parr,9,hilder ptreet,ardrossan,parkdale,5084,nsw,19190317,6349510 +rec-2387-dup-0,alisa,stanley,23,fairbridge crescent,oberne park,mount pleasant,2016,nsw,19811210,8806692 +rec-828-dup-0,jeed,musolqno,19,spalding street,rosehill,willetton,4820,nsw,19631219,7754049 +rec-3456-dup-0,blake,purdvon,1,beauchamp street,francis chambers,maida vale,3153,sa,19510318,1098632 +rec-1850-dup-0,macormack,clarke,215,giblin ktreet,argyle vi fllage,leongatha,3334,vic,19580218,3112446 +rec-36-dup-0,,bottcoff,5,jindivik place,homewood,meringandan,3222,vic,19640816,5214622 +rec-2494-dup-0,tirfany,schuster,35,vanzetti crescent,snug beach cvn park,smithfield,2579,vic,19440522,6698734 +rec-3383-dup-0,blake,,26,ranken olace,goodrick park,elwood,4740,nsw,19760330,8133663 +rec-2367-dup-0,,clarke,9,biddellplace,laurieton hvn ret,collie,4120,vic,19430622,7449892 +rec-4529-dup-0,hayden,needham,1,daintree crescent,kiowua,corrimal,3218,nsw,19020930,4674771 +rec-1251-dup-0,lauern,ryna,115,jardine street,adelaide dental hospital,broadbeach waters,4207,vic,19420313,6195510 +rec-730-dup-0,matthew,etheridge,113,louis loder street,wood crest,frenchs forest,3015,vic,19950128,5585524 +rec-4276-dup-0,mikhayla,clacke,33,benson drescent,allensleigh,brigton,3456,vic,19170129,2179147 +rec-3218-dup-0,lachlan,weller,6,gara place,berkeley vlge,nunawading,3810,nsw,19140403,8566655 +rec-3802-dup-0,emiily,de micjle,23,lawrence crescent,manila,mount alford,2577,nsw,19530522,7400612 +rec-3916-dup-0,harley,white,79,mcelhone court,abbaston,harbord,2360,tas,19480318,5946514 +rec-2274-dup-0,luke,wilkins,22,ironbark vrescent,,heckenberg,2390,nsw,19360325,2755084 +rec-841-dup-0,jake,nelsen,10,rossoznplace,elmwood,,4815,nsw,19300403,7364984 +rec-791-dup-0,matthew,schuster,1,elmslie place,centrefai rplaza,ulladulla,2251,vic,19890911,9319732 +rec-1283-dup-0,lewis,strubbe,7,badenoc hcrescent,meadow banks,bayview heights,2564,nsw,19900106,7706707 +rec-3893-dup-0,ned,gren,6,higgs place,radwon,ourimbah,4880,sa,19840321,4691573 +rec-1003-dup-0,matthews,bradley,2,jondol place,horsesheo ck,jacobs qell,7018,sa,19481122,8927667 +rec-4142-dup-0,samantha,bellon,21,rosenthal street,anzac house (cnr ar cher s street,beaconsfield upper,3099,vic,19661212,1850361 +rec-957-dup-0,mardus,whiteu,9,golf zoad,verdon street,punchbowl,4165,vic,19971124,7116750 +rec-3008-dup-0,georgia,green,18,dexter street,kareela,mount riverview,3137,qld,19341195,5788426 +rec-4763-dup-0,alisha,,22,duffy s treet,meadowview,frankston,3134,nsw,19800916,1450223 +rec-908-dup-0,lucy,rewe,,haddon street,cremona stud,tiddy widdy beach,2469,nsw,19250702,3258771 +rec-3669-dup-0,zac,ryan,,naas lose,willandrarvillage,applecross,7249,nsw,19340605,9433767 +rec-382-dup-0,ella,mahno,51,ulm tsreet,,northmead,2086,nsw,19330520,4464237 +rec-3734-dup-0,noah,klemencic,46,truscott tsreet,mc kail,dulwich hill,2094,qld,19421216,9564581 +rec-4883-dup-0,brodee,egan,88,axon sireet,greens lopes,wamberal,2067,qld,19121113,6039042 +rec-2253-dup-0,matthews,harry,40,perrinscircuit,broadwater caravn park,kedron,2466,vic,19670914,1826915 +rec-2929-dup-0,bethanie,artis,21,brigden crescent,caragnoo,cronulla,6143,sa,19020810,4534363 +rec-1201-dup-0,jayden,blake,3,kemsley place,mlc ceyntre,kariong,2210,qld,19020112,7106228 +rec-4700-dup-0,jared,allstpp,35,theodore mstreet,peroomgba,hazelbrook,4121,nsw,19511220,5416662 +rec-41-dup-0,luc,drought,1,solander place,janefield,moonah west,4879,vic,19230101,7649261 +rec-4086-dup-0,thomas,crofton,21,battersby circuit,phillip lodge,old reynlla,4810,nsw,19120925,6433953 +rec-3356-dup-0,erin,red,,cornish place,ferdnale,renown park,2281,vic,19420519,7078005 +rec-324-dup-0,aidan,finlay,27,maribyrnong avenue,villa 3,roleystone,2000,,19131416,8412107 +rec-365-dup-0,ned,kalka,3,,silvefweir,hazelwood north,2040,vic,19820419,7612543 +rec-4104-dup-0,bethany,deakin,43,tazewellc circuit,winchesterdowns,ballarat,5371,tas,19520625,4152955 +rec-1185-dup-0,heather,bengier,8,fergusson q rescent,palazz,currajong,2650,wa,19840703,9010502 +rec-3657-dup-0,rachael,widdip,19,gurrang avenue,clanville,sale,2176,qld,19120117,6879955 +rec-3498-dup-0,alysha,maier,,kerrigan street,craigie-lea,morphettville,3124,qld,19480111,8215736 +rec-4756-dup-0,olivia,davdi,67,,thorndale,chelsea heights,4218,,19910923,3201406 +rec-562-dup-0,jasper,webb,7,forsythe treet,tallow-wood,geelong east,5073,nsw,19780525,4462979 +rec-3757-dup-0,bailey,petresn,1,niok da,goodmanstreet,plymptonsouth,4214,,19090102,3547315 +rec-4770-dup-0,tegan,rosendale,1,sherbrooke street,nazareth village,innaloo,2550,nsw,19801011,9351309 +rec-1950-dup-0,,mccarthy,42,oliver s treet,brentwo od village,cherrybrook,2880,vic,19350103,5462917 +rec-3788-dup-0,riley,benn ier,235,shackleton circuit,lakeview park,dianella,2340,qod,19030228,2251111 +rec-2372-dup-0,nicholas,colantoni,45,illingworthl street,,st albans,2518,vic,19651019,4914391 +rec-4694-dup-0,hayden,richmnid,59,louis loder street,wattagan,craigmore,2192,nsw,19670619,1098844 +rec-787-dup-0,connor,neumann,302,debenham atreet,sandalford homestead,the entrance,2774,vic,19790629,1382097 +rec-3257-dup-0,tayah,nobxle,10,city w alk,george forbes house,merino,5097,vic,19250315,8376614 +rec-2920-dup-0,amber,burnell,11,captain cook crescent,fig thees,kilsyth,2283,qld,19820812,3394398 +rec-4394-dup-0,hanka,nirta,113,mcburney crescent,caroona village,glen eden,4814,qld,19940127,5873271 +rec-209-dup-0,eliza,millar,15,sydney avenue,bass highway,booval,4701,nsw,19480506,6758505 +rec-2132-dup-0,mhary,gaitanis,,howitt street,thirty creek,mathoura,2830,nsw,19891212,2923514 +rec-761-dup-0,cameron,lavis,2,albermarl place,dananbulla,glenwood,6442,vic,19410723,5700120 +rec-1287-dup-0,alisha,rawlings,40,white sands tourist park (cnr beach),hyndes crcescent,bayswater,2754,nsw,19150122,1114083 +rec-3531-dup-0,cassannra,seymour-griffin,3,priddles treet,thebruren,bayswater,3104,nsw,19961213,6740375 +rec-2997-dup-0,india,block,26,skardon street,,dianella,2173,qld,19950131,4804710 +rec-4018-dup-0,jessoca,radic,1,edmondson street,kimeb,raceview,6280,qld,,7256699 +rec-2439-dup-0,isab elle,beattie,19,southern close,gulmarrad street,stanley,2166,vic,19460303,1698866 +rec-1511-dup-0,jack,bridgland,170,thermeda place,mirreanda,berkeleyv ale,2286,nsw,19980721,2930436 +rec-3748-dup-0,iain,noble,84,rischbieth crescent,the bi g tree,albanyh cerek,6391,qld,19500616,2205130 +rec-4895-dup-0,kiandra,waller,41,stobiew place,west r oad,rossmoyne,4071,vic,19480123,5588564 +rec-949-dup-0,campbell,thomas,10,bywaters lace,rosettav illage,east melbourne,2611,sa,19640129,1872563 +rec-4133-dup-0,,ryan,480,britten-jones drive,yulgiobah,roxburghwpark,7054,nsw,19610512,6344786 +rec-270-dup-0,sophie,weidenhofer,18,owen dix on drive,,cremlrne,2170,sa,19750525,7013216 +rec-2156-dup-0,brooke,broadby,13,smith street,golden ponds resort,petrie,4076,qld,19101119,1067112 +rec-1566-dup-0,liam,petersen,16,solomon crescent,,mosman,3630,vic,19800221,7148654 +rec-3638-dup-0,renee,browne,215,vale place,,warrandyte,2251,nsw,19490742,9563421 +rec-1560-dup-0,kane,campbell,236,scarfe close,bega flats,elermor e vale,3228,nsw,19281207,3391391 +rec-1777-dup-0,tommy,gre ne,122,nanima road,port 44,lower temclestowe,6064,vic,19901006,6395843 +rec-947-dup-0,brodie,coleman,8,woronora street,suffoli downs,carngdie,4115,qld,19880122,6395380 +rec-2586-dup-0,carlin,sherriff,190,hardmanstreet,ocean park towers,greensborpugh,6059,vic,19651125,5986787 +rec-1842-dup-0,vigneswaran,gabriel,80,chuculba crescent,,altona mmeadows,3159,qld,19560125,4243167 +rec-3016-dup-0,ellen,armanious,4,summerville crescent,cabrini medcial centre,corio,3130,nt,19670816,3732493 +rec-1800-dup-0,emiily,maida,27,beaneystreet,blue gum park,padstow,3340,qld,19790818,7320684 +rec-1818-dup-0,parremore,paris,16,guerin place,,north hpbart,2250,wa,19260913,1309531 +rec-2806-dup-0,jeremf,grubb,5,derrington crescent,gwandalan,south melbourne,2777,nsw,19520719,8082214 +rec-3671-dup-0,zane,snell,30,altair place,grangemore,,6057,,19090918,3576930 +rec-3475-dup-0,william,everett,140,hall street,fernbank,bull creek,7184,tas,19921006,2805870 +rec-2358-dup-0,caitlin,dolan,55,lawrence wacke tt crescent,garden settlement,beaumaris,2193,wa,19571211,7745058 +rec-1010-dup-0,zalk,matthews,308,solly place,fai rawy,valoa,2138,sa,,8924972 +rec-1909-dup-0,kayla,braitahite,25,forwoods treet,braemar vlge,chewton,2261,nsw,19640906,6775714 +rec-3618-dup-0,erin,hearn,,port jackson circuit,gowan,preston,2605,nt,19101004,5064504 +rec-2211-dup-0,limbert,abbie,3,yurng,burraly court,oyster bay,7310,sa,19061013,2508428 +rec-66-dup-0,koula,houseling,3,mileha m street,old airdmillan road,williamstown,2350,nsw,19440718,6375537 +rec-417-dup-0,adam,westbrook,4,newman morris circuit,medical centre,springwood,2087,nsw,19181006,7935674 +rec-2613-dup-0,hayley,hassall,53,morton street,,taringa,5028,nsw,19170113,5401135 +rec-1038-dup-0,mia,crofts,11,nunan crescent,wilag,millmerran,4850,sa,19550722,3041807 +rec-1666-dup-0,maier,rhet,6,,lindisfarme,marsden,5251,qld,19420726,5663323 +rec-2158-dup-0,jenna,neumann,22,percy cresscent,,lennox head,5043,qld,19821024,7587719 +rec-1732-dup-0,sophie,mahony,8,ashby circuit,bunya ihghway,pumphryes,3040,qld,19651025,5839336 +rec-3031-dup-0,lachlan,rollitt,566,cossington smith crescent,the mano rgarden,,3215,qld,19051107,2847641 +rec-1219-dup-0,kayla,ottend,5,mollison street,,rossmoyne,6285,act,19110325,1782013 +rec-1784-dup-0,bethany,reid,9,totterdell street,kingaroy agrden,deniliquin,2800,qld,19080203,5554694 +rec-3597-dup-0,bethany,dixon,25,burraly court,denny donws,culburr a,2208,nsw,19850214,5650922 +rec-907-dup-0,kye,morrison,6,biddlecombe street,,daylesford,4670,vic,19951109,8949737 +rec-968-dup-0,aidan,blake,15,namatjifra drive,cooramin,dromana,4074,vic,19270928,4317464 +rec-4824-dup-0,mitchell,longo,52,faucett dtreet,beagle bay,wamuran,3139,nsw,19760429,4714885 +rec-4159-dup-0,alexandra,berry,18,mckinle y circuit,arouni,tahmoor,2206,nsw,19120808,9418450 +rec-709-dup-0,lachlan,bennell,154,southwood retreat,walkers orchard,wheeo,4118,qld,19830601,2694324 +rec-161-dup-0,david,tanyshah,3,redcliffd street,northwood park,palana,3166,qld,19680823,6914643 +rec-724-dup-0,jaden,parr,12,sid barnesz crescent,,orange,4744,qld,19210526,7179398 +rec-4617-dup-0,lucy,kranenbrg,34,clara close,blue h ills,cora lynn,6030,nsw,19740827,7896434 +rec-2875-dup-0,luke,white,31,outtrim aqenue,glenora farm,flinedrs bay,2227,sa,19151010,6925269 +rec-508-dup-0,adam,henricks,10,merv waite street,manacumble,downer,2582,wa,19581007,3204460 +rec-464-dup-0,,britten,15,whiteside court,,kirwan,2330,nsw,,2001865 +rec-4863-dup-0,abigail,whisson,,davenport street,,joondanna,6602,qld,19140828,3039182 +rec-1030-dup-0,trey,saines,26,throsselel srreet,kindian,buff point,4161,act,19110205,2740304 +rec-4587-dup-0,shenae,campbell,4,lander crscent,kerradan,bondi junction,3186,nsw,19580611,5546102 +rec-2758-dup-0,chloe,green,3,stantke place,gemma,dianella,4872,vic,19570715,8691066 +rec-3515-dup-0,cooper,perth,50,blacket street,avalyn,young,2580,qld,19950107,5404942 +rec-3068-dup-0,berry,jye,303,chirnside circuit,,benowa,4021,,19891213,3022720 +rec-4327-dup-0,thomas,shephred,1,newdegate street,dorothy genders vlge,lalor,2830,nsw,19560417,1744115 +rec-2961-dup-0,riley,okoniewski,370,howitt street,rp 24089,rylstine,6174,vic,19030216,1234018 +rec-4377-dup-0,caitlyn,campbell,39,amagula kavenue,delvasood,coolum beach,3714,qld,19930612,3516962 +rec-895-dup-0,kane,nguyen,47,ranken place,gumnut czttage,dapto,5107,qld,19850120,9212538 +rec-1216-dup-0,matthew,raward,2,duffus place,,mount gravatt,4011,qld,19580630,6865352 +rec-3438-dup-0,olivia,mcnnll,1,alberga street,gulmarrad street,lue,6107,nsw,19100419,6664512 +rec-4121-dup-0,jaykob,smeaton,246,stuart street,,ardee,6112,qld,19120411,5014834 +rec-4585-dup-0,hayley,mortlock,19,augustusclose,rono bti,tallebudgera,2630,nsw,19110617,9154301 +rec-381-dup-0,lac hlan,obetsteller,13,hovea st reet,plainbrook,preston,3095,nsw,19361218,8188130 +rec-3486-dup-0,jake,ryan,5,cutlack street,grandview,ashfield,3724,qld,19480526,7030512 +rec-2266-dup-0,tobt,chater,16,holland street,inne s est,keysborough,2885,vic,19440624,2828200 +rec-3847-dup-0,isaac,clarke,17,leonardclose,highpoint,bundaberg north,7310,tas,19361017,4346183 +rec-1795-dup-0,fitzpatrick,lucy,264,ainsworthstreet,,camden,3500,qld,19220222,6619336 +rec-3477-dup-0,jake,torzillo,193,frew close,howie cifcuit,darlington,3875,vic,19370321,1546559 +rec-3203-dup-0,isabeola,bowerman,22,aspinall street,campaspe,northbr idge,2913,nsw,,5138593 +rec-1995-dup-0,tomney,chloe,24,woollum street,carranya,pymble,2321,nsw,19901223,8831246 +rec-3129-dup-0,,ahier,8,crowder c ircuit,peridon vlge,long jetty,4817,nsw,19270309,6824379 +rec-4217-dup-0,barnaby,dixon,71,charteris crescent,,ascot vsle,5012,nsw,19960422,4817798 +rec-3619-dup-0,brooke,ryan,9,weekes close,,greenacre,3040,nsw,19100427,7392488 +rec-3989-dup-0,kobe,brock,14,folingsby street,yarrandale,coonamble,4575,qld,19941016,6183698 +rec-3243-dup-0,jacobie,white,27,pitcaibr street,willowfield,sefton,2565,wa,19940831,6421870 +rec-2022-dup-0,stephanie,tuckwell,6,weddin circuit,hillsidrfarm,scarborough,4125,sa,19920918,7564218 +rec-211-dup-0,madeline,jolly,6,,crown allot,lilli pilli,2546,nsw,19280509,8473152 +rec-3120-dup-0,ada,dallas,79,copland drive,,rye,4034,sa,19170316,9230368 +rec-4752-dup-0,phoebe,millar,31,rayment place,concept,wantirna,4064,qld,19230111,6425281 +rec-4911-dup-0,marlee,ryan,,brittlebank circuit,,ringwoid,7248,sa,19180126,4573130 +rec-3015-dup-0,kylwc,clarke,19,kirkton street,little forest,florey,4109,qld,19380419,6477305 +rec-3865-dup-0,imogen,novak,40,ebden istreet,carinya vlge,mooroolbark,5074,vic,19870905,5546417 +rec-4624-dup-0,schkirra,de nichilo,14,kirkwood crescent,apt 16 thu village,killara,4740,nsw,19060211,3688155 +rec-4748-dup-0,zand,tao,5,cromwell icircuit,heve arham,lalor,4825,nsw,19631204,7503892 +rec-110-dup-0,amber,coleman,13,lennard street,barnawartha,wendouree,4163,vic,19960625,2700453 +rec-4741-dup-0,aidan,finlay,393,,,aitkenvale,6064,qld,19611226,1013943 +rec-4012-dup-0,connor,sleat,21,toohey lace,manor court,highett,3081,nsw,19040425,3130394 +rec-3098-dup-0,jacob,webb,6,majura road,moline ivllage,ashfield,4352,tas,19470221,1586712 +rec-4367-dup-0,pakia,beams,11,strangwahs street,upson & downs,hadspen,6014,qld,19520203,1295582 +rec-3632-dup-0,connor,godfiey,50,centauru s street,locn 59 40,o'sullivan beach,2216,qld,19010823,7376725 +rec-2826-dup-0,kai,hobsxn,1985,battersby circuit,,dulwich hill,5573,nsw,19280304,9227124 +rec-327-dup-0,aleisha,campbell,4,mackay crescent,,coolamon,5011,qld,19910630,3454612 +rec-3233-dup-0,jessica,donaldson,2,mainwaringrich circuit,cliffney park,hamilton,2147,nsw,19361211,5900031 +rec-213-dup-0,finn,ryan,5,,champsaur,coombabah,2536,vic,19500807,3429777 +rec-1361-dup-0,clement,white,4,knox s treet,bimby vale,campsie,6060,nsw,19960916,8856376 +rec-4209-dup-0,joshua,pringlse,27,fred johns crescent,glenview,elwood,2640,sa,19720127,9406321 +rec-3222-dup-0,anfrew,reid,51,ocean hunter,arndell street,,4054,qld,,4475335 +rec-3588-dup-0,kydan,siviour,18,galibalesgreet,the willows,,2327,nsw,19830421,8231850 +rec-4738-dup-0,mitchell,whte,2,denovan circuit,brackenl eigh,mill park,6210,nsw,19031229,2276261 +rec-3903-dup-0,jack,dimonte,104,mckeahniestreet,carinyah station,woy woy,2142,nsw,,4854960 +rec-3756-dup-0,burrill,lucinda,31,corrdiella,bamir square,inglewood,4575,qld,19471211,4875837 +rec-911-dup-0,jack,lowe,16,lambert street,belon fame,lavington,6615,vic,19091212,6247312 +rec-3590-dup-0,nell,reid,14,groom street,warrina lakes,goonellqbah,2775,nsw,19850813,9822354 +rec-2560-dup-0,ang,daneql,8,villa 2,reader court,arundel,1346,nsw,19470912,2029176 +rec-3674-dup-0,thomas,monis,30,schofiel d place,duck creek,terrey hills,2145,nsw,19620331,3724382 +rec-1580-dup-0,thomas,coleman,35,daviesplace,aptupc,marayong,4819,nsw,19660918,6106983 +rec-4438-dup-0,jordan,noble,4,kosciusko avenue,st francis vlge,surry hilels,2170,wa,19270820,7231665 +rec-445-dup-0,mccarthy,jaxin,46,dalyell street,wiringa,marsden,3142,nsw,19640914,9531739 +rec-3220-dup-0,michael,chigros,8,beasley street,gypsumpit,murrumbateman,3930,vic,19380317,5018010 +rec-2292-dup-0,ryan,werh,51,marconi crescent,lassvwade,robertson,2165,qld,19990627,6787650 +rec-3143-dup-0,kobe,jolly,26,alroy circuit,salmaldo caravgan park,kyabram,6317,sa,19841213,4583639 +rec-60-dup-0,tiana,ryan,146,doyle terrace,danric lodge,totteham,3355,sa,19280723,9762204 +rec-2359-dup-0,mackenzi,jarick,51,wilkinson street,willow lodge,picton,2171,vic,19240823,4264896 +rec-3484-dup-0,harry,dignam,22,investigato rstreet,,fairlihgt,2535,qld,19241105,2134538 +rec-3485-dup-0,sarahp,white,97,,,cronulla,2278,wa,19320303,7287941 +rec-61-dup-0,kynan,sincovich,95,,,barrack heights,4222,nsw,19470922,4440480 +rec-599-dup-0,joshu a,fitzpatrick,10,groveland crescent,toolebewong farm,carrum,3012,vic,19110616,2933121 +rec-1787-dup-0,charlei,browne,33,riversstreet,rowetohrpe,east hills,2539,sa,19360722,3866327 +rec-1610-dup-0,brock,nyg aard,58,lockyerstreet,,kununurra,2079,vic,19730526,4753010 +rec-2949-dup-0,daniel,ryan,8,gordon hclose,blue srings,hamilton,6230,qld,19540105,3698795 +rec-4269-dup-0,rebecca,coppacok,3,homeleighwallaroo road,tinaroo falls,embleton,6152,vic,19101211,2971980 +rec-2218-dup-0,tylee,berryman,223,broad place,villai3,clayton,6355,vic,19901803,2531288 +rec-3437-dup-0,ethan,mcacrt hy,257,chambers street,berkel eh vlge,west wollongong,3818,nsw,19020506,4852331 +rec-4915-dup-0,benjamin,green,10,hodgkinsno street,sunset,crafers west,2570,nsw,19810814,5709794 +rec-3557-dup-0,alessandra,druitt,4,frome street,brightwater villas,dunsb rolugh,2795,qld,19810517,7828185 +rec-412-dup-0,pascoe,kyle,14,cygnet crescent,shdaell,abbotsford,4069,wa,19901202,5389384 +rec-223-dup-0,ky,kyriacou,30,ash place,kilo ran,paddington,2665,nsw,19350528,5592621 +rec-2592-dup-0,flynh,banham,164,starke street,stonehuose,carlingford,2444,sa,19890221,3189743 +rec-1442-dup-0,zachaey,mccuylly,10,allambee street,sec 1,urangan,6146,nsw,19190417,9635640 +rec-2152-dup-0,megna,fitzpatrick,,aland place,keralalnd,rowville,2219,vic,19270130,1148897 +rec-1914-dup-0,olivia,bennell,95,sidaway street,south seas (cn cook s street,ballarat,6150,sa,19520214,9360716 +rec-4093-dup-0,dylan,eglinton,11,nambucca street,woodkeigh,arthurotn,2870,sa,19660115,8227230 +rec-1422-dup-0,phillip,ngueyn,83,clark place,wollongbar,st kilda,3808,nsw,,9799704 +rec-4333-dup-0,marinos,anton,44,geils court,mayflower retrmnt vlge,bridgewater,4066,vic,19510826,7146853 +rec-359-dup-0,joshua,clobke,11,mcquade close,malinga,kyabram,2650,,19640531,9168763 +rec-809-dup-0,kulas,jasmin,1,sheehanastreet,salimtal,toowoomba,3850,nsw,19210113,7425903 +rec-3663-dup-0,caitlin,hervey,4,woolner circuit,,parap,2404,qld,19331205,2155379 +rec-4110-dup-0,ruby,gilcfist,98,aleon,honyong crescent,bassendean,6230,qld,19760723,9352851 +rec-854-dup-0,arren,leonardos,106,eggleston cfescent,hidden valley estate,east maitland,3220,vic,19171029,8849722 +rec-2975-dup-0,isablela,mcfadden,133,bennelong crescent,cranbrook,port fairy,2833,,19440706,4644493 +rec-2133-dup-0,brooe,clarke,4,namadgi circuit,emerald tgarden,ascot vale,5031,vic,19430823,6719097 +rec-2830-dup-0,jesse,webb,48,penningtoh crescent,thistbledoo,curraong,6112,nsw,19931125,1432305 +rec-3895-dup-0,dylan,laucht,14,hoddle garden,oakabnk,oakey,5051,vic,19600107,2156016 +rec-3330-dup-0,thomas,hare,68,gilderston circuit,canow indra,coffs harbour,4311,nsw,19190206,3277988 +rec-624-dup-0,abby,spark,10,cordeaux street,mortlock house,,2217,vic,19930311,8511819 +rec-3047-dup-0,emiihly,lowe,80,investigauor street,mirilla,,3377,vic,19420731,3718111 +rec-2004-dup-0,emii ly,roko,142,hambidge crescent,sec 26,north ryde,4825,vic,19880525,6262463 +rec-3303-dup-0,liam,wehner,11,monaro crescent,oaklands village,bidwill,3205,nsw,19350426,7873898 +rec-297-dup-0,alysha,nguyen,7,hurleystreet,avenue road,brunkerville,3904,nsw,19970304,4977712 +rec-368-dup-0,caleb,feeney,2,barringer street,holmeleigh,bright on,3165,vic,19071029,1440128 +rec-922-dup-0,stanley,samantha,16,jay place,knackery rhs,kingston,6330,vic,19951027,2725144 +rec-1475-dup-0,joshua,yeoman,7,drysdale circuit,,camp holl,6150,nsw,19791212,3599370 +rec-2427-dup-0,ebony,wynne,261,teaguestreet,fleetview,harris park,4359,act,19070922,2766218 +rec-779-dup-0,rohan,ruskin,4,wenholz street,,rowville,5067,vic,19020302,9606352 +rec-2706-dup-0,joshua,rees,5,ewing shtreet,austra lfarm,diggers rest,4034,qld,19160829,9643284 +rec-258-dup-0,harrington,sp,9,la perouse astreet,bull plain,bogangar,3173,vic,19030123,4348887 +rec-224-dup-0,liaym,beckwith,6,murrung crescent,,revesby,3155,sa,19730522,2475787 +rec-3249-dup-0,ebony,thorpe,8,,,yarra junction,6028,qld,19421204,2504255 +rec-2362-dup-0,isabell,mcandrew,5,ramage place,tantallon,prospect,2151,qld,19621223,9696568 +rec-2455-dup-0,talia,green,8,groom street,ikllke,medina,3500,wa,19800109,7656892 +rec-2268-dup-0,taliah,buitendyk,19,emily bulcock crescent,palmwoo d court,flinders park,5109,sa,19950831,3139107 +rec-3705-dup-0,grace,gully,201,karrugangc ircuit,milbrodale,eldorado,2835,nsw,19930330,8575092 +rec-656-dup-0,jolyl,hannah,89,,palm lake resort,joondalup,3550,nsw,19020625,2585701 +rec-28-dup-0,blake,brac ci,159,duffy street,hillcrestlodge,bacchus marsh,4510,nsw,19590213,9950906 +rec-1110-dup-0,emma,adzaip,38,amherst street,,nairne,4860,sa,19050421,5988275 +rec-3090-dup-0,meggie,george,16,,greenlake,airds,5267,nsw,19111227,1040139 +rec-4427-dup-0,james,lupoi,46,mirrool street,,carlingford,2607,qld,19540202,7582894 +rec-2346-dup-0,nathan,clarke,12,forbes street,rainbow park rp 8965,flinde rs park,2117,qld,19500725,5135466 +rec-4050-dup-0,jamie,hashemizadeh,1,julia flynn avenue,st johns retirement village,gorokan,4205,vic,19851030,4092093 +rec-3666-dup-0,sea,gaskin,51,harris street,waterdale,newmarket,4226,wa,19030110,5111528 +rec-2631-dup-0,meagan,falting,14,boolimba crescent,chain gate,robina,2036,vic,19130619,6854344 +rec-2916-dup-0,owen,haeusler,9,martley circuit,,mooroolbark,5083,qld,19361018,2837091 +rec-1008-dup-0,timothy,dignam,17,berrigan crescent,seaforth vlge,moorak,4608,qld,19771123,2663449 +rec-981-dup-0,chandler,laklynn,7,bangalaycrescent,carisbrook,mount gravatt,4122,nsw,19371103,3919587 +rec-3201-dup-0,annika,campbell,71,totterdell street,the mews royal hotel bldg,lavertons outh,4359,vic,19290222,3988407 +rec-3102-dup-0,jake,tweedie,12,flinders way,guest vlge,texas,4570,vic,19460308,5178030 +rec-4264-dup-0,dixon,zac,101,dodwell street,unt 3,macgregor,4627,wa,19960221,8228346 +rec-2684-dup-0,rebecca,dimuaro,54,marlee place,rowethorpe,oakleigh,2543,vic,19970111,6763318 +rec-1997-dup-0,webb,casszndra,15,wentwort h avenue,,mill park,5290,nsw,19300310,2827902 +rec-4838-dup-0,abbey,quill,,rafferty street,blue hills,gumdale,2460,nsw,19150305,5107379 +rec-3096-dup-0,keeley,moolenaar,18,tangaristreet,sec 1,mosman,4680,nsw,19240130,2647421 +rec-2050-dup-0,ella,blkae,14,mckinlay street,cape hawke hosptl medcl centre,wendouree,2060,sa,19770427,9846556 +rec-2227-dup-0,capurso,christian,16,burkitt street,giniderra,frankston,4103,vic,19210722,2242368 +rec-3421-dup-0,hayley,dixon,32,ashkanasy crescent,enderlge,surry hills,2069,nsw,19300303,6355088 +rec-4301-dup-0,dayna,hassall,8,laughton street,anzac house (cnr archer s street,highon,3028,sa,19040622,3632388 +rec-2695-dup-0,angeilda,domkus,9,stanfield close,bowser,modbury heights,2232,qld,19690820,8976049 +rec-4316-dup-0,nicholas,bridgland,8,lethbridbe street,,toowoomba,2767,qld,19720428,2108881 +rec-4531-dup-0,alex,babocy,7,burnett ttreet,whattleglen,wilmot,4552,vic,19051202,5673881 +rec-615-dup-0,emiily,nguyen,01,noble close,hillbyrne,naradan,6151,nsw,19550413,5771309 +rec-2368-dup-0,liam,,28,sculpto street,villa 2,upwey,2077,nsw,19370824,9117501 +rec-1419-dup-0,natasha,alessi,1,davies p oace,bindan a downs,tungamull,2060,vic,19410721,6485512 +rec-2739-dup-0,kiaree,gail,54,maxhenry c rescent,gainsbury (cnr waldegrove r road,emerald,3220,nsw,19060223,5762709 +rec-2102-dup-0,conxor,soulsby,53,bussau close,hi pien,mooroolbark,3108,nsw,19750429,7659266 +rec-3892-dup-0,charlee,coulson,,diamantin acrescent,specialistq centre,preston west,4740,qld,19100918,3920842 +rec-333-dup-0,joshua,akot,8,edmunds place,villal18,dapto,6071,vic,,3188786 +rec-910-dup-0,sophie,bradsahw,18,rowet horpe,kidston crescent,gerladton,4069,vic,19380426,2830844 +rec-4267-dup-0,harroson,zimmdrmann,25,fairweather circuit,burnie north west private hospital,brighton,4211,vic,19370426,2620091 +rec-2831-dup-0,lucas,simmonds,25,blackwood terrace,lyndon lodge,kilmor,6333,wa,19101023,5919385 +rec-3622-dup-0,,huddy,,maltby rircuit,destiny park,moorabbin,3195,tas,19720627,5832871 +rec-4184-dup-0,georgia,campbmell,20,balsillie crescent,glen mia,loganlea,3806,wa,19280823,1041041 +rec-3808-dup-0,mitchell,dunnicjliff,,illingwort hstreet,,penrith,3162,nsw,19350411,5567119 +rec-1206-dup-0,alissa,rpiest,7,lawley street,,granville,4116,qld,19241102,1113130 +rec-2911-dup-0,james,,2,frome street,diacos caravn prk,sylvtnia,5203,vic,,2532680 +rec-430-dup-0,thomas,fogliano,522,hawdon rtreet,francis c hambers,bonville,6617,qld,19290927,3505678 +rec-1223-dup-0,bailldy,smallscombe,16,beagle street,castle reagh terrace,greenwood,3181,vic,19941222,4529850 +rec-983-dup-0,kyle,dixon,106,robertso street,merrilea,fullarton,3929,qld,19060420,6808962 +rec-4673-dup-0,jesse,bagwekl,12,tuckey plsce,ellagnowan,urangan,4659,nsw,19930914,6491012 +rec-2955-dup-0,d'acry,webb,3,ebenezer street,,cressy,2443,wa,19901222,8604852 +rec-4963-dup-0,,sherriff,97,rischbieth crescent,berkelgey vlge,macquariw fields,4152,nsw,19510502,1541627 +rec-3260-dup-0,emiily,camozzato,1,weston street,bulala,waverley,2450,vic,19321224,6435812 +rec-1590-dup-0,paige,pateron,8,lindrum crescent,miandetta,st jajes,3805,nsw,19090422,5550381 +rec-3279-dup-0,hannah,ho,13,bradfieldfstreet,,hurstbridge,2795,nsw,19180207,6938730 +rec-3584-dup-0,riey,pascoe,68,lexcen avenue,,south brisane,7035,sa,19380905,7792395 +rec-4723-dup-0,tommy,morrison,28,mcnamara street,rowan lodge,north ryde,2083,nsw,19231010,8097782 +rec-3381-dup-0,shepherd,nicholas,2,,gnornajg,bayonethhead,3021,nt,19400303,8128223 +rec-2981-dup-0,nathah,wiemann,10,gingana street,,brighton,3011,vic,19370429,8432426 +rec-40-dup-0,finlay,,3,summerland circuit,,auburn,3216,tas,19001106,5825057 +rec-3217-dup-0,neneh,wheatley,37,bunda s treet,,torquay,3844,nsw,19530310,6451877 +rec-292-dup-0,oliver,clarke,84,macrobertson street,whitelodge,toowoomba,4077,qld,19180825,5422013 +rec-4690-dup-0,brandon,freiman,27,tucanastreet,sunnyhills,tweed heads south,2500,nsw,19370325,5018665 +rec-2891-dup-0,tabitha,orchard,2,marsden qstreet,john flynn medical centre,mount low,3179,nsw,19230831,1102361 +rec-3776-dup-0,heron,josiua,23,dooring street,drypoint,barraba,4214,nsw,19700227,6931228 +rec-4939-dup-0,fraser,hebbemran,28,hendersonstreet,kalinda park,cowra,3429,qld,19900809,9636276 +rec-2498-dup-0,lachlan,geduld,2,karrugang circuit,jacqoona station,arundel,4306,vic,19520703,3086091 +rec-1181-dup-0,jessica,liddy,15,hyndes crescent,sec1,fairlight,4133,nsw,19620602,3547293 +rec-2309-dup-0,henry,pozn ika,2,ashkanasy crescent,nelgrovepark,beenlegigh,2171,tas,19521203,7678518 +rec-3631-dup-0,taylay,berry,56,corbin place,honey pa tch,brighton-le-sands,3041,vic,19650831,7786757 +rec-1334-dup-0,adele,morrison,18,woollums treet,riverside professionarl centre (cnr banks,ormond,6059,wa,19101205,7729842 +rec-2554-dup-0,madison,shepherd,18,ballumbir street,blue hills,corrmal,3168,wa,19170819,8120482 +rec-2173-dup-0,talah,campbell,418,bean crescent,warramby,hopperscrissing,4208,qld,19601111,3013090 +rec-3594-dup-0,,willmot,19,fairweather circuit,meebery,cabramatta,3285,vic,19450224,5540735 +rec-2807-dup-0,,bradshaw,9,dallachh place,coral house even tide,ryde,3805,nsw,19071027,8707306 +rec-2540-dup-0,giorgia,struck,5,ambalindum street,lazyac res,thornlie,2144,wa,19250507,4468206 +rec-3053-dup-0,sophie,mcilar,10,steinwedl street,ponderosa,geelong ast,3550,qld,19640509,4135696 +rec-726-dup-0,jaden,dagley,2,pelham close,central clinic,brouece,3942,sa,19660707,3196657 +rec-2108-dup-0,mitchell,cof fey,12,conder street,kangaroo grnd,cook shill,2762,qld,19530924,2701477 +rec-3696-dup-0,toby,walkley,29,hatfiekd street,st ehle ns,albury,2528,nsw,19860619,9827400 +rec-2539-dup-0,emiily,stearnes,26,hugh mckay ctescent,honey patch,ettalpng,2259,sa,19040826,7188856 +rec-1016-dup-0,courtney,painter,12,pinkerton circuit,,richlands,4560,vci,19161214,4066625 +rec-2262-dup-0,gabriel,moyse,12,currie cfescent,platinai,sefton,3337,wa,19160926,3553783 +rec-4719-dup-0,kirarh,southwod,137,sugarloaf circuit,cooli bah,smithfoeld,4715,wa,19980504,4827713 +rec-826-dup-0,chloe,white,33,gadali crescent,rondyavoo,logankea,3069,vic,19331024,8293935 +rec-1193-dup-0,jake,pascoe,,gooreens rreet,,mittagpang,3023,wa,19300716,8300308 +rec-25-dup-0,joel,campbell,,savige street,glemore,arana hills,3152,nsw,19880824,5412397 +rec-3586-dup-0,karl,adart,56,launceston street,aprt 504,clarkson,2032,nsw,19860315,1526150 +rec-2181-dup-0,,clarke,13,hicks snreet,brentwodo vlge,broadmeadows,3094,vic,19340818,7285543 +rec-2620-dup-0,brooklyn,mercoerlla,13,knox retirement village,endeavour street,concord west,2038,nsw,19050715,7877973 +rec-4964-dup-0,,lungershausen,28,hilder sreet,morayfieldexchange,redbank plains,4350,nsw,19431008,3687513 +rec-4060-dup-0,matthew,green,57,howitt street,,,4704,wa,19861119,3767916 +rec-4811-dup-0,sophe,grosser,39,tryon steet,bethel y ostel,bull creek,3875,wa,19011031,6415988 +rec-4383-dup-0,ryley,dods,24,helemon treet,john curtin hostel,villawood,6061,nsw,19350808,9316786 +rec-77-dup-0,gillian,chanlder,232,caladenia street,,gowrie,3150,nsw,19960922,4237925 +rec-3496-dup-0,elijah,,76,lane-poole place,rosetta village,malvkern,3337,vic,19910131,7588197 +rec-242-dup-0,joshua,green,13,duncan street,eurok,artarmon,4871,qld,19970505,4108253 +rec-3127-dup-0,alyssa,shepherdson,,wuruma place,the wi llows,leichhardt,2165,qld,19380508,8856494 +rec-2879-dup-0,amaya,pulford,41,challinor ctescent,rowethorpe,newcatsle,2534,qld,19930615,5220952 +rec-1460-dup-0,elbla,faull,42,dowling s treet,nomore,norwood,2627,nsw,,8885164 +rec-645-dup-0,benjamin,berryman,43,thornhill rescent,country tclub,magill,2072,qld,19360111,7934124 +rec-2066-dup-0,tahlia,wotton,11,darby street,greenacres ca ravan park,lindfield,2206,nsw,19250907,1825836 +rec-1849-dup-0,,grafton,30,springvale drive,fernbank,sunshine,3168,vie,19350919,3481992 +rec-3778-dup-0,sascha,dema rco,3,franks place,tantadlon,gracetown,5169,tas,19960906,9430667 +rec-2846-dup-0,lauren,mcneill,,caley crescent,gimberts road,kilsyth,3752,qld,19050527,4744679 +rec-237-dup-0,corey,feeney,303,forbes street,,suffolk park,2049,nsw,19670414,9098376 +rec-4991-dup-0,,horkings,144,box hill avenue,alexandra racecourse,paddington,4061,vic,19291011,1360308 +rec-880-dup-0,bryce,morrison,1,rowethorpe,clavert place,parramatta park,3214,nsw,19120213,8125144 +rec-3885-dup-0,louise,campgell,3,clark dlose,manton's rise,annandale,2360,vic,19871212,6743419 +rec-4772-dup-0,fitzpatrick,hayley,14,boote pl ace,armidale private hospital,concord west,3058,nsw,19240223,6366376 +rec-3553-dup-0,james,stearnes,8,leahy close,,bayswater,1395,nsw,19330802,9900161 +rec-564-dup-0,kane,reid,12,arnolc place,lakefront retrmnt vlge,seventeen mile rocks,6285,nsw,19181209,4118529 +rec-1806-dup-0,madison,cowle,14,port jackson circuit,marriottdowns,new mollyan,4215,sa,19280625,9403686 +rec-628-dup-0,amaya,skirca,3,heagney ecscent,willow lodge,ross,3980,wa,19980122,3781022 +rec-99-dup-0,kyle,wehr,27,naas close,rowethorpe,stocktln,2151,wa,19440131,7528586 +rec-873-dup-0,devan,ottens,3,muggaw ay,,gosford east,5163,qld,19410514,3579690 +rec-280-dup-0,joshua,toseland,19,roughley place,,,5263,wa,19820825,3749440 +rec-4444-dup-0,alexandra,hied,27,tweddle place,barley hill,williamstown,3055,vic,19070929,3625008 +rec-2269-dup-0,serena,wbeb,9,,aptmnt 2,tin can bay,2540,qld,19770422,3504192 +rec-2633-dup-0,alex,wbeb,13,kirkland circuit,bernleigh,sandy bay,4655,sa,19720617,5932947 +rec-2567-dup-0,amy,george,15,faithfull circuit,tynwall,cranbourne,5083,nsw,19180219,9555129 +rec-4171-dup-0,adam,clarkde,3,skinnerstreet,kona,woodcroft,4878,wa,,7112414 +rec-1391-dup-0,,padas,7,edmondson atreet,goughs bay,modbury,2036,wa,19170811,3374275 +rec-2953-dup-0,alex,hanna,146,pocket avenue,scottsdale,yangebup,3942,vic,19040515,7193215 +rec-1134-dup-0,ebert,lachlan,37,barcoop lace,low ponds,cirio,3191,sa,19720105,4689114 +rec-3449-dup-0,lily,collier,47,sargood street,amelia,port macquarie,3148,vic,19860413,6053604 +rec-2971-dup-0,jack,highet,26,mathieson crescent,,kaleen,3064,vic,19650507,6260000 +rec-4636-dup-0,,rei,147,marr sreet,walkers orchard,arthurs creek,7330,nsw,19240712,7585720 +rec-4203-dup-0,,walls,14,florence tayoor street,nepean shores,p adstow,3048,qld,19200129,1018744 +rec-1938-dup-0,noah,bishop,325,shannon circuit,eriswell park,south pefth,4551,nsw,19210214,5100494 +rec-2816-dup-0,jackoson,edgecombe,3,ranken place,johamelnine,bonytho,5167,wa,19970731,5991164 +rec-2835-dup-0,luyc,braithwaite,65,ellerston avenue,marx garden world,munno para west,2705,qld,19580501,6060746 +rec-420-dup-0,kate,stephenson,8,sinclair street,,ryde,5333,nsw,19051012,4182623 +rec-4910-dup-0,felicity,la porte,25,groomstreet,gundalnie,glenmore park,3892,wa,19631026,9577115 +rec-1594-dup-0,davd,shepherd,3,eggers olace,ainslieh ouse,nubeena,4869,nsw,19380403,6575835 +rec-2765-dup-0,lara,cannell,23,lenehan treet,blue ctane farm,nome,3152,nsw,19210211,2766975 +rec-2686-dup-0,imogen,white,12,macrossan crescent,,mount isa,2088,nsw,19580528,9882514 +rec-1097-dup-0,joshua,clarke,4,ragless circuit,,sylvania,3163,fic,19110818,5574844 +rec-4190-dup-0,zanj,crocuh,9,allan treet,sbend carvn park,invemrsy,2135,tas,19590501,6678712 +rec-2214-dup-0,elia,burnellz,2,badimarastreet,,armidale,2607,nsw,19960416,3920251 +rec-686-dup-0,zarlia,hage,69,catchpole street,tryphi inaview,casino,3180,vic,19130311,5080759 +rec-780-dup-0,har risn,boulter,9,macgregor street,stonyi rdge,cecil plains,3070,nsw,,5094110 +rec-2223-dup-0,zane,dixon,2,southern cross drive,nanto,dickson,3842,sa,19870503,7439457 +rec-1071-dup-0,braiden,hohn,6,swinden wtreet,alanvlo,mulgraveeeast,7140,nsw,19920920,4170069 +rec-185-dup-0,maxi,burford,2,dixon drive,inglecell,aspley,2090,nsw,19030325,6228407 +rec-3412-dup-0,went,oliver,11,augustus close,sheep station,st ives,5006,vic,19160706,6364957 +rec-3264-dup-0,benjamin,fullwood,4,pulleine crescent,pangnai,labrador,2621,wa,19840715,6999348 +rec-586-dup-0,wilson,green,,jaeger circuit,bungqrra,coroi,2650,qld,19111005,8910567 +rec-2331-dup-0,christian,redi,10,britten-jones drive,honey patch,moe,2250,wa,19870501,2773283 +rec-4809-dup-0,marianne,reni,23,bat h pace,,casnio,5118,sa,19350713,3009656 +rec-3495-dup-0,nicholas,dixon,60,archibalqd xtreet,,dalyston,2154,vic,19230212,6851976 +rec-1444-dup-0,martinovic,thomas,24,killarney,ivo whitton circuit,greenwtih,7207,qld,19801111,4222783 +rec-1426-dup-0,lucsa,thorpe,25,port jackson circuit,,eimeo,6255,sa,19320715,2374689 +rec-1955-dup-0,tanyshah,jolly,462,finnertyplace,belvedeqre,alice springs,3167,nsw,19861204,2562045 +rec-1454-dup-0,sebastian,papagfeorgiou,192,carstensz street,,cherrybrook,2479,vic,19570326,5979503 +rec-4759-dup-0,makayla,herbert,5,plummer street,tarwyn aprk,hopetoun,3925,vic,19111103,1756031 +rec-3480-dup-0,kyle,kowtin,69,hambidge crescent,,frankston,3056,wa,19380303,2024772 +rec-2280-dup-0,,tholrn,66,keithstreet,ocean sta r villas,beenleigh,6107,vic,19550703,6047972 +rec-757-dup-0,bayns,charlotte,96,bainton crescent,winton,malvern east,6111,nsw,19221231,7857555 +rec-1771-dup-0,sam,matthews,15,parkin treet,hawkins mas onic vlge,camp hill,4305,vic,19131126,8110517 +rec-3124-dup-0,nicholas,colquhoun,241,chataway crescent,gibraltar,blandford,2166,qld,,2145262 +rec-1844-dup-0,benjamin,lowe,26,wentcheyr place,emoh,austins ferry,7261,nsw,19385621,1039986 +rec-1690-dup-0,georgia,cothber,132,captain cookq crescent,whiske r dhill,seelands,2220,nsw,19171218,8148701 +rec-667-dup-0,daniel,rollins,22,hemmings crescent,flt 68,wantirnz,9316,nsw,19840108,9812011 +rec-4598-dup-0,samantha,bereza,52,shaudell,waddell place,piney range,6026,vic,19420813,7631947 +rec-4758-dup-0,robert,nguyen,26,willoughby crescent,wand endi,dianekla,5155,nsw,19381017,4982192 +rec-2437-dup-0,eden,crossman,26,michael holt crescent,scenic lodge,peakhnurst,2020,wa,19240123,9861015 +rec-1478-dup-0,ellen,campbell,24,giles street,avalyn,bull creek,5048,nsw,19560304,7223186 +rec-1620-dup-0,zachary,michelmore,11,oakdale,brisbane avenue,warrane,6330,qld,19430124,2800552 +rec-3274-dup-0,domihic,hogguan,29,devanny place,birrabilla,portarlington,3175,nsw,19561215,5034600 +rec-3408-dup-0,caleb,bersable,13,parkhill street,myola dtreet,mount pleasant,7248,tas,19510311,5036866 +rec-150-dup-0,clarke,ned,1,london circuit,vills 5,carnegie,5703,wa,19740801,4238081 +rec-2318-dup-0,aidan,fysh,165,must circuit,yarrumf,forest hill,2132,vic,19330404,1070728 +rec-1142-dup-0,joshua,campbell,,jonsson court,,bayswater,6353,nsw,19261206,6149683 +rec-123-dup-0,angie,mcgahey,54,moorestreet,farnorah home,elwood,4077,vic,19001102,8638894 +rec-4780-dup-0,amber,coleman,6,bunda street,altona,mount isa,2121,wa,19050907,2464697 +rec-2788-dup-0,,carbone,194,burdekin street,glente,glen innes,6552,wa,19070409,2229631 +rec-1924-dup-0,alexandra,nguyen,26,fremanthe drive,merricroft,hightno,6532,nsw,19440220,2682401 +rec-194-dup-0,jaydem,sekulitch,,casuarina street,cottage rose,yagoona,4503,nsw,19310401,6055233 +rec-3265-dup-0,aaron,baohm,,,locnc316,upper coomera,6016,qld,,7238727 +rec-3202-dup-0,chloe,mason,2,beirne street,grandview,st albans,2035,nsw,19760319,1704704 +rec-4401-dup-0,sara,weller,39,,heathfiled qld,keilor east,4304,nsw,,3408564 +rec-550-dup-0,indinaa,wasely,70,alabaster street,glenavon,maryborough,6530,qld,19380728,8716390 +rec-210-dup-0,riley,,27,kauper street,lesma,eastwood,4070,nsw,19161017,6512341 +rec-2777-dup-0,jake,mazurkiewicz,7,ashcroft crescent,,tannum sands,3917,vic,19580122,8132590 +rec-2470-dup-0,henry,dichiera,34,pomeroy street,towe rh ill,orange,5690,nsw,19000910,7446554 +rec-4379-dup-0,alisa,tiller,381,grevillea street,rosetat illage,dandenong north,3087,qld,19550719,9314806 +rec-3003-dup-0,zachariah,kilmarzin,56,barrallierg atreet,gree nslopes,torquay,3249,nws,19980325,1870225 +rec-3876-dup-0,zali,clutterbuck,13,twelve treescrescent,colbes,taringa,4718,vic,19821023,1538475 +rec-2225-dup-0,matthew,,330,forbes street,locn 7560,botany,3091,nsw,19291107,9737703 +rec-1664-dup-0,annabel,greenhalgh,28,mowle lpace,don ray,st james,2257,qld,19561214,7860148 +rec-4514-dup-0,rachael,beams,19,mackellar crescent,rosedale,,3340,vic,19670422,5928661 +rec-3479-dup-0,makenzie,michelmore,29,marcus clarke street,leitrim,ivanhoe,2199,vic,19081127,5210533 +rec-2391-dup-0,dylan,covino,63,mcgowanwplace,pine creek drubyvale,camden ssouth,2280,wa,19880205,9610572 +rec-948-dup-0,molly,clapham,25,watamurra,thring place,orbost,3305,nsw,19621123,7549694 +rec-4315-dup-0,edward,clarxke,151,strehlow place,pleasant wpines,eden hills,7000,vic,19520123,3945218 +rec-734-dup-0,scott,hoggan,6,zox circuit,straegath,northmead,5031,qld,19091119,2063442 +rec-1720-dup-0,,haak,54,parrp lace,ulah,burpengary,6010,wa,19170712,3239785 +rec-1888-dup-0,kazuki,white,65,maranboy treet,,marrara,2220,wa,19101205,4980306 +rec-1455-dup-0,chle,bastiaans,49,sturdee rcescent,,warrewood,2232,vic,19470305,1209800 +rec-4026-dup-0,blake,smith son,31,cavanaugh street,holmleigh,canley vale,4170,wa,19711019,2675546 +rec-1735-dup-0,grace,alderson,1,chippindal lcircuit,rockview,broadeadows,3000,nsw,19770722,3799511 +rec-3297-dup-0,alicia,lamonaca,15,vickers crescent,ballawinna stud,deaikn,6701,nsw,19780805,4465146 +rec-285-dup-0,burford,bridget,14,gibbh place,melaleuca,greenwood,3280,wa,19090212,4048860 +rec-4967-dup-0,jmaes,feast,139,goldstein crescent,kooringl epark,beenleogh,4214,vic,19500714,9202596 +rec-2864-dup-0,alia,taubert,178,mauricr cplace,lindsey rise,belmont,4802,nsw,19160125,3241981 +rec-2909-dup-0,isabelle,quilliam,,bannerstreet,marjidin,ulverstone,3250,sa,19671214,3784610 +rec-2653-dup-0,lochlan,pendergrast,3,hoodplace,kenara,loftus,6136,wa,19790831,3095270 +rec-1232-dup-0,kirra,coppola,,waugh close,,warylla,3926,nsw,19531118,9223478 +rec-2240-dup-0,savannah,hyland,17,pennefather street,camusfearna,cronula,3672,nsw,19050620,9386164 +rec-4248-dup-0,jade,scheerlinck,11,boswell crescent,jarrah,bicton,2290,vic,19521024,9034415 +rec-1886-dup-0,william,paru,46,stieglitz circuit,,coromandel valley,6210,qld,19100815,1269870 +rec-4638-dup-0,holl,collihson,195,burn sreet,rosary village,four mileg beach,4221,qld,19671102,7790499 +rec-1549-dup-0,willam,portors,11,donnelly road,medical centre,murray bridge,2125,nsw,19321223,1315964 +rec-620-dup-0,sophie,mccqrthy,91,woodfull loop,norma,west culburra,2340,qld,19580523,1578155 +rec-625-dup-0,pagoda,tiffany,43,pitcairn street,clear creek,bundaberg,4300,nsw,19371008,1115720 +rec-4796-dup-0,mollie,berry,15,perry drive,beulah ettate,,3043,act,19520323,8496716 +rec-3006-dup-0,matthews,benjamin,5,namatjira drive,buena vista,preston,5290,vic,19531201,3174571 +rec-4574-dup-0,cooper,blake,09,packham place,australia fair medi xal west centre,surfers paradise,2747,vic,19100307,2013713 +rec-4678-dup-0,jessfe,donkin,68,mackennal street,ferndale,somerset,2573,nsw,19900096,3358033 +rec-1352-dup-0,william,doman,7,copland drive,grandview,adamstown,2325,sa,19810208,5779269 +rec-1743-dup-0,riley,landow,43,hannafors street,wattl e tree,marayong,6025,vic,19971031,4812402 +rec-1245-dup-0,amelie,lohe,107,coghill crlose,gurnam unya,port macquarie,2021,vic,19200613,6372043 +rec-78-dup-0,stelio,minter,23,mehaffey rescent,airforce memofial estate,roleystone,2456,nsw,19540125,3373062 +rec-2805-dup-0,elle,royle,40,maribyrnong avenue,stapletonj station,port lincoln,4220,nsw,19430114,8517129 +rec-1497-dup-0,elie,hirzel,162,angas street,,stoneville,3209,vic,19710723,8829577 +rec-2714-dup-0,taylor,,1,kerkerisclose,,south perth,4650,nt,19740805,4419884 +rec-2919-dup-0,kaleb,hobson,,scadda place,pacific palms caravn park,bunbury,2259,vic,19960630,9573457 +rec-3759-dup-0,michael,leslie,2,kirwanciircuit,blenmorje,bangor,1350,qld,19350423,7283323 +rec-4137-dup-0,liam,pauch,1005,elvire place,nara da,bronte,2137,tas,19470324,4505367 +rec-1853-dup-0,jade,clarke,63,fred william s crescent,plaiview,kitchener,3127,nsw,19350407,4177666 +rec-2484-dup-0,james,wyllie,15,university of canberra,westfalls,sippyd owns,3201,wa,19811112,6047605 +rec-2377-dup-0,lauren,soae,187,grounds crescent,strathleigh,denmark,3075,qld,19021209,5792462 +rec-3091-dup-0,richqrd,keatch,34,,belvedere,mount plaesant,2168,qld,19980216,8117319 +rec-3482-dup-0,kyle,wegman,16,,parkland motor village,modbury,4213,nsw,19790106,4561101 +rec-590-dup-0,blzke,doray,9,muresk street,,st albans,2305,qld,19410221,6927749 +rec-2311-dup-0,harry,hingstton,4,yraren,mather street,mathoura,2170,nsw,19780820,1659262 +rec-106-dup-0,chantelle,mason,21,zeitz court,cleveland waters,bayswater,3840,qld,19730217,9809705 +rec-1794-dup-0,sienna,cacciotti,32,nullagienstreet,avonlea parkcrmb 4045,parkinson,3168,qld,19770318,1586091 +rec-3213-dup-0,nichoqlas,hope,39,rossarden street,oakdale,clayt ln,2037,qld,19080513,1209261 +rec-756-dup-0,allard,fynn,1,rolph place,st vincents hospital,hillsborough,4216,nsw,19700328,7861274 +rec-3795-dup-0,shaun,stanley,17,,callatoota,northwood,2217,nsw,19450829,7849495 +rec-3860-dup-0,alexander,crossman,31,spinifexstreet,binnawee,texas,3068,sa,,7807999 +rec-402-dup-0,hugo,sporn,150,clive stelee avenue,kurr ajong,peechelba,5212,qld,19420523,8443463 +rec-469-dup-0,emiily,dods,110,solomoncrescent,crowden,bendemeer,2602,vic,19970213,6929273 +rec-1680-dup-0,damien,madigan,92,barringe street,forest edge,,2226,qld,19700502,7969974 +rec-2480-dup-0,james,spall,28,alabaster treet,inglewood,orange,5124,vic,19750720,5050590 +rec-1802-dup-0,ellen,hare,9,windradyce street,,rosegud,6076,nsw,19910512,5036453 +rec-978-dup-0,rebcca,riddekl,10,glasgow place,fowlers bay,picnic point,2915,tas,19010105,2892366 +rec-2528-dup-0,madison,cannell,2,seabornplace,tara palms,north hobart,6030,vic,19251217,4366054 +rec-1064-dup-0,georgia,reid,5,flower oace,rainmore,forest hill,7301,nsw,19970612,7201701 +rec-3441-dup-0,lke,trenerry,6,scotch colege,shepherd street,,5355,sa,19800424,1086821 +rec-685-dup-0,zachary,clarke,19,melrose drive,jemula r downs,clifton springs,7000,wa,19680624,3444095 +rec-673-dup-0,stephanie,braithwaite,86,chisholmstreet,bundong,toowoomba,2516,nt,19750104,4226794 +rec-100-dup-0,hayden,stapley,,tindale street,villa 2,cromer heights,4125,vic,,4620080 +rec-3870-dup-0,benjamin,harrington,45,cascina,mackenzie street,morpeth,6012,qld,19130302,6966636 +rec-1371-dup-0,timothy,j ollo,13,mcmahon court,calltaoota,hill end,3075,nsw,19721103,3751485 +rec-1532-dup-0,jese,nguyen,,waddell place,,wagaman,2810,qld,19470716,9161884 +rec-2478-dup-0,aidyn,morrison,1215,bertram street,tievrton,woy woy,4021,nsw,19160319,8015513 +rec-4202-dup-0,harrison,nguyemn,,fraenk ek street,harvuc,cardiff,3073,tas,19240421,5852654 +rec-3889-dup-0,bridget,bordi,27,froggatt street,villa 3,nhill,2016,sa,19290813,9532722 +rec-3281-dup-0,elton,shadbolt,35,finniss rcescent,riverbend,bacchus marsh,4197,vic,19031005,1581334 +rec-2054-dup-0,zalka,glennon,158,florence tayllr street,,mansfield,4014,qld,19150226,9056397 +rec-1889-dup-0,matthew,nurse,64,cygnet rescent,,portarlington,3840,nsw,19670101,6591571 +rec-4485-dup-0,jarod,lusted,22,prescotttstreet,girrahween himestead,burleigh waters,4502,nsw,19321125,6896793 +rec-314-dup-0,cheela,meaney,47,blamey crescent,nuffield vjillage,pymbjle,4812,nsw,,3266277 +rec-1491-dup-0,kirra,white,68,strangwaysustreet,diamonddowns,bundaberg,2120,sa,19230223,7213703 +rec-631-dup-0,shannon,hope,22,,,tennant creek,4017,vic,19300617,6942665 +rec-3951-dup-0,lachlan,nguyen,23,templestoew avenue,elmw ood,o'co nnor,5046,vic,19931013,8311385 +rec-3206-dup-0,alexander,malow,4,barlow street,merryvale,berwick,3400,tas,19661021,8600151 +rec-4725-dup-0,erin,buttrose,,greeves street,aprt 22,clarkson,5172,vic,19810203,5640265 +rec-2041-dup-0,julia,worsley,9,aggie place,,bellevuem hill,2877,nsw,19780815,5650768 +rec-154-dup-0,joel,bowran,16,port arthur street,laure,bundaberg,3927,aw,19360117,3484624 +rec-4696-dup-0,samusel,green,13,cordeaux street,morningtonret vlg,woorinen,6135,nsw,19911221,5676411 +rec-4148-dup-0,gabr ielle,richmond,3,ebenezer street,peakv iew,maningrida,4352,sa,19941228,5532143 +rec-2737-dup-0,tiana,gr een,18,grylls cerescent,rsl veterans retir,blakehurst,4670,qld,19151215,6565990 +rec-2312-dup-0,ella,ryan,15,marshall street,mayflower retrmnt vlge,castlecrag,2356,wa,19510519,7463223 +rec-3288-dup-0,harry,grosser,30,chambers street,lake oad,albionp ark,4560,nsw,19420607,7537775 +rec-3574-dup-0,,genovvese,6,axon sctreet,aprt 04,march,3166,qld,19681013,2402512 +rec-2768-dup-0,makenzie,reid,,sherbrooek street,torbanlea,st ives,2010,qld,19930630,9745948 +rec-2811-dup-0,vanessa,geogre,,cleland street,rowethope,mount isa,4122,nsw,19420220,3116789 +rec-2577-dup-0,noah,reetz,20,ellenborojgh street,lakes retirement estate,blacktown,3126,vic,19791110,2350308 +rec-1544-dup-0,madeline,jeffries,22,saywell place,little nest,charlestown,6430,nsw,19810222,3776945 +rec-4042-dup-0,steven,pwa,39,weatherburnplace,,malvefrn,7315,qld,19620819,1623496 +rec-2469-dup-0,riley,nguyen,76,florenceta ylor street,wacharoo,mill park,3181,nsw,19951106,4237972 +rec-3854-dup-0,jasper,nguyen,18,harbison crescent,riverside professional centre (cnr banks,calista,5043,nsw,19211203,1824456 +rec-3641-dup-0,jake,willmot,33,,,ringwood east,2538,vic,19171002,3406386 +rec-4030-dup-0,eloise,cheribi,9,northmore crescent,skerman chambers,joondanna,3350,vic,19220725,8822107 +rec-1671-dup-0,ethan,lomman,404,edwell plnace,,ivanhoe,3792,nsw,19740120,8595511 +rec-2295-dup-0,caitlin,tebbutt,5,knoke avenue,section,tweed heads south,4811,wa,19851223,9714537 +rec-3729-dup-0,ruby,hentze,30,harkness street,glenearra,florey,4178,sa,,2379793 +rec-1962-dup-0,sophie,mason,134,lendon place,mt pleasant,ashgrove,4005,wa,19411215,9349267 +rec-2140-dup-0,erin,jaridne,36,sainsbury street,alice downs,windsor,4573,nsw,19180805,2211171 +rec-3046-dup-0,alesha,hinfston,41,epenarr aclose,compton downs hostel,mentone,4215,nsw,19240921,8948668 +rec-626-dup-0,lauren,moorby,29,rapanea street,new chum,leongatha,3146,nsw,19802530,1758831 +rec-1032-dup-0,harrison,paintre,,nina jones crescent,ballawinna stud,lennox head,6017,vic,19961105,9133988 +rec-4328-dup-0,rach zel,meeking,14,wisdom street,rosedale,fisher,3150,qld,19181114,5395262 +rec-4403-dup-0,harriet,paterson,5,smiths road,jaybees,ringwood past,6012,nsw,19321027,3012880 +rec-2923-dup-0,erin,carbone,7,carr crescent,bexlye,matravlle,2452,nsw,19801216,8840510 +rec-1191-dup-0,mitcpell,campton,5,watt place,merrircoft,brandon,7270,nsw,19931028,2226898 +rec-4371-dup-0,jai,riddell,142,jane price crescent,industrial estate,hoppers crossing,2800,nsw,19720618,9147307 +rec-2067-dup-0,katharine,penno,16,cuthbertcircuit,brentwood vlge,,3215,qld,19491225,1089142 +rec-3906-dup-0,jacob,sporton,28,kosciusko avenue,walhalla,ringwood,2466,vic,19300816,1934981 +rec-2974-dup-0,michael,maclennan,6,richmond street,lake downs super f ine merino stud,emu plamins,5279,qld,19390409,1643013 +rec-4332-dup-0,georgia,carmoldy,107,ashburton circuit,,wamuran,3936,nsw,19660406,9507232 +rec-4547-dup-0,benjamin,hyland,14,coxen street,rowethrpe,yaroomba,5044,vic,19921225,8509780 +rec-4058-dup-0,hannah,coleman,12,canopusmrcescent,school house,port kembla,2795,qld,19010422,1651755 +rec-3030-dup-0,hannkh,maynard,3,oaklands village,fizelle place,toowoomba,2340,,19971104,3318159 +rec-990-dup-0,jasnyn,yeap,30,white crscent,lawley p ark,murray bridge,3079,nsw,19500508,9139909 +rec-1215-dup-0,isabella,grimum,7,pither close,haigh park,ringwood,2256,vic,19660730,9089145 +rec-2632-dup-0,shai,robson,,dooralong valley,white crescent,bunnaloo,4005,act,19711226,6720340 +rec-243-dup-0,riley,bennell,52,sabine close,browne's reef,toowoomba,4556,qld,19441206,1596501 +rec-3522-dup-0,caire,bethany,10,mountain creek road,trailview,paddington,3228,wa,19361026,4393661 +rec-481-dup-0,jajes,kagn,11,frayne place,,concord,4869,qld,19350731,7427314 +rec-1766-dup-0,james,hayball,30,hemmings c rescent,,tiaro,2117,qld,19720110,8590321 +rec-4360-dup-0,owen,hingston,16,goldner circuit,bramhall,yanco,6105,qld,19991220,1508216 +rec-3115-dup-0,benjamin,miles,,totterdell street,poplar bend,acton,6317,qld,19830303,4385595 +rec-3114-dup-0,cassidt,morrison,13,a'beckett street,argyke,ardeer,2518,nsw,19160403,6156712 +rec-1048-dup-0,alexandra,budge,11,outtrim avenue,sec 528,jacaua,2096,wa,19590819,3277841 +rec-1604-dup-0,musolino,ryan,22,smeaton circuit,pangani,mckinnon,2700,nsw,19890525,4971506 +rec-3838-dup-0,koula,hagget,18,southern cross drive,woodleigh,lilydale,0328,vic,19000625,3064629 +rec-4391-dup-0,felicity,,246,edmondsonstreet,rowethorpe,clareville,4165,nsw,19380928,5994744 +rec-763-dup-0,jack,whtie,,herbert crescent,fourways,north pinjarra,2261,nsw,19830827,3374161 +rec-3219-dup-0,olievr,ryan,23,candlebark close,holiday vlge,banks,4570,vic,,5337535 +rec-4990-dup-0,miranda,breedt,11,lalor street,,maiden gully,3672,vic,19050618,2333106 +rec-3261-dup-0,rhett,matthes,16,cadell street,warhaven h ome,surfers paradise,3911,nsw,19870715,5123065 +rec-2184-dup-0,tahlia,fenwik,6,brentwood vlge,wray place,north curl curl,4825,qld,19430604,8360325 +rec-3503-dup-0,lily,hamon,59,clutsam place,villa 444 th e village glen,ashgrove,4717,acg,19490707,1603670 +rec-1790-dup-0,shannon,heurr,65,fossey street,brindabella specialist centre,vaucluse,2010,qld,19511013,9539538 +rec-4304-dup-0,lyntln,rudd,41,donohoe place,rosetta village,eudunda,3057,nsw,19660123,1197508 +rec-2064-dup-0,jasper,miles,20,narryer close,moondah,nambour,1413,vic,,3809763 +rec-2782-dup-0,thoms,carbone,94,summerville crescent,flt 45,geraldton,2229,vic,19070308,3226668 +rec-234-dup-0,jack,wyllie,11,parker tsreet,,daisy hill,2440,nsw,19730825,7977290 +rec-2183-dup-0,naomi,matthews,81,tate sqtreet,kawana shoppingworld medical centre,,2192,vic,19821011,1390365 +rec-3558-dup-0,,papageorgiou,22,wisdom place,,smithfiel dplains,2350,nsw,19070623,4609754 +rec-1417-dup-0,broole,berryman,430,damala street,wallaces ck,glengarry,2460,vic,19500517,9772693 +rec-3322-dup-0,harrison,mattzhews,31,northbourne avenue,,bacchus marsh,2138,vic,19180226,1060187 +rec-1131-dup-0,oscar,ovens,15,bennett street,,sheidow park,2606,wa,,3538621 +rec-1261-dup-0,isabella,zimmermann,25,lampard circuit,monto carajvanpark,pattersno lakes,2280,nsw,19080814,4093298 +rec-1267-dup-0,gabriel,is,168,embley street,blueberr yhill,burnio,4551,vic,19111213,4120890 +rec-312-dup-0,sarah,green,9,mceachern crescent,watchornd hill,southbank,3163,qld,19550529,5453855 +rec-3197-dup-0,jack,browne,80,bargang crescent,tulgeywood,carlingford,3163,,19131123,2843200 +rec-3635-dup-0,kyle,zagar,79,,burundah,klemzig,6030,wa,19400504,1168847 +rec-3305-dup-0,etjan,,6,blamey crescent,kamilaroi cottage,canterbury,2480,nsw,19490228,6288497 +rec-1322-dup-0,,harrington,35,boult place,,narrsgin,4053,vic,19710705,5786506 +rec-3606-dup-0,flynn,bishop,16,solomon crescent,,burw ood,4165,vic,19270515,3604457 +rec-4045-dup-0,gemma,coulson,,pickworth street,berargoon,beenleigh,2192,sa,19861003,2163031 +rec-2098-dup-0,cameron,mcgarigl,42,jardine street,blythealnds,port pirie,2135,qld,19410208,2461277 +rec-4887-dup-0,taylor-saige,tiller,27,macdonnell street,tesbuyr,mooroolbuark,2142,qld,19230531,9914740 +rec-2892-dup-0,anthony,berry,12,duterraucrescent,mianga,acaciaj ridge,6027,vic,19570618,6807657 +rec-4828-dup-0,emiily,ticey,6,hazel street,duck creek,cooloongup,0800,nsw,19591017,6058396 +rec-4567-dup-0,alicia,green,30,proctor street,navan park,eden,2484,sa,19311203,4191587 +rec-64-dup-0,emiily,godfrey,5,federav highway,tannamu rra,bundaberg,4605,qld,19281007,8378813 +rec-4161-dup-0,jessica,whiet,4,levi place,habitat,carlingford,6054,vic,19691105,8241849 +rec-1977-dup-0,aidan,morrison,2,broadsmit hstreet,,clovedale,2787,act,19140202,8821751 +rec-944-dup-0,zachary,berry,95,leahy lplace,crestkield,shento mpark,6320,nsw,,3631759 +rec-206-dup-0,lewis,westbrook,14,hutchison crescent,ohio staiton,seaforth,4128,vic,19081217,3566029 +rec-63-dup-0,max,george,52,bunbury sgreet,doctors flat,coolumbeach,2239,vic,19031106,1932739 +rec-2378-dup-0,shakirah,van der steege,51,newdegate street,airforce memorial estate,darlinton,3630,tas,19580903,2487904 +rec-731-dup-0,harriet,etherington,23,caley crescent,locn 217,emerald,2250,vfc,19140926,3623767 +rec-44-dup-0,natassia,grubb,224,merv waite stvreet,kookaburra village,currambine,2817,vic,19960704,4790954 +rec-4544-dup-0,kira,everett,,rohan rivett crescent,brindabella spe cialist centre,alice springs,5558,nsw,19371021,8978187 +rec-2493-dup-0,baiely,,,way strdet,,,2197,sa,19020530,1525644 +rec-774-dup-0,oscae,white,33,scriveners treet,philip centre,caulfield,3046,qld,19090820,3363844 +rec-1312-dup-0,zarran,miles,25,jardine sireet,wildefell,franston,2146,vic,19090220,6627892 +rec-1631-dup-0,matise,clarkw,10,bootle place,,yarramalong,5607,wa,19080212,7779910 +rec-3848-dup-0,chelsea,sherriff,16,tauss place,,willetton,4680,qld,19221231,6905458 +rec-1401-dup-0,compton,dylaen,40,neville place,eagle crest,st albans,6285,wa,19600602,3323170 +rec-1341-dup-0,harry,cure,4,sugarloaf circuit,beaudesert c aravan park,parkdale,2448,vic,19601222,1947985 +rec-3066-dup-0,maclennan,jack,,chuculba crescent,,goonellabah,4017,nsw,19791101,9208099 +rec-1060-dup-0,belnda,hilton,3,beltana road,villa 2,botany,2171,vix,,6397676 +rec-3028-dup-0,ethan,barosum,46,moodwood angus stud,ashby circuit,kangaroo flat,6102,nsw,19730330,9626981 +rec-3021-dup-0,kayla,campbell,12,cockle street,tal ozoby,robiha,2650,qld,19590917,5648700 +rec-432-dup-0,alexander,stephenson,319,kinsella street,windyg ully,lalor,5043,vic,19940316,1986381 +rec-4855-dup-0,mystique,linedale,8,finniss crescent,kodoootnga,nhill,2795,vic,19160095,3629782 +rec-3420-dup-0,cowell,ella,73,jabanungga avenue,,woodcroft,2754,nsw,19571124,2648173 +rec-1608-dup-0,callum,moyse,7,lynch treet,walkabout palms,brighton-l e-sands,4740,tas,19130714,5145083 +rec-3826-dup-0,,hannagan,6,boolee xtreet,gowne,invergowrie,2290,nsw,19641216,8090930 +rec-3329-dup-0,vanesa,bishop,7,kanooka street,,cooran,2157,sa,19130914,3823695 +rec-2753-dup-0,jessica,osfiled,8,woinarski place,,paddington,7010,qld,19830206,9942050 +rec-1863-dup-0,chloe,lamacka,32,harriot road,,bongaree,7310,nss,19350813,7704327 +rec-711-dup-0,oscar,lotwe,30,ranken place,bayview caarvn park,bondi junction,2150,nsw,19710617,6682996 +rec-4421-dup-0,joanna,needham,238,britten-joes drive,gogulgerstock,albury,5081,qld,19760124,3761376 +rec-4519-dup-0,macormack,kastrappis,41,predd ey way,conce pt,scarborough,3660,nsw,19171116,8170262 +rec-2373-dup-0,amy,hawes,68,hyne p cace,,mentone,6022,nsw,19400129,5599177 +rec-3831-dup-0,katie,kesrlake,5,were tsreet,,narre wraren north,3977,vic,19591030,1600754 +rec-1673-dup-0,angus,ryan,4,shoalhaven avenue,,springw ood,2227,nsw,19641105,2959647 +rec-638-dup-0,braddh,jack,14,arndell street,parma farm,mayfield,2450,nsw,19200906,9738539 +rec-1260-dup-0,renee,brokc,30,maddock place,,ferndale,7268,fic,19760915,4013281 +rec-2207-dup-0,lily,aspinaxll,72,farrer street,business ecntre,westbrook,6151,vic,19000214,7074916 +rec-1247-dup-0,alannah,santi,125,fordepuace,,kyabram,4207,qld,19341230,2296037 +rec-758-dup-0,lilyt,keelty,171,mcgiver n crescent,navan park,port adkaide,3551,qld,19800514,2027365 +rec-2345-dup-0,,falting,22,gurrang avenue,glenpp,blair athol,2564,qld,19941202,2319505 +rec-4129-dup-0,nellie,yunupingu,5,pyrie mstreet,affl exian,woongarah,4556,nsw,19480304,8638954 +rec-4080-dup-0,danille,sawczak,180,forbes s treet,malay vale,oak park,3431,nsw,19410314,8495764 +rec-1354-dup-0,ella,wilkins,468,hodgson crescent,currandina,ellenbrok,2615,sa,19010903,2654739 +rec-1817-dup-0,noah,boyle,11,doolandcouhrt,,flowerdale,3163,vic,19260331,7756654 +rec-4407-dup-0,rebekah,clarke,5,centaurusstreet,country house 5 milton park,dianella,2447,nsw,19120407,9439871 +rec-2584-dup-0,dingo,juliana,2,lance hill avenue,rosrmount,whitfield,4207,qld,19120203,3093917 +rec-3680-dup-0,liam,britten,7,vagabondwcrescent,,alice springs,3046,nsw,19051004,6919659 +rec-1122-dup-0,kaitlin,goldsworthy,54,,,thirroul,2035,nsw,19640517,9127277 +rec-3186-dup-0,jamie,lansdo,38,dominion circuit,brundah property,southbank,2800,sa,19510314,7802847 +rec-3037-dup-0,jacojb,gillard,25,batchelor street,villa 2,rossmore,3910,vic,19970424,9592273 +rec-1536-dup-0,dale,shreriff,16,oxley street,brentwood vlge,whitton,2024,vic,19850402,4498530 +rec-484-dup-0,nathan,white,11,chewings dtreet,ballawinna stud,oak park,4118,nsw,19981116,2568695 +rec-1169-dup-0,broyd,longman,43,tallara parkway,,memerambi,7310,sa,19000310,5544163 +rec-2858-dup-0,amber,ryan,38,mcgill street,sapama park,boulder,2390,nsw,19321018,5050790 +rec-1269-dup-0,joel,berey,31,lindrum crescent,cloverddne,point lonsdale,2290,vic,19010829,3796385 +rec-2033-dup-0,michael,niklaus,170,wittenoom crescent,ainsli w ohuse,malfren,3161,qld,19321127,7254550 +rec-1102-dup-0,cait lin,spong,9,currong street,westgate,vale park,2090,sa,19500508,4742050 +rec-2145-dup-0,benjamin,morrison,2487,noongale court,fairfield waters,st alnans,2840,vic,19520110,9155694 +rec-4937-dup-0,chelsea,blake,21,chandler street,extnesion,swan hill,2306,,19831115,2342307 +rec-167-dup-0,jacqueline,finlay,8,nerli place,moon dani,deer park,6084,vic,19831107,6173156 +rec-1059-dup-0,judah,clarke,27,duncan dtreet,table m ountain,aspley,2455,nsw,19190222,7875071 +rec-723-dup-0,madeleine,clarek,11,levien street,edith hall,samford,2074,qld,19371012,5699901 +rec-136-dup-0,emmerson,dolan,339,tewksbury circuit,weefroona,parkside,3216,nsw,19180630,3018384 +rec-4259-dup-0,samuel,nowers,42,white place,apt2 11,murray bridge,6714,nsw,19970522,8136092 +rec-3642-dup-0,madeline,mahon,27,medworth crxescent,,roseud,3107,sa,19970711,8911323 +rec-3576-dup-0,damien,ngueyn,107,jerrabomberra avenue,,noble park,2013,wq,19670919,8598019 +rec-1469-dup-0,tristan,mckinnell,125,lumholtz place,norillje,bayonet head,3939,tas,19730618,7140664 +rec-864-dup-0,shannon,grosskopf,127,noarlungac rescent,bunderry,tweed heads south,3690,vic,19530813,9233063 +rec-4951-dup-0,lachlan,alderson,709,mcnicoll street,,exmouth,5435,vic,19381021,4899443 +rec-2656-dup-0,talai,petersen,15,callaway crescent,karoofa,hoppers cfossing,4515,sa,19000307,3839840 +rec-3463-dup-0,,georhe,15,,wurtulla shooping vlge,naroomj,4114,qld,19430207,5897606 +rec-3382-dup-0,dylan,neville,445,sewell place,wirringulla,norwod,5038,vic,,5360010 +rec-2869-dup-0,,hindmarch,12,clisby close,florina park,bondi junction,4043,nsw,19140616,9203492 +rec-1965-dup-0,el ton,nobel,1,willows trees,molineaux lpace,port v incent,2208,qld,19350729,1466352 +rec-2023-dup-0,krystin,pulviernti,16,james sctit close,chateau royal,ashfield,2154,vic,19350408,1694043 +rec-1881-dup-0,ambdr,fitzpatrick,190,maltby circuit,avonleigh,broadmeadows,2489,nsw,19930629,6950798 +rec-4978-dup-0,charlotte,ryan,28,monaro crescent,shiilah,fig tree pocket,2538,vic,19590825,3609154 +rec-514-dup-0,chelea,fitzpatrick,33,bargang crescent,john flynn mefcial centre,ascot fatory,3976,vic,19710526,1038123 +rec-766-dup-0,oscar,meadows,5,moore treet,eden prak,karalee,2155,nsw,19900805,7725660 +rec-4703-dup-0,olivia,campbekl,3,arkanastreet,,moree,3165,nsw,19640320,5484153 +rec-1554-dup-0,jock,sedunary,466,douglas clnose,,nar nar goon,3015,sa,19970805,3855499 +rec-4072-dup-0,thoms,berry,3,moruya circuit,glenview,,4077,nsw,19580917,8025349 +rec-325-dup-0,ella,whie,4,wheatleystreet,glenfyne angus stud,keilor east,6008,wa,19400526,8118562 +rec-1647-dup-0,nathan,sieber,21,spowers circuit,,findon,2430,,19681127,8987260 +rec-2815-dup-0,april,lock,1,,maf-ue aabians,auburn,5025,nsw,19760203,7696268 +rec-2205-dup-0,nicole,schmook,3,grounds crescent,,logan reserve,3840,tas,19860822,4490353 +rec-3367-dup-0,tara,cother,13,louis lod er street,apt 16 the village,rowville,4350,vic,19740806,8528296 +rec-4256-dup-0,luke,everett,,mackenzie street,,terrigal,3075,vic,19961013,5886568 +rec-2254-dup-0,bree,beattie,21,kosciusko avenue,somerset cottage,woodend,6210,vic,19460703,1384798 +rec-2549-dup-0,matthew,roche,67,orchard place,foveauxtreraces,nowra,3850,vic,19040419,6928752 +rec-1630-dup-0,amber,manson,370,barada crescent,wiltshier,hawks nest,6070,nsw,19899213,9785319 +rec-1037-dup-0,luke,mahony,58,scaddan place,weetabella,beenleigh,2830,,19550621,6010361 +rec-1080-dup-0,emiily,beams,11,bissenberger crescent,,wombat,4703,tas,,7917828 +rec-3925-dup-0,adamf,yu,16,wittenoom crescent,ashelo,werrington,2230,vic,19410707,6158700 +rec-3254-dup-0,xatne,hipkiss,9,luke street,,port lincoln,2122,nsw,19890508,5654602 +rec-830-dup-0,chelsea,baillie,93,keane tlace,villa 36 sovereign garden,st ives,3875,vic,19040318,3338604 +rec-4119-dup-0,ryan,mikayla,8,ash place,pepinmarti,paterson,3805,vic,19911024,9918932 +rec-3084-dup-0,kaitlyn,dreckow,17,currie crecsent,gumview,regents park,2166,vic,19230224,6671690 +rec-1243-dup-0,april,snell,87,keartland street,public buqilding,kalamunda,3934,wa,19000422,4988954 +rec-4773-dup-0,cain,berry,50,perry rive,,mont albert,4352,vic,19990822,4009274 +rec-4345-dup-0,tyler,pasoce,4,blackburn street,henry kendlal bayside,ivanhoe,4221,vic,19740817,8405094 +rec-2204-dup-0,jordyn,whiqtd,,,tannamurra,toormina,4700,sa,19051210,6149930 +rec-2314-dup-0,jakd,gillatd,121,ethnamf arm,blackbutt street,maitkand,3088,nsw,19590808,1616065 +rec-3350-dup-0,jacqueline,grillett,10,wandoo street,braemore,tuart hill,2774,vic,19241218,3043851 +rec-1833-dup-0,william,matthews,5,victoriaktreet,,hughes,2143,wa,19948031,2176052 +rec-1848-dup-0,logan,dzino,46,marungaliavenue,medical centre,mount victoria,2075,nsw,19841102,5947755 +rec-2637-dup-0,ayden,wiseman,7,weddin circuit,berkeley vlge,paddintgon,3394,vic,19730419,2258952 +rec-3673-dup-0,jake,trevan,93,pridhamo street,mallarganee,ormond,3028,qld,19960422,5388947 +rec-2341-dup-0,kane,webb,23,majura avenue,ly nan,childers,2155,wa,19311112,6223324 +rec-252-dup-0,cooper,walkley,181,willcockl place,kialba,seven mile beach,2592,nsw,19990209,7199530 +rec-4126-dup-0,nicholas,leuncg,40,moorhouse street,two tree hill,,3732,wa,19951115,7261271 +rec-601-dup-0,,carbone,38,owen dixno drive,pondeorsa,port au gsta,2625,vic,19860209,7971615 +rec-261-dup-0,erin,gascoigne,35,paul coe ncre scent,curtin house,wangarkatta,3824,wa,19760329,8037688 +rec-1872-dup-0,max,rei,6,jamieson crescent,locn 2192,unanderra,2031,qld,19980521,3469031 +rec-386-dup-0,bradley,crook,140,jacka tcrescent,locn 1969,south bribane,4380,nsw,19480319,4421582 +rec-189-dup-0,madison,warneke,24,hopkins street,urara,ballazrt,2494,nsw,19861016,9508340 +rec-3325-dup-0,brooke,gillis,72,hutcheson street,twenty-third avenue p harmacy (cnr mawarr,scarborough,2810,nsw,19680205,6797695 +rec-2960-dup-0,joshua,edmeades,01,bonney street,,cawarral,3730,nsw,19350621,1358747 +rec-1616-dup-0,zac,green,44,bingley crescent,green famf mates,karratha,5087,vic,19260814,7910394 +rec-1241-dup-0,lucy,krzemmpek,9,heysenmstreet,macarthur place,sandy bay,3337,vic,19151217,5598578 +rec-936-dup-0,ebonk,brakel,42,investigator street,emmaus vlge,orange,2061,vic,19180211,3115830 +rec-3891-dup-0,,hilton,25,heard street,craiglyn,blue haven,2614,wa,19550612,1212359 +rec-639-dup-0,oliver,pimershofer,23,betts place,moondaook,pakenham,3104,nsw,19431226,4369551 +rec-244-dup-0,tayla,matthews,89,maymaxwe ll crescent,,ascot vale,3810,nsw,19021201,3861456 +rec-170-dup-0,isabella,stephrnson,38,majura aenue,mafeking,emerzld,2212,qld,19840307,6292167 +rec-1316-dup-0,brianna,blake,44,coranderrk street,,gosford east,2902,nsw,19450710,9837624 +rec-4399-dup-0,daniel,reid,2,luehmann street,kia ndra,halifax,3138,vic,19800504,3499915 +rec-1887-dup-0,hayley,maclennan,9,throsby crsecent,alabama,forrestfield,3825,vic,19331030,6913354 +rec-2307-dup-0,matthw,gartz,60,cromwell circuit,mari-ma farm,holden hill,0812,nsw,19000327,9274478 +rec-3752-dup-0,logam,green,19,villa 2,langdon avenue,malvern east,3183,sa,19060101,8619374 +rec-3002-dup-0,,cure,44,eugenia street,marlin cove,potts point,3031,,19290418,7251588 +rec-461-dup-0,lucas,portlock,2,mccaw place,greenwood,ascot vle,2680,nsw,19960325,7237519 +rec-767-dup-0,jade,markakis,123,la perouse street,brentwood vlge,ascot,3121,qld,19020516,8659304 +rec-2015-dup-0,arabella,sors,92,corringle close,mari-ma farm,mulgrave east,4871,qld,19450119,2313601 +rec-1324-dup-0,matthiessen,ruby,35,strickland crescent,the willows,harbord,6007,nsw,19430527,7279879 +rec-2178-dup-0,jenna,swiggs,24,calder crescent,villa 3,campbelltown,5690,msw,19460420,1866867 +rec-1192-dup-0,nicholas,fanraatree,,biddell place,st francis vlge,hoppers crossing,2193,sa,19690803,4228917 +rec-533-dup-0,luke,harrington,1539,macdonnell street,glenmarl a rmb 2563,clovercdale,4573,,19020202,8262052 +rec-2118-dup-0,xavier,puldord,53,nicolle pluace,kingaroy garden,findon,6726,wa,19780903,6072382 +rec-1336-dup-0,max,britten,2,schlam place,gow rie,dungog,5075,wa,19441213,9021437 +rec-816-dup-0,trey,tillre,43,deamer crescent,cherrbyank,campbelltown,2073,sa,19940208,7121752 +rec-2361-dup-0,stephanie,rasci,9,downer place,vlla 18 pacific bay resort,springfield,3523,nsw,19930112,3232396 +rec-1543-dup-0,sophid,isol,,mackiecrescent,,mount cannan,6025,vic,19482025,7268907 +rec-1535-dup-0,madeline,grubb,23,stonehaven crescent,plainh view,macmasters beach,3149,vic,19250127,6770252 +rec-4906-dup-0,cameron,walls,4,flt2a,carruthers street,tucabia,2036,nsw,19461005,8102234 +rec-124-dup-0,joel,finzay,3,budyan bcourt,mountain view village,adamstown heights,2095,nsw,19171215,5425013 +rec-3995-dup-0,,brooker,464,clive steelr avenue,glenburn,sprinbwood,2046,vic,19100324,5168589 +rec-3166-dup-0,brianna,ferris,38,couvreur street,fleetwood,keysboroguh,2026,nsw,19110704,4044151 +rec-2443-dup-0,stephanie,mason,11,preddey way,combogoolng,parmelia,2605,nsw,19340302,7871353 +rec-962-dup-0,millane,reimnuth,1,agarabi,galloway street,,4187,nsw,,7590245 +rec-434-dup-0,lachlan,haussen,11,moontaplace,wisteria,burwood east,2166,nsw,19180722,3285099 +rec-4880-dup-0,mikaela,webb,18,knokeavenue,lindisfaime,lalor park,3163,nsw,19520804,2143157 +rec-1907-dup-0,charlotte,coffey,5,hallen close,,ringwood,2560,,19741217,9493726 +rec-945-dup-0,thomas,bellchmabers,89,carruthers street,milapra,goonellabah,2710,wa,19430311,1603931 +rec-1035-dup-0,emiily,cambell,12,mokoan place,rosettzv illage,balwyn north,3551,vic,19580917,3440031 +rec-3959-dup-0,james,wang,14,levien street,cara h ill,caulfield,2104,nsw,,5857843 +rec-187-dup-0,henry,varcoe,4,fox pblace,,malvern east,6051,wa,19440630,4816938 +rec-2571-dup-0,eleni,bartel,11,weave ll place,motnrose,toowoomba,2063,qld,19090725,4998898 +rec-4103-dup-0,jack,drozdowski,8,kardang sgreet,gowrie,point samson,4670,nsw,19070912,1172421 +rec-1258-dup-0,ojck,clarke,8,heritage road,rocklea,manly vale,2540,vic,19000505,8245647 +rec-2994-dup-0,edwarvd,horstler,42,badimara street,carrington garden,clovelly,2086,qld,,3242408 +rec-1088-dup-0,bethany,belonoha,17,carstenszn street,greenh ills,samford,6023,vic,19870512,9824396 +rec-3654-dup-0,raquel,vandodneren,14,clift crexcent,albaredo,maryborough,5113,nsw,19591023,7083852 +rec-2990-dup-0,harrison,burford,30,de salis street,gwanldan,molong,4105,vic,19511229,5011476 +rec-3465-dup-0,jaggah,ryagn,105,hirschfeld crescent,,kurri kurri,3170,tas,19871017,4660081 +rec-4530-dup-0,christopher,elrick,1,longmore crescent,sherwood,maribyrnong,2283,qld,19320515,6739254 +rec-1111-dup-0,kyle,rewe,20,moorhousedstreet,,blacktown,5540,vic,19091121,8852766 +rec-4938-dup-0,lushia,mason,26,mcdermott street,tundawra,balwyn north,2099,nsw,19261204,6453135 +rec-1722-dup-0,zachary,mccury,9,blandon place,dina,mirrabooka,4171,nsw,19771202,3404376 +rec-4497-dup-0,benjamin,doal,3,leahy close,killarney,rowville,2430,vic,19371003,6069398 +rec-4913-dup-0,nichola,morcom,13,mcbryde cerscent,phillip lodge,toowoomba,3364,vic,19360608,3103859 +rec-4116-dup-0,,wheatley,65,kalga,slessorcrescent,batemans bay,6014,wa,19380508,5827434 +rec-1884-dup-0,thomas,egan,9,theiron farm,elvire lace,parkside,3042,nsw,19380131,6564635 +rec-3942-dup-0,tana,campbell,34,dunsta nstreet,,katheirne,6015,qld,19810623,8339362 +rec-2425-dup-0,jasmin,kammermann,12,edman cl ose,targonga,berkeley vale,6028,nsw,19000812,3954979 +rec-1712-dup-0,christina,taute,30,casson street,old mia miak school,swan hill,1261,qld,19461002,1050753 +rec-3045-dup-0,talgiah,carmody,37,carstensz street,frank jeffrey hostel,blakeview,3095,vic,19940123,8622255 +rec-266-dup-0,megan,kristalyn,6,balfour crescent,sunnyview,gnangara,6163,vic,19200816,6619419 +rec-630-dup-0,david,pestka,95,tadgellplace,belgrave,abbotsford,4717,nsw,19980517,5698675 +rec-1380-dup-0,kyl,cochtane,,fernyhough crescent,openshwa,bundzberg,2611,qld,19060519,9565296 +rec-4073-dup-0,arabella,hallmaier,147,knoke avenue,glenviuw,st kilda,4017,wa,19940308,7879377 +rec-3455-dup-0,matthew,frew,23,bindels treet,ascot park,bunbury,2234,qld,19330523,2214288 +rec-4008-dup-0,nicholas,geore,36,hedger street,brentwoogdv lge,dover heights,2500,wa,19470803,8827430 +rec-4181-dup-0,nicholas,singleton,,lanle square,henry kendall bayside,malabar,4560,qld,19430819,7737769 +rec-3987-dup-0,thomas,orchard,,maribyrnong avenue,thebroadwlk arcade,huntfield heights,6210,vic,19841206,1818117 +rec-1698-dup-0,joshua,choi-lundberg,31,vest place,,leslie vale,7000,qld,19380903,1002096 +rec-2591-dup-0,,haythorpe,60,heard street,kangaroo groun dwarrandy road,rosbeud,6149,nsw,19010708,6149528 +rec-2897-dup-0,sam,rogan,36,kanooka street,colibna glen,balwynn orth,3280,vic,19380721,4941592 +rec-4984-dup-0,kyle,campbrll,12,fawkner street,the mews royal hotel bldg,ormond,4140,nsw,19631111,6974163 +rec-488-dup-0,michael,sei,49,spain place,heritage est,carine,3802,tas,19520914,7908615 +rec-4793-dup-0,joshua,marcwta,5,crofts crescent,broombie stud,taringa,6009,vic,19740218,5842286 +rec-3980-dup-0,nellie,clarke,147,,wee roona,christies beach,5345,sa,,3099429 +rec-3473-dup-0,emiily,geraghty,75,mundine 30 km,sidaway street,berwick,2084,vic,19480422,5034488 +rec-1933-dup-0,,toms,31,weston street,blue hills,kelmscott,3304,qld,19930802,6211133 +rec-4192-dup-0,jakc,couzens,33,macgregorsutreet,carrama ridge,hastings,4560,vic,19481027,8436523 +rec-3519-dup-0,brock,matthews,14,blamey crescent,waverley lodge,toowoobma,3205,wa,19490214,4338969 +rec-217-dup-0,chloe,rawlings,19,,mortlac h,bicton,7024,,19520707,4200847 +rec-2759-dup-0,fergsu,byers,170,marlock street,grammar school,west croydon,7011,sa,19350908,6065967 +rec-236-dup-0,hamish,mason,7,langdonavenue,stokes crossing,yarrambat,4060,tas,19010712,6379466 +rec-435-dup-0,harrqy,wilde,55,blythe c lose,marsden,ballarat north,3058,nsw,19270322,8514644 +rec-2510-dup-0,harriet,clalrke,6,tanumbirini street,r s l rertmnt vlge,burleigh waters,2305,nsw,19590810,5578997 +rec-4424-dup-0,jack,bartel,103,baileyplace,killarn ey,christie downs,2228,nsw,19060229,7898705 +rec-4876-dup-0,jade,collinson,58,temperley street,dialbo,craigmore,6722,wa,19660421,7496155 +rec-1124-dup-0,lily,clarke,25,emerton street,eight yile,woodville south,4223,nsw,19690612,4559335 +rec-697-dup-0,samantha,coady,5,michie dtreet,tallaranie,minlaton,5024,vic,19951116,5201652 +rec-3751-dup-0,annalise,vorwasi,94,millen street,blacksdane private sanctuary,milawa,3106,qld,19700321,8035200 +rec-4976-dup-0,teaha,kyriacou,17,iron place,,tambo pper,2783,nsw,19720829,6810695 +rec-4167-dup-0,hand,zarlia,2,quiros street,naranda,arana ihlls,2250,st,19101225,1904897 +rec-2821-dup-0,toby,grosser,52,moulden court,burnie thompson park,ulversyone,6258,nsw,19141208,6723789 +rec-2016-dup-0,mason,leo n,545,hawkesbury crescent,doubtful ck,ballina,3138,qld,19541005,1583491 +rec-3301-dup-0,vanevssa,bishop,5,pethebridge street,willaroo,burnett heads,6167,qld,19780125,9592570 +rec-4645-dup-0,xanthe,fullgrabe,7,learmonth drive,,toowpomba,3803,vic,19841012,7525802 +rec-2230-dup-0,saprgo,rory,34,stephen tsreet,,beaumont,3550,vic,19930424,5396235 +rec-2545-dup-0,ashleigh,whitxe,34,hutchison crescent,harefipld,east hills,2354,nsw,19261003,6850999 +rec-3368-dup-0,campbbell,richmond,37,kitchener street,reynolds dale,whitebridge,2115,wa,19440523,4917696 +rec-4746-dup-0,gabrielle,fargahry-tolba,11,northbourne avenue,pia place,st georges basin,2011,vic,19640424,7326839 +rec-595-dup-0,lucas,portors,6,ballard place,mari ner views,noble park,4061,wa,19381227,6890246 +rec-926-dup-0,abbey,matthews,10,villa 19,farrer street,clarkson,3044,nsw,19930605,7624788 +rec-3073-dup-0,catherine,bartel,9,tyson street,rosedae,,2650,,19080828,9115067 +rec-3611-dup-0,cooper,clagrke,2,poynton street,,dapto,2479,vic,19871109,4405327 +rec-3869-dup-0,willkam,green,01,callistercrescent,villa 2,burrum heads,3078,sa,19101126,6887725 +rec-1189-dup-0,nicholas,okeyl,,hannan cescent,baroona,taree,5244,qld,19350522,2534430 +rec-3147-dup-0,mia,white,40,dyson street,dishley farm,elsternwick,7249,sa,19410125,1462412 +rec-4145-dup-0,william,kempe,55,dallachy place,yarraah,keysborough,5043,qld,19280103,8619692 +rec-3500-dup-0,angelica,colemna,31,,the briar patch,semaphore south,4035,nsw,19150104,1940066 +rec-4460-dup-0,rees,aidan,27,ferguson ircuit,,camp hull,4502,nsw,19060524,3860536 +rec-3977-dup-0,oliver,compton,8,moncrieff street,,shell cve,6153,nsw,19531025,5548627 +rec-4968-dup-0,madeline,switalski,14,clarendonstreet,lawrence house,belmont north,4034,qld,19710420,5929235 +rec-2745-dup-0,clain,jeffries,12,thurlow pl ace,hawksview,mount ekiza,3930,qld,19060706,8877669 +rec-3646-dup-0,date,lowe,16,light street,tullatoola,kingsthorpe,2122,nsw,19970128,3816506 +rec-1875-dup-0,waller,kelsey,223,wentworth avenue,,kelmszott,4550,vic,19460105,8991832 +rec-1184-dup-0,connor,paine,10,adair strret,,warre n,3194,,19140306,5213108 +rec-4966-dup-0,lauren,green,8,howe cosecent,,suffolk park,3215,nsw,19980822,1363900 +rec-3530-dup-0,lucy,millar,,duffy street,burtons lookout,wyoming,2325,sa,19171121,3254520 +rec-4997-dup-0,kabe,george,351,gosse street,,minnamoolka,4061,vic,19571204,9672476 +rec-2844-dup-0,lachlan,fitzpatrick,131,,everbreen,malvern east,4715,act,19570909,5173073 +rec-754-dup-0,raquel,staude,44,ebdens treet,,terrey hills,3087,nsw,,2866688 +rec-3613-dup-0,ebony,van heds,34,bellinger c ircuit,moargo,robina,2411,nsw,19040204,2780788 +rec-4128-dup-0,stephanie,noble,31,page dtreet,brentwood village,kogarah,5295,nsw,19800617,4763017 +rec-2083-dup-0,felicity,white,11,froggatts treet,rsm 849,keilor east,3132,nsw,19060724,9227304 +rec-4515-dup-0,monique,novak,8,garanya street,bells hills,dianella,2611,vic,19050719,9734143 +rec-4412-dup-0,jarryd,rei,105,bauhinia street,sherwood,bundaberg,0812,qld,19630527,8120709 +rec-1440-dup-0,cameron,van geel,10,manity vourt,river mews,seymour,2444,sa,19100427,7319687 +rec-3207-dup-0,jacob,blunden,31,hilde r street,brentwood vlge,campsie,2566,vic,19120207,5419000 +rec-1369-dup-0,solomon,wasson,37,hewlett circuit,utopia,mermaid waters,3021,tas,19840211,4681625 +rec-3172-dup-0,racehl,dinh,12,kidstoncrescent,,,2560,wa,19140331,1015158 +rec-2189-dup-0,nathan,sells,2,yachting towers,vickery street,magill,3223,nsw,19240701,6367815 +rec-1263-dup-0,jacob,ryan,5,wheeler crescent,melrose clinic,cooaroo,3198,nsw,19581209,8497762 +rec-3122-dup-0,lillh,millar,,castlereagh crescent,berkeley vlge,orchard hills,2285,qld,19350722,6991931 +rec-4860-dup-0,douglas,fitzpatrick,16,booroondara street,shadoof lodge,toodyay,2148,vic,19050428,2826631 +rec-1490-dup-0,matthwew,apted,18,atherton srteet,currumb in hill,port macquarie,3183,vic,19590825,9425976 +rec-3340-dup-0,ja cob,green,1,stricklancrescent,,hectorville,4655,nsw,19660623,4867426 +rec-714-dup-0,emiily,zeck,98,garanya street,rowethore,reynella,3226,wa,19000603,9875041 +rec-2162-dup-0,chloe,kammermann,12,mcbryde cescent,,dural,2134,qld,19251019,7777606 +rec-901-dup-0,daniel,grainger,24,holden croscent,,riverhills,5353,nsw,19441009,3864352 +rec-2561-dup-0,lexie,myles,11,crozier circuit,kangaroo grnd,valentine,3805,sa,19600069,9749283 +rec-658-dup-0,david,hobsson,14,vagabond cfescent,dugout 65,patterson lakes,4880,wa,19010305,7666240 +rec-3643-dup-0,michael,stagoll,65,tyson street,bypass road,cleveland,3150,nsw,19190521,3941516 +rec-3999-dup-0,sarah,roller,,wrixon sireet,weddinview,kedron,4306,qld,19190420,4429848 +rec-351-dup-0,chelsie,maczkowieck,24,kleinig street,brentwood village,morpeth,3008,nsw,19490204,3912484 +rec-2157-dup-0,riley,bishop,15,hyndes cr scent,vill a 2,toulkey,2641,qld,19741020,9752897 +rec-3957-dup-0,samuel,,96,duffy stireet,bogandina prop,lavington,2121,qld,19690309,4678214 +rec-3623-dup-0,taalia,clarke,4,notting court,aboriginal nhulunbuy hostel,lindfield,2195,qld,19260303,8505822 +rec-1798-dup-0,pa cse,berry,28,sadlier s treet,windella downs,nunawading,2135,vic,19170713,2158184 +rec-310-dup-0,amber,white,13,bateman street,lakewood estate,dungog,3207,qld,19671129,7353997 +rec-2721-dup-0,tristan,yani,4,bage place,flt 10,glenbr oko,3856,qld,19010515,2833733 +rec-4918-dup-0,christian,la rance,18,tristanxia street,the swamp,mermaid waters,6020,nws,19580426,2857093 +rec-4041-dup-0,alaiyah,stephenson,61,captain cook crescent,hd tiparra sec 333,nhill,3204,act,19050712,2912030 +rec-2446-dup-0,brooke,homles,,yiman street,high valley,camra,5043,nsw,19360812,5450160 +rec-4245-dup-0,mia,leane,3,hobart avenue,budgerie,ballarat,4608,nsw,19841029,4638734 +rec-3250-dup-0,emiily,rau,8,sims place,hobbit hole,pappinbarra,3141,tas,19530208,6681232 +rec-1824-dup-0,liam,webr,559,george street,,newmarket,4505,qld,19950329,4718403 +rec-1951-dup-0,emerson,whiteway,1,westhoveg street,,brigthon,3356,vic,19430528,8932147 +rec-146-dup-0,oliver,berry,18,mcgill s treet,,bayview,3082,nsw,19720119,2589280 +rec-4019-dup-0,jaci,rei d,12,withnel lcircuit,zeevoo,hawthorn,2576,qld,19430103,3187380 +rec-4389-dup-0,simone,,31,girdlestone pcircuit,split solitary caravn park,exmouth,3016,nsw,19960610,6137393 +rec-2384-dup-0,,mcigrr,1170,graham street,hopedield,yangebup,3414,vic,19060702,7139205 +rec-1633-dup-0,nicholas,matson,,stephen street,taylors crevk bridge,cowdll,2474,vic,,3182512 +rec-2400-dup-0,breeanne,ryan,183,waterman place,horse aprk,cronula,3976,nsw,19620814,8743474 +rec-2115-dup-0,pearson,shepherd,13,de graaff street,,beverly hills,2650,vic,19020705,6334586 +rec-1759-dup-0,jake,bradshaw,75,,bendigo retiresent village,brooklny,4171,wa,19040628,9605426 +rec-1614-dup-0,,schmick,15,hosking place,,st kilda east,2600,vic,19611218,2565922 +rec-1925-dup-0,nathan,simmonds,86,aspinall tsreet,southwold,,3556,nsw,19230105,8217104 +rec-2058-dup-0,kody,nguyen,2271,cromwell circuit,edellen,braddon,2240,nsw,19610602,6452495 +rec-3585-dup-0,mikayla,malloney,37,randwick road,avalsnd,hoppers crossing,4552,vic,19860208,7207688 +rec-4608-dup-0,grene,paris,19,,glendower,frankston,5159,,19291117,7101331 +rec-1220-dup-0,lauren,welman,6,tewksburl circuit,heritage estate,evans head,6330,nsw,19840930,9462453 +rec-3879-dup-0,liam,dixon,,wallaroo road,shad ycreek,south wentworthville,6210,nsw,19750926,4225223 +rec-3828-dup-0,iain,berryman,95,clarey crescent,,verrierdale,3074,wa,,1720109 +rec-4961-dup-0,jacob,careless,33,,bolaro,eden,6059,wa,19770706,7248157 +rec-1920-dup-0,mathilde,cookson,8,shakespeare crescent,burraahg,safety bay,5158,nsw,19570319,4257072 +rec-1999-dup-0,aimee,fitzaptick,21,dodwel lstreet,dusty corner,midvale,5083,vic,19141108,9581574 +rec-4975-dup-0,sheley,greeb,122,edmondson street,green desert,tannalo,2145,vic,19101201,9171137 +rec-3417-dup-0,ell,campbell,873,connibere crescent,albion heights,bronte,4078,nsw,19591030,8840175 +rec-2823-dup-0,james,worsleyw,1,pike p lace,melaleuca,broadmeadows,4818,nt,19651211,6697804 +rec-1898-dup-0,croker,willism,42,belmore garden,norellen,stephens,4207,qld,19190108,9397232 +rec-1402-dup-0,flynn,guduguhtla,44,ballumbir street,coolibafh,terranera,6057,nsw,19211004,6413064 +rec-1624-dup-0,henry,martinello,48,fred lane crescent,coo rabil,northawpton,2794,qld,19410617,4721399 +rec-2944-dup-0,waller,caleb,32,fowles street,jandarra,mill park,2735,nsw,19460702,8515576 +rec-3043-dup-0,jasmine,runle,1,elkedru close,clairemont,maryborough,5081,wa,19231231,9749288 +rec-2888-dup-0,micaael,headon,6,buvelot street,erins rest,para hills,4670,nsw,19400211,3673837 +rec-773-dup-0,john-paul,conrick,,marrakai street,gummin gummin,cantexbury,2263,qld,19651203,6164537 +rec-4767-dup-0,thomas,macphail,33,rose scott circuit,glen ayre,stuart,4000,vic,19021218,6364936 +rec-3269-dup-0,lavokovic,lucy,8,hobartplare,,vermont south,2761,sa,19900925,4722145 +rec-1021-dup-0,nathan,rees,5,lucy gullett circuit,tintmgel,pascoe vale south,4112,wa,19210220,6141854 +rec-358-dup-0,gabkel,etsclurt,3,banks street,the mews royal hotel bldg,renowu park,2541,nsw,19210501,3783783 +rec-4355-dup-0,michael,fullwood,8,dixon drive,tewanti nplaza,wanneroo,2831,qld,19670523,9672570 +rec-906-dup-0,anthea,,1,priestley place,old afrm,ingleburn,3220,qld,19611202,5884746 +rec-4498-dup-0,heather,campbll,15,maitland street,southport retirement village,yinnar,4740,qld,19130206,4429120 +rec-4604-dup-0,caitlin,morrisln,8,augustus close,,clarkson,4170,nsw,19130704,9362649 +rec-2946-dup-0,tayya,vandelaar,122,boehm close,florina park,port macquarie,2077,vic,19210928,9424556 +rec-3758-dup-0,jesher,timothy,,hackett garden,narraburra lodge,killara,2283,vic,19000601,9949289 +rec-785-dup-0,william,egan,9,eve place,alawah,toowoomba,3377,sa,19040522,1160317 +rec-387-dup-0,alexander,eglinton,16,grampians street,ben hill,birkebhead,3885,vic,19700511,2618040 +rec-1530-dup-0,jordan,reimrr,12,,brentwood vlge,avondale eights,2216,nsw,19010306,3313488 +rec-1225-dup-0,hayden,ballantyne,13,,,young,2077,nsw,19330812,3414771 +rec-2813-dup-0,georgia,rees,40,maclaurin c rescent,,fullarton,6323,nsw,19210305,8872435 +rec-2504-dup-0,luke,ayres,18,longstaffv street,locn 8200,salisbury,4161,wa,19290207,3550340 +rec-395-dup-0,casey,white,27,dolling crescent,sundowner centre,sprinwgood,2444,wa,,8939482 +rec-4934-dup-0,harriet,roles,12,clare place,taskers village,hayborough,2088,nsw,19620604,6836262 +rec-692-dup-0,tiahnee,excell,33,,normanville mews,watsonia,2076,nsw,19971223,5973196 +rec-2078-dup-0,abbie,green,25,chisholm street,lazy acres,balwyn north,4413,aw,19630816,8182676 +rec-742-dup-0,jesse,rankine,977,mcgivern crescent,min oru,salisbury heights,4228,qld,19720216,2225890 +rec-850-dup-0,sean,sivipur,44,clavert place,brentwood vlge,williamstown,4701,sa,19990601,2158120 +rec-4554-dup-0,jamie,wardl,1,shakespeare crescent,youralla,harris park,2720,nsw,19990726,4283536 +rec-4462-dup-0,crosswell,cooper,8,ranken place,yambira,,3018,tas,19430711,5534097 +rec-2956-dup-0,harry,matthews,205,ferguson circuit,,herberron,6722,vic,19690515,5231050 +rec-4835-dup-0,tristan,thonan,,solly place,leisure living vlge,booragul,3356,vic,19640221,9034172 +rec-3733-dup-0,jacobie,meaney,32,maitland street,norty arm,sandgate,2110,nsw,19820219,3123016 +rec-4220-dup-0,william,nguyen,52,tantangara street,anzachouse (cnr archer s street,kingsthorpe,2580,sa,19341203,9928610 +rec-3762-dup-0,kai,wilczke,83,oliver street,appleglen,toowoomba,7285,wa,19290502,1878744 +rec-4063-dup-0,aiden,roche,48,eppalock street,elmwodo,port lincoln,4573,wa,19400329,7028007 +rec-540-dup-0,mitchell,shepherd,341,richstreet,,balhannah,2077,nsw,19500430,8291804 +rec-3139-dup-0,caitlin,coxaon,144,evergood mclose,blue gum park,smithfield,3109,act,19160701,4213502 +rec-2343-dup-0,reegan,noble,4,kauper street,poplars,carlinxford,7173,vic,19501211,7621584 +rec-214-dup-0,elki,webb,33,max henry crescent,willow s trees,corio,2077,nsw,19711211,7999700 +rec-84-dup-0,georgr,de oar,30,gungurra crescent,black snake creek,exeter,2430,nsw,19051129,2671881 +rec-152-dup-0,lewis,portlok,11,english court,,burwood,2452,nsw,19240603,6036701 +rec-4726-dup-0,raquel,,11,windeyer street,kookaburra village,reveaby,2134,qld,19850128,1770895 +rec-3359-dup-0,dylan,needham,41,eucumbene drive,,carrara,2456,nsw,19750722,2780577 +rec-2751-dup-0,baeu,vincent,18,tryon street,springg rove,rosslynqpark,3174,nsw,,8217970 +rec-307-dup-0,macey,pasczoe,9,macrobertosnstreet,,highett,7320,nsw,19470710,5499383 +rec-2827-dup-0,mya,hoffman,757,cantor crescent,,kallista,5033,,19440312,2516740 +rec-3505-dup-0,charli,soden,37,stockdale street,,com,3028,nsw,19030206,7856242 +rec-2089-dup-0,william,white,33,downesb place,,normahnurst,3057,sa,19970306,9053801 +rec-4107-dup-0,br inlry,ho,6,vickers crescent,parks cottage,greenwith,2166,sa,19311119,9420562 +rec-174-dup-0,xanthe,rasic,16,anice-ohn,ivo whitton circuit,mulgrave east,2330,vic,19520527,5541516 +rec-1607-dup-0,sarah,lanyon,48,torrens street,boxwood hill,taree,2217,tas,19220722,6534862 +rec-4625-dup-0,joshau,seddon,1,murranji street,parkridge villa,slacks creek,2650,qld,19090214,3661114 +rec-2501-dup-0,emiily,haggett,788,tullaroop street,padgee,cooloongup,2640,nsw,19030519,7983751 +rec-1155-dup-0,jessica,mayer,25,dugan street,,nambour,6056,sa,19340201,3346974 +rec-1788-dup-0,,durbridge,64,macarthur avenue,little pddocks,albury,4680,nsw,19820308,4922810 +rec-2396-dup-0,christopher,menzies,39,,kinglake central,malzern,2621,nsw,19180721,8813225 +rec-1178-dup-0,rachel,dinnison,14,canopus crescent,,barrack heights,3221,act,19410510,5292435 +rec-2525-dup-0,vrin,excell,15,waller crescent,,,2359,qld,19460622,5466287 +rec-3348-dup-0,blake,milesm,147,traeger street,cabrini medic al centre,port noarlunga south,3130,nsw,19811230,6803144 +rec-3982-dup-0,grace,seib,24,landsborough street,rainbowdowns,como,2641,vic,19760603,8191813 +rec-1157-dup-0,,kubenk,35,araban asreet,carrington retrmnt vlge,revesby,2212,nsw,19901231,6501846 +rec-1707-dup-0,giorgia,smallacombe,10,dundas court,somerton aprk,glengarry,4106,sa,19990313,6652739 +rec-2069-dup-0,olivia,lackher,9,douglas splace,,dalby,6324,vic,19830328,9889496 +rec-383-dup-0,angus,tiller,1,,rosetta village,chelsea hieghts,3020,wa,19170409,8677579 +rec-4981-dup-0,matthew,gulliver,50,malcolm olace,,sefton,4817,nsw,19790129,2462951 +rec-2792-dup-0,anita,afflrd,19,andamookastreet,,lilydale,5631,,19391104,6863258 +rec-1779-dup-0,brooklyn,whitwg,362,o'loghlenstreet,mirrimbah,toowoomba south,2259,wa,19410904,7203795 +rec-4679-dup-0,christopher,calow,8,talbot srteet,cliffney park,waterloo,4173,qld,19820525,8644857 +rec-1420-dup-0,sam,grne,43,leita court,strathmore vineyard,geelony east,4350,nsw,19040618,1956745 +rec-2562-dup-0,katie,binns,50,,carranta,,3216,qld,19031119,1179767 +rec-4174-dup-0,shai,lock,20,arabanajstreet,kyeema vineyard,melville,6065,vic,19820129,9117058 +rec-2335-dup-0,lily,webb,274,conlon crescent,strathalancommunity,oakleigh,2050,vic,19920411,8994352 +rec-1214-dup-0,mitchell,matthews,21,kulgera s treet,the willows,north beach,4109,vic,19590701,8051712 +rec-4204-dup-0,joshua,webb,1,gundulu place,shire clerk,greenowod,2583,wa,,7883180 +rec-3711-dup-0,abii,hedaux,26,sparkes llose,will era,bribie island,5322,ss,19390824,1171524 +rec-1404-dup-0,reuben,clarke,284,rischbieth crescent,ocean pines caravn park,blakehurst,2304,nsw,19391117,3232193 +rec-4640-dup-0,,berry,276,cooranil,victoria street,bayswater,3166,nsw,19250620,3866668 +rec-1573-dup-0,dam,hage,1,woodlands surgery centre,sweet place,port macqyarie,3206,qld,19430116,1799750 +rec-222-dup-0,adele,shorrock,116,mack street,manor park,connollt,3149,nsw,19080107,1788372 +rec-1084-dup-0,sarah,ryan,19,grayson street,medical entre,beecroft,5343,nsw,19310314,7898665 +rec-1752-dup-0,,lombardi,6,quandong street,warialda,granivlle,5410,qld,19080313,1317582 +rec-3157-dup-0,malakai,palethorpe,23,boonal,marsden street,gaven,2340,nsw,19031029,5176770 +rec-4362-dup-0,macormack,wilkins,30,sextonstreet,raaf,buxton,4123,vic,19081026,4698984 +rec-943-dup-0,rosoe,karlsen,48,lowe court,cottonwood,redbank lains,3013,nsw,19041101,3233946 +rec-650-dup-0,luke,kennealy,30,moorehead place,sun valley caravan park,inglebirn,3749,wa,19070108,5173077 +rec-4578-dup-0,georgcia,bysord,,cann lcose,,boondall,7120,qld,19570724,5717956 +rec-2399-dup-0,kalli,houldsworh,23,fellows street,ardmona,claremont meadows,5041,nsw,19871214,9768941 +rec-4816-dup-0,williaim,tangallpalla,166,lachlan street,minnawarr zfarm,stanhope gardens,7008,nsw,19320616,9859566 +rec-3123-dup-0,jackson,carbone,133,mileham street,,carraqnballac,3139,qld,,6993200 +rec-4909-dup-0,harrison,reid,32,charterisville avenue,lissoy holdings,lowesdale,2282,qld,19301018,9267290 +rec-1971-dup-0,gredn,amelia,60,beasley street,silversand caravan park,charlestown,3199,vic,19160824,4340002 +rec-4868-dup-0,dreyer,flynn,148,haydenclose,hawkesbury natural health acupuncture ce,sanctuary point,3669,vic,19010221,7104329 +rec-1106-dup-0,emiioy,staude,215,leltaplace,yanalha,nowra,1479,nsw,19091124,2809085 +rec-165-dup-0,ryan,allsopp,25,warramoo crescent,shiloha,athetron,3796,qld,,5369163 +rec-598-dup-0,james,hebberman,26,phillis lace,twenty-third avenue p harmacy (cnr mawarr,ettalong,2326,vic,19760410,1748689 +rec-4390-dup-0,,mercorella,16,emery street,yarrambah,kununurra,2048,qld,19541031,6022838 +rec-4433-dup-0,lilyn,matthews,5,captain cook crescent,,matravplle,2774,vic,19420708,9637615 +rec-3541-dup-0,katelyn,goldsworthy,10,meyers place,tinnaroo falls,bnudamba,3127,qld,19880820,1519466 +rec-2564-dup-0,pino,shepherrd,55,warragamba avenue,pineview farm,sael,5698,vic,19100226,5952587 +rec-1321-dup-0,tyler,painter,74,michael holt crescent,,kangaroo flat,4858,nsw,19291017,6615450 +rec-1205-dup-0,holly,white,28,martens crescent,olui wen,aspley,3977,nsw,19281113,6507633 +rec-458-dup-0,blaw,cheers,217,rees place,,dalby,6021,qld,19751205,6719640 +rec-3489-dup-0,joel,morrison,5,meredith circuit,rawdon,greenwood,4011,qld,19597022,6153468 +rec-4850-dup-0,cooper,rovirq,19,maclaurin crescent,suunyrbae,broken hill,3414,qdl,19121113,8734370 +rec-3355-dup-0,lily,marris,28,deumongascourt,fouways,ulverstone,3048,nsw,19980524,4654900 +rec-342-dup-0,elli,noble,1,saggers close,tinaroo f alls,spearowod,6330,vic,19420501,9762210 +rec-441-dup-0,edson,william,,fitzhardinge crescent,windy gully,ashwood,3078,nsw,19530403,3148460 +rec-1161-dup-0,hansah,coleman,3,marchant circuit,southland ss hpcntr,hinchinbrook,2755,vic,19270425,7785677 +rec-2403-dup-0,,dunnicliff,79,banfield street,milton,,2116,vic,19130108,6220830 +rec-2381-dup-0,wasley,thomas,4,tantangar street,eden park,frankston,5086,wa,19830128,7062733 +rec-3952-dup-0,noah,herbert,13,beasley street,herber t creek,oak park,4280,sa,19431227,7049548 +rec-4378-dup-0,mia,koeman,20,wattle street,elston,willetton,4068,vic,19670212,2071975 +rec-610-dup-0,lachlan,rau,68,loxton place,montrose,dedearng,3377,wa,19260502,1638351 +rec-4853-dup-0,jacqueline,coady,20,borrowdale street,garden creek,little grove,4570,nsw,19220503,6945746 +rec-3526-dup-0,lilian,berry,578,goldstein c rdescent,berowra,maida vale,3109,vic,19030329,3427724 +rec-1113-dup-0,carmen,miles,146,mccormack street,palinq g south,monavale,2782,nsw,19220601,4126596 +rec-2336-dup-0,konstantinos,morrison,297,euree street,berkely vlge,farleigh,2099,nsw,,1191867 +rec-818-dup-0,holly,clarke,,macgregor street,,brighton-le-sands,2540,sa,19620404,2345058 +rec-2526-dup-0,seth,doody,54,bastow circuit,maranui,cowra,4129,vic,19711125,3842987 +rec-1796-dup-0,jake,george,22,springvale drive,inverwood,belmont,3350,wa,19200727,3265845 +rec-2029-dup-0,benjamin,cassimatis,23,,yacklin,thornleigh,6006,nsw,,6107392 +rec-4432-dup-0,isabella,salt,1,kingsmill street,town & country c aravn park,wyee,2156,wa,19850103,8443768 +rec-3887-dup-0,hafvey,wang,1,kosciusko avenue,rosedale,toowoonba,2594,vic,19531021,4095296 +rec-2417-dup-0,rourke,roets,78,grun er street,,kaleen,3227,,19690509,1455274 +rec-2824-dup-0,rilxey,nobxle,23,onkaparinga crescent,bellambi,cabarlah,3959,sa,19130706,1621751 +rec-1873-dup-0,gabritel,green,18,alroy circuit,birrabilla,surry hills,4585,nsw,19901018,6193075 +rec-1613-dup-0,connor,lowe,50,augustus close,corunna,west lakes shore,2017,nsw,19611015,1592036 +rec-3940-dup-0,tahlia,lowe,,antis street,millwood,stanwelo park,2452,nws,19150218,4957408 +rec-2476-dup-0,abey,simmonds,13,greenvale street,haven vourt,campbellfield,4069,qld,19141205,2403689 +rec-4187-dup-0,matiswe,mccaffrey,164,throssell street,argyle,woy w oy,6012,vic,19961123,3108714 +rec-1564-dup-0,madison,gren,67,atherton street,moorilla,bondi junction,2489,wa,19920222,1194102 +rec-4001-dup-0,dillon,nettleford,23,haskett place,glenbrae,emu plains,0822,wa,,6238993 +rec-776-dup-0,maddiosn,morrison,18,derringtoncrescent,janefield,gunbwoer,6308,nsw,19021108,5581067 +rec-2851-dup-0,chelsie,priest,99,companion crescent,ashbank,torquay,2325,vic,19691018,9141369 +rec-4639-dup-0,jamilla,mcdaid,29,barrett wtreet,,south melbourne,3166,qld,19301116,2784587 +rec-3060-dup-0,brokengshire,rosie,34,antill street,hse13,athelstone,2042,qld,19770815,3921318 +rec-3464-dup-0,webb,maggie,5,eucumbene drive,hawkins maosnic vlge,elwood,2265,nsw,19060830,3505267 +rec-1514-dup-0,kiana,pieris,33,,mungrum stud,hawthorn,4650,vic,19370813,5026429 +rec-2533-dup-0,jayden,hick,42,wisdom place,baroona,north motton,3350,sa,19861919,9522196 +rec-3400-dup-0,maddiason,newpptr,,bingle street,burrendong est,burwood east,4818,nsw,19590707,5640367 +rec-3922-dup-0,joshua,milalr,4,chowne street,lirambenda,springield,2088,qld,19410825,6371427 +rec-4613-dup-0,robin,swiggs,29,mcclellan d avenue,,preston,3170,qld,19051107,9180357 +rec-3396-dup-0,cain,synnet,17,langdon avenue,millard centre,leichhardt,2625,nsw,19881209,9321868 +rec-511-dup-0,grubb,olivia,16,boolee street,berkeley vlge,catalina,2823,nsw,19050616,8765826 +rec-1730-dup-0,kyle,straczek,1,hardwick crescent,the willows,blacktown,2100,vic,19160506,4656343 +rec-308-dup-0,michaerl,maynaryd,132,rogers street,leisure living vlge,pooraka,2144,nsw,19570508,3096389 +rec-924-dup-0,callum,teti,686,wheelwright crescent,,brighton,4018,wa,19260102,9064672 +rec-1832-dup-0,timothy,kinter,29,hawker street,argyle village,quilpie,2598,vic,19190926,7137952 +rec-3537-dup-0,joshua,leaver,30,nardoo crescent,diment otwers,st luca,2167,qld,19650306,7912588 +rec-4783-dup-0,tahlia,donaldson,59,badimara street,gibratlar,,3149,qld,19630202,1983061 +rec-4088-dup-0,phoebe,hage,,marchantcircuit,bracknegrae,mount graeatt,2119,sa,,8504441 +rec-3378-dup-0,webb,lukxas,2,nowra mall,freda gibpsnn circuit,kingston,2830,nsw,19120423,6570926 +rec-504-dup-0,balchin,reeve,12,hadleigh icrcuit,tam-beni,deer park,2318,sa,19100615,3829737 +rec-480-dup-0,luke,mcphie,20,wheadon street,beltunga,christsas creek,3796,nsw,19110123,8869942 +rec-4983-dup-0,juke,tu,5,holland street,manrdesa,ventnor,5039,qld,19571024,3333385 +rec-4418-dup-0,charlotte,scatgini,4,miller street,sunset,south melbourne,6011,nsw,19540114,4866579 +rec-15-dup-0,kye,brain,8,stillwell place,,bellambi,2320,nsw,19630812,8358959 +rec-4583-dup-0,lucas,daysh,11,bolger place,,andrews,4130,vic,19701026,7306086 +rec-1559-dup-0,jemima,belperio,12,strehlow place,rainbo w ridge,margaret river,4021,nsw,19281001,3997984 +rec-3625-dup-0,zachary,lowe,10,knox street,myliton,ulversyone,5604,wa,19690408,9556948 +rec-3849-dup-0,hague,georgia,5,leahy close,,mount warren park,3218,vic,,4151813 +rec-1253-dup-0,cambell,clarke,99,jardine street,alexander'sf olly,lower temsplestowe,2114,wa,19250326,2467909 +rec-20-dup-0,bfody,lowe,100,waller crescent,keaonr,armidale,4055,sa,19900409,8444970 +rec-4118-dup-0,matghew,clarke,101,brisbane avenue,billsblock,richadrson,3658,nsw,19450606,4699715 +rec-1039-dup-0,ethan,greenhalgh,,crozier circuit,richn o,rosebrook,4156,qld,19400702,4863653 +rec-4875-dup-0,annabelle,ebert,20,douglas place,glenhusrt,brooklyn,2307,wa,19440813,6811641 +rec-4420-dup-0,alexander,vitkunnas,17,catani place,kelindy ridge,kilhoy,2285,vic,19991216,6469394 +rec-444-dup-0,alana,zoanetti,19,gudgenby close,,birksale,2113,sa,19510214,1412351 +rec-2389-dup-0,courtney,wellerv,35,florence taylor street,flt 61,vermont,4352,vic,19910120,7615358 +rec-4208-dup-0,maya,bibby,40,monarocrescent,learning aerth farm,deer park,3184,qld,19720418,1185491 +rec-933-dup-0,alicia,mollross,72,mcnamara street,corobie,kuravy,4552,qld,19050908,7195535 +rec-2977-dup-0,fiona,crosfsman,487,brophy dtreet,,maryborough,4700,qld,19340301,9968811 +rec-4014-dup-0,white,felicity,24,carter crescent,mirreanda,geelong south,3892,sa,19480806,9575304 +rec-3067-dup-0,joshua,beaty,19,blackwood terrace,the summre house,prosplect,6163,vic,19721121,1725695 +rec-1242-dup-0,jasmyn,marceta,35,cabena court,ascot spark,ashfield,5011,wa,19821129,6095474 +rec-3773-dup-0,jessica,mckeroie,8,john close,rosewood garden,yarrawonga,3804,nsw,19810709,3600417 +rec-2495-dup-0,ella,malzardc,4,namatjirabdrive,tolemac,armidale,4220,nsw,19381112,6513848 +rec-3027-dup-0,danielle,modody,21,redlands,owen crescent,burwood east,4701,nsw,19850616,8727753 +rec-963-dup-0,clohagh,sibeer,14,pandanus tsreet,highfields medkcal centre,davistown,4066,nsw,19104913,2698880 +rec-2705-dup-0,holly,ryan,18,fallins palce,frm 654,safety bay,2074,qld,19310814,7222933 +rec-3198-dup-0,kristen,white,5,sherlockstreet,morayfield exchange,wangaratta,5082,wa,19761201,8300732 +rec-1266-dup-0,emiily,wallkey,4,barangaroo street,meadowvale village,quilpie,7030,wa,19190615,2871929 +rec-4582-dup-0,daniel,mcarda,34,maccallum circuit,westwood homestead,homuebush,2619,nsw,19920927,2550366 +rec-1115-dup-0,berry,isabelle,71,chipperfield circuit,yakatoon,clarinda,3194,qld,19010210,5294123 +rec-2352-dup-0,carlin,brooker,57,sturtaevnue,lakeview court,alice springs,3174,qld,19651223,4263375 +rec-2169-dup-0,jye,hewetson,46,jabanungga avenue,moorabee,bowen mountain,2148,vic,19500330,7093866 +rec-994-dup-0,carly,hoffamn,38,blair place,lynden lea,south melbourne,3995,qld,19521207,6762264 +rec-457-dup-0,thomas,mcauslan,14,trugani ni place,,bongaree,5064,nt,19801028,8944611 +rec-2422-dup-0,keziah,thind,111,tate street,un 1,kincumber,5043,nsw,19231013,5822993 +rec-101-dup-0,dillon,colenan,8,paul coe crescent,clinton caarvan park,yarraville,3260,nsw,19531117,1835941 +rec-2337-dup-0,sara,schiansky,40,fullerton crescent,tabbzgong,llandilo,3020,nsw,19450822,4913489 +rec-555-dup-0,harry,manthorpe,19,charteris crescent,the blackhut,macquarie fields,2756,nsw,19841905,7232794 +rec-999-dup-0,jacob,lowe,,parkhill street,brigalow court,arundel,2167,vic,19761225,8295931 +rec-3583-dup-0,isabella,bucyhhorn,,rosetta village,officer crescent,oaklands park,5034,vic,19930522,7645759 +rec-2330-dup-0,sebastian,mcneill,3,ferndale,dryandra street,west lakes,2265,vic,,2765960 +rec-2250-dup-0,cooper,humphreys,1,burnett street,villq 3,st albans,4413,nsw,19300226,7614633 +rec-937-dup-0,oliver,nettefeold,35,alphard dplace,fairlgiht,semaphore park,3802,vic,19570625,4691024 +rec-158-dup-0,abbey,,17,stark e street,,fadden,2286,vic,19150829,6050399 +rec-1998-dup-0,william,robson,77,springvale drive,magpie spings,lowood,4151,,19520721,2322463 +rec-4526-dup-0,emiily,brambld,7,collybur l rcescent,arcadia,stratford,5087,vic,19290305,1960201 +rec-1480-dup-0,owen,grezn,5,dryandrazstreet,bythorne,campbelltown,3175,vic,19160427,4013988 +rec-1462-dup-0,aleesha,rashley,26,wybalena grove,,baysqaer,3047,nsw,19500413,7372274 +rec-2106-dup-0,moly,hannagan,15,the verge,the stockyards,ballarat,6027,nsw,19241115,9178151 +rec-4842-dup-0,ainsley,shepherdson,16,jackie howeocrescent,huntawyle,moorooka,2261,nsw,19480630,3591742 +rec-228-dup-0,oliver,verner,29,mcnicollstreet,sunbuey,berlaa,3175,vic,19160819,7677004 +rec-303-dup-0,maria,dun,28,sheaffe xtreet,brookvale,midway point,2229,wa,19990308,2567879 +rec-1328-dup-0,emiily,hewson,10,,the links,mount ksa,5422,wa,19320504,6458398 +rec-3825-dup-0,rosie,whitr,2,snowden place,brambletye vinyard,black rock,0835,wa,19020405,4810152 +rec-2687-dup-0,oscar,chegwidden,12,terraawh,currong s treet,mount eliza,4823,vic,19981224,6135137 +rec-4902-dup-0,jarre,crouch,33,currong street,montrose,st james,7316,nsw,19180503,4588775 +rec-3921-dup-0,jessca,mason,27,garsia street,warhaven home,lower templestowe,2160,wa,19320216,1753787 +rec-2385-dup-0,charlotte,wilde,28,warwarick,diamond street,werrington,2220,qld,19001117,4847191 +rec-2996-dup-0,keegan,stubbs,30,sellwoom street,transvaal,westmeadows,4870,nsw,19650506,9736949 +rec-1156-dup-0,jackon,simmonds,4,raymonad street,ainslie house,tongala,2164,nsw,19020519,8651617 +rec-2573-dup-0,thomas,edis,61,kellick place,f lt h0,bateman,3782,nsw,19890830,6857124 +rec-2297-dup-0,thomas,rankine,7,davis street,veonec,bossley park,2127,vic,19280703,6882558 +rec-1051-dup-0,timothy,modystacuh,32,julia flynn avenue,rcg cnetre,charlestown,4655,vic,19671125,2430632 +rec-2496-dup-0,,whishaw,25,roseberyhill,ashcroft crescent,vaucluse,4607,nsw,19070127,3381395 +rec-2640-dup-0,ljosbtad,jackson,2,hensman s treet,,berwick,5422,nsw,19640817,9825573 +rec-905-dup-0,jemima,apaty,79,,unfzan,dandenong north,3000,sa,19830719,6617205 +rec-1879-dup-0,jacob,kapeller,5,mountvernog drive,noelurma,toowoomba,2216,vic,19361129,5761018 +rec-4717-dup-0,georgia,demetriou,17,canberra avenue,,ballina,3871,nsw,19200828,1391870 +rec-4247-dup-0,dylan,la ndau,14,togo place,wattandee,whalan,4310,nsw,19500525,3431616 +rec-738-dup-0,charles,hurkett,77,pocket avenue,craigview grove,rowvikle,3223,sa,19841222,9205765 +rec-3111-dup-0,bianca,bishop,,crozier circuit,linton,wolvi,4812,nsw,19761209,6772943 +rec-2878-dup-0,jacob,badalsssi,7,patey street,summer hill,surfers paradise,4035,nsw,19171217,7615199 +rec-2433-dup-0,brus,joselnyn,21,,,murray bridge,2090,tas,19020520,6801064 +rec-410-dup-0,makayla,thredgold,29,chillagoestreet,west road,campbellfield,5107,nsw,19530218,5691229 +rec-17-dup-0,kobe,dixon,146,longman street,fernlea,rosebud,3315,nsw,19960927,7060978 +rec-1622-dup-0,,menzes,120,archibald street,krismark,belmont,2287,nsq,19871019,8064929 +rec-3692-dup-0,miranda,bery,5,shirra close,,connooly,4814,nsw,19300619,6070746 +rec-3691-dup-0,tara,pratap,15,wattle street,cantlay farm,aspley,2527,wa,19301128,2834693 +rec-3687-dup-0,may,ryan,87,medley strneet,glen cho,westmead,2500,nsw,19360504,5518965 +rec-1816-dup-0,,noyce,5,rosellastreet,rowethorpe,,2540,wa,19660091,2277894 +rec-2603-dup-0,nikita,leditchke,86,sidaways treet,parkdalel odge,mirrabooka,2031,vic,19510630,1387001 +rec-47-dup-0,finn,whit e,403,mcculloch street,all saints college,kempsey,6084,qld,19450410,9601625 +rec-2976-dup-0,zachary,lock,,tazewell circuit,henry kendall hostel,chiltern,2193,ndw,19600128,4768273 +rec-2138-dup-0,daniel,dreckow,39,govettplace,gogulge r stock,preston,6210,vic,19510111,3162776 +rec-3601-dup-0,aleaxndra,newberry,69,earle lace,broome vacatin village,wallsend,3749,nsw,19691006,5799594 +rec-1808-dup-0,gemaley,covino,158,naismith p lace,,paddignton,4551,qdl,19060725,6706561 +rec-1488-dup-0,daniel,wojciechowski,141,somerset street,melody coytage,dulwichhill,2120,nsw,19500125,2930336 +rec-2103-dup-0,jajie,hofmfan,592,dalrymple s treet,carrangarra,vauclyse,4356,naw,,4392122 +rec-4059-dup-0,gabrielle,toseland,3,lethbridge court,pinkerton dcircuit,campbellfield,2590,qld,19200414,6631971 +rec-2559-dup-0,binns,emiilzy,24,howell place,sec 142 hd rounsevell,ryde,2627,wa,19941108,8919080 +rec-3909-dup-0,ruby,vincent,1,gawler cerscent,knmre street,graceville,3585,nsw,19700602,6532162 +rec-4884-dup-0,georgia,coffey,41,disneycourt,siesta caravn park,coonabarabran,2428,act,19960110,9287951 +rec-4800-dup-0,jordan,tons,20,lachlan sreet,belgrave arcade,plainby,2620,nsw,19760913,3320758 +rec-3947-dup-0,mitchell,trowse,22,boolee street,john flynn medical centre,malvern,4350,vic,19640225,4579159 +rec-2531-dup-0,nguyen,isavel,8,mccawley street,jarkhellms,campbelltown,2122,vic,19860530,3659521 +rec-2588-dup-0,thomas,tsonis,33,de little ircuit,arndilly,rey,5024,sa,19130119,9807073 +rec-4702-dup-0,jamie,paterson,,lindrum crescent,fairlane estate,wangaratta,3014,wa,19860221,5336409 +rec-4615-dup-0,kalli,froscio,23,fergusson drescent,wirruna,manyama,6530,wa,19680403,3617186 +rec-38-dup-0,aiden,thorpe,51,chauvel circle,eureka,rowville,2767,nsw,19270407,6959840 +rec-1301-dup-0,mansk ey,john,90,mckinley cipcuit,,plympton south,5108,vic,19071112,2774041 +rec-4318-dup-0,timothy,mathews,2,blandon place,harrowvsle,mill park,3184,nsw,19560930,6083907 +rec-2834-dup-0,jasmine,mcmurdo,195,manna close,killarney,baynton,7009,vic,19340207,7978445 +rec-3807-dup-0,isabellaf,ryna,81,ackland place,philip centre,kirwa,4173,qld,19940808,6364020 +rec-1280-dup-0,francesco,canhell,5,ngunawa ldrive,whisperni g pines,brighton,7320,nsw,19900219,2439499 +rec-1959-dup-0,jorja,selth,5,arnold place,wooloondoolfarm,colonel light gardens,4350,nsw,19460602,5599958 +rec-1335-dup-0,indiana,jeffries,24,carrodusdstreet,clarkwood,cremorne,2615,msw,19790628,5993849 +rec-4972-dup-0,zoe,paterson,8,chauncy crescent,heritage est,blayney,6602,qld,19930912,2580670 +rec-372-dup-0,lachlan,pascoe,,ballumbvir street,inishmore,toowong,2766,vic,19470107,1606779 +rec-3308-dup-0,jaregd,white,57,walsh place,dunmunkle lodge,evans head,3124,wa,,8491221 +rec-3423-dup-0,,nguyen,8,wardill close,st francuis vlge,sunshine beach,3174,vic,19461016,4768225 +rec-2986-dup-0,thoma s,santi,138,krichaufd street,rose-elea,port pirie,3976,vic,19590808,5694951 +rec-543-dup-0,eliza,mason,33,schonell circuit,john flynn medical centre,mount warren park,2093,sa,19271018,5422520 +rec-3998-dup-0,annabelle,webbh,105,eyre street,alcarnaa,turner,4157,nsw,19020930,2019510 +rec-1104-dup-0,andrew,berry,70,galibal street,blue have n village,ascot,5606,sa,19540522,4799173 +rec-526-dup-0,bailee,ryan,33,edgar tsreet,little pines,milperra,5680,wa,19410207,7905025 +rec-4087-dup-0,joshu,hoyland,36,hemmings crescent,solitaire,mount eliza,0828,wa,19090810,7921703 +rec-4935-dup-0,mikyla,broadhead,44,sewell place,golde n own,waterloo corner,3123,qld,19571018,8632021 +rec-805-dup-0,madison,hawejs,132,vasey crescent,canberra hse,kellyville,3194,nsw,19360628,2097590 +rec-4147-dup-0,bethany,godfrey,3,culleb street,sunning,narellan vale,3603,qld,19330508,4827546 +rec-102-dup-0,elli,sindorff,15,lansell circuit,palestine,yagoona,2148,sa,19671114,5791840 +rec-3106-dup-0,finn,kazmiir,472,belconnen way,,mackay north,2502,sa,19880315,6526812 +rec-3591-dup-0,markellos,kiarnee,21,la perouse street,fairholme,toora k,3121,sa,19620130,4234492 +rec-205-dup-0,isabella,crimes,5,newbu place,gracemece grdns,cecil hills,5351,viv,,2238755 +rec-3145-dup-0,talia,holer,1,dennis street,,ashfheld,2287,qld,19840907,3019342 +rec-2147-dup-0,jackson,spanton,108,sargeantnplace,waioma,race viww,4500,qld,19680828,1159113 +rec-975-dup-0,damien,clarke,18,brimage place,airforce memorial estate,mentone,2115,nsw,19721023,2631407 +rec-1705-dup-0,alessia,smithson,,shandon place,amarillo,boorowa,6002,vic,19421105,6639770 +rec-1149-dup-0,sebasitan,campbell,34,atherton street,glen-fale,north sydney,4350,nsw,19660715,8686683 +rec-955-dup-0,william,gohl,378,charlton street,toomba,kellyville,3028,vic,19030711,1291827 +rec-4454-dup-0,damien,garnett,9,narrabundah lane,laur e,penola,6168,nsw,19900710,2711549 +rec-4503-dup-0,jaek,campbell,67,larcombe crescent,oaklands village,greensborough,4570,wa,19240304,4245106 +rec-2177-dup-0,mcvilly,georgia,34,gardiner sktreet,cadogan,bayview heights,4370,nsw,19830221,2711924 +rec-3923-dup-0,kaitlin,egan,43,haywardlplace,glentryst,geraldton,2074,vci,19410610,3120103 +rec-842-dup-0,talia,wotton,211,burn street,gillin park,seymour,0821,nsw,19781119,8432542 +rec-2167-dup-0,sarah,campbell,6,loddon street,,miasmi,3227,qld,19321221,5872484 +rec-4306-dup-0,levi,hunting,203,eureesyreet,northern tablelands tennis academy,condell park,4207,wa,19580418,7383570 +rec-4000-dup-0,jasper,,6,mirroolstreet,bristin,mosman,2745,nsw,19640228,1807750 +rec-1974-dup-0,natasha,clarke,63,mallanganee,tasmania circle,whitemore,2840,sa,19710223,5969104 +rec-2912-dup-0,curihual,blakeston,35,wheadon street,kyree,broadmeadows,3138,vic,,9241622 +rec-4797-dup-0,matthew,lock,14,shoalhaven avenue,nootina,ringowod,2207,sa,19931125,3915530 +rec-1679-dup-0,lachlan,plumb,14,garling street,brentwood vlge,julatten,4217,nsw,19550313,2243015 +rec-988-dup-0,jack,andvrae,7,clelandojstreet,mundine30 km,cherrybrook,6025,vic,19260626,3267222 +rec-652-dup-0,dylan,nickolai,46,jackie howe crescent,bonnie doon,waramanga,2535,nsw,19510622,6519452 +rec-884-dup-0,riley,loehr,370,caldwell street,springdale,maitland,4680,tas,19000723,4599665 +rec-2546-dup-0,genevieve,ronan,37,mokare street,,yunderup,2657,sa,19980924,9571750 +rec-151-dup-0,arabella,reid,35,baracchicrescent,argyle,hermit park,3806,qld,19640323,1433160 +rec-4448-dup-0,harrison,whibte,58,morant circuit,,highton,4118,qld,19310706,6806350 +rec-4751-dup-0,reani,quilliam,8,newman morris circuit,black snake creek,geurie,3121,nsw,19220309,8176103 +rec-375-dup-0,elise,miles,63,oliverstreet,rosettavillage,byford,4670,nsw,,1613758 +rec-1128-dup-0,alissa,yelds,2,bingley crescent,woodlands house,leeton,3012,sa,19881106,8003824 +rec-2014-dup-0,jared,coleman,37,cumpston p lace,heatherdale,kingston,3130,nsw,19280705,2238622 +rec-1913-dup-0,lioam,george,5,lindrum crescent,retirement village,hoppers crossing,3030,vic,19060325,3435395 +rec-3370-dup-0,nicholas,malin,17,hearn street,mia in,acton,5166,nsw,19700121,6007254 +rec-4216-dup-0,lauren,harrington,28,leibnitzplace,rosetta village,newcastle,6066,vic,19550719,2207203 +rec-164-dup-0,ruby,jesser,37,boult plcae,catumbel oodge,broadbeach waters,6203,nsw,19680506,3452449 +rec-875-dup-0,danielle,tomasevic,,frohda,amangu street,kedron,2380,nsw,19270622,9306292 +rec-453-dup-0,edward,denholm,10,corin place,goldt yne,clayfield,4221,vic,19130629,7119771 +rec-753-dup-0,micah,monis,38,lefroy street,,yass,3088,nsw,19970605,3265234 +rec-1696-dup-0,kydan,edson,1714,lexcen avenue,wirraway,tuart hill,2519,vic,19581231,6695038 +rec-4970-dup-0,ethan,muthukuda,25,,glen aern,hililsice,2250,vic,19581107,4421577 +rec-340-dup-0,kyle,rawlings,22,henty street,don ray,moruya,4870,vic,19810122,9723395 +rec-284-dup-0,jaslyn,jonjic,1,lindrum crescent,,ascot park,4213,vic,19250102,1023721 +rec-3872-dup-0,hahnah,slape,20,french street,beulah estate,,3065,qld,19800920,1061185 +rec-90-dup-0,barnaby,godfrey,18,hopegood place,ostesr,brighton,5086,nsw,19461029,9137216 +rec-1177-dup-0,taylor,green,30,jay place,little tinana,cremorne,3564,wa,19461212,1468008 +rec-3215-dup-0,nikita,green,4,greenough circuit,glenmarla drmb 2563,elizabeth south,2504,nsw,19941002,8531091 +rec-1966-dup-0,cenatempo,archer,15,chauncy crescent,kildrummie,armiale,3616,sa,19060824,1111899 +rec-2424-dup-0,sma,reeh,275,forbes street,,alligator creek,2167,wa,19060718,3497084 +rec-2523-dup-0,tyler,edgecombe,,willoughbh crescent,,bray park,2324,vic,19551113,8936270 +rec-4733-dup-0,husey,benedict,,erldunda c ircuit,barwon s tation,tingalpa,3056,qld,19060127,5070016 +rec-1293-dup-0,stronach,ethan,555,hodgkinsong street,,dapto,3199,tas,19830423,4516064 +rec-3655-dup-0,samantha,paterson,8,kelli ckfplace,berri cottage hmes,belrose,6030,tas,19460814,7611475 +rec-1443-dup-0,harrison,schuster,21,boldrewood street,brambletye vinyard,portmacquarie,4069,vic,19851117,4249919 +rec-1436-dup-0,joel,waller,12,quiros atreet,marella,bowral,4670,vic,19740716,8352619 +rec-4031-dup-0,karissa,cannell,30,arrietta close,pindaramedical centre,harris park,3153,nsw,19600508,7035862 +rec-3569-dup-0,madeleine,white,50,hunter street,universityhsores,marlow lagoon,2500,sa,19401228,6386791 +rec-736-dup-0,christopher,chammne,8,crisp ci rcuit,,croydon north,3126,wa,19030403,4266096 +rec-1895-dup-0,prytula,tabitha,2,totterdell street,rsde 817qallace,nabawa,4017,sa,19930102,4076797 +rec-3700-dup-0,steven,pokkias,407,may maxwell crescent,ardonachie,dalveen,5046,wa,19350305,2928326 +rec-3033-dup-0,benjamin,rankine,34,anstey street,forest hi lls,broome,3140,nsw,19120704,2412111 +rec-3379-dup-0,jack,rudd,4,limestone avenue,orcadia park,hoppers crossing,5007,nsw,19086018,3984278 +rec-1365-dup-0,kane,tiller,19,verbrugghem street,karana hojestead,,2122,vic,19680109,4091125 +rec-706-dup-0,talis,dhara,14,kirkham place,,bidwill,4160,wa,19700715,9048094 +rec-3287-dup-0,william,white,331,stanburo close,,hawthorn,5092,wa,19120603,6104386 +rec-2537-dup-0,isabe lla,weaver,,adair s treet,,charldstown,2229,nsw,19100327,6483602 +rec-2383-dup-0,will,carmody,7,waugh close,knoa,elwood,2067,vic,19540605,5434473 +rec-2707-dup-0,michatel,berry,177,canberra avenue,teleon,east melbourne,2259,qld,19110224,5076815 +rec-799-dup-0,jack,gren,,macalpine close,emu downs,aspley,6014,wa,19350317,4402882 +rec-2840-dup-0,marianne,kastrappis,,hansen circuit,hotell aguna,wentworth falls,3175,vic,19490106,2934534 +rec-1351-dup-0,nicholas,joly,8,jansz crescent,rosehill,burnsice,0872,nsw,19011217,7662074 +rec-2065-dup-0,shana,mavrangelos,3,,,surrey hills,4655,sa,19860504,3793509 +rec-765-dup-0,harriet,tamassy,148,academy close,doribank,wunghnu,2680,wa,19350531,3455124 +rec-4416-dup-0,ben,nguyen,17,doherty pplace,centenary marketplace,bayview neights,2049,nt,19731201,1783041 +rec-3333-dup-0,cooper,fitzpatrick,46,owen dixon drive,,collie,2525,nsw,19870622,1736085 +rec-2001-dup-0,antonio,hagwe,34,grigsnplace,warrawong,tinamba,3636,nsw,19330331,8499345 +rec-4232-dup-0,zali,shadbllt,56,tillyardb drive,,brown hill,4890,wa,19440205,7276255 +rec-1103-dup-0,,grierson,326,,sect 106,mcmahons point,6362,tas,19181212,4107638 +rec-600-dup-0,john,,55,meriden wallaroo road,ivydale (rsd 1820),empire bay,5063,wa,19380716,1321103 +rec-2209-dup-0,georgia,hantke,2051,hovea dtreet,,cromer,3199,vic,19260708,1055098 +rec-18-dup-0,riley,kerr-sullivan,166,clem hill street,mindaree,oyster bay,7325,nsw,19991104,7355856 +rec-2161-dup-0,connor,no,62,barunga street,jim holm hostel,ingleburn,6618,sa,19171023,4958150 +rec-3488-dup-0,emiily,mchnery,1,hurwooplace,paramatta park,leeton,2228,nsw,19550504,1357509 +rec-218-dup-0,jade,browne,407,sabine close,brentwoidvlge,leichhardt,4708,vic,19810923,8107465 +rec-4555-dup-0,caleb,,53,banksia street,rosevillea,rye,4740,act,19490425,8230410 +rec-4936-dup-0,dean,lock,16,bunduluk crescent,wylarah,campsie,4031,sa,19150408,4029960 +rec-465-dup-0,hanmah,gluc,63,noblec lose,,kolodong,4352,vic,19760710,6057103 +rec-1-dup-0,isabella,everett,25,pike mlace,rowethorpe,marsden,2152,nsw,19110816,6653129 +rec-4481-dup-0,,dantiochia,,wiburd street,solander centre,como,4035,nsw,19221020,6629558 +rec-3439-dup-0,zack,novak,2,burara crescent,poppad owns,,4311,sa,19591026,2536498 +rec-4889-dup-0,hugh,deblasio,,totterdellqstreet,mariner views,west perth,4814,nsw,19280627,8578252 +rec-348-dup-0,leah,clarke,2,iterra place,,new farm,4109,vic,19650213,9701309 +rec-2895-dup-0,kimberly,kelley,59,harwood court,aprt 18 the village,emerald,3127,qld,19560627,3990210 +rec-4246-dup-0,tyler,nguyen,11,hoddinott sltreet,bridgefoot down,bullsbrook,2002,nsw,19030702,2003210 +rec-2146-dup-0,luke,barisica,4,macarth u rplace,kurrajong,windsor,5365,nsw,19510612,6325283 +rec-1738-dup-0,rebekh,whitters,55,mcginness street,bay cit y hplaza,ganmain,2076,nsw,19360902,9026077 +rec-4509-dup-0,,tiller,12,colebatchplace,brentwood vlge,jesmond,3163,vic,19280518,3425576 +rec-1061-dup-0,pia,chell,81,bayley street,youralla,,2614,qld,19400227,4770120 +rec-1963-dup-0,rebekah,green,14,laker crescent,,whittinhgam,2166,wa,19920111,4383145 +rec-2776-dup-0,abby,ryan,10,paul coeacrescent,kooyong,carlingford,3144,vic,19670119,9471831 +rec-2071-dup-0,lauren,voskulen,8,mccubbingstreet,inveraray,toorak,2600,nsw,19540407,6075780 +rec-4630-dup-0,max,clarke,36,playfair place,kanga park,parramatta,5608,vic,19360102,5709157 +rec-482-dup-0,white,wilson,22,bellinger crcuit,brentwood vlge,carine,5504,qld,19330625,7471491 +rec-4173-dup-0,fenwick,mi,8,dunstanstreet,vinder lodge,keilor east,2441,qld,19240220,7504708 +rec-2030-dup-0,whoe,chloe,7,myall street,yallanbee,north maclean,2016,vic,19830207,7105783 +rec-1204-dup-0,indiana,campbell,6,linger place,oakdene,,5069,wa,19430315,7787158 +rec-2928-dup-0,harriet,doogue,4,concept,mugga lne,matraville,3194,qld,19091014,4166027 +rec-1915-dup-0,shawn,boothroyd,19,melrose drive,,oak park,2166,sa,19700418,8329531 +rec-4812-dup-0,anthony,roche,11,waller ceescent,gungarlin,st andrews,3103,act,19930109,7209435 +rec-881-dup-0,talia,berrey,24,nemarangcrescent,,nollamara,3707,vic,19690713,1239638 +rec-1797-dup-0,jessica,regalcado,,,edge hizll,devonport,6076,qld,19441202,2223697 +rec-1993-dup-0,taliaw,collinson,20,oliver street,,paraburdoo,3197,nsw,19320209,1496537 +rec-3945-dup-0,elie,reid,35,nemarang crescent,brandywines tud,jarra creek,4051,wa,19090612,3825290 +rec-2608-dup-0,shane,groenveld,733,herschell circuit,cold higham,rowville,3016,nsw,19770716,8547078 +rec-500-dup-0,sonja,clarke,7,carrington street,,coolaroo,6317,vic,19750513,4512800 +rec-4131-dup-0,jessica,webb,81,bimberi crescent,chevioth ills,wanniassa,5073,qld,19250410,9559799 +rec-1098-dup-0,jacob,bradsha,30,tipiloura street,lansdowne,burringbar,2622,nsw,19380406,1735204 +rec-3827-dup-0,warrick,farragher,1,,dental 3 garden ctiy shopping centre,rose bay,3175,nsw,19920222,6909540 +rec-1701-dup-0,georgwa,laria,16,oxley street,townv iew,allambie,5127,qld,19170818,2152599 +rec-220-dup-0,gabrielle,finlay,14,lipman street,willowcrnest,park holme,2680,vic,19880609,2407770 +rec-691-dup-0,kalli,detnzer,23,florence taylr street,lumeah hosmes,rowville,4306,qld,19440320,3527872 +rec-1180-dup-0,carly,herbert,9,strathalan homes,darwinia terrace,,2221,vic,19561119,6065655 +rec-142-dup-0,emiily,jeffreis,39,oxley street,paddy,blair athol,4051,wa,19250402,9596327 +rec-3334-dup-0,keely,demarco,56,serpentioe estreet,,mona vale,5113,wa,19910622,2184846 +rec-2053-dup-0,flytnn,fitzpagrick,19,burns xircuit,the willows,tuggerah,3033,vic,19540125,1010947 +rec-57-dup-0,erin,fedst,23,brentnallz place,blacklea d farm,atherton,4650,nsw,19181028,1261908 +rec-2272-dup-0,slack-smith,katelyn,5,mugga way,bundong,marrara,3505,nsw,19990408,3255344 +rec-646-dup-0,holy,patersoen,1,collier p ark vlge,biffin street,kogarah,2360,qld,19620830,7769159 +rec-4419-dup-0,jessica,mac nell,13,neeld place,bessy sue,sheffield,3124,atc,19160213,7779746 +rec-1144-dup-0,joel,shephrdson,515,elvire place,glanworth station,mayfield,2000,vic,19250903,9617566 +rec-4236-dup-0,bailee,berryman,7,jarrah street,bishops creek,stanhope,4053,as,19780405,1761772 +rec-2747-dup-0,joshua,trait,94,batchelor street,kurrajong,mirboo north,2259,sa,19161010,9285169 +rec-3717-dup-0,tyler,siviour,1,ina gregor circuit,oivi,blakeview,3630,qld,19030131,6849934 +rec-79-dup-0,joel,runnle,108,reveley crescent,st vincents hospital,dunsboorugh,2317,nsw,19780403,8984765 +rec-3830-dup-0,nathan,samuniuk,53,forest dale,burkitt street,hindmarsh west,5540,nsw,19831213,3693831 +rec-1337-dup-0,,sztollc,29,berrigan crescent,,rivett,3094,qld,19481217,6141781 +rec-180-dup-0,thomas,white,42,cochrane rcescent,balmoralgarden,sefthn,3136,qld,19800413,1153372 +rec-115-dup-0,gabrielle,mailp,77,rich atreet,boonoo soonoo,rokeby,5271,sa,19561107,9010254 +rec-839-dup-0,teegan,gaskin,10,maclagaja street,the lojdge,spearwood,2765,nsw,,8091072 +rec-301-dup-0,benjamin,campbell,2,cockburn place,kangaroo gnd,banyo,2605,nsw,19180920,2472793 +rec-2436-dup-0,mitchell,crofuch,5,hurtle avenue,lucerne park,telanga tuk,4812,qod,19130817,9172315 +rec-4699-dup-0,daniella,chandler,1226,lewin wtreet,the willows,robertson,4173,vic,,3790237 +rec-3134-dup-0,erin,embrey,85,arabana s treet,caloundra family medic al practice trinit,caves beach,4000,nsw,19990704,7556655 +rec-2521-dup-0,bailey,ryan,94,parker street,envirdona,nowra,6042,vic,19361224,2466735 +rec-1319-dup-0,tuscany,yen,138,sage close,woolomoolan,mundingburra,3174,nsw,19011205,1974035 +rec-2718-dup-0,jye,feleppa,72,,bowtells caravn park,carrara,3630,,19691127,9051864 +rec-2264-dup-0,madeline,volpato,7,elliott street,lakeview park,glenhzaven,6442,vic,19341126,1203476 +rec-3119-dup-0,alice,wynne,3,st john crescent,civic cenire,robina,3971,vic,19220112,1785202 +rec-3810-dup-0,kallgi,,187,getting crescent,koah lodge,newrybar,4301,vic,19031202,2486956 +rec-607-dup-0,jessica,vogiatzi,34,kinsella street,,connolly,2800,vic,19610619,7088980 +rec-446-dup-0,callum,everkett,19,grayson street,logan central plaza,willetton,2621,sa,19840331,2551623 +rec-3961-dup-0,emma,thorpe,60,sharwood crescent,wyuna,warriewood,4510,vic,19211218,3966976 +rec-4561-dup-0,rebekah,mccracken,923,henningplace,john flynn hospital,dandenong north,5356,nsw,19170824,9290031 +rec-591-dup-0,sarah,brgels,23,torrensxs treet,,tarrag indi,2747,vic,19521019,8447931 +rec-3227-dup-0,niamh,kingsley,36,badimara street,warrowitue,eastwbood,2220,vic,19060707,5893180 +rec-1541-dup-0,jessica,paine,58,eddisonv place,pine hut,new farm,2022,vic,19661210,8315488 +rec-3677-dup-0,madison,maruos,42,crouch place,heights estate,junee,2444,nsw,19030404,7501014 +rec-3352-dup-0,kylie,webb,1,gard poace,,findon,3156,nsw,19860814,5234286 +rec-728-dup-0,olivia,iacopeyta,45,arnot place,windellama est,point turton,4565,qld,19740702,5166554 +rec-3263-dup-0,jacob,weaeer,27,fergusonfcircuit,braeburn,hoppers crossing,6062,nsw,19231001,4297631 +rec-2901-dup-0,harrson,laihg,158,bunburryjstreet,brightling park,wamberal,2086,wa,19620510,1807525 +rec-2128-dup-0,flynn,glopster,2,davies place,canowindra,andergrove,2519,nsw,19570911,5757208 +rec-4307-dup-0,claudia,bihar,33,arabana street,belandean,mod,5025,qld,19150406,8874107 +rec-2188-dup-0,ella,egliinton,03,alexander mackie circuit,treetops,frankston,2450,nsw,19630129,1794441 +rec-4994-dup-0,,mercoreola,14,couchman crescent,springfielsd farms,taringa,4501,vic,19520708,9804598 +rec-2841-dup-0,sideris,madeleine,6,ferry place,brunton,glendsle,4670,nsw,19851113,4355459 +rec-979-dup-0,jed,stanley,69,fisken c rescent,hawkhurst cottage,ermington,2090,nsw,,5004344 +rec-105-dup-0,breony,webb,168,lewis luxton avenue,court units,duncraig,4216,nsw,19680529,8214196 +rec-4197-dup-0,talan,stubbs,21,binns street,ashell,croydon north,3032,wa,19221022,7550622 +rec-2011-dup-0,ruby,grobler,128,lonsdale srteet,tallinga park,newbridge,2105,nsw,19190104,5332690 +rec-4395-dup-0,jessica,andretzke,14,chowne street,stfrancis village,lilydale,3134,qld,19340225,6331022 +rec-4303-dup-0,alessadra,stanley,9,araluen stteet,bombow lee,beaudesert,3104,qld,19940325,8650329 +rec-4077-dup-0,julinaa,matthrws,1261,lamingtonj street,mount pztrick,cherrybrook,2227,vic,19030123,9544022 +rec-1406-dup-0,brett,beauman,5,stockdale street,promenadie arcade,sheffield,2358,vic,19170420,4623290 +rec-3298-dup-0,alessia,krajnc,30,fergusson crescent,kalga,shorewell park,5044,nsw,19421102,4012486 +rec-2579-dup-0,madaoyn,mccarthy,53,lind close,tressing ifelds,beenlegigh,2219,qld,19620612,6626116 +rec-1757-dup-0,ruby,nguyen,131,berghofer court,wealdstone,lilydale,3934,vic,19660122,1868976 +rec-4436-dup-0,pia,aba,16,tarden t street,,clifton springs,6100,tas,19030803,9804900 +rec-286-dup-0,kiara,drechslerj,2,shackleton circuit,glenvi ew,bulimba,4064,tas,19590816,5052016 +rec-3536-dup-0,jade,clutternuck,142,chipperfielod circuit,westcourt,bundamba,6050,sa,19151030,3828291 +rec-1100-dup-0,bailey,garcia,2,archibald street,kimberley,swan view,3071,act,19351102,2638117 +rec-495-dup-0,madion,renfrey,7,mcdougal l street,pine hill,barwon heads,6001,vic,19070611,5700724 +rec-3845-dup-0,claire,hutcheson,13,tunney crescent,rmbh 8 84,muchea,4510,qld,19640626,8325756 +rec-2732-dup-0,garcia,sebastian,24,cockcroft avenue,,blacktown,4077,sa,19640925,2452041 +rec-3375-dup-0,jayden,rees,480,beaufort retreat,ramano estate locn 1,black rock,5253,qld,19350102,8170572 +rec-2630-dup-0,nicholas,mamarika,15,allambe street,koonawarra mreino stud,wantirna,2533,vic,19840311,4175032 +rec-1598-dup-0,riley,nevolvle,51,irvine street,the canberra hospital,lockhart,3127,qld,19430319,3568574 +rec-627-dup-0,,orchad,84,smal l loace,jalbarragup h omestead,glen eden,3075,qld,19181128,5132162 +rec-506-dup-0,madeline,hage,15,banner street,oredl,bayswater,4860,nsw,19640929,6710911 +rec-4213-dup-0,charlotte,,64,elvire olace,mt pleasant,port macpquarie,2210,tas,19182115,3647256 +rec-2587-dup-0,tori,reid,16,arthur circle,nowramall,lalor,2176,vic,19570425,5350892 +rec-2411-dup-0,thomas,kullmann,79,delorainestreet,strasus,park holme,5009,vic,19120424,9266755 +rec-2658-dup-0,flynn,rosato,25,la perousw street,cowal,east msitland,7410,wa,19160718,6064519 +rec-1556-dup-0,kayden,hochuli,15,william webb drive,,wangaratta,2292,nsw,19891108,2978402 +rec-1540-dup-0,isabelle,thorpe,20,rischbieth crescent,north stra resort,ross creek,2444,nsw,19720731,6747384 +rec-2527-dup-0,ryleh,milesg,7,yarra street,annecy park,carlingford,3616,nsw,19850930,8262494 +rec-836-dup-0,breony,aujard,166,barada crscent,clear creek,flinder stpark,3151,vic,19870124,4700161 +rec-1812-dup-0,hoie,aurro,1,pinkerton circuit,brentwood village,miaim,3030,vic,19561122,7478672 +rec-3191-dup-0,kyle,campbell,56,traeger street,bowen palms caravan park,beenleigh,3424,vic,19230828,5010535 +rec-1586-dup-0,phoenix,pinzon,205,hawker syreet,scottish masonic village,carina yeights,6062,wa,19290505,1130499 +rec-2328-dup-0,taar,negrin,493,,unmnea,leppington,5251,vic,19381130,4747156 +rec-2885-dup-0,max,mayer,36,braeburn,riley hcfose,wynhdqm,6056,vic,19350817,7515435 +rec-4035-dup-0,chooe,worm,6,brentnal place,donna valley,karloo,3128,nsw,19000814,9383057 +rec-4449-dup-0,olivia,boyle,37,chauncycrescent,cygnet river schoolhouse,plumpton,2460,nsw,19581017,8738461 +rec-4992-dup-0,caleb,kwistek,16,gatty street,villa 2,castle cove,4220,qld,19641121,5138480 +rec-3736-dup-0,alita,mogavero,24,beattie crescent,heritage est,moe,3142,nsw,19170315,2991381 +rec-188-dup-0,,kukla,3,dines place,bayford cottage,blue haven,2526,vic,19240628,5073770 +rec-1518-dup-0,fardwll,alicia,63,,pint p ot,sunshine jeach,2203,nsw,19471004,7172127 +rec-4375-dup-0,burford,sascha,1,o'connell street,rowethorpe,berrimah,3212,vic,19801119,2679424 +rec-4900-dup-0,charlotte,fingas,94,lendon place,lexington,frankston,6201,nsw,19080713,2597760 +rec-2267-dup-0,jacqueline,tomiich,34,giles street,noorls,kilsyth,7030,wa,19230609,5698710 +rec-2369-dup-0,kaitkin,katarski,6,gidabal street,lawley park,milperrs,0802,nsw,19900303,1052599 +rec-4714-dup-0,mclaine,chloe,1,appel crescent,milly milly,old toognabbie,3199,wa,,1418089 +rec-1901-dup-0,white,shelby,23,britten-jones drive,finisr iver,brighton,5159,vic,19090729,3656655 +rec-2647-dup-0,timothy,twigger,9,tunney crescent,,toorak,5013,vic,,9871543 +rec-3508-dup-0,jacob,campain,7,logan street,,toowoomba,4551,qld,19520416,1591935 +rec-4571-dup-0,kirra,large,20,jondol place,coolsdie,blaclheath,2034,qld,19620904,6564371 +rec-1683-dup-0,andiew,renfrey,95,dickson shoping centre,margaret river carvn park,swan hill,4740,nsw,19640819,9425075 +rec-4369-dup-0,sienpna,kilb,21,archdal l street,yoorana,st albans,2090,qdl,19940203,8614284 +rec-3011-dup-0,alaiyah,klmem,12,crozier circuit,sec 161,towradgi,6330,vic,19100824,5690083 +rec-1740-dup-0,oliver,beatie,68,brigden crdscent,mortlach,matraville,6164,vic,19030824,4461623 +rec-2080-dup-0,madison,hand,4,mcnicoll s treet,old farm,kongal,2518,vic,19270511,3480162 +rec-3017-dup-0,josua,caromdy,19,shakespeare crescent,kellhaven,edensor pak,3250,qld,19050227,6686589 +rec-319-dup-0,juliana,campbell,18,nicholls place,illuka prak,ridleyton,6720,nsw,19540308,2165254 +rec-2769-dup-0,caitlin,weller,1,fullerton pcrescent,villa 5,rowville,4113,,19980825,1647081 +rec-3679-dup-0,senner,tylaj,10,kenyon circuit,eaglev iew,taree,3192,qld,19900331,5063985 +rec-707-dup-0,emm,webb,16,manning treet,craiglee station,montmorency,6155,nsw,19560630,6562713 +rec-916-dup-0,tians,whiet,20,tazewell circuit,ningana rekirement,toorak,2205,vic,19460218,7461693 +rec-2258-dup-0,thomas,brock,4,temperleh street,northwood park,mount warren park,4670,sa,19520624,9531535 +rec-2121-dup-0,sophie,masolagti,67,lyndonstreet,,wynnum west,2022,sa,19320713,4414033 +rec-3432-dup-0,,alwast,6,nunkeri,lhotsky street,brighton,5032,nsw,,7148945 +rec-1724-dup-0,caitlin,ridr,37,morgan crescent,,oak lfats,6330,vic,19580428,2527146 +rec-1418-dup-0,beau,dallas,19,lange place,,blakeview,0827,vic,19581021,2569822 +rec-3422-dup-0,alyssa,klusk,17,woodgrovw close,b,keiraville,4125,vic,19170822,4937438 +rec-674-dup-0,kylee,clarke,57,pethebrid ge street,lansodwne,normanville,2034,qld,19000930,3275236 +rec-3859-dup-0,lep,waterfall,21,mockridge crescent,aptmn 1 2,malvern east,4157,vic,19430408,8187145 +rec-1410-dup-0,kyle,faull,38,moynihan street,cosy corner,lennox head,6081,vic,19960130,1684057 +rec-538-dup-0,lucy,eglinton,15,jefferis street,,midway point,3050,wa,19070301,3897066 +rec-1952-dup-0,livia,,73,stapylton street,kanjara,roxburgy park,2212,qld,19790329,8689632 +rec-2466-dup-0,,millar,2,coglinp lace,hmas cerekrus,burrum heads,4157,vic,19591021,5479529 +rec-574-dup-0,emma,marcola,7,totterdell street,rosetta billage,goonellabah,6018,vic,19641017,7190961 +rec-3258-dup-0,shana,ryan,30,monaro crescent,old lakez hotel,duncraig,3220,nsw,19000819,4773341 +rec-2659-dup-0,elise,padbury,137,bennett street,,labrador,3630,vic,19400826,9441828 +rec-1588-dup-0,jye,humberdross,273,coles place,de cameron,kingaroy,6230,qld,19510505,8884850 +rec-2296-dup-0,caitlyn,green,105,hawker street,snugbeach vvn park,crestmead,2145,nsw,19691194,2466204 +rec-89-dup-0,ned,glennon,46,donohoe place,australi a arcade,menangle,2222,vic,19750118,6310028 +rec-426-dup-0,robert,clarke,42,miller street,,port macgquarie,3337,vic,19601221,8342535 +rec-563-dup-0,sybella,meaney,82,julius street,east end,seafroth,3690,sa,,7466921 +rec-4720-dup-0,mccarthy,jack,122,shackleton circuit,macquarie inn,westfield,4109,vic,19411214,5715719 +rec-231-dup-0,ellen,harrington,45,kardang street,cro ssands,balhannah,3168,vic,19130627,6204857 +rec-2752-dup-0,todd,allabanda,,pindari crescent,afflepxian,ottoway,2074,qld,19120701,9676170 +rec-3365-dup-0,mackenzie,rendulic,,auburn street,lonesome dove,blackbutt,4271,,19700812,5371450 +rec-4841-dup-0,connor,bergsma,180,ferndlae,tinderry circuit,penrith,3047,nsw,19580116,5081459 +rec-3672-dup-0,stella,,408,kallarq close,,burleigh eaters,4122,wa,19510426,7535262 +rec-2703-dup-0,alyssa,coleman,9,marsden street,main beach med ical centre,rowville,4556,qld,19260829,5376425 +rec-2197-dup-0,finlay,bedding,2,,abbey fields,orchard jills,4301,nsw,19640329,3074334 +rec-3224-dup-0,nathan,dudley,2,chevalie r street,,wanitrna,3150,vic,19740724,6423373 +rec-3986-dup-0,sophie,joaquim,35,,,lindfield,3151,qld,19320118,4865826 +rec-4670-dup-0,konstantinos,nguyen,56,pinda,twamley crescent,wanmiassa,2173,nsw,19730401,4155990 +rec-4885-dup-0,lia,sheley,102,wisdom sreet,de cameron,port lincoln,2747,tas,19510313,7625458 +rec-3701-dup-0,jenna,burleigh,59,floraplace,glenfine s tation,chisohlm,3231,wa,19151113,9906150 +rec-1431-dup-0,judah,badger,10,darby street,taskers village,yangebup,6003,tas,19530826,3374540 +rec-4098-dup-0,liyl,warnock,68,darlints treet,,exton,2154,nsw,19620520,2626334 +rec-2625-dup-0,renai,leaham,25,arabana street,glenview,frankston,6751,vic,19370312,8777592 +rec-2524-dup-0,ryan,moody,7,pooley bridge,tyrrell circuit,nedlands,3809,nsw,19320818,7217442 +rec-421-dup-0,deakyn,cannell,20,vansittart crescent,st vincents me dical centre,,6065,nsw,19951221,1255552 +rec-644-dup-0,casey,meyler,12,gryllscrescent,,berala,4109,nsw,,8730501 +rec-122-dup-0,bianca,ryan,120,de little i rcuit,march rising,westmead,6163,wa,19091028,4864427 +rec-1403-dup-0,zac,bellchambers,19,michael holt crescent,duc kcreek,kemblawarra,6104,nsw,19870104,4503098 +rec-1675-dup-0,brigette,marow,56,binya place,toowoombia,frankstn,2263,qld,19981021,6603838 +rec-971-dup-0,dylan,jedynak,,genoa s treet,ruthven street,glenhaven,4213,act,19201112,1200539 +rec-3542-dup-0,erin,lovelck,22,druit tplace,on river,dorrigo,4118,,19680706,8834319 +rec-3609-dup-0,gillan,lilee,32,yarra street,glen-erin,leongatha,2518,,19510828,6966115 +rec-4381-dup-0,william,minnicn,10,tunney crescent,berkeley vlge,redbank plains,2835,qld,19530313,5016829 +rec-1306-dup-0,erin,nguyen,80,crotonstreet,rockview aohtead,werrington,2066,nsw,19561212,9413029 +rec-3104-dup-0,louise,campbell,42,melrose drive,fairnolme,king river,2066,qld,19931202,3214176 +rec-565-dup-0,reuben,mccarthy,130,greenvale street,delaware,hoppers corssing,6019,nsw,19030224,5053375 +rec-2324-dup-0,,scarce,92,perry drive,parklands village,,3199,act,19930925,6703972 +rec-4941-dup-0,beau,lowe,272,fergusson crescent,,carrara,6066,sa,19651206,8529720 +rec-1745-dup-0,jackson,faull,14,delprat icrcuit,erina gardns,maryborough,2430,,19510814,6483913 +rec-1814-dup-0,connlr,asendorf,21,falkiner place,luskincourt,oraneg,4032,vic,19290430,6699074 +rec-1146-dup-0,amy,jessbp,27,,sect 12,kellyville,2824,vic,19461007,9991046 +rec-4160-dup-0,harry,waller,111,lochbuy street,willmon tpark,glendale,3170,wa,19680628,1311728 +rec-4708-dup-0,ellie,hamon,17,lyon place,oxon ia,st johns park,6163,vic,19750322,4621557 +rec-3938-dup-0,jack,morrison,10,leahyclose,the w illows,edensor park,3068,qld,19480822,1000754 +rec-3223-dup-0,bianca,mccamrthy,23,wakefield agrden,,elizabeth south,3126,vic,19991221,2431148 +rec-804-dup-0,james,kostrzynski,3,berkeley vlge,chipperfield circuit,potts point,4285,vic,19200505,6498292 +rec-3596-dup-0,nicholas,milalr,201,malandao rchard,temperley street,hyde park,2767,wa,19300617,1000123 +rec-4017-dup-0,sophie,canavbn,13,yandastreet,evergreen,malvern east,2022,wa,,7624166 +rec-3307-dup-0,chevodnne,wilkins,575,wilga plce,theslpiway,kellyville,4215,sa,19721204,2353183 +rec-2565-dup-0,brigette,siviour,19,bromleys treet,rowethorpe,parramatta,3204,nsw,19691123,4393770 +rec-2596-dup-0,amber,green,20,tom robers avenue,kimberlvey,north ryde,2510,nsw,19530919,3705115 +rec-3561-dup-0,eri,calrke,11,patten street,paddy's river,mourya,2066,nsw,19690410,6325590 +rec-3366-dup-0,rahcel,lowe,141,milford street,,darlington,4510,nsw,19810216,1700052 +rec-4023-dup-0,emiily,choi-lunkdberg,10,moseley place,glen alviw rsd,warriewood,2099,vic,19081225,8598033 +rec-3992-dup-0,marcus,spratt,39,chave stlreet,,oaklands park,4054,nsw,19170824,5276247 +rec-507-dup-0,ty,white,25,newbery crescent,jillamtong,albany cr eek,0630,tas,19111216,1390829 +rec-4261-dup-0,anthny,hope,136,locn 2 565,buckmasteri crescent,numeralla,3138,nsw,19330922,3443364 +rec-2007-dup-0,danidl,toms,5,mcclelland avenue,sprintbanks,kendaol,2030,vic,19760921,3896174 +rec-4760-dup-0,mloly,clarke,398,cameronsrteet,stonyridge,windsor,5806,nsw,19210202,2679994 +rec-1981-dup-0,william,ryan,1,fortitude street,hd of solomon,atherton,2206,qld,19520613,8994180 +rec-3103-dup-0,alusa,mulvie,35,osburn drive,emoh,booy a,2000,sa,19400808,2724093 +rec-635-dup-0,james,thorpe,27,cusack place,,kardinya,4580,qld,19410413,3938054 +rec-3817-dup-0,jared,masonr,9,woolner circuit,beachwood,pagw,3309,nsw,19510406,5818690 +rec-1278-dup-0,emiily,coleman,5,burdett crescent,withern house,wanguru,3757,vic,19030123,3292797 +rec-2247-dup-0,tabitha,walch,22,kosciusk oavenue,sec 3 11,jurien,2340,vic,19380223,2307700 +rec-318-dup-0,kiria,grosshan,41,greta main,maribyrnong avenue,buninyong,3163,sa,19180518,3161935 +rec-2429-dup-0,dylan,white,8,dirrawan garden,,manyana,2795,vic,19160414,8832194 +rec-4125-dup-0,jayden,browne,20,marshall treet,,farrer,2112,nws,19291128,7073714 +rec-2696-dup-0,jenna,nguyen,85,diselmaplace,villz2,collinswood,4343,nsw,19630325,2861961 +rec-1567-dup-0,campbell,webb,63,wade street,,mount vrosby,3152,nsw,19981022,3000281 +rec-2966-dup-0,heath,tao,1,holden cfescent,,cooloongup,2594,nsw,19420605,9669484 +rec-3349-dup-0,lily,nobel,24,stonehaven crescent,aga rabi,emerald,2145,vic,19981015,3188848 +rec-4986-dup-0,philip,nguyen,1,cutlack s treet,narada,bunbury,3183,nsw,19391206,5131671 +rec-1472-dup-0,,wilde,8,laidleyplace,halfmoon sotation,burnet theads,4702,nsw,19001220,4981478 +rec-3450-dup-0,jesse,white,9,dalley crescent,,north ikrra,3143,nsw,19820904,8123158 +rec-182-dup-0,haklra,hokly,40,kirklandc ircuit,meear,wahroonga,3149,sa,19721209,5682368 +rec-844-dup-0,charlotte,crossman,19,collings street,bridgefoot down,botany,6564,nsw,19221220,3932172 +rec-745-dup-0,white,tahlia,8,black street,the haven pole,wantirna,4350,sa,19570317,4436806 +rec-3527-dup-0,barnsaby,westbrook,221,hadlei gh cricuit,the lakes retirement village,petersham,4181,qld,19440405,2487468 +rec-3970-dup-0,,camp,28,sharwood crescent,,laverton,2153,vic,,8240507 +rec-3852-dup-0,talia,brooker,30,bellchambers crescent,rowethorpe,hawtohrn,2033,sa,19561107,4841722 +rec-4621-dup-0,alivia,dixon,15,northbourne avenue,kergumyah,sandilands,2142,nsw,19961001,6449400 +rec-548-dup-0,jadue,czoloszyski,,waller crescent,st francis vlge,cabramatta,7190,qld,19491001,6141371 +rec-715-dup-0,mia,lock,42,morrow treet,,woodburn,2810,nsw,19650307,6006824 +rec-2766-dup-0,mckane,caleb,21,lochee plce,,auburn,3083,nsw,19370320,3598063 +rec-4830-dup-0,danile,green,1,hartog street,retirement village,bonnyrigg,2749,vic,19900926,9765781 +rec-2582-dup-0,madeleine,wang,129,goodsir place,may ctotage,devonport,4030,vic,19840516,6195273 +rec-2515-dup-0,abbey,colquhoun,21,buntine crescent,glen e den,thornlie,2390,nsw,19960607,7703106 +rec-4691-dup-0,william,tomney,25,dulverton street,oma ru,gilmore,5043,nsw,19280525,2940053 +rec-4790-dup-0,lachlan,ryan,38,leven street,pyramid caravn park,bulimba,2251,qld,19010120,7889345 +rec-2704-dup-0,oscar,frew,87,scotty,akma place,mont albert,2138,wa,19800611,8407358 +rec-4127-dup-0,dayna,gilfedder,104,burgan place,edwardsc jambers,hawthorn,3191,nsw,19520413,7277011 +rec-2220-dup-0,anthoy,green,51,honyong cqrescent,kilwin ning,fadden,2171,wa,19790424,9686264 +rec-2915-dup-0,zachafy,stanley,,southern cross,luehmannjstreet,berwick,2099,sa,19031015,3379992 +rec-2326-dup-0,tayah,de lucia,210,eugenia street,electorat eoffice,maiden gully,4567,qld,19520703,1220730 +rec-2418-dup-0,chloe,mason,62,kinchela crescent,,spotswood,6530,vic,19400204,7931480 +rec-201-dup-0,huxley,claudia,108,crease place,edellen,northryyde,2464,vic,19851022,9295307 +rec-4308-dup-0,samantha,laing,,stopford crescent,argyle ivllage,tharbgoang,2333,sa,19490130,3281458 +rec-4882-dup-0,charlotte,saltiel,25,discovery street,wanderers rest,long jelty,2135,sa,19291014,4955093 +rec-216-dup-0,ashleigh,de bono,4,sloane place,villa 2,kilmore,2292,sa,19430521,9702458 +rec-2610-dup-0,josephine,highet,6,haydenclose,marandyvale,spotswood,2181,nsw,19121110,6475561 +rec-1379-dup-0,ambr,grubb,,eady sreet,corella,edithvale,2590,nsw,19850127,1191313 +rec-4798-dup-0,crook,channing,1,villa 115,rumkerp lace,thorbnury,4380,wa,19701023,3361106 +rec-862-dup-0,riley,green,20,riorda n sreet,tillside,burwood,3199,vic,19531216,5368190 +rec-3627-dup-0,paul,maksom,35,blazvyplace,elouera park,kingston,3143,vic,19280108,2229267 +rec-4314-dup-0,samuel,david,62,namatjiradrive,apmng 501,north arm,2166,qld,19560208,8268023 +rec-651-dup-0,nicholas,hoyland,45,shirlow place,jewells medical centre,wantirna,5049,vic,19200610,4055212 +rec-1762-dup-0,hayley,mort,23,namatjira drive,nioka,iluka,6027,qld,19150115,8448786 +rec-1553-dup-0,ebon,robson,31,freda bennetjt circuit,rowethorpe,ryd,2450,nsw,19301219,3841520 +rec-2475-dup-0,karla,wilins,66,clifford cerscent,talgarth,oatlands,2323,nt,19590520,3511629 +rec-549-dup-0,chloe,vincent,196,goodwin street,rosehill,wallsend,2745,wa,19140726,4286524 +rec-1985-dup-0,,lund,287,caley crescent,allandale agedc are facility,mill aprk,4053,nsw,19180902,7074690 +rec-4310-dup-0,phoe be,dixon,7,ambalindu mstreet,bracke n leigh,yass,6027,tas,19960119,3838118 +rec-4036-dup-0,makayla,colquhoun,11,collocott crescent,locn 2093,port augusta,2605,tas,19431223,8018767 +rec-3130-dup-0,emiily,green,24,luehmanh street,tawonga rdside,rose bay,2350,wa,19190825,2408163 +rec-76-dup-0,,miteff,10,goldenoaks village,tristania street,brookvale,3156,nsw,19550618,9393296 +rec-2938-dup-0,stephanie,dudek,181,forbes street,,buddinda,3226,qld,19130127,6246452 +rec-4221-dup-0,megan,wilkinsr,49,rosella s treet,nioka,eaglehawk,6011,vic,19590204,9298501 +rec-1957-dup-0,kelse,hoebee,83,paul coe crescent,,st kilda,6027,wa,19970705,7042275 +rec-2061-dup-0,dylan,millar,58,,the wi llows,woodbuen,2034,nsw,19330911,8113457 +rec-1558-dup-0,sebatian,collier,14,cutlackstreet,tara park,east fremantle,3191,vic,19571233,7739308 +rec-1366-dup-0,moulton,rory,2,box hill avenue,,beulah park,3844,qld,19760503,8152321 +rec-3710-dup-0,alana,morrison,28,,allanavle,,6056,vic,19081110,2007717 +rec-293-dup-0,robert,westhorp,26,kosciusko avenue,oa kp ark,,3109,vic,19690516,1463700 +rec-3517-dup-0,dante,prieset,18,bamford street,robin's cottage,willrtton,2618,nsw,19150225,9740161 +rec-3118-dup-0,emma,rook,11,chauvel cricle,,boyanup,4221,,19650302,9822954 +rec-4637-dup-0,aurora,gigney,64,o'rourke street,timdoolin,shellharbour,4059,nsw,19760409,7169291 +rec-2073-dup-0,hayley,doaln,59,,delicate nobby street,,5031,qld,19960713,1276506 +rec-2038-dup-0,marlee,boss,16,slessor crescent,north a rm,ballsrat,2134,sa,19940504,2634944 +rec-3132-dup-0,ethan,mcdermid,27,buggy crescent,rsde 817 wallace,eden hills,3287,nsw,19921128,3857378 +rec-392-dup-0,harrion,reid,45,sangster wplace,mount valley van park,harbord,5518,tas,19451222,7347950 +rec-1665-dup-0,sohie,abeywickrama,48,bambridge street,brentwood vlge,old beach,4067,nsw,19570314,9229864 +rec-2492-dup-0,aidank,banham,5,rowntree crescent,locn 8774,,2284,wa,19280830,5929976 +rec-4329-dup-0,zac,doman,112,buvelotstreet,,ballarat,2097,qld,19150628,7022901 +rec-4846-dup-0,billy,hawes,50,ella close,executive arcade,mosman,5461,viy,19110524,1201773 +rec-1506-dup-0,kiria,bradshaw,15,burkitt street,mindaree,tuart hill,3300,nsw,19180720,9562529 +rec-2624-dup-0,masobn,natalia,2,aspinall street,blackridge flyfishing school,oak park,3134,vic,,2222516 +rec-1946-dup-0,michael,rawlings,1554,millen sy ryeet,thehomestead,coolbellup,2750,sa,,6689349 +rec-363-dup-0,kirra,campbell,29,groom street,rockleighc ottage,north ryde,3206,nsw,19951128,9444838 +rec-4579-dup-0,chloe,ryan,5,lambrig g treet,eldeslee vlge,eastwood,4371,,19570622,2578857 +rec-4716-dup-0,lucy,dunthorn,7,grattn lpsce,thurlimbah,,4510,qld,19380809,7921182 +rec-135-dup-0,lomman,brayden,1,cockburncstreet,hyladn,taloumbi,2756,vic,19941224,2435246 +rec-784-dup-0,lillian,humphrwys,8,mack s treet,,narooma,4352,nsw,19710908,6242916 +rec-3406-dup-0,zachariah,bulgin,,throssell street,farn 43,modbury,2190,nsw,19590703,5683667 +rec-4734-dup-0,anthony,burkevics,8,dryandra street,alexandraracecourse,balla rat,3048,vic,19180927,2312985 +rec-1748-dup-0,mhary,rnudle,12,bradfield street,,woodlands,3280,vic,19960812,5560844 +rec-3850-dup-0,montana,webb,28,joyce pojace,ormerod cottage,surfers paradise,2305,vic,19420710,8424221 +rec-612-dup-0,jake,david,13,pearson treet,hazelwood garden,casino,2076,sa,19320306,5193402 +rec-309-dup-0,eliza,campbell,113,dines place,villa 74 village glen,figtree,3550,nsw,19651205,4509107 +rec-4471-dup-0,william,campbell,448,tarra p lace,lochefnels,savage river,3075,qld,19630610,7272235 +rec-1714-dup-0,latham,shepherd,50,namatjiradrive,banksia village,whitebridge,6083,act,19050621,8015196 +rec-3240-dup-0,james,crook,3,antis street,myrrhee,shelley,2711,nsw,19520227,5851238 +rec-2139-dup-0,emiily,campbell,62,oakwood place,thewedge,bogangar,4214,nsw,19810407,5373209 +rec-1769-dup-0,anari,pettigove,9,betche place,b,gwandalan,3156,nsw,19890618,1209547 +rec-2453-dup-0,samantha,mccracken,162,shackleton circuit,old pur rawunda,westbrook,6020,nsw,19730929,3197473 +rec-3481-dup-0,bethany,steers,3,temperleustreet,parkside flats,east aitland,4210,vic,19610825,5823896 +rec-4886-dup-0,tommi-ee,pagoad,1,strzelecki crescent,rathdangan,moama,3825,vic,19360520,8652033 +rec-67-dup-0,erin,matthews,10,williamson street,yaraan,kilcyo,4218,qld,19991129,7747845 +rec-1233-dup-0,,demetriou,4,,zimms corner,bayone t head,2550,qld,19100722,3790130 +rec-3712-dup-0,heath,everett,7,hurry place,reinfr ew park,belmont,2447,qld,19430834,7474300 +rec-3182-dup-0,luke,abrahamson,56,deepdale farm,vowles road,taringa,5330,nsw,19170625,4386896 +rec-2941-dup-0,connor,grewen,2,benny place,the gums,crescnet head,3067,vic,19450207,7329507 +rec-2855-dup-0,dominic,papageorgiou,1544,laperouse street,the lakes retirement village,bacchus marsh,3995,nsw,19140218,4660218 +rec-2970-dup-0,charlie,mccarthy,1,swinden street,court units,sandgtae,2250,wa,19830303,3510238 +rec-1468-dup-0,aaliyah,ottens,17,mullan syreet,,ascot vale,5540,sa,19181214,3004031 +rec-3713-dup-0,chelosea,clarke,34,marrawah street,koonawarra meino stud,ashfield,3912,vic,19560528,1305791 +rec-1644-dup-0,david,panaga ris,5,hannan c rescent,st george,bonnyrigg,2785,nsw,19160809,2039630 +rec-634-dup-0,,maynard,,mckillop circuit,norely,ede,2339,qld,19420418,7402311 +rec-1749-dup-0,amber,vincet,313,kneeshawstreet,vlla 18 pacifiv bay resort,oyster bay,4740,nsw,,2066144 +rec-4605-dup-0,georgia,,7,chipperfield circuit,eastern end,ryde,3500,vic,19141110,1576434 +rec-4138-dup-0,justin,weller,3,sprent street,heritawge est,thornlie,2074,nsw,19441214,5085526 +rec-501-dup-0,brbdy,kis,88,knox street,kingway tourist park,caves beach,2284,sa,19560723,6452285 +rec-4922-dup-0,rolliqns,ashleigh,22,mcrae place,mansfie l dpark,dato,4672,tas,19180307,4706557 +rec-2482-dup-0,hayley,benger,125,mckailcrescent,rosetta ivllage,southbank,5048,nsw,19390818,2726971 +rec-3338-dup-0,jason,tebbutt,,stradbroke street,kildurham,winthrop,6213,act,19750627,1072661 +rec-3181-dup-0,katharine,stubbs,158,serpentin estreet,grasmere park,magill,5290,nsw,19511101,8604811 +rec-355-dup-0,painter,eva,116,castleton bcrescent,mawingo,malvern east,3338,nsw,19770419,6468703 +rec-902-dup-0,angus,chandler,20,archibald street,,eight mile plains,6150,qkd,19531214,3626178 +rec-4522-dup-0,broose,reid,27,skertchly place,santa lucille,rye,4115,qld,19341227,3146566 +rec-3346-dup-0,talena,white,4,tyson street,rocklea,eagldahwk,3188,sa,19580101,7287410 +rec-1876-dup-0,abbey,lewkowicz,33,stead place,dalamar,lake munmorah,6108,nsw,19240802,1187314 +rec-1213-dup-0,brendan,whillas,30,nindaawrri,horrocks street,carlingflrd,6061,qld,19140619,7279575 +rec-4443-dup-0,amber,nguyen,293,hartungc rescent,grandview,aubura,2209,nsw,19780324,1331391 +rec-1235-dup-0,michael,ryaan,3,mollee crescent,,birkdale,3757,wa,19460409,1467578 +rec-1869-dup-0,anari,burrill,41,burrinjuc crescent,,east freemantle,2537,wa,19671115,7891299 +rec-1249-dup-0,benjamin,browne,710,beazley crescent,,merrimac,2094,nsw,19660327,9379589 +rec-4029-dup-0,darcy,montfort,194,,upper newe ecreek street,mount helen,2448,qld,19580822,6099624 +rec-1231-dup-0,sma,detn,4,chillagoe street,myliton,hamilton,7325,nsw,19270825,9350791 +rec-4076-dup-0,,slavvjevic,5,bellinger circuit,panfani,snowtown,6230,vic,19770927,8191221 +rec-4064-dup-0,benjamin,asche,2,cochrane c rescent,st helens pastoral co,boyne island,6149,vic,19260316,8036732 +rec-3630-dup-0,cain,quilliam,40,,nuffield vkllage,clayfield,3858,nsw,19861124,5735991 +rec-4662-dup-0,james,,,fihelly street,leumezah,woodville north,2155,vic,19081030,5908468 +rec-1785-dup-0,tiarna,whitd,1,faucett street,dallyn,childers,4880,qld,19310412,3803605 +rec-3196-dup-0,indiana,hyland,19,aronson crescent,evergreen,cooranbong,4741,qld,19101219,8061638 +rec-4488-dup-0,lochlan,shephrec,51,barnett close,winteirga,bimbi,2328,vic,19850102,8073994 +rec-2243-dup-0,benjamin,herbert,,vonwilleer crescent,,geelong east,3163,nsw,19310822,6246038 +rec-1775-dup-0,sian,debt,12,kaeppel place,walhalla,belmont north,5253,sa,19470506,9599013 +rec-4172-dup-0,robbie,harbobrd,3,wrixon street,darjeeling,myall,2299,sa,19760411,2936318 +rec-3620-dup-0,diamond,mason,371,madigan street,,flora hill,2520,nsw,19161109,7721397 +rec-3763-dup-0,clodagh,tromp,7,boustea dcircuit,lochenf els,greenacre,2770,nsw,19870808,7950786 +rec-4931-dup-0,rebecca,spzrk,10,walker c rescent,,casino,4121,nsw,19990319,3829447 +rec-2006-dup-0,hunter,dietrich,67,,wandella park snowy,chinchilla,6156,vic,19680320,8096012 +rec-3877-dup-0,vendula,forgie-sendt,11,mccabe crescent,parry house,allingham,2484,nsw,19650317,1609178 +rec-245-dup-0,taylah,meaney,,lumholtz place,cordelia y state,torquay,2282,vic,19470106,1744252 +rec-4271-dup-0,sam,reid,333,leahy close,lavender farm,lakemba,2291,vic,19961213,1592375 +rec-2619-dup-0,bryce,white,134,macdonnell street,bindaree,nollamara,5127,vic,19090530,8089512 +rec-1046-dup-0,wiechec,joshzua,12,parkinson street,chanak,goovgien,3976,tas,19601111,6247547 +rec-3665-dup-0,harvey,webb,185,lindsay street,dovens flat,brighton,3139,nsw,19091228,6664660 +rec-149-dup-0,carla,hofhuis,7,mcculloch street,wytal bia,south brisbane,4066,nsw,19660816,3472110 +rec-4930-dup-0,nicholas,jolly,181,tullaroop street,federation cove,old toongabbie,2606,wa,19660414,1461086 +rec-1074-dup-0,benjamin,paterson,31,dodwell street,,devonport,2905,,19120913,6303884 +rec-4092-dup-0,kelsea,snell,5,petterd street,mac donnells bldg ( cnr grafton s street,thornlie,4226,wa,19510210,2775215 +rec-4321-dup-0,natalia,bissett,98,springvale drive,,kaleen,4218,qld,19500422,8653274 +rec-1510-dup-0,imogen,beaty,68,hilders treet,,toowoomba,2120,nsw,19771106,4994511 +rec-3897-dup-0,ella,estcourt,12,gellatly pplace,mayfair,braddpn,3850,nsw,19090814,2110759 +rec-2516-dup-0,sarah,wheatley,24,oxley street,,kellyville,2430,wa,19640212,5382301 +rec-2639-dup-0,liam,scerri,55,benham street,the sycmaores,berwick,6155,vic,19320829,9489744 +rec-3616-dup-0,evan,matthews,112,kildarra,enid lorimer circuit,port augusta,6103,nsw,19961123,1551414 +rec-2649-dup-0,bethanie,nguyen,23,morrisse y street,navillus,st ives,4214,vic,19400724,7869955 +rec-1826-dup-0,kynzn,doolqey,14,mcintyre street,apt 27,woollahra,6021,qld,19319924,1493049 +rec-3010-dup-0,thomas,quas,6,fiveash sreet,,st clair,4565,vic,19730804,9009452 +rec-1611-dup-0,connor,foall,17,lamb p lace,berri cottage hmes,kilsyth,3174,qld,19140927,4900414 +rec-1435-dup-0,thomas,dinh,5,jervois treet,dugout 65,goonellabah,2077,nws,19841214,5448033 +rec-4982-dup-0,holla,paterson,,cowderyplace,dragon rising,torquay,3910,act,19641219,1987760 +rec-2589-dup-0,,manson,150,syron place,wirong,,4066,vci,19880923,8557384 +rec-518-dup-0,jack,wegman,9,julia flyn navenue,myros,armidale,2444,qld,19710718,3680861 +rec-1986-dup-0,sarah,handel,32,twelve trees crescent,maclee,brooloo,4111,nsw,19311009,8033344 +rec-3708-dup-0,reeve,michelmore,3,wambaya crescent,war veterans hme,cooloongup,6112,wa,19940723,8143187 +rec-1392-dup-0,joshua,clarke,1,savery street,bexley,carnegoe,3028,sa,19011011,7741570 +rec-2609-dup-0,brooke,egan,93,mcinnes street,riverbencd,wanniassa,4215,vic,19880417,8165238 +rec-2365-dup-0,fraser,jasniach,39,davidson street,riverbend,kingston,3183,qld,19310910,6160407 +rec-1747-dup-0,annabelle,,6,dethridge street,the castle,oakviile,2526,vic,19350712,1214735 +rec-2882-dup-0,sarah,eglinton,19,beasleyz street,,naraocorte,4012,nsw,19451107,4310446 +rec-3209-dup-0,catherine,david,109,ijong street,nedl yn,mallacoota,2316,qld,19620212,1973270 +rec-186-dup-0,georgia,campbell,1,kalgoorlie crescent,rowethorpe,sherwood,3134,nsw,19730322,6197687 +rec-1289-dup-0,brandon,tallaxdira,123,chippendale village,hawkekr place,currambine,3016,nsw,,5752105 +rec-616-dup-0,ruby,allchin,20,mccarten place,glenhjrst,ascot,2106,sa,19470412,1630282 +rec-2202-dup-0,dylan,gillard,22,ryrie street,lithgo wvale,corryong,5152,nsw,19410128,6232488 +rec-4667-dup-0,,clarke,53,stumm place,booroondoo north,westmebdows,5115,vic,19500203,9535984 +rec-48-dup-0,georgia,shih,14,hopeview,furey street,toowoomba,6008,nsw,19870324,1794716 +rec-4396-dup-0,brayden,tomuny,6,attunga street,killarney,sunnybank,4670,nsw,19031003,3973459 +rec-3582-dup-0,michadla,rickett,13,sorlie place,terra nostra,robina,5157,nsw,19920309,4084583 +rec-2034-dup-0,alexander,udovcic,7,canberrahavenue,dunbogan caarvan park,ryde,6164,nsw,19140306,3194688 +rec-1210-dup-0,amber,kerslak-eling,5,glencros s street,lumley,wahronga,4897,sa,19031228,1079968 +rec-1960-dup-0,henry,webb,15,wearmouth,kalgoorlie crescent,dunoon,3763,wa,19100626,8261350 +rec-2126-dup-0,timothy,soulemezzis,18,allambee street,brentwood vlge,balaklava,2590,vic,19010923,1004889 +rec-2370-dup-0,,eyles,157,totterdelli street,,st kilfa,2602,nsw,19060606,3998859 +rec-2460-dup-0,,felmingham,49,gawler crescent,wing ara,wynnym west,6159,nsw,19920718,7791969 +rec-1640-dup-0,ned,hamblin,1,bokhara c ircuit,,ballarat,5012,,19150226,9945787 +rec-3401-dup-0,toby,stanley,32,craydon place,lenzoy,heywood,2904,wa,19381214,3931157 +rec-191-dup-0,madeline,liteploj,28,mckayg arden,kangaroo grnd,creswick,2871,nsw,19640410,9933895 +rec-3994-dup-0,nathan,,33,stobie place,,ascot,2218,qdl,19121126,9963518 +rec-401-dup-0,lela,guyatt,19,domain street,lansdowne,st kilda aest,5418,vic,19360703,9745316 +rec-294-dup-0,william,badger,,dwyer s treet,glenlee,west lakes shore,3291,nsw,19001210,4656608 +rec-3312-dup-0,alexander,georg e,45,legge street,lashbrooke,mount low,3163,qld,19150920,5235447 +rec-3472-dup-0,timothy,mouajlli,14,cobby street,,christkes beach,2167,qld,19770117,4552685 +rec-4877-dup-0,roles,kierra,22,musson close,,coledale,3977,wa,19650917,8518344 +rec-1710-dup-0,ayla,thorpe,34,black street,wunplm,currabmine,5540,vic,19031202,8748647 +rec-1083-dup-0,kyle,siviiur,21,bungonia street,eight mile,loftus,4868,qld,19821215,7416603 +rec-2635-dup-0,isabeole,,14,larkin close,naringal orchard,box hill south,2406,nsw,19440723,3423612 +rec-733-dup-0,shelby,garforth,,madigan s treet,st francis village,nannup,4506,vic,19060707,5601065 +rec-2045-dup-0,jack,steinert,21,lamington street,st franc is village,holden hill,7019,sa,19680119,5389848 +rec-693-dup-0,rachel,donaldson,9,lee-steere crescent,lake kenn eyd street,sunshine,3175,nsw,19581218,2248813 +rec-998-dup-0,bailey,gree n,76,jackie howe crescent,glengara billage,murgon,3340,nsw,19960416,1468056 +rec-4999-dup-0,victqorka,fitzpatrick,16,clermont street,amber vale,lake tyers,4570,nsw,19220818,2176335 +rec-2575-dup-0,charlotte,grierson,12,hooley place,,kellyville,2479,nsw,19691116,8381516 +rec-1006-dup-0,cooper,rya,166,torrens street,callatoota,bondi junction,3992,snw,19341027,1163656 +rec-2853-dup-0,holly,ang,9,pinkerto circuit,professional centre,robina,3919,vic,19300225,1127897 +rec-1643-dup-0,georgia,kouba,1,gay place,new chum,east lan uceston,4169,nsw,19830526,8748935 +rec-1557-dup-0,ben,grub,9,girrahween street,loma,brunswick west,1382,nsw,19360711,6198116 +rec-623-dup-0,jacqueline,ferris,107,kriewaldt circuit,dunmoven,mirraooka,3195,vic,19251030,7808140 +rec-2698-dup-0,drew,bihshop,6,gask pqlce,balala station,heywood,3058,nsw,19000402,1551804 +rec-4619-dup-0,isabel,bitmead,14,bellchambers crescent,glenu mbral,warnbro,2093,sa,19680509,1302707 +rec-3193-dup-0,,finlay,14,castleton crescent,killuke,bundaberg,4670,qld,19600319,1709445 +rec-2581-dup-0,kate lin,denq,29,sugarloaf hcircuit,wildfeell,windsor,4503,qld,19280517,4402607 +rec-1776-dup-0,corey,gresn,8,blamey cr escent,briony downs,cardiff,3121,qld,19961225,6076482 +rec-1153-dup-0,sam,ried,243,roope close,brentwood vlge,blacktown,6015,nsw,19050930,8900010 +rec-1246-dup-0,koben,ryan,17,forema n place,,eastwood,3101,nsw,19341114,2722891 +rec-347-dup-0,alexandpra,strers,38,banambils street,,taree,2820,vic,19560329,6925665 +rec-3165-dup-0,shakira,ryan,89,ainslie avjenue,wanda na,pymble,3631,qld,19241014,1774551 +rec-2598-dup-0,diamond,branston,124,longstaff street,two sticks estate,grenfell,3108,nsw,19720728,2121177 +rec-4429-dup-0,j oel,ryan,22,robertso n street,erinmoore,portarlington,3196,qld,19950602,9067165 +rec-4226-dup-0,nikakis,sara-louise,51,ashbycircuit,sunshine farm,kincumber,2298,qld,19000820,4911869 +rec-166-dup-0,robert,ngudn,22,barlow street,fred lean hostel,dickson,6152,nws,19140127,9527501 +rec-163-dup-0,darcy,ben-grion,3,howitt street,arlington,,3151,nsw,19691225,8281055 +rec-4194-dup-0,leslie,nichllas,10,de little circuit,retirement xvillage,daisy hill,4802,nsw,19691231,9490741 +rec-1288-dup-0,vanessa,parr,905,macquoid place,broadbridge manor,south qrafton,2135,sa,19951119,9239102 +rec-3242-dup-0,jordan,godfrey,79,bettington circuit,raycrfot,merricks north,2229,nsw,19380817,7501347 +rec-2221-dup-0,jacqueline,rudd,189,crichton crescent,,raglan,3088,nsw,19320306,9649030 +rec-1883-dup-0,georgia,rau,12,wolff crscent,,greenale,3806,qld,19451104,7297422 +rec-4143-dup-0,tyler,mcclelland,1,millen street,old post office,,2049,vic,19061004,8000542 +rec-1676-dup-0,,lamprey,12,twynam street,alanavle,revesby,2537,qld,19200815,2877637 +rec-334-dup-0,matthew,bartel,,furphy place,bridgewater estate,ekibin,3630,nt,19890220,2422771 +rec-1024-dup-0,charlotute,bishdop,24,bourne street,dp 808602,port macquarie,3484,sa,19420131,5896457 +rec-1626-dup-0,katelin,thrpe,93,vagabond crescent,furmiston,cabramatta,4574,nsw,19930611,8939082 +rec-3313-dup-0,thoma,ryan,24,coo lalie,weavell place,emeral,4280,vic,19970129,8879018 +rec-4511-dup-0,levi,oaks,38,courtice close,sunshin e farm,findon,6050,wa,19101128,9317947 +rec-1789-dup-0,,white,10,spafford crescent,clear cr eoek,pakenhm,4059,nsw,19480205,7285108 +rec-1652-dup-0,zac,ebdell,,gogulge rstock,outtrim avenue,preston,4123,vic,19461126,3704089 +rec-3979-dup-0,ky,renfrey,9,southwell street,cottagerose,tooperang,4217,vic,19290827,6382127 +rec-1545-dup-0,sarah,grosvenor,190,moyes crescent,,ballaart,6155,nsw,,6043963 +rec-3806-dup-0,ethan,goode,262,minnett close,,prospe ct,3550,nsw,19830302,9757237 +rec-547-dup-0,jack,ziersch,9,melba street,belvedgere,nes farm,5501,wa,19741024,8799452 +rec-4283-dup-0,marcus,ryan,7,,villa 5,stoneville,3977,nsw,19670616,9348856 +rec-647-dup-0,henry,greenhaplgh,2,,,shorncliffe,4516,wa,19670212,3335029 +rec-1120-dup-0,angeilca,green,,nash place,palm grove,vauculse,5242,nsw,19051230,7491589 +rec-2334-dup-0,jasmyn,lowe,48,toohey place,grand ecntral,bicton,3085,nsw,19320918,1430128 +rec-3645-dup-0,samuel,coukson,1186,wheatley street,,acland,3183,qld,19050630,1100698 +rec-4537-dup-0,mia,miles,54,beiren street,pacific palms c aravn park,windsor,3268,nsw,19720726,3671331 +rec-3259-dup-0,laura,newey,6,archibaldstreet,,harrisp ark,3006,wa,19570428,5725917 +rec-1203-dup-0,amh,flannery,15,timberscombe,jansz crescent,lakemba,5556,qld,19871219,1702911 +rec-1237-dup-0,jordan,nerry,41,anderson street,wilag,moorabbin,2097,vic,19880826,2009434 +rec-4117-dup-0,jaimee,bems,5,cobbadah stvreet,grandcetnral,chevron island,2620,nsw,19001005,9646957 +rec-2198-dup-0,matilda,bergsma,73,macrobertson street,derrym lodge,greensborough,2076,wa,19880213,5520743 +rec-3283-dup-0,gregory,bujtas,,badimara street,tourist park,killaora,4285,nsw,19811017,6763771 +rec-2091-dup-0,cait lin,khammash,125,carbeen street,salimtal,elsternwick,2493,nsw,19810113,7990656 +rec-168-dup-0,katilin,,4,hawkins close,tullatrnudle,eaglehawk,4280,nsw,19671026,8483513 +rec-898-dup-0,annabel,malin,5,findlay street,pacific ba villas,mawson,2099,vic,19291020,4116074 +rec-2615-dup-0,rebekah,camp,165,tom roberts avenue,,st kilea,3199,wa,19860227,1035731 +rec-2674-dup-0,lachlan,clarke,20,condamine street,deswod,tarew,4019,qld,19900626,5423805 +rec-2817-dup-0,amber,canavna,,,karinga park,hawthorn,2540,vic,19820904,1356716 +rec-3050-dup-0,victotria,rankine,661,redcliffe sttreet,strathmore vineyard,moranbah,6298,vic,19260809,5842904 +rec-3280-dup-0,schembri,brock,71,arkana stereet,redwoodvillage,cola,3156,wa,19530417,8819783 +rec-2857-dup-0,angie,hylaned,1,wardell place,port fairy road,beaumaris,4605,wa,19770803,7407973 +rec-2305-dup-0,thomgas,peachey,1090,willis street,,preston,2114,wa,19901004,5902615 +rec-4353-dup-0,emiily,rundyle,112,tarago place,fiveways,brookvale,2122,nsw,19461226,2412960 +rec-1052-dup-0,giaan,everett,6,,sunnysideo rchards,wangaratta,4551,tas,19420909,7947853 +rec-3492-dup-0,kayl,elrick,95,jardine street,tudor,bronte,2610,vic,19250202,8616786 +rec-2738-dup-0,james,rosendale,1,boultin close,middle earth,bateman,2147,nsw,19720223,3756981 +rec-2024-dup-0,tara,riding,11,palm lake resort,allchin circuit,wanniassa,2262,nsw,19761123,9131364 +rec-1964-dup-0,sophie,haythorpe,12,bamforedstreet,,alligator creek,6230,sa,19670809,3361594 +rec-1347-dup-0,skye,clarkae,11,buiktplace,,northbrridge,2225,nsw,19260328,6512778 +rec-735-dup-0,mark,nicolle,20,florence taylor street,greenacres caravan park,cloverdale,5090,wa,19780430,5862681 +rec-1744-dup-0,tiffany,green,32,sid barnes crescent,dudley specialistm edical centre,wingfield,2027,qld,19860328,4528322 +rec-2709-dup-0,montana,blake,24,,spring banks,college park,2620,,19400808,9535357 +rec-676-dup-0,samuel,princehorn,20,gould street,somerview,warra,3152,nsw,19716209,1347961 +rec-3547-dup-0,vimpaey,eliza,113,renwick street,,st ives,4730,qld,19070323,2705720 +rec-2462-dup-0,ruby,garnsey,317,harcourt street,navan park,north narrabeen,4163,nsw,19731030,5892459 +rec-2779-dup-0,natalie,clarke,11,narryer close,,aranah ills,3016,vic,19281031,8177483 +rec-2712-dup-0,abbey,oats,116,sabine close,ki loran,,3930,qld,19471031,7179281 +rec-594-dup-0,,binnsd,90,plummer street,toow oomba,hoppers crossing,2026,sa,19011227,4137992 +rec-4071-dup-0,laklynn,whhite,,french street,mari-ma farm,eleebana,4655,nsw,,2842344 +rec-4810-dup-0,kyl,milse,10,michellstreet,tallinga park,hinchi nbrook,2575,tas,19160202,6888097 +rec-3735-dup-0,churches,jyeq,1,fraser scourt,,labrador,4151,vic,19200210,2271801 +rec-1150-dup-0,benjamin,lovelock,1,tanumbirin i street,apmnt 203,willetton,4570,nsw,19980628,6282406 +rec-4505-dup-0,grace,carbne,37,longstaff street,gleneira,seymour,6233,vid,19380212,4562890 +rec-2141-dup-0,alexandra,emixer,42,mannheim street,casablanca,st albans,2913,sa,19030525,3838784 +rec-2547-dup-0,joshua,sherriff,159,portus place,sun city resort,blighp ark,2035,qld,,6454105 +rec-4334-dup-0,,webv,,degraves crescent,marriott downs,maryborough,6151,nsw,19130715,5325666 +rec-2070-dup-0,christopher,lock,9,swinden street,heritage est,campsie,3045,vic,19200617,3438940 +rec-3232-dup-0,isabelle,hope,140,ellenborough street,grimes paddock cotge,murray bridge,6512,qld,19480522,1334359 +rec-87-dup-0,shandril,,6,maclean street,seaford,ganmain,7006,vic,19410912,2925713 +rec-2568-dup-0,kristo,mckinnell,14,,salmaldo caravan park,sunshnie,2571,qld,19081106,1212914 +rec-393-dup-0,alexander,,4,fink crescent,rubicon,orange,3041,nsw,19620324,7933489 +rec-4626-dup-0,kyxle,seddo,164,shackleton circuit,the wharf c omplex,ashfield,2406,vic,19030813,7244560 +rec-1398-dup-0,kristo,white,13,evergreen,mchale place,devonport,2050,qld,19790907,4175137 +rec-3707-dup-0,hayden,mortlock,5,,alices downs,kulikup,4805,qld,19570219,3860930 +rec-2072-dup-0,kelsey,bacskai,7,northbourne avenue,kooyong,como,5241,qld,19700110,3814852 +rec-1423-dup-0,,greewn,13,folingsby street,pint pot,queenscliff,2720,vic,19840808,9788564 +rec-456-dup-0,jaxson,ryan,01,staunton place,wildernhss,greenacre,6430,vic,19270613,7731951 +rec-4388-dup-0,ashleigh,neumagnn,13,hadlow drive,ningana,canterbury,2208,vic,19961127,5633162 +rec-1375-dup-0,jye,bradshaw,,wyles place,normanhurst,homebush,2036,wa,19900905,7164427 +rec-4709-dup-0,jordan,gripton,8,kinkead street,navan park,somerse,2070,qld,19701212,3869041 +rec-4293-dup-0,adriana,jenko,28,samuels crescent,wariadla,cambooya,3691,vci,19620402,8518234 +rec-965-dup-0,mac,beaty,,maloney street,cottage r mn east,medima,6027,tas,19980531,8216119 +rec-1634-dup-0,alicoa,kluske,69,eggleston crescent,wunnamurra homestead,brighton,3020,vic,19701124,2499759 +rec-2534-dup-0,michelle,morrison,348,retirement village,nunan crescent,coolaroo,3754,tas,19580308,2642188 +rec-2611-dup-0,hanah,graihger,34,fitzsimmons street,northbrideg marina,middleton,4680,nsw,19340314,1608436 +rec-3559-dup-0,rebecca,wojciechowski,16,evergood close,diment towers,pelican w aters,7018,nsw,19881017,5881744 +rec-4470-dup-0,tori,reid,244,sellwod street,,parknson,6169,vic,19280331,2530021 +rec-1929-dup-0,wilson,sporn,1,barnett close,sherwood,bowral,2008,tas,19311113,3629982 +rec-371-dup-0,alexander,noble,5,downes place,buena vista,greenacre,4220,nsw,19330331,3691864 +rec-727-dup-0,danidl,mason,,hazel smith crescent,grant patch,rochedale south,3688,vic,19900531,3210073 +rec-2812-dup-0,adam,gilbertson,2,albermarle place,the willows,yarra juntion,5252,qld,19570515,8465469 +rec-790-dup-0,gabrielle,patience,16,helen mayo crescent,paradone,orange,3198,sa,,8563603 +rec-1651-dup-0,caitlin,clarke,7,bradfield street,kerry street,margaret river,2216,,19200126,5030581 +rec-3176-dup-0,laufn,,,moore street,jormaieze,mullaloo,3182,sa,19600314,2240511 +rec-4200-dup-0,lara,sekuless,9,loch sutreet,,yarraville,3196,qld,19861129,1392776 +rec-1584-dup-0,james,paterson,138,mcelhonecourt,balmain cove,collie,6023,vic,19080720,4654129 +rec-492-dup-0,matthews,carky,14,mcnamara street,henry kendqll hostel,aroona,2275,nsw,19460115,6001116 +rec-2802-dup-0,joel,bartel,6,chewings street,buena fista,sea lake,2777,nsw,19550822,9818191 +rec-1742-dup-0,amber,crouch,75,crisp tsreet,manning village,kyabram,2648,vic,19010309,2336725 +rec-2465-dup-0,emiinly,campbell,13,beazley crescent,cameroo,leichhardt,2759,qld,19250103,2816217 +rec-4311-dup-0,ty,brads haw,12,greenhood place,conmurra,lauderdale,3146,qld,19630327,7145468 +rec-4873-dup-0,sma,blake,72,stockdale street,yarrandale moonee,sandgate,2262,nsw,19511223,4671131 +rec-155-dup-0,lachlan,meeing,02,whitford place,westlela,lilli pilli,2141,vic,19580816,8359944 +rec-4081-dup-0,mackeznie,collinson,24,beaurepaire rescent,riverside park,maryborough,3444,nsw,19750803,1576308 +rec-2000-dup-0,cain,dooley,85,boobialla street,osborne nouse,marsden,2284,vic,19570621,5346367 +rec-4857-dup-0,mitchell,paterson,10,boniwellstreet,kilacloran,point lonsdale,3021,vic,19550830,3431890 +rec-2671-dup-0,betn,webb,10,doutney place,parkridge villa,leichhardt,2808,vic,19761122,2024248 +rec-1781-dup-0,jessica,lomman,28,wallis place,glengariffe,north sydney,3039,sa,19801217,6284781 +rec-4995-dup-0,jessica,singleton,40,villa 2,tyrrell circuit,farrer,4422,qld,19241115,7634940 +rec-254-dup-0,ebony,webb,21,knox street,crestwood,higgate,2196,,19001231,5875656 +rec-2235-dup-0,kiria,ryan,41,rumsey place,mountm arion,hayborough,2289,wa,19081205,1490347 +rec-366-dup-0,callum,webb,34,callaghan street,emerald garden,lockleys,3166,vic,19000429,2494767 +rec-2939-dup-0,gastarini,lauren,12,spowers circuit,menedebri,modu bry,4680,vic,19731226,5596194 +rec-3598-dup-0,katelyn,simmonds,9,kellways treet,,noble park,2184,vic,19930530,4611006 +rec-313-dup-0,amelka,mo,46,,rowethorpe,waterloo,2017,vic,19010613,6555841 +rec-2951-dup-0,matthw,tombleson,37,blackett xrescent,coranidrk,broken hill,3046,nsw,19410702,4972641 +rec-2303-dup-0,peter,ha ge,3,maclaurin crescent,,ormond,4704,tas,19190517,6174860 +rec-4370-dup-0,berryman,mikayla,1,luckinsplace,bulga wine estates,captains flat,2067,vic,19130516,8135586 +rec-4242-dup-0,solomon,morrison,67,jarrahdale street,yalda ra,empire bay,2907,qld,19400406,5013206 +rec-2497-dup-0,maya,webb,927,woodful lloop,birubipoint caravn park,tolland,4300,qld,,1365038 +rec-4960-dup-0,alisha,winfield,17,guerin place,gummyg ully,altona north,3561,nsw,19760414,8806168 +rec-277-dup-0,emiily,frebeorn,8,may maxwell crescent,melinda lodge,kilsyth,7325,wa,19250411,6206529 +rec-578-dup-0,kai,widdowson,33,frost place,kemminu pfarm,burpengary,6707,qld,19731112,8416181 +rec-2096-dup-0,deakin,secokib,10,gelane street,palm lakevresort,raby,7052,nsw,19830930,3116371 +rec-2819-dup-0,polly,nguyen,278,raiwallacourt,willaroo,beaconsfield upper,3029,qld,19260902,8797418 +rec-3007-dup-0,elly,webb,11,gouger sthreet,everxgreen,leichhardt,2550,nsw,19240923,6770160 +rec-3231-dup-0,hayley,covwno,18,von guerard crescent,karingah,oatlands,2380,nsw,19151011,1653948 +rec-3589-dup-0,patrick,wasley,8,barwon srteet,llangollen,winmalee,2538,nsw,19860312,9514502 +rec-2351-dup-0,jack,white,35,fiveasha street,meadowvale illage,noble prk,2759,qld,19900716,7111367 +rec-1272-dup-0,pearson,reid,19,hodgkinson street,mar enoe,woodcrfot,4815,nsw,19101109,1582056 +rec-1136-dup-0,lachlan,clarke,19,bunbury street,kildurham,nhill,3850,nsw,19180501,2371774 +rec-2479-dup-0,harvey,dunstone,23,merrett garden,guest hse,macedon,2097,nsw,19150106,9370500 +rec-184-dup-0,tiana,worthington-eyre,10,hassell place,governosr resort,corrinal,6112,qld,19171101,3674431 +rec-604-dup-0,alexander,heron,11,damalastreet,,westmeadows,5159,vic,19660531,1400642 +rec-3546-dup-0,oliver,tiede,248,kendle green,scrivener street,mentone,6280,nsw,19101129,3891450 +rec-4445-dup-0,tara,nguyen,38,anembo street,hattah-uklkyne,kurri kurri,4405,nsw,19640410,8872454 +rec-1240-dup-0,kyle,kyricaou,6,brigalow street,kilacloran,surfersp aradise,2528,vic,19560704,6294045 +rec-4907-dup-0,harry,whiteway,19,fernyhoug h crescent,c f vkllage,loganholme,5062,wa,19310808,6408389 +rec-3797-dup-0,isabekla,hoehne,8,casuarinam street,wai iti,salisbury,2452,nsw,19880607,4585386 +rec-4258-dup-0,kalli,bisjop,36,,moon bni,yarrasnga,2750,wa,19020306,4667624 +rec-98-dup-0,elana,mchenry,80,gurnaiplace,umavale,eatin,4215,vic,19304302,4214409 +rec-1746-dup-0,lucy,callahan,73,bainbridbe close,bungarra,rowville,4209,vic,19430602,9663021 +rec-1860-dup-0,christpher,millar,12,piddington street,cannonvale whitsunday shopping centre,lavington,5047,qld,19250807,1831647 +rec-2744-dup-0,newpirt,catherone,13,hawkesbury crescent,nedlyn,pinjarra,4870,vic,19580901,1828218 +rec-1810-dup-0,fraser,miles,8,bungonias treet,hartley st school,kardinya,3728,vic,19390405,8206238 +rec-4158-dup-0,matthew,nguaen,273,hugh mckaymcrescent,katherinol ow leve,,4560,act,19320414,5765039 +rec-3927-dup-0,holly,rees,5,dangar place,thomond,sylvania,2541,vix,19740419,6279787 +rec-4807-dup-0,nathan,,1582,collings street,dalmoora,scarbo rough,2350,nsw,19591112,1760594 +rec-1329-dup-0,rubh,morrison,,armidal e hospital,nemarang crescent,avoca ebach,2100,,19280502,4180920 +rec-4607-dup-0,sarauh,noble,75,perrin circuit,westside,glenside,0216,vic,19010712,3254420 +rec-747-dup-0,cadec,coleman,21,damala street,mater professional centre,minchinbury,2280,sa,19471123,8098924 +rec-4985-dup-0,alissa,ryan,22,boobialla street,urimbira,seaforth,6018,nsw,19990829,1669592 +rec-797-dup-0,shantal,novak,9,hall tsreet,freo nbrae,cleveland,6110,vic,19000303,3342200 +rec-22-dup-0,tayah,white,15,stenhouse close,,mona vale,2206,sa,19390323,2815977 +rec-3362-dup-0,adam,nguyn,13,stokes street,,weerite,3216,vic,19461273,6333286 +rec-4943-dup-0,hilton,timothy,,coventr y close,killuke,goonellabah,5034,nsw,19241018,8085483 +rec-3529-dup-0,joel,cerins,24,majura lane,bungarra,matraville,4146,wa,19860411,6230406 +rec-4623-dup-0,isabella,white,5,glenore,clavert place,myrtleford,7310,sa,19651115,3189046 +rec-2889-dup-0,liam,webb,37,river street,medicalh centre,whittington,2088,sa,19131010,2490042 +rec-4373-dup-0,jack,carvone,55,wrenfordsley place,,moira,2038,vic,19710726,1202844 +rec-977-dup-0,jordn,ryan,41,schutt street,euroka,o'connor,4306,vic,19030111,1659852 +rec-2416-dup-0,ella,chell,,lawrence close,sec 301,harris park,4650,wa,19230110,9573051 +rec-1382-dup-0,bridget,maynrd,82,barwon station,irvine street,bassendewan,4503,nsw,19250615,7440041 +rec-2665-dup-0,erin,te kawau,5,namatjira drive,glen are,magill,2324,qld,19641126,6335645 +rec-2566-dup-0,kelsye,bullock,19,torreny s place,the meadows,williamstown,5251,tas,19581001,3037931 +rec-306-dup-0,samuwl,loos,60,gilday place,eriswel lpark,kintoss,2646,,19350908,9238386 +rec-3926-dup-0,stephannie,reid,4,bugden avenue,,avaoln,2290,nsw,19351106,1287472 +rec-1972-dup-0,joshua,trenerry,104,tenison-woods circuit,camusfearna,edensor park,2177,tas,19900810,8678668 +rec-782-dup-0,cheynene,nguyen,33,mary potter lircuit,vicsrcossing,bibra lake,6156,qld,19240128,2029887 +rec-1367-dup-0,isabelle,morrison,72,majuraavenue,rockviiew,sherwood,4164,sa,19940413,5896664 +rec-969-dup-0,alexandra,clarke,17,hancocks treet,currimundi garden,st albans,3204,sa,19311219,6631451 +rec-4819-dup-0,hayden,kluske,25,kanooka street,grenoble,bonnyrigg,4740,nsw,19111028,9665354 +rec-416-dup-0,zanelli,harrison,62,britten-jones drive,weeroona,exeter,4305,nsw,19870724,8743573 +rec-4965-dup-0,daish,william,500,osburn drive,pink lake caravan park,eastwood,3085,nsw,19311114,8646353 +rec-3268-dup-0,makenzi,weaver,10,pandanus street,the homestead,springfield,2745,vic,19370123,3748458 +rec-2699-dup-0,angip,wimmre,,baracchi crescent,mawarra herefords,marsden,2406,sa,19700928,3795146 +rec-2374-dup-0,,nguyen,9,chaselnig street,,burwood east,2122,qld,19560901,4833200 +rec-3221-dup-0,rilte,ryan,14,getting crescent,grandview,paringa,2148,nsw,19720205,2526000 +rec-1527-dup-0,thaker,harrison,31,foveaux street,the meadwos,orange,5453,nsw,19960724,9919852 +rec-1446-dup-0,christopher,,39,haugh place,athlone,blacktown,3766,nsw,19230116,8362475 +rec-2164-dup-0,channing,genovese,193,fernyhough bcrescent,cockatoo,clayton,7140,sa,19570424,4371940 +rec-592-dup-0,chloe,camp,25,euroka street,llantwit house,norwood,6149,nsw,19351005,4550681 +rec-3804-dup-0,benjamin,hartland,,ranken place,sorrento,collie,3799,qld,19080206,7081202 +rec-1572-dup-0,josgua,nguyen,11,beattie crescent,altona,casino,3029,vic,19240622,8948695 +rec-4942-dup-0,rachel,karlovcec,5,alberga street,,eastern heights,3228,nsw,19250114,9531225 +rec-4263-dup-0,samantha,crouuch,,crisp circuit,medical centre,roselands,3199,nsw,19280914,9016486 +rec-4415-dup-0,trais,wang,10,hawken street,draytony villas,airlie beach,4121,vic,19810617,5809880 +rec-1318-dup-0,,white,24,maddock place,headland garden,roseb ay,2380,qld,19560217,8506035 +rec-3714-dup-0,tayah,pascoe,595,o'halloran circuit,stonehenge,salisburh east,2285,nsw,19410809,9400248 +rec-3747-dup-0,jakce,hanks,11,meares place,,mentone,2038,nsw,19380614,4349715 +rec-3731-dup-0,,lamprey,16,bavin street,,goodwood,3260,nsw,19490504,2250069 +rec-2634-dup-0,croker,cambell,4,baldwin drive,wemyss,moodiarup,0836,act,19741117,1734947 +rec-3555-dup-0,thomas,huntinbg,880,shannob circuit,aboriginal nhluunbuy hostel,port macquarie,2904,vic,,7068400 +rec-2693-dup-0,makayla,malpas,255,musgravlhouse,hallen lcose,sippy downs,4214,nsw,19361113,9173799 +rec-2651-dup-0,wizlliam,,127,mataranka street,retirement village,mundingubrra,5211,nsw,19350212,5998994 +rec-899-dup-0,robert,gibb,2,springcreek,mckeahnie street,frankston,2450,wa,19440618,9181026 +rec-2293-dup-0,ava,spark,60,larkin close,,mulgrave east,3203,nsw,19470913,5766734 +rec-1171-dup-0,blake,kontopopulos,1,coolinda,genoa sreet,penrjth,2673,wa,19181122,4193541 +rec-2729-dup-0,danika,colquhoun,,summerlandcircuit,victoriadquare,willagee,3194,qll,19661116,9078185 +rec-378-dup-0,william,mason,14,bindaga street,unt 2,yackandandah,3150,nsw,19780603,3588709 +rec-427-dup-0,jordan,vincent,7,carnegie crescent,darg am,floreat,3032,nsw,19101107,3591952 +rec-751-dup-0,emiily,greedn,47,craig lace,rosemeade,ashfield,3095,nsw,19580116,4427542 +rec-1615-dup-0,,lydlon,79,heard stgeet,sennocke,ashfield,2285,vic,19631207,6564471 +rec-1198-dup-0,lucas,whiten,56,mcgivern crescent,,prospect,4650,vkc,19400902,2640399 +rec-4483-dup-0,amy,berry,241,barlee olace,barrcalear,christiemdowns,6056,vic,19651223,9112808 +rec-118-dup-0,hannzh,carbray,5,rawson street,cranbrook,mayfield,2032,wa,19170912,7822273 +rec-4543-dup-0,xavier,moorby,38,cockburn street,granite hills,windspr,4740,nsw,19570817,7332449 +rec-4300-dup-0,elana,camepbell,12,crisp circuit,broughton brook,midland,2768,qld,19720103,9877933 +rec-2520-dup-0,jessica,wintulich,224,hoseaso nstreet,yarrambah,,3133,nsw,19380330,8634113 +rec-3600-dup-0,brooke,rabbitt,46,cockcroft avenue,swalneigh,coolum bdach,6110,wa,19080421,6122971 +rec-1063-dup-0,schmitzer,zachariah,5,alford place,rosetta village,budgewoi,5052,wa,19560103,3180656 +rec-4518-dup-0,ryan,jack,23,popplewell place,condor,applecross,3156,wa,,1285717 +rec-1381-dup-0,bullock,samuel,6,fuhrman street,,casino,4165,nsw,19760505,1377013 +rec-897-dup-0,cameron,shephrd,16,cliftcrescent,nurock,northgate,2340,qld,19620826,1930383 +rec-3491-dup-0,chelsea,malcolmson,12,chalker circuit,woodlaigh,moonah west,6233,vkc,19281114,4413674 +rec-4837-dup-0,charlotte,humphreys,10,jemalong wstreet,danica,lennox head,4655,vic,19450417,3763315 +rec-559-dup-0,olivia,david,78,alabastwer street,lindoran,oak flats,4035,sa,19210322,8629017 +rec-2232-dup-0,louise,grossman,5,maddison cjlose,langunyah,north ryde,5253,nsw,19251101,9474636 +rec-1637-dup-0,ninhcich,kierra,17,mehaffey crescent,old farm,northmead,3028,wa,19530926,2089030 +rec-4322-dup-0,hewson,seanb,17,christmas street,champsaur,wantirna,2203,nsw,19180917,5004753 +rec-939-dup-0,ykle,hope,26,bundey street,kacadoo,armidale,2097,nsw,19631116,2650117 +rec-1043-dup-0,lam,sted,61,traeger street,table montain,rowville,7101,nt,19110729,7786184 +rec-1186-dup-0,harrison,du,22,cooks treet,green abnk,adelong,5244,wa,19320522,6650303 +rec-3099-dup-0,,reid,6,,ardrossan,rinwgood,4701,vic,19620822,7700094 +rec-4527-dup-0,april,nguyen,7,,mungru p stud,branxton,2018,qld,19210113,1634109 +rec-1825-dup-0,jarvis,lutz,290,brand street,the tops,belmont north,2106,act,19050520,5963506 +rec-3863-dup-0,jack,dancey,174,wells g arden,,taree,2216,vic,19311206,1490674 +rec-4832-dup-0,carlin,flannery,67,namadgi circuit,regal oaks rteirement vlge,swan hill,4191,vic,19240419,3896653 +rec-3372-dup-0,janegs,bishop,4,taronga,jemalong street,tweed heads south,7250,nsw,19540224,7589870 +rec-4109-dup-0,louise,bowermqn,27,nelson place,,keysborough,3805,vic,19141204,7234868 +rec-1546-dup-0,emiily,white,12,crago place,rockela,mosman,3300,vic,19390429,6209600 +rec-2039-dup-0,marcus,chandlef,5,rason place,,blacks beach,2226,vic,19700417,1098082 +rec-4224-dup-0,christopher,felmingham,,tallaraparkway,the provincial,moree,2195,sa,19600327,7478108 +rec-657-dup-0,danika,mcvciar,25,maclagan street,rosed ale,canterbury,4350,vic,19550817,3962564 +rec-3022-dup-0,renee,hanigan,109,epenarra close,al eon,flemington,5048,wa,19070928,2588263 +rec-3092-dup-0,ashton,boyes,,westgarth street,cherrymount,mount pleasant,2125,act,19440329,5428639 +rec-521-dup-0,courtney,clarke,24,myles connell crescent,,northgate,4621,nsw,19410813,8144739 +rec-1505-dup-0,emiily,dent,27,gungurra crescent,redlands,whyalla,3775,nsw,19960112,9836985 +rec-4701-dup-0,sean,varcoe,29,osburn dtive,bonaza aprk,ferndale,4569,nse,19601031,7839163 +rec-1987-dup-0,camefon,prideaux,50,evenstar,oakes sreet,condon,6164,nsw,19990615,3537526 +rec-2618-dup-0,kristen,reid,5,mckillop circuit,casuarina village,forest hill,3128,qld,19830801,8552844 +rec-1828-dup-0,emiily,crapp,3,couchman c rescent,glendower,ramsgate,2035,nsw,19500106,6187478 +rec-2200-dup-0,kiria,pamnany,02,gatton street,,beechmont,4301,vic,19040202,8371110 +rec-904-dup-0,claudia,bowerman,66,fidge street,ashgrov e farms,salisbury,3328,vic,19060517,3167418 +rec-472-dup-0,mason,o'shannessy,223,claxton crescent,parkmoor,hahndorf,3111,nsw,19251019,8544264 +rec-970-dup-0,jessica,vick,45,leahy close,villa74 village glen,scarness,2027,vic,19830919,8778791 +rec-4069-dup-0,jeremy,matthews,70,spensley place,pandoraoorchard,cecig park,3035,act,,6692321 +rec-265-dup-0,hamiah,teague,46,middleton circuit,coloolivillage,matraville,4128,nws,19731030,9222441 +rec-4302-dup-0,molly,roche,59,willoughby crescent,donna vblaley,carrxara,4825,nsw,19200712,1847058 +rec-1733-dup-0,brianna,singleton,7,agoni s close,,muleala,2067,act,19510311,7420967 +rec-3948-dup-0,thomas,berrgy,71,plowman place,linto n vlge,daw park,5159,nsw,19010714,5972566 +rec-4408-dup-0,aidan,bishop,36,mcintyre street,un t2,sidmouth,3011,nsw,19490620,1383389 +rec-803-dup-0,abbey,crisci,23,gorge creekorchards,spence place,cygnet river,7030,,19890327,7400712 +rec-573-dup-0,james,bissett,115,ellerstonx avenue,pepin,hawthorn,3268,sa,19400613,5935841 +rec-2340-dup-0,zachary,ban,4,maurice place,cabbage iree,moore,6011,as,19710105,4571622 +rec-3932-dup-0,meaney,jard,2,northbouryne avenue,york hopse,mitxham,3141,qld,19431210,3744694 +rec-3427-dup-0,jackson,herbert,15,gooreen street,ripple brok station,highett,4870,vic,19170311,3155721 +rec-2808-dup-0,emiily,lowry,13,chaseling street,,ingleburn,2193,nsw,19940616,9820630 +rec-3971-dup-0,emiily,kutschki,,ebden street,colleton,elwood,2425,nsw,19451004,3187789 +rec-1807-dup-0,maya,nevin,351,rapanea street,chelseahouse,evanston,2033,,19220204,5095261 +rec-3524-dup-0,lachlan,matthews,6,mcmillan crsecent,corcoran,miriam vale,2009,nsw,19420818,7138643 +rec-3266-dup-0,vavic,ben,62,blamey crescent,paling south,kyogle,3170,wa,19410903,5394712 +rec-1125-dup-0,callum,jancek,2,darley p lace,garema plae surgery,ballarat zorth,4745,nsw,19201229,2980733 +rec-2301-dup-0,finlay,danien,150,pethebridg e street,rosetta village,samford valley,2119,vic,19020614,3997416 +rec-954-dup-0,noah,painter,50,kingscote crescent,tewantinplaza,drillham,4650,vic,19590501,2779286 +rec-618-dup-0,crouch,ella,1710,amadeus zplace,sec 1,clifton saprings,4304,nsw,19870511,5975406 +rec-1176-dup-0,kierra,burford,32,adamson crescent,lee graznig farm,bayview heights,5080,tas,19100914,4902237 +rec-137-dup-0,pa ine,thomas,215,ina gregory circuit,stoneoak farm,kilcoy,7330,wa,19881207,2550718 +rec-127-dup-0,imogen,boyle,57,gilmore crescent,,safety bay,3088,qld,19360622,4299143 +rec-4686-dup-0,blake,dudlry,14,pethebridge street,lorrachael park,cowra,6045,qld,19050703,5970471 +rec-1295-dup-0,abby,ang,21,dunstanstreet,the parks,belmont,4125,nsw,19830621,8045581 +rec-3386-dup-0,alisa,kalinowski,99,,river quays,lavington,4878,vic,,9382250 +rec-4199-dup-0,,ryan,42,beazley crescent,shaudell,torquay,0830,sa,19820718,9041834 +rec-2636-dup-0,cheyenne,petersen,5,tauss place,kacadoo,abbotsford,3630,vic,19790602,6593871 +rec-415-dup-0,neneh,large,14,onkaparinga crescent,heritage manor est,woolladdra,4352,sa,19950725,8160717 +rec-4629-dup-0,tiarna,burghof,1,,delmar,east maitkand,2550,vic,19911125,8808422 +rec-3624-dup-0,,manzie,33,hemmant street,lasswade,ormons,3150,qld,19560714,7289058 +rec-3690-dup-0,jackson,weaver,4,tenison-woods circuit,,glenmore park,2776,vic,19881101,4634662 +rec-2236-dup-0,alexandra,finlay,3,erldunda circuit,neaavie,cooroy,2147,nsw,19600723,4039238 +rec-120-dup-0,tynn,,2,gallegha n circuit,,wakeley,4655,wa,19800407,1022048 +rec-4802-dup-0,laim,wilkins,2,hansen circuit,foresdtale,sadleir,5018,sa,19530304,6164019 +rec-3785-dup-0,abbry,stephebson,67,duggan street,makowat a siding,elwood,2095,nsw,19520731,3195277 +rec-853-dup-0,ty,green,411,hughmckay crescent,,mullumbimby,3550,nsw,19520829,7797381 +rec-3424-dup-0,riley,clarke,12,edwell hplace,bonnie,eatons hill,3218,nsw,19570717,3007913 +rec-1870-dup-0,talia,feast,21,dorrit bladk crescent,the stociyards,burnie,6063,vic,,8284375 +rec-2898-dup-0,,mcgregor,214,keys crescent,cooloolafarms,bouler,3072,nsw,19480329,6504301 +rec-698-dup-0,benjamin,constance,15,coventry close,omeo,wahroonga,3079,qld,19620628,4562356 +rec-3501-dup-0,calev,blake,15,hawker street,,adamstown heights,3020,nsw,19530105,6351072 +rec-3236-dup-0,christopher,pegg,56,martens crescent,diamon dsands,embleron,2577,qld,19200214,5556197 +rec-3345-dup-0,bailley,fair,27,laceyp lace,sunny-bfae,auburn,3757,wa,19730509,9201283 +rec-129-dup-0,ebonie,myles,262,inlander crescent,,albany creek,2250,qld,19300201,8494390 +rec-3656-dup-0,robert,leslie,12,crozier circuit,mt pleasant,garbutt,2259,,19670110,3509633 +rec-1813-dup-0,louise,butt,20,chirnside circuit,robiny,mclaren vale,7004,vic,19250204,4646918 +rec-677-dup-0,skye,ryan,39,anningie place,terra notra,macedon,3097,sa,19941118,8669770 +rec-39-dup-0,gabrielle,blaje,360,hardwick crescent,carramar home,camp hill,2001,qld,19960302,5207765 +rec-256-dup-0,arabella,holyoak,49,hughes crescent,b,malvern,4405,wa,19280311,1284712 +rec-197-dup-0,ruby,nguyen,26,barraclough vrescent,,st peters,4011,qld,19521110,8292725 +rec-272-dup-0,annabel,thorpe,5,thake place,parry house,mulgrave east,2573,vic,19480708,1654518 +rec-544-dup-0,jasmine,wardle,25,smiths road,westholme,prospevt,5007,nsw,,7650116 +rec-4010-dup-0,joshua,morrison,26,dixson circuit,glenfyne angus stud,adelaide,2071,,19870429,7034895 +rec-4237-dup-0,paine,braedon,15,edwards street,narellanc ourt,young,3300,qld,19871225,8743183 +rec-3255-dup-0,micaela,harrington,9,burrinjuckcrescent,loc n 2192,condellwpark,3175,nsw,19971004,2317861 +rec-2720-dup-0,cailin,berry,6,hakea rcescrnt,lort he ights,cronulla,2093,nt,19590328,5662864 +rec-719-dup-0,madison,penberthy,12,dunbar street,,villawood,4621,nsw,19931005,4607576 +rec-4794-dup-0,olivia,shepherd,19,santalum street,the wllows,lismore,5277,vic,19610121,2441128 +rec-2535-dup-0,montana,lowe,18,stanfield close,,plympton south,2111,vic,19230424,5226883 +rec-4917-dup-0,,staunton-smith,68,kookaburra village,frome street,broken hill,2870,vic,19820117,6922783 +rec-2845-dup-0,jack,harrington,1385,gladstone street,amberu,watsonia,4066,nsw,19820311,7610085 +rec-570-dup-0,taylah,oats,47,federal highway,scotch college,armidale,2125,nsw,19300715,9175271 +rec-145-dup-0,kieren,steers,10,whittell crescent,lomo,east innisfail,2280,nsw,19060603,1532338 +rec-4539-dup-0,isabella,longman,7,eucumbeneq drive,kooyonp,lalor,5157,vic,19460810,4725516 +rec-3972-dup-0,mason,charlotte,16,ratcliffe crescent,barooa,hackham,5703,vic,19060923,6430306 +rec-1845-dup-0,gabrielle,telleglou,163,huelin circuit,,st john spark,2126,nsw,19820403,3405740 +rec-2298-dup-0,joshua,hendy-pooley,3,staceplace,nuffield iillage,oakddn,6108,vic,19160101,5515164 +rec-199-dup-0,william,kammermaann,6,clive steeleuavenue,2nd last on right,newcastdle west,2804,vic,19430126,3515659 +rec-3521-dup-0,spencer,bates-brownsword,151,tora,pinkerton circuit,smithfield,4860,nsw,19810308,5402648 +rec-128-dup-0,jasper,rylands,10,abernethy treet,,ingleburn,2784,nsw,19730615,9353426 +rec-4731-dup-0,aleisha,mason,120,appel cerwcent,gillin park,tanilba bay,3936,nse,19860522,3858465 +rec-4924-dup-0,reid,william,12,tatchell street,st george spark,hoppers crossing,4814,nsw,19750418,1498408 +rec-9-dup-0,paris,reid,39,crowder circuit,,st ives,3225,vic,19980826,2543313 +rec-3871-dup-0,jessica,kranz,,the mews royalhhotel bldg,brunton street,norwood,5159,sa,19880226,7412923 +rec-739-dup-0,joanns,neighan,41,berkeley street,wychwood,premer,2203,sa,19381128,3927665 +rec-3564-dup-0,chloe,clakre,91,hurtle avenue,avonwood,martinville,4152,act,19760805,6520116 +rec-1737-dup-0,levi,prideaux,10,beckett tsreet,,milprrra,2606,wa,19230510,9135299 +rec-976-dup-0,isabelle,campbell,1,jukes street,pinei tree,port fairy,4811,qld,19820103,6554212 +rec-1483-dup-0,calvin,steed,24,hamelin crescent,,preston beach,4214,nsw,19300502,9340008 +rec-2291-dup-0,kle,kalogerakos,,aird place,cassis,granvlle,4680,wa,19950119,4748391 +rec-4260-dup-0,mia,neeb,5,,pine hill,stonevlile,2110,wa,19730518,1310519 +rec-2325-dup-0,ajay,poumacko,100,bedford street,youralla,rostrevor,3029,qld,19540417,4762088 +rec-248-dup-0,havriluk,jacinta,47,macquar ie street,carrington r etrmnt vlge,paralowie,7030,wa,19150929,7263381 +rec-3908-dup-0,emiliy,bradshaw,19,parkhill street,foxdown,south grafton,4287,vic,19270912,2964855 +rec-2760-dup-0,tyler,vincent,4,cambridge street,kintyre,deagon,3151,vic,19950713,3309482 +rec-369-dup-0,caitlin,dixon,42,leahy close,rowethorpe,midway point,3926,nsw,19980907,6375470 +rec-2550-dup-0,katie,noble,16,torrens street,old hiloside,rose bay,4510,nsw,19050728,6816111 +rec-3792-dup-0,jack,marcaros,59,goyder sreet,st johns t errace,ormeau,3104,qld,19810311,5200718 +rec-178-dup-0,kirra,okonieewski,11,,molyneu xhse,kardinya,5330,nsw,19700823,2077704 +rec-760-dup-0,nguyen,lachlan,70,bushby close,locheil,wilson,5046,nsw,19660926,4360586 +rec-2569-dup-0,lara,bennier,16,mccormack street,yalgora,dandenong north,4122,nsw,19490422,4493543 +rec-1605-dup-0,jackson,kellow,2,dumas sireet,rocklea,hamilton,6029,wa,19660925,8602157 +rec-3841-dup-0,leslie,esme,3,galleghan circuit,five aoks,brighton,6007,tas,19520521,7091838 +rec-3063-dup-0,kynan,beattie,2,narrabundah lane,banana hshed,ferndale,2680,nsw,19080412,4383141 +rec-2735-dup-0,adam,barnetosn,3,wicks rqoad,,vermont,2234,nsw,19770922,1249535 +rec-4494-dup-0,thomas,montalvo,209,,medical v entre,wanniassa,2905,sa,19020302,9993328 +rec-4888-dup-0,caitlyn,pallot,149,pine islan road,nuffield village,hightbon,2792,nsw,19660115,3051696 +rec-878-dup-0,elton,rushby,2,charleston street,toowwoomba,wyoming,4382,nsw,19320419,3833752 +rec-2349-dup-0,maruc,parr,11,hilder street,glemn ore,braidwood,4810,vic,19460725,4267000 +rec-3461-dup-0,gabrilele,clarke,24,troughton m street,unt 3,,2114,qld,19440219,9711144 +rec-1692-dup-0,emiily,finalay,13,lawrence close,upton,boddingnton,2485,nsw,19800129,5998213 +rec-775-dup-0,gemma,brain,536,lingiari court,flt 167,ancona,3130,sa,19261125,8731806 +rec-346-dup-0,,nabialek,,warby place,somerset cottage,margaret river,2224,sa,19191126,2473424 +rec-820-dup-0,abbie,finlay,5,,unt e1,mount warren park,4350,nsw,19730526,4857274 +rec-752-dup-0,georgia,weidengbach,4,marou place,blueberry,innaloo,4068,vic,19280919,5368290 +rec-4786-dup-0,talissa,passmore,115,lyall crescent,yarrowe efarm,ashfield,3152,tas,19621214,2120101 +rec-3605-dup-0,dimitri,hopel,24,demaine crescent,canberra centre,port addelaide,2131,nsw,19541110,7206463 +rec-2431-dup-0,siendna,lock,5,outtrim avenue,seaforth senior citizens vlge,coopers shoot,4119,vic,19650410,3787467 +rec-3490-dup-0,cooper,kernvey,11,phillimore place,boeing park,thornbury,3356,vic,19340713,6518170 +rec-3507-dup-0,gemma,lowe,77,currie c rescent,,san remo,4208,sa,19730809,7414003 +rec-2393-dup-0,symmons,ruby,32,miller street,locn2093,rosslun park,2069,sa,19351025,3976926 +rec-1085-dup-0,julia,commons,33,nungara street,glenhubrst,chester hill,4470,wa,19350922,1606130 +rec-3607-dup-0,zali,shadnolt,1,yassr oad,rowethorpe,cronulla,3911,vic,19771225,7247098 +rec-2294-dup-0,tasman,green,36,wynns greet,nixon nostel,pentith,2132,qld,19390608,2928427 +rec-4724-dup-0,,bristow,11,minter place,wilsonton medical centre,ngunnwaal,4551,vic,19890212,7893433 +rec-1164-dup-0,imog en,vinxent,78,brazel street,,penrith,5280,qld,19130303,9001480 +rec-972-dup-0,sophie,bacchus,11,adamson c rescent,tweed heritage caravan park,katherine,2036,nsw,19700707,3628289 +rec-257-dup-0,daniel,ryapn,3,de littlev ircuit,the lakes retirement village,brighton-le-sands,2400,,19920826,6267294 +rec-4839-dup-0,alexadra,,31,woodger place,tinaroo falls,pannawonica,2650,wa,19850302,2175226 +rec-68-dup-0,riy,howie,59,reader clurt,rosebery hill,wanniassa,4213,qld,19360115,9350479 +rec-1937-dup-0,nicholas,wikde,46,renny place,golden pohds,leongatha,4153,vic,19961119,7886527 +rec-2616-dup-0,webb,hari,1,throssell street,malmani,springfield,5108,sa,19270216,3864525 +rec-3867-dup-0,ethan,wihtr,,barwell place,ore el,ashfield,3941,sa,19830825,2215887 +rec-1069-dup-0,ameljia,lowry,54,jandamarra street,ellwood,kinglake east,4280,qld,19231009,2439451 +rec-2861-dup-0,katherine,lovk,16,kootingas treet,,montmorency,3023,nsw,19400714,9161147 +rec-4130-dup-0,sophie,mason,20,mt providenec hostel,johnson place,hope vlaley,6056,wa,19580507,9799282 +rec-3983-dup-0,benjnin,paine,10,,rose lane entre,,2406,vic,19531018,3571554 +rec-4284-dup-0,sophie,finlay,7,badimara street,ewlyamartu farm,ringwood,2064,sa,19230607,3775980 +rec-3487-dup-0,emiily,white,26,marrstreet,,lower templestowe,3161,vci,19290127,4621716 +rec-141-dup-0,peta,callister,16,baracchi crescent,jaholmazpark,moranbah,2117,qld,19871125,4177367 +rec-1077-dup-0,sarah,dixln,107,corellawplace,stapleton tsation,kelmscott,2304,qld,,1565265 +rec-4506-dup-0,samantha,ryan,16,forsythe street,murrawarra,winthrop,4800,nsw,19100120,2049414 +rec-4776-dup-0,georgia,metaxiotis,15,augustus way,,tuart hill,3196,vic,19130627,5883327 +rec-1577-dup-0,lachlan,stamley,28,cottam place,plainview,mounta samson,7310,nsw,19740824,4200578 +rec-1897-dup-0,isabela,pride,29,porteousjcrescent,,black rock,2062,vic,19630926,7058877 +rec-2259-dup-0,hayley,hanna,240,burhop close,peridon vlge,ryde,2230,nsw,19491020,3697216 +rec-4570-dup-0,kyle,block,45,erldunda circuit,mt warrigalretrmnt vlge,greenacre,2614,nsw,19740424,4380571 +rec-2166-dup-0,isabelle,geraghty,16,hawdonstreet,council accomm,theodore,4812,nsw,19861012,4201009 +rec-2948-dup-0,kylie,browne,11,clancy street,,tamborine,3812,nsw,19040712,4522939 +rec-1170-dup-0,grace,morrison,5,groom street,hellemere village,concord,3510,wa,19321010,3352261 +rec-2471-dup-0,anthony,lavis,198,titheradgeplace,kalyra retirement,new farm,3130,qld,19000617,9007184 +rec-438-dup-0,heatn,alison,4,macdonnell street,cabrini medicalb centre,adelaide,2270,vic,19191230,2937695 +rec-3012-dup-0,hannah,sandman,32,mcinnes street,,lewiston,3134,sa,19690707,2339019 +rec-593-dup-0,brend an,chabrel,39,medworth crescent,thistle da le lodge,buninyong,6028,qld,19290327,1315588 +rec-3343-dup-0,holly,simmonds,26,sinclair sotreet,unt 2,sunnycliffs,3141,nsw,19970921,9812796 +rec-3510-dup-0,kimberly,mason,150,tauss lace,,rosewater,7008,vic,19840507,5663441 +rec-4711-dup-0,hugh,bsihop,42,denovan circuit,ironbark ridge,vermont south,4470,nsw,19790408,3465665 +rec-694-dup-0,kastrappis,charlie,81,hedler steret,parkland motor village,bonbeach,2515,vic,19330630,7470082 +rec-2127-dup-0,miranda,andresen,93,wenholz street,telopearpark,williamstown,2450,vic,19180404,1851874 +rec-1830-dup-0,caitlin,hanigan,298,,francis chambers,thornbury,5072,nsw,19680909,7831777 +rec-3779-dup-0,aajy,chetwyn,13,cope place,c/-the studen t village,,2164,nsw,19290222,6258884 +rec-1979-dup-0,lewis,coleman,9,northbourne venue,our folly,toowoomba,2145,nsw,19341227,4576898 +rec-2265-dup-0,benedict,vincnet,27,mcclaughry place,k mart p laza,cunnamulla,5047,qld,19721119,3291682 +rec-1284-dup-0,harriet,horsley,12,woinarski place,white lodge,mulgrave east,3280,wa,19710926,4215402 +rec-4659-dup-0,lucy,hemsmings,4425,mimosa close,kinloch court,lockleys,3850,nsw,19051023,3194253 +rec-831-dup-0,laura,flannery,54,sid barnes crescent,,winstonhills,5073,qld,19581023,9712180 +rec-2530-dup-0,harrison,gillard,18,melba street,ningafa,loganlea,2162,qld,19840128,8021771 +rec-3793-dup-0,mccarthy,lucy,29,charltonstreet,warrahlea,bundaverg,4061,qld,19940917,6596660 +rec-4556-dup-0,simon,,151,waddell place,northwest mediical centre,palmerston,2913,nsw,19590525,5350801 +rec-476-dup-0,klye,armient o,266,jaegerc ircuit,kookabura village,elwood,7307,vic,19570728,3494623 +rec-502-dup-0,laurn,berryiman,,doyle terrace,canberra avenue,menitndee,3016,vic,19390528,8295272 +rec-2323-dup-0,rachael,yallop,5,fullagar crescent,rsde 668,been leigh,4860,qld,19760214,1296128 +rec-2426-dup-0,taylah,timbrell,87,mcglinn pkace,villa 2,bligh park,2450,nsw,19440825,6149166 +rec-1726-dup-0,thomas,butt,,hindmarshdrive,mayflower rtermnt vlge,currans hill,3799,qld,19290620,2143953 +rec-579-dup-0,braedon,bindoxff,9,eve place,moreton,hamiltpn,2099,nsw,,7181006 +rec-2168-dup-0,alicia,whiet,10,madigan dtreet,,barraba,3055,nsw,19620821,4067329 +rec-637-dup-0,campbelil,alexandra,15,paul coe crescent,laloki,woollahra,5108,nsw,19531022,3106590 +rec-2518-dup-0,thoonen,makayla,119,tullaroop street,rosetta village,byford,3977,vic,19750818,1423820 +rec-3321-dup-0,bradley,komsic,6,westbury cricuit,meadow view,adamstowv heights,2046,qld,19140420,5731419 +rec-4240-dup-0,solomon,hannagan,83,clemenger street,brookfield,forrestfield,4216,sa,19890520,3944717 +rec-3812-dup-0,dean,web,52,buggy crescent,mount patrick,stratton,3138,nsw,19171128,4129591 +rec-4656-dup-0,marcov,volpato,57,rabnor place,kurajong,spearwood,4242,nsw,19750312,4101153 +rec-2836-dup-0,joe,whitle,5,towers place,hyberni apark,coolaroo,2066,vic,19851122,1899363 +rec-2570-dup-0,jacob,coppola,3,smeaton circuit,deer farm,stanmore,3400,sa,19211130,8983109 +rec-4852-dup-0,tanyshah,praehofer,15,moogerah street,rosglen,woollahra,3875,nsw,19290421,7881845 +rec-3836-dup-0,erin,campbell,11,learmonth drive,lassaan,dulwich hill,4261,,19790408,5750866 +rec-2315-dup-0,flynn,laing,191,partridge street,,goonellabah,3021,nsw,19730524,8183648 +rec-4177-dup-0,paipne,nicholas,77,tara hills,neales street,richardson,5118,tas,19040321,2360796 +rec-4032-dup-0,,santi,1,griffiths street,rowethorpe,mckinnon,6163,nsw,19151129,2102559 +rec-126-dup-0,nikki,jaruic,13,renmark street,parishlorne,chester hill,2106,nsw,19520401,9272910 +rec-3109-dup-0,calvin,trumam,63,newton street,locn 3439,warilla,3104,vic,19331106,8583204 +rec-701-dup-0,,clarke,117,hurley street,weemilah,tallebugdera,4021,vic,19010403,4822857 +rec-4869-dup-0,taylah,reid,25,albermarlze place,cypress garden,pennant hills,2210,nsw,19571029,7596151 +rec-572-dup-0,courtney,whuet,4,green street,armidale private hospital,launching place,2800,nsw,,6763868 +rec-13-dup-0,thomas,slack-smith,106,hawkenstreet,emmaus vlge,kirwxn,2566,vic,19900607,2094894 +rec-1923-dup-0,kalli,garcia,12,mckivat close,leebold htll farm,clayfkeld,5022,qld,19990423,3214869 +rec-3071-dup-0,charlie,wakpbole,43,lampard circuit,the meadows,albertno,2750,sa,19260710,5982948 +rec-1660-dup-0,jessica,goode,24,gundamain,devonport street,tanilba bay,6104,qld,19620120,3222738 +rec-1857-dup-0,hugh,bartel,11,brewster place,blue hills,bakers creek,4069,nsw,19370522,7516697 +rec-4468-dup-0,tai,stanley,29,blamey crescent,ocean sta r villas,gordonvale,3915,nsw,19141011,4459842 +rec-139-dup-0,holly,sherrqiff,56,heagney crescent,winter park,devonport,2546,qld,19980309,5260793 +rec-771-dup-0,xantne,maynard,2,blackman crescent,rosab laenca,cooran,2196,qld,19110520,6070195 +rec-568-dup-0,katelyn,dountsis,111,goldner circuit,cremon astud,mulgrav eeast,2256,nsw,19430612,6491584 +rec-1387-dup-0,mitch ell,berry,2,roope oose,larook,torquay,2199,nsw,19190710,1968724 +rec-2538-dup-0,lynton,leonavicius,7,mcilwraith close,leitrim,kolora,4401,wa,19511227,8167665 +rec-176-dup-0,lraa,seychqell,20,ferber place,brentwood vlge,highgate,5501,vic,19060816,9577137 +rec-3809-dup-0,harry,matthews,1,dalmancrescent,timbara,leongatha south,2519,vic,19110203,4984322 +rec-4095-dup-0,sophie,campbll,61,belconnen way,hazel hill,,2323,qld,19210520,9019644 +rec-4099-dup-0,harrison,george,,woronoar street,south melbourne market,kangaroo flat,2450,nsw,19370115,3711821 +rec-4288-dup-0,ruby,staude,241,,crowedn,rose bay,3249,nsw,19410115,9633722 +rec-3789-dup-0,casey,fitzpatrick,34,hugh mckay crescent,glass house,hamilton,4178,nsw,19320411,3603835 +rec-2217-dup-0,alicia,curry,51,,yarrandoo,loganholme,4118,vic,19340827,2973687 +rec-4754-dup-0,ava,fuds,11,dines place,kings apmts,rostrevor,3250,tas,19580912,9818747 +rec-4565-dup-0,jarde,klemm,,,cowaryst ation,batemqn,6152,act,19770328,4616949 +rec-996-dup-0,emiily,finlay,61,coranderrk street,,ulverstone,3043,vic,19070731,9964204 +rec-3930-dup-0,isac,sherriff,6,britten-jnoes drive,wyuna,greendale,3976,tas,19330719,7421428 +rec-3880-dup-0,hayley,moody,1,lambell close,solitaire,jones yill,3013,nsw,19831231,7465219 +rec-1767-dup-0,keaton,webb,2,mckinleycircuit,solitaire,lemon tree passage,3943,nsw,19850328,6634675 +rec-1314-dup-0,michaela,motbey,43,badimara street,roweth oroe,rosebud,3345,nsw,19500318,3314402 +rec-3814-dup-0,jasper,dorling,155,dowling street,gateway vlgefcaravn park,upwey,2069,nsw,19470208,2142730 +rec-2877-dup-0,tori,mcgarrigan,2,hallen close,,bangor,6004,wa,19841007,5119714 +rec-2925-dup-0,lachlan,lanyon,33,maranao street,,elsternwick,2228,wa,19950930,4086155 +rec-1107-dup-0,shepherd,sybella,34,mainwaring rich circuit,,werrington,2118,tas,19460321,7440243 +rec-2042-dup-0,hannah,insley,4,wanganeen avenue,plumptonpark,drysdale,3199,vic,19921024,3031015 +rec-1140-dup-0,luke,beattie,16,blinkhorn place,lucerneoark,corrimal,4118,act,19211118,5586410 +rec-3195-dup-0,goode,bailey,57,,coolbellup hotel (c nr waverley r road,albury,4720,nsw,19100307,1906329 +rec-4225-dup-0,ruby,mcphie,12,hambidgecrescent,namarva station,ballarat,4868,nsw,19470101,3454863 +rec-2148-dup-0,nathan,green,10,franc p lace,tara p ark,marsden,3337,qld,19060131,8615544 +rec-3094-dup-0,jacob,heron,4,leebold hill farm,stubbs crescent,bilgola beach,4401,act,,2421446 +rec-2285-dup-0,madeline,bissett,3,wagga street,bonnie doon,port brolghton,3977,nsw,,8938036 +rec-357-dup-0,chelsea,blackwell,37,grounds crescent,c/o post o ffice,emerald,4210,sa,19390203,6074956 +rec-4879-dup-0,rebecca,clutterbuck,325,blair street,apt 0205,proserpine,4701,nsw,19350120,3520636 +rec-1663-dup-0,jaden,zepina,23,mayflower rerrmnt vlge,hawkesbury rescent,narellan,6053,tas,19030610,4672007 +rec-1244-dup-0,,oreskovic,16,marrakai strqeet,gooroomon park,ballaat,2035,wa,19710815,4253689 +rec-1804-dup-0,paig,di cesare,8,tardent street,apt 27,balwyn north,4560,vic,19791223,6112690 +rec-675-dup-0,jacob,margrie,,moulderourt,collaroy,clifyon,3840,vic,19130517,4315229 +rec-3070-dup-0,talia,lucadou wells,59,de little circuit,,forrestvield,4740,vic,19560221,2600068 +rec-1538-dup-0,lucas,sherrjiff,1,galloway street,renown,hoskinstown,5280,vic,19370430,7403002 +rec-3967-dup-0,ash,nguhen,54,mcmillan crescent,warraview,mount gravatt,4156,nsw,19230118,2770136 +rec-3093-dup-0,oliver,white,18,kinchela crescent,murray river queen,emu aby,2219,nsw,19340722,1420638 +rec-4446-dup-0,zachary,bradshaw,106,totterdell street,barossa village,colo hvale,3444,qld,19151219,6773922 +rec-3315-dup-0,dominic,jormaaninen,,geeves court,gretamain,,6025,vic,19880214,7639310 +rec-4386-dup-0,talah,rankine,14,kibby place,colooli village,dungog,7179,vic,19530816,8828523 +rec-558-dup-0,alicai,white,9,darrell place,,fletcher,2850,vic,19821015,7695489 +rec-1055-dup-0,hayley,white,,medley tsreet,raymond terrace market place,regents park,2656,vic,19391111,6020101 +rec-31-dup-0,laura,white,67,arndell street,,hoppers crowsing,6053,vic,19900615,7517707 +rec-3228-dup-0,harrison,stirland-mitchell,176,badimars street,wirreanda vlge,port augusta,2196,qld,19040106,3551585 +rec-2149-dup-0,mccarthy,mikaela,62,derrington crescent,,denistonw east,3564,vic,19821001,8749270 +rec-1498-dup-0,katie,fitzpztick,37,bourchier close,donore,hurlstone park,6108,vic,19380621,7125161 +rec-3834-dup-0,hannah,bishop,79,merriman crescent,,millgorve,4625,nsw,19740414,4492531 +rec-390-dup-0,rebecac,white,34,wilkins street,,campbelltown,5038,vic,19040710,3551789 +rec-4916-dup-0,india,etherington,432,buckmastercrescent,kurrajong,moree,4812,qld,19111101,5165691 +rec-3509-dup-0,hannah,reid,21,bisdee street,tall pibes,malvern,2478,qld,19840208,1762901 +rec-73-dup-0,eloise,afford,188,dennystreet,fairfield housing bg,caves beach,2118,nsq,19090702,8884493 +rec-3470-dup-0,dominic,aldedrson,309,clamp place,,bundamba,2767,sa,19871130,1163272 +rec-1994-dup-0,haylee,doaln,49,carrington street,brentwood village,deer park,3047,nsw,19690801,4703920 +rec-4384-dup-0,marley,,9,namatjira drive,dangaroo park,unanderra,2614,sa,19350812,3973825 +rec-1222-dup-0,faith,dougal,1,levey place,minora cotge,toowoomba,2905,nsw,19550808,1574726 +rec-1370-dup-0,breeanne,browne,5,ebeneze rtreet,kilburnie,toowong,5072,nsw,19511023,6301444 +rec-1473-dup-0,,leslie,952,carpenter close,,cantebrry,2340,vic,19950608,2438058 +rec-1928-dup-0,kyle,hawes,6,len waters street,castlesood,greensorough,3171,nsw,19090430,5553221 +rec-2719-dup-0,,negri,159,hageltho rn street,port rush parade,port macquarie,4702,qld,19260319,4740975 +rec-3548-dup-0,takeisha,white,6,chuculba crescent,melale uca,bundaberg,6062,vic,19350824,1092846 +rec-2645-dup-0,mackenzie,meandey,193,london cigrcuit,,franwston,2148,vic,19600306,9550123 +rec-4166-dup-0,ruby,masoin,18,hurleystreet,openshaw,samford valley,3805,qld,19420728,1047066 +rec-3402-dup-0,browne,anthony,118,,shalvah,elwood,5023,nsw,19320227,6105593 +rec-2771-dup-0,joshua,petersen,8,wybalen a grove,lyra park,surry hills,3162,vic,,4895026 +rec-2741-dup-0,mattheo,hazell,13,palmer street,jarlah,harbord,4116,qld,19240211,2546491 +rec-4722-dup-0,catherine,bishrp,29,stapylton street,,box hill south,2260,vic,19410527,6228462 +rec-2847-dup-0,emiily,boyle,25,bega fl ats,rose valley farm,loganlea,3141,wa,19220406,5388162 +rec-2419-dup-0,hawke-fitzhardy,bethany,10,horne place,,granville,2350,vic,19880416,1515136 +rec-3049-dup-0,joshua,bralic,76,myleshclose,old gre en hill,beaumaris,6108,vic,19110727,6708902 +rec-1591-dup-0,jasmine,clarke,489,,cambooya,noble park,3413,vic,,9562970 +rec-4349-dup-0,jare,white,33,dawes street,villa 3,sandy bay,2871,nww,19640307,2135501 +rec-2163-dup-0,ella,riddell,99,springvale drive,,melville,5012,nsw,19640405,5082521 +rec-1980-dup-0,caitlin,cheel,,herron cnescent,glenview,bligh park,3735,nsw,19661116,3957302 +rec-2201-dup-0,danielle,nygaard,1,battersgy circuit,iron shoe lodge,burwood,5271,nsw,19350414,2589501 +rec-3746-dup-0,marleqigh,paterson,28,canopus crescent,kirkladns,devonport,2800,vic,19820824,7472468 +rec-4078-dup-0,harrison,leung,36,catchpole street,,mountakn creek,3057,nsw,19640118,2584055 +rec-1529-dup-0,ebonie,campbell,32,gellibrand street,carowood,kessick,3148,vic,19271210,2544494 +rec-1229-dup-0,lauren,perrwe,22,castleton crescent,karinayh,oran ge,7250,act,19820605,6993851 +rec-1196-dup-0,matthew,bozzetti,79,braminastation,lakewoo destate,vermont,6027,qld,19670905,1057227 +rec-4865-dup-0,jory,musolino,26,steinfeld court,table mountain,moree,3134,wa,19381019,4887622 +rec-4764-dup-0,,dessart,165,macvitiewplace,brambletye v inyard,lindenow south,4218,,19361017,2517857 +rec-4195-dup-0,katelin,capmbell,16,sid barnes cdrescent,,forestdale,2450,wa,19240716,7296237 +rec-1068-dup-0,joshua,cupo,16,greglea village,gabriel place,lobethal,5126,qld,19670425,4178304 +rec-4482-dup-0,ewan,mildren,60,loftus tsreet,,bellevue hill,2001,wa,19941205,6218110 +rec-2918-dup-0,ella,perriam,17,chipperfield circuit,kingfisher lodge,north bondi,5022,act,,7801650 +rec-3770-dup-0,kirra,whige,24,bungoni a street,villa 3,kyabram,2036,tas,19290202,5171004 +rec-1467-dup-0,cameron,virgeln,51,wilson crescent,blacklead farm,stephens,2110,nt,19400306,5118228 +rec-1896-dup-0,ssha un,campbell,37,mcginnesd street,bexely,tarnagulla,3802,vic,,4088978 +rec-2056-dup-0,ethan,malvestuto,14,macnaughton street,veone,lauridton,2577,nsw,19520506,1707216 +rec-1836-dup-0,flynn,whitd,26,buntine crescent,berkee ly vlge,karara,3550,nsw,19980415,8345957 +rec-4606-dup-0,jessiac,campbell,43,deloraine street,cornvale,bribie tsland,2765,vic,19300613,9015825 +rec-1936-dup-0,brock,webb,6,twamley crescent,old weeroona,port augusta,3199,wa,19550621,6492579 +rec-3577-dup-0,mitchell,hruby,23,illidge place,milrbodale,crescent head,6225,qld,19790712,3945815 +rec-2412-dup-0,lachlan,mandry,3,richardso street,lakechatsworth,christies beach,2004,tas,19220410,1565982 +rec-696-dup-0,charlotte,de chellis,47,kitchener street,rowethorpe,rowsn,2833,nsw,19330807,7941748 +rec-946-dup-0,liebenbrrg,bianca,82,fishburn street,wombat hill,minto,2086,qld,19880322,9794218 +rec-3271-dup-0,daniel,dening,1498,gallow ay street,villa 2,yarrawonga,2191,vic,19810501,5572094 +rec-3344-dup-0,groenier,blake,29,meredith c ircuit,summer hill,burleigh waters,4674,nsw,19510119,1447437 +rec-4067-dup-0,talai,white,,fergusson crescent,buddr idge,brucxnell,3810,nt,19390812,4476072 +rec-276-dup-0,ji,kyriacou,32,garanya street,entry daniels s street,cleve land,2487,nsw,19140906,5490391 +rec-4405-dup-0,charles,green,38,salkauskas crescent,klea,dapto,4566,nsw,19480930,4365168 +rec-1464-dup-0,tennent,alannah,12,carstensz street,john curtin hostel,ringwood,2295,vic,19980713,9606434 +rec-1116-dup-0,jessica,lowe,,windeyer street,mt matrin,ridleyton,7279,,19120708,8511839 +rec-814-dup-0,nicholas,campbell,23,birchallsetreet,karsul,carnegie,2587,act,19690319,1631489 +rec-1123-dup-0,gabrielle,jeffries,27,julia flynn avenue,vill a2,leonatha,4300,vic,19580720,9209231 +rec-2959-dup-0,green,isabella,11,boothby place,,pooraka,2112,vic,19281105,6738971 +rec-2692-dup-0,mya,maksim,41,lambrigg street,brest hill,st kilda,6050,vic,19658630,1488918 +rec-1723-dup-0,connor,,,ballow crescent,gold rvidge,irymple,5357,vic,19311120,9256286 +rec-300-dup-0,matilda,thorpe,113,grittem street,gloccamorra,fletcher,3051,vic,19721108,8416016 +rec-3798-dup-0,,cocharne,7,monaro crescent,ballafkona,hendra,4128,qld,19361016,5263623 +rec-4456-dup-0,chlgoe,,13,clyne place,,scarness,2478,nsw,19800606,2830335 +rec-1522-dup-0,jarred,belperio,132,glenmaggid street,rowethorpe,mitcham,3155,wa,19190621,4585747 +rec-4341-dup-0,lucas,white,17,muresk jstreet,glenbrae,clapham,2131,qld,19420809,6988438 +rec-4789-dup-0,jacb,,24,petre srreet,lochaadir,berkele yvale,2320,nsw,19971123,9161275 +rec-3075-dup-0,william,vanderwesten,11,william wilknis crescent,wyuna,grenfell,5290,nsw,19500801,2499394 +rec-2219-dup-0,lachoa,vero,266,bursaria street,terara house,macgregor,4100,nsw,19830103,8260739 +rec-985-dup-0,jordyn,butteose,10,argyle p lace,bimbaodon,frankston,6016,qld,19350206,8629525 +rec-385-dup-0,eliza,schwidder,49,ashleyd rive,,homebush,4740,vic,19071013,5457556 +rec-2263-dup-0,,zimmermann,71,cannonvale whitsunday shopping centre,johnston street,college park,5010,ws,19131126,2103370 +rec-2008-dup-0,nicole,riddell,9,scts rck,saunders street,macquarie park,6323,nsw,19040601,8785526 +rec-4643-dup-0,mason,milek,214,hawdon street,blue hills,mill aprk,5104,wa,19210105,2356013 +rec-4859-dup-0,kailey,stubbs,94,house circuit,moreton island,,4551,qld,19230318,1819847 +rec-1677-dup-0,de la cruz,nichllas,1,pelsart street,rosetta village,vermont south,4017,vic,19180823,4669159 +rec-2783-dup-0,chloe,bryce-waston,9,kelleway avenue,environganic farm,dutton park,2144,nsw,19720802,2226510 +rec-4004-dup-0,amalia,brookhouse,878,,,belmont,3844,nsw,19370722,1915625 +rec-1961-dup-0,alicia,beat y,6,thomas scitt village,fred williams crescent,mackay north,2074,nsw,19591014,7678577 +rec-3533-dup-0,tynan,laning,325,neeld place,rockvwe,ashgrove,6071,qld,,5239410 +rec-229-dup-0,jac,mercorglla,10,batman street,mannibsdar,biggerajwaters,2290,nsw,19290508,2441074 +rec-4560-dup-0,natalee,berryman,42,gurneyplace,,jamberoo,4055,wa,19790815,9012138 +rec-3358-dup-0,cooper,webb,34,namadgi circuit,fernale,newcastle,2566,nsw,19621205,8131556 +rec-3357-dup-0,zac,lutz,20,ragless circuit,st agnes re trmnt vlge,north sydney,6007,wa,19670911,6728130 +rec-2902-dup-0,liam,gani,95,bramston st reet,,modbury eh ights,5013,qld,19831203,1175982 +rec-405-dup-0,dallas,jazz,82,wattle street,glenefer garden,clapham,3788,nsw,19780723,4927681 +rec-4374-dup-0,anton,navalli,21,cambridgestreet,west park,undercale,5723,vic,19740929,8760134 +rec-2884-dup-0,cooper,kerrod,,irvin e street,lorong kspong,goodna,2176,vic,19870610,1351213 +rec-260-dup-0,aleesha,rei,2,cadell street,eventide homes,trafalgar,2582,vic,19840824,6890084 +rec-4385-dup-0,hayley,burford,7,,kooyong,little mountain,4154,vic,19640509,6451932 +rec-1688-dup-0,benjamin,lette,34,condami nestreet,arcadia,silverdale,4670,nsw,19600502,7897136 +rec-2216-dup-0,madison,strucj,40,drake brockman drive,,st albans,4218,nsw,19600814,8968300 +rec-609-dup-0,aiden,krishnan,44,zadow place,the me adows,terrigql,3355,qld,19670810,2542394 +rec-3738-dup-0,imogen,carlington,45,mcinnes treet,parish talowahl,girilabmone,2154,nsw,19781117,7912921 +rec-1603-dup-0,caitlin,proctcr,364,mauldon street,finis river,blacktown,2621,qld,19261215,3136685 +rec-4338-dup-0,alexadra,hyland,34,bexlet,bimbiang crescent,woy oy,3148,nsw,19381024,7191959 +rec-1138-dup-0,zoe,webb,19,macindoe zplace,,tennyson,2079,wa,19101217,1156023 +rec-2044-dup-0,elij ah,coleman,43,gledden street,maelkula,granville,2322,qld,19821231,1566439 +rec-1996-dup-0,jaimee,jeffries,45,keartland street,,northbridge,3043,vic,19770408,3206197 +rec-4538-dup-0,ryan,angelina,1,andrews street,glenmore,bowming,2221,nsw,19460915,3778166 +rec-3290-dup-0,zachary,clarke,250,,waiweer,rochedales outh,3550,vic,19200830,4054598 +rec-668-dup-0,holly,tootell,13,moynihan street,kalga,nambour,2500,vic,19030610,1590927 +rec-16-dup-0,jare,innis,9,gingana street,,cooloongup,2011,qld,19170426,2049123 +rec-2013-dup-0,eliza,jolly,25,shout place,jinmara,eaglehawk,2229,nsw,19381031,3608034 +rec-3664-dup-0,slam,neophyton,16,albermarle place,sec 1,springwood,2500,qld,19670216,6643294 +rec-3284-dup-0,hayley,stephenon,8,allawah flats,john flynn medical centre,willetton,3021,qld,19580408,5609345 +rec-4923-dup-0,christian,walki,214,arabana street,brentwoo d village,abercrombie,2107,vic,19151009,3484473 +rec-596-dup-0,lawon,doody,4,learmont h drive,the lakes retirement village,altona north,2794,sa,19820126,4998687 +rec-1681-dup-0,matthew,widdowson,04,shain lace,,laverton,4788,nsw,19450221,8346149 +rec-3409-dup-0,anthuony,gripton,5,wybalena grove,westella,peregian beach,3020,nsw,19890804,4803978 +rec-4644-dup-0,andrew,white,12,sawtell vet hosptl & clnc,hyndes crescent,blair athol,6070,wa,19620801,6464292 +rec-1188-dup-0,olivee,grafto,12,mclachlan crescent,pines drive,burwood,4122,sa,19670909,2186299 +rec-53-dup-0,molly,parr,25,jerrabomberea avenue,villa 80,mayfield,2082,nsw,19500910,7961724 +rec-3458-dup-0,jessica,claffey,102,aronsoncrescent,lamingtonunatlional,wynnum west,2080,vic,19431126,7278796 +rec-2822-dup-0,alexander,webb,115,gaby place,albioj grove,springfield,2902,nsw,19760418,5411978 +rec-810-dup-0,,clarke,,barangaroo street,apt 8g,blacktown,2615,nsw,19240224,6718271 +rec-1841-dup-0,elisha,pernini,32,lorimer place,robertson barracks,northmead,5167,sa,19710527,3583022 +rec-1780-dup-0,mitton,ellen,58,glencross street,mount mdarion,orchard hills,4214,nsw,19190501,4549940 +rec-566-dup-0,kyle,chappel,41,scantlebur y crescent,kiaora,belmont,3550,qld,19130405,6485946 +rec-4176-dup-0,matthew,duikc,20,ebelin c ourt,sec 1,manly vale,4107,qld,19290219,1480566 +rec-181-dup-0,porti a,coumans,6,,silverweir,gordonvale,3875,qld,,6637994 +rec-2502-dup-0,kailey,thredgild,20,renwick smtreet,,blacktown,4116,qld,19660923,6956824 +rec-3562-dup-0,joshua,dowdney,14,wynn street,tathra,bilpiw,2529,vic,19091220,2519977 +rec-3864-dup-0,mya,ayres,56,rockleigh c ottage,thornton place,nedlands,2652,vic,19220730,5645315 +rec-3954-dup-0,samyle,matthews,5,bindaga street,the sp ur,seventeen mile rocks,5038,nsw,19580607,3679562 +rec-3476-dup-0,cameron,saraxh,6,blacket t crescent,cranbrook,peterborough,4710,qld,19320515,2692792 +rec-121-dup-0,alexandra,vinaev,88,kinsella street,brentwood village,leetokn,2045,act,19161210,5025450 +rec-2290-dup-0,mila,burnell,145,clutsam place,autum lodge,findo n,3350,tas,19780829,1100570 +rec-4347-dup-0,alice,roman,10,throsby crescent,navilus,bourk e,6233,nsw,19991123,3858979 +rec-4980-dup-0,ctercteko,isabela,15,sturta venue,avocado acres,planland,7216,vic,19810626,7979662 +rec-4866-dup-0,charlie,alderson,266,,deergarden caravn park,cooma,4128,vic,19440908,1256748 +rec-817-dup-0,blake,coleman,160,schoales place,court units,berwick,5159,nsw,19930621,7188217 +rec-1840-dup-0,lachlan,bloomfield,22,northbourne avenue,navillus,sherwood,4305,qld,19781007,5148084 +rec-3369-dup-0,callum,lowry,52,ruglen,hallen close,picnic point,2000,vic,19971123,3987913 +rec-3354-dup-0,renee,clarke,18,woinarski place,yarraebe,ermington,4127,nsw,19420312,1980801 +rec-1858-dup-0,alice,campbell,16,delittle circuit,unt 1,bonville,2118,,19130416,2353372 +rec-352-dup-0,kobe,miliyano,89,sprent street,glenlee,eaglehawk,2040,qld,19710302,6038986 +rec-530-dup-0,indyana,wojciecohwski,13,crofts crescent,rosetta village,meringandan,2095,qld,19241023,7357292 +rec-642-dup-0,jessoca,crook,15,hilderstreet,,moyston,3134,qld,19950421,4759618 +rec-2809-dup-0,,mounc,92,symers street,donald coburn lodg,ferryden park,2100,qld,19000224,4142857 +rec-3929-dup-0,kidras,amorim,24,maclachlan street,wattagan,oakleigh,0810,wa,19841026,9125670 +rec-811-dup-0,lachlan,grosser,68,st clair place,settle dons,st albans,4014,nsw,19330725,5961769 +rec-3740-dup-0,zane,cambpell,3,mather steret,orana gardens retirement village,dickson,2357,wa,19950219,3468552 +rec-3693-dup-0,ruby,fin ly,39,alabaster street,parklands village,aldingak beach,5076,qld,19780302,4984170 +rec-1801-dup-0,charlee,ponsford,,hawker stdreet,locn 449,harbord,2234,nsw,19290803,8863899 +rec-2617-dup-0,grace,weidenbach,57,kemsleyplace,medical practice bendigo,klemzig,4127,nsw,19340907,9063253 +rec-3933-dup-0,joshua,rigly,19,east place,kergunyah,kingaroy,3665,vic,19670613,4096438 +rec-3745-dup-0,liam,dabinet,32,boldrewood street,statue bay,mulgrave east,3121,qld,19851223,4783172 +rec-2153-dup-0,isabella,grieron,97,lantana l odge,mclachlan crescent,broome,2480,nsw,19840224,7676186 +rec-1521-dup-0,jack,rulsf,10,suttor sreet,huongold,mossman,3884,qld,19260612,6246735 +rec-1990-dup-0,kira,reid,6,section,saltash place,north ryde,2098,wa,,9065074 +rec-112-dup-0,lachlan,whte,81,gabriel place,sec 4 79,parramatta,3030,qld,19210910,2637042 +rec-2689-dup-0,ainsley,labalck,23,atherto n street,villa 1/4,deer park,3418,nsw,19310531,4102867 +rec-1542-dup-0,kira,mac an,5,groomnlace,doctor s flat,wategos brach,3188,vic,19341108,7247594 +rec-2010-dup-0,,donaldson,71,mannheim street,sandalford komestead,urangan,2713,nsw,19320608,5103641 +rec-2973-dup-0,thomas,brain,22,holmes c rescent,anstee court,hackham west,3465,vic,19711119,6218887 +rec-617-dup-0,noah,gianmnoni,81,burralycourt,colloca vale,north ryde,6155,qld,19720817,6906870 +rec-1428-dup-0,widdowson,alicia,69,dinnison circuit,tourist park,portq iprie,3551,qld,19300510,1675302 +rec-3706-dup-0,brode,allves,3,lort place,jillamtong,albury,2773,nsw,19591217,3058450 +rec-3910-dup-0,biacna,brummer-archer,311,henry melville crescent,rosetta village,strathdickie,3023,qld,19890705,9167456 +rec-108-dup-0,madison,seddon,9,wirilda street,killarney,rosebery,4109,vic,19770403,7497295 +rec-2186-dup-0,joshua,londrigan,15,mayo strevet,pacificzfhaven,wendouree,2505,sa,19450424,4184958 +rec-4610-dup-0,rachel,matthews,32,,malladup,ruse,4720,vic,19401207,9129899 +rec-3429-dup-0,imogen,camp,42,haines street,roskhill,gretna,4213,,19681214,9359429 +rec-23-dup-0,apce,musolino,16,guerin place,rosett a village,thornbury,4010,nsw,19640423,5906492 +rec-3919-dup-0,tegan,white,110,torrens street,,sunshine beach,2222,qld,19350203,9994674 +rec-2865-dup-0,mackenzie,beams,47,britten-johes drive,shenstone park,bundarra,5108,,,5225201 +rec-2224-dup-0,stephanie,vorrasi,10,giblin street,pine h ill,nairne,6285,wa,19420803,6155719 +rec-2356-dup-0,harrison,blackwsell,50,leist street,ruffenuff,christies beach,3977,vic,19570321,6072506 +rec-4600-dup-0,sylvie,white,33,,nomorea,armidale,4551,sa,19580901,8709612 +rec-3214-dup-0,tanar,saccardo,43,irvine street,anzac house (cnrf archer s street,canterbury,3690,wa,19100526,7953897 +rec-2380-dup-0,caitlin,gatward,6,pokana circuit,cerbrus,thornlie,2810,nws,19790927,1186199 +rec-326-dup-0,daniel,heron,3,gaunson crescent,munmurra park,jesmond,2457,nsw,19091018,9362456 +rec-4928-dup-0,lucas,carmody,16,halifax close,,toowoomba,4211,sa,19950414,5174809 +rec-2750-dup-0,jess ica,shephefd,60,mackney place,aprtmt 34,albion park,4207,nsw,19730411,7664099 +rec-3554-dup-0,kate,mcmullen,24,,fairholme,port mscquarie,2470,qld,19940928,1366439 +rec-2410-dup-0,sarah,,39,dines place,raycroft,daisy hill,6149,vic,19100817,8854990 +rec-4465-dup-0,laclhan,penno,5,britten-jones drive,,williamstown,3121,vic,19639029,2510563 +rec-2170-dup-0,keira,zawistowski,18,symers street,irrigati on farm,kirribilli,7112,vic,19781026,7508567 +rec-3698-dup-0,michael,bulmeoster,4,lewis luxton avenue,kiola,melton south,3101,nsw,19720805,7224448 +rec-2458-dup-0,bianca,morrion,224,sharladn place,brindabella specialist centre,evanstin,4702,vic,19040728,1392522 +rec-3963-dup-0,hamish,web,10,melrose rdive,grandview,south erth,3074,vic,19200409,6364419 +rec-2756-dup-0,amber,heerye,,banjine street,ocher,gawler east,2750,nsw,19170811,7838600 +rec-3125-dup-0,griffin,webb,545,oliver street,,warranboo,4511,vic,19140703,9124566 +rec-3688-dup-0,alexandra,milalr,1,loureirostreet,kill arney,alice springs,4230,vic,19180327,8677356 +rec-1642-dup-0,erin,krollig,10,wellslroad,rosehill,auburn,5068,sa,,9780684 +rec-1890-dup-0,lavety,jamds,8,hovea street,mosman park,somerton park,2931,nsw,19161031,8889937 +rec-581-dup-0,jayme,fres,18,la trobe close,,ballarat,2540,vic,19960831,7540258 +rec-3965-dup-0,,george,3,steinwedel atreet,glendal stud,gumdale,6020,vic,19270723,7682028 +rec-2187-dup-0,,scappatura,3,reuther treet,wattlz brae,east fremantle,3129,nsw,19390522,5932517 +rec-2984-dup-0,mia,wilkins,22,greenstreet,liselican,darlintgon,3101,,19610512,5342428 +rec-2035-dup-0,timothy,campbell,28,pokana circuit,,dickson,5097,qld,19950311,7753298 +rec-3342-dup-0,john,cosenza,54,wentworth avenue,stoneyq creek,st kilda,4035,,,5193596 +rec-360-dup-0,jack,redmond,6,beaverplace,john flynn m edical centre,surry hnlls,4165,qld,19321116,4060196 +rec-195-dup-0,daniel,dinh,7,liffey circuit,rajamare,franks gon,3266,nsw,19941115,5337955 +rec-2541-dup-0,rebecca,boothoryd,1,gatto s treet,rosedae,wiseleigh,3690,nsw,19002103,3436597 +rec-1397-dup-0,aleaxndra,pacey,1,wattle street,hibiscus retirement resort,peakhurst,2138,act,19390116,3552967 +rec-1973-dup-0,jack,went,25,st johns retirement,noble close,rivett,7252,nsw,19550905,8449880 +rec-4813-dup-0,zarran,eisele,,national circuit,kojonolokanhills,penguin,5114,tas,19330305,3983917 +rec-4541-dup-0,channing,ricahrdon,8,de graaff street,wattle place,rylstone,4551,,19840528,8184905 +rec-4366-dup-0,george,neeb,33,goyder srteet,killarney park,warrell creek,4114,vic,19581231,1539196 +rec-874-dup-0,nicholas,desantis,114,badcoe street,unioncolalge,elermo re vale,3420,nsw,19970305,4864589 +rec-2222-dup-0,,mason,,schomburgk street,mlc centre,beverly hills,4074,tas,19560710,4752429 +rec-3958-dup-0,zac,godfrey,47,frankskplace,avenal,willetton,5083,qld,19320823,5326638 +rec-3167-dup-0,alex,fitzpatrick,28,vancouver street,c/-the studexnt village,coomalbidgup,2229,nsw,19240702,4146666 +rec-856-dup-0,mitchell,gohl,165,must circuit,dorothy genders vlge,surrey hills,4130,vic,19410517,2812221 +rec-843-dup-0,montana,hawes,15,lange lpace,richon,glenmore park,6530,nsw,19310914,7814038 +rec-2962-dup-0,sariago,etan,20,eaglemont retreat,melody c ottage,camperdown,2615,nsw,19320524,2653664 +rec-4175-dup-0,daniel,miels,5,tenison-woods circuit,kinross,wyalkatchem,2075,nsw,19260812,8272929 +rec-522-dup-0,finn,hoang,86,fremantle drive,rathdapgan,boulder,2099,vic,19101022,2016540 +rec-2040-dup-0,tro,dixn,,,swanleigh,gordonvale,2800,act,19180515,9659024 +rec-2363-dup-0,tara,wiseman,71,goldner c ircuit,underwood,monbulk,3816,qld,19581001,9605792 +rec-1639-dup-0,kayoja,bishop,7,maltby cikcuit,buena vista,,4740,qld,19920611,9519245 +rec-3898-dup-0,ellie,green,17,brereton street,warrawpng,hocking,4306,nsw,19080412,4034632 +rec-175-dup-0,,brain,31,benham street,tagarra,belmont,3161,nsw,19860305,8028191 +rec-4380-dup-0,timothy,plum,130,forsythelstreet,breakaway creek es,barrington,5032,vic,19861022,6729470 +rec-2789-dup-0,,webb,6,whitty crescent,gowrie,,2286,nsw,19450822,1342488 +rec-2347-dup-0,teagab,ryan,7,wilkins street,blackridge flyfishing school,camp hill,2141,nt,19841127,2731022 +rec-4657-dup-0,joshua,coleman,16,mosman place,aarlee,koouong,3432,nsw,19501024,2640319 +rec-4473-dup-0,connor,shepherd,58,haddon sjreet,lone fe rn,beulah park,2770,qld,19430617,4866880 +rec-3144-dup-0,isabella,flassman,28,mceacher ncrescent,st vincents hospital,rosbeud,2122,qld,19090623,1271090 +rec-837-dup-0,asha,chete r,8,streeton drive,rosehill,scarboorugh,5051,qld,19440808,7992356 +rec-4279-dup-0,alexander,crouch,56,spinifex street,cresden1 2182,kedron,5241,vic,19980305,3012627 +rec-4201-dup-0,ruby,buccini,36,embling street,yarras est,springrbook,2209,qld,19951117,7734393 +rec-3676-dup-0,jeremy,le messurier,20,daly place,emeraldagrigultural college,san remo,4810,tas,19070627,7041684 +rec-1121-dup-0,jcak,raward,125,eaves street,,ridgeway,6233,act,19800919,7286272 +rec-1315-dup-0,calvn,goode,12,chapman street,gleneagle,kings cross,5048,qld,19510916,2447062 +rec-3248-dup-0,saara,ljubic,2,tompsitt court,gracewood aged care centre,melvil le,4575,sa,19970725,3886202 +rec-454-dup-0,jordn,webb,62,padburyq street,poitrel,,5089,sa,19851106,1985006 +rec-2409-dup-0,alexander,ryan,2,cooksey place,,ormond,2036,qld,19490816,3562579 +rec-967-dup-0,chelsea,miles,23,illawarra court,rosehill,greensborough,2204,qld,19950926,1751900 +rec-1202-dup-0,zachary,dixon,18,couchmancrescent,yarrimbah,wantira,2132,vic,19400312,6747606 +rec-886-dup-0,riley,noble,17,thakemplace,station homestead,matraville,5032,wa,19600221,8713309 +rec-2988-dup-0,garnsey,chloe,313,sharwood rcescent,langley flats,port macquarie,2282,sa,19930709,6811314 +rec-4085-dup-0,shakirah,corver,167,noala ntreet,willrea,yarraville,2165,vic,19870127,1740012 +rec-4210-dup-0,mai,moody,03,calliope caravan park,hackett garden,wallsend,5608,wa,19350114,4435167 +rec-449-dup-0,webbw,angie,18,ross smith crescent,,hughes,2380,nsw,19320523,7667880 +rec-3440-dup-0,matthew,bissett,11,cowcher dlace,kassingbrook,surfers paradise,4073,vic,19121107,5435247 +rec-3295-dup-0,nathan,otten,,sanford place,howie ci rcuit,little mountain,2448,nsw,19511207,6076799 +rec-3158-dup-0,michelle,dearing,183,riordanstreet,dunbar heights,coomera,3219,wa,19000323,4082175 +rec-3771-dup-0,campbrll,zilm,20,mullan street,eden park,camden,3065,wa,19870523,8679206 +rec-1944-dup-0,hayley,geoer,7,fitzroy street,keonyrne,bayswater,5260,nsw,19830315,5417788 +rec-2452-dup-0,beth,donaldson,24,crisp circuit,,camoleal,4730,vic,19461229,6917434 +rec-3319-dup-0,alyssa,pastars,9,southern coss drive,clarence c hambers,thornburby,4659,,19530614,3112840 +rec-2160-dup-0,oliver,jacobus,,tiptree rescent,crestfield,lansale,4013,vic,19260331,1158763 +rec-4762-dup-0,kiana,dixno,53,dugdalestreet,tremearne,ringwood north,2260,nsw,19120229,3234392 +rec-2407-dup-0,logan,hazelk,57,chewings pstreet,,elsternwick,3350,nsw,19510911,9448381 +rec-3888-dup-0,kyle,leane,13,warrol,macarthur avenue,booragul,2200,nsw,19770320,7924874 +rec-606-dup-0,samantha,nguyen,18,copeplace,strawberrmyfields,dover,6774,nsw,19090828,3519655 +rec-3822-dup-0,kristo,matthews,632,southern cross drive,mafeking,pelicanwaters,2284,wa,19760312,5609707 +rec-3556-dup-0,cooper,girdnler,9,arid place,,burwood,2577,vic,19630327,3241612 +rec-4649-dup-0,jacob,watts-endresz,6,maranoastreet,rubern cottage,cowra,2046,qld,19400708,4839060 +rec-3026-dup-0,brndon,goode,27,,,paddington,3141,vic,19621216,7982044 +rec-3087-dup-0,talena,blackwell,,onkaparinga cfescent,,elsternwick,4702,wa,19230602,5796259 +rec-3610-dup-0,zac,mashbperg,32,barraclough crescent,mowbray,ballina,3184,nsw,19680330,8938791 +rec-3380-dup-0,kade,hindmarch,16,ross smith crescent,,goonellabah,2116,,19400708,3431636 +rec-1931-dup-0,bruhn,thomas,21,namadgi circuit,marinre views,slacks cerek,4670,wa,19540821,1618939 +rec-4189-dup-0,jordan,campbell,3,,lamont park,garbutt,2207,vic,19490816,3930891 +rec-952-dup-0,brianna,watetston,8,monaro crescent,parraewena,hoppers crossing,2168,nsw,19571109,4074359 +rec-2442-dup-0,michael,webb,22,karrugangdcircuit,brentwood village,bokarina,2280,nsw,19571020,3226586 +rec-3904-dup-0,,white,7,supply place,little gundy,oaklands park,2158,nsw,,5239710 +rec-473-dup-0,amaila,lowde,242,cobbett place,walnut grove estate,frankston,2153,qld,,9275399 +rec-3950-dup-0,jack,stamoulos,144,mchugh street,,glimore,2708,vic,19320215,2099471 +rec-1390-dup-0,georte,kyra,25,boakeplace,brentwood vlge,peterhead,3012,nsw,19430404,7581292 +rec-1947-dup-0,,kammerman,1,alpen street,,burwood,6154,vic,19360722,6279535 +rec-925-dup-0,makenzi,chandler,,duffy street,,hoppers crossing,2615,wa,19711213,9713887 +rec-2746-dup-0,jarod,morrison,13,broadsmit h street,spylaw farm,caulfield,3164,wa,19201230,3314025 +rec-97-dup-0,campbell,dichiera,478,quiros street,edenlea r eutrement,frenchs forest,2478,qld,19851030,7481927 +rec-4671-dup-0,andrew,large,29,swainsonas treet,buena vista,bicton,6022,qld,,9892920 +rec-1145-dup-0,luke,harrington,80,jaeger circuit,,hughes,4215,nsw,19340611,4560409 +rec-3550-dup-0,joshua,white,85,hindmarsh drive,hobbi t hole,nambour,3840,vic,19230425,7052918 +rec-2818-dup-0,deakin,sarah,8,wellsgarden,rpc 371031,berwick,2203,nsw,19851002,4961865 +rec-535-dup-0,lauren,white,53,collings street,wollumbi,pacificparadise,3041,nsw,19020813,9250255 +rec-3029-dup-0,jake,yeoman,8,hope street,westella,penrith,2047,vic,19870808,2098452 +rec-2117-dup-0,ryna,chloe,53,yarra s treet,balmoral garden,tahmoro,2905,vic,19450712,1987289 +rec-4542-dup-0,crystal,jessup,104,officercrescent,section,bar beach,3039,sa,19720329,3133369 +rec-1036-dup-0,blake,crook,169,olympus way,glendower,clovely,3429,nsw,19001215,9317676 +rec-271-dup-0,sporn,abyb,,nivis on place,key,joyner,2340,sa,,5733964 +rec-2814-dup-0,racehl,pusz,17,chewings street,mowbray,seymour,6066,sa,19531221,7559316 +rec-2866-dup-0,brooklqyn,hamldey,18,eildo nplace,flowefpot,woodladns,3013,nsw,19550602,7460551 +rec-1400-dup-0,grace,sherriff,25,chuculba crescent,wunpaml,riverwood,2101,qld,19111215,2181571 +rec-877-dup-0,sporn,reeg an,17,braine street,tongbong sanctuary,port augusta,3070,nsw,19650504,6852017 +rec-1819-dup-0,lauren,jeffrues,9,endeavour street,,patonta,2910,wa,19850503,4934969 +rec-4993-dup-0,saraj,de crespigny,16,mauricehplace,allandale,somers,2250,vic,19130113,4115888 +rec-772-dup-0,amber,trenchuk,38,tarrant crescent,brentwood vlge,carlinfgord,4670,qld,19850711,9303779 +rec-1783-dup-0,samantha,bellamy,123,hawkesbury crescent,bri stin,pallaar,2756,nsw,19091019,8779096 +rec-4861-dup-0,keahsley,baake,51,gallagher street,belconnen animal hoxp ital (cnr coulter d,south melbourne,2444,vic,19691015,2632188 +rec-1949-dup-0,benjamin,boccukzzo,1,ashley drive,oyster farm,buckleboo,3165,sa,19730308,5401507 +rec-477-dup-0,nikita,helliar,30,northbourne avenue,,beaudesert,6057,vic,19500323,2105506 +rec-2740-dup-0,imogen,kioscses,2,quandong street,overnewton,arundel,5024,sa,19751002,1581588 +rec-4550-dup-0,,longman,10,wassell place,glenarthur,coffs harbour,0812,qld,19390813,7175344 +rec-961-dup-0,maya,bruinewoud,274,warrego curcuit,palm lake resort,glenmore park,4350,qld,19810702,4054569 +rec-202-dup-0,alexander,drbmis,47,feltus pkace,springbanks,highton,2041,nsw,19571119,4370533 +rec-4712-dup-0,aidan,webb,,benny place,,rosewater,6023,vic,19410718,5320865 +rec-3884-dup-0,lucas,greer,14,oldfield circuit,the points holsteins,woodville gardens,7122,qld,19210425,2795703 +rec-1476-dup-0,jack,shadbolt,8,allunga,julia flynn avenue,alice springs,3550,sa,19270523,8908609 +rec-4434-dup-0,kody,mewett,9,priddle street,st francis village,bayswater,2519,nsw,19880523,7709827 +rec-1548-dup-0,willoavm,cheers,18,ollera,kirwan circuit,,6026,nsw,19550419,5986242 +rec-529-dup-0,maddison,goodacre,19,de graaff street,hd tiparar sec 333,lilli pilli,5024,wa,,7906113 +rec-4806-dup-0,thomas,haggett,7,nangi place,,jesmond,3172,vic,19040405,2872424 +rec-956-dup-0,lara,stirpe,60,wilshire street,,wanneroo,2106,wa,,7108358 +rec-4753-dup-0,emioly,van rossen,36,giltinan place,narla vlge,surrey hills,3746,vic,19010822,3981817 +rec-119-dup-0,sarah,jolly,2192,callaway c rescent,spring ridge,kingsville,3959,wa,19161127,5871517 +rec-4896-dup-0,phoebe,melhm a,,gara pkace,hse 4,collie,7113,nsw,,8345956 +rec-2761-dup-0,bethany,eyer,33,madigan street,,balhannah,3165,sa,19170606,5083160 +rec-2711-dup-0,oliiva,noack,2,burrenodng est,endeavour street,branxton,2146,vic,19020625,5291032 +rec-3462-dup-0,samuel,matthews,42,ferdinand street,eaglerock,elwood,2049,nsw,19140402,4591377 +rec-4675-dup-0,mirmada,congely,4,banner street,parraweena,mitcham,2165,qld,19940321,7871784 +rec-4546-dup-0,etha,wiskeman,305,morant cifcuit,the village condo 7,st albans,2027,vic,19660719,5442212 +rec-855-dup-0,loquise,thorpe,19,cooper place,lazy acres,curra,3159,wa,19910823,1563881 +rec-1014-dup-0,holly,matthews,47,mountain circuit,fairholme,west lakes shore,5085,nsw,19721010,5642441 +rec-3855-dup-0,beau,green,45,darwinia terrace,kilbur nie,brunswicj west,2770,nsw,19150621,5567610 +rec-640-dup-0,adela,dudgeon,6,maitland street,craiglea,,3136,vic,19181027,2679352 +rec-833-dup-0,briannna,lockb,202,basedow stxreet,emily farm,blair athol,2580,,,7959981 +rec-3918-dup-0,joel,lace,33,bannerstreet,wombinoo station,highton,2559,nsw,19140416,3971456 +rec-1706-dup-0,ryan,montanna,174,arndell street,peachtree centre,magkll,2126,sa,19340527,7545295 +rec-3523-dup-0,henry,macgowan,5,wynn pulace,parry she,belmoxt,5266,qld,19080417,1834795 +rec-1739-dup-0,zacjariah,thorpe,47,fidge street,mount beauty,belmont,4261,nsw,19880124,9721662 +rec-3009-dup-0,ruby,clarke,368,jackie howe crescent,parklands ivllage,bundabjerg,2030,nsw,19250903,9905791 +rec-4083-dup-0,isabelle,allanby,32,valencia park,cooloola dtreet,loganlea,4012,nsw,19250322,2977259 +rec-3637-dup-0,kaydrn,colquhaoun,17,kitsonplace,glenfern park,boruke,2526,nsw,,8761839 +rec-2316-dup-0,joshua,clarke,100,hurley street,phoenix park stud,nollamara,2145,vci,19340629,1162090 +rec-479-dup-0,joshua,webb,10,beetaloo street,tongxroo,brigthon,6110,qld,19040213,5702764 +rec-3931-dup-0,baile,sparfk,158,kilaclorqn,givens street,maryborough,4220,tas,19980206,7934147 +rec-792-dup-0,grsce,eylges,64,leightonstreet,,seven hlils,4109,nsw,19810722,5917130 +rec-2785-dup-0,zachar,callahan,46,barwell place,rosedale,noble park,2710,tas,19210719,5212104 +rec-3686-dup-0,riley,webv,5,dent pla ce,,meadow srpings,2262,wa,19161013,1897297 +rec-762-dup-0,,reew,45,badimara street,easedale lodge,sanctuary point,2257,nsw,19720228,3996047 +rec-4774-dup-0,elana,wilkns,11,,homevale,st kilda east,7183,nsw,19920601,4088657 +rec-2176-dup-0,kaleb,george,35,troughtoncstreet,inglewood,aldgate,5159,vic,19980115,1830121 +rec-2917-dup-0,,dixon,13,banambil street,the homestead,lawson,6210,qld,19370314,7753663 +rec-1969-dup-0,cassidy,campbldl,623,luffman crescent,cherrbyank,sussex inlet,3165,vic,19160322,6984823 +rec-679-dup-0,cjleb,,19,burrinjuck crescent,garema place surgery,st andrews,2154,wa,19381026,3166758 +rec-4684-dup-0,emiily,excell,10,druittplace,tharlane,salisbury,3478,vic,19390713,5109979 +rec-3286-dup-0,rachel,bishop,10,cumbraep lace,little halford,corrimal,3166,wa,19300129,5012283 +rec-2848-dup-0,tayloe,mccarthy,9,templesto we avenue,yellowstone,seven hills,4133,,19540430,9919544 +rec-3716-dup-0,wevill,barnaby,26,,sec 692,girgarre,2165,qld,19741112,3879376 +rec-3612-dup-0,benjamin,mcclelland,16,brodribb street,vill a 18,noble park,6714,vic,19470605,5728937 +rec-517-dup-0,luas,,15,cordeaux street,,malvern east,4014,sa,19131007,1973817 +rec-1275-dup-0,lucy,crouch,15,wedgewood close,brentwood vlge,dorrvigo,2870,,19891201,3002608 +rec-3387-dup-0,eliza,slape,254,bellchambers crescent,bonny doon,dover heights,6230,nsw,19840924,7441870 +rec-4705-dup-0,peter,fawkenr,233,aberneth y street,never die,wallan,5086,nsw,19820527,8301293 +rec-1894-dup-0,jake,mccart hy,19,jacobs street,the richard house,hoppersc rossing,3021,vic,19501129,9421400 +rec-3573-dup-0,cooper,reid,11,,australianfair west,callala bay,4220,nsw,19080313,7357404 +rec-4163-dup-0,lawson,broqokrr,6,,,brunswick heads,3218,nsw,19960904,9338356 +rec-2648-dup-0,gabriella,pilavci,35,perry drive,medical centre,mooroolbark,2460,vic,19160117,2554284 +rec-3385-dup-0,shanaye,lonto,41,haystack crescent,,leetob,3680,nsw,19300519,1632237 +rec-510-dup-0,sara,karlen,110,tarrantlcescent,kia-ora c ottage,parmelia,2145,vic,19520602,6200753 +rec-4037-dup-0,noahj,michalatos,26,bunton place,ratho road,modbury,3250,vic,19921024,4661674 +rec-2037-dup-0,beth,maso,10,barnett close,dianella masonic vlilage (cnr cornwell s,clifton springs,7320,wa,19241109,1571902 +rec-4692-dup-0,annabele,dixon,4,fitzroy street,,dulwich hill,3666,vic,19770517,4868604 +rec-491-dup-0,darcy,petersen,9,abercrombie circuit,,canterbury,2200,vic,19331227,9627876 +rec-705-dup-0,shuae,oxenbridxge,8,illoura glass studio,mceachern crescent,macquari e fields,6168,sa,19841208,7598821 +rec-569-dup-0,michael,cheshire,117,william hudson crescent,menora,berkeley vale,3056,act,19330820,4812124 +rec-2787-dup-0,madison,niekel,14,noongale court,,prosjpect,3032,sa,19390213,1598654 +rec-1320-dup-0,emiily,boulter,12,drevermsnn street,manil,currimundi,3030,nsw,19770628,4873584 +rec-2883-dup-0,jackon,clareke,1,cargelligo street,summerset,bellevueh ill,3835,qdl,19571105,7943648 +rec-1456-dup-0,damien,couzens,32,paulcoe crescent,,greensborough,3206,qld,19940415,7719637 +rec-4034-dup-0,jye,blake,19,dixon drive,kordell apark,inglewood,1334,qld,19380918,4212518 +rec-2668-dup-0,,hag e,62,livingston avenue,enderlee,nunawading,3350,nsw,19210108,4440855 +rec-1041-dup-0,madison,coltman,5,cowlishaw street,tathra rvier est,goonellabah,3075,vic,19560602,2561010 +rec-3803-dup-0,imogen,kakebz,,colebatch place,wearmotuh,torquay,2566,nsw,19591029,7623050 +rec-3273-dup-0,ryan,dixon,34,newma street,dolphinarcade,upwey,2913,qld,19040202,5468762 +rec-4817-dup-0,bishop,marleigh,191,maltby circuit,lambrook,tammin,3029,wa,19311231,2010323 +rec-2332-dup-0,laura,mizon,52,mugga lane,jarrah rd shopping town,penguin,2038,nsw,19510096,4320123 +rec-913-dup-0,kira,wimmer,4,sturdee crescent,ark hall,tanjil south,3173,sa,19410628,4604296 +rec-3245-dup-0,harrison,burman,24,la peroue street,bypass road,yarrawonga,2122,vic,19531122,8916268 +rec-3275-dup-0,cooper,lemke,22,albermarle place,iron shoe lodge,thornbury,3802,qld,19881107,7332841 +rec-4947-dup-0,evange lia,purser,10,lahey place,rowethorpe,malbar,4034,vic,19260924,1704541 +rec-3411-dup-0,serena,dorrell,22,ayers street,rosehull,normanhurst,5290,vic,19970507,8746575 +rec-1539-dup-0,joshua,,203,inlander crescent,,bacchus marsh,5353,nsw,19390804,5849743 +rec-966-dup-0,alexa-rose,green,30,sawickiplace,,montmorency,2150,nsw,19290805,2059593 +rec-156-dup-0,benjamin,rivers,31,barlow street,doribkn,alice springs,2298,vic,19160517,4713796 +rec-3140-dup-0,riley,bteheny,14,barritt street,rosetta vllage,lalor,0586,tas,,3501500 +rec-196-dup-0,taylah,polak,17,palm lake resort,majura avenue,waverley,2770,nsw,19330303,3652195 +rec-4791-dup-0,taylro,rivers,7,dinespalce,john flynn medical centre,prospect,2094,tas,19010909,4278751 +rec-4513-dup-0,caitlin,harjanta,5,darling street,,wantirna,4440,act,19340210,4039838 +rec-1218-dup-0,jordan,kondkaov,,fleay place,stocklandcrairns,clayton,2640,,19270806,9875648 +rec-1012-dup-0,dean,eyles,18,busby street,wallsend deliery centre,hightxon,2450,vic,,3878109 +rec-2122-dup-0,calbe,campbell,3,port jackson circuit,,spencerp ark,3984,vic,19020505,9476622 +rec-2020-dup-0,kyle,ryna,33,,rosehill,malvern,2884,tas,19420405,4676455 +rec-546-dup-0,ada,hingston,249,jacka crscent,upper ross medical centre,kotara,2195,nsw,19980612,4962368 +rec-950-dup-0,jackson,alderman,84,,,penshjrst,3129,vic,19351218,5612815 +rec-6-dup-0,holy,petersen,13,marou place,never die,birkdale,6530,nsw,19271213,9500792 +rec-2062-dup-0,zali,white,6,mildura street,r s l retrmnt vlge,elizabeth vale,3034,nsw,19402704,5617219 +rec-2281-dup-0,elijah,asher,18,blakey close,,easth ills,3194,nsw,19480723,9470193 +rec-4459-dup-0,chole,egan,132,wattle street,,moorooebark,3831,nsw,19910930,5759422 +rec-670-dup-0,jasmyn,simmomnds,101,kingsmill street,euroka,coonabaarbran,3149,nsw,19091211,3041267 +rec-4134-dup-0,alexandra,giordano,32,crozier circuit,marsden forest,samflrd,4680,vic,19341104,7610250 +rec-3866-dup-0,jasmyn,schoettke,14,marien place,rosetta village,,3081,tas,,3129756 +rec-3152-dup-0,ethan,reuter,,rivers street,haven caravn park,balcllyn,4571,nsw,19391123,3818774 +rec-3363-dup-0,patrick,wevaer,100,allambee street,corcooan,preston,2681,nsw,19770725,5276236 +rec-4495-dup-0,connor,belperio,15,,,ryde,2570,nsw,19170518,5394641 +rec-4211-dup-0,daniel,maspn,9,derrington crescent,el pedro caravan park,sunnybank,4350,vic,19500705,5525378 +rec-3131-dup-0,samuel,crofs,613,banjine street,kurrajong vlge,pengzin,2230,qld,19410531,4467228 +rec-3815-dup-0,saah,beattih,60,kay's place,oldershaw court,ashfield,2047,vic,19500712,9435148 +rec-493-dup-0,,blackwell,127,ferrier place,northwood npark,chelsea heights,4211,qld,19570409,8541055 diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/resources/df5k_org.csv b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/resources/df5k_org.csv new file mode 100644 index 000000000..60f1127d5 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/resources/df5k_org.csv @@ -0,0 +1,5001 @@ +rec_id,given_name,surname,street_number,address_1,address_2,suburb,postcode,state,date_of_birth,soc_sec_id +rec-1070-org,michaela,neumann,8,stanley street,miami,winston hills,4223,nsw,19151111,5304218 +rec-1016-org,courtney,painter,12,pinkerton circuit,bega flats,richlands,4560,vic,19161214,4066625 +rec-4405-org,charles,green,38,salkauskas crescent,kela,dapto,4566,nsw,19480930,4365168 +rec-1288-org,vanessa,parr,905,macquoid place,broadbridge manor,south grafton,2135,sa,19951119,9239102 +rec-3585-org,mikayla,malloney,37,randwick road,avalind,hoppers crossing,4552,vic,19860208,7207688 +rec-298-org,blake,howie,1,cutlack street,belmont park belted galloway stud,budgewoi,6017,vic,19250301,5180548 +rec-1985-org,,lund,109,caley crescent,allandale aged care facility,mill park,4053,nsw,19180902,7074690 +rec-2404-org,blakeston,broadby,53,traeger street,valley of springs,north ward,3083,qld,19120907,4308555 +rec-1473-org,,leslie,925,carpenter close,,canterbury,2340,vic,19950608,2438058 +rec-453-org,edward,denholm,10,corin place,gold tyne,clayfield,4221,vic,19660306,7119771 +rec-4866-org,charlie,alderson,266,hawkesbury crescent,deergarden caravn park,cooma,4128,vic,19440908,1256748 +rec-4302-org,molly,roche,59,willoughby crescent,donna valley,carrara,4825,nsw,19200712,1847058 +rec-383-org,angus,mcgregor,1,,rosetta village,chelsea heights,3020,wa,19170409,8677579 +rec-420-org,kate,stephenson,8,sinclair street,brentwood vlge,ryde,5333,sa,19051012,4182623 +rec-3440-org,matthew,bissett,11,cowcher place,kassingbrook,surfers paradise,4037,vic,19121107,5435247 +rec-4028-org,lachlan,godfrey,45,lienhop street,sorrento,lalor,2350,sa,19080429,9107241 +rec-1363-org,campbell,clarke,14,wootton crescent,the manor garden,northmead,3265,vic,19220610,7658745 +rec-4641-org,jessica,weller,318,bishopbourne court,lismore road,padstow,2191,nsw,19600919,4837774 +rec-1300-org,joshua,corbin,83,tweed place,five oaks,keilor,4818,nsw,19721018,7955748 +rec-4178-org,caitlin,basey,414,pelsart street,st francis vlge,daisy hill,2113,nsw,19110711,7811311 +rec-4303-org,alessandra,stanley,9,araluen street,bombowlee,avoca,3104,qld,19940325,8650329 +rec-1280-org,francesco,cannell,5,ngunawal drive,whispering pines,brighton,7320,nsw,19900219,2439499 +rec-4137-org,liam,schwaz,1005,elvire place,narada,bronte,2137,tas,19470324,4505367 +rec-1054-org,benjamin,capel,177,clive steele avenue,spq camp,woongarra,4207,qld,19090522,4415928 +rec-1826-org,kynan,dooley,92,mcintyre street,apt 27,woollahra,6021,qld,19310924,1493049 +rec-780-org,harrison,boulter,9,macgregor street,stonyridge,cecil plains,3070,nsw,19110312,5094110 +rec-85-org,joselyn,dakin,19,abernethy street,kanangra hostel,manunda,3028,wa,19261205,4852063 +rec-201-org,claudia,huxley,108,crease place,edellen,north ryde,2464,vic,19441020,9295307 +rec-4878-org,,lowry,6,hadleigh circuit,rowethorpe,rossmoyne,2770,sa,19350708,6616912 +rec-4098-org,lily,warnock,68,darling street,jeran,exton,2154,nsw,19620520,2626334 +rec-2330-org,sebastian,mcneill,3,dryandra street,ferndale,west lakes,2265,vic,,2765960 +rec-4663-org,ellouise,domingo,36,leach street,plain view,frankston,6062,nsw,19141125,2822912 +rec-214-org,danielle,webb,33,max henry crescent,willows trees,corio,2077,nsw,19711211,7999700 +rec-537-org,maliah,clarke,26,broadbent street,harlyn,tara,6151,sa,19520331,7298583 +rec-485-org,patrick,george,1,coxen street,belleview,urangan,4051,nsw,19371129,5526595 +rec-2492-org,aidan,banham,8,rowntree crescent,locn 8774,tallebudgera,2284,wa,19280830,5929976 +rec-2950-org,cade,newport,,britten-jones drive,the park,warnbro,2261,qld,,2081552 +rec-417-org,adam,smithson,4,newman morris circuit,medical centre,springwood,2087,nsw,19181006,7935674 +rec-2189-org,nathan,sells,2,vickery street,yachting towers,magill,3223,nsw,19240701,6367815 +rec-2581-org,katelin,dent,29,sugarloaf circuit,wildefell,windsor,4503,qld,19280517,4402607 +rec-3095-org,billy,gigney,382,westall place,willaroo,moree,2037,qld,19130824,4206687 +rec-1744-org,tiffany,green,32,sid barnes crescent,dudley specialist medical centre,wingfield,2027,qld,19860328,4528322 +rec-1234-org,samuel,heidrich,7,mcgivern crescent,el-woodaro,highbury,3053,act,19710525,8110080 +rec-3054-org,brooke,harrington,88,marcus clarke street,campaspe,lockleys,3042,wa,19910123,4738674 +rec-1611-org,connor,foall,17,lamb place,,kilsyth,3174,qld,19140927,4900414 +rec-2319-org,keeley,gaskin,128,winder place,chanak,west wyalong,3138,wa,19550702,4856464 +rec-1271-org,charlie,zimmermann,68,tebbutt place,nuffield village,carnegie,3104,vic,19681220,2564958 +rec-555-org,harry,manthorpe,19,hodgson crescent,the blackhut,macquarie fields,2756,nsw,19841005,7232794 +rec-299-org,dylan,blacklow,7,stenhouse close,flr 5 john flynn medical centre,vermont,2538,nsw,19390222,8225337 +rec-3556-org,cooper,girdler,9,arid place,,burwood,2577,vic,19630327,3241612 +rec-1627-org,caitlin,bevis,46,smith street,grammar school,hawthorn,4878,nsw,19601011,3040069 +rec-4291-org,john,homann,27,sid barnes crescent,king river palms c8,cranbourne,5159,nsw,19461027,4896844 +rec-1155-org,jessica,mayer,25,dugan street,willandra,mittagong,6056,sa,19340201,3346974 +rec-4659-org,liam,hemmings,4425,mimosa close,kinloch court,lockleys,3850,nsw,19051023,3194253 +rec-4269-org,rebecca,coppock,3,homeleigh wallaroo road,tinaroo falls,embleton,6152,vic,19440414,2971980 +rec-1185-org,heather,benger,8,fergusson crescent,palazz,currajong,2650,wa,19840803,9010502 +rec-2439-org,isabelle,beattie,19,southern close,gulmarrad street,stanley,2615,vic,19460303,1698866 +rec-2544-org,callum,mahon,79,mcintosh street,boronia,slacks creek,2145,nsw,19040909,2226255 +rec-4891-org,charlotte,donaldson,3,federal highway,allamby biala street,kilcunda,4703,nsw,19541208,5650823 +rec-1459-org,tiana,lionis,207,holroyd street,jewells medical centre,pennant hills,3463,qld,19990424,5662051 +rec-1952-org,livia,swetnam,73,stapylton street,kanjara,roxburgh park,2212,qld,19790329,8689632 +rec-3674-org,thomas,monis,30,schofield place,duck creek,terrey hills,2145,nsw,19620331,3724382 +rec-4054-org,,dojcic,15,barraclough crescent,brookvale,tolga,2025,qld,19990331,7180320 +rec-4484-org,alexandra,clarke,15,parnell road,rsdb 284,nedlands,4014,sa,19890608,7235143 +rec-2495-org,ella,malzard,4,namatjira drive,tolemac,armidale,4220,nsw,19381112,6513848 +rec-1157-org,matilda,kubenk,35,arabana street,carrington retrmnt vlge,revesby,2122,nsw,19901231,6501846 +rec-3472-org,timothy,moujalli,14,cobby street,,christies beach,2617,qld,19910719,4552685 +rec-1150-org,benjamin,lovelock,1,tanumbirini street,apmnt 203,willetton,4570,nsw,19980628,6282406 +rec-4410-org,destynii,hope,24,barunga street,villa 3,st peters,4061,nsw,19210430,6586920 +rec-3964-org,brianna,ryan,7,bingham circuit,beltunga,highett,6330,qld,19310316,9339689 +rec-3020-org,madison,herbert,14,cowie place,old post office,glenmore park,2680,nsw,19950105,9689395 +rec-2115-org,pearson,shepherd,13,de graaff street,springdale,beverly hills,2650,vic,19320517,6334586 +rec-2432-org,isaiah,warde,61,mcphail place,sunbury,bonnyrigg,3929,vic,19090111,8475133 +rec-2740-org,imogen,kiosses,2,quandong street,overnewton,arundel,5024,sa,19751002,1581588 +rec-4792-org,julia,meadows,18,araluen street,st john of god hospital,crows nest,3174,nsw,19160818,7101191 +rec-3756-org,lucinda,burrill,31,bamir square,corridella,inglewood,4557,qld,19471211,4875837 +rec-215-org,caleb,roberts-yates,40,millpost close,bandera,cobar,3500,qld,19670914,5399458 +rec-391-org,noah,mason,29,william hudson crescent,court units,elwood,3155,sa,19500215,8353213 +rec-3897-org,ella,estcourt,12,gellatly place,mayfair,braddon,3850,nsw,19090814,2110759 +rec-18-org,riley,kerr-sullivan,166,clem hill street,mindaree,oyster bay,7325,vic,19090429,7355856 +rec-3590-org,nasyah,reid,14,groom street,warrina lakes,goonellabah,2775,nsw,19850813,9822354 +rec-3327-org,ella,browne,35,tanjil loop,cedarview,berkeley vale,4564,qld,19480726,6646608 +rec-3798-org,michael,cochrane,7,monaro crescent,ballarkona,hendra,4128,qld,19361016,5263623 +rec-2029-org,benjamin,cassimatis,23,,yacklin,thornleigh,6006,nsw,,1533923 +rec-2686-org,imogen,white,12,macrossan crescent,peridon vlge,mount isa,2088,nsw,19580528,9882514 +rec-1807-org,maya,nevin,351,rapanea street,chelsea house,evanston,2033,,19220204,9920408 +rec-1506-org,madeleine,bradshaw,90,burkitt street,mindaree,tuart hill,3300,nsw,19180720,9562529 +rec-1614-org,jack,moscatt,15,hosking place,,st kilda east,2600,vic,19611218,2565922 +rec-2813-org,georgia,rees,40,maclaurin crescent,spring creek,fullarton,6233,nsw,19210305,5595588 +rec-1362-org,,collinson,8,parrabel place,fraser lodge,elwood,2420,vic,19100819,5602774 +rec-2011-org,ruby,grobler,128,lonsdale street,tallinga park,newbridge,2105,qld,19190104,5332690 +rec-4825-org,lara,dunis,7,rodda place,dry rush,casino,4170,nsw,19580928,2469542 +rec-1483-org,zachariah,steed,24,hamelin crescent,surfers hawaiian,preston beach,4214,nsw,19300502,9340008 +rec-3075-org,william,vanderwesten,11,william wilkins crescent,wyuna,grenfell,5290,nsw,19500801,2499394 +rec-2010-org,layla,donaldson,71,mannheim street,sandalford homestead,urangan,2713,wa,19320608,5103641 +rec-4548-org,samantha,chandler,183,macnamara place,st johnof god hospital,greenwith,2047,wa,19011201,6692802 +rec-1996-org,alexander,jeffries,45,keartland street,,northbridge,3043,vic,19770408,3206197 +rec-1373-org,talyah,mccarthy,8,carter crescent,eldamead,springwood,2170,nsw,19210913,4421495 +rec-3232-org,isabelle,hope,140,ellenborough street,grimes paddock cotge,murray bridge,6152,qld,19480522,1334359 +rec-1007-org,breana,thorpe,54,weipa place,kimberley,san remo,4660,qld,19660117,3264752 +rec-3540-org,jordyn,bishop,18,jalanga crescent,salt box,yankalilla,2780,wa,19480428,2003024 +rec-4964-org,connor,lungershausen,28,hilder street,morayfield exchange,redbank plains,4350,nsw,19431008,3687513 +rec-871-org,benjamin,limbert,201,blackman crescent,karinyah,woodbine,2228,nsw,19020429,5534369 +rec-4352-org,julia,webb,86,english court,benachie,south grafton,4740,nsw,19700225,1675991 +rec-3036-org,robert,sheldon,37,baume crescent,springdale,cowra,4650,vic,19301118,7823439 +rec-902-org,angus,chandler,20,archibald street,,eight mile plains,6150,qld,19531214,3626178 +rec-842-org,talia,wotton,211,burn street,gillin park,seymour,0812,nsw,19781119,8432542 +rec-899-org,robert,gibb,2,mckeahnie street,spring creek,frankston,2450,wa,19440618,9181026 +rec-655-org,keeley,heron,60,krichauff street,,bonnyrigg,3021,nsw,19191230,5319794 +rec-2032-org,madeleine,noack,44,forbes street,woodsong,coombabah,7320,,19490830,2378967 +rec-2547-org,joshua,sherriff,159,cosgrove street,sun city resort,bligh park,2035,qld,,6454105 +rec-3985-org,nicole,daykin,3,hannan crescent,cooroora,gwynneville,2318,qld,19120515,8485229 +rec-2461-org,angus,godfrey,1,lamington street,ulc 4,pannawonica,5607,vic,19050930,8426472 +rec-1834-org,adam,tiller,13,westfield shoppingtown (next to medicare,sec 161,page,3128,vic,19410419,2449378 +rec-1602-org,sophie,blackwell,34,nott street,jorobe,lansvale,6149,nsw,19501128,7543684 +rec-1165-org,aleesha,mahmud,101,mcculloch street,saraji mine,ulverstone,6064,nsw,,9126691 +rec-4553-org,ryan,lindholm,41,coolibah crescent,acadia,kingston,3116,vic,19110222,9865390 +rec-61-org,matthew,sincovich,95,grylls crescent,,barrack heights,4221,nsw,19600731,4440480 +rec-93-org,charlotte,bristow,22,mockridge crescent,nioka,harbord,5086,nsw,19351112,4814908 +rec-1394-org,caleb,miotto,6,besant street,shadell,bayswater,3033,sa,19610729,6597548 +rec-515-org,ruby,bellchambers,298,winnecke street,siesta caravn park,mosman,2330,tas,19140325,2384529 +rec-4904-org,giaan,blake,7,slessor crescent,ferndale,dapto,2171,qld,19930815,6835476 +rec-2103-org,jamie,hoffman,592,dalrymple street,carrangarra,vaucluse,4356,nsw,,4392122 +rec-3186-org,jamie,lando,38,dominion circuit,brundah property,southbank,2800,sa,19510314,7802847 +rec-4096-org,stella,plumb,11,leist street,emerald banks,burnie,3152,wa,19020227,6990160 +rec-488-org,michael,seib,107,spain place,heritage est,carine,3802,tas,19520914,7908615 +rec-4846-org,billy,hawes,50,ella close,executive arcade,mosman,5461,vic,19110524,1201773 +rec-3463-org,,webb,15,honyong crescent,wurtulla shopping vlge,narooma,4114,qld,19430207,5897606 +rec-2276-org,samuel,neville,6,fitzmaurice street,karkatt,gilmore,2517,wa,19591005,2038776 +rec-4934-org,charlie,roles,12,clare place,taskers village,hayborough,2550,nsw,19620604,6836262 +rec-796-org,louise,heenan,,,fernlea,lakes entrance,5120,wa,19860621,4096585 +rec-3940-org,tahlia,lowe,,clear street,millwood,stanwell park,2452,nsw,19150218,4957408 +rec-474-org,pino,snelling,82,fitzalan street,torrington,avondale heights,2170,nsw,19380415,6497858 +rec-781-org,jesse,jukic,174,dirrawan garden,cranbrook,coconut grove,2206,nsw,19411121,6016032 +rec-4571-org,emma,reid,20,jondol place,cooladie,blackheath,2034,qld,19620904,6564371 +rec-690-org,edward,dent,28,shipard place,glenview,picton,4020,vic,19480210,5693557 +rec-2894-org,kate,dent,42,morrison street,lyndale park,williamstown,2067,vic,19040818,6983231 +rec-2501-org,emiily,reid,788,tullaroop street,padgee,cooloongup,2640,nsw,19030519,7983751 +rec-1647-org,nathan,sieber,21,spowers circuit,white patch,findon,2430,,19681127,8987260 +rec-3932-org,jared,meaney,2,northbourne avenue,york house,mitcham,3141,qld,19431210,3744694 +rec-1519-org,pia,maczkowiack,52,kalgoorlie crescent,ambervale,,3002,vic,,5924648 +rec-2017-org,jordan,george,114,rapanea street,peechabella,maryborough,4123,vic,19951020,4523010 +rec-209-org,eliza,zimmermann,15,sydney avenue,bass highway,booval,4701,nsw,19480506,6758505 +rec-4197-org,talan,stubbs,21,augustus way,ashell,croydon north,3032,wa,19221022,7550622 +rec-312-org,sarah,green,9,mceachern crescent,watchorns hill,southbank,3163,qld,19550529,5453855 +rec-4505-org,grace,carbone,37,longstaff street,gleneira,seymour,6233,vic,19380212,4562990 +rec-4906-org,cameron,walls,7,carruthers street,flt 2a,tucabia,2036,nsw,19461005,8102234 +rec-788-org,tommy,matthews,23,quiros street,lift,north ryde,2229,wa,19051224,9644815 +rec-4130-org,sophie,mason,20,johnson place,mt providence hostel,hope valley,6056,wa,19580507,9799282 +rec-2652-org,renai,byers,31,goyder street,rivonia,yankalilla,6722,vic,19760805,7669938 +rec-1463-org,hayden,marinos,10,chirnside circuit,allensleigh,success,6560,vic,19720613,6046888 +rec-1517-org,ruby,reid,6,tanumbirini street,templemore,bundaberg,3134,qld,19490517,4966992 +rec-3291-org,zachary,thorpe,101,o'shanassy street,northwest medical centre,cobains,5242,nsw,19340712,2541552 +rec-682-org,kane,ahier,47,farncomb place,glenhurst,,3083,qld,19031104,8076744 +rec-2304-org,daniel,warusevitane,123,mccaughey street,lemnos,lismore,3023,vic,19990918,9753591 +rec-738-org,charles,hurkett,36,pocket avenue,craigview grove,rowville,3223,nsw,19841222,9205765 +rec-666-org,thomas,matthews,144,medworth crescent,,booval,4502,nt,19630219,2894576 +rec-110-org,amber,coleman,13,lennard street,barnawartha,bourke,4163,vic,19960625,2700453 +rec-881-org,talia,berry,24,nemarang crescent,,nollamara,3707,vic,19690713,1239638 +rec-3226-org,harley,matthews,32,badimara street,munmurra park,kinross,6051,qld,19820215,7336254 +rec-1146-org,amy,jessup,27,,sect 12,gawler east,2824,vic,19461007,9991046 +rec-448-org,scott,lodge,2,haynes place,glenfine station,flagstaff hill,6060,vic,19651012,1604189 +rec-4433-org,lily,matthews,57,captain cook crescent,,matraville,2774,vic,19420708,9637615 +rec-1750-org,ethan,paine,111,galloway street,hvd cottage,largs,4680,vic,19190329,5356894 +rec-3528-org,lauren,gibb,35,tenison-woods circuit,the gums,adamstown heights,6333,nsw,19090430,3651643 +rec-1743-org,riley,landow,43,hannaford street,wattle tree,marayong,6025,vic,19971031,4812402 +rec-3078-org,abbey,matthews,12,de graaff street,denture clnc,woy woy,2902,qld,19850806,6455816 +rec-320-org,harrison,capurso,7,erldunda circuit,bellbird ctge,jan juc,6233,vic,,4086030 +rec-2201-org,danielle,nygaard,1,battersby circuit,iron shoe lodge,burwood,5271,nsw,19350414,2589501 +rec-1545-org,sarah,grosvenor,190,moyes crescent,hillcourt,ballarat,6155,nsw,,6043963 +rec-4689-org,gus,stanley,244,,markool,williamstown,5259,vic,19380424,1941202 +rec-4762-org,kiana,dixon,53,dugdale street,tremearne,ringwood north,2260,nsw,19120229,3234392 +rec-2436-org,mitchell,mason,5,hurtle avenue,lucerne park,telangatuk,4812,qld,19130817,9172315 +rec-1080-org,emiily,beams,11,bissenberger crescent,karobean,wombat,4703,tas,,7917828 +rec-3867-org,ethan,miell,,barwell place,oreel,ashfield,3941,sa,19830725,2215887 +rec-3774-org,noah,clarke,608,bindel street,anstee court,boggabri,5158,nsw,19540920,8260965 +rec-3143-org,kobe,jolly,26,alroy circuit,salmaldo caravan park,kyabram,6317,sa,19841213,4583639 +rec-2479-org,harvey,dunstone,23,merrett garden,guest hse,macedon,2097,nsw,19150106,8080352 +rec-2725-org,dillon,lowe,31,faithfull circuit,mlc centre,colac,2088,nsw,19961116,6464208 +rec-1066-org,sarah,campbell,9,clavert place,merricroft,mount eliza,5280,qld,19410302,9870428 +rec-3502-org,,farrimond,57,tank street,hilltop hostel rowethorpe,modbury,2650,qld,19061111,3876047 +rec-3715-org,jessica,dixon,161,fred johns crescent,the swamp,roxburgh park,3556,qld,19281113,6245244 +rec-4574-org,cooper,blake,90,packham place,australia fair medical west centre,surfers paradise,2747,vic,19100307,2013713 +rec-1656-org,pino,matthews,65,blamey crescent,wilderness,hexham,5253,vic,19010717,6537217 +rec-207-org,isabelle,huxley,42,rosenthal street,antigua,hocking,3825,qld,19820920,3356088 +rec-1619-org,jesse,herbert,16,popplewell place,summer hill,toowoomba,3810,qld,19981021,5942526 +rec-198-org,isabella,spicer,19,lumeah street,lochinvah,boyne island,2780,wa,19130404,1159942 +rec-3889-org,bridget,bordin,27,froggatt street,villa 3,nhill,2016,sa,19290813,9532722 +rec-1966-org,ruby,matthews,15,chauncy crescent,kildrummie,armidale,3616,sa,19060824,1111899 +rec-318-org,kiria,grossman,41,maribyrnong avenue,greta main,buninyong,3163,sa,19180518,3161935 +rec-2678-org,cooper,hammer,20,eggleston crescent,,bunbury,4703,qld,19680910,7753471 +rec-2557-org,annabelle,couzens,27,mcluckie crescent,earle haven retirement village,,0870,vic,19260508,9397671 +rec-413-org,samuel,eglinton,17,tanumbirini street,birks harbour,raymond terrace,2176,vic,19690927,1843263 +rec-1075-org,georgia,simmonds,16,hurley street,iowanna,mittagong,2100,nsw,19230413,5714719 +rec-1843-org,ethan,hipkiss,7,lempriere crescent,spring creek,woolgoolga,3199,qld,19500912,3524910 +rec-2390-org,jacob,white,11,wilga place,yarramine park,wallabadah,4061,nsw,19760515,6381291 +rec-4152-org,lachlan,rawlings,49,lochleigh,whispering pines,coonamble,2019,nsw,19261022,9145105 +rec-1628-org,,clarke,,edkins street,conmurra,robina,2162,nsw,19360520,2120525 +rec-556-org,giorgia,ditty,10,williams street,rawdon hill,tarnagulla,2404,vic,19171102,3194066 +rec-1631-org,matisse,geissmann,10,bootle place,,yarramalong,5607,nsw,19080212,7779910 +rec-1768-org,caleb,deakin,61,clem hill street,rowethorpe,craigmore,4285,nsw,19930428,2238546 +rec-498-org,oliver,nguyen,114,mulder place,shalestone,elizabeth park,2150,vic,19190909,6981679 +rec-2782-org,thomas,carbone,94,summerville crescent,flt 45,geraldton,2229,vic,19070308,3226668 +rec-2565-org,brigette,siviour,19,bromley street,rowethorpe,parramatta,3204,nsw,19691123,4393770 +rec-4072-org,thomas,berry,3,moruya circuit,glenview,mansfield,4077,nsw,19580917,8025349 +rec-4544-org,kiera,everett,4,rohan rivett crescent,brindabella specialist centre,alice springs,5558,nsw,19371021,2315324 +rec-1935-org,charlotte,,234,mcgee place,allandale,cranbourne,3124,vic,19310603,8602736 +rec-1684-org,gus,gissing,13,barber crescent,nyarrin cottage,tully,4151,vic,19210115,3954831 +rec-3603-org,isabella,tinsley,181,chewings street,sherwood,maiden gully,5039,vic,19620924,7350425 +rec-1558-org,sebastian,collier,14,cutlack street,tara park,east fremantle,3191,vic,19571223,7739308 +rec-4604-org,caitlin,morrison,8,augustus close,,clarkson,4170,nsw,19130704,9362649 +rec-617-org,noah,giannoni,81,burraly court,colloca vale,north ryde,6155,qld,19720817,6906870 +rec-3484-org,harry,dignam,22,investigator street,,fairlight,2535,qld,19241105,2134538 +rec-744-org,chevonne,simmonds,24,victory place,dandarra,hoppers crossing,2074,qld,19420531,3553538 +rec-3712-org,heath,everett,7,hurry place,reinfrew park,belmont,2447,qld,19430804,7474300 +rec-1067-org,april,wehr,1,ellerston avenue,darlington,joondanna,2150,wa,19941109,2560536 +rec-52-org,abbey,dixon,1,marcus clarke street,grasmere park,scarborough,3141,qld,19441008,8127929 +rec-3194-org,jarred,rider,500,robinson street,goldview,evans head,3123,nsw,19401202,2875179 +rec-3188-org,jenna,alderson,223,eggleston crescent,west-view,granville,5070,nsw,19780926,6446268 +rec-2246-org,desi,spargo,114,tenison-woods circuit,kenara,abbotsford,7261,qld,19800308,9515868 +rec-2875-org,luke,white,31,outtrim avenue,glenora farm,flinders bay,2227,sa,19151010,6925269 +rec-2491-org,ruby,rollins,28,flinders way,lazy acres,kilsyth,3775,nsw,19941004,3535164 +rec-2995-org,koben,courtenay-ralph,30,illidge place,,st peters,3363,nsw,19921228,1887648 +rec-3509-org,hannah,reid,21,bisdee street,tall pines,malvern,2478,qld,19840208,1762901 +rec-683-org,oscar,zdanowicz,4,arndell street,tilburoo,burwood,2088,vic,19450906,5103704 +rec-4353-org,emiily,rundle,112,tarago place,fiveways,brookvale,2122,nsw,19461226,2419260 +rec-667-org,daniel,rollins,22,hemmings crescent,flt 68,wantirna,3916,nsw,19840108,9812011 +rec-2666-org,laura,hefford,3,partridge street,home 186,banksia,6530,sa,,4977825 +rec-3505-org,charli,soden,37,bee place,,como,3028,nsw,19030206,7856242 +rec-2514-org,ayla,poore,11,cowdery place,richmond caravan park,dover,2200,nsw,19200801,8015794 +rec-2687-org,oscar,chegwidden,12,currong street,terrawah,mount eliza,4824,vic,19981224,6135137 +rec-4369-org,sienna,kilby,21,archdall street,yoorana,st albans,2090,qld,19940203,8614284 +rec-4138-org,justin,weller,3,sprent street,heritage est,thornlie,2074,nsw,19441214,5085526 +rec-3697-org,mystique,agius,79,meeson street,cherry haven,albion park,3104,vic,19070427,4578360 +rec-4144-org,holly,rees,2,palmer street,granny flt,nairne,2387,,19700911,3352448 +rec-2529-org,amy,blake,351,prevost place,warramunda,hammondville,4422,nsw,19920715,6686050 +rec-4690-org,brandon,freiman,27,tucana street,sunnyhills,tweed heads south,2500,nsw,19370325,3419459 +rec-595-org,lucas,portors,6,ballard place,mariner views,noble park,4061,wa,19381227,6890246 +rec-3510-org,kimberly,mason,150,tauss place,,rosewater,7008,nsw,19840507,5663441 +rec-2873-org,rhys,horsley,11,,calala farm,sale,7310,wa,19070227,5179281 +rec-3661-org,hudson,chandler,86,campbell street,lazy acres,whittington,4570,sa,19950220,8352621 +rec-3351-org,adam,reid,50,disney court,,tea tree gully,3690,nsw,19550102,8441272 +rec-1741-org,bryce,laverty,3,dobinson place,weddinview,woombye,3162,nsw,19950921,8513947 +rec-2306-org,zali,white,89,blackman crescent,glenairne,bundaberg,6280,wa,19020311,7291149 +rec-3034-org,emiily,robnik,288,gosse street,townview,werrington,4216,nsw,19671025,8062583 +rec-4297-org,alana,weluk,,cade place,locn 5940,crestmead,7006,nsw,19150308,5179887 +rec-2984-org,emiily,wilkins,22,green street,liselican,darlington,3101,,19610512,5342428 +rec-2371-org,michaela,dunstone,37,deane street,rosedown,woodcroft,2065,vic,19121018,3166178 +rec-1391-org,nicholas,beattie,7,edmondson street,goughs bay,modbury,2036,wa,19170811,3374275 +rec-3615-org,alessandra,van groesen,,arthur circle,hse 4,o'connor,3040,sa,,5885340 +rec-1938-org,noah,bishop,23,shannon circuit,eriswell park,south perth,4551,nsw,19210214,5100494 +rec-2839-org,connor,moscarda,20,lindsay street,shepherds hill,mount beauty,2319,nsw,19010223,1065886 +rec-3500-org,angelica,coleman,31,meldrum street,the briar patch,semaphore south,4035,nsw,19150104,1940066 +rec-4687-org,samantha,papoutsis,21,titheradge place,st francis village,wyoming,3300,vic,19260627,7785823 +rec-3645-org,samuel,coulson,1186,wheatley street,kintyre,acland,3183,qld,19050630,1100698 +rec-3319-org,alyssa,pastars,9,southern cross drive,clarence chambers,thornbury,4659,nsw,19530614,3112840 +rec-2961-org,riley,okoniewski,91,howitt street,rp 24089,rylstone,6174,vic,19101121,1234018 +rec-2-org,olivia,trigwell,13,waldock street,wilpena,new lambton heights,3194,vic,19571126,9991752 +rec-4126-org,nicholas,leung,40,moorhouse street,two tree hill,boondoola,3732,vic,19951115,7261271 +rec-2827-org,mya,hoffman,757,cantor crescent,largo,kallista,5033,wa,19440312,2516740 +rec-308-org,michael,maynard,132,rogers street,leisure living vlge,pooraka,2144,nsw,19570508,3096389 +rec-783-org,joe,clarke,7,skardon street,bonnie doon,north curl curl,4122,sa,19640223,3654594 +rec-1369-org,solomon,wasson,37,hewlett circuit,utopia,mermaid waters,3021,vic,19840211,4681625 +rec-609-org,aiden,krishnan,34,zadow place,the meadows,,3355,qld,19670810,2542394 +rec-4246-org,taylah,nguyen,11,hoddinott street,bridgefoot down,,2022,nsw,19030702,2003210 +rec-22-org,tayah,white,87,chowne street,sweet waters,mona vale,2206,sa,19390323,2815977 +rec-3246-org,isabelle,mccarthy,3,nullagine street,pangani,scarborough,0846,sa,19660628,6386847 +rec-4222-org,luke,wardle,30,holyman street,middle ridge medical centre (cnr ramsay,kirwan,3073,wa,19500525,9974023 +rec-4431-org,hayley,roles,4,newlop street,rabbit warren,acacia ridge,2770,vic,19581005,7340730 +rec-2760-org,tyler,beattie,4,cambridge street,kintyre,deagon,3151,vic,19950713,3309482 +rec-1284-org,harriet,horsley,12,woinarski place,white lodge,mulgrave east,3280,wa,19710926,4215401 +rec-1446-org,christopher,shinnick,39,haugh place,athlone,blacktown,3766,nsw,19230116,8362475 +rec-3664-org,sam,neophyton,16,albermarle place,sec 1,springwood,2500,qld,19670216,6643294 +rec-3007-org,elly,webb,11,gouger street,evergreen,leichhardt,2550,nsw,19240923,6770160 +rec-121-org,alexandra,vinaev,88,kinsella street,brentwood village,leeton,2045,act,19161210,5025450 +rec-4783-org,tahlia,donaldson,59,badimara street,gibraltar,smithfield,3149,qld,19630202,1983061 +rec-1229-org,lauren,perre,22,castleton crescent,karinyah,orange,7250,qld,19820605,6993851 +rec-4941-org,madeline,lowe,272,fergusson crescent,,carrara,6066,sa,19651206,8520720 +rec-2870-org,jaimee,bowerman,1,sainsbury street,tiverton,coonamble,3155,nsw,19510309,2542408 +rec-1331-org,mikayla,mainero,54,haddon street,monkani,graceville,2250,vic,19240330,1458740 +rec-3803-org,imogen,kaleb,39,colebatch place,wearmouth,torquay,2566,nsw,19591029,7623050 +rec-16-org,jade,innis,9,gingana street,ivydale (rsd 1820),seventeen mile rocks,2011,qld,19170426,2049123 +rec-4364-org,harry,boyes,14,kadina crescent,hobbit hole,regents park,3199,qld,19550309,6398424 +rec-3029-org,jake,yeoman,8,shakespeare crescent,westella,penrith,2047,vic,19870808,2098452 +rec-23-org,pace,musolino,16,guerin place,rosetta village,thornbury,4019,nsw,19640423,5906492 +rec-3754-org,joshua,moody,15,glover street,el-woodaro,warren,2304,qld,19580620,9224762 +rec-1641-org,catherine,dolzan,8,burrinjuck crescent,bakers creek,west kempsey,2615,nsw,19441222,8238507 +rec-4627-org,juliana,watkin,18,feint street,laura pengilly wing,doubleview,4032,qld,19710311,8665714 +rec-2064-org,jasper,miles,20,narryer close,moondah,nambour,4113,vic,19160130,3809763 +rec-1672-org,jacobie,shepherdson,316,augusta court,pinda,ardeer,5069,nt,19830606,2226979 +rec-3167-org,alex,fitzpatrick,28,vancouver street,c/-the student village,coomalbidgup,2229,nsw,19240702,4146666 +rec-418-org,simone,goz,313,marconi crescent,alabama,bayswater,3029,qld,19080313,1331839 +rec-677-org,skye,ryan,39,anningie place,terra nostra,macedon,3079,sa,19190311,8669770 +rec-4467-org,oliver,rundle,82,priddle street,myross,dural,2061,nsw,,2156141 +rec-1993-org,talia,collinson,20,oliver street,,paraburdoo,3197,nsw,19320209,1496537 +rec-125-org,ruby,reid,12,judkins street,the willows,airds,4350,sa,19300620,8834327 +rec-4968-org,madeline,switalski,14,clarendon street,lawrence house,belmont north,4034,qld,19710420,5929235 +rec-2546-org,genevieve,ronan,37,mokare street,finis river,yunderup,2675,vic,19980924,9571750 +rec-4348-org,malakai,neville,71,pleasance place,macarthur place,wanniassa,3875,qld,19730731,5739885 +rec-741-org,hannah,candida,48,santalum street,moorabee,,2030,vic,19210519,9787204 +rec-2670-org,kydan,webb,1,emily bulcock crescent,belmont bayview park,fairlight,3055,wa,19510310,9153676 +rec-480-org,luke,mcphie,20,wheadon street,beltunga,christmas creek,6058,nsw,19110123,8869942 +rec-2905-org,destynii,humphreys,41,black street,najee,carrum,4066,nsw,19810924,6458612 +rec-761-org,cameron,lavis,2,albermarle place,dananbilla,glenwood,6442,vic,19410723,5700120 +rec-3734-org,noah,reid,46,truscott street,mckail,dulwich hill,2049,qld,19421216,9564581 +rec-6-org,holly,petersen,13,marou place,never die,birkdale,6530,nsw,19271213,9500792 +rec-2804-org,,gilbertson,5,goodwin street,court units,ethelton,2193,qld,19020904,2879807 +rec-613-org,oliver,tootell,363,shackleton circuit,myola street,cardiff,3182,vic,19000604,8984164 +rec-3749-org,connor,trimble,75,werriwa crescent,scts crk,mill park,2162,nsw,19290729,5610380 +rec-2378-org,shakirah,van der steege,51,newdegate street,airforce memorial estate,darlington,3630,tas,19580903,8013399 +rec-102-org,elli,sindorff,15,lansell circuit,palestine,yagoona,2145,sa,19671114,5791840 +rec-2053-org,flynn,fitzpatrick,19,burns circuit,the willows,tuggerah,3033,vic,19550713,1010947 +rec-3512-org,alex,webb,92,outtrim avenue,st francis village,paddington,3056,nsw,19700807,5594371 +rec-1152-org,samuel,wilkins,16,schlich street,wildes mdw,hayborough,3152,nsw,19680910,2994606 +rec-606-org,taliah,morrison,7,cope place,strawberry fields,dover,6714,nsw,19090828,3519655 +rec-1707-org,giorgia,smallacombe,10,dundas court,somerton park,glengarry,4108,sa,19990313,6657239 +rec-3804-org,benjamin,hartland,40,ranken place,sorrento,collie,3799,qld,19080206,7081220 +rec-3780-org,ethan,hand,1,lambrigg street,rainmore,south perth,5075,vic,19410622,3559862 +rec-1147-org,michael,boyle,3,river street,,lakemba,2611,vic,19091217,7962096 +rec-4318-org,timothy,matthews,2,blandon place,harrowvale,mill park,3184,nsw,19560930,6083907 +rec-1997-org,cassandra,webb,15,wentworth avenue,,mill park,5290,nsw,19300310,2827902 +rec-1059-org,judah,clarke,27,duncan street,table mountain,aspley,4670,nsw,19190222,7875071 +rec-548-org,jade,worsley,,waller crescent,st francis vlge,cabramatta,7190,qld,19491001,6141371 +rec-963-org,clodagh,sieber,14,pandanus street,highfields medical centre,davistown,4066,nsw,19140913,2698880 +rec-2505-org,caleb,bristow,134,brunswick circuit,granny flat rear,mclaren flat,5019,tas,19720321,7570563 +rec-2906-org,nicholas,wheatley,64,cox street,venture,fennell bay,4740,qld,19681129,6155450 +rec-4681-org,meg,matthews,42,mccawley street,vambi back,carlingford,6058,qld,19850331,6932257 +rec-4058-org,benjamin,coleman,12,canopus crescent,,port kembla,2795,qld,19010422,1651755 +rec-2120-org,kylie,stanley,10,bugden avenue,wrem house,nunawading,2653,sa,19481020,6634230 +rec-2090-org,aiden,mcmellon,10,cromwell circuit,redwood lodge,wanneroo,2666,vic,19301206,9452274 +rec-1481-org,thomas,humphreys,35,mayne street,gull cottage,the entrance,2000,qld,19880516,3033985 +rec-3538-org,benjamin,everett,17,herron crescent,redhill,forrestfield,3550,nsw,19621023,2043392 +rec-4723-org,tommy,morrison,49,mcnamara street,rowan lodge,north ryde,2038,nsw,19231010,1815246 +rec-4848-org,rachel,godfrey,41,discovery street,2/98-latchford barracks,trigg,6019,wa,19030330,7434268 +rec-1359-org,jacob,maynard,11,lutana street,caprice,lower templestowe,2720,nsw,19370219,2009297 +rec-4845-org,michael,acciairresa,18,eyre street,george forbes house,preston,4218,vic,19580720,5106898 +rec-3141-org,blaize,matthews,119,mirning crescent,laurel bank,ardrossan,2550,nsw,19441202,5876491 +rec-3738-org,imogen,carlington,45,mcinnes street,parish talowahl,girilambone,2154,nsw,19781117,7912921 +rec-2294-org,tasman,green,36,wynn street,nixon hostel,penrith,2132,qld,19390608,2928427 +rec-3848-org,chelsea,sherriff,16,gellibrand street,electorate office,willetton,4680,qld,19221231,6905458 +rec-1712-org,christina,taute,30,casson street,old mia mia school,swan hill,2161,qld,19461002,1050753 +rec-4384-org,marley,waller,9,namatjira drive,dangaroo park,unanderra,2614,sa,19350812,3973825 +rec-1802-org,ellen,hare,9,windradyne street,,rosebud,6076,nsw,19910512,5036453 +rec-3632-org,connor,godfrey,50,centaurus street,locn 5940,o'sullivan beach,2216,qld,19010823,7376725 +rec-870-org,jessica,bradshaw,,wheadon street,yarrabin,minyip,2290,nsw,19080415,5572327 +rec-4618-org,chloe,musolino,19,warrumbul street,gordonvale,brighton,3782,nt,,7147784 +rec-4585-org,hayley,mortlock,19,augustus close,ronobri,tallebudgera,2630,nsw,19110617,9154301 +rec-178-org,kirra,okoniewski,11,,molyneux hse,kardinya,5330,nsw,19700823,2077704 +rec-1220-org,lauren,weltman,6,tewksbury circuit,heritage estate,evans head,6330,nsw,19840930,9462453 +rec-612-org,jake,david,13,pearson street,henry kendall bayside,casino,2076,sa,19320306,5193402 +rec-843-org,montana,hawes,15,lange place,richon,glenmore park,6530,nsw,19310914,7814038 +rec-4726-org,raquel,,11,windeyer street,kookaburra village,revesby,2134,qld,19850128,1770895 +rec-1384-org,ruby,mason,24,weatherburn place,yammacoona,tarragindi,5606,vic,19090627,4941274 +rec-2662-org,,fullerton,20,leichhardt street,gostwyck,chelsea heights,6107,nsw,19620113,4058902 +rec-4456-org,chloe,grosvenor,13,clyne place,waddi,scarness,2478,nsw,19800606,2830335 +rec-3318-org,leah,eisele,16,howie court,oaks caravan village,dunkeld,2505,nsw,,6306615 +rec-30-org,xavier,campbell,9,norton street,pine camp,coniston,5092,nsw,19640316,9178267 +rec-1584-org,james,murabito,138,mcelhone court,balmain cove,collie,6023,vic,19080720,4654129 +rec-624-org,abby,spark,36,cordeaux street,mortlock house,mittagong,2217,vic,19930311,8511819 +rec-172-org,adam,craze,,mcclintock street,loma langie,portarlington,3199,wa,19270510,3239913 +rec-652-org,dylan,nickolai,46,jackie howe crescent,bonnie doon,waramanga,2535,nsw,,6519452 +rec-333-org,joshua,akot,8,edmunds place,villa 18,dapto,6071,vic,19010703,3188786 +rec-2558-org,tyler,dolan,189,staaten crescent,newnham house,ringwood north,6059,qld,19821028,6683175 +rec-1876-org,abbey,lewkowicz,33,stead place,dalamar,minchinbury,6108,nsw,19240802,1187314 +rec-692-org,tiahnee,excell,33,aroona court,normanville mews,watsonia,2290,nsw,19971223,5973196 +rec-860-org,daniel,belperio,17,templeton street,murray vale murray valley,gawler west,2066,nsw,,8978859 +rec-4275-org,isobel,burnell,4,heidelberg street,cinema centre bldg,stretton,5680,vic,19900603,1027213 +rec-4487-org,madison,blake,17,owen crescent,pontresina,burraneer,4701,vic,19470410,6459959 +rec-136-org,emmerson,dolan,339,tewksbury circuit,weeroona,parkside,3216,nsw,19180630,3018384 +rec-3813-org,amy,mason,279,casuarina street,memorial hospital,bundaberg,3056,vic,19121126,4368305 +rec-2938-org,stephanie,dudek,181,forbes street,,buddina,3226,qld,19130127,6246452 +rec-2194-org,samantha,lock,6,o'sullivan street,brentwood vlge,yarra junction,7320,vic,19380113,3912051 +rec-3470-org,dominic,alderson,309,clamp place,,bundamba,2766,sa,19871130,1163272 +rec-1349-org,daniella,boothroyd,101,elkington street,witsend,waterloo,6058,sa,19600904,7721398 +rec-4657-org,joshua,coleman,16,mosman place,aralee,kooyong,3431,nsw,19501024,2640319 +rec-1061-org,pia,chell,17,bayley street,youralla,,2614,qld,19400227,4770120 +rec-1377-org,david,stapenell,31,gosse street,treetops,new farm,2582,qld,19710118,6109183 +rec-824-org,holly,clarke,16,ballumbir street,talooby,sale,3163,nsw,19121217,8303839 +rec-1513-org,madeline,adair,2,allman circuit,robboview,balwyn north,6006,vic,19410309,7581364 +rec-3005-org,charles,white,23,westbury circuit,albion heights,dover heights,2107,qld,19470123,5209300 +rec-4213-org,adam,matthews,64,elvire place,mt pleasant,port macquarie,2210,tas,19181115,3647256 +rec-4127-org,dayna,gilfedder,104,burgan place,edwards chambers,hawthorn,3191,nsw,19520413,7277011 +rec-3431-org,harry,rollins,22,antill street,valbella,mount isa,3142,wa,19240905,5927194 +rec-0-org,rachael,dent,1,knox street,lakewood estate,byford,4129,vic,19280722,1683994 +rec-2346-org,nathan,clarke,12,forbes street,rainbow park rp 8965,flinders park,2117,qld,19500725,5135466 +rec-576-org,james,kempson,14,melia place,birks harbour,elwood,2350,nsw,19480708,1343391 +rec-3926-org,stephanie,reid,4,bugden avenue,tudor,avalon,2290,nsw,19351106,1287472 +rec-2771-org,joshua,petersen,8,wybalena grove,lyra park,surry hills,3162,vic,19420824,4895026 +rec-4500-org,zali,mcgregor,25,goulburn street,,richlands,4307,qld,19490225,9800116 +rec-3274-org,dominic,hoggan,29,devanny place,birrabilla,portarlington,3175,nsw,19561215,5034600 +rec-4209-org,joshua,pringle,13,fred johns crescent,glenview,elwood,2640,sa,19720127,9406321 +rec-3307-org,chevonne,wilkins,18,wilga place,the slipway,kellyville,4215,sa,19721204,9505241 +rec-384-org,michael,richmond,7,tanumbirini street,professional centre,bundaberg,3020,sa,19650831,6836733 +rec-3882-org,jacob,siviour,12,dobbie place,brentwood vlge,gundagai,2839,qld,19160602,6846430 +rec-4938-org,lushia,mason,26,mcdermott street,tundarra,balwyn north,2099,nsw,19261204,6453135 +rec-2705-org,holly,ryan,9,cradle close,frm 654,safety bay,2074,qld,19310814,7222933 +rec-1104-org,andrew,berry,70,galibal street,blue haven village,ascot,5606,sa,19540522,4799173 +rec-925-org,makenzi,quan,18,duffy street,sutherwood north,hoppers crossing,2615,wa,19711213,9713887 +rec-2185-org,mia,garrigan,53,michie street,westholme,armidale,3178,nsw,19700522,6416070 +rec-4190-org,zane,crouch,9,allan street,sbend carvn park,invermay,2135,tas,19590501,6678712 +rec-4478-org,joel,reid,7,pearson street,lytton,floreat,3153,qld,19051112,1523622 +rec-3604-org,wil,clarke,8,osburn drive,guest village (cnr bullcreek d drive,chelsea heights,5700,nsw,19100504,2181436 +rec-210-org,chelsie,,27,kauper street,lesma,eastwood,4070,nsw,19161017,6512341 +rec-4367-org,pakita,beams,73,strangways street,upson & downs,hadspen,6014,qld,19520203,1295582 +rec-2112-org,lachlan,hage,34,ballumbir street,opal cove resort,newmarket,6061,nsw,19850523,3230581 +rec-242-org,joshua,green,13,duncan street,euroka,artarmon,4871,qld,19970505,4108253 +rec-2045-org,jack,steinert,21,lamington street,st francis village,holden hill,7010,sa,19680119,5389848 +rec-3961-org,emma,thorpe,60,sharwood crescent,wyuna,warriewood,4510,vic,19211218,3969676 +rec-3723-org,lara,carbone,61,beasley street,ebony's retreat,bossley park,5343,vic,19560105,2542464 +rec-1652-org,zac,ebdell,,outtrim avenue,gogulger stock,preston,4123,vic,19461126,3704089 +rec-4301-org,nicholas,hassall,8,laughton street,anzac house (cnr archer s street,highton,3028,sa,19040622,3632388 +rec-2901-org,harrison,laing,158,bunbury street,brightling park,wamberal,2086,wa,19620510,1807525 +rec-495-org,madison,renfrey,7,mcdougall street,pine hill,bundaberg,6010,vic,19070611,5700724 +rec-1942-org,jessica,mccarthy,131,eagle circuit,sherwood,findon,0812,sa,19341117,5667929 +rec-2515-org,abbey,colquhoun,21,buntine crescent,glen eden,thornlie,2390,nsw,19960607,7703106 +rec-4380-org,timothy,plume,130,forsythe street,breakaway creek es,barrington,5032,vic,19861022,6729470 +rec-3672-org,stella,mason,408,kallara close,the parks,mount eliza,4122,wa,19510426,7535262 +rec-586-org,wilson,green,2,jaeger circuit,bungarra,corio,2650,qld,19111005,8910567 +rec-4818-org,alexandra,yiannoulis,159,archdall street,tall pines,rowville,3284,vic,19790913,7515259 +rec-2635-org,isabelle,,14,larkin close,naringal orchard,box hill south,2402,nsw,19440723,3423612 +rec-4300-org,elana,manivone,980,crisp circuit,broughton brook,midland,2768,qld,19720103,9877933 +rec-2460-org,,felmingham,49,gawler crescent,wingara,wynnum west,6159,nsw,19920718,7791969 +rec-3530-org,lucy,millar,57,duffy street,burtons lookout,wyoming,2325,sa,19171121,3254520 +rec-2406-org,samantha,white,9,tillyard drive,tieve tara,hawthorne,3068,vic,19310120,8686735 +rec-4685-org,kelsea,worsley,65,mackellar crescent,,hemmant,4208,qld,19990610,6206107 +rec-3368-org,sienna,richmond,37,kitchener street,reynolds dale,whitebridge,2151,wa,19440523,4917696 +rec-468-org,connor,arda,35,fenner street,summervale,south melbourne,2530,wa,19750417,9721130 +rec-1051-org,timothy,modystach,32,julia flynn avenue,rcg centre,charlestown,4655,vic,19671125,2430623 +rec-4975-org,shelbey,green,122,edmondson street,green desert,tannalo,2145,vic,19101201,9171137 +rec-4070-org,hamish,chandler,9,eton place,allanvale,bribie island,2831,tas,19871001,3981694 +rec-4416-org,ben,nguyen,17,tipiloura street,centenary marketplace,bayview heights,2049,nt,19731201,1783041 +rec-1854-org,lucas,rider,17,mount vernon drive,boonsville,whitfield,3193,vic,19561024,7575668 +rec-3687-org,maya,ryan,74,medley street,glen echo,westmead,2500,nsw,19360504,5518965 +rec-3757-org,bailey,petersen,1,goodman street,nioka,plympton south,4214,qld,19090102,3547315 +rec-2234-org,jack,katarski,3,lange place,rose gardens touri,rowville,3975,qld,19320704,8850947 +rec-4745-org,lucas,kulesza,7,bertel crescent,southern cross,lawrence,2577,wa,19460901,1047465 +rec-3396-org,cain,synnet,17,langdon avenue,millard centre,leichhardt,2652,nsw,19881209,9321868 +rec-2708-org,alana,mcgregor,8,chandler street,loughmore,blue rocks,5081,nsw,19841227,3230948 +rec-3214-org,tanar,saccardo,43,irvine street,anzac house (cnr archer s street,canterbury,3690,wa,19100526,7953897 +rec-2656-org,talia,petersen,15,callaway crescent,karoola,hoppers crossing,4515,sa,19000307,3839840 +rec-213-org,finn,ryan,5,spowers circuit,champsaur,coombabah,2536,vic,19500807,3429777 +rec-414-org,benjamin,liccioni,2,golden grove,jestarlei,lavington,2042,wa,19100711,2197467 +rec-2701-org,keelin,kalnins,2,ellerston avenue,goughs bay,berwick,2022,nsw,19621011,7541911 +rec-2314-org,jake,gillard,121,blackbutt street,ethnam farm,maitland,3088,nsw,19590828,1616065 +rec-4774-org,elana,wilkins,11,blowering street,homevale,st kilda east,7183,nsw,19920601,4088657 +rec-1479-org,jessica,fabel,28,hilder street,mount beauty,glenlee,2116,sa,19140806,5932691 +rec-4009-org,ruby,parashar,773,tytherleigh street,the willows,eastwood,4605,sa,19900510,1990268 +rec-4426-org,bailee,dooley,24,balfour crescent,baybreeze,bowral,3152,vic,19140520,5906239 +rec-1071-org,braiden,hohn,6,swinden street,alanvale,mulgrave east,7140,nsw,19920920,4170069 +rec-4785-org,imogen,miles,14,smalley circuit,tingara vlge,toorak,2259,sa,19070626,4846134 +rec-927-org,claudia,white,76,willoughby crescent,greenslopes,albion park rail,3178,wa,19810107,1170705 +rec-78-org,stelio,hand,23,mehaffey crescent,airforce memorial estate,roleystone,2456,nsw,19540125,3373062 +rec-729-org,aidan,hamdan,163,bacchus circuit,mermaid plaza dental centre (cnr gold co,mitcham,2710,qld,19101119,1603791 +rec-647-org,henry,greenhalgh,2,elizabeth crescent,murray vale u p a,shorncliffe,4516,wa,19670212,3335029 +rec-3626-org,sophie,wynne,25,leahy close,box range,beechboro,2340,wa,19940105,5948897 +rec-1148-org,emiily,reid,32,ina gregory circuit,,camira,3172,nsw,19041113,8734967 +rec-1717-org,jade,binns,2,fiveash street,caterer,auburn,3690,nsw,19470306,5117331 +rec-2252-org,allegra,cobbin,19,abbott street,palestine,glenside,3400,nsw,19690819,8391278 +rec-3056-org,wil,whiteley,93,simpson street,strathleven,kingston,2151,wa,19440822,8896048 +rec-1528-org,,muthukuda,11,waratah street,keira,thornlie,0820,vic,19890328,5670243 +rec-3983-org,benjamin,paine,277,,rose lane centre,glengowrie,2046,vic,19531018,3571554 +rec-4392-org,lochlan,reifferscheidt,626,carrington road,haigh park,eaton,4172,vic,19020119,6477624 +rec-3654-org,raquel,vandonderen,23,clift crescent,albaredo,maryborough,5113,nsw,19591023,7083852 +rec-458-org,blake,cheers,217,rees place,,dalby,6021,qld,19751205,6719640 +rec-1645-org,christian,drechsler,75,white crescent,,summer hill,7018,sa,19580327,1471940 +rec-1167-org,sara-louise,chandler,309,schonell circuit,shoal bay,sheidow park,2761,nsw,19050207,3731436 +rec-1999-org,kirra,fitzpatrick,21,dodwell street,dusty corner,midvale,5083,vic,19141108,9581574 +rec-1041-org,madison,coltman,5,cowlishaw street,tathra river est,goonellabah,3075,vic,19560602,2561010 +rec-5-org,josephine,yu,145,hensman street,lambar,burwood,6164,wa,19110903,5792336 +rec-4955-org,callum,hauser,2,nambir court,zeevoo,mount annan,2641,vic,19480329,3757652 +rec-3987-org,thomas,orchard,,maribyrnong avenue,the broadwalk arcade,huntfield heights,6210,vic,19841206,1818117 +rec-3758-org,timothy,jesser,,hackett garden,narraburra lodge,killara,2283,vic,19000601,9949289 +rec-1924-org,alexandra,nguyen,26,fremantle drive,merricroft,highton,6532,nsw,19440220,2682401 +rec-920-org,benjamin,clarke,122,archibald street,locn 1487,nickol,2535,nsw,19010518,1978760 +rec-727-org,daniel,mason,10,hazel smith crescent,grant patch,rochedale south,3688,vic,19900531,3210073 +rec-2605-org,oliver,jennions,4,o'shanassy street,rye park,glenmore park,3555,nsw,19500316,1498603 +rec-3648-org,matilda,ryan,5,bogan place,aldinga beach court,bethania,2259,nsw,19401012,6674118 +rec-152-org,lewis,portlock,11,english court,,burwood,2541,nsw,19240603,6033701 +rec-1608-org,callum,moyse,7,lynch street,walkabout palms,brighton-le-sands,4740,tas,19130714,5145083 +rec-2527-org,ryleh,miles,7,yarra street,annecy park,carlingford,3616,nsw,19850930,8262494 +rec-3810-org,kalli,watkin,187,getting crescent,koah lodge,newrybar,4301,vic,19031202,2486965 +rec-4281-org,sara,carmody,14,gilmore crescent,brentwood vlge,denmark,4560,wa,19830421,7880298 +rec-3089-org,annabel,thorpe,19,ardlethan street,galloway,rokeby,4670,vic,19920305,2814912 +rec-2755-org,robert,maczkowiack,40,broadbent street,jandera south,port lincoln,6153,nsw,19030102,4106094 +rec-355-org,eva,painter,116,castleton crescent,mawingo,malvern east,3338,nsw,19770419,6468703 +rec-1125-org,callum,jancek,22,darley place,garema place surgery,ballarat north,4745,nsw,19201229,2980733 +rec-1432-org,tarshya,hazell,51,chauvel circle,,toorak,3073,nsw,19211102,1853367 +rec-3428-org,ashlee,bishop,40,john james hospital,omaha,dromana,4816,nsw,19000916,8269833 +rec-3334-org,keely,demarco,56,serpentine street,,mona vale,5113,wa,19910622,2184846 +rec-4365-org,georgia,glover-smith,34,howse street,,raby,5340,wa,19790813,8934327 +rec-3219-org,oliver,ryan,23,candlebark close,holiday vlge,banks,4570,vic,19100420,5337535 +rec-1967-org,eboni,kempton,22,walton street,henry kendall bayside,vale park,2205,sa,19330113,3037416 +rec-4580-org,caleb,webb,52,badimara street,retirement village,kuraby,4655,qld,19890709,7501704 +rec-760-org,lachlan,nguyen,70,bushby close,locheil,wilson,5046,nsw,19660926,4360586 +rec-4217-org,barnaby,dixon,21,charteris crescent,,ascot vale,5012,nsw,19960422,4817798 +rec-3825-org,rosie,white,2,snowden place,brambletye vinyard,black rock,0835,wa,19020405,4810152 +rec-4003-org,andrew,simmonds,9,blackman crescent,ra 23012,ashgrove,2204,nt,19131226,1378126 +rec-1057-org,samara,pringle,7,allan street,bonnie doon,campbelltown,5073,nsw,19560429,3493586 +rec-3009-org,ruby,clarke,368,jackie howe crescent,parklands village,bundaberg,2030,nsw,19250903,9905791 +rec-2730-org,,white,28,young street,ripplevale,maydena,3102,nsw,19260930,2545305 +rec-2661-org,riley,mort,4,shirra close,the meadows,kalamunda,0880,nsw,19870801,4540256 +rec-4947-org,evangelia,purser,10,lahey place,rowethorpe,malabar,4034,vic,19260924,1704541 +rec-4596-org,jai,browne,124,eugenia street,jacqoona station,ascot vale,3350,wa,19030809,8431885 +rec-2860-org,zane,white,15,mcwhae circuit,westmead accom,concord west,2032,vic,19770208,9225108 +rec-2260-org,adam,adair,14,wattle street,red arrow,albany creek,2825,nsw,19560420,1699586 +rec-4811-org,sophie,grosser,86,tryon street,bethel hostel,bull creek,3875,wa,19011031,6415988 +rec-4171-org,adam,clarke,3,skinner street,kona,woodcroft,4878,wa,19270705,7112414 +rec-4666-org,john-paul,parr,22,david street,greater cess vill,croydon north,4737,wa,19800811,8703902 +rec-3908-org,emiily,bradshaw,19,parkhill street,foxdown,south grafton,4207,vic,19270912,2964855 +rec-1729-org,hayden,thredgold,7,callaway crescent,danric lodge,keilor park,2365,nsw,19370416,5433941 +rec-3206-org,freya,marlow,4,barlow street,merryvale,berwick,3400,tas,19661021,8600151 +rec-4842-org,ainsley,shepherdson,16,jackie howe crescent,huntawyle,moorooka,2261,nsw,19161125,3591742 +rec-1106-org,emiily,nguyen,215,lelta place,yanalah,nowra,4179,qld,19091124,2809085 +rec-204-org,jed,boulter,41,mcmillan crescent,old post office,bundaberg,5213,nsw,19471229,2521349 +rec-4406-org,caleb,newberry,14,mackenzie street,mountainview retirement vlge,emerald,2560,sa,19211203,1454135 +rec-2650-org,caitlin,de boar,21,crisp street,section,jan juc,5400,nsw,19460307,3080624 +rec-2907-org,tiarna,cannell,685,deacon close,,wooli,2287,wa,19020305,6547713 +rec-2140-org,matthew,jardine,36,sainsbury street,alice downs,windsor,4573,nsw,19180805,2211117 +rec-3776-org,joshua,heron,23,dooring street,drypoint,barraba,4214,nsw,19700227,6931228 +rec-1847-org,luke,karlsen,119,mckenzie street,moonee beach caravan park,woodlands,2224,vic,19060425,3838005 +rec-187-org,henry,varcoe,4,fox place,cabbage tree,robina,6051,wa,19440630,4816938 +rec-1355-org,hannah,morrison,14,strzelecki crescent,orchid square,auburn,2151,qld,19010126,4820527 +rec-1174-org,lily,browne,1,spring range road,wandella park snowy,somerset,2042,qld,19990812,1727298 +rec-2433-org,joselyn,brus,21,carandini street,,murray bridge,2090,tas,19020520,6801064 +rec-1840-org,lachlan,crouch,21,northbourne avenue,navillus,sherwood,4305,qld,19781007,5148084 +rec-2325-org,ajay,poumako,100,bedford street,youralla,rostrevor,3029,qld,19540417,4762088 +rec-4298-org,mitchell,wheatley,63,embling street,,mongarlowe,2795,qld,19641102,3016745 +rec-777-org,charlotte,needham,46,wattle street,courallie,colo vale,3161,sa,19890118,2377987 +rec-4123-org,leah,huxley,4,knoke avenue,,minto,2782,nsw,19680903,4353919 +rec-3069-org,ashleigh,droegemueller,8,callaghan street,osters,adamstown,3070,nsw,19300808,1309189 +rec-1030-org,trey,saines,26,throssell street,kindilan,buff point,4161,act,19110205,2740304 +rec-3703-org,holly,harrington,340,kirkton street,barwick pastoral,taringa,4454,vic,19180806,6513574 +rec-3241-org,jacob,o'shannessy,233,osburn drive,goldenoaks village,maitland,2640,nsw,19380807,4654746 +rec-4566-org,archie,mccarthy,9,playoust place,keriroca,ascot,3919,vic,19591221,4937930 +rec-2939-org,lauren,gastarini,12,spowers circuit,menedebri,modbury,4680,vic,19731226,5596194 +rec-4970-org,ethan,muthukuda,25,,glen fern,hillside,2250,vic,19581107,4421577 +rec-4864-org,thomas,campbell,45,windich street,spring vale,blacktown,7304,nsw,19640105,4359063 +rec-4923-org,christian,wallin,214,arabana street,brentwood village,abercrombie,2107,vic,19151009,3484473 +rec-1018-org,bianca,cobbett,32,yerralee road,wongon,woodend,3083,vic,,1020735 +rec-4935-org,luke,broadhead,44,sewell place,golden down,waterloo corner,3123,qld,19571018,8632021 +rec-2297-org,thomas,rankine,7,davis street,veone,bossley park,2127,vic,19280703,6882558 +rec-440-org,james,alderson,52,bellchambers crescent,paddy's river,,3337,qld,19071013,4232347 +rec-1963-org,brooke,green,14,laker crescent,sapri,whittingham,2166,wa,19920111,6640023 +rec-2486-org,mitchell,ramush,1,hann street,keira,sunshine beach,3943,sa,19480321,7925486 +rec-1529-org,zachariah,campbell,32,gellibrand street,carowood,keswick,3148,vic,19271210,2544494 +rec-516-org,ruby,hulley,,knaggs crescent,strabane,bayswater north,2283,wa,19201008,3808150 +rec-4238-org,zachariah,nadels,68,dennys place,laureldale,northgate,2133,qld,19801214,9144398 +rec-993-org,jack,fitzpatrick,,condell street,sec 1,fullarton,2221,vic,19041121,9595043 +rec-1516-org,trey,goetze,4,petterd street,bonny doon,brighton,7054,qld,19520118,1744778 +rec-4701-org,sean,varcoe,29,osburn drive,bonaza park,ferndale,4560,nsw,19601031,7839163 +rec-4953-org,christian,goetze,5,manna close,torrington,mill park,2323,nsw,19510117,3619285 +rec-4507-org,william,colquhoun,955,smalley circuit,villa 3,harbord,2200,vic,19141107,1327358 +rec-812-org,oliver,agius,54,ashburton circuit,gilston lodge,bray park,2161,wa,19651114,6136263 +rec-3822-org,kristo,matthews,632,southern cross drive,mafeking,pelican waters,2284,wa,19760312,5609707 +rec-1009-org,,clarke,14,,rowethorpe,newcastle,2220,vic,19670314,9542197 +rec-3993-org,ruby,ackermans,,luehmann street,mt pleasant,tongala,2640,nsw,19090322,9034954 +rec-3469-org,richard,roche,104,beaurepaire crescent,the garden village,cranbourne,3073,nsw,19870624,5733343 +rec-976-org,isabelle,campbell,1,jukes street,pine tree,port fairy,4811,qld,19820103,6554212 +rec-2228-org,william,ziswiler,68,bellchambers crescent,galloway,queenscliff,2218,vic,19010406,5172369 +rec-4446-org,zachary,bradshaw,106,totterdell street,barossa village,colo vale,3444,qld,19151219,6773972 +rec-1216-org,matthew,raward,2,duffus place,stephens creek,mount gravatt,4011,qld,19580630,6865352 +rec-4593-org,georgia,rundle,3,hicks street,blackbutwood,orange,3078,nsw,19910726,4860814 +rec-407-org,riley,rees,9,archibald street,wispering pines,coonabarabran,5162,wa,19700922,4932145 +rec-3256-org,liam,grainger,251,magrath crescent,brindabella specialist centre,mclaren flat,2041,nsw,19690906,9030428 +rec-561-org,jack,,3,light street,pine hill,windermere,3212,vic,19651013,1551941 +rec-4278-org,sophie,bevis,8,bungonia street,fernlea,ringwood east,2541,vic,19820602,4133682 +rec-2342-org,lauren,hilton,16,grayson street,glenmore,corio,2645,wa,19150223,5611249 +rec-463-org,molly,slape,23,currie crescent,dickson family practice,glenwood,2777,wa,19370706,6905342 +rec-1633-org,nicholas,matson,17,stephen street,taylors creek bridge,cowell,2454,vic,19990419,3182512 +rec-2232-org,jinni,grossman,5,maddison close,langunyah,north ryde,5253,nsw,19251101,9474636 +rec-3591-org,jayden,markellos,21,la perouse street,fairholme,toorak,3121,sa,19620130,4234492 +rec-2636-org,abigail,petersen,42,tauss place,kacadoo,abbotsford,3630,vic,19560125,6593871 +rec-394-org,lachlan,ryan,51,totterdell street,roseglen,dalby,3168,qld,19480724,7284475 +rec-99-org,blake,wehr,27,naas close,rowethorpe,stockton,2151,wa,19440131,7528586 +rec-1862-org,brydon,macgowan,14,jaeger circuit,glenview,oaklands park,7262,act,19130615,8190321 +rec-3353-org,jack,coleman,7,cumming place,rio rita caravn park,dandenong north,6026,sa,19560223,9860608 +rec-4760-org,molly,clarke,398,cameron street,stonyridge,windsor,5086,nsw,19210202,2679994 +rec-1786-org,taliah,clarke,16,,brentwood vlge,greenacre,4158,qld,19521121,8211585 +rec-708-org,mila,campbell,36,beasley street,krismark,dalby,2357,nsw,19010602,5343180 +rec-2452-org,beth,donaldson,24,crisp circuit,cherrymount,camooweal,4730,vic,19461229,6917434 +rec-1679-org,lachlan,plumb,14,garling street,brentwood vlge,julatten,4217,vic,19550313,2243015 +rec-4255-org,nathan,webb,,cumpston place,the summer house,wanguri,6215,tas,19660404,7465594 +rec-2339-org,jarod,clarke,19,boldrewood street,locn 7560,fairlight,2028,vic,19151004,9604490 +rec-1702-org,michael,drechsler,5,hone place,,newcomb,3032,qld,19291014,3902049 +rec-1822-org,maddison,fullgrabe,44,scarlett street,allunga,forest glen,5070,qld,19110327,3898794 +rec-2216-org,madison,struck,40,drake brockman drive,eden park,st albans,4218,nsw,19600814,8963800 +rec-4236-org,bailee,berryman,7,jarrah street,bishops creek,stanhope,4053,sa,19780405,1761772 +rec-3519-org,brock,matthews,14,blamey crescent,waverley lodge,toowoomba,3205,wa,19490214,4338969 +rec-2338-org,damien,webb,34,molesworth street,fairfield housing bg,werribee south,2448,qld,19440826,5682631 +rec-4183-org,layla,stening,54,la perouse street,tewantin plaza,coolbellup,4740,tas,19850119,5169349 +rec-1811-org,jack,campbell,11,bremer street,sec 1,san remo,2134,tas,19291016,2920956 +rec-2000-org,cain,dooley,85,boobialla street,osborne house,marsden,2284,vic,19570621,5346367 +rec-3335-org,lily,musolino,13,fernyhough crescent,gunn's gully,burwood east,2097,qld,19600226,9776077 +rec-1555-org,jaykob,cochrane,1,fowler place,sugden glen,tweed heads,4503,nsw,19390209,7792214 +rec-2386-org,mitchell,hunting,14,catchpole street,windara,,3155,qld,19050619,7824179 +rec-4266-org,christopher,george,12,loftus street,brookvale,mayfield,6016,nsw,19741228,2025503 +rec-2359-org,mackenzi,jarick,51,wilkinson street,willow lodge,picton,2117,vic,19240823,4264896 +rec-2710-org,jordan,mirritjawuy,8,batchelor street,st vincents medical centre,applecross,3505,sa,19250215,1153859 +rec-4710-org,,robson,10,flegg crescent,kuliup,woongarrah,3149,nsw,19880603,6084403 +rec-2837-org,raquel,mason,17,,,,3225,qld,19341010,1823323 +rec-179-org,vincent,braithwaite,29,tweed place,brileen,cabramatta,5051,vic,19740815,8052521 +rec-397-org,elizabeth,wojciechowski,16,walker crescent,phillip lodge,winston hills,2250,vic,19190118,6972527 +rec-1092-org,jaykob,ladyman,76,carbeen street,apmnt 65,guyra,2564,vic,19071217,2992907 +rec-29-org,kylee,kincaid,16,eucumbene drive,ochiltree,leongatha,2232,qld,19300802,4662381 +rec-1910-org,campbell,jeffries,12,calder crescent,yarrabee,abbotsford,4560,nsw,19810621,9991473 +rec-4676-org,joshua,coffey,2,blueberry street,yalgoora,kings park,2502,wa,19240713,9217500 +rec-4078-org,harrison,leung,36,catchpole street,,mountain creek,3057,nsw,19640118,2584055 +rec-669-org,chelsea,ryan,50,osburn drive,hansons estate,punchbowl,4869,nsw,19091017,6615930 +rec-504-org,joshua,balchin,12,hadleigh circuit,tulloch,deer park,2318,sa,19100615,3829737 +rec-445-org,jaxin,mccarthy,46,dalyell street,wiringa,marsden,3142,nsw,19640914,9531739 +rec-71-org,connor,tromp,8,eildon place,willtarny,east maitland,4740,qld,19280129,8096262 +rec-1723-org,connor,karvelas,,ballow crescent,gold ridge,irymple,5357,vic,19311120,9256286 +rec-861-org,chantelle,seppelt,6,cruikshank street,oaklands village,burrum heads,2212,vic,19370814,8334319 +rec-3957-org,samuel,green,96,duffy street,bogandina prop,lavington,2112,qld,19690309,4678214 +rec-4378-org,mia,koeman,20,wattle street,elston,cabramatta,4068,vic,19670212,2071975 +rec-726-org,jaden,allanby,2,pelham close,central clinic,broulee,5523,sa,19660707,3196657 +rec-1437-org,michael,sideris,45,,erinundra,yarram,6059,qld,19510317,9096326 +rec-442-org,william,matthews,5205,tunney crescent,rainbow downs,andergrove,2146,nsw,19981106,7834791 +rec-3406-org,zachariah,bulgin,3,throssell street,farn 43,modbury,2190,nsw,19590703,5683667 +rec-3719-org,connor,baillie,186,lambie place,,port lincoln,7303,qld,19670529,4702335 +rec-1379-org,amber,grubb,,eady street,corella,edithvale,2590,nsw,19850127,1191313 +rec-645-org,benjamin,berryman,43,thornhill crescent,country club,magill,2073,qld,19360111,7934124 +rec-1368-org,matteus,leong,13,hawkesbury crescent,bonnie doon,raymond terrace,3129,qld,19621228,5792923 +rec-4402-org,charles,flaus,43,andamooka street,parkfield,pakenham,2845,,19230110,8983783 +rec-2089-org,william,white,33,downes place,,normanhurst,3057,sa,19970306,9053801 +rec-2743-org,henry,mccarthy,94,beasley street,crystal brook farm,ingleburn,6164,nsw,19770913,1347524 +rec-4237-org,braedon,paine,15,edwards street,narellan court,young,3030,qld,19871225,8743183 +rec-221-org,samantha,mapstone,44,hutchins street,golden ponds resort,maitland,2076,sa,19941127,4499927 +rec-3559-org,rebecca,wojciechowski,16,evergood close,diment towers,pelican waters,7018,nsw,19881017,5881744 +rec-1527-org,harrison,thaker,31,foveaux street,the meadows,orange,5453,nsw,19960724,9919852 +rec-3099-org,,reid,6,kirwan circuit,ardrossan,shoalwater,4701,vic,19620822,7700094 +rec-4637-org,kydan,gigney,64,o'rourke street,timdoolin,shellharbour,4059,nsw,19760409,3279351 +rec-2508-org,luke,seng,30,glossop crescent,craigston,megan,4812,vic,19980906,7108946 +rec-1501-org,bailey,haack,56,heysen street,goolman street,cronulla,2480,nsw,19171029,5238749 +rec-983-org,ruby,dixon,106,robertson street,merrilea,fullarton,3929,qld,19060420,6808962 +rec-2797-org,alice,neumann,82,shand place,lindsay island,karratha,3131,qld,19731130,8004272 +rec-163-org,darcy,ben-gurion,3,howitt street,arlington,,3151,nsw,19691225,8281055 +rec-3331-org,zane,dixon,29,boustead circuit,baranbali,redbank plains,4740,nsw,19590328,3308725 +rec-2775-org,caitlin,rastar,595,la trobe close,cressy grove,byaduk,2207,,19940531,2416013 +rec-4011-org,james,dixon,68,fanning place,regal oaks retirement vlge,marsden,4300,qld,19750913,8198316 +rec-1008-org,timothy,dignam,17,berrigan crescent,seaforth vlge,moorak,4068,qld,19771123,2663449 +rec-3290-org,zachary,clarke,250,fristrom crescent,waiweer,rochedale south,3550,vic,19200830,4054598 +rec-3344-org,blake,groenier,29,meredith circuit,summer hill,burleigh waters,4674,nsw,19510119,1447437 +rec-1882-org,max,lund,5,syme crescent,broome vacation village,aspley,6111,nsw,19011228,2696750 +rec-2770-org,clodagh,campain,37,captain cook crescent,glen appin,wattle flat,4870,nsw,19281101,5067638 +rec-1467-org,cameron,virgen,51,wilson crescent,blacklead farm,stephens,2110,nt,19400306,5118228 +rec-3492-org,kayla,elrick,95,jardine street,banksia,catalina,2160,vic,19250202,6802075 +rec-853-org,ty,green,411,hugh mckay crescent,,mullumbimby,3550,nsw,19520829,7797381 +rec-2916-org,owen,haeusler,9,martley circuit,the willows,mount riverview,5083,qld,19361018,2837091 +rec-2502-org,kailey,thredgold,20,renwick street,,blacktown,4113,qld,19660923,6956824 +rec-3133-org,caitlin,mitton,6,arthur circle,george forbes house,sale,3182,vic,19260517,4276696 +rec-1004-org,john,priest,1,damala street,woodstock park,beaumont,2566,wa,19420618,7215574 +rec-224-org,liam,beckwith,6,murrung crescent,brindabella specialist centre,revesby,3155,sa,19730522,2475787 +rec-1117-org,nicholas,mcfadden,92,copland drive,lithgowvale,griffin,3556,qld,19020330,6563324 +rec-3549-org,harry,thorpe,11,kambalda crescent,louisa tor 4,angaston,2777,qld,19421128,2701790 +rec-410-org,makayla,thredgold,9,chillagoe street,west road,campbellfield,5107,nsw,19530218,5691229 +rec-4073-org,arabella,hallmaier,147,knoke avenue,glenview,st kilda,4017,wa,19330228,7879377 +rec-3673-org,jake,trevan,93,pridham street,mallanganee,ormond,3028,qld,19960422,5388947 +rec-2513-org,jessica,jolly,13,higinbotham street,rosetta village,woodpark,7109,vic,19850112,2565859 +rec-2074-org,emma,dent,,partridge street,elizabeth residential village,ballarat,2285,vic,19900531,1162702 +rec-380-org,kyle,badawee,5,staunton place,dockside marina b,mount warren park,3138,qld,19391213,3257675 +rec-1374-org,lachlan,balasubramaniam,26,mackinolty street,balmoral garden,scarborough,2388,nsw,19731007,1798069 +rec-3208-org,alexander,kerslake,8,lipscomb place,fm 627,ascot park,2036,wa,19120211,9737053 +rec-2075-org,natasha,lohmann,3,clive steele avenue,gerovin valley ldge,view bank,5343,nsw,19101110,1778982 +rec-1295-org,abby,ang,21,dunstan street,the parks,belmont,4125,nsw,19830621,8045581 +rec-2761-org,bethany,eyre,47,madigan street,,balhannah,3165,sa,19170606,5083160 +rec-409-org,beau,eyles,268,solomon crescent,table mountain,granya,5280,nsw,19970827,8983029 +rec-4951-org,lachlan,nguyen,709,mcnicoll street,,exmouth,5453,vic,19381021,4899443 +rec-773-org,john-paul,conrick,,marrakai street,gummin gummin,canterbury,2263,qld,19651203,6164537 +rec-2766-org,caleb,mckane,21,lochee place,toowoomba,landsdale,3083,nsw,19370320,3598063 +rec-3691-org,tara,pratap,15,wattle street,cantlay farm,aspley,2527,wa,19301128,3688555 +rec-1562-org,kaitlin,matthews,45,grote place,recreation camp,clifton,2024,vic,19960612,7208315 +rec-2971-org,jack,highet,26,mathieson crescent,,whittington,3064,vic,19650507,6260000 +rec-1235-org,michael,ryan,3,mollee crescent,,birkdale,3757,wa,19640409,1467578 +rec-3847-org,isaac,clarke,17,leonard close,highpoint,bundaberg north,7310,tas,19361017,4346183 +rec-4614-org,nicholas,bruinewoud,335,shakespeare crescent,marandyvale,kareela,2577,nsw,19621123,1642628 +rec-610-org,lachlan,rau,68,loxton place,montrose,dederang,3377,wa,19260502,1638351 +rec-2921-org,eden,clarke,1,towns crescent,tall pines,elimbah,3075,wa,19351223,9713955 +rec-3014-org,brandon,wintulich,260,bromley street,carowood,regents park,6023,vic,19810304,9945357 +rec-2172-org,imogen,broadby,70,letters street,jemalong retrmnt vlge,frankston,3149,vic,19840516,5771467 +rec-2776-org,abby,ryan,10,paul coe crescent,kooyong,carlingford,3144,vic,19670119,9471831 +rec-703-org,noah,staude,25,mac george place,locn 8200,stratford,6011,wa,19760505,9182953 +rec-247-org,brett,falcione,106,burdekin avenue,berragoon,pennant hills,4114,nsw,19890803,3152019 +rec-2385-org,charlotte,wilde,28,diamond street,warwarick,werrington,2220,qld,19001117,4847191 +rec-2244-org,fergus,sunderland,88,wilson crescent,dunbar heights,whalan,6060,,19591210,4398162 +rec-3771-org,campbell,zilm,20,mullan street,eden park,camden,3056,wa,19870523,8679206 +rec-392-org,harrison,reid,45,sangster place,mount valley van park,harbord,5158,tas,19451222,7347950 +rec-3378-org,lukas,webb,2,freda gibson circuit,nowra mall,kingston,2830,nsw,19120423,6570926 +rec-1486-org,matisse,felmingham,351,kingsford smith drive,sherwood,cooks hill,3207,nsw,19320615,5414268 +rec-4684-org,nicholas,excell,10,druitt place,tharlane,salisbury,3478,vic,19390713,5109979 +rec-2169-org,aikaterina,hewetson,13,jabanungga avenue,moorabee,bowen mountain,2148,vic,19500330,7093866 +rec-3562-org,joshua,ryan,14,wynn street,tathra,bilpin,2529,vic,19240510,2519978 +rec-4397-org,emmet,reichardt,15,hansen circuit,kellhaven,camden,3350,vic,19470716,9713002 +rec-2917-org,,dixon,13,salsola street,the homestead,lawson,6210,qld,19370314,7753663 +rec-4958-org,peta,edson,209,banner street,sec 1,highgate,2257,wa,19940118,4862259 +rec-2230-org,lucas,spargo,34,stephen street,bidgee park,beaumont,3550,vic,19930424,5396235 +rec-2637-org,jasmine,wiseman,7,weddin circuit,berkeley vlge,paddington,3934,vic,19730419,2258952 +rec-3011-org,alaiyah,klemm,12,crozier circuit,sec 161,towradgi,6330,vic,19100824,5690083 +rec-2952-org,matteus,monda,54,burrinjuck crescent,sherwood,auburn,3345,nsw,19041125,9464025 +rec-3929-org,kiera,amorim,24,maclachlan street,wattagan,oakleigh,0810,wa,19841026,9125670 +rec-36-org,liam,bottroff,5,jindivik place,homewood,meringandan,3222,vic,19640816,5214622 +rec-1600-org,joshua,mortlock,62,yates garden,bulala,camperdown,2147,nsw,19180804,4756935 +rec-1977-org,aidan,morrison,2,broadsmith street,,cloverdale,2787,act,19140202,8821751 +rec-4029-org,darcy,montfort,194,,upper newee creek street,mount helen,2448,qld,19580822,6099624 +rec-2203-org,sophie,noble,9,university avenue,shenstone park,albion park,3325,vic,19361013,3379987 +rec-1520-org,jack,cute,7,dash crescent,little forest,seventeen mile rocks,4567,nsw,19090402,3506178 +rec-1449-org,jenna,salas,2,tasman place,kinvarra,netherby,3820,qld,19490605,1868937 +rec-4562-org,cambell,ryan,23,bradfield street,bolinda vale,brighton,2537,nsw,19700416,7188248 +rec-2126-org,timothy,soulemezis,18,allambee street,brentwood vlge,balaklava,2590,vic,19010923,1004898 +rec-1795-org,lucy,fitzpatrick,264,ainsworth street,the sarina centre,camden,3500,qld,19210222,6619346 +rec-58-org,jayde,glass,15,macarthur avenue,shillelagh park,glenella,3200,vic,19161226,9446563 +rec-1835-org,nikita,bezuch,10,boddington crescent,holiday vlge,mcdowall,3020,nsw,19460615,8620625 +rec-4893-org,harry,gaden,208,,musgrave house,surry hills,3216,vic,19770407,5999211 +rec-4420-org,alexander,vitkunas,17,moynihan street,kelindy ridge,kilcoy,2285,vic,19991216,6469394 +rec-3770-org,kirra,white,24,bungonia street,villa 3,kyabram,2036,tas,19290202,5171004 +rec-4936-org,dean,lock,16,durville crescent,wylarah,campsie,4031,sa,19150408,4029960 +rec-1461-org,thomas,moulton,26,buckley circuit,,north sydney,2260,qld,19550604,1286659 +rec-2717-org,abbey,coleman,26,ebenezer street,the lodge,,2540,nsw,19100116,5514906 +rec-1239-org,konstantinos,white,13,clive steele avenue,,crookwell,2211,wa,19440706,5173965 +rec-4937-org,chelsea,blake,21,chandler street,extension,swan hill,2360,nsw,19831115,2342307 +rec-237-org,corey,feeney,2,forbes street,milamba,suffolk park,2049,nsw,19670414,9098376 +rec-2999-org,paris,negrin,30,stapylton street,treleen,coleambally,2145,qld,19620726,4121618 +rec-2512-org,sonja,hyland,86,flanagan street,dodonaea wing,boyup brook,2032,qld,19840708,5354642 +rec-764-org,devan,clarke,,windradyne street,buena vista,south perth,4127,nsw,19060130,3013362 +rec-238-org,max,nevin,36,creswick place,penny lane shopping centre,colonel light gardens,3169,qld,19840223,8258349 +rec-2016-org,leon,mason,545,hawkesbury crescent,doubtful ck,ballina,3137,qld,19541005,1583941 +rec-4764-org,olivia,dessart,165,macvitie place,brambletye vinyard,lindenow south,4128,vic,19361017,2517857 +rec-3330-org,thomas,hare,18,gilderston circuit,canowindra,coffs harbour,4211,nsw,19190206,3277988 +rec-1814-org,connor,asendorf,12,falkiner place,luskin court,orange,4032,vic,19290430,6699074 +rec-1758-org,kylie,travar,37,morrison street,,westmeadows,3844,nsw,19070620,1372055 +rec-3195-org,bailey,goode,57,heard street,coolbellup hotel (cnr waverley r road,albury,4720,nsw,19100307,1906329 +rec-1087-org,mitchell,tien,18,padbury street,greenslopes,concord,3429,nsw,19780903,6760018 +rec-4239-org,bianca,cuming,9,albermarle place,harkness station,natimuk,3158,nsw,19911129,2315136 +rec-4558-org,jason,mcmullen,,musgrave street,black creek,ingham,2820,qld,19280901,4547398 +rec-1875-org,kelsey,warrior,223,wentworth avenue,,kelmscott,4550,vic,19460105,8991832 +rec-784-org,lillian,humphreys,8,mack street,bracken leigh,narooma,4152,nsw,19710908,6242916 +rec-3387-org,eliza,slape,5,bellchambers crescent,bonny doon,dover heights,6230,nsw,19840924,7441870 +rec-4981-org,matthew,gulliver,50,malcolm place,,sefton,4817,nsw,19790129,2462951 +rec-517-org,lucas,binns,15,cordeaux street,,malvern east,4014,sa,19131007,1973817 +rec-4409-org,joshua,needham,20,cornish place,jackaranda lodge,manunda,2325,qld,19130421,6586520 +rec-4992-org,caleb,kwiatek,16,gatty street,villa 2,castle cove,4220,qld,19641121,5138480 +rec-4769-org,jed,salt,15,kurrama close,,midway point,4102,nsw,19541122,7471593 +rec-2018-org,hannah,ranson,34,edge place,fernlea,laverton,2008,qld,,9730826 +rec-607-org,jessica,vogiatzi,34,kinsella street,brownrigg,connolly,2800,vic,19240212,7088980 +rec-923-org,eliza,koziol,183,wattle street,blueberry hill,blacktown,6026,nsw,19940208,8842130 +rec-4273-org,jesse,vincent,13,bengee place,,loxton north,3216,sa,19031203,8181500 +rec-2982-org,jaimee,hanna,8,harkness street,belmore river,armidale,2062,nsw,19871116,2798753 +rec-1934-org,ewan,brock,8,warrambool close,hawkins masonic vlge,clarkson,3021,nsw,19161123,3522578 +rec-2731-org,tegan,galbraith,130,pinkerton circuit,kellhaven,altona meadows,6020,wa,19850912,9290065 +rec-637-org,alexandra,campbell,15,paul coe crescent,laloki,woollahra,5108,nsw,19531022,3106590 +rec-2520-org,jessica,wintulich,,hoseason street,yarrambah,,3133,nsw,19380330,8634113 +rec-4567-org,alicia,green,13,proctor street,navan park,eden,2484,sa,19950919,4191587 +rec-1878-org,tyler,clarke,11,bogan place,,werrington,4500,qld,19720225,3711822 +rec-4205-org,caitlyn,millar,38,tullaroop street,glenview,macgregor,2343,vic,19940917,8863827 +rec-306-org,samuel,loos,60,gilday place,eriswell park,kinross,2646,qld,19350908,9238386 +rec-427-org,jordan,vincent,7,carnegie crescent,dargam,floreat,3032,nsw,19101107,3591952 +rec-2435-org,bella,grierson,27,priddle street,green lagoon,christies beach,3125,vic,19310623,5873915 +rec-2478-org,aidyn,morrison,1215,bertram street,tiverton,woy woy,4021,nsw,19160319,7949710 +rec-4849-org,holly,campbell,4,syme crescent,ahwahnee,hamilton,4868,nsw,19160516,7267433 +rec-3890-org,arren,white,4,eggleston crescent,valencia park,toowoomba,7116,nsw,19740614,1963582 +rec-1339-org,ryan,verner,40,hyndes crescent,kurrajong,glenmore park,3730,qld,19901208,4388841 +rec-1725-org,lachlan,,27,mugga way,,leichhardt,2150,nsw,19700930,6838887 +rec-1839-org,paris,nguyen,13,moroak street,forest views,cranbourne,2217,qld,19010108,1825355 +rec-3818-org,madison,plane,18,bardolph street,rosehill,sunnybank,2541,nsw,19971022,9432416 +rec-4543-org,xavier,moorby,38,cockburn street,granite hills,windsor,4740,nsw,19570817,7332449 +rec-2517-org,katelyn,reid,30,james smith circuit,karma park,dolls point,2478,qld,19970318,9915348 +rec-2735-org,adam,barnetson,3,wicks road,,vermont,2234,nsw,19770922,1249535 +rec-2309-org,henry,pozniak,2,ashkanasy crescent,nelgrove park,beenleigh,2171,tas,19521203,7678518 +rec-816-org,trey,tiller,43,deamer crescent,cherrybank,campbelltown,2063,sa,19940208,7121752 +rec-3430-org,sophie,thredgold,43,bramble street,tigers hill,montmorency,6210,sa,19830705,8974658 +rec-4414-org,joel,campbell,2,hamelin crescent,,riverstone,3168,vic,19621110,8265289 +rec-2264-org,madeline,volpato,7,elliott street,lakeview park,glenhaven,6442,vic,19341126,1203476 +rec-2008-org,nicole,riddell,9,saunders street,scts crk,macquarie park,6323,nsw,19040601,8785526 +rec-1777-org,tommy,green,122,nanima road,port 44,lower templestowe,6064,vic,19901006,6395834 +rec-437-org,mikayla,heans,2,alexandra street,anona farm,broken hill,2444,qld,19510303,7694084 +rec-4220-org,william,nguyen,52,tantangara street,anzac house (cnr archer s street,kingsthorpe,2580,sa,19341203,9928610 +rec-4249-org,yana,stanesby,8,blamey crescent,the gums,flinders park,7260,vic,19080415,9864532 +rec-4741-org,aidan,finlay,393,cowper street,,aitkenvale,6064,qld,19611226,1013943 +rec-3948-org,thomas,parr,71,plowman place,linton vlge,daw park,5159,nsw,19010714,5972566 +rec-1470-org,ruby,paine,27,tatchell street,belandean,lennox head,3350,nsw,19030605,4010380 +rec-2833-org,jed,kempton,45,novar street,kalang,corrimal,2756,wa,19991224,3763645 +rec-3417-org,ella,campbell,873,connibere crescent,albion heights,bronte,4078,nsw,19591030,8840175 +rec-1919-org,noah,bishop,12,stobie place,highgate,bailey creek,2134,qld,19130403,4950296 +rec-1110-org,emma,adzaip,38,amherst street,villa 2,nairne,4860,sa,19050421,5988275 +rec-4354-org,simon,clarke,21,verdon street,antanoff' south,warracknabeal,2777,vic,19630730,1009287 +rec-2236-org,alexandra,finlay,3,erldunda circuit,neaavie,cooroy,2147,nsw,19600723,3910557 +rec-2722-org,,beattie,56,howchin place,,mount isa,3912,vic,19980913,3509530 +rec-3451-org,logan,goldsworthy,21,florentine circuit,settlers hills,ashfield,2571,nsw,19160117,8867229 +rec-2320-org,alexander,musolino,43,duggan street,the bend,kareela,2483,nsw,19850417,4595017 +rec-4546-org,arren,wiseman,305,morant circuit,the village condo 7,st albans,2027,vic,19660719,5442212 +rec-3042-org,lydia,ryan,48,davis street,wychwood,eaglemont,3138,nsw,19370701,8755417 +rec-4170-org,noah,rawlings,6,melrose drive,lethbridge court,darlington,3216,nsw,19680922,8526649 +rec-4-org,jayde,crouch,42,weston street,waimaru,niagara park,2119,wa,19250406,8892697 +rec-3861-org,charlie,gaskin,24,james smith circuit,villa 2,gawler river,2641,vic,19590904,3925628 +rec-1248-org,hayley,wyeth,,griffin place,terawah station,broadmeadows,6060,vic,19590129,8188526 +rec-2541-org,rebecca,boothroyd,1,gatton street,rosedale,wiseleigh,3690,nsw,19001103,3436597 +rec-1287-org,alisha,rawlings,40,hyndes crescent,white sands tourist park (cnr beach),bayswater,2754,nsw,19150122,1114083 +rec-3981-org,john,tuke,,moore street,cuthberts court,castlemaine,4558,qld,19290912,4216956 +rec-2698-org,drew,bishop,6,gask place,balala station,heywood,3058,nsw,19000402,1553804 +rec-2034-org,alexander,bishop,7,canberra avenue,dunbogan caravan park,ryde,6164,nsw,19140306,3194688 +rec-3173-org,carmen,wiseman,41,sherwin place,wangi shoppng centre,newborough,2216,wa,19000714,2741568 +rec-432-org,alexander,stephenson,319,kinsella street,windy gully,lalor,5043,vic,19940316,1986381 +rec-3013-org,george,mccarthy,35,clubbe crescent,yakilli park,mentone,2540,vic,19350704,9460223 +rec-92-org,alana,frahn,530,a'beckett street,pyramid caravn park,lakes entrance,2477,vic,19630307,4624018 +rec-1065-org,zachary,jevons,79,pankhurst crescent,old farm,oyster bay,4123,nsw,19010908,9596699 +rec-3541-org,katelyn,goldsworthy,10,meyers place,tinnaroo falls,bundamba,3127,qld,19880820,1519466 +rec-2093-org,nicole,madigan,8,carroll street,newton park,goonellabah,2749,qld,19610919,3710610 +rec-1500-org,jade,stronach,4,broadsmith street,miami,denmark,2251,nsw,19090102,5258162 +rec-4204-org,joshua,webb,1,perry drive,shire clerk,greenwood,2583,wa,19411204,7883180 +rec-4166-org,ruby,mason,18,hurley street,,samford valley,3805,qld,19420728,1047066 +rec-1032-org,harrison,painter,,nina jones crescent,ballawinna stud,lennox head,6017,vic,19961105,9133988 +rec-2128-org,flynn,gloster,2,davies place,canowindra,andergrove,2519,nsw,19570911,5757208 +rec-1900-org,jasmine,matthews,25,osburn drive,marathon mews,burwood,3185,wa,19691211,9299325 +rec-1194-org,daniel,gaden,21,,solander centre,duntroon,6056,qld,19840606,3484120 +rec-4735-org,patrick,newbown,8,la perouse street,vaughan vlge,rose bay,6430,qld,19470920,2408047 +rec-2160-org,oliver,jacobus,6,tiptree crescent,crestfield,lansvale,4013,vic,19260331,1158763 +rec-4922-org,ashleigh,rollins,22,mcrae place,mansfield park,dapto,4670,tas,19180307,4706557 +rec-1214-org,mitchell,matthews,21,kulgera street,the willows,north beach,4109,vic,19590701,8051712 +rec-4617-org,lucy,kranenborg,19,clara close,blue hills,bargara,6030,nsw,19740827,7896434 +rec-278-org,samuel,gilbertson,7,phillips place,bulliac street,potts point,6151,qld,19581011,9448590 +rec-581-org,jayme,frew,18,la trobe close,water fall,ballarat,2540,vic,19960831,7540258 +rec-2780-org,,ryan,12,breona place,lakes retirement estate,highton,4207,nsw,19620821,7592380 +rec-2864-org,alia,taubert,178,maurice place,lindsey rise,belmont,4802,nsw,19160125,3241981 +rec-3294-org,shane,milburn,4,topp place,north nowra shopping centre,gunalda,2257,vic,19300311,7717125 +rec-3409-org,anthony,gripton,5,blackburn street,westella,peregian beach,3020,nsw,19890804,4803978 +rec-457-org,thomas,mcauslan,14,truganini place,,bongaree,5046,nt,19801028,8944611 +rec-3910-org,bianca,brummer-archer,311,henry melville crescent,rosetta village,strathdickie,3023,qld,19890705,9167456 +rec-2157-org,riley,bishop,15,hyndes crescent,villa 2,toukley,2641,qld,19741020,9752897 +rec-3782-org,tiffany,,26,southern close,westleigh,kirribilli,3437,qld,19860301,7926952 +rec-370-org,isabella,lowe,18,wolff crescent,learmont,sylvania,2032,nsw,19771116,5672191 +rec-3762-org,kai,wilczek,83,oliver street,appleglen,toowoomba,2785,wa,19290502,1878744 +rec-4388-org,ashleigh,neumann,13,hadlow drive,ningana,canterbury,2208,vic,19961127,5633162 +rec-2212-org,samuel,goldsworthy,28,louis loder street,grant patch,naremburn,4055,sa,19270607,5061165 +rec-4441-org,deakin,michelmore,,percival street,west aerodrome,kyogle,2540,vic,19911030,6770823 +rec-1123-org,gabrielle,rees,27,julia flynn avenue,villa 2,leongatha,4300,vic,19580720,9209231 +rec-4081-org,mackenzie,collinson,24,beaurepaire crescent,riverside park,maryborough,3444,nsw,19750803,1576308 +rec-3812-org,dean,webb,52,buggy crescent,mount patrick,stratton,3138,nsw,19171128,4129591 +rec-4445-org,tara,nguyen,38,anembo street,hattah-kulkyne,kurri kurri,4405,nsw,19640410,8872454 +rec-2211-org,abbie,limbert,7,burraly court,yurnga,oyster bay,7310,sa,19061013,2508428 +rec-4872-org,lachlan,white,1,atherton street,the mews royal hotel bldg,alexandra bridge,3390,vic,19810422,5260328 +rec-2585-org,harvey,roselli,132,twelve trees crescent,dargam,reynella,3089,vic,,7501852 +rec-3571-org,emiily,wilson-wheeler,1,woolcock street,willandra,taree,2477,qld,19610625,8119451 +rec-2728-org,gemma,lowe,36,forbes street,nunkeri (cnr linburn r road,trevallyn,3199,wa,19700524,5918591 +rec-4993-org,sarah,de crespigny,16,maurice place,allandale,somers,2250,vic,19130113,4115888 +rec-1069-org,amelia,lowry,54,jandamarra street,ellwood,kinglake east,4208,qld,19231009,2439141 +rec-3474-org,josephine,gallio,23,marsden street,sunnydale cottage,blacktown,2753,qld,19230227,8542303 +rec-2560-org,danjel,ang,8,reader court,villa 2,arundel,3146,nsw,19470912,2029176 +rec-2537-org,harrison,weaver,24,adair street,,charlestown,2229,nsw,19100327,6483602 +rec-2458-org,bianca,morrison,224,sharland place,brindabella specialist centre,evanston,4702,vic,19040728,1392522 +rec-742-org,jesse,rankine,977,mcgivern crescent,minoru,salisbury heights,4228,qld,19720216,2225890 +rec-3161-org,ellie,oatey,84,woollum street,blaxlands ck,lower templestowe,2196,wa,19390419,9791693 +rec-494-org,elisha,gibb,59,weavell place,st vincents hospital,tawonga south,2119,nsw,19490606,8704563 +rec-827-org,michael,heidrich,49,degraves crescent,wonga square,samford,6104,nsw,19440910,3945989 +rec-2415-org,chloe,coleman,50,mina wylie crescent,monto caravan park,gowrie,3114,sa,19850701,6761005 +rec-3108-org,georgia,carbone,20,ross smith crescent,medical centre,southbank,3070,vic,19910825,4433630 +rec-1217-org,maddison,mahon,62,ellenborough street,brentwood vlge,east gordon,2224,qld,19381111,9640898 +rec-1782-org,sophie,burford,17,merfield place,legacy units,surat,3144,wa,19321031,6901639 +rec-141-org,peta,callister,16,baracchi crescent,jaholma park,moranbah,2117,qld,19700110,4177367 +rec-2068-org,molly,garcia,1,chuculba crescent,arawang,ballarat,2048,qld,19571103,2305243 +rec-3928-org,molly,burford,19,erldunda circuit,rcg centre,ermington,3081,qld,19181119,7640441 +rec-3920-org,jacqueline,pride,9,william webb drive,bell place (cnr bell r road,richardson,4065,nsw,19830708,4570880 +rec-4582-org,daniel,mcard,34,maccallum circuit,westwood homestead,homebush,2619,nsw,19920927,2550366 +rec-4776-org,georgia,metaxiotis,15,augustus way,moodwood angus stud,tuart hill,3196,vic,19130627,5883327 +rec-2067-org,katharine,penno,91,cuthbert circuit,brentwood vlge,long jetty,3215,qld,19491225,1089142 +rec-996-org,emiily,finlay,61,coranderrk street,john flynn medical centre,ulverstone,3043,vic,19070731,9964204 +rec-575-org,jorja,green,29,moon place,yakilli park,junee,7307,sa,19590106,3411925 +rec-4797-org,matthew,lock,14,shoalhaven avenue,nootina,ringwood,2207,sa,19931125,3915530 +rec-2809-org,lily,mounce,92,symers street,donald coburn lodg,ferryden park,2100,qld,19000224,4142857 +rec-1577-org,lachlan,stanley,28,cottam place,plainview,mount samson,7310,nsw,19740824,4200578 +rec-206-org,lewis,westbrook,14,hutchison crescent,ohio station,seaforth,4128,vic,19081217,5442782 +rec-2772-org,william,george,31,kidman close,ocean breeze,labrador,3438,sa,19250214,9555232 +rec-1634-org,alicia,miles,69,eggleston crescent,wunnamurra homestead,brighton,3020,vic,19701124,2499759 +rec-2039-org,marcus,chandler,5,rason place,sect 329,flagstaff hill,2226,vic,19700417,1098082 +rec-290-org,george,webb,16,beatham close,nelsons lake,lakemba,2064,nsw,19721211,6420147 +rec-905-org,jemima,apathy,79,,unfaan,dandenong north,3000,sa,19830719,6617205 +rec-3696-org,toby,walkley,29,hatfield street,st helens,albury,2528,nsw,19350608,9827400 +rec-3449-org,lily,collier,47,sargood street,amelia,port macquarie,3148,vic,19860413,6053640 +rec-3789-org,casey,fitzpatrick,34,hugh mckay crescent,glass house,hamilton,4178,nsw,19320411,3603845 +rec-3609-org,gillian,lilee,9,yarra street,glen-erin,granville,2518,nsw,19181009,6966115 +rec-1805-org,jackson,thorpe,21,grayson street,kilwinning,daisy hill,3058,nsw,19460526,3307556 +rec-119-org,sarah,jolly,2192,callaway crescent,spring ridge,kingsville,3995,wa,19161127,5871517 +rec-324-org,aidan,finlay,27,maribyrnong avenue,villa 3,roleystone,2000,,19131116,8412107 +rec-2909-org,tristan,quilliam,14,banner street,marjidin,ulverstone,3250,sa,19671214,3784610 +rec-4747-org,roberta,caire,14,welch place,port 44,beaconsfield upper,5113,sa,19630418,5100047 +rec-1027-org,luke,hursey,23,turriff street,inishmore,port franklin,4017,qld,19220923,1219514 +rec-845-org,arki,mason,5,verran place,rowethorpe,frankston,6147,vic,19851022,7763548 +rec-1038-org,mia,crofts,101,nunan crescent,wilga,millmerran,4850,sa,19550722,3041807 +rec-1424-org,braiden,hering,26,snowden place,peppercorn lodge,new farm,3016,nsw,19240408,7720229 +rec-1392-org,joshua,clarke,1,savery street,bexley,carnegie,3028,sa,19011101,7741570 +rec-1105-org,nicholas,jenvey,59,bogan place,hopeview,bundaberg,2440,nsw,19921231,1646485 +rec-2754-org,ellen,schumann,51,barr-smith avenue,glengariffe,ridleyton,4034,qld,19610507,1287031 +rec-2142-org,sarah,leslie,740,baddeley crescent,flt 10,jamboree heights,4053,vic,19110604,7593106 +rec-2396-org,christopher,menzies,39,maclachlan street,kinglake central,malvern,2621,nsw,19180721,8813225 +rec-2104-org,olivia,leong,75,naismith place,mckail,deer park,3177,nsw,19820831,9379794 +rec-1306-org,erin,fassina,80,croton street,rockview ashtead,werrington,2066,nsw,19561212,9413029 +rec-279-org,lachlan,laing,65,,bega flats,parap,4101,nsw,19240304,4688353 +rec-4917-org,,staunton-smith,68,frome street,kookaburra village,broken hill,2870,vic,19820117,6922783 +rec-2343-org,reegan,noble,4,kauper street,poplars,carlingford,7173,vic,19501211,7625184 +rec-915-org,emerson,soulemezis,15,marshall street,birks harbour,st albans,2135,vic,19450805,8760466 +rec-4310-org,phoebe,dixon,7,ambalindum street,bracken leigh,yass,6027,tas,19960119,3838118 +rec-794-org,kristen,godfrey,48,dumas street,dromard,bray park,4157,sa,19700425,5874139 +rec-4913-org,nicholas,morcom,13,mcbryde crescent,phillip lodge,toowoomba,3364,qld,19360608,3103859 +rec-1531-org,aidan,minorchio,13,chewings street,ningana,vermont,6056,qld,19500604,7288279 +rec-3969-org,josephine,hohn,8,pandanus street,rosebridge,avoca beach,3173,vic,19440501,1426564 +rec-4551-org,joshua,stubbs,50,bimbiang crescent,rosetta village,holsworthy,3071,nsw,19580212,4826701 +rec-4665-org,ky,morrison,275,hardie close,arthur river park,mount eliza,2031,nsw,19411120,9053979 +rec-382-org,ella,mahon,51,ulm street,naygoondy,northmead,2086,nsw,19330520,4464237 +rec-3391-org,madelyn,blizard,6,southwood retreat,hoxton park,northgate,2067,vic,19540215,2341148 +rec-1081-org,caitlin,white,174,collyburl crescent,,kurwongbah,2456,nsw,19431207,2627787 +rec-4610-org,rachel,matthews,32,kirkcaldie circuit,malladup,ruse,4720,vic,19401207,9129899 +rec-1987-org,cameron,prideaux,50,oakes street,evenstar,condon,6164,nsw,19990615,3537256 +rec-2925-org,lachlan,lanyon,34,maranoa street,,elsternwick,2228,wa,19950930,9007961 +rec-995-org,isabella,westbrook,20,yanda street,carlow,seven hills,2048,tas,19730807,1274198 +rec-1259-org,talia,allard,2,groom street,fair lea,newmarket,6064,qld,19060220,2778608 +rec-157-org,lachlan,coleman,59,marsden street,bell place (cnr bell r road,richmond west,3995,tas,19060305,2870281 +rec-4194-org,nicholas,leslie,10,de little circuit,retirement village,daisy hill,4802,nsw,19691231,9490741 +rec-3764-org,talia,,22,raymond street,norillee,newborough,2303,nsw,19440528,2601600 +rec-133-org,jackson,koklas,43,cousin place,villa 2,pearcedale,7018,wa,19850701,1074399 +rec-3340-org,jacob,green,1,strickland crescent,rosetta village,hectorville,4655,nsw,19660623,4867426 +rec-3136-org,pakita,o'shannessy,83,handasyde street,villa 3,torquay,4878,qld,19270218,8599006 +rec-4673-org,jesse,bagwell,12,tuckey place,ellangowan,urangan,4659,nsw,19930914,6491012 +rec-2750-org,jessica,shepherd,60,mackney place,aprtmt 34,albion park,4207,nsw,19730411,7664099 +rec-2242-org,michael,shepherd,39,pinkerton circuit,millwood,camira,3377,nsw,19301008,3537158 +rec-3162-org,lachlan,rees,25,darwinia terrace,moline village,ulverstone,3162,vic,19131017,1414477 +rec-1864-org,ruby,donaldson,42,,glenbrook orchard,appin,2035,tas,19141014,3742981 +rec-2281-org,elijah,asher,18,blakey close,,east hills,3194,nsw,19480723,9470193 +rec-3385-org,shanaye,carbone,41,haystack crescent,st vincents hospital,matong,3690,nsw,19300519,1632237 +rec-2312-org,ella,ryan,18,marshall street,mayflower retrmnt vlge,coolaroo,2365,wa,19510519,7463223 +rec-747-org,cade,coleman,21,damala street,mater professional centre,minchinbury,2280,sa,19471123,8098924 +rec-3176-org,lauren,,42,moore street,jormaizee,mullaloo,3182,sa,19600314,2240511 +rec-1020-org,phillip,finlay,,maclachlan street,arcadia,glendale,6171,qld,19080623,5324023 +rec-4145-org,william,kempe,18,dallachy place,yarrawah,keysborough,5043,qld,19280103,8619692 +rec-3515-org,cooper,perth,52,blacket street,avalyn,young,2580,qld,19950107,5404942 +rec-3996-org,georgia,maynard,10,temperley street,tieve tara,toowong,3175,qld,19700324,3465730 +rec-4321-org,natalia,bissett,42,springvale drive,star court arcade,kaleen,4218,qld,19500422,8653274 +rec-2880-org,emiily,paterson,7,gruner street,platina,seaforth,5157,vic,19840318,7177837 +rec-2796-org,brooklyn,ryan,1,sainsbury street,pine hill,american river,3241,nsw,19200516,5720021 +rec-953-org,charlotte,heuston,92,wayal place,memorial hospital,cremorne,2619,vic,19970428,9940785 +rec-1159-org,rhys,mason,49,geils court,banksia village,maryborough,5066,wa,19000608,7868339 +rec-4696-org,samuel,green,13,cordeaux street,mornington ret vlg,woorinen,6153,nsw,19911221,5676411 +rec-2589-org,,lowry,150,syron place,wirong,,4066,vic,19880923,8557384 +rec-2258-org,thomas,brock,117,temperley street,northwood park,port macquarie,4670,sa,19520624,9531535 +rec-585-org,danny,stephenson,16,o'shanassy street,banksia village,armidale,3130,tas,19831019,7199358 +rec-4608-org,paris,green,19,zamia place,glendower,frankston,5159,qld,19291117,7101331 +rec-1973-org,jack,vick,23,noble close,st johns retirement,rivett,7252,nsw,19550905,8449880 +rec-3135-org,gianni,campbell,39,spring range road,,putney,2602,vic,19911228,4150453 +rec-2395-org,jacinta,bastiaans,12,bean crescent,barwon station,narellan,3074,qld,19330803,3787817 +rec-1624-org,henry,martinello,48,fred lane crescent,coorabil,northampton,2794,qld,19410617,4721399 +rec-4438-org,jordan,noble,4,kosciusko avenue,st francis vlge,surry hills,2170,wa,19270820,7231665 +rec-1596-org,alexander,green,18,julia flynn avenue,sec 375,connolly,2516,nsw,19071024,5282495 +rec-3925-org,adam,yu,33,wittenoom crescent,ashell,werrington,2203,vic,19410707,6158700 +rec-2267-org,jacqueline,tomich,34,giles street,noorla,kilsyth,7030,wa,19230609,5698710 +rec-4765-org,riley,godfrey,,clift ck,the lodge,oakwood,3108,nsw,19451121,3493339 +rec-3779-org,ajay,chetwyn,13,cope place,c/-the student village,,2164,nsw,19290222,6258884 +rec-4188-org,andrew,mason,12,starling place,brentwood vlge,rosewater,5086,nsw,19321115,1878301 +rec-2846-org,lauren,mcneill,37,caley crescent,gimberts road,kilsyth,3752,qld,19050527,4744679 +rec-4077-org,juliana,matthews,1261,lamington street,mount patrick,brighton-le-sands,2287,vic,19030123,9544022 +rec-660-org,evan,wilkey,26,gudgenby close,portland house,park orchards,4818,vic,19571204,4568068 +rec-4731-org,aleisha,mason,120,appel crescent,gillin park,tanilba bay,3936,nsw,19860522,3858465 +rec-547-org,jack,ziersch,9,badcoe street,belvedere,new farm,5501,wa,19741024,8799452 +rec-1957-org,kelsea,hoebee,83,paul coe crescent,,st kilda,6027,wa,19970705,7042275 +rec-1618-org,thomas,campbell,35,lethbridge street,scenic lodge,paddington,2450,nsw,19610710,5974512 +rec-3289-org,megan,jessup,5,wyatt street,beachfront caravan park,ringwood,3225,nsw,19010928,9738709 +rec-32-org,caleb,spurden,119,mcalpine place,greenslopes,boyne island,4228,sa,19580816,8017617 +rec-3066-org,jack,juric,,chuculba crescent,,goonellabah,4017,nsw,19791101,9208099 +rec-2829-org,timothy,de angelis,95,casey crescent,lumeah homes,brighton,3400,sa,19910709,6079337 +rec-884-org,riley,loehr,20,caldwell street,springdale,maitland,4680,tas,19000723,4599665 +rec-1971-org,amelia,green,60,beasley street,silver sand caravan park,charlestown,3199,vic,19160824,4340002 +rec-3843-org,talia,bramble,5,wattle street,taree caravn park,north bondi,5074,vic,19090623,2565238 +rec-832-org,benjamin,spaans,72,ellerston avenue,birkenau,kulnura,5082,qld,19010804,1924477 +rec-362-org,jessica,ditty,22,dunlop street,oak-lodge,bundaberg,3183,nsw,19500328,6813350 +rec-4317-org,scott,buterfield,116,crozier circuit,uc-dai-loi,noble park,2213,qld,19230731,9102056 +rec-2545-org,ashleigh,white,34,hutchison crescent,harefield,east hills,2354,nsw,19261003,6850999 +rec-2187-org,emma,scappatura,3,reuther street,wattle brae,east fremantle,3129,nsw,19390522,5932517 +rec-1524-org,lily,krishnan,25,bourne street,redhill,keysborough,2640,qld,19681003,8956118 +rec-2587-org,tori,reid,16,arthur circle,nowra mall,lalor,2176,vic,19570425,5350892 +rec-1926-org,savannah,cappelluti,4,lightfoot crescent,brampton,seymour,6084,wa,19160523,5168724 +rec-749-org,sarah,curth,14,knoke avenue,heathfield qld,mullumbimby,3175,vic,19131205,8264314 +rec-3030-org,hannah,maynard,3,fizelle place,oaklands village,toowoomba,2340,sa,19971104,3318159 +rec-1488-org,daniel,wojciechowski,141,somerset street,melody cottage,dulwich hill,2120,nsw,19500125,2930336 +rec-2099-org,caitlin,milburn,17,heard street,lexington,south arm,2850,qld,19530105,3195330 +rec-54-org,imogen,whillas,121,embley street,flowerydale,molong,2170,tas,19090319,7145066 +rec-4253-org,harley,mclaine,419,john young crescent,,hamilton,2261,qld,19380511,5510205 +rec-4373-org,jack,carbone,55,wrenfordsley place,,moura,2038,vic,19710726,1202844 +rec-2059-org,isabella,orme,125,officer crescent,,sandgate,2190,nsw,19471012,5078419 +rec-3489-org,joel,dixon,5,meredith circuit,rawdon,greenwood,4011,qld,19590722,6153468 +rec-3249-org,ebony,thorpe,117,,,yarra junction,6028,qld,19421204,2504255 +rec-1514-org,kiana,pieris,33,mortimer lewis drive,mungrup stud,coffs harbour,4650,vic,19370813,5026429 +rec-1594-org,david,,3,eggers place,ainslie house,nubeena,4869,nsw,19380403,6575835 +rec-4517-org,isabella,waller,155,blackburn street,omeo,brighton,5035,vic,19500719,7270771 +rec-1356-org,rory,jehle,125,companion crescent,brinjarry,cromer,2340,nsw,19730227,1533301 +rec-3716-org,barnaby,wevill,26,barringer street,sec 692,girgarre,2165,qld,19741112,3879376 +rec-3873-org,bryce,crosswell,34,monkman street,clems place,colac,4551,nsw,19301122,8289252 +rec-114-org,alana,green,2,wittenoom crescent,tulla burra,mount eliza,4051,wa,19030904,7711269 +rec-103-org,amelia,kingswell,12,balbo place,sunny braes,tuchekoi,3192,vic,19520510,7388956 +rec-3643-org,michael,stagoll,,tyson street,bypass road,cleveland,3150,nsw,19190521,3941516 +rec-1411-org,harrison,thredgold,3,antill street,monavale,charlestown,2289,nt,19390828,3707828 +rec-3032-org,maddison,jiang,8,templeton street,kurrabri,lamington,3556,vic,19610619,7894969 +rec-3293-org,samuel,miles,138,hawkesbury crescent,,north ward,2148,sa,,2763477 +rec-4775-org,callie,webb,164,dalley crescent,rocklea,frankston,3094,qld,19081121,5176285 +rec-2787-org,madison,niekel,14,noongale court,summer hill,prospect,3032,sa,19030530,1598654 +rec-1181-org,jessica,liddy,15,hyndes crescent,sec 1,fairlight,4133,nsw,19620602,9399509 +rec-150-org,ned,clarke,11,london circuit,villa 5,carnegie,5073,wa,19740801,4238081 +rec-4342-org,luke,grubb,10,berne crescent,yooringa,st huberts island,6530,nsw,19341211,6333533 +rec-1828-org,,crapp,3,couchman crescent,glendower,ramsgate,2035,nsw,19500106,6187478 +rec-2863-org,matthew,priest,310,benson crescent,glenhurst,tarragindi,4124,qld,19860226,2553510 +rec-2851-org,chelsie,hlawa,99,companion crescent,ashbank,torquay,2325,vic,19691018,9141369 +rec-339-org,samuel,kontopoulos,11,bamir square,pleasant view,carnegie,3631,vic,19870312,9712523 +rec-1757-org,ruby,nguyen,6,berghofer court,wealdstone,lilydale,3934,vic,19660122,1868976 +rec-3642-org,madeline,mahon,27,medworth crescent,airforce memorial estate,rosebud,3107,sa,19970711,8911383 +rec-569-org,kaitlyn,cheshire,117,william hudson crescent,menora,berkeley vale,3056,act,19330820,4812124 +rec-2934-org,zarlia,boyle,113,audas place,clanville,robina,2322,wa,19230805,8270751 +rec-4535-org,hugh,rook,52,badimara street,,warburton,2040,qld,19231010,1438323 +rec-3649-org,alexandra,agett,48,keith street,boronia,taree,6430,nsw,19180406,8624670 +rec-3596-org,nicholas,millar,201,temperley street,malanda orchard,hyde park,2767,wa,19300617,1000123 +rec-544-org,jasmine,wardle,25,smiths road,westholme,prospect,5007,nsw,,7650116 +rec-3389-org,madeline,boyes,4,dowsley place,wattle place,kingsford,5062,vic,19760522,6564625 +rec-2680-org,gillian,leon,10,armbruster street,walmount,elizabeth south,4021,nsw,19660416,2875631 +rec-592-org,chloe,camp,25,euroka street,llantwit house,ardrossan,6149,nsw,19351005,4550681 +rec-4272-org,cooper,stockall,32,madigan street,fig trees,mayfield,3944,nsw,19700719,6708332 +rec-2895-org,joshua,kelley,59,harwood court,aprt 18 the village,emerald,3127,qld,19340831,3990210 +rec-159-org,connor,toms,22,taggerty street,vivigani,malvern east,7310,qld,19991026,6080369 +rec-4005-org,maddison,longo,5,namadgi circuit,,kiels mountain,2261,qld,19050429,8559890 +rec-1475-org,joshua,yeoman,7,drysdale circuit,,camp hill,6150,nsw,19791212,3599370 +rec-697-org,samantha,coady,5,michie street,tallaranie,minlaton,5024,vic,19951116,5201652 +rec-47-org,finn,white,403,mcculloch street,all saints college,kempsey,6084,qld,19450410,9601625 +rec-743-org,daniel,white,1,albermarle place,summer hill,brierfield,3810,sa,19870703,8258779 +rec-1031-org,ben,chorny,16,mcquade close,our folly,bonnyrigg,4120,qld,19481025,3512659 +rec-259-org,matisse,chandler,362,mcbryde crescent,21st,gowrie,3498,wa,19980731,5696159 +rec-3718-org,hannah,white,2,gallagher street,fairholme,aspendale gardens,2505,nsw,19840119,9007134 +rec-3942-org,tara,campbell,34,dunstan street,westpoint,katherine,6015,qld,19810623,8339362 +rec-2893-org,matthew,mason,14,derrington crescent,santa lucille,avalon,2602,nsw,19280503,6339601 +rec-1062-org,dale,dietrich,20,sturt avenue,unt 2,,6110,nsw,19860101,6503115 +rec-4991-org,mikaela,horkings,144,box hill avenue,berkeley vlge,paddington,4061,vic,19291011,1360308 +rec-4288-org,ruby,staude,241,,crowden,rose bay,3249,nsw,19410115,9633722 +rec-2979-org,caleb,dabinet,30,rodway street,,mount ommaney,3133,qld,19040620,2071263 +rec-3506-org,isaiah,crossman,14,hopetoun circuit,inveraray,emu park,3175,nsw,19680729,7045589 +rec-649-org,mia,haeusler,,stockdale street,rowethorpe,cleveland,3011,nsw,19091107,3742016 +rec-2190-org,dimitri,kowald,5,watson street,sec 791,alice springs,2430,sa,19510207,1597094 +rec-1566-org,liam,petersen,38,solomon crescent,blue hills,mosman,3630,vic,19800221,7148654 +rec-2485-org,madeline,zbierski,31,newman morris circuit,nedlyn,westmead,2087,nsw,19801012,6366322 +rec-814-org,nicholas,campbell,23,birchall street,karsul,carnegie,2097,act,19690319,1631489 +rec-2623-org,alannah,morrison,15,warragamba avenue,brentwood vlge,como,2031,vic,19450628,3163775 +rec-802-org,mya,mccarthy,43,wakool circuit,wilgalea,moonah west,2063,nsw,19670509,5475592 +rec-4910-org,felicity,la porte,25,groom street,gundaline,glenmore park,3892,wa,19631026,9577115 +rec-926-org,abbey,kluske,10,farrer street,villa 19,clarkson,3044,nsw,19930605,7624788 +rec-4295-org,james,grillett,268,sheaffe street,bella dona,caulfield north,2117,nsw,19890331,9598556 +rec-3311-org,coby,brinsmead,110,musgrave street,st francis vlge,canley heights,4552,qld,19391009,8442114 +rec-4464-org,peyton,marshal,53,arabana street,,plympton south,4156,nsw,19950916,3348499 +rec-2124-org,isabella,petrikowski,4,mcbryde crescent,beaumont hills,loganlea,4034,nsw,19900210,2493367 +rec-928-org,samantha,barmore,23,bilby place,yarrandoo,somerset,3073,vic,19641215,5082469 +rec-2397-org,riley,matthews,34,westhoven street,stone oak farm,success,4034,vic,19890629,5906706 +rec-2351-org,benjamin,white,35,fiveash street,meadowvale village,cranbourne,2759,sa,19900716,7111467 +rec-979-org,chloe,stanley,69,fisken crescent,hawkhurst cottage,ermington,2090,nsw,,5004344 +rec-1998-org,william,robson,77,springvale drive,magpie springs,lowood,4151,vic,19520721,2322463 +rec-639-org,oliver,pimershofer,23,betts place,moondarook,port pirie,3130,nsw,19431226,4369551 +rec-736-org,christopher,chammen,8,crisp circuit,,croydon north,3126,wa,19030403,4266096 +rec-481-org,james,kang,11,frayne place,,concord,4869,qld,19350731,7427314 +rec-503-org,carla,kirasak,5,albermarle place,,bacchus marsh,5085,vic,19630801,6299625 +rec-4461-org,marleigh,miell,20,spring range road,tulloch,peakhurst,4226,vic,19931025,4689620 +rec-2610-org,josephine,highet,6,hayden close,marandyvale,spotswood,2151,nsw,19121110,6475561 +rec-1039-org,ethan,greenhalgh,,crozier circuit,richon,rosebrook,4151,qld,19400702,6431791 +rec-4781-org,jacob,waller,89,dalley crescent,the willows,mosman,2480,qld,19580408,6317326 +rec-959-org,zac,hand,18,kambalda crescent,mckinnon glen,east maitland,4500,sa,19970725,2709860 +rec-3773-org,jessica,mckerlie,8,john close,rosewood garden,yarrawonga,3840,nsw,19810709,3600417 +rec-960-org,benjamin,berry,4,glenmaggie street,trewilga,kariong,3064,qld,19220905,3664258 +rec-1887-org,hayley,maclennan,9,throsby crescent,alabama,forrestfield,3825,vic,19331030,6913354 +rec-2238-org,millane,laundon,14,forbes street,red cross units,auburn,2035,nsw,19640213,6060013 +rec-1589-org,emma,frencham,175,hayball place,,punchbowl,4018,qld,19170628,2070987 +rec-2624-org,natalia,streich,2,aspinall street,blackridge flyfishing school,oak park,3138,vic,19250521,2222516 +rec-3347-org,willow,tsolakis,35,elsey street,kempfield,low head,6169,vic,19200916,1293288 +rec-4502-org,scott,rudd,3,saunders street,sec 1,toowoomba,2617,nsw,19600806,4857758 +rec-3286-org,rachel,bishop,10,cumbrae place,little shalford,corrimal,3167,wa,19300129,5012283 +rec-3613-org,ebony,van hees,34,bellinger circuit,morago,robina,2481,nsw,19040204,1761872 +rec-4512-org,bailey,meaney,82,miago court,uarah,mortlake,3156,qld,19880918,8223923 +rec-3630-org,cain,quilliam,40,fidge street,nuffield village,clayfield,3858,nsw,19861124,5735991 +rec-3913-org,cain,lowe,34,robertson street,hillside villas,sunshine,2145,nsw,19060725,6210006 +rec-4611-org,bailee,nguyen,17,undoolya street,,como,4125,qld,19100708,1573421 +rec-1579-org,robert,leane,8,green street,court units,broadbeach waters,4128,vic,19880611,3938828 +rec-2003-org,mitchell,webb,15,denovan circuit,villa 3,connewarre,5091,nsw,19801006,8786441 +rec-4620-org,flynn,zilm,6,beaurepaire crescent,mandurah gardens est,duncraig,3068,vic,19500619,6378859 +rec-4707-org,amber,estacio,4,glenmaggie street,perry park hostel,launceston south,3075,qld,19720412,3256476 +rec-4643-org,mason,miles,214,hawdon street,tintagel,mill park,5014,wa,19210105,2356013 +rec-1510-org,imogen,beaty,68,hilder street,,toowoomba,2120,nsw,19771106,4994511 +rec-2127-org,miranda,andresen,93,wenholz street,telopea park,williamstown,2450,vic,19180404,1851874 +rec-2617-org,grace,weidenbach,57,kemsley place,medical practice bendigo,klemzig,4127,nsw,19340907,9063243 +rec-3616-org,evan,matthews,112,enid lorimer circuit,kildarra,port augusta,6103,nsw,19961123,1551414 +rec-2277-org,noah,white,2,bardsley place,lindoran,boorowa,5021,tas,19480206,7052624 +rec-2849-org,nicholas,mcveigh,23,boolimba crescent,young retirement village,st kilda east,4224,qld,19341207,1581884 +rec-4670-org,konstantinos,nguyen,12,twamley crescent,pinda,wanniassa,2173,nsw,19730401,4155990 +rec-3678-org,,dixon,4,tytherleigh street,bulga wine estates,singleton heights,2097,nsw,19040831,8170333 +rec-2080-org,emiily,hand,4,mcnicoll street,old farm,kongal,2518,vic,19270511,3480162 +rec-945-org,thomas,bellchambers,89,carruthers street,milpara,goonellabah,2710,wa,19810726,1603931 +rec-837-org,asha,chetter,8,streeton drive,rosehill,scarborough,5051,qld,19440808,7992366 +rec-4742-org,noah,flatman,13,mawalan street,northbourne,frankston,5049,vic,19790808,6564082 +rec-2271-org,emiily,perduns,19,wilkins street,yenda units,broken hill,3124,nsw,19990108,5105163 +rec-13-org,thomas,slack-smith,106,hawken street,emmaus vlge,kirwan,2566,vic,19900607,2094894 +rec-4425-org,tiana,bastiaans,34,decima circuit,karinya lodge,hallsville,4702,wa,19150613,1914490 +rec-1196-org,matthew,bozzetti,79,bramina station,lakewood estate,vermont,6027,qld,19760609,1057227 +rec-3137-org,ridley,dumbrell,11,terry close,dalamar,naremburn,3031,qld,19870116,3888893 +rec-3543-org,toby,roles,63,chippindall circuit,afflexian,peregian beach,2337,nsw,19770325,8154319 +rec-1927-org,michael,reid,8,upton street,terranora,macquarie fields,2452,qld,19050922,1117934 +rec-1948-org,flynn,painter,7,thomas hart street,railway stn,seaton,2640,vic,19211124,8126727 +rec-4242-org,solomon,morrison,67,jarrahdale street,yaldara,empire bay,2097,qld,19400406,2523626 +rec-1313-org,layla,chammen,9,discovery street,st francis vlge,keilor east,5352,nsw,19550123,4055724 +rec-3832-org,jack,rochette,53,bennelong crescent,bexley,lakemba,4352,vic,19300831,4014081 +rec-820-org,abbie,finlay,5,,unt 1,mount warren park,4350,nsw,19730526,4857374 +rec-3218-org,lachlan,leon,6,gara place,berkeley vlge,nunawading,3810,nsw,19140403,8566655 +rec-4107-org,brinley,ho,6,vickers crescent,parks cottage,greenwith,2166,sa,19311119,9490562 +rec-1352-org,william,doman,7,copland drive,grandview,adamstown,2325,vic,19810208,5779269 +rec-192-org,madeline,huxley,7,murrell place,westbury,orange,3939,nsw,19850421,5740778 +rec-3303-org,liam,wehner,11,monaro crescent,oaklands village,bidwill,3205,vic,19350426,7873898 +rec-3178-org,natalia,maczkowiack,,badcoe street,berkeley vlge,south turramurra,3199,vic,19830221,3152282 +rec-3004-org,zachary,hulands,51,caley crescent,illoura glass studio,albany creek,5162,tas,19360826,9722255 +rec-1049-org,amy,urenda,15,jerrabomberra avenue,narraburra lodge,riverwood,4610,vic,19040320,4689528 +rec-3946-org,samantha,garnett,10,furey street,raworth cottage medical practice,wallacia,2530,sa,19210919,2074453 +rec-2358-org,caitlin,dolan,55,lawrence wackett crescent,garden settlement,beaumaris,2193,wa,19571211,7745058 +rec-27-org,angelina,campbell,161,jackie howe crescent,bugoren,woorim,6052,nsw,19531108,8948230 +rec-4530-org,christopher,elrick,4,longmore crescent,sherwood,heckenberg,2283,qld,19320515,6739254 +rec-1380-org,kyle,irons,,fernyhough crescent,openshaw,bundaberg,2611,qld,19060519,9565296 +rec-4587-org,shenae,campbell,4,lander crescent,kerradan,bondi junction,3186,nsw,19580611,5546102 +rec-4481-org,connor,dantiochia,8,wiburd street,solander centre,como,2774,nsw,19221020,6629558 +rec-454-org,jordan,webb,62,padbury street,poitrel,dynnyrne,5089,sa,19851106,1985006 +rec-48-org,georgia,shih,14,furey street,hopeview,toowoomba,6008,nsw,19870324,1794716 +rec-1276-org,abbey,parfilo,13,chandler street,barossa village,albany creek,2065,vic,19891112,8843836 +rec-3082-org,kyle,ryan,7,maranboy street,,southbank,4012,nsw,19390608,5356709 +rec-4243-org,harry,pembroke,138,sparkes close,st georges medical centre,sutton forest,3338,qld,19260311,6618265 +rec-3336-org,jacob,crossman,19,stromlo crescent,st francis vlge,bassendean,5031,vic,19681226,6490727 +rec-4908-org,hannah,miles,1,majura avenue,locn 2916,kialla,2617,qld,19100504,1629688 +rec-2736-org,bayden,lonie,37,callister crescent,mcdougall hill,burwood,2320,nsw,19880619,6874557 +rec-2843-org,lily,reid,77,streeton drive,kaweku park,parkside,3630,wa,19170624,7864863 +rec-1593-org,jayden,thorpe,44,warrego circuit,yacklin,cabramatta,2259,wa,19281105,6871482 +rec-990-org,jasmyn,yeap,30,white crescent,lawley park,murray bridge,3079,nsw,19500508,9139909 +rec-4097-org,,noble,5,carter crescent,belgravia estate,glenwood,5114,vic,19120724,8141708 +rec-1799-org,alexander,shepherd,11,sprent street,orange specialist medical centre,taree,0812,nsw,19121023,6769513 +rec-565-org,reuben,mccarthy,130,greenvale street,delaware,hoppers crossing,6019,nsw,19030224,5053375 +rec-1667-org,robert,george,28,erldunda circuit,nioka,picton,4814,nsw,19400601,4149373 +rec-281-org,evan,calio,40,sugarloaf circuit,mulvra,karalee,3033,nsw,19251026,1186290 +rec-4974-org,joshua,grimsley,22,barwon street,edwards chambers,carnegie,3136,qld,19390617,3359093 +rec-1477-org,david,green,170,enid lorimer circuit,riverbank offices,toowoomba,2071,qld,19180714,7178350 +rec-3888-org,kyle,leane,13,macarthur avenue,warrol,booragul,2200,nsw,19770320,7924874 +rec-3207-org,jacob,blunden,31,hilder street,brentwood vlge,campsie,2566,vic,19120207,5419000 +rec-4674-org,chelsea,brooker,40,stuart street,coolalie,wellington point,2076,qld,19981109,5456111 +rec-1043-org,liam,steed,61,traeger street,table mountain,rowville,7010,nt,19110729,7786184 +rec-3299-org,emiily,green,19,callemonda rise,ocean park towers,semaphore park,4306,qld,19540924,1804853 +rec-3954-org,samuel,matthews,5,bindaga street,the spur,seventeen mile rocks,5038,nsw,19580607,3679562 +rec-501-org,brody,kiss,88,knox street,kingway tourist park,caves beach,2284,sa,19560723,6452285 +rec-3154-org,samantha,howie,6,mauldon street,environa,palmview,4053,act,19840918,3489071 +rec-156-org,benjamin,rivers,31,barlow street,doribank,alice springs,2298,vic,19160517,4713796 +rec-1460-org,ella,faull,24,dowling street,nomore,norwood,2627,nsw,19600429,8885164 +rec-763-org,jack,paterson,,herbert crescent,fourways,north pinjarra,2261,nsw,19830817,3374161 +rec-3260-org,trey,camozzato,1,weston street,bulala,waverley,2450,vic,19321224,6435812 +rec-648-org,matthew,adair,6,langdon avenue,cinema centre bldg,upwey,3095,sa,19031126,6474688 +rec-4179-org,luke,parr,9,hilder street,ardrossan,parkdale,5048,nsw,19190317,6349510 +rec-4915-org,benjamin,green,10,hodgkinson street,sunset,port augusta,2570,nsw,19810814,5709794 +rec-2601-org,alexandra,thurlow,29,de burgh street,bowan downs,north turramurra,2197,nsw,19581002,9502776 +rec-4385-org,hayley,burford,7,bavin street,kooyong,little mountain,4154,vic,19640509,6451932 +rec-4994-org,jaime,mercorella,14,couchman crescent,springfields farms,taringa,4051,vic,19520708,9804598 +rec-1303-org,thomas,boileau,8,mirrabucca crescent,felbrigg,sheffield,4300,nsw,19111221,4100557 +rec-4833-org,william,millar,6,meredith circuit,larnach,thornbury,6014,vic,19340731,1314310 +rec-1342-org,seth,salt,148,carss place,burnside,alice springs,4005,sa,19531004,9880146 +rec-3836-org,erin,campbell,11,learmonth drive,lassaan,dulwich hill,4216,,19790408,5750866 +rec-2602-org,nikita,coady,18,watling place,wattle tree,athelstone,4551,act,19160504,5801919 +rec-4756-org,olivia,david,67,,thorndale,chelsea heights,4217,wa,19910923,3201406 +rec-4557-org,emma,white,1,eaglemont retreat,glenmore,eight mile plains,3025,vic,19251010,4488560 +rec-2632-org,shai,robson,51,white crescent,dooralong valley,bunnaloo,4005,act,19711226,6720340 +rec-1269-org,jessica,berry,,lindrum crescent,cloverdene,point lonsdale,2290,vic,19010829,3796385 +rec-37-org,lachlan-john,snelling,20,summerville crescent,harvic,maldon,3206,vic,19660114,7931741 +rec-1312-org,zarran,miles,25,jardine street,wildefell,frankston,2146,vic,19090220,6627892 +rec-4057-org,liam,rollins,30,lampard circuit,erinmoore,clayton,2445,,19690515,2549634 +rec-4874-org,silas,coulson,29,bindon place,warra creek,kempsey,6450,nsw,19770903,3722652 +rec-2407-org,logan,hazell,57,chewings street,,elsternwick,3350,nsw,19510911,9448381 +rec-3210-org,zachary,croker,27,guthridge crescent,riana,ryde,3143,nsw,19630415,9034657 +rec-987-org,,lodge,634,companion crescent,argyle,ballina,2161,nsw,19020407,1555679 +rec-3052-org,lucas,yoon,54,johnstone circuit,shady creek,wingham,3039,qld,19761101,8649392 +rec-531-org,kyle,rudd,,atherton street,glenmore,muttama,5158,nt,19590521,2268332 +rec-174-org,xanthe,rasic,16,ivo whitton circuit,anice-ohn,mulgrave east,2330,vic,19520527,5541516 +rec-1827-org,heath,monteleone,,marsden street,safari lodge,bicton,2227,qld,19781013,6970423 +rec-248-org,tiarna,havriluk,47,macquarie street,carrington retrmnt vlge,paralowie,7030,wa,19150929,7263381 +rec-4331-org,joe,kamp,,forbes street,neaavie,forrestfield,3585,vic,19930303,4367894 +rec-2240-org,savannah,hyland,17,pennefather street,camusfearna,cronulla,3672,nsw,19050620,9386164 +rec-1466-org,william,hare,10,steffanoni circuit,benbullen lowline stud,ranelagh,3148,nsw,19260501,1891847 +rec-3103-org,alisa,,35,osburn drive,emoh,booyal,2000,sa,19400808,2724093 +rec-428-org,bailey,stanley,30,colmer street,rocklea,rowes bay,0850,nsw,19010804,3200988 +rec-3360-org,matisse,fawkner,100,satchell place,thorndale,ashgrove,3995,qld,19990605,9611984 +rec-1714-org,latham,shepherd,50,namatjira drive,banksia village,whitebridge,6083,act,19050621,8015196 +rec-336-org,tess,pembroke,95,lawes place,sheep station,brookvale,4605,vic,19890611,6248469 +rec-1903-org,rachel,burford,4,alabaster street,griffiths wing,adelaide,3155,qld,19201014,1452003 +rec-130-org,harry,mcgregor,8,vanzetti crescent,mansfield park,taree,2763,nsw,19670709,2611052 +rec-252-org,cooper,walkley,181,willcock place,kialba,seven mile beach,2529,nsw,19990209,7199530 +rec-3386-org,alisa,kalinowski,99,morrison street,river quays,lavington,4870,vic,19991012,9382250 +rec-1042-org,alexa-rose,nguyen,5,bemm place,,currimundi,4305,nsw,19830703,4776446 +rec-120-org,tynan,,2,galleghan circuit,,wakeley,4655,wa,19800407,1022048 +rec-1616-org,zac,green,44,bingley crescent,green farm mates,karratha,5087,vic,19260814,7913094 +rec-3121-org,megan,hunns,37,blackburn street,lazy acres,bassendean,3070,qld,19430114,2634931 +rec-1651-org,caitlin,sommariva,7,bradfield street,kerry street,margaret river,2216,,19200126,5030581 +rec-4612-org,samuel,manson,52,,vivigani,cloverdale,2117,vic,19460725,4207566 +rec-2248-org,brydon,fogg,12,brigalow street,sec 1 hd molineux,loganholme,2232,qld,19260908,6678930 +rec-4125-org,jayden,browne,220,marshall street,,farrer,2112,nsw,19291128,7073714 +rec-4631-org,lachlan,zawadzki,,hazel smith crescent,wdgee street,bowral,6148,sa,19990420,7589775 +rec-2903-org,vianca,ryan,10,mareeba street,manila,leichhardt,2480,tas,19211205,7065063 +rec-4143-org,tyler,mcclelland,1,millen street,old post office,woy woy,2094,vic,19061004,8000542 +rec-3520-org,alyssa,artis,44,mceachern crescent,,cabramatta,3064,qld,19220615,9906451 +rec-3618-org,erin,hearn,,port jackson circuit,gowan,elwood,2605,nt,19101004,5064504 +rec-4075-org,rhys,dugdale,9,port jackson circuit,ainslie house,ryde,7009,nsw,19010725,5007081 +rec-1489-org,matthew,brock,18,longworth place,never die,oaklands park,2092,nsw,19500905,5036431 +rec-1553-org,ebony,robson,31,freda bennett circuit,rowethorpe,ryde,2450,nsw,19301219,3841520 +rec-4053-org,sebastian,doody,10,mcintyre street,,molong,2061,qld,19881126,4712894 +rec-3332-org,lily,chabrel,12,majura avenue,lambton denture clinic,geelong west,6056,qld,19700626,7967866 +rec-1122-org,kaitlin,goldsworthy,11,,poitrel,thirroul,2035,nsw,19640517,9127277 +rec-2023-org,krystin,pulvirenti,6,james scott close,chateau royal,ashfield,2145,vic,19350408,1694043 +rec-1810-org,fraser,miles,8,bungonia street,hartley st school,kardinya,3782,vic,19390405,8206248 +rec-2399-org,kalli,houldsworth,23,fellows street,ardmona,claremont meadows,5041,nsw,19871214,9768941 +rec-2503-org,vendula,coleman,21,currong street,cherrymount,riverwood,2526,vic,19940114,6675466 +rec-961-org,maya,bruinewoud,274,warrego circuit,palm lake resort,glenmore park,4350,qld,19810702,4054569 +rec-1759-org,jake,bradshaw,75,scantlebury crescent,bendigo retirement village,brooklyn,4171,wa,19210731,9605426 +rec-4117-org,jaimee,beams,5,cobbadah street,grand central,chevron island,2620,nsw,19720601,9646957 +rec-4387-org,holly,neumann,6,ordell street,littledale,blackmans bay,3046,qld,19340707,6366326 +rec-847-org,riley,spicer,124,mclachlan crescent,glengallan,boort,2508,nsw,19941213,3182778 +rec-4979-org,timothy,webb,23,tom roberts avenue,cathederal place,padstow heights,2193,nsw,19270531,2303333 +rec-1671-org,ethan,lomman,404,edwell place,brentwood vlge,ivanhoe,3792,nsw,19740120,8595511 +rec-3636-org,blaize,mcfadden,12,fitchett street,brentwood village,yass,2062,nsw,19470701,1930825 +rec-3457-org,james,coleman,297,discovery street,irrigation farm,campsie,2315,wa,19350803,7236834 +rec-502-org,lauren,berryman,3,doyle terrace,canberra avenue,menindee,3016,vic,19390528,8295272 +rec-183-org,connor,orpwood,171,domain street,brampton,parkdale,2040,vic,19870522,2514560 +rec-636-org,adam,vaszocz,63,wyles place,willows caravn park,gravesend,3135,vic,19881113,1015197 +rec-12-org,caitlin,hingston,29,braine street,,willagee,6020,nsw,19980805,7044257 +rec-1015-org,brianna,zilm,11,,craigow,deer park,6112,tas,19471001,5100168 +rec-285-org,bridget,burford,14,gibb place,melaleuca,greenwood,3280,wa,19090212,4048860 +rec-147-org,cassandra,lock,5,glossop crescent,kames,scarborough,6153,nsw,19371206,2516564 +rec-2967-org,emiily,clarke,5,john russell circuit,,canley heights,5032,wa,19760608,4952094 +rec-490-org,crystal,webb,6,holman street,rowethorpe,nowra,3095,vic,19800226,6491894 +rec-3467-org,jack,reid,1,purser street,villa 43,flemington,3763,qld,19160817,6955318 +rec-525-org,emiily,lock,14,collins place,pipers river,oakleigh,6064,nsw,19350628,6850395 +rec-2047-org,belinda,de gennaro,178,sturdee crescent,birks harbour,bundaberg,6030,nsw,19210814,9392022 +rec-3579-org,megan,scripps,40,karawatha place,raycroft,bonnells bay,2761,sa,19970108,7573986 +rec-4443-org,amber,nguyen,293,hartung crescent,grandview,auburn,2209,nsw,19780324,1624161 +rec-914-org,dylan,szmeja,6,ellerston avenue,rowethorpe,como,3824,vic,19610131,4996805 +rec-1192-org,nicholas,fanraatree,9,biddell place,st francis vlge,hoppers crossing,2193,sa,19690803,4228917 +rec-4065-org,oliver,,4,jeanette place,mehruda,mosman,4226,sa,,7007321 +rec-1585-org,cooper,green,14,kingsford smith drive,australia fair medical west centre,innaloo,4114,sa,19661010,1494383 +rec-2555-org,jacob,webb,15,chapman street,flr 3,lutwyche,4032,sa,19320926,3970231 +rec-2063-org,maya,coffey,11,tucana street,bombowlee,dianella,2795,nsw,19880218,2732680 +rec-2751-org,beau,vincent,78,tryon street,spring grove,rosslyn park,3174,nsw,19880120,8217970 +rec-46-org,april,bellchambers,2,borrowdale street,,wollongong north,2080,qld,19970426,8134681 +rec-4084-org,ethan,beckwith,26,hirst place,miniacres,morphettville,4870,qld,19981113,9473353 +rec-939-org,kyle,hope,26,bundey street,kacadoo,armidale,2097,nsw,19631116,2650117 +rec-2836-org,joe,white,4,towers place,hybernia park,coolaroo,2066,vic,19851122,1899363 +rec-2674-org,lachlan,clarke,20,condamine street,deswod,chester hill,4019,qld,19900626,5423805 +rec-1538-org,chelsie,sherriff,1,galloway street,renown,hoskinstown,5280,vic,19370430,7403002 +rec-1366-org,rory,moulton,2,box hill avenue,redwood village,beulah park,3844,qld,19760503,8152321 +rec-4624-org,schkirra,de nichilo,14,kirkwood crescent,apt 16 the village,killara,4740,nsw,19060211,3688155 +rec-1035-org,emiily,campbell,12,mokoan place,rosetta village,balwyn north,3551,vic,19580917,3440031 +rec-3525-org,kirra,spratt,14,giles street,rajamare,cleveland,5127,qld,19390404,2611615 +rec-1314-org,,motbey,43,badimara street,rowethorpe,rosebud,3345,nsw,19500328,3314402 +rec-236-org,hamish,mason,7,langdon avenue,stokes crossing,yarrambat,4060,tas,19010712,6379466 +rec-2222-org,jack,mason,,schomburgk street,mlc centre,beverly hills,4074,sa,19560710,4752429 +rec-4355-org,michael,fullwood,8,dixon drive,tewantin plaza,wanneroo,2831,qld,19060113,9672570 +rec-3617-org,darcy,nguyen,67,ferdinand street,willarra,osborne park,3073,act,19810513,8210958 +rec-3792-org,jack,marcaros,59,goyder street,st johns terrace,ormeau,2088,qld,19810311,5200718 +rec-4779-org,matthew,apted,1369,macrobertson street,pine tree,toowoon bay,2120,vic,19540130,5268631 +rec-673-org,stephanie,braithwaite,86,chisholm street,paradise lake resort,toowoomba,2516,nt,19750104,4262794 +rec-3316-org,sophie,coulson,8,blackburn street,makana station,mansfield park,5097,nsw,19690320,9010006 +rec-4452-org,meg,newel,23,steele street,kubin village,yenda,3202,nsw,19610112,2538798 +rec-2414-org,noah,cronshaw,55,tristania street,,rowville,4610,nsw,19690202,9453034 +rec-4480-org,jessica,serafin,11,bucknel circuit,farm shed,toowong,3130,nsw,19140516,5581897 +rec-4489-org,emiily,bishop,12,,pine dale,vermont,2088,wa,19730322,3947458 +rec-4411-org,montanna,dicks,224,totterdell street,quarter deck,toorak,3024,qld,19571101,7774754 +rec-4559-org,ryan,white,19,wilkins street,logancrail,banksia,4064,sa,19760204,7368589 +rec-2526-org,liam,doody,54,bastow circuit,maranui,cowra,4129,qld,19711125,3842987 +rec-1412-org,anthea,nguyen,16,kelleway avenue,rydal bank,concord,3196,qld,19281104,2137596 +rec-1056-org,chloe,imgraben,47,curlewis crescent,dragon rising,burleigh waters,2680,qld,19520516,6111417 +rec-3724-org,jacob,beatton,,maharatta circuit,specialist centre,robertson,2643,nsw,19860630,9285118 +rec-4824-org,mitchell,longo,52,faucett street,beagle bay,wamuran,4814,nsw,19010102,4714885 +rec-676-org,samuel,princehorn,20,gould street,somerview,warra,3152,nsw,19761209,1347961 +rec-1860-org,christopher,millar,12,piddington street,cannonvale whitsunday shopping centre,lavington,5048,qld,19250807,1831647 +rec-3817-org,jared,mason,9,woolner circuit,beachwood,page,3309,nsw,19510406,5818690 +rec-2852-org,joshua,huxley,12,southern close,littledale,maryborough,2517,nsw,19670618,1728316 +rec-4114-org,mia,pascoe,54,dwyer street,connemara,leichhardt,2015,sa,19080310,5423895 +rec-678-org,lucy,crisci,13,callister crescent,villa 2,leichhardt,4510,vic,19531017,6493933 +rec-4510-org,noah,white,804,caladenia street,sec 437,molong,2119,wa,19040118,9864936 +rec-3914-org,mya,rundle,9,adair street,mehelu,north narrabeen,2090,sa,19110912,9427450 +rec-2963-org,fyynlay,deblasio,163,longerenong street,werribee plaza,forest hill,2790,nsw,19161102,8968244 +rec-3306-org,,green,2,castlereagh crescent,dunbogan caravan park,beecroft,3073,tas,19760131,5181228 +rec-443-org,olivia,matthews,7,frater crescent,waterdale,marmion,3185,qld,19230219,8833281 +rec-1931-org,thomas,bruhn,21,namadgi circuit,mariner views,slacks creek,4670,wa,19540821,1246505 +rec-1592-org,karli,campbell,85,burdekin avenue,brambletye vinyard,surry hills,2118,vic,19580309,4423725 +rec-177-org,aidan,campbell,41,edwards street,clanville,rolleston,4130,nsw,19410718,8324852 +rec-3869-org,meg,herbert,162,callister crescent,villa 2,burrum heads,3078,sa,19101126,6887725 +rec-1029-org,charlotte,dixon,8,lavan place,afflexian,booragul,3196,sa,19920713,7020668 +rec-989-org,paul,fauser,6,bargang crescent,springdale,dareton,2213,nsw,19540911,3667818 +rec-1215-org,isabella,grimm,7,pither close,haigh park,ringwood,2256,vic,19660730,9089145 +rec-913-org,kira,wimmer,4,sturdee crescent,ark hall,tanjil south,3173,sa,19410628,4604196 +rec-2748-org,alex,beatton,237,kosciusko avenue,anzac house (cnr archer s street,midway point,4214,sa,19100717,3485662 +rec-3729-org,ruby,hentze,30,harkness street,glenearra,florey,4178,sa,19030606,2379739 +rec-3444-org,tenille,heron,15,mcwhae circuit,trail view,orange,3128,nsw,19200707,6908407 +rec-4959-org,jessica,kusel,50,limestone avenue,jinchilla,lavington,4519,qld,19721222,3705755 +rec-434-org,lachlan,haussen,11,moonta place,milmilland,burwood east,2166,nsw,19180722,3285099 +rec-2408-org,tristan,aldous,11,solander place,,goornong,4157,vic,19990121,5511852 +rec-1841-org,erin,pernini,32,lorimer place,robertson barracks,northmead,5167,sa,19710527,5533014 +rec-139-org,holly,rieman,3,heagney crescent,winter park,devonport,2546,qld,19751221,5260793 +rec-2638-org,jordan,mcmullen,4,albermarle place,,northmead,3579,,19291225,4004053 +rec-4788-org,shanaye,averats,162,benjamin way,ashville,bamawm,3175,qld,19340625,8457909 +rec-1546-org,emiily,white,12,crago place,rocklea,mosman,3300,vic,19390429,6209600 +rec-405-org,jazz,dallas,82,wattle street,glenefer garden,clapham,3788,nsw,19780723,4927681 +rec-4492-org,hayden,,13,durham place,hamilton,young,3121,nsw,19780531,9988689 +rec-4695-org,christian,dietrich,27,lindrum crescent,matilda blue,rostrevor,4560,wa,19170207,3108840 +rec-4108-org,calvin,herbert,260,shortland crescent,kookaburra village,kalorama,3130,nsw,19990902,4778880 +rec-1845-org,gabrielle,telleglou,163,huelin circuit,the gorge portion,st johns park,2126,nsw,19820403,3405740 +rec-3820-org,anita,kalma,10,eugenia street,tantallon,karalee,5076,qld,19780922,1975087 +rec-2355-org,luke,rollins,360,hickenbotham street,berkeley vlge,arundel,2221,qld,19240109,6938121 +rec-3190-org,caitlin,grimm,10,yapunyah street,beaumonts beach house,bethania,3350,vic,19520809,9350011 +rec-3414-org,alysha,alderman,28,benson crescent,southbidge,mill park,2261,nsw,19700704,1772593 +rec-3976-org,tara,stanley,109,haswell place,dale view,surfers paradise,2196,nsw,19091118,7519489 +rec-3317-org,amber,von hoist,75,pattinson crescent,school house,hoppers crossing,3311,vic,19970624,8009122 +rec-804-org,james,kostrzynski,3,chipperfield circuit,berkeley vlge,potts point,4285,vic,19200505,6498292 +rec-4595-org,samuel,rudd,46,powlett street,gilgowie jacks,kingston,3453,sa,19580819,7309587 +rec-955-org,william,gohl,378,charlton street,toomba,kellyville,3058,vic,19030711,1291827 +rec-2734-org,grace,green,8,nagara street,sit 50b,nullawarre,2540,nsw,19771008,9946309 +rec-1914-org,olivia,bennell,95,sidaway street,south seas (cnr cook s street,ballarat,6150,sa,19520214,9360716 +rec-1745-org,christian,faull,23,delprat circuit,erina gardns,maryborough,2430,sa,19510814,6483913 +rec-2296-org,caitlyn,green,105,hawker street,snug beach cvn park,crestmead,2145,nsw,19691114,2466204 +rec-4128-org,stephanie,noble,31,page street,brentwood village,carrum,5290,nsw,19800617,4763017 +rec-1972-org,billy,trenerry,104,tenison-woods circuit,camusfearna,edensor park,2177,tas,19900810,8678668 +rec-1682-org,kiara,starega,51,knoke avenue,llen nomis,southern cross,4615,nsw,19541115,5126468 +rec-4020-org,callum,wheatley,3,john cleland crescent,murrong,florey,2065,nsw,19651106,9895199 +rec-2986-org,olivia,santi,138,krichauff street,rose-lea,port pirie,3976,vic,19590808,5694951 +rec-1697-org,andie,george,118,mckail crescent,brentwood vlge,pelican waters,3121,wa,19490414,4798962 +rec-3442-org,william,frahn,,haystack crescent,rainbow park rp 8965,calista,4740,nsw,19500602,6417261 +rec-1817-org,noah,boyle,11,dooland court,,flowerdale,3163,vic,19260331,2019310 +rec-4486-org,isabelle,ryan,2,lambrigg street,flt 167,jardee,2750,act,19880816,7698870 +rec-2073-org,hayley,dolan,59,,delicate nobby street,deniliquin,5031,qld,19920913,1276506 +rec-1317-org,laura,,82,doyle terrace,polynesian village,stretton,3103,nsw,19200221,1808199 +rec-1193-org,jake,pascoe,,gooreen street,lords house,mittagong,3023,wa,19300716,8300308 +rec-3833-org,nicholas,clarke,13,gaylard place,tryphinia view,wetherill park,2810,nsw,19041223,3927795 +rec-2752-org,alexandra,allabanda,,pindari crescent,afflexian,ottoway,2074,qld,19120701,9676170 +rec-96-org,george,macha,25,tepper circuit,erins rest,kardinya,2758,vic,19270326,8072800 +rec-809-org,jasmin,kulas,1,sheehan street,salimtal,toowoomba,3850,nsw,19210113,7425903 +rec-3322-org,harrison,matthews,31,northbourne avenue,,bacchus marsh,2138,vic,19180226,1060187 +rec-3323-org,bailee,vearing,18,bavin street,sun city tourist park,safety beach,6076,nsw,19741208,4201824 +rec-1748-org,mhary,rundle,12,bradfield street,hollybrooke,woodlands,3280,vic,19960812,2523448 +rec-269-org,summer,deleon,1,uriarra road,tesbury,kurri kurri,2333,qld,19401028,6523096 +rec-3390-org,isaac,hoffman,3,livingston avenue,wildefell,burleigh heads,2289,vic,19450220,8451831 +rec-3461-org,gabrielle,clarke,24,troughton street,unt 3,,2114,qld,19440219,9711144 +rec-800-org,erin,matthews,37,pocket avenue,kangaroo grnd,goodna,3160,nsw,19960529,7562147 +rec-2733-org,patrick,green,88,kelsall place,killarney east,rose bay,5108,nsw,19151112,5843260 +rec-1674-org,keely,harrington,296,brickhill place,henry kendall hostel,menindee,2830,nsw,19330913,1759909 +rec-4292-org,channing,white,28,limbunya street,willow lodge,lutwyche,2264,wa,19770224,3839656 +rec-3744-org,jake,jongewaard,195,proserpine court,caroona village,taree,2035,act,19200201,4423130 +rec-3163-org,daniele,campbell,20,freehill street,botin,towradgi,7000,vic,19400817,6050678 +rec-3917-org,angelina,lowry,20,browne place,craigston,peakhurst,3284,qld,19350921,5692471 +rec-3944-org,kyle,candida,26,spofforth street,pinecroft,clearview,3187,nsw,19001111,1796923 +rec-3653-org,samantha,glass,40,whistler place,foxlea,evans head,5480,wa,,3783154 +rec-4091-org,cheyenne,campbell,18,forbes street,kinjibi,bundamba,4814,vic,19080715,6532935 +rec-3598-org,katelyn,simmonds,9,kellway street,amboyne,noble park,2148,vic,19930530,5268119 +rec-975-org,damien,clarke,18,brimage place,2nd hse lhs,mentone,2115,nsw,19721023,2631407 +rec-4324-org,lauren,nguyen,253,myers place,canberra hse,coomba,5034,nsw,19110707,2534716 +rec-3635-org,kyle,zagar,79,buller crescent,burundah,klemzig,6030,wa,19400504,1168847 +rec-1250-org,luke,gazzola,10,newman morris circuit,ruffenuff,lakemba,3046,nsw,19420929,2904508 +rec-4119-org,mikayla,cavaivolo,8,ash place,pepinmarti,paterson,3805,vic,19911024,9918932 +rec-2704-org,oscar,frew,87,akma place,scotty,mont albert,2138,wa,19050914,8407358 +rec-1053-org,jade,quast,4,hodgkinson street,raworth cottage medical practice,east ryde,6210,vic,19390121,5098690 +rec-4924-org,william,reid,12,tatchell street,st georges park,hoppers crossing,4814,nsw,19750418,4238509 +rec-4059-org,gabrielle,toseland,3,pinkerton circuit,lethbridge court,campbellfield,2590,qld,19200414,6631971 +rec-1773-org,liam,haggett,64,macpherson street,schofield hill,minto,6210,qld,19550910,5068609 +rec-4329-org,zac,doman,112,buvelot street,tulse hill,ballarat,2097,qld,19150628,7022901 +rec-4677-org,tate,spagnoletti,29,blamey crescent,tullatoola,wangaratta,4520,qld,19200505,7390367 +rec-2828-org,dylan,pinheiro,7,canopus crescent,strabane,birkdale,5050,nsw,19131214,2918000 +rec-1458-org,connor,green,95,warrai place,brindabella specialist centre,padstow,4051,nsw,19500301,5431719 +rec-3436-org,joel,marson,40,tinaroo place,catumbel lodge,hoppers crossing,2035,vic,19100123,9238396 +rec-4429-org,joel,ryan,22,robertson street,erinmoore,portarlington,3196,qld,19950602,9067165 +rec-4896-org,phoebe,melham,,gara place,hse 4,collie,7113,nsw,,8345956 +rec-4601-org,taliah,pascoe,17,,glenview,north turramurra,5540,nsw,19960111,7724515 +rec-4423-org,meg,everett,13,greenough circuit,miowera,caves beach,2267,nsw,19660606,8990768 +rec-3529-org,joel,cerins,24,majura lane,bungarra,matraville,4164,wa,19860411,3772618 +rec-363-org,kirra,campbell,29,groom street,rockleigh cottage,north ryde,3206,nsw,19951128,9444838 +rec-4082-org,caitlin,dominey,2,,kilburnie,plainby,6018,nsw,19761113,3992744 +rec-166-org,robert,nguyen,22,barlow street,fred lean hostel,dickson,6152,nsw,19140127,9527501 +rec-1203-org,amy,flannery,15,jansz crescent,timberscombe,lakemba,5556,qld,19871219,1702911 +rec-2044-org,elijah,coleman,43,gledden street,malekula,granville,2322,qld,19821231,1566439 +rec-4135-org,simone,meaney,105,lambrigg street,rowethorpe,kirribilli,2765,nsw,19930504,6453396 +rec-424-org,nicholas,george,25,kambah vlge,casuarina shoppingsqre,fish creek,3585,nsw,19370405,8589026 +rec-1823-org,jackson,zilm,8,marungal avenue,dykehead,toormina,3052,nsw,19390626,2961711 +rec-1454-org,sebastian,papageorgiou,129,carstensz street,belgravia,cherrybrook,2479,vic,19570326,5979503 +rec-2533-org,jayden,hick,42,wisdom place,baroona,north motton,3350,sa,19861119,9522196 +rec-3124-org,nicholas,colquhoun,241,chataway crescent,gibraltar,blandford,2166,qld,19370130,2145262 +rec-2569-org,lara,bennier,16,mccormack street,yalgoora,golden grove,4122,nsw,19490422,4493543 +rec-670-org,jasmyn,simmonds,101,kingsmill street,euroka,coonabarabran,3194,nsw,19091211,3041267 +rec-958-org,jye,humphreys,25,maynard street,,berala,6057,vic,19670801,9902860 +rec-499-org,james,reece,35,delprat circuit,villa 5,woorinen,4870,qld,19730623,1718031 +rec-4345-org,tyler,pascoe,4,blackburn street,henry kendall bayside,ivanhoe,4221,vic,19740817,8405094 +rec-3494-org,william,redington,107,postle circuit,white rock,nowra,4034,sa,19840716,3386603 +rec-129-org,ebonie,myles,262,inlander crescent,ferndale,albany creek,2250,qld,19300201,8494390 +rec-1126-org,lydia,mcglinn,42,federal highway,bessboro,noble park,4626,nsw,19840629,1700034 +rec-3018-org,amber,schmelter,10,o'connor circuit,,hermidale,3083,nsw,19740411,2810306 +rec-3372-org,james,bishop,4,jemalong street,taronga,tweed heads south,7250,nsw,19540224,7589870 +rec-4961-org,jacob,careless,33,,bolaro,coolaroo,6059,wa,19770706,7248157 +rec-2382-org,emma,mccarter,21,enderby street,,burwood east,3052,nsw,,1635330 +rec-2218-org,tyler,berryman,223,broad place,villa 3,clayton,6355,vic,19550922,2531288 +rec-2908-org,sam,plessnitzer,26,william webb drive,rockview,cowra,3023,nsw,19800518,3756443 +rec-1947-org,aloysius,kammerman,1,alpen street,marriott downs,burwood,6153,vic,19360722,6279535 +rec-2094-org,hannah,ferris,25,brereton street,macian house,ruse,2211,qld,19650926,5013659 +rec-3879-org,liam,dixon,,wallaroo road,shady creek,south wentworthville,6210,nsw,19750926,4225223 +rec-3192-org,emiily,dolan,19,bagshaw place,legacy units,hopefield,2705,tas,19320911,7815080 +rec-68-org,roy,howie,59,reader court,rosebery hill,wanniassa,4213,qld,19360115,9350479 +rec-1803-org,robbie,carmody,34,bernacchi street,melita,north st ives,2170,qld,19391211,8441818 +rec-475-org,mitchell,mousellis,11,bougainville street,river mews,safety bay,2722,nsw,19480302,2186834 +rec-2111-org,matteus,wilde,13,cumberlege crescent,treetops,bourke,4740,qld,19260702,7889277 +rec-28-org,blake,bracci,159,duffy street,hillcrest lodge,bacchus marsh,4510,nsw,19590213,9959006 +rec-4654-org,samantha,stroeh,18,narryer close,mylandra,parkside,4125,tas,19180113,2662103 +rec-3253-org,,prideaux,117,wilshire street,rosetta village,loch,4503,nt,19700320,4150192 +rec-2002-org,nicholas,rees,93,murrell place,harriman park,hemmant,5162,nsw,19350308,3061813 +rec-4231-org,,durban,63,ormond street,girrahween homestead,narrogin,3284,vic,19010130,3247158 +rec-897-org,cameron,shepherd,16,clift crescent,nurock,northgate,2340,qld,19620826,1930833 +rec-390-org,rebecca,white,34,wilkins street,,campbelltown,5038,vic,19040710,7459820 +rec-2550-org,katie,noble,16,torrens street,old hillside,rose bay,4510,nsw,19050728,6816111 +rec-2931-org,,campton,31,kennewell place,palms lodge,coolbellup,4171,nsw,19030416,2809212 +rec-4812-org,anthony,roche,11,waller crescent,gungarlin,inglewood,3103,act,19930109,7209435 +rec-4308-org,samantha,laing,368,stopford crescent,argyle village,tharbogang,2333,sa,19490130,3281458 +rec-1639-org,megan,bishop,7,maltby circuit,buena vista,naremburn,4740,qld,19920611,9512945 +rec-2640-org,jackson,ljostad,2,hensman street,,berwick,5242,nsw,19640817,9825573 +rec-2214-org,eliza,burnell,2,badimara street,pangani,armidale,2607,nsw,19960416,3920251 +rec-568-org,katelyn,dountsis,111,goldner circuit,cremona stud,mulgrave east,2256,nsw,19430612,6491584 +rec-376-org,phoebe,whisson,12,glasgow street,white house,kandos,2770,nsw,19870307,4025481 +rec-757-org,charlotte,baynes,156,bainton crescent,winton,malvern east,6111,nsw,19221231,7857555 +rec-4693-org,archie,white,19,kernot street,ingevale,corndale,2260,sa,19560508,5801177 +rec-3967-org,ash,nguyen,45,mcmillan crescent,warraview,mount gravatt,4165,nsw,19230118,2770136 +rec-4576-org,liam,nitsolas,7,tauss place,dp 808602,koo wee rup,2287,vic,19400210,3752472 +rec-3671-org,zane,snell,30,altair place,grangemore,toowoomba,6057,nsw,19090918,3576930 +rec-3851-org,jairus,blackwell,211,igera place,ambervale,mentone,2519,wa,19060228,2309849 +rec-3098-org,jacob,webb,6,majura road,moline village,ashfield,4352,tas,19470221,1586712 +rec-2981-org,nathan,wiemann,10,gingana street,,brighton,3101,vic,19370429,8432426 +rec-3994-org,nathan,clarke,33,stobie place,coolamon road,ascot,2218,qld,19121126,9963518 +rec-1409-org,tylah,kempe,8,arthur circle,tylden park,adamstown heights,3133,sa,19721016,1844518 +rec-1586-org,phoenix,pinzon,205,hawker street,scottish masonic village,carina heights,6062,wa,19290505,1130499 +rec-2014-org,jared,coleman,37,cumpston place,heatherdale,kingston,3130,nsw,19280705,2238622 +rec-4899-org,daniel,coleman,1,russell drysdale crescent,palm lake resort,mount eliza,6159,wa,19651018,1615911 +rec-2135-org,ethan,green,1,masonic birks place,ridgebrook,aspendale gardens,2069,wa,19520318,8666305 +rec-148-org,charlotte,suth,12,deasland place,carisbrook,belmont,4814,nsw,19191009,8934958 +rec-132-org,bryce,clarke,15,kellick place,beau-ridge,mill park,4413,tas,19821213,6173366 +rec-2263-org,jade,zimmermann,71,johnston street,cannonvale whitsunday shopping centre,college park,5010,wa,19131126,2103370 +rec-2394-org,alisha,kaderes,37,jaeger circuit,locn 8,park holme,4514,vic,19020714,2567085 +rec-2970-org,charlie,mccarthy,1,swinden street,court units,sandgate,2250,wa,19830303,3510238 +rec-1874-org,connor,webb,,hargraves crescent,,andergrove,3806,wa,19501118,4659489 +rec-3354-org,renee,clarke,18,woinarski place,yarrabee,ermington,4127,nsw,19420312,1980801 +rec-982-org,,allard,26,dyring place,retirement village,south perth,4852,nsw,19491011,9472794 +rec-353-org,zachary,bartel,116,leist street,the gums,hawthorn,3178,vic,19481219,9052374 +rec-2614-org,aleisha,bridgland,11,arndell street,tathra,kempsey,2594,sa,19931019,4871743 +rec-2758-org,chloe,rafanelli,3,stantke place,gemma,dianella,4872,vic,19570715,8691066 +rec-935-org,alexandra,steers,108,chambers street,loch snizort,bondi junction,6009,nsw,19620521,9899937 +rec-3949-org,belinda,de la cruz,7,carumbi place,eddington,charlestown,2460,vic,19020217,6051352 +rec-1732-org,sophie,mahony,8,ashby circuit,bunya highway,pumphreys,3040,qld,19651025,5839336 +rec-348-org,leah,clarke,2,iterra place,brentwood village,new farm,4109,vic,19650213,9701390 +rec-1079-org,jessica,robson,337,marcus clarke street,macarthur,vermont,3429,nsw,19790719,6293706 +rec-2316-org,joshua,clarke,100,hurley street,phoenix park stud,nollamara,2145,vic,19340629,1162090 +rec-3198-org,kristen,white,5,sherlock street,morayfield exchange,wangaratta,5082,wa,19761201,8300732 +rec-1158-org,adela,lomman,7,,canberra hse,frankston,3158,vic,19980301,2548086 +rec-1262-org,emmerson,maziakowski,58,irvine street,loughmore,nunawading,4211,qld,19400316,1807250 +rec-1541-org,jessica,paine,58,eddison place,pine hut,new farm,2022,vic,19661210,8315488 +rec-720-org,lucas,coleman,27,burn street,bluegum,ringwood,2843,vic,19991101,7896258 +rec-554-org,domenique,alves,4,croton street,,marayong,7017,qld,19590615,2034593 +rec-3481-org,bethany,steers,3,temperley street,parkside flats,east maitland,4210,vic,19610825,5823896 +rec-4509-org,,tiller,12,colebatch place,brentwood vlge,jesmond,3163,vic,19800720,9020997 +rec-3255-org,micaela,harrington,9,burrinjuck crescent,locn 2192,condell park,3175,nsw,19971004,2317861 +rec-451-org,daniel,chandler,31,porteous crescent,northaven,ashwood,2152,vic,19410825,3631138 +rec-2945-org,katelyn,cochrane,2,thozet place,eden park,narellan,2750,nsw,19910821,9564362 +rec-2474-org,tansy,carp,11,fiveash street,blueberry,loxton north,3551,wa,19360605,5801878 +rec-229-org,jack,mercorella,10,batman street,mannibadar,biggera waters,2290,nsw,19290508,2441074 +rec-3433-org,charlotte,meadows,59,totterdell street,b,plumpton,2905,qld,19030219,6004748 +rec-1260-org,renee,brock,10,maddock place,,ferndale,7268,vic,19760915,4013281 +rec-1821-org,dale,laundy,75,miller street,,redhead,6112,qld,,8721689 +rec-4124-org,brianna,white,39,laughton street,corandirk,stratton,4551,sa,19840310,9784905 +rec-3720-org,julia,gao,17,horizon avenue,arthur river park,woodcroft,3952,nsw,19280810,7151454 +rec-831-org,laura,flannery,54,sid barnes crescent,weemilah,winston hills,5073,qld,19581023,9712180 +rec-700-org,noah,menzies,18,bingley crescent,east lynn,abbotsford,0870,nsw,19391026,1502043 +rec-1710-org,ayla,thorpe,34,black street,wunpalm,currambine,5540,vic,19031202,8748647 +rec-3044-org,nicholas,mycko,259,alma close,farm shed,centennial park,3000,qld,19450728,3274337 +rec-2990-org,harrison,burford,30,de salis street,gwandalan,molong,4105,vic,19511229,5011476 +rec-3681-org,david,lowe,67,bride place,karinga park,mount hutton,4152,vic,19231020,4604084 +rec-346-org,,nabialek,,warby place,,margaret river,2224,sa,19191126,2473424 +rec-4289-org,elly,miles,2,vidal place,pacific regis,loganlea,6061,qld,19451126,5179731 +rec-4228-org,amber,reid,3,hedley street,westerham,bibra lake,6108,vic,19440915,9481816 +rec-1308-org,mitchell,crossman,75,wakefield garden,fairburn park,charlestown,3995,vic,19751101,4081790 +rec-3424-org,riley,clarke,12,edwell place,bonnie,eatons hill,3218,nsw,19570717,3007913 +rec-2437-org,eden,crossman,26,michael holt crescent,scenic lodge,peakhurst,2200,wa,19240123,9861015 +rec-1282-org,,teteris,76,kellermann close,bondo,brighton,3030,nsw,19381004,5797955 +rec-1440-org,alana,van geel,10,manity court,river mews,seymour,2444,sa,19100427,7319687 +rec-1830-org,caitlin,weaver,298,vagabond crescent,francis chambers,thornbury,5072,nsw,19680909,7831777 +rec-381-org,brooke,obersteller,13,hovea street,plainbrook,preston,3095,nsw,19361218,8188130 +rec-2087-org,jarrod,manson,29,dalgleish close,beth-el,mypolonga,3182,qld,19160808,9103373 +rec-869-org,zarlia,slape,63,cory place,ingevale,como,3356,wa,19821201,7582121 +rec-907-org,kye,morrison,6,biddlecombe street,martins well station,daylesford,4670,vic,19951109,8949737 +rec-594-org,,binns,90,plummer street,toowoomba,hoppers crossing,2026,sa,19011227,4137992 +rec-4942-org,rachel,karlovcec,1,alberga street,,eastern heights,3228,nsw,19250114,9531225 +rec-188-org,,greenland,3,dines place,bayford cottage,blue haven,2526,vic,19240628,5073770 +rec-3199-org,madison,maynard,11,scrivener street,attadandoo,south maclean,2800,vic,19331104,7673675 +rec-2865-org,mackenzie,beams,47,britten-jones drive,shenstone park,bundarra,5108,,,5225201 +rec-3518-org,alexander,priest,41,manu place,,bundeena,4701,qld,19420417,9205694 +rec-4531-org,alex,babic,7,burnett street,whattleglen,wilmot,4552,vic,19051202,5673881 +rec-1844-org,benjamin,lowe,26,wentcher place,emoh,austins ferry,2761,nsw,19380621,1039986 +rec-4838-org,abbey,quill,22,rafferty street,blue hills,gumdale,2460,nsw,19150305,5107379 +rec-118-org,hannah,carbray,5,rawson street,cranbrook,mayfield,2032,wa,19170912,7822273 +rec-2220-org,anthony,green,51,honyong crescent,kilwinning,fadden,2171,wa,19790424,9686264 +rec-2898-org,thomas,mcgregor,214,jarrah street,cooloola farms,boulder,3072,nsw,19001023,6504301 +rec-4012-org,connor,sleath,10,toohey place,manor court,highett,3081,nsw,19040425,3130394 +rec-4214-org,ka,george,8,gaunson crescent,australia fair medical west centre,auburn,7325,vic,19041031,8708132 +rec-1760-org,nicholas,eglinton,13,newdegate street,villa 2,elwood,4061,nsw,19680630,7806235 +rec-2672-org,bianca,neumann,19,torres street,ainslie nursing home,ascot vale,7000,wa,19801124,8402773 +rec-3165-org,shakira,,89,ainslie avenue,wandana,pymble,3631,qld,19241014,1774551 +rec-1905-org,arren,matthews,,coombe street,ballyboy,wahroonga,3617,nsw,19860121,8047381 +rec-2049-org,emma,webb,11,baracchi crescent,thornbrook,eight mile plains,3016,qld,19910314,5201994 +rec-1733-org,brianna,singleton,7,agonis close,,mulwala,2067,act,19510311,7420967 +rec-4599-org,james,,12,mewton place,ellwood,st georges basin,3073,vic,19250703,5362406 +rec-2739-org,kiarnee,gail,54,max henry crescent,gainsbury (cnr waldegrove r road,emerald,5162,nsw,19060223,5762709 +rec-3558-org,,papageorgiou,22,wisdom place,lazee m,smithfield plains,2350,nsw,19070623,4609745 +rec-4235-org,lachlan,swoboda,14,sue geh circuit,shadoof lodge,katherine,4740,nsw,19931215,1635174 +rec-1752-org,carmen,lombardi,6,quandong street,warialda,granville,5410,qld,19080313,1317582 +rec-3828-org,iain,berryman,95,singleton crescent,,verrierdale,3074,wa,19870626,1720109 +rec-3298-org,alessia,krajnc,30,fergusson crescent,kalga,shorewell park,5044,nsw,19421102,7927039 +rec-1699-org,kate,brock,12,kareelah vista,pine hill,yaroomba,4740,vic,19130707,2213154 +rec-2285-org,madeline,david,3,wagga street,bonnie doon,port broughton,3977,nsw,19451005,8930836 +rec-2749-org,,priest,41,marsden street,nioka,broken hill,2340,nsw,19060617,7169908 +rec-1219-org,kayla,ottens,5,mollison street,the mall springwood,rossmoyne,6285,act,19110325,1782013 +rec-1323-org,jack,steinert,61,french street,meadows estate,adamstown,4350,vic,19460712,3691990 +rec-3422-org,alyssa,kluske,17,woodgrove close,b,keiraville,4122,vic,19170822,4937438 +rec-3657-org,rachael,widdup,19,gurrang avenue,clanville,sale,2176,qld,19820620,6879955 +rec-1132-org,brianna,dixon,70,sidaway street,fm 226,linton,5097,qld,19780707,3396896 +rec-3581-org,ethan,hoover,151,monaro crescent,tiverton,yarra junction,2219,nsw,19920703,8513913 +rec-358-org,gabriel,estcourt,3,banks street,the mews royal hotel bldg,renown park,2541,nsw,19210501,3783783 +rec-2779-org,natalie,clarke,11,narryer close,holmeleigh,arana hills,3141,vic,19281031,8177483 +rec-2431-org,sienna,lock,5,outtrim avenue,seaforth senior citizens vlge,coopers shoot,4119,vic,19650410,3787467 +rec-4830-org,daniel,green,1,hartog street,retirement village,bonnyrigg,2749,vic,19900926,9765281 +rec-1231-org,,dent,4,chillagoe street,myliton,hamilton,7325,nsw,19270825,9350791 +rec-2848-org,taylor,mccarthy,9,templestowe avenue,yellowstone,seven hills,4133,qld,19540430,9919544 +rec-829-org,lucy,easling,97,mimosa close,the old parsonage,manyana,3016,,19810520,5467025 +rec-2769-org,caitlin,weller,39,fullerton crescent,villa 5,railton,4113,vic,19690725,1647081 +rec-31-org,laura,white,67,arndell street,riverbend,hoppers crossing,6053,vic,19900615,7517707 +rec-4359-org,clain,green,20,osborne place,lakewood estate,aldinga beach,6172,nsw,19210628,8724836 +rec-1578-org,maddison,goldsworthy,3,cavill close,killanoola,manly vale,2258,qld,19820307,6557335 +rec-852-org,annabella,byers,114,teece place,glenmarla rmb 2563,canley heights,4300,nsw,19630128,8053255 +rec-3679-org,tylah,senner,10,kenyon circuit,eagle view,taree,3192,qld,19900331,5063985 +rec-316-org,jordan,white,8,,,ryde,2148,vic,19890416,6617539 +rec-3705-org,grace,bastiaans,201,karrugang circuit,milbrodale,eldorado,2835,nsw,19930330,8575092 +rec-4223-org,gabriel,david,24,downward place,berkeley vlge,bossley park,2827,qld,19030305,7363149 +rec-4861-org,keahley,blake,51,gallagher street,belconnen animal hospital (cnr coulter d,south melbourne,2444,vic,19691015,2632188 +rec-4653-org,james,taslidza,47,galloway street,lazy acres,limeburners creek,2650,vic,19700312,9827257 +rec-3191-org,kyle,campbell,56,traeger street,bowen palms caravan park,beenleigh,3442,vic,19230828,5010535 +rec-1643-org,georgia,kouba,1,gay place,new chum,east launceston,4169,nsw,19840526,8748935 +rec-274-org,erin,clarke,96,teakle place,,granville,3040,wa,19170313,8285633 +rec-235-org,katelyn,campbell,11,ogden close,willandra village,preston,2148,tas,19291114,4043690 +rec-3898-org,ellie,green,17,brereton street,warrawong,hocking,4306,nsw,19080412,4034632 +rec-2048-org,georgia,vaccaro,18,leahy close,rocor,maribyrnong,3124,nsw,19381228,2725753 +rec-2994-org,edward,horstler,42,badimara street,carrington garden,clovelly,2086,qld,,3242408 +rec-4120-org,casey,flatman,3,wyselaskie circuit,,mentone,7250,vic,19931002,9564208 +rec-3146-org,georgia,lionis,137,fitchett street,summer hill,hillville,5520,vic,19060910,7770207 +rec-3607-org,zali,shadbolt,1,yass road,rowethorpe,cronulla,3911,vic,19771225,7247098 +rec-208-org,harriet,molland,43,,sheep station,bridgeman downs,6053,nsw,19760523,9418691 +rec-2392-org,marianne,adair,24,mcclelland avenue,colefield cvn park,warrandyte,2217,nsw,19910122,7356931 +rec-2173-org,taliah,campbell,418,bean crescent,warramby,hoppers crossing,4280,qld,19601111,3013090 +rec-3471-org,nicholas,donaldson,8,stobie place,heritage manor est,newcomb,4104,sa,19051119,3361470 +rec-2138-org,daniel,dreckow,39,govett place,gogulger stock,preston,6210,vic,19510111,3162776 +rec-4358-org,alexandra,stearnes,201,hackett garden,redfern station,seaforth,4154,qld,19440928,7272157 +rec-3244-org,alexander,george,11,eaglemont retreat,tarqua,dapto,3087,vic,19970108,7688076 +rec-3338-org,jason,tebbutt,92,stradbroke street,kildurham,winthrop,6213,act,19750627,1072661 +rec-947-org,christina,coleman,8,woronora street,suffolk downs,carnegie,4151,qld,19880122,6395380 +rec-1806-org,madison,cowle,14,port jackson circuit,marriott downs,new mollyan,4215,sa,19280625,9403686 +rec-2375-org,taliah,armanini,23,lind close,telebang station,matraville,4021,vic,19210204,4931434 +rec-3271-org,daniel,denning,1498,galloway street,villa 2,yarrawonga,2194,vic,19810501,5572094 +rec-1173-org,amy,white,27,doyle terrace,tantallon,duncraig,3810,nsw,19340217,3650503 +rec-3120-org,adam,dallas,79,copland drive,,rye,4034,vic,19170316,9230368 +rec-2198-org,matilda,bergsma,73,macrobertson street,derry lodge,greensborough,2076,wa,19880213,5520743 +rec-1264-org,emiily,george,17,ebenezer street,bayview caravn park,swan hill,3178,qld,19710827,7813722 +rec-721-org,jack,blake,12,angophora street,rowethorpe,ascot,2390,vic,19001116,9895808 +rec-4640-org,,berry,276,victoria street,coorabil,bayswater,3166,nsw,19250620,3866668 +rec-4839-org,alexandra,craske,31,woodger place,tinaroo falls,pannawonica,2650,wa,19850302,2175226 +rec-1928-org,kyle,hawes,6,len waters street,castlewood,greensborough,3171,nsw,19090430,5553221 +rec-2180-org,max,white,220,braund place,aprt 59,ferndale,3337,qld,19110220,5718630 +rec-4858-org,joshua,quinzi,15,bagster place,arabian stud kelkette park,miami,4670,vic,19330808,4918400 +rec-4668-org,elton,coldicutt,3,somerset street,newman medical centre,ashfield,5073,vic,19341016,9721944 +rec-2291-org,kyle,kalogerakos,,aird place,cassia,granville,4680,wa,19950119,4748391 +rec-765-org,harriet,tamassy,378,academy close,doribank,wunghnu,2680,wa,19350531,3455124 +rec-3203-org,isabella,bowerman,22,aspinall street,campaspe,northbridge,2913,nsw,,5138593 +rec-2642-org,mitchell,mason,47,edkins street,lochadair,north ryde,3355,nsw,19390212,8859999 +rec-4432-org,isabella,salt,1,kingsmill street,town & country caravn park,wyee,2516,wa,19850103,8443768 +rec-2784-org,tiffany,van der hoek,4,holt place,learmont,kirribilli,0810,sa,19980630,3179832 +rec-1765-org,,webb,,mclachlan street,anukana,eastwood,2112,vic,19170509,8331654 +rec-3931-org,bailee,spark,158,givens street,kilacloran,maryborough,4220,tas,19980206,7934147 +rec-2119-org,oakleigh,shepherd,106,rosewood place,allanvale,dalby,2259,vic,19480913,9643705 +rec-2354-org,connor,shepherd,7,bulloo place,,kangaroo flat,4621,wa,19681115,1737778 +rec-4560-org,natalee,berryman,42,gurney place,morningsite,jamberoo,4055,wa,19790815,9012138 +rec-4597-org,olivia,trent,10,manity court,,campbelltown,6220,nsw,19740731,4392378 +rec-4479-org,nicholas,humphreys,7,forbes street,peak view,north ryde,2131,sa,19460529,9271718 +rec-2607-org,thomas,leong,124,,tilburoo,wantirna,3064,qld,19670430,2292707 +rec-2696-org,campbell,nguyen,6,diselma place,villa 2,collinswood,4343,nsw,19630325,2861961 +rec-895-org,kane,nguyen,47,ranken place,gumnut cottage,dapto,5107,qld,19850120,9212538 +rec-2794-org,april,webb,25,anketell street,sec 437,millmerran,2226,vic,19060125,3661897 +rec-2388-org,joshua,millar,1,bandulla street,sherwood,forcett,3463,tas,19580204,7520191 +rec-435-org,harry,wilde,55,blythe close,marsden,ballarat north,3058,nsw,19270322,8514644 +rec-3799-org,alana,lombardi,6,mandurah place,tantallon,canterbury,4034,wa,19021123,5203409 +rec-3105-org,jacqueline,webb,8,kitchener street,herbert river,batlow,3019,vic,19370226,5963832 +rec-3982-org,grace,seib,24,landsborough street,rainbow downs,como,2641,vic,19760603,8191813 +rec-3546-org,oliver,tiede,248,scrivener street,kendle green,mentone,6280,nsw,19101129,3891450 +rec-3663-org,caitlin,hervey,40,woolner circuit,vermont ret estate,parap,2440,nsw,19331205,2155379 +rec-4871-org,casey,croker,137,summerville crescent,shalestone,wanniassa,2602,sa,19471226,3095657 +rec-1846-org,hana,gianakis,6,madigan street,weowner,mooloolaba,3101,qld,19950522,9028103 +rec-2434-org,,ebert,96,rapanea street,pangani,,6061,nsw,19310909,9105802 +rec-3527-org,barnaby,westbrook,221,hadleigh circuit,the lakes retirement village,petersham,4118,qld,19440405,2487468 +rec-3763-org,clodagh,tromp,7,boustead circuit,lochenfels,greenacre,2770,nsw,19870808,7950786 +rec-3001-org,joel,badger,75,blamey crescent,brookfields,broadford,4807,qld,19791106,2164581 +rec-1205-org,holly,white,28,martens crescent,oliwen,aspley,3977,vic,19281113,6507633 +rec-2876-org,,green,13,spowers circuit,brookfield,labrador,5063,nsw,19421213,8321036 +rec-1073-org,jack,stanbury,25,de vis place,kersley mews,koorawatha,4074,qld,19381113,7301101 +rec-825-org,mia,white,6,national circuit,sec 301,narembeen,2765,nsw,19130418,5053650 +rec-4014-org,felicity,white,24,carter crescent,mirreanda,geelong south,3892,sa,19480806,9575304 +rec-2936-org,harrison,tinfina,5,deasland place,toolebewong farm,southbank,2217,nsw,19880108,4659883 +rec-1727-org,reeve,noble,7,finlayson place,nordale farm,bellevue hill,4032,wa,19080324,7109523 +rec-2715-org,lewis,green,256,hickenbotham street,tryphinia view,newlands arm,3055,nsw,19530919,8012486 +rec-3542-org,erin,lovelock,22,druitt place,on river,dorrigo,4118,vic,19680706,8834319 +rec-1340-org,spencer,klus,7,gatton street,whispering pines,young,5097,vic,19020122,4996874 +rec-3760-org,keaton,stanley,9,ern florence crescent,deergarden caravn park,daisy hill,2835,qld,19750130,6553331 +rec-3073-org,catherine,bartel,9,tyson street,rosedale,concord,2650,vic,19080828,9115067 +rec-4254-org,marleigh,verner,150,macquarie street,jarroo,murrumbateman,3150,nsw,19500227,8469038 +rec-4052-org,saskia,roberti,2070,wiburd street,dodonaea wing,rose bay,4078,vic,19691123,5721375 +rec-874-org,nicholas,desantis,114,badcoe street,union collage,elermore vale,3420,nsw,19740601,4864589 +rec-329-org,robert,wilczek,60,sugarloaf circuit,eldwick,thirroul,2325,nsw,19630615,5960552 +rec-2303-org,tahlia,hage,3,maclaurin crescent,,ormond,4740,tas,19190517,6174860 +rec-1607-org,sarah,lanyon,48,torrens street,boxwood hill,reynella,2217,tas,19220722,6534862 +rec-1603-org,caitlin,procter,364,mauldon street,finis river,blacktown,2261,qld,19261215,3136685 +rec-1522-org,jarred,belperio,64,glenmaggie street,rowethorpe,mitcham,3155,nsw,19190621,4585747 +rec-354-org,lily,wastell,2,clare dennis avenue,glen arthur,marsden,2118,sa,19720903,2526870 +rec-2209-org,georgia,hantke,215,hovea street,,cromer,3199,vic,19260708,1055098 +rec-50-org,emerson,reid,5,kater place,forest views,acacia ridge,4215,nt,19820814,2582300 +rec-4759-org,makayla,herbert,5,plummer street,tarwyn park,hopetoun,3925,vic,19111103,1756031 +rec-263-org,john,ryan,19,chuculba crescent,redfern station,cowra,4065,vic,19840524,2056918 +rec-1298-org,taliah,ryan,45,hopetoun circuit,the willows,shorewell park,3805,vic,19950105,3100732 +rec-580-org,natalia,mccarthy,10,vogelsang place,albion heights,blair athol,6018,act,19841123,4528680 +rec-1403-org,zac,bellchambers,5,michael holt crescent,duck creek,kemblawarra,6104,nsw,19870104,4503098 +rec-2313-org,reece,marsom,1,paul coe crescent,catumbel lodge,highett,3081,qld,19351129,4804920 +rec-2156-org,brooke,broadby,13,smith street,golden ponds resort,petrie,4070,qld,19101119,1067112 +rec-2289-org,alessandra,thorpe,33,crowder circuit,melrose farm,karalee,7250,qld,19080406,8221563 +rec-3582-org,michaela,rickett,,sorlie place,terra nostra,robina,5157,nsw,19920309,4827369 +rec-441-org,william,edson,,fitzhardinge crescent,windy gully,ashwood,3078,nsw,19530403,3148460 +rec-3682-org,rupert,drzezdzon,11,magennis place,sec 161,ashford,6100,vic,19000219,4126935 +rec-4801-org,adam,cordingley,50,chandler street,kenbar,duncraig,3915,vic,19000322,2892892 +rec-3700-org,steven,pokkias,407,may maxwell crescent,ardonachie,dalveen,5064,wa,19350305,2928326 +rec-3392-org,montana,delrue,12,herington street,st vincents medical centre,allora,2010,nsw,19591003,4382424 +rec-2658-org,noah,rosato,25,la perouse street,cowal,east maitland,7140,wa,19160718,6064519 +rec-3899-org,noah,berry,8,alice jackson crescent,rosehill,hawthorn,5251,sa,19240908,1446426 +rec-3333-org,cooper,fitzpatrick,94,owen dixon drive,,collie,2525,nsw,19870622,1736085 +rec-849-org,matthew,ploughman,,severne crescent,goodhope,raby,2541,wa,19900710,4917759 +rec-733-org,shelby,garforth,,madigan street,st francis village,nannup,4506,vic,19060707,5601065 +rec-4121-org,jaykob,smeaton,246,stuart street,,ardeer,6112,qld,19120411,5014834 +rec-2137-org,schkirra,ryan,1,dumas street,baringa orthopaedic centre,frankston,3028,vic,19520108,1566350 +rec-3560-org,tai,matthews,161,norman fisher circuit,home vlge,bracknell,2258,qld,19120506,7535799 +rec-253-org,samantha,kerslake,14,howard street,the meadows,keiraville,6167,nsw,19690926,7977658 +rec-4403-org,harriet,paterson,5,smiths road,jaybees,ringwood east,6012,nsw,19321027,3012880 +rec-1637-org,kierra,ninchich,57,mehaffey crescent,old farm,northmead,3028,wa,19530926,2089030 +rec-4645-org,xanthe,fullgrabe,7,learmonth drive,,toowoomba,3803,vic,19841012,7525802 +rec-4639-org,jamilla,mcdaid,29,barrett street,kingston tower,lalor,3166,qld,19301116,2784587 +rec-1692-org,emiily,finlay,13,lawrence close,upton,boddington,2485,nsw,19800129,5998213 +rec-4504-org,jasmine,camens,7,plowman place,,tennant creek,2088,vic,19020413,9907745 +rec-4499-org,alissa,byers,6,beasley street,,coffs harbour,6009,sa,19550131,2851382 +rec-3990-org,makayla,matthews,42,cullen street,st francis room,oakleigh,3233,nsw,19061006,7914405 +rec-2805-org,elle,royle,40,maribyrnong avenue,stapleton station,port lincoln,4220,nsw,19430114,8517219 +rec-1576-org,luke,dinh,80,rischbieth crescent,rooganore,spearwood,4053,vic,19120208,7700965 +rec-295-org,ash,munyarryun,6,lachlan street,,braddon,2641,nsw,19421130,7370167 +rec-2255-org,benjamin,green,11,marou place,city centre plaza,clear mountain,5115,nsw,19810305,8410885 +rec-3374-org,rachel,matthews,359,lambrigg street,main beach medical centre,burpengary,4209,qld,19290411,8890950 +rec-4705-org,peter,fawkner,57,abernethy street,never die,wallan,5086,nsw,19820527,8301293 +rec-2449-org,jarrod,green,60,forbes street,ryhd-talog,port macquarie,3013,vic,19600324,5445613 +rec-4136-org,,vincent,47,kent street,blue hills,forest hill,4655,vic,19190304,5807175 +rec-3304-org,adam,pichugin,16,tiwi place,ettrick,yackandandah,3116,qld,19650328,1748977 +rec-1941-org,jack,campbell,282,osburn drive,white patch,carrara,6030,vic,19881003,2172403 +rec-1930-org,,teague,38,emily bulcock crescent,locn 341,caulfield,2041,nsw,19900523,1754920 +rec-222-org,adele,shorrock,116,mack street,manor park,connolly,3149,nsw,19080107,1788372 +rec-1101-org,ruby,webb,63,decker place,docker river community,morphettville,2420,nsw,19690619,9196315 +rec-2899-org,elli,trowse,3,bellingham crescent,villa 3,islington,2560,vic,19220705,1676559 +rec-1482-org,tara,green,25,chisholm street,lashbrooke,boyne island,3073,nsw,19860505,1388911 +rec-862-org,riley,green,20,riordan street,tillside,burwood,3199,vic,19531216,5368190 +rec-3863-org,jack,dancey,174,wells garden,,taree,2216,vic,19311206,1490674 +rec-1991-org,fergus,clarke,14,o'rourke street,bobblegigbie,casula,2213,vic,19380302,1449123 +rec-330-org,helena,haskett,5,namadgi circuit,ryanfield,berowra heights,7307,qld,19560926,3772585 +rec-223-org,ky,kyriacou,30,ash place,kiloran,paddington,2665,nsw,19350528,5592621 +rec-2249-org,emiily,miels,3,dartnell street,murrawarra,woodgate,7310,tas,19280417,6959390 +rec-2888-org,michael,headon,6,buvelot street,erins rest,para hills,4670,nsw,19400211,3673837 +rec-1289-org,lily,green,105,hawker place,chippendale village,currambine,3016,nsw,19660530,5752105 +rec-3586-org,karla,adair,56,launceston street,aprt 504,clarkson,2032,nsw,19860315,1526150 +rec-1698-org,joshua,choi-lundberg,31,vest place,tulloch,leslie vale,7000,qld,19380903,1002096 +rec-2564-org,pino,shepherd,55,warragamba avenue,pineview farm,sale,5608,vic,19100226,5952587 +rec-2383-org,thomas,carmody,7,waugh close,kona,elwood,2066,vic,19540605,5434473 +rec-3047-org,emiily,lowe,80,investigator street,mirilla,hopetoun,3377,vic,19420731,2555272 +rec-375-org,elise,miles,63,oliver street,rosetta village,byford,4670,nsw,19930514,1613758 +rec-518-org,jack,wegman,9,julia flynn avenue,myross,armidale,2444,qld,19710718,3680861 +rec-3732-org,harry,singleton,57,mackenzie street,terranora,currambine,2502,nsw,19170130,1412842 +rec-244-org,tayla,matthews,89,may maxwell crescent,the willows,ascot vale,3810,nsw,19021201,3861456 +rec-3945-org,ellie,reid,35,nemarang crescent,brandywine stud,jarra creek,4051,wa,19090612,3825290 +rec-730-org,matthew,etheridge,6,louis loder street,woodcrest,frenchs forest,3015,vic,19950128,5585524 +rec-3045-org,taliah,carmody,37,carstensz street,frank jeffrey hostel,blakeview,3094,vic,19940123,8622255 +rec-4252-org,stephanie,tiller,281,mcleod place,villa 19,katherine,2680,vic,19690208,7432991 +rec-164-org,ruby,jesser,37,boult place,catumbel lodge,broadbeach waters,6230,nsw,19680506,3452449 +rec-2116-org,mitchell,green,165,meldrum street,hd talunga,eastwood,3490,nsw,19800917,8965691 +rec-3631-org,taylah,berry,56,corbin place,honey patch,brighton-le-sands,3041,vic,19650831,7786757 +rec-2274-org,luke,wilkins,22,ironbark crescent,,heckenberg,2390,nsw,19360325,2755084 +rec-1539-org,joshua,green,,inlander crescent,,rupanyup north,5353,nsw,19390804,5849743 +rec-3355-org,lily,marris,28,deumonga court,fourways,ulverstone,3048,nsw,19980524,4654900 +rec-2699-org,angie,wimmer,36,baracchi crescent,mawarra herefords,marsden,2406,sa,19700928,3795146 +rec-3101-org,jacqueline,fehrmann,3,eungella street,penquite road,marayong,3193,wa,19651021,6612185 +rec-3455-org,matthew,frew,23,bindel street,ascot park,bunbury,2234,qld,19330523,2214288 +rec-11-org,jake,fawkner,,wolff crescent,,proserpine,4011,vic,19500506,3844004 +rec-916-org,tiana,white,20,tazewell circuit,ningana retirement,toorak,2250,vic,19460218,7461693 +rec-4962-org,ruby,acciairresa,4,broad place,rowan lodge,wamberal,3431,nsw,19250609,7388992 +rec-1581-org,nathan,dunstone,10,shirlow place,poldoe park,blacktown,3820,nsw,19001013,1854047 +rec-2539-org,emiily,stearnes,34,hugh mckay crescent,honey patch,ettalong,2250,sa,19040826,7188856 +rec-396-org,nell,campbell,4,stroud place,st pauls court,lindfield,6011,vic,19170614,5659846 +rec-1884-org,hannah,egan,9,elvire place,the iron farm,parkside,3042,nsw,19380131,6564365 +rec-1360-org,charlotte,clarke,9,captain cook crescent,nara cottage,yarraville,2099,sa,19470305,9614637 +rec-2245-org,chelsie,goldsworthy,21,woronora street,alanvale,south wentworthville,4216,nsw,19500313,5547857 +rec-109-org,daniel,fysh,27,appel crescent,wildes mdw,hermit park,2333,nsw,19620207,8595168 +rec-2954-org,noah,wiseman,17,wakefield garden,kareela,frenchs forest,6535,nsw,19640101,8735485 +rec-1790-org,bailey,heuer,65,fossey street,brindabella specialist centre,vaucluse,2010,qld,19511013,9539538 +rec-4704-org,keziah,lavender,11,rankin street,,hazelgrove,2088,vic,19780813,6420551 +rec-4538-org,angelina,ryan,1,andrews street,glenmore,bowning,2221,nsw,19460915,3778166 +rec-3447-org,caleb,rauseo,1,mcshane place,lockwood,sanctuary point,3044,nsw,19440927,3969191 +rec-3870-org,benjamin,harrington,4,mackenzie street,cascina,morpeth,6012,qld,19130302,6966636 +rec-1848-org,logan,dzino,46,marungal avenue,medical centre,mount victoria,2075,nsw,19841102,5947755 +rec-2957-org,bradley,shepherd,71,kilgour place,gull cottage,smithfield,4078,act,19160301,1369189 +rec-922-org,samantha,stanley,16,jay place,knackery rhs,kingston,6330,vic,19951027,2725144 +rec-551-org,ridley,blake,142,forbes street,white lodge,mill park,3133,sa,19990618,1662040 +rec-1258-org,jock,clarke,8,heritage road,rocklea,manly vale,2540,vic,19000505,8245647 +rec-2643-org,jayde,eneberg,44,donohoe place,professional centre,kahibah,6163,nsw,19750318,5568018 +rec-1983-org,henry,coleman,42,mackaness place,lake downs super fine merino stud,benowa,4557,tas,19791029,1714953 +rec-4525-org,hayley,bloomfield,58,jondol place,pine hill,plumpton,5725,qld,19310515,2689302 +rec-1266-org,emiily,walkley,4,barangaroo street,meadowvale village,padstow,7030,wa,19190615,2871929 +rec-3452-org,brooke,rees,381,temperley street,polynesian village,mosman,2100,qld,19630314,3610323 +rec-4946-org,samuel,lvarga,64,postle circuit,abbey green,rokeby,2199,vic,19641231,4801979 +rec-1533-org,sophie,elderton,1,theodore street,seabank,salisbury,6026,nsw,19320402,6259234 +rec-4265-org,jasmine,hope,32,jaques place,specialist centre,geraldton,2611,vic,19380418,2006619 +rec-2058-org,kody,nguyen,2271,cromwell circuit,edellen,braddon,2204,nsw,19610602,6452495 +rec-1272-org,pearson,reid,19,hodgkinson street,marebone,woodcroft,4815,nsw,19101109,1582056 +rec-1455-org,chloe,bastiaans,49,sturdee crescent,rowethorpe,toowoomba,2232,vic,19470305,1208800 +rec-4376-org,thomas,drougas,29,collins place,moonylora,oakville,2560,qld,19670112,8993502 +rec-4285-org,sophie,manson,14,elizabeth crescent,manor house,gorokan,3465,vic,19510201,4818868 +rec-1542-org,kira,mac an,5,groom place,doctors flat,wategos beach,4207,vic,19341108,7247594 +rec-2649-org,bethanie,nguyen,23,morrissey street,navillus,st ives,4214,vic,19400724,7869955 +rec-4032-org,samantha,santi,14,griffiths street,rowethorpe,mckinnon,6163,nsw,19151129,2102559 +rec-3159-org,lewis,mercovich,5,jensen street,zeevoo,cooroy,2251,wa,19071128,8628720 +rec-1422-org,phillip,nguyen,83,clark place,wollongbar,st kilda,3808,nsw,19351123,9799704 +rec-185-org,maxin,burford,190,dixon drive,ingledell,aspley,2090,nsw,19030325,6228407 +rec-596-org,lawson,doody,4,learmonth drive,the lakes retirement village,altona north,2749,sa,19820126,4998687 +rec-1720-org,,haak,54,parr place,ulah,burpengary,6010,wa,19170712,3239785 +rec-1571-org,alicia,clarke,72,fitchett street,rowethorpe,whalan,2643,nsw,19811201,4620985 +rec-2747-org,joshua,crosswell,49,batchelor street,kurrajong,mirboo north,2259,sa,19161010,9285169 +rec-4154-org,joel,nalpantidis,1,paul coe crescent,rp 24089,baskerville,6230,vic,19501117,3815548 +rec-1838-org,thomas,rielly,257,norman fisher circuit,cressbrook,valley view,4211,nsw,19720118,6802659 +rec-770-org,samara,,2,lewis luxton avenue,,pooraka,2778,act,19170725,9740765 +rec-3477-org,jake,doody,193,frew close,howie circuit,darlington,3875,vic,19370321,1546559 +rec-1898-org,william,croker,42,belmore garden,norellen,stephens,4207,qld,19190108,9397232 +rec-767-org,jade,markakis,123,la perouse street,brentwood vlge,ascot,3121,qld,19020516,8651304 +rec-4262-org,ellen,nguyen,36,burdon place,hillendale,semaphore park,4216,nsw,19701020,8122850 +rec-408-org,charles,rees,19,hobby place,locn 2557 talland,orange,6210,vic,19710428,6849799 +rec-3460-org,blake,ryan,7,faithfull circuit,tryphinia view,ringwood,3781,wa,19900531,1192663 +rec-53-org,molly,parr,52,jerrabomberra avenue,villa 80,mayfield,2082,nsw,19500910,7961724 +rec-2842-org,james,hefford,59,tuckett place,,west wollongong,2228,nsw,19591227,4834804 +rec-2405-org,makenzi,white,12,bimberi crescent,,seymour,2061,wa,19350712,6816535 +rec-4540-org,hugo,dichiera,19,gallagher street,glenmore,byford,4053,qld,19510703,1403854 +rec-2186-org,joshua,londrigan,15,mayo street,pacific haven,wendouree,2505,sa,19450424,4184958 +rec-2788-org,lachlan,carbone,194,burdekin street,glenlee,glen innes,6525,wa,19070409,2229631 +rec-3840-org,finn,baradakis,13,launceston street,ferndale,coolbellup,2323,qld,19281212,1281405 +rec-2007-org,daniel,toms,5,mcclelland avenue,springbanks,kendall,2030,vic,19760921,3896174 +rec-630-org,david,pestka,95,tadgell place,belgrave,abbotsford,4717,nsw,19980517,5698675 +rec-1321-org,tyler,painter,74,michael holt crescent,three rivers tourist park,kangaroo flat,4858,nsw,19291017,6615450 +rec-2946-org,tayla,vandelaar,38,boehm close,florina park,port macquarie,2077,vic,19210928,6944524 +rec-1348-org,benjamin,kerslake,6,mcdonnell close,bethany,chester hill,2199,nsw,19571214,3250168 +rec-2871-org,noah,fusco,65,kruse place,the points holsteins,kununurra,3400,nsw,19490107,9136935 +rec-633-org,brooke,lock,5,godfrey street,noosa village shopping centre,goonellabah,2446,qld,19201008,1614256 +rec-4879-org,rebecca,clutterbuck,,blair street,apt 2005,proserpine,4701,nsw,19350120,3520636 +rec-2413-org,indyana,clarke,111,fisher street,mountain view village,wetherill park,4211,vic,19170704,3405046 +rec-3563-org,lachlan,clayden,4,atkinson street,parklands village,buninyong,2765,qld,19330705,7427334 +rec-3909-org,ruby,vincent,1,gawler crescent,knmre street,penshurst,3585,nsw,19700602,6532162 +rec-2821-org,toby,grosser,52,moulden court,burnie thompson park,ulverstone,6258,nsw,19141208,6723789 +rec-4383-org,ryley,dods,24,helemon street,john curtin hostel,villawood,6061,nsw,19350808,9316786 +rec-739-org,neve,neighan,41,berkeley street,wychwood,premer,2203,sa,19381128,3927665 +rec-2563-org,olivia,moody,10,mimosa close,bowillia court,hahndorf,7316,nsw,19620505,4040256 +rec-1909-org,kayla,braithwaite,19,forwood street,braemar vlge,chewton,2261,nsw,19640906,6775714 +rec-4722-org,catherine,bishop,29,stapylton street,chain gate,box hill south,2260,vic,19410527,6228462 +rec-45-org,adam,coleman,14,ewart street,camrai village,springfield,2795,nsw,19491108,6543835 +rec-1974-org,natasha,clarke,63,tasmania circle,mallanganee,whitemore,2840,sa,19710223,5969104 +rec-1085-org,daniel,commons,33,nungara street,glenhurst,chester hill,4740,wa,19350922,1606130 +rec-2521-org,bailey,ryan,94,parker street,environa,nowra,6042,vic,19361224,2466735 +rec-1970-org,jack,robson,33,girdlestone circuit,granny flt,ringwood,2217,nsw,19770311,6427137 +rec-2188-org,ella,eglinton,30,alexander mackie circuit,treetops,frankston,2450,nsw,19630129,1794441 +rec-4442-org,kadin,crosswell,2,telopea park,karobean,leongatha south,2070,vic,19410715,4079644 +rec-4184-org,isabella,campbell,20,balsillie crescent,glen mia,loganlea,3806,wa,19280823,1041041 +rec-1098-org,jacob,bradshaw,30,tipiloura street,lansdowne,burringbar,2262,nsw,19380406,1735204 +rec-395-org,casey,white,27,dolling crescent,sundowner centre,springwood,2444,wa,19481024,8939482 +rec-4985-org,alissa,ryan,519,boobialla street,urimbirra,seaforth,6018,nsw,19990829,1669952 +rec-509-org,benjamin,green,12,woolner circuit,mirani,reynella,2905,sa,19651021,8195933 +rec-1095-org,tiarna,croker,3,roope close,westport,preston west,3318,,19460426,9509846 +rec-909-org,ella,chudzinski,7,carter crescent,alice downs,caulfield,7008,qld,19321101,4473731 +rec-3906-org,jacob,sporton,28,kosciusko avenue,,ringwood,2466,vic,19300816,1934981 +rec-3348-org,blake,miles,174,traeger street,cabrini medical centre,port noarlunga south,3130,nsw,19811230,6803144 +rec-3794-org,leah,hilton,38,birdwood street,lucky corner,mitcham,3169,nsw,19380702,9968264 +rec-3532-org,samuel,tunstall,22,wattle street,bayana,fish creek,7216,wa,19840412,8429651 +rec-549-org,chloe,vincent,196,miller street,rosehill,wallsend,2745,wa,19140726,4286524 +rec-1135-org,dylan,oatey,,barringer street,thurlimbah,avalon,2217,vic,19441106,7915328 +rec-3838-org,koula,haggett,18,hugh mckay crescent,woodleigh,lilydale,3028,vic,19000625,3064629 +rec-3872-org,hannah,slape,20,french street,beulah estate,warrandyte,3065,qld,19800920,1061185 +rec-550-org,indiana,wasley,70,alabaster street,glenavon,kilcunda,6530,qld,19380728,8716390 +rec-2100-org,talia,millar,8,la perouse street,macsview,kellyville,2250,wa,19800606,3894135 +rec-4042-org,steven,pwa,39,weatherburn place,,malvern,7315,qld,19620819,1623496 +rec-4660-org,georgia,clarke,278,blowering street,dunfield park,port pirie,6111,vic,19990330,3328605 +rec-529-org,maddison,goodacre,19,de graaff street,hd tiparra sec 333,casino,5024,wa,19470901,7906113 +rec-4909-org,harrison,reid,20,charterisville avenue,lissoy holdings,lowesdale,2282,qld,19301018,9267290 +rec-2534-org,michelle,morrison,70,nunan crescent,retirement village,coolaroo,3754,tas,19580308,2642188 +rec-680-org,jacqueline,abbondandola,24,myers place,ingledell,seelands,2560,tas,19590617,7256635 +rec-4549-org,mitchell,stanley,3,palmer street,tesbury,lake heights,2430,vic,19250116,7447942 +rec-3660-org,reuben,corera,14,menkens court,creswick,campbelltown,4218,qld,19900512,1415502 +rec-3063-org,kynan,beattie,9,narrabundah lane,banana shed,ferndale,2680,nsw,19170712,4383141 +rec-1769-org,anari,pettigrove,9,betche place,b,gwandalan,3165,nsw,19890618,1209547 +rec-1161-org,hannah,coleman,3,marchant circuit,southlands shpcntr,hinchinbrook,2754,vic,19270425,7785677 +rec-1431-org,judah,badger,10,darby street,taskers village,yangebup,6030,tas,19530826,3374540 +rec-856-org,mitchell,gohl,165,must circuit,dorothy genders vlge,bundaberg north,4130,vic,19410517,2812221 +rec-400-org,emiily,paine,26,bussell crescent,koyo,karratha,3977,vic,19750805,7519967 +rec-4167-org,zarlia,gearman,2,quiros street,naranda,arana hills,2250,sa,19101225,4751144 +rec-885-org,harley,coleman,4,pridham street,merrydale,broome,2528,wa,19670119,3924037 +rec-1094-org,timara,campbell,12,mowle place,ruffenuff,paralowie,2141,qld,19820408,1798782 +rec-3788-org,willow,bennier,235,shackleton circuit,lakeview park,dianella,2340,qld,19030228,2251111 +rec-340-org,ella,rawlings,55,henty street,don ray,moruya,4870,vic,19810122,9723395 +rec-4158-org,matthew,nguyen,273,hugh mckay crescent,katherine low leve,,4560,act,19320414,5765039 +rec-4435-org,isabella,dolby,16,hodgson crescent,break-o-day,daw park,4304,qld,19030725,7732123 +rec-186-org,georgia,campbell,22,kalgoorlie crescent,rowethorpe,sherwood,3134,nsw,19730322,6197687 +rec-4511-org,levi,oaks,38,courtice close,sunshine farm,findon,6050,wa,19101128,9317947 +rec-2834-org,jasmine,leditschke,195,manna close,killarney,baynton,7009,vic,19340207,7978445 +rec-2251-org,joshua,crouch,94,forbes street,westerdale,johnsonville,2327,sa,19700216,4813329 +rec-3068-org,jye,berry,303,chirnside circuit,wildefell,benowa,4021,,19891213,3022720 +rec-4876-org,jade,collinson,58,temperley street,diablo,craigmore,6722,wa,19660421,7496155 +rec-2683-org,oliver,dent,169,noble place,bellambi,strathalbyn,3088,sa,19051006,4438825 +rec-3-org,reeve,stanley,4,alawa street,rowethorpe d1,mourilyan,2474,sa,19190811,5961670 +rec-212-org,irene,morrison,16,maitland street,the mall,burleigh heads,4077,vic,19650804,9676215 +rec-1154-org,gracie,crook,399,macalister crescent,grant patch,east preston,4108,nsw,19360323,1096576 +rec-1917-org,jasper,flockhart,25,,briardale,modbury,4035,vic,19211017,2278318 +rec-4718-org,tara,hem,3,birnie place,strathlea,burwood,6330,nsw,19080318,6896187 +rec-1197-org,deakin,peachey,16,officer crescent,tesbury,nollamara,2144,tas,19690824,8507376 +rec-1557-org,ben,grubb,9,girrahween street,loma,brunswick west,3182,nsw,19551105,6198116 +rec-1103-org,,grierson,326,,sect 106,mcmahons point,6326,tas,19181212,4107638 +rec-4030-org,eloise,cherini,9,northmore crescent,skerman chambers,joondanna,3350,vic,19220725,8822107 +rec-4929-org,lachlan,green,53,golden grove,jodayne,armidale,3058,vic,,4526867 +rec-623-org,jacqueline,ferris,107,kriewaldt circuit,dunmoven,mirrabooka,3195,vic,19250708,6320610 +rec-601-org,ella,carbone,38,owen dixon drive,ponderosa,port augusta,2615,vic,19860209,7971615 +rec-1906-org,nicholas,green,14,hodgson crescent,barwon station,mosman,2600,qld,19850327,5859130 +rec-937-org,oliver,netteefold,35,alphard place,fairlight,semaphore park,3802,vic,19570625,4691024 +rec-144-org,olivia,white,2,sturt avenue,berkeley vlge,ringwood,5016,wa,19941026,7159814 +rec-2210-org,mitchell,birkin,4,birdwood street,anglican church,bonville,3214,qld,19810614,4271401 +rec-3947-org,mitchell,trowse,22,boolee street,john flynn medical centre,malvern,4350,qld,19640225,4579159 +rec-464-org,amy,britten,4,whiteside court,gumnut cottage,kirwan,2330,nsw,,2001865 +rec-1564-org,madison,green,67,atherton street,moorilla,bondi junction,2480,wa,19920222,1194102 +rec-2440-org,amy,green,8,cahalan place,iron shoe lodge,east preston,2114,qld,19900401,2287496 +rec-2009-org,george,meaney,164,elder street,jingara,st albans,4060,vic,19320703,9691332 +rec-1404-org,reuben,clarke,22,rischbieth crescent,ocean pines caravn park,blakehurst,2340,nsw,19391117,3232193 +rec-1472-org,jock,wilde,8,laidley place,halfmoon station,burnett heads,4702,nsw,19001220,4981468 +rec-3021-org,kayla,campbell,12,cockle street,talooby,robina,2650,qld,19590917,5648700 +rec-723-org,madeleine,clarke,11,levien street,edith hall,samford,2074,qld,19801221,5699901 +rec-2561-org,lexie,myles,11,crozier circuit,kangaroo grnd,valentine,3805,sa,19600609,9749283 +rec-1654-org,eliza,campbell,10,arnold place,,raby,6148,tas,19860203,8112754 +rec-2278-org,imogen,bishop,10,badimara street,rockvale road,mount eliza,2606,qld,19460109,9681787 +rec-2420-org,josephine,mahon,99,service street,clarkwood,arana hills,2580,nsw,19131111,4786683 +rec-402-org,hugo,sporn,150,clive steele avenue,kurrajong,peechelba,5212,qld,19420523,8443463 +rec-4589-org,lily,mccaffrey,166,john cleland crescent,kirkdale,port pirie,4870,vic,19260727,8711730 +rec-2562-org,katie,binns,50,,carranya,roleystone,3216,qld,19031119,1179767 +rec-4112-org,lachlan,bottroff,92,,quandialla,bronte,4670,nsw,19641111,4134354 +rec-1852-org,kaitlyn,nurse,1,hampton circuit,,gawler east,5091,tas,19340420,4801263 +rec-4761-org,matthew,dibble,58,candlebark close,mt callan,acacia ridge,5253,vic,19341010,2053693 +rec-3358-org,cooper,hyland,34,namadgi circuit,ferndale,newcastle,2566,nsw,19621205,8131556 +rec-3986-org,sophie,joaquim,35,warring place,lvel 2180,lindfield,3151,qld,19320118,4865826 +rec-4391-org,felicity,,246,edmondson street,rowethorpe,clareville,4165,nsw,19380928,5994744 +rec-4268-org,riley,campbell,12,mulleun close,channel,oakey,2615,qld,19090824,2750463 +rec-1969-org,cassidy,campbell,623,luffman crescent,cherrybank,sussex inlet,3165,vic,19160322,6984823 +rec-4444-org,alexandra,hide,27,tweddle place,barley hill,williamstown,3055,vic,19070929,3625008 +rec-310-org,amber,white,40,bateman street,lakewood estate,dungog,3207,qld,19671129,7353997 +rec-1478-org,ellen,campbell,24,giles street,avalyn,wendouree,5048,nsw,19560304,7223186 +rec-2807-org,,bradshaw,9,dallachy place,coral house even tide,ryde,3805,nsw,19071027,8707306 +rec-805-org,madison,hawes,123,vasey crescent,canberra hse,kellyville,3194,nsw,19360628,2097590 +rec-3123-org,jackson,carbone,133,mileham street,,carranballac,3139,qld,19180312,6993200 +rec-627-org,,nguyen,84,small place,jalbarragup homestead,glen eden,3073,qld,19181128,5132162 +rec-4198-org,nathan,ryan,1340,,bute park,berwick,2228,qld,19790525,5533064 +rec-111-org,amy,seetoh,50,busby street,bellfield,st albans,2870,qld,19160523,4467636 +rec-3024-org,michaela,wilkins,1,hoseason street,robley house,jamestown,3782,nsw,19390517,4477585 +rec-4515-org,monique,novak,8,garanya street,bells hills,dianella,2611,vic,19750223,9734143 +rec-2202-org,finlay,gillard,22,ryrie street,lithgowvale,corryong,5152,nsw,19410128,6232488 +rec-896-org,eleanor,klemm,110,carrodus street,henry kemball village,greensborough,2122,vic,19771109,9856779 +rec-4074-org,james,fimeri,93,andrews street,,vermont,2198,vic,19230520,2169259 +rec-4613-org,robin,swiggs,29,mcclelland avenue,mayflower retrmnt vlge,preston,3170,qld,19051107,9180357 +rec-1988-org,joshua,jolly,815,kingston street,benbullen lowline stud,thornlie,2546,qld,19200423,1559039 +rec-1812-org,aurora,howie,1,pinkerton circuit,,miami,3030,vic,19561122,7478672 +rec-4088-org,phoebe,hage,77,marchant circuit,brackengrae,mount gravatt,2119,sa,19710401,8504441 +rec-782-org,cheyenne,nguyen,33,mary potter circuit,vics crossing,bibra lake,6156,qld,19240128,2029887 +rec-2593-org,harry,pardey,86,launceston street,ainslie house,hillston,2478,tas,19750105,3922548 +rec-2528-org,madison,cannell,2,seaborn place,tara palms,north hobart,6030,vic,19251217,4366054 +rec-2941-org,liam,green,2,benny place,the gums,crescent head,3067,vic,19570330,7329507 +rec-2645-org,mackenzie,meaney,193,london circuit,,frankston,2148,vic,19600306,9550123 +rec-1297-org,noah,scott-jackson,38,kosciusko avenue,upper flat,punchbowl,4306,nsw,19811218,2859455 +rec-2076-org,benjamin,kapioldassis,199,farrelly close,texas station,goodwood,3197,nsw,19860801,6377421 +rec-789-org,pakita,alderson,17,canberra centre (next to medicare),tinaroo falls,brighton-le-sands,2486,sa,19710808,6651007 +rec-1636-org,layla,donaldson,5,kater place,parry house,burwood east,5251,qld,19730408,5189661 +rec-26-org,natalee,campbell,37,upton street,brentwood village,woollahra,3355,wa,19990213,2201146 +rec-3366-org,rachel,lowe,141,milford street,,darlington,4510,nsw,19810216,1700052 +rec-4727-org,alicia,dixon,22,embling street,kimberley park,upper coomera,3551,vic,19860731,2677733 +rec-1265-org,olivia,girdler,242,joyner place,jinchilla,annandale,2422,qld,19840812,1413325 +rec-4623-org,isabella,white,5,clavert place,glenmore,myrtleford,7310,sa,19651115,3189046 +rec-3426-org,emiily,sariago,13,boobialla street,the meadows,clareville,2229,qld,19740226,5576047 +rec-1390-org,kyra,george,25,boake place,brentwood vlge,peterhead,3012,nsw,19430404,7581292 +rec-449-org,angie,webb,18,ross smith crescent,,hughes,2380,nsw,19320523,7667880 +rec-3943-org,riley,quilliam,12,hayden close,,north ryde,2450,nsw,19021008,2734415 +rec-3670-org,ash,mayer,5,freda gibson circuit,willaroo,erskine,2214,vic,19080705,6979379 +rec-3974-org,carly,webb,31,dash crescent,freston cotge,buffalo,3225,wa,19121203,5240972 +rec-3587-org,emiily,white,85,marou place,jingara,marsden,3412,vic,19510901,6646759 +rec-2685-org,joel,lodge,200,steinwedel street,kmart p plaza,toowoomba,4012,wa,19710830,2655513 +rec-2441-org,sophie,furze,590,goldsborough close,tallageris-demijoh,carina heights,3171,qld,19110502,4765244 +rec-3053-org,sophie,mcilvar,10,steinwedel street,ponderosa,geelong east,3550,qld,19640509,4135696 +rec-710-org,christopher,edson,63,bennie street,,tailem bend,4868,qld,19880809,2348557 +rec-2305-org,rachel,peachey,1090,willis street,,preston,2114,wa,19901004,5902615 +rec-4600-org,sylvie,morcom,33,,nomore,armidale,4551,sa,19580901,8709612 +rec-2347-org,teagan,ryan,7,wilkins street,blackridge flyfishing school,camp hill,2141,nt,19841127,2731022 +rec-3644-org,natassia,mccarthy,16,newman morris circuit,st john of god hospital,port sorell,6324,nsw,19761016,1123871 +rec-2856-org,chloe,setlhong,4,nunki place,yacklin,cronulla,6164,act,19950628,2829638 +rec-1888-org,kazuki,white,65,maranboy street,springdale,marrara,2220,wa,19101205,4980306 +rec-2256-org,delaney,kiernan,3,weavell place,tilbrook,robina,7018,tas,19180423,8250056 +rec-4532-org,indiana,thorpe,39,newmarch place,nelsons lake,mill park,2250,qld,19271212,8901632 +rec-882-org,sarah,eyles,34,badgery street,yarrallah,gailes,0810,qld,19760516,5129649 +rec-4772-org,blake,fitzpatrick,14,boote place,armidale private hospital,concord west,3058,nsw,19240223,6366376 +rec-2720-org,caitlin,berry,6,hakea crescent,lort heights,cronulla,2093,nt,19590328,5662864 +rec-4315-org,edward,clarke,18,strehlow place,pleasant pines,eden hills,7000,vic,19520123,3945218 +rec-267-org,liam,white,33,hargrave street,buderim meadows,caulfield,7250,nsw,19140112,6654477 +rec-3031-org,lachlan,rollitt,566,cossington smith crescent,the manor garden,pottsville,3216,qld,19051107,2847641 +rec-2471-org,anthony,lavis,36,titheradge place,kalyra retirement,new farm,3130,qld,19000617,9007184 +rec-3041-org,hari,dominey,24,albermarle place,wingara,theodore,5235,qld,19360715,6430390 +rec-2197-org,finlay,bedding,2,burnett street,abbey fields,orchard hills,4301,nsw,19640329,3074334 +rec-2472-org,amy,campbell,12,kinchela crescent,aceland poll hereford stud,sadleir,4753,qld,19021030,2533567 +rec-4019-org,jack,reid,1,withnell circuit,zeevoo,hawthorn,2576,qld,19430103,3187380 +rec-3420-org,ella,cowell,73,jabanungga avenue,,woodcroft,2754,nsw,19571124,2648173 +rec-2716-org,georgia,polmear,5,sherbrooke street,ra 881,blacktown,3156,vic,19321116,1862687 +rec-4010-org,joshua,morrison,26,bainbridge close,glenfyne angus stud,adelaide,2071,vic,19870429,8684749 +rec-289-org,riley,paddon,5,burdekin street,rosetta village,mount eliza,6230,vic,19510214,4214905 +rec-3561-org,erin,clarke,11,patten street,paddy's river,moruya,2066,nsw,19690410,6325590 +rec-3548-org,takeisha,white,6,chuculba crescent,melaleuca,bundaberg,6062,vic,19350824,1092886 +rec-2929-org,bethanie,artis,21,brigden crescent,caragnoo,cronulla,6147,sa,19020810,4534363 +rec-2615-org,rebekah,camp,27,la perouse street,yambira,st kilda,3199,wa,19860227,1035731 +rec-3237-org,adam,boeyen,200,belconnen way,dolphin arcade,underdale,3188,nsw,19440418,1726023 +rec-930-org,noah,cadman,20,kingsmill street,mirra monte,ulverstone,4614,qld,19200119,1543323 +rec-3112-org,samara,joel,66,crisp circuit,john curtin hostel,mount eliza,2477,qld,19001010,9937630 +rec-1518-org,alicia,fardell,63,reveley crescent,pint pot,sunshine beach,2203,nsw,19471004,7172127 +rec-4226-org,sara-louise,nikakis,51,ashby circuit,sunshine farm,goorambat,2298,qld,19000820,4911869 +rec-1756-org,joshua,donkin,16,mather street,glebe retirement villa,park holme,3020,nsw,19750509,3544363 +rec-2811-org,vanessa,george,6,cleland street,rowethorpe,mount isa,4122,nsw,19420210,3116798 +rec-3171-org,jamie,fernando,37,collings street,bogong apartments,lansdowne,3910,sa,19200720,1939746 +rec-433-org,cameron,cioffi,18,harpur street,inverneath,new farm,2153,qld,19860725,7511789 +rec-1721-org,madison,van tuil,39,vonwiller crescent,wentworth house,coombabah,3094,qld,19110716,8651342 +rec-3915-org,jacob,richmond,195,flack street,cadagi grove,berwick,5109,nsw,19820727,7932680 +rec-2633-org,alex,clarke,13,kirkland circuit,bernleigh,sandy bay,4655,sa,19720617,5932947 +rec-2889-org,liam,webb,37,river street,medical centre,south melbourne,2088,nsw,19131010,2490042 +rec-421-org,deakyn,cannell,20,vansittart crescent,st vincents medical centre,,6065,nsw,19951221,1255552 +rec-3080-org,bridget,rippingille,11,,south punyelroo,como,6152,vic,19200930,1882529 +rec-2129-org,luke,verrion,32,mcclintock street,silverdale south,carlingford,0880,nsw,19301223,6708080 +rec-1655-org,lily,innis,39,harricks crescent,yarrandale,st albans,3002,qld,19880321,2533253 +rec-1889-org,matthew,nurse,46,cygnet crescent,,portarlington,3804,nsw,19670101,6591571 +rec-4106-org,zakariah,ryan,1,cochrane crescent,homevale,aldinga beach,3941,nsw,19030508,7629205 +rec-2993-org,amy,tiggeman,3,dugdale street,kooyong,roselands,3840,vic,19740926,9867216 +rec-924-org,joel,teti,686,wheelwright crescent,grandview,brighton,4018,wa,19260102,9064672 +rec-1025-org,grace,maynard,49,woodgate street,hillendale,greenwood,2260,qld,19860314,4508059 +rec-2191-org,joshua,arribas,30,nicholas street,dangaroo park,narellan,4068,nt,19800502,7705455 +rec-3035-org,gianni,peachey,55,tate street,rowethorpe,burwood,2154,sa,19451127,5162025 +rec-1129-org,andrew,rankine,84,boddington crescent,beau-lieu,connolly,3644,qld,19311116,2128049 +rec-155-org,lachlan,meeking,20,whitford place,westella,kyabram,2148,vic,19580816,8359944 +rec-1523-org,chloe,matthews,3,city walk arcade,sheep station,pallarenda,4210,vic,19590508,9412116 +rec-3418-org,,riding,336,kallara close,unt 2,altona north,2177,qld,19320604,7712618 +rec-1829-org,imogen,goldsworthy,1,nungara street,bendigo retirement village,knoxfield,3816,vic,19660727,7147139 +rec-472-org,mason,mccarthy,223,claxton crescent,parkmoor,hahndorf,3111,nsw,19251019,8544264 +rec-4806-org,thomas,haggett,858,nangi place,rheo bland,jesmond,3172,vic,19040405,2872424 +rec-949-org,thomas,campbell,10,bywaters place,rosetta village,dewhurst,2611,sa,19640129,1872563 +rec-4933-org,hudson,caine,19,mackellar crescent,judy's creek,east melbourne,2130,nsw,19490406,7689320 +rec-2497-org,maya,webb,927,woodfull loop,birubi point caravn park,tolland,4300,qld,19901005,1365038 +rec-4822-org,luke,geue,12,rocklands street,,allambie heights,6104,vic,19720807,8840914 +rec-3407-org,catherine,campbell,3,henty street,bega flts,moorabbin,2794,nsw,19730310,9201547 +rec-657-org,danika,mcvicar,25,maclagan street,rosedale,canterbury,4305,vic,19550817,3962564 +rec-2850-org,rupert,browne,5,sturdee crescent,lingdale,greensborough,3227,qld,19981026,5706098 +rec-2275-org,alissa,leong,4,maranoa street,,windang,2795,vic,19380612,2265634 +rec-1180-org,carly,herbert,9,darwinia terrace,strathalan homes,lalor,2212,vic,19561119,6065655 +rec-165-org,ryan,allsopp,25,warramoo crescent,shiloah,atherton,3796,qld,19920806,5369163 +rec-1310-org,olivia,woodstock,209,,edinburgh caravan,orelia,2370,qld,19191127,2364919 +rec-671-org,corey,godfrey,74,sturt avenue,cox court hostel,rapid creek,3976,wa,19720408,7156463 +rec-527-org,max,bradshaw,13,marrakai street,arkaba,st kilda,3108,wa,19621220,4677446 +rec-2219-org,lachlan,verco,266,bursaria street,terara house,macgregor,4109,nsw,19830103,8260739 +rec-1612-org,annabelle,webb,48,squire place,lytton,beaumaris,4670,act,19320717,7334846 +rec-3668-org,hudson,clarke,,port jackson circuit,redhill,port lincoln,2680,vic,19600417,7391640 +rec-4476-org,imogen,bellchambers,216,benstead place,oreel,nedlands,2158,nsw,19230217,9615495 +rec-315-org,erin,kunoth,131,wyselaskie circuit,grange house,wendouree,6107,vic,19340721,4791842 +rec-3091-org,richard,keatch,34,,belvedere,mount pleasant,2168,qld,19980216,8117319 +rec-4256-org,luke,everett,4,kidston crescent,,terrigal,3075,vic,19961013,5886568 +rec-2789-org,jackson,barisic,6,whitty crescent,gowrie,ringwood east,2286,nsw,19450822,1342488 +rec-971-org,dylan,jedynak,,genoa street,ruthven street,glenhaven,4213,act,19201112,1200539 +rec-471-org,lucas,mcgregor,29,brigden crescent,deridgeree,uplands,3135,nsw,19491115,7215881 +rec-1012-org,dean,eyles,18,busby street,wallsend delivery centre,highton,2450,vic,19491206,3878109 +rec-3093-org,oliver,white,18,kinchela crescent,murray river queen,emu bay,2219,nsw,19340722,1420638 +rec-3196-org,michael,hyland,19,aronson crescent,evergreen,cooranbong,4741,qld,19101219,8061638 +rec-3393-org,,reid,46,dooring street,windalea,dandenong north,3581,nsw,19130312,1322845 +rec-1995-org,chloe,lazaraki,24,woollum street,,pymble,2321,nsw,19901223,8831246 +rec-264-org,jessica,painton,92,gallagher street,berkeley vlge,north bondi,4740,nsw,19430327,2751175 +rec-2692-org,mya,maksim,41,lambrigg street,brest hill,st kilda,6050,vic,19650630,1488918 +rec-2105-org,holly,wehr,64,gooromon ponds road,ainslie house,gorokan,2234,qld,,9292420 +rec-1749-org,amber,vincent,313,kneeshaw street,vlla 18 pacific bay resort,oyster bay,4740,nsw,19901002,2066144 +rec-2997-org,india,block,26,skardon street,,dianella,2173,qld,19950131,9859519 +rec-2159-org,,carullo,5,longman street,home vlge,mawson,4572,nsw,19260527,5895140 +rec-2221-org,jacqueline,geduld,189,crichton crescent,ponderosa,raglan,3088,nsw,19320306,9649030 +rec-1666-org,rhett,george,6,,lindisfarme,marsden,5251,qld,19420726,5663323 +rec-146-org,oliver,berry,18,arthaldo court,kalang,bayview,3802,nsw,19720119,2589280 +rec-1292-org,jacinta,lenzi,10,couvreur street,mt drysdale,mortlake,2068,qld,19640807,1067001 +rec-2937-org,connor,trait,6,lane place,sun city resort,leichhardt,3337,vic,19150208,1776479 +rec-2097-org,brianna,white,5,hazel smith crescent,water view,loganholme,2210,nsw,19860705,3275049 +rec-9-org,paris,reid,39,crowder circuit,,st ives,3225,vic,19980826,2553313 +rec-2196-org,timothy,de crespigny,6,barraclough crescent,,gnangara,2166,vic,19300524,1913293 +rec-388-org,ewan,whiteley,23,bennelong crescent,,glen innes,3171,nsw,19840205,1326266 +rec-2223-org,zane,dixon,27,southern cross drive,nanto,dickson,3842,sa,19870503,7439457 +rec-3412-org,oliver,sherriff,7,augustus close,sheep station,st ives,5006,vic,19160706,6364957 +rec-2477-org,alexander,stoneman,124,kent street,sec 1,northgate,4010,qld,19320612,7675532 +rec-3574-org,,genovese,6,axon street,aprt 504,march,3166,qld,19681013,2402512 +rec-2131-org,kaitlyn,van schie,127,capella crescent,banksia village,oak park,5093,nsw,19000127,1321883 +rec-4100-org,william,hope,32,doonkuna street,colomie,dululu,4560,vic,19860326,9704755 +rec-1818-org,paris,parremore,16,guerin place,coralyn,north hobart,2250,wa,19260913,1309513 +rec-1570-org,matthew,ryan,55,fitzhardinge crescent,mlc centre,burpengary,2546,sa,19510417,2890790 +rec-162-org,portia,weaver,34,angophora street,knox retirement village,parramatta,3192,vic,19560218,7422879 +rec-1367-org,isabelle,morrison,72,majura avenue,rockview,sherwood,4164,sa,19940413,5896664 +rec-2611-org,hannah,grainger,34,fitzsimmons street,northbridge marina,middleton,4680,nsw,19340314,1608436 +rec-3539-org,tuscany,stephenson,108,burdett crescent,wombat hill,south sydney,4560,wa,19460925,6871514 +rec-3076-org,xani,andrae,20,wade street,myona,noble park,2105,vic,19450312,4709521 +rec-3904-org,hannah,white,7,supply place,little gundy,oaklands park,2158,nsw,,5239710 +rec-901-org,daniel,grainger,24,holden crescent,,riverhills,5353,nsw,19441009,3864352 +rec-3995-org,thomas,brooker,464,clive steele avenue,glenburn,springwood,2046,vic,19100324,5168589 +rec-687-org,brodie,green,169,staunton place,,bellevue hill,3171,nsw,19690410,5667813 +rec-1551-org,lucy,rees,78,badenoch crescent,galveston,macquarie fields,3076,nsw,19230613,8204200 +rec-367-org,reganne,sanakidis,20,broadhurst street,sawtell vet hosptl & clnc,kyabram,5279,vic,19621217,7989856 +rec-4316-org,nicholas,bridgland,8,lethbridge street,,winston hills,2767,qld,19230404,3946937 +rec-1149-org,sebastian,campbell,34,atherton street,glen-vale,north sydney,4350,nsw,19660715,8686683 +rec-372-org,lachlan,pascoe,5,hodgson crescent,inishmore,toowong,2766,vic,19470107,1606779 +rec-4865-org,lara,musolino,26,steinfeld court,table mountain,moree,3134,wa,19381019,4887522 +rec-2773-org,daniella,millar,12,rapanea street,the briar patch,taree,3193,qld,19920714,7697624 +rec-505-org,meg,sedunary,29,castles place,wollangambe,tweed heads,3129,vic,19450601,2413526 +rec-4131-org,jessica,webb,81,bimberi crescent,cheviot hills,wanniassa,5073,qld,19250410,9559799 +rec-2380-org,caitlin,gatward,6,pokana circuit,cerbrus,thornlie,2810,nsw,19790927,1186199 +rec-3933-org,joshua,rigley,19,east place,kergunyah,kingaroy,3665,vic,19670613,4096438 +rec-349-org,ryleh,burford,3,bendigo street,shady creek,warrandyte,4217,wa,19050504,8427851 +rec-425-org,shantal,psorakis,61,barcoo place,stonyridge,hawthorn,2324,vic,19850722,6633125 +rec-4299-org,jayden,pendle,484,naas road,weeroona,mount gravatt,2164,vic,19070815,6759267 +rec-679-org,caleb,,19,burrinjuck crescent,garema place surgery,st andrews,2154,wa,19381026,3166758 +rec-1629-org,karla,talapaneni,166,kater place,allanvale,balcatta,3133,vic,19671223,4859425 +rec-1316-org,brianna,blake,44,coranderrk street,taatooke,gosford east,2902,nsw,19450710,9837624 +rec-2942-org,mikayla,nguyen,11,jauncey court,karinya gardns,helidon,5107,nsw,19030122,3964863 +rec-86-org,aiden,son,17,sharwood crescent,,lakemba,2866,sa,19490716,3651118 +rec-2162-org,chloe,kammermann,12,mcbryde crescent,corella,dural,2134,qld,19251019,7777606 +rec-3656-org,robert,white,12,crozier circuit,mt pleasant,garbutt,2259,,19670110,3509633 +rec-3919-org,tegan,white,110,torrens street,promenade arcade,sunshine beach,2222,qld,19350203,9994674 +rec-265-org,hamish,teague,46,middleton circuit,colooli village,burwood,4128,nsw,19731030,9222441 +rec-2948-org,kylie,browne,11,clancy street,grange house,tamborine,3812,nsw,19040712,4522939 +rec-4001-org,dillon,nettleford,23,haskett place,glen brae,emu plains,0822,wa,,6238993 +rec-2457-org,caitlin,white,10,yabsley place,bellona,kariong,2280,nsw,19020814,1317399 +rec-2445-org,ella,campain,2,bimbiang crescent,st john of god hospital,seven hills,2160,vic,19900406,8809552 +rec-4363-org,kenneth,priest,12,piper street,,ferny creek,2257,nsw,19151017,9976586 +rec-3450-org,jesse,white,9,dalley crescent,,north kirra,3143,nsw,19820904,8123185 +rec-4229-org,harley,kreymborg,160,spinifex street,laurieton hvn ret,holsworthy,4630,act,19550403,8066192 +rec-3692-org,jack,berry,5,shirra close,bindana downs,connolly,4814,nsw,19300619,6070746 +rec-3058-org,lachlan-john,spears,5,o'connor circuit,,risdon park,6064,qld,19950105,2405882 +rec-4763-org,max,kirby-fahey,21,duffy street,meadowview,frankston,2130,nsw,19800916,1450223 +rec-2660-org,alexander,munyarryun,2,allambee street,,moranbah,4218,qld,19551107,9890402 +rec-4319-org,hannah,bansemer,3,owen crescent,glynstan,lemnos,3065,nsw,19380604,8798025 +rec-1659-org,holly,glennon,8,ballumbir street,summervale,glengowrie,4124,wa,19490518,6635323 +rec-2518-org,makayla,thoonen,119,tullaroop street,rosetta village,byford,3977,vic,19750818,1423820 +rec-301-org,benjamin,campbell,26,cockburn place,kangaroo gnd,banyo,2605,nsw,19180920,2472793 +rec-4110-org,ruby,gilcrist,98,honyong crescent,aleon,bassendean,6230,qld,19760723,9352851 +rec-563-org,madison,meaney,22,julius street,east end,seaforth,3690,sa,19731218,7466921 +rec-2403-org,,dunnicliff,97,banfield street,milton,,2116,vic,19130108,6220830 +rec-4634-org,rachel,deakin,1748,hugh mckay crescent,stockwell hotel,inverleigh,5268,wa,19400613,7083021 +rec-4427-org,james,lupoi,46,mirrool street,walhalla,carlingford,2607,qld,19540202,7582894 +rec-1399-org,joel,,,coane street,mountview,thornlands,2548,nsw,19150412,1945725 +rec-3483-org,darcy,bullock,95,ashley drive,star court arcade,rosebud,2171,nsw,19660224,2192983 +rec-4503-org,jake,campbell,67,larcombe crescent,oaklands village,greensborough,4570,wa,19240304,4245106 +rec-2976-org,zachary,nakahara,,tazewell circuit,henry kendall hostel,chiltern,2193,nsw,19600128,4768273 +rec-3245-org,harrison,burman,24,la perouse street,bypass road,yarrawonga,2122,vic,19531122,8916268 +rec-4160-org,harry,waller,111,lochbuy street,willmont park,glendale,3170,wa,19680628,1311728 +rec-2456-org,cassandra,cappelluti,3,flecker place,,holden hill,2529,nsw,19350419,7613246 +rec-779-org,rohan,ruskin,8,wenholz street,fenner hall,rowville,5067,vic,19020302,9606352 +rec-3049-org,joshua,bralic,76,myles close,old green hill,beaumaris,6108,vic,19110727,6708902 +rec-2350-org,gillian,lodge,29,stacy street,,menangle,2765,nsw,19000626,9298526 +rec-4563-org,zachary,white,20,shain place,,glenwood,3840,vic,19111109,7091861 +rec-4570-org,kyle,block,45,erldunda circuit,mt warrigal retrmnt vlge,greenacre,2614,nsw,19740424,4380571 +rec-1006-org,cooper,ryan,166,torrens street,callatoota,bondi junction,3992,nsw,19341027,1163656 +rec-970-org,jessica,vick,64,leahy close,villa 74 village glen,leichhardt,2027,vic,19830919,8778791 +rec-1291-org,tiana,webb,59,spalding street,,glendorf,2444,nsw,19270920,6947860 +rec-2974-org,michael,maclennan,6,richmond street,lake downs super fine merino stud,emu plains,5271,qld,19390409,1643013 +rec-644-org,casey,meyler,12,grylls crescent,,berala,4109,nsw,,8730501 +rec-2713-org,benjamin,morrison,16,kingscote crescent,malanda orchard,evans head,0820,nsw,19761231,3201927 +rec-4488-org,lochlan,shepherd,51,barnett close,winteriga,bimbi,2328,vic,19850102,8073994 +rec-373-org,yasmin,reid,8,gurr street,gunn's gully,san remo,2011,nsw,19530308,5213022 +rec-1691-org,pascale,quast,33,kingham place,killarney,robertson,2135,wa,19570201,7680717 +rec-1791-org,joshua,reid,416,muresk street,karingal farm,bayswater north,2160,vic,19160311,3652623 +rec-4794-org,amy,shepherd,19,santalum street,the willows,lismore,5277,vic,19610121,2441128 +rec-4304-org,lynton,rudd,30,donohoe place,rosetta village,eudunda,3057,nsw,19660123,1197508 +rec-775-org,gemma,brain,14,lingiari court,flt 167,ancona,3130,sa,19261125,8731806 +rec-3445-org,joshua,white,93,archibald street,allman court,narrogin,2280,nsw,19611206,2059387 +rec-3900-org,katie,jolly,26,reuther street,aprtmt 34,,2780,nsw,19690224,4300643 +rec-4682-org,teagan,richmond,18,wettenhall circuit,flt 17,pleystowe,3000,nsw,19210820,8646516 +rec-477-org,nikita,helliar,30,northbourne avenue,henry kendall bayside,beaudesert,6057,vic,19500323,2105506 +rec-4523-org,callum,erett,9,tiptree crescent,felbrigg,edenhope,3280,tas,19550825,3727793 +rec-4267-org,jessica,zimmermann,25,fairweather circuit,burnie north west private hospital,brighton,4211,vic,19370426,2620091 +rec-4332-org,georgia,carmody,107,ashburton circuit,,wamuran,3936,nsw,19870920,9507232 +rec-283-org,jenna,shew,21,fincham crescent,rosetta village,thornleigh,3111,vic,19060322,7681478 +rec-867-org,emiily,green,8,kurria place,ocean beach caravan park,north rocks,5095,nsw,19810511,6240008 +rec-302-org,jack,ryan,109,lampard circuit,bega flats,lennox head,6066,nsw,19690724,4124424 +rec-520-org,nicholas,mcneill,16,taylor place,tunis,bacchus marsh,6019,nsw,19800829,4524218 +rec-3903-org,jack,dimonte,104,mckeahnie street,carinyah station,woy woy,2132,nsw,19880316,4854960 +rec-3435-org,indiana,eves,42,holmes crescent,,torquay,5098,vic,19181015,6393328 +rec-3398-org,kelsey,dearing,25,,bindaree,clare,4109,sa,19400117,1841588 +rec-4393-org,rachel,coffey,99,dampier crescent,katimba,ashfield,6152,vic,19300416,7093245 +rec-2247-org,tabitha,walch,22,kosciusko avenue,sec 311,tumbarumba,2340,vic,19380223,2307700 +rec-57-org,brianna,feast,23,brentnall place,blacklead farm,atherton,4650,nsw,19181028,1261908 +rec-1951-org,emerson,whiteway,1,westhoven street,yurara park,brighton,3356,vic,19430528,8932147 +rec-1179-org,stephanie,george,50,mcculloch street,ardrossan,berwick,2226,qld,19691102,3352388 +rec-2872-org,renee,havrda,51,cuthbertson crescent,salimtal,firle,5089,vic,19500910,3898443 +rec-1102-org,samantha,spong,9,currong street,westgate,vale park,2090,sa,19500508,4742050 +rec-1568-org,connor,vincent,391,woolner circuit,locn 8200,geraldton,2560,qld,19811218,9810666 +rec-1328-org,emiily,hewson,10,,the links,mount isa,5422,wa,19320504,6458398 +rec-4132-org,jake,warnock,98,martley circuit,rosetta village,taralga,2474,sa,19670608,7452671 +rec-785-org,matthew,egan,80,eve place,alawah,toowoomba,3377,sa,19040522,1160317 +rec-2897-org,sam,rogan,36,kanooka street,coliban glen,balwyn north,3280,vic,19380721,4941592 +rec-2345-org,,falting,22,gurrang avenue,glenapp,blair athol,2564,qld,19941202,2319505 +rec-2542-org,harley,webb,6,brownless street,willow lodge,harbord,2905,qld,19760709,5012250 +rec-151-org,arabella,reid,35,baracchi crescent,argyle,hermit park,3806,qld,19640323,1433160 +rec-2376-org,erin,wehr,51,tange place,whispering pines,east fremantle,4717,wa,19190330,8202628 +rec-774-org,oscar,white,33,scrivener street,philip centre,caulfield,3046,qld,19090820,3363844 +rec-3216-org,charlotte,feeney,6,dangar place,brookfield,ermington,3182,nsw,19810505,9513852 +rec-806-org,jacinta,webb,37,port jackson circuit,nimmitabel motel,maryborough,3500,nsw,19991017,7529668 +rec-1400-org,paige,sherriff,25,chuculba crescent,wunpalm,marks point,2101,qld,19111215,2181571 +rec-4151-org,matthew,browne,392,parsons street,north star resort,slacks creek,4501,qld,19720102,9033952 +rec-4439-org,lara,mccowat,15,dumas street,westholme,dimboola,3041,qld,19290815,8213647 +rec-2019-org,mya,ongley,20,tenison-woods circuit,aleon,rosebud,3194,wa,19940810,3204273 +rec-3155-org,benjamin,campbell,159,corrigan place,mornington ret vlg,thornbury,2300,nsw,19870227,4459447 +rec-4534-org,henry,hobson,10,limestone avenue,clarkbrae,warilla,2614,nsw,19280928,6436995 +rec-1632-org,jasmine,stancombe,41,roseby street,,dulwich hill,2086,wa,19980319,8947188 +rec-2575-org,charlotte,grierson,40,hooley place,,kellyville,2479,nsw,19691116,8381516 +rec-4729-org,jack,waller,31,currie crescent,summer hill,bayswater,3579,vic,19550324,8581279 +rec-352-org,kobe,miliano,89,sprent street,glenlee,eaglehawk,2040,qld,19710302,6038986 +rec-748-org,campbell,campbell,136,croton street,ocean park towers,hawkesbury heights,3850,nsw,19550115,8861700 +rec-823-org,anna,reid,19,morant circuit,grammar school,south turramurra,2040,vic,19960111,2799251 +rec-3130-org,emiily,reid,24,luehmann street,tawonga rdside,rose bay,2350,nsw,19190825,2408163 +rec-2845-org,jack,harrington,,gladstone street,amberu,watsonia,4066,nsw,19820311,7610085 +rec-688-org,sarah,crosswell,37,handasyde street,matlock,beaumont,2773,vic,19511018,6179719 +rec-4978-org,charlotte,ryan,28,monaro crescent,shiloah,fig tree pocket,2538,vic,19590825,3609154 +rec-2817-org,amber,canavan,,,karinga park,hawthorn,2540,vic,19820904,1356716 +rec-1139-org,prudence,monaco,8,barraclough crescent,glendaurel,midland,4017,wa,19060919,2264092 +rec-4828-org,emiily,tidey,6,hazel street,duck creek,cooloongup,0800,nsw,19591017,6058396 +rec-261-org,erin,gascoigne,35,paul coe crescent,curtin house,wangaratta,3824,wa,19760329,8037688 +rec-2324-org,michael,scarce,92,perry drive,parklands village,long jetty,2620,act,19930925,6703972 +rec-4691-org,william,tomney,25,houghton place,omaru,gilmore,5043,nsw,19280525,7882159 +rec-3834-org,hannah,bishop,79,merriman crescent,,millgrove,4625,nsw,19740414,4492531 +rec-2482-org,hayley,benger,125,mckail crescent,rosetta village,southbank,5048,nsw,19390818,2726971 +rec-4995-org,jessica,singleton,40,tyrrell circuit,villa 2,farrer,4422,qld,19241115,7634940 +rec-280-org,joshua,toseland,19,roughley place,bells ck,kings park,5253,wa,19820825,3749440 +rec-1371-org,timothy,jolly,13,mcmahon court,callatoota,hill end,3075,nsw,19721103,3751485 +rec-2732-org,sebastian,garcia,24,cockcroft avenue,,blacktown,4077,sa,19640925,2452041 +rec-3742-org,sophie,friswell,40,shannon circuit,sunbury,geurie,3181,nsw,19050421,7502749 +rec-1505-org,melissa,dent,27,gungurra crescent,redlands,whyalla,3775,nsw,19960112,9846985 +rec-857-org,courtney,benger,15,callaway crescent,flight springs,canterbury,6059,qld,19101114,3489916 +rec-2151-org,ayla,colefax,3,o'halloran circuit,riana,belgrave,2228,wa,19611006,9876911 +rec-4339-org,lily,reid,27,tyrrell circuit,bright view,port sorell,2578,sa,19010405,2062273 +rec-2483-org,zachary,white,97,witt place,villa 74,laurieton,2206,vic,,8708647 +rec-2387-org,alissa,stanley,23,fairbridge crescent,oberne park,mount pleasant,2016,nsw,19790317,8806692 +rec-4854-org,michael,darch,55,batman street,rockview,salisbury east,3523,nsw,19130907,9846815 +rec-4360-org,owen,hingston,16,goldner circuit,bramhall,yanco,6150,qld,19991220,1508216 +rec-2816-org,jackson,edgecombe,3,ranken place,johamenline,bonython,5167,wa,19970731,5991164 +rec-3109-org,calvin,truman,63,newton street,locn 3439,warilla,3104,vic,19540807,8583204 +rec-231-org,ellen,harrington,45,kardang street,crosslands,balhannah,3168,vic,19130627,6204857 +rec-3000-org,caitlin,everett,716,clive steele avenue,vincent court,penshurst,2111,qld,19010417,1129560 +rec-1176-org,kierra,burford,32,adamson crescent,lee grazing farm,adamstown,5008,tas,19100914,4902237 +rec-3416-org,gabrielle,garcia,74,dutton street,kehlhof,burwood,4311,sa,19081210,2519794 +rec-3835-org,jade,bartel,10,london circuit,kurrajong vlge,buronga,2338,vic,19430103,4602097 +rec-2511-org,wil,araya,57,sandover circuit,,belmont,4220,wa,19770709,9179475 +rec-4768-org,caitlin,leslie,24,eyre street,retirement village,worongary,2830,nsw,19420102,1257356 +rec-3702-org,sophie,wiseman,42,rivett street,,greenfield park,2615,wa,19290619,3983966 +rec-3092-org,ashton,boyes,207,westgarth street,cherrymount,mount pleasant,2125,act,19440329,5428639 +rec-2360-org,julia,clarke,180,marconi crescent,hamilton park,whitfield,2642,wa,,8460647 +rec-3536-org,jade,clutterbuck,142,chipperfield circuit,westcourt,bundamba,6050,sa,19151030,3828291 +rec-1491-org,kirra,white,68,strangways street,diamond downs,bundaberg,2210,sa,19230223,7213703 +rec-834-org,,ryan,17,nelson place,toowoomba,croydon north,0860,,19610701,2369541 +rec-4740-org,henry,sach,69,hawdon street,logie brae,harbord,2141,nsw,19051226,7123737 +rec-3745-org,liam,dabinet,23,boldrewood street,statue bay,,3121,qld,19851223,3336732 +rec-4770-org,tegan,rosendale,1,sherbrooke street,nazareth village,innaloo,2250,wa,19801011,9351309 +rec-4646-org,india,green,11,feltus place,ningana,urangan,2197,nsw,19720703,8013479 +rec-4579-org,chloe,ryan,5,lambrigg street,eldeslee vlge,eastwood,4371,,19570622,2578857 +rec-2711-org,olivia,noack,2,endeavour street,burrendong est,armidale,2146,vic,19661109,5291032 +rec-2299-org,lachlan,gaskin,61,haystack crescent,gemma,koroit,6233,vic,19590425,3676871 +rec-4733-org,benedict,hursey,63,erldunda circuit,barwon station,tingalpa,3056,qld,19060127,5070016 +rec-1880-org,liam,coenen,66,stretton crescent,brinjarry,patterson lakes,6060,qld,19690602,1128736 +rec-2904-org,lily,matthews,6,gilmore crescent,masonic memorial village,,3880,vic,19960620,8250432 +rec-1034-org,briony,dudley,6,goodwin street,ctge 25,allawah,3138,vic,19590905,2103478 +rec-4578-org,jasper,bysord,5,cann close,,boondall,7120,qld,19570724,7152705 +rec-2426-org,taylah,timbrell,87,mcglinn place,villa 2,bligh park,2450,nsw,19440825,6149166 +rec-2170-org,keira,zawistowski,18,symers street,irrigation farm,kirribilli,7112,vic,19781026,4217543 +rec-798-org,henry,ryan,22,marconi crescent,,tea tree gully,4019,qld,19930928,6244854 +rec-3938-org,jack,morrison,109,leahy close,the willows,edensor park,3068,qld,19480822,1000754 +rec-4349-org,jared,white,33,dawes street,villa 3,sandy bay,2871,nsw,19640307,2135501 +rec-3100-org,brody,nguyen,93,,mt derriwong,lauderdale,2135,wa,19970629,2691340 +rec-1739-org,zachariah,thorpe,47,fidge street,,belmont,4216,nsw,19880124,9721662 +rec-4819-org,hayden,kluske,25,kanooka street,grenoble,bonnyrigg,4740,nsw,19111028,9665345 +rec-4980-org,isabella,ctercteko,61,sturt avenue,avocado acres,planland,7216,vic,19810626,8794181 +rec-1415-org,amber,braunack,10,fingleton crescent,alchemy,campsie,2508,act,19420513,7964228 +rec-4829-org,flynn,smallacombe,62,bimberi crescent,marlin cove,taylors beach,2171,qld,19330907,3577473 +rec-4886-org,tommi-lee,pagoda,1,strzelecki crescent,rathdangan,moama,3825,vic,19360520,8652033 +rec-4451-org,jairus,scamoni,375,bissenberger crescent,dalmoora,goodna,4670,qld,19120912,6966609 +rec-4060-org,matthew,green,57,howitt street,,,4740,wa,19861119,3767916 +rec-3309-org,cooper,clarke,54,ballumbir street,ballymannin,springwood,5153,nt,19111009,8251151 +rec-3402-org,anthony,browne,118,,riverside park,elwood,5023,nsw,19320227,7567935 +rec-3359-org,dylan,needham,14,eucumbene drive,,carrara,2456,nsw,19750722,2780577 +rec-2229-org,casey,chittleborough,9,brigalow street,hamilton central,belgrave,5341,nsw,19550530,3208087 +rec-429-org,matisse,kromwyk,14,charterisville avenue,phillip lodge,toowoomba,2880,nsw,19190122,1739657 +rec-4577-org,ellie,coleman,8,gurney place,sec 479,dover gardens,6018,vic,19941205,1547145 +rec-691-org,kalli,detzner,23,florence taylor street,plainbrook,rowville,4306,qld,19440320,3527872 +rec-863-org,madison,arganese,1,bracker place,padicam,glengarry,2154,nsw,19530610,4752945 +rec-1804-org,paige,di cesare,8,tardent street,apt 27,balwyn north,4560,vic,19791223,6112690 +rec-818-org,annalise,clarke,22,macgregor street,,brighton-le-sands,2540,sa,19620404,2345085 +rec-3850-org,montana,webb,28,joyce place,ormerod cottage,surfers paradise,2035,vic,19420710,8424221 +rec-1653-org,shaun,cristiani,5,burbidge crescent,unt 2,lower chittering,3962,nsw,19640825,5841667 +rec-1083-org,kyle,lowe,21,bungonia street,eight mile,loftus,4868,qld,19821215,7416603 +rec-1494-org,harriet,jean,184,gooreen street,ordview estate,greensborough,5097,nsw,19600312,4399358 +rec-4382-org,cambell,coleman,54,norton street,skilbister,coniston,3803,act,19731016,2382912 +rec-1033-org,beau,zeitzen-van der burg,32,william webb drive,kilnsey,bundaberg,6489,nsw,19500927,5594467 +rec-2057-org,jye,dibben,6,cossington smith crescent,clarkbrae,kincumber,4005,sa,19291003,3787671 +rec-216-org,ashleigh,de bono,4,sloane place,villa 2,kilmore,2262,sa,19430521,9702458 +rec-4490-org,kai,mason,37,trimmer place,glenlee,warrane,4132,nsw,19651116,3708941 +rec-4051-org,luke,mccarthy,5,bandjalong crescent,gemma,north curl curl,2160,nsw,19521124,9203828 +rec-4926-org,haylee,metherell,16,lambrigg street,wacharoo,aspley,2209,qld,19050614,4025303 +rec-3552-org,bella,clarke,90,schonell circuit,greenhills,magill,3981,vic,19620712,7533159 +rec-944-org,joshua,berry,95,leahy place,crestfield,shenton park,6302,nsw,19550519,3007951 +rec-2919-org,kaleb,hobson,,scaddan place,pacific palms caravn park,bunbury,2259,vic,19960630,9573457 +rec-3725-org,james,hyland,38,hurley street,springmount,emu plains,3207,nsw,19870607,7791289 +rec-2079-org,kirra,,29,atherton street,kiya,londonderry,3756,nsw,19230214,9919791 +rec-790-org,talyah,hewson,16,helen mayo crescent,paradome,orange,3189,sa,,8563603 +rec-1178-org,rachel,kerslake,14,canopus crescent,tartan park,barrack heights,3221,act,19410510,5292435 +rec-4498-org,heather,campbell,15,maitland street,southport retirement village,yinnar,4740,qld,19130206,4429520 +rec-3918-org,joel,lace,33,banner street,wombinoo station,highton,2559,nsw,19140416,3971456 +rec-4655-org,isaiah,drysdale,10,hingston close,,glenhaven,3630,vic,19370729,4360928 +rec-3140-org,riley,breheny,42,barritt street,rosetta village,lalor,5086,nt,,3501500 +rec-711-org,oscar,lowe,30,ranken place,bayview caravn park,bondi junction,2150,nsw,19710617,6682996 +rec-972-org,sophie,bacchus,11,adamson crescent,tweed heritage caravan park,katherine,2036,nsw,19700707,3628289 +rec-3003-org,zachariah,kilmartin,56,barrallier street,greenslopes,torquay,3249,nsw,19980325,1870225 +rec-2353-org,benjamin,bellon,11,croton street,omaru,artarmon,4405,nsw,19120805,3089666 +rec-620-org,sophie,mccarthy,91,woodfull loop,norma,west culburra,2350,qld,19580523,1578155 +rec-1397-org,alexandra,pacey,1,wattle street,keira,peakhurst,2138,act,19390116,3552967 +rec-2786-org,imogen,lamprey,23,backler place,kilburnie,windsor,6083,nsw,19401125,4959474 +rec-1605-org,jackson,kellow,2,dumas street,rocklea,hamilton,6029,wa,19660925,8602157 +rec-4581-org,tess,sherriff,58,burkitt street,oxonia,lavington,4037,vic,19270919,8204283 +rec-1544-org,madeline,bradshaw,22,saywell place,little nest,charlestown,6430,nsw,19190915,3776965 +rec-3071-org,charlie,walpole,43,lampard circuit,the meadows,alberton,2750,sa,19491212,5982948 +rec-2499-org,samara,reid,6,gardiner street,yulunga,blacktown,5433,nsw,19020405,4889678 +rec-2738-org,hamish,rosendale,1,boulton close,middle earth,bateman,2147,nsw,19720223,3756981 +rec-2421-org,zachary,drysdale,13,lee-steere crescent,roblinvale,lindfield,2196,qld,19011228,4223439 +rec-2215-org,lachlan,markowski,26,maribyrnong avenue,kuliup,leichhardt,4570,nsw,19570926,7115051 +rec-4200-org,lara,sekuless,82,loch street,,yarraville,3196,qld,19861129,1392776 +rec-4400-org,yasmin,white,33,body place,st annes rest home,koo wee rup,7249,nsw,,8632908 +rec-1452-org,samuel,quilty,19,wanganeen avenue,kooyong,sherwood,3121,qld,19820317,9211278 +rec-63-org,max,george,52,bunbury street,doctors flat,coolum beach,2230,vic,19031106,1932739 +rec-3921-org,jessica,mason,27,garsia street,warhaven home,lower templestowe,2160,wa,19320216,1753787 +rec-4986-org,hunter,nguyen,1,cutlack street,narada,bunbury,3138,nsw,19391206,5131671 +rec-1922-org,alana,warnock,5,federal highway,belmore river,kurrajong heights,2283,vic,19790619,1270595 +rec-2085-org,isabella,matthews,48,may maxwell crescent,corporate house,armidale,6016,qld,19060809,1255415 +rec-3755-org,tahlia,ryan,,john young crescent,flr 5 john flynn medical centre,westlake,2148,nsw,19740102,4169896 +rec-699-org,felicity,english-obst,15,abercrombie circuit,bega,neville,6726,nsw,19421105,2382886 +rec-1326-org,madison,campbell,2,terrigal crescent,pendleside,port macquarie,4184,vic,19480830,4528630 +rec-3267-org,,painter,60,cockle street,tantallon,casula,3064,nsw,19181001,4954628 +rec-3866-org,jasmyn,schoettke,14,marien place,rosetta village,,3018,tas,,3129756 +rec-4277-org,mitchell,flannery,2,wilkins street,paradise springs,toowoomba,5088,vic,19581016,8712141 +rec-2595-org,jasper,bowerman,21,newlop street,byron arcade,burleigh heads,6016,tas,19390710,1880798 +rec-1302-org,tiarna,mason,37,ames place,grandview,ashgrove,2077,sa,19640227,7346247 +rec-2980-org,flynn,sideris,17,bundey street,,spearwood,5061,vic,19030310,3067715 +rec-4146-org,emiily,marous,42,short place,eventide homes,dolphin heads,3182,vic,19151031,9458847 +rec-4862-org,matthew,walls,1121,massie place,the stockyards,dalby,3352,nsw,19170118,6147905 +rec-3202-org,chloe,mason,9,beirne street,grandview,st albans,2035,nsw,19760319,1704784 +rec-3382-org,dylan,neville,445,sewell place,wirringulla,norwood,5038,vic,,5360010 +rec-956-org,lara,stirpe,60,wilshire street,the boulevarde,wanneroo,2160,wa,19100118,7108358 +rec-2879-org,amaya,pulford,41,challinor crescent,villa 5,newcastle,2535,qld,19930615,5220952 +rec-3491-org,chelsea,malcolmson,12,chalker circuit,woodleigh,moonah west,6233,vic,19281114,4413674 +rec-371-org,nicholas,noble,5,downes place,buena vista,greenacre,4220,nsw,19330331,3691864 +rec-4626-org,kyle,seddon,164,shackleton circuit,the wharf complex,ashfield,2406,vic,19030813,7244560 +rec-2352-org,carlin,crouch,462,mclachlan crescent,lakeview court,alice springs,3174,qld,19651223,4263375 +rec-2052-org,joshua,,8,conlon crescent,the provincial,balwyn north,7262,qld,19620323,2264634 +rec-134-org,delaney,,3,o'sullivan street,the lodge,mount evelyn,2166,nsw,19331220,7133986 +rec-3797-org,isabella,hoehne,8,casuarina street,wai iti,salisbury,2452,nsw,19880607,4585386 +rec-792-org,grace,eyles,64,leighton street,,seven hills,4109,nsw,19810722,5917130 +rec-992-org,nikita,mcgregor,1,sherwood circuit,cooranga,frankston,3892,sa,19250127,5134549 +rec-2764-org,emiily,green,31,julius street,appleglen,mount colah,2290,vic,19340525,7373124 +rec-460-org,lara,paine,89,hibbins place,hawkins masonic vlge,compton,2444,nsw,19710418,3544402 +rec-567-org,giaan,sribar,32,sturt avenue,evergreen,buronga,2710,sa,19020104,9160808 +rec-2583-org,mia,leaver,2,jennings street,miranda,tailem bend,3636,nsw,19960425,7346590 +rec-1046-org,joshua,wiechec,12,parkinson street,chanak,goovigen,3976,tas,19601111,6247547 +rec-3960-org,nellie,webb,21,spencer street,yarrabee,dareton,2234,vic,19231018,5196117 +rec-2033-org,michael,niklaus,170,wittenoom crescent,ainslie house,malvern,3161,qld,19321127,7254550 +rec-1868-org,amelia,graham-jones,5,mcgivern crescent,australian fair west,new town,2163,act,19000619,5013227 +rec-258-org,daniel,harrington,,la perouse street,bull plain,bogangar,3173,vic,19030123,4348887 +rec-2005-org,finn,eckersley-maslin,2,ebden street,kondalilla,harden,6564,nsw,19360522,9218750 +rec-904-org,joel,bowerman,66,fidge street,ashgrove farms,salisbury,3328,vic,19060517,3551824 +rec-3490-org,hayley,kerney,11,phillimore place,boeing park,thornbury,3356,vic,19340713,6518170 +rec-1565-org,anthony,bansgrove,1,falkiner place,bowser,burwood,7249,vic,19400611,5970749 +rec-1775-org,sian,dent,12,kaeppel place,walhalla,belmont north,5253,sa,19470506,9599013 +rec-769-org,deakin,dooley,52,moulder court,highgate,dundowran,3113,qld,19111113,9047714 +rec-225-org,isabella,sanby,18,veale street,wongowal,west swan,3066,nsw,19181010,7757358 +rec-1670-org,cameron,kouimanis,51,nulsen circuit,,tecoma,3931,qld,19671009,1274183 +rec-176-org,lara,seychell,271,ferber place,brentwood vlge,highgate,5501,vic,19060816,9577137 +rec-2062-org,zali,white,6,mildura street,r s l retrmnt vlge,elizabeth vale,3034,nsw,19420704,2318181 +rec-419-org,james,mcclelland,9,chandler street,glen elgin,hinchinbrook,4350,nsw,19270128,5369982 +rec-4260-org,phoebe,pinny,5,beaurepaire crescent,pine hill,stoneville,2110,wa,19730518,1310519 +rec-4164-org,jayde,lazaroff,21,castleton crescent,morayfield exchange,lindfield,4311,nsw,19350424,7611601 +rec-646-org,holly,paterson,1,biffin street,collier park vlge,kogarah,2360,qld,19620830,7769159 +rec-2543-org,mia,white,6,theodore street,lamington national,haddon,2905,nsw,19640403,5969084 +rec-4017-org,sophie,canavan,13,yanda street,evergreen,malvern east,2022,wa,19520105,7624166 +rec-2996-org,keegan,stubbs,30,sellwood street,transvaal,westmeadows,4870,nsw,19650506,9736949 +rec-2056-org,ethan,malvestuto,14,macnaughton street,veone,laurieton,2577,nsw,19520506,1707216 +rec-4473-org,connor,shepherd,58,haddon street,lone fern,beulah park,2770,qld,19430617,4866880 +rec-347-org,alexandra,steers,38,banambila street,john flynn medical centre,taree,2820,vic,19560329,6925665 +rec-3977-org,oliver,compton,8,moncrieff street,bingletree,shell cove,6153,nsw,19531025,5548627 +rec-1442-org,zachary,mccully,33,allambee street,sec 1,urangan,6164,nsw,19190417,9635640 +rec-1990-org,kira,reid,6,saltash place,section,north ryde,2088,wa,19541209,9065074 +rec-2890-org,kiana,lenzi,35,bugden avenue,the meadows,goodooga,2075,,19110824,6557448 +rec-2311-org,harry,hingston,4,mather street,yarren,mathoura,2170,nsw,19780820,1659262 +rec-528-org,troy,copp,32,chinner crescent,huntington,dural,6105,nsw,19921025,8516174 +rec-4743-org,benjamin,menzies,3,bangalay crescent,gowrie,toowong,2903,nsw,19570601,5363153 +rec-668-org,larissa,tootell,13,moynihan street,kalga,nambour,2500,vic,19030610,1590927 +rec-3119-org,alice,wynne,39,st john crescent,civic centre,robina,3971,vic,19220112,1785202 +rec-3523-org,henry,macgowan,5,wynn place,parry hse,belmont,5266,qld,19080417,1834795 +rec-2041-org,julia,worsley,9,aggie place,,bellevue hill,2877,nsw,19780815,5650768 +rec-1278-org,emiily,coleman,5,burdett crescent,withern house,wanguri,3757,vic,19240722,3292797 +rec-2493-org,bailey,thrussell,42,way street,tambo,potts point,2197,sa,19020530,1525644 +rec-1019-org,charlotte,klemm,6,clive steele avenue,port hills,carrum,5085,nsw,19020603,3461436 +rec-2573-org,thomas,edis,47,kellick place,flt 10,bateman,3782,nsw,19890830,6857124 +rec-113-org,gabrielle,langer,562,delegate street,oak valley,paddington,3910,wa,19800810,6248832 +rec-2933-org,harry,bradshaw,96,musca place,longridge,lilydale,2137,qld,19961111,3683424 +rec-4040-org,adam,carbone,16,warrai place,cherokee vlge,elizabeth south,3150,qld,19820611,2023828 +rec-1563-org,rachel,jukic,9,blandon place,clear creek,kangaroo flat,2229,wa,19880430,2851372 +rec-1601-org,isabella,reid,42,sherbrooke street,armidale private hospital,tallong,2088,vic,19101002,2434717 +rec-4471-org,william,campbell,448,tarra place,lochenfels,savage river,3075,qld,19630610,7272235 +rec-2444-org,hannah,povey,81,hooke place,gleneriffe,sylvania,3015,wa,19870509,4598128 +rec-3060-org,rosie,brokenshire,34,antill street,hse 13,athelstone,2042,qld,19770815,3921318 +rec-3916-org,brigitte,white,79,mcelhone court,abbaston,harbord,2306,tas,19480318,5946514 +rec-3950-org,jack,stamoulos,9,mchugh street,,gilmore,2780,vic,19320215,2099471 +rec-542-org,tiahnee,clarke,3,golden grove,,dural,7000,nsw,19790215,9714630 +rec-3887-org,harvey,wang,1,kosciusko avenue,rosedale,toowoomba,2594,vic,19531021,4095296 +rec-401-org,ella,guyatt,19,domain street,lansdowne,st kilda east,5417,vic,19360703,9745316 +rec-4966-org,lauren,green,8,howe crescent,,suffolk park,3215,nsw,19980822,1363900 +rec-243-org,riley,bennell,39,sabine close,browne's reef,toowoomba,4556,qld,19441206,1596501 +rec-2808-org,emiily,lowry,31,chaseling street,wonba,ingleburn,2193,nsw,19940616,9820630 +rec-4843-org,thomas,butt,11,freeling crescent,mylo house hostel,paterson,2486,nsw,19711104,4301794 +rec-2430-org,lara,white,6,sturdee crescent,summit cottage,toowoomba,2122,nsw,19190123,2444018 +rec-3970-org,harry,camp,28,sharwood crescent,,laverton,2153,vic,,8240507 +rec-3321-org,bradley,komsic,6,westbury circuit,meadowview,adamstown heights,2046,qld,19140420,5731419 +rec-2522-org,bianca,thurlow,910,,shack 118,malvern,2852,vic,19120204,8574662 +rec-593-org,brendan,chabrel,39,medworth crescent,thistle dale lodge,buninyong,6208,qld,19290327,1315588 +rec-1709-org,bella,coleman,26,yolla place,hounbank,whitfield,5007,nsw,19480127,9581654 +rec-123-org,angie,mcgahey,54,moore street,farnorah home,elwood,4077,vic,19001102,8638894 +rec-756-org,fynn,allard,1,rolph place,st vincents hospital,hillsborough,4216,nsw,19700328,7861274 +rec-56-org,jacob,mcfadden,70,cowdery place,plumpton park,sunshine,5086,nsw,19090731,9735499 +rec-858-org,lucy,hassall,84,kulgera street,orchid square,northbridge,2580,nsw,19150908,8007265 +rec-1439-org,barnaby,moody,1,learmonth drive,sun city resort,emerald beach,2480,act,19150718,7082194 +rec-4925-org,isaac,riddell,20,ern florence crescent,villa 147 henry kendall bayside,concord west,5042,nsw,19210805,7044469 +rec-4778-org,hannah,browne,4,fergusson crescent,villa 5,mount dandenong,2645,vic,19181016,1931940 +rec-3423-org,jasper,nguyen,8,wardill close,st francis vlge,sunshine beach,3174,vic,19461016,4768225 +rec-643-org,benjamin,fiorenza,20,brisbane avenue,boronia lodge,batemans bay,2259,wa,19451117,4087941 +rec-2969-org,emiily,conaghty,43,o'meara place,minjarra,ashgrove,3042,wa,19140520,4368793 +rec-3580-org,hannah,valentini,5,rymill place,mayo,east maitland,4615,nsw,19490216,2488395 +rec-3634-org,joshua,holmyard,87,darwin place,victoria mill estate,dover,2287,vic,19710810,5679774 +rec-3413-org,amber,durnin,41,hindmarsh drive,walmount,knoxfield,3634,vic,19251010,8760281 +rec-1225-org,hayden,ballantyne,13,,nunnook,young,2077,nsw,19330812,3414771 +rec-4990-org,miranda,bunt,11,lalor street,,maiden gully,3672,vic,19050618,2333106 +rec-2598-org,diamond,branston,124,longstaff street,two sticks estate,grenfell,3108,nsw,19720728,7015483 +rec-1704-org,bradley,pegg,1,gask place,swanleigh,toukley,5600,qld,19190625,8214409 +rec-2333-org,sara,hage,89,collits place,the lodge,mount eliza,4217,vic,19871026,2919243 +rec-4784-org,sean,blackwell,2722,may maxwell crescent,gleeson park,stratford,5201,qld,,3485540 +rec-4280-org,lauren,ferri,121,hedger street,katherine low leve,banyo,3150,wa,19440118,9553756 +rec-3737-org,archer,brammy,119,free place,,killara,2795,vic,19190802,3738388 +rec-2412-org,lachlan,mandry,3,richardson street,lake chatsworth,christies beach,2040,tas,19220410,1565982 +rec-1111-org,kyle,rees,9,moorhouse street,,blacktown,5540,vic,19091121,8852766 +rec-2348-org,adam,tuckwell,38,mcmillan crescent,banksia village,broome,5037,nsw,19960528,8397512 +rec-3709-org,william,reid,18,martin street,australia arcade,smiths lake,2010,vic,19690624,7251376 +rec-3573-org,cooper,reid,11,,australian fair west,callala bay,4220,nsw,19080313,7357404 +rec-4248-org,joel,scheerlinck,11,boswell crescent,jarrah,bicton,2290,vic,19521024,9034415 +rec-3324-org,kane,whillas,150,mcmillan crescent,balmoral garden,shoalhaven heads,4879,qld,19680908,4013554 +rec-321-org,ruby,rogan,6,guthridge crescent,eldeslee vlge,parkside,6050,vic,19050201,6557114 +rec-2488-org,bree,boase,48,lyndon street,rathdangan,east melbourne,2087,nsw,19210614,2185538 +rec-44-org,natassia,grubb,224,merv waite street,kookaburra village,currambine,2871,vic,19960704,4790954 +rec-3984-org,david,sette,8,spring range road,jessiefield,villawood,2213,wa,19950603,9471099 +rec-3592-org,reganne,camp,4,colvin street,pine hill,parmelia,2010,nsw,19681013,1236601 +rec-638-org,jack,braddy,14,arndell street,parma farm,goodna,2450,nsw,19200906,9738539 +rec-1936-org,sophie,webb,6,twamley crescent,old weeroona,port augusta,3199,wa,19550621,6492579 +rec-2409-org,alexander,kermeen,2,cooksey place,,ormond,2036,qld,19490816,3562579 +rec-1090-org,alexandra,grainger,31,wambool street,vinda lodge,winthrop,3629,vic,19251017,9094252 +rec-1873-org,gabriel,green,18,alroy circuit,birrabilla,surry hills,4558,nsw,19901018,6199029 +rec-2918-org,ella,perriam,17,chipperfield circuit,kingfisher lodge,north bondi,5022,act,19090118,7801650 +rec-2377-org,lauren,soave,187,grounds crescent,strathleigh,denmark,3075,qld,19021209,5792462 +rec-4565-org,jared,klemm,78,,gloccamorra,bateman,6152,act,19770328,4616949 +rec-1526-org,dominic,elwan,91,tinderry circuit,larnach,coutts crossing,3350,vic,19890815,6995897 +rec-4458-org,mackenzie,boocock,81,tipiloura street,ursula,budgewoi,7027,nsw,19030720,6435654 +rec-2647-org,timothy,twigger,9,tunney crescent,argyle,toorak,5031,vic,19210926,4013666 +rec-4714-org,chloe,mclaine,9,appel crescent,milly milly,old toongabbie,3199,wa,,1418089 +rec-4008-org,nicholas,george,104,lyttleton crescent,brentwood vlge,dover heights,2500,wa,19470803,8827430 +rec-4483-org,amy,berry,241,barlee place,barraclear,christie downs,6056,vic,19651223,9112808 +rec-4720-org,jack,mccarthy,122,shackleton circuit,macquarie inn,westfield,3178,vic,19411214,5715719 +rec-3157-org,malakai,palethorpe,23,marsden street,boonal,gaven,2340,nsw,19031029,6356251 +rec-4928-org,lucas,coffey,16,halifax close,links court (cnr susanne s street,south maclean,4211,sa,19950414,5174809 +rec-142-org,emiily,jeffries,39,oxley street,paddy,blair athol,4051,wa,19250402,9596327 +rec-4085-org,shakirah,corver,167,noala street,willera,yarraville,2165,vic,19870127,1740012 +rec-4897-org,brooke,klimowski,222,beasley street,dungavon,woree,4113,nsw,19140805,6086531 +rec-4007-org,rachel,campbell,22,dutton street,the willows,geraldton,3129,nsw,19710314,6934561 +rec-1346-org,joel,sommariva,27,miranda place,sec 2737,rosebery,2264,wa,19681110,4235226 +rec-97-org,campbell,dichiera,478,quiros street,edenlea retirement,frenchs forest,2478,qld,19851030,7481927 +rec-3750-org,jacob,byrt,1199,binya place,bridgewater estate,wallsend,3155,wa,19420908,7691324 +rec-311-org,noah,maier,2,cromwell circuit,pine view,ryde,4700,nsw,19020410,4418189 +rec-294-org,ellie,badger,,dwyer street,glenlee,west lakes shore,3021,nsw,19001210,4656608 +rec-1294-org,jared,riddell,346,hawkesbury crescent,pine tree,berkeley vale,3015,nsw,19430121,2944608 +rec-4716-org,lucy,dunthorn,7,gratton place,thurlimbah,crows nest,4510,qld,19380809,7921182 +rec-2401-org,fergus,sherin,3,whitford place,locn 2093,mulwala,6064,nsw,19950727,1284784 +rec-284-org,jaslyn,jonjic,1,lindrum crescent,rowethorpe,ascot park,4213,vic,19250102,1023721 +rec-3849-org,georgia,hague,13,leahy close,,mount warren park,3218,vic,,4151813 +rec-1989-org,jordan,tuckwell,23,harricks crescent,holloway haven,atherton,4560,vic,19730908,6240898 +rec-3145-org,talia,holer,19,dennis street,,ashfield,2287,qld,19700608,3019342 +rec-1383-org,trinity,coulson,45,horsley crescent,wilga,para hills,3056,nsw,19920226,4445753 +rec-2878-org,jacob,badalassi,7,patey street,summer hill,surfers paradise,4035,nsw,19171217,9068304 +rec-2536-org,kayden,nguyen,52,batman street,willaroo,toowoomba,2763,nsw,19940208,6065480 +rec-3640-org,tara,white,1,bugden avenue,belvoir,mona vale,2282,vic,19870412,9595240 +rec-3924-org,mitchell,havelberg,2,dempster place,stonehouse,barwon heads,2750,nsw,19480510,7123931 +rec-1096-org,olivia,druitt,22,hacking crescent,westminster village,greenacre,5141,vic,19950307,7527562 +rec-1899-org,,stubbs,175,aspinall street,cruachan,albany creek,5162,vic,19380924,6966319 +rec-4506-org,samantha,ryan,12,forsythe street,murrawarra,winthrop,2107,nsw,19100210,2049144 +rec-2631-org,meagan,kelakios,14,boolimba crescent,chain gate,robina,2036,vic,19130619,6854344 +rec-4428-org,philip,hyland,77,lightfoot crescent,remo,ashwood,4102,vic,19071218,7390839 +rec-3153-org,pearson,weidenhofer,17,carruthers street,villa 147 henry kendall bayside,annandale,3850,nsw,19650218,8701573 +rec-4664-org,,czarnik,10,bunbury street,glenavon,ulmarra,4225,qld,19601222,3960160 +rec-3278-org,matthew,berry,560,westbury circuit,rosetta village,north ward,5082,qld,19820813,7825135 +rec-2599-org,sidonie,trenery,143,jerrabomberra avenue,lindoran,ashfield,2766,nsw,19150107,9307008 +rec-4337-org,blake,steed,17,chirnside circuit,rosetta village,balwyn north,2731,qld,19880408,3748565 +rec-1011-org,tara,bishop,7,namatjira drive,riverpark,rye,0812,nsw,19771030,3820896 +rec-1669-org,luke,fenwick,94,city walk,amberu,,6019,nsw,19071019,2392345 +rec-3621-org,lachlan,abdullah,7,daintree crescent,wondersun,sandgate,2537,vic,19480906,8781863 +rec-4340-org,kiana,jolly,23,ashcroft crescent,villa 2,airds,4507,wa,19220507,6113261 +rec-3305-org,ethan,,6,blamey crescent,kamilaroi cottage,canterbury,2480,nsw,19490228,6288497 +rec-603-org,ebony,zaffino,24,max henry crescent,ripon estate,newmarket,4350,nsw,19420501,8073270 +rec-557-org,ruby,braddy,11,allott place,c/-the student village,wynnum west,2260,wa,19440101,7323803 +rec-2467-org,zali,walpole,25,william hudson crescent,muralappi,brymaroo,3174,wa,19550701,9616019 +rec-2667-org,daniel,nykamp,10,jingara cottage,baanenuc,warburton,3806,nsw,19611221,3482588 +rec-4104-org,bethany,deakin,43,tazewell circuit,winchester downs,ballarat,5371,tas,19520625,4152955 +rec-883-org,ethan,wotton,10,crisp circuit,marlou,beenleigh,3400,qld,19260127,9022306 +rec-3722-org,emiily,scheel,12,cuscaden crescent,hopeview,jamboree heights,4816,vic,19521013,4479115 +rec-933-org,alicia,mollross,72,mcnamara street,corombie,kuraby,4552,qld,19050908,7195535 +rec-3893-org,ned,green,6,higgs place,rawdon,ourimbah,4880,sa,19840321,4691573 +rec-2473-org,chelsea,,18,crisp circuit,walnut grove estate,seven hills,6311,nsw,19040215,4172892 +rec-4950-org,charlotte,petersen,66,sturgess place,gerovin valley ldge,landsdale,2217,nsw,19190914,6017558 +rec-389-org,william,mccarthy,47,culgoa circuit,research station,evans head,6110,nsw,19010118,1681813 +rec-4413-org,cameron,white,178,carlile street,laureldale,alice springs,6108,nsw,19470605,1655664 +rec-1809-org,sophie,colquhoun,,solomon crescent,villa 3,whittington,3223,nsw,19111219,8261379 +rec-3349-org,lily,noble,24,stonehaven crescent,agarabi,emerald,2145,vic,19981015,3188848 +rec-2700-org,maxin,tchung,10,pullen street,emmaus vlge,cabarlah,3620,qld,19060604,6340831 +rec-2423-org,channing,hick,132,tunney crescent,,albury,3060,nsw,19201122,2347507 +rec-117-org,nicholas,huxley,12,biala place,c w v,anglesea,3109,nsw,19921105,6501674 +rec-2657-org,james,portlock,27,lightfoot crescent,linton,frenchs forest,5037,nsw,19330619,6392001 +rec-4971-org,william,white,34,mortlock circuit,ponderossa,chinchilla,3156,sa,19800517,1549841 +rec-3373-org,alisa,clarke,25,langdon avenue,cliffdon park,eaglehawk,2100,nsw,19760105,1902858 +rec-2489-org,thomas,green,10,dumas street,bonnie doon,innaloo,5108,nsw,19340204,6817957 +rec-1382-org,bridget,maynard,82,irvine street,barwon station,bassendean,4503,nsw,19250615,7440041 +rec-3499-org,kydan,burford,249,garran place,cape hawke hosptl medcl centre,launceston south,2162,nsw,19530728,5743011 +rec-4314-org,samuel,david,62,rodway street,apmnt 501,north arm,2166,qld,19560208,8268023 +rec-2798-org,kane,carbone,15,penrhyn street,solander centre,deer park,4030,sa,19960506,9098940 +rec-3405-org,kane,grainger,15,may maxwell crescent,meadowvale village,dungarubba,2281,vic,19350222,6671921 +rec-1911-org,olivia,gully,3,cockburn street,booligal,,2163,qld,19150112,1992595 +rec-2462-org,ruby,garnsey,317,harcourt street,navan park,north narrabeen,4163,nsw,19731030,3572082 +rec-3279-org,hannah,ho,13,bradfield street,cremona stud,hurstbridge,2795,nsw,19180207,6938730 +rec-3535-org,michael,nguyen,6,lukin place,sunnyspot farm,beaumont,2213,nsw,19130316,6962550 +rec-1722-org,zachary,mccurdy,9,blandon place,dinta,mirrabooka,4171,nsw,19771202,3404376 +rec-589-org,,bennier,7,ruthven street,walnut grove estate,chinchilla,5723,qld,19910528,7222769 +rec-4949-org,brianna,blackwell,20,john russell circuit,yarrandoo,cremorne,3192,nsw,19440515,6543804 +rec-1493-org,ebonie,quinton,143,,warialda,,3910,qld,19781228,7282886 +rec-2070-org,christopher,lock,9,swinden street,heritage est,campsie,3046,vic,19200617,3438940 +rec-4767-org,thomas,macphail,33,rose scott circuit,glen ayre,maryborough,4000,vic,19021218,6364936 +rec-3268-org,makenzi,lowe,10,pandanus street,the homestead,springfield,2745,vic,19370123,3748468 +rec-1708-org,taliah,mccarthy,,bourne street,locn 3439,greenacre,3198,nsw,19730822,7901066 +rec-931-org,matthew,goldsworthy,5,karuah street,,cabramatta,5554,wa,19771013,5645462 +rec-3534-org,christian,jolta,2,jerrabomberra avenue,yambungan station,cecil hills,4702,vic,19481117,6961701 +rec-8-org,nicholas,procter,1,cavanaugh street,sherwood,leeville,2089,nsw,19031219,2662272 +rec-1728-org,daniel,rafanelli,1,warragamba avenue,aptmnt 240,eight mile plains,3233,nsw,19450221,3820840 +rec-2626-org,thomas,snoad,26,mcclintock street,st francis vlge,warilla,4551,vic,19790413,3010606 +rec-3189-org,,ongkiko,15,murray crescent,rowethorpe,corowa,6156,nsw,19740627,8899763 +rec-2402-org,makenzi,boase,29,box hill avenue,carrington retrmnt vlge,oak flats,2036,sa,19770104,4259426 +rec-754-org,raquel,staude,44,merv waite street,,terrey hills,3078,nsw,,2866688 +rec-724-org,brianna,parr,12,sid barnes crescent,,orange,4744,qld,19210526,7179398 +rec-2913-org,bertie,faraday,30,sid barnes crescent,c/-bundoora park,lismore,0832,qld,19840818,4606633 +rec-665-org,daniel,siew,41,culgoa circuit,brindabella specialist centre,cooloongup,2085,wa,19341220,7170445 +rec-1144-org,joel,shepherdson,515,elvire place,glanworth station,mayfield,2000,vic,19250903,9617566 +rec-462-org,sienna,ryan,3,laycock place,fred lean hostel,lalor,4702,nsw,19680321,4809923 +rec-1476-org,deakin,shadbolt,8,julia flynn avenue,allunga,alice springs,3550,sa,19270523,8908609 +rec-127-org,imogen,boyle,57,gilmore crescent,village walk (cnr high s street,safety bay,3088,qld,19360622,4299413 +rec-1222-org,faith,dougal,921,levey place,minora cotge,toowoomba,2905,nsw,19550808,1574726 +rec-1393-org,matthew,speight,8,worrall street,the willows,lower beechmont,6230,sa,19590301,1641889 +rec-3659-org,alexander,vincent,51,gallagher street,top end,belmont,2333,qld,19150726,3732438 +rec-1191-org,mitchell,campton,37,watt place,merricroft,brandon,7270,nsw,19931028,2226898 +rec-2689-org,ainsley,robison,23,atherton street,villa 1/4,deer park,3418,nsw,19310531,4102867 +rec-4672-org,naomi,bishop,40,zox circuit,anzac house (cnr archer s street,lismore,2168,vic,19771008,3069847 +rec-1855-org,livia,white,,chaffey crescent,kooyong,drysdale,6111,qld,19180719,8718575 +rec-4421-org,joanna,needham,238,britten-jones drive,gogulger stock,albury,5081,qld,19760124,3761376 +rec-2831-org,lucas,simmonds,20,blackwood terrace,lyndon lodge,kilmore,6333,wa,19101023,5919385 +rec-2884-org,cooper,kerrod,,irvine street,lorong kampong,goodna,2176,vic,19870610,1351213 +rec-4919-org,mia,jolly,15,findlay street,hayfield vlge,kincumber,3995,qld,19171012,8801194 +rec-4024-org,katelin,wheatley,35,blakey close,derwent wtrs,hackham west,4515,,19130924,2489779 +rec-2001-org,antonio,hage,34,grigson place,warrawong,tinamba,3636,nsw,19330331,8493945 +rec-4649-org,jacob,watts-endresz,6,maranoa street,rubern cottage,cowra,2046,qld,19400708,4839960 +rec-4111-org,hannah,campbell,8,cowan street,plantation caravn park,casino,2113,qld,19531029,3909212 +rec-588-org,sana,nguyen,242,gibbs place,fleetview,bayswater,2154,vic,19000624,2842614 +rec-4103-org,jack,badman,8,kardang street,gowrie,point samson,4670,nsw,19070912,1172421 +rec-1005-org,micah,green,26,blakely row,kelanna,harbord,4502,wa,19911228,2687580 +rec-1796-org,jake,george,22,springvale drive,inverwood,belmont,3350,wa,19731020,3265845 +rec-4320-org,holly,du,151,harricks crescent,shopping village,brighton,2162,vic,19390830,5581617 +rec-2109-org,matthew,broadby,4,hinton place,blck 1089,raymond terrace,2145,vic,19740703,2775852 +rec-3759-org,michael,leslie,2,kirwan circuit,blenmore,bangor,3150,qld,19350423,7283233 +rec-2381-org,thomas,wasley,4,tantangara street,eden park,frankston,5086,wa,19170505,7062733 +rec-3975-org,deakin,shepherd,17,torrens street,south macroom,rose bay,3058,nt,19011229,5190083 +rec-3197-org,jack,browne,80,bargang crescent,tulgeywood,carlingford,3163,qld,19131123,2843200 +rec-84-org,george,de boar,304,gungurra crescent,black snake creek,exeter,2430,nsw,19051129,2671881 +rec-77-org,gillian,chandler,232,caladenia street,,gowrie,3150,nsw,19960922,4237925 +rec-1026-org,lochlan,weaver,30,carnegie crescent,gantham,wendouree,3198,nsw,19990511,5721590 +rec-2300-org,georgia,dasilva,29,trumble street,willaroo,bayswater north,7320,vic,19591226,6737283 +rec-2145-org,benjamin,morrison,2487,noongale court,fairfield waters,st albans,2840,vic,19520110,9155694 +rec-1677-org,nicholas,de la cruz,1,pelsart street,rosetta village,vermont south,4017,vic,19180823,4669159 +rec-4669-org,brooke,hendricks,34,eucumbene drive,lake downs super fine merino stud,narooma,3177,nsw,19450517,6179346 +rec-2268-org,taliah,buitendyk,19,emily bulcock crescent,palmwood court,flinders park,5109,sa,19950831,1039913 +rec-2516-org,sarah,wheatley,24,oxley street,jaspars,kellyville,2430,wa,19640212,3619638 +rec-2590-org,madeleine,birthisel,,marulda street,nunkeri,abbotsford,2820,vic,19960805,7177159 +rec-1474-org,samuel,satterley,,osmand street,cascade condo,scotland island,6151,wa,19620515,1430466 +rec-108-org,madison,seddon,9,wirilda street,killarney,rosebery,4109,vic,19770403,7497285 +rec-2122-org,caleb,campbell,3,port jackson circuit,port 363v,spencer park,3084,vic,19020505,9476622 +rec-658-org,david,hobson,14,vagabond crescent,dugout 65,patterson lakes,4880,wa,19010305,7666240 +rec-3282-org,indiana,clarke,9,wade street,merlewood,llandilo,2077,qld,19450816,7669254 +rec-1982-org,rachel,elstob,3,mullan street,,ivanhoe,4350,sa,19570111,5616006 +rec-2654-org,bailey,lu-bow,12,barrallier street,roskhill,gailes,5576,vic,19530922,2252430 +rec-2422-org,keziah,thind,111,tate street,unt 1,kincumber,5043,nsw,19561112,5822993 +rec-1719-org,blake,mohammadi,30,propsting street,,surrey hills,4560,vic,19721222,7654499 +rec-2566-org,kelsye,bullock,19,torrens place,the meadows,williamstown,5251,tas,19581001,3037931 +rec-4448-org,madison,white,58,morant circuit,,highton,4118,qld,19920901,6806350 +rec-3675-org,meg,blunden,602,allchin circuit,lingdale,ballarat,0810,qld,19470831,7587560 +rec-3690-org,nathan,weaver,4,tenison-woods circuit,,glenmore park,2776,vic,19881101,4634662 +rec-2757-org,georgia,asher,38,onslow street,rsdb 284,prospect,5434,nsw,19801009,6899844 +rec-3261-org,rhett,matthews,16,cadell street,warhaven home,surfers paradise,3911,nsw,19870715,5123065 +rec-1182-org,ella,wasley,58,guthridge crescent,crown allotment,carole park,5112,vic,19411214,3051473 +rec-4572-org,lachlan,reid,20,starke street,busbey's flat,caulfield,2611,vic,19600906,3614628 +rec-4401-org,,weller,39,,heathfield qld,keilor east,4304,nsw,19640411,3408564 +rec-3683-org,alicia,hyland,112,fullagar crescent,ambervale,keilor east,5116,vic,,9571063 +rec-3953-org,isabella,concannon,15,alli place,mlc centre,keilor east,0822,sa,19410803,1922236 +rec-1598-org,riley,neville,51,irvine street,the canberra hospital,lockhart,3123,qld,19430319,3568574 +rec-640-org,adela,dudgeon,6,maitland street,craiglea,corio,3146,vic,19181027,2679352 +rec-4173-org,mia,fenwick,8,dunstan street,vinder lodge,keilor east,2441,qld,19240220,7504708 +rec-1815-org,aleisha,spratt,16,wild street,ashbank,seaton,4310,sa,19920328,6548039 +rec-2944-org,caleb,menzies,32,fowles street,jandarra,mill park,2753,nsw,19460702,8515576 +rec-314-org,chelsea,meaney,74,blamey crescent,nuffield village,pymble,4812,nsw,19151116,3266277 +rec-1958-org,emiily,gruener,14,jarman place,girrahween homestead,kalorama,3003,vic,19780128,4299404 +rec-230-org,taylah,leaver,5,newlop street,moreton,florey,3150,nsw,19130703,3251860 +rec-3620-org,diamond,mason,371,madigan street,brumby's run,flora hill,2250,nsw,19161109,2452931 +rec-1587-org,vendula,middlin,4,baldwin drive,,orbost,6108,wa,19790820,4808614 +rec-2361-org,stephanie,rasic,5,downer place,vlla 18 pacific bay resort,springfield,3523,nsw,19970123,3232396 +rec-4789-org,jacob,,24,petre street,lochadair,berkeley vale,2320,nsw,19971123,9161275 +rec-2718-org,jye,feleppa,72,fishburn street,bowtells caravn park,carrara,3630,,19691127,9051864 +rec-1136-org,lachlan,clarke,19,bunbury street,kildurham,nhill,3805,nsw,19180501,2371874 +rec-650-org,peter,kennealy,30,moorehead place,sun valley caravan park,ingleburn,3740,wa,19070108,5173077 +rec-2315-org,flynn,simmonds,5,partridge street,,goonellabah,3021,nsw,19730524,8183648 +rec-3736-org,alia,mogavero,24,beattie crescent,heritage est,rye,3142,nsw,19170315,2991381 +rec-1778-org,rosie,dieckmann,1360,mckinley circuit,hamden place,panorama,2225,nsw,19820207,8380171 +rec-1370-org,breeanne,browne,5,ebenezer street,kilburnie,toowong,5072,nsw,19511023,6301444 +rec-1535-org,madeline,grubb,23,stonehaven crescent,plain view,macmasters beach,3149,vic,19250427,6770252 +rec-4921-org,brooke,waller,25,goyder street,watchorns hill,st lucia,3995,wa,19680216,5166618 +rec-3958-org,zach,saul,47,franks place,avenal,willetton,5083,qld,19320823,5326638 +rec-3401-org,toby,stanley,32,craydon place,lenaroy,heywood,2904,wa,19381214,3931157 +rec-4711-org,hugh,bishop,42,denovan circuit,ironbark ridge,cherrybrook,4470,nsw,19790408,3465665 +rec-4335-org,elana,wiechec,11,belconnen way,upper ross medical centre,,4077,sa,19460820,3124171 +rec-1372-org,brooke,burford,85,smiths road,moolooboola,kinglake west,4560,nsw,,8804970 +rec-2861-org,katherine,hyland,16,kootingal street,,montmorency,3023,nsw,19400714,9161147 +rec-4588-org,deakin,nguyen,142,pasco street,erins rest,marlo,4560,tas,19060928,1380475 +rec-1939-org,oakleigh,rundle,194,mcdowall place,tatyara,bridgeman downs,2259,nsw,19860110,9292818 +rec-1609-org,oscar,hartland,16,prout place,gummin gummin,moonah west,3218,nsw,19440709,6879379 +rec-4791-org,sophie,rivers,7,dines place,john flynn medical centre,prospect,2094,tas,19010909,4278751 +rec-2428-org,benjamin,blake,11,tantangara street,summit cottage,oaklands park,2640,wa,19270916,6285591 +rec-969-org,alexandra,clarke,17,hancock street,currimundi garden,gosford east,2304,sa,19311219,6631451 +rec-3394-org,emiily,finlay,20,temperley street,lincoln close,bellevue hill,2231,qld,19000801,1739435 +rec-4725-org,erin,buttrose,487,greeves street,aprt 22,clarkson,5172,vic,19810203,5640265 +rec-4621-org,alivia,dixon,15,northbourne avenue,kergunyah,sandilands,2142,nsw,19961001,6449400 +rec-2691-org,ellorah,verco,11,girdlestone circuit,kingston tower,clifton springs,4152,,19340706,1075870 +rec-4370-org,mikayla,berryman,1,luckins place,bulga wine estates,captains flat,2067,vic,19130516,8135586 +rec-1532-org,jesse,nguyen,,waddell place,ardmona,wagaman,2810,qld,19470716,9161884 +rec-217-org,chloe,paine,19,,mortlach,bicton,7024,,19571105,4200847 +rec-3841-org,esme,leslie,89,galleghan circuit,five oaks,brighton,6007,tas,19520521,7091838 +rec-1497-org,jessica,hirzel,162,angas street,glendale stud,stoneville,3029,vic,19710723,8829577 +rec-900-org,kyle,felmingham,20,cassinia street,marella,kingston,3936,nsw,19121120,1300375 +rec-4474-org,sarah,rosa,11,kangaroo court,glen shiel,wamberal,3144,vic,19330424,3530952 +rec-2004-org,emiily,rook,10,hambidge crescent,sec 26,north ryde,4825,vic,19880525,6262463 +rec-540-org,mitchell,shepherd,341,rich street,,balhannah,2077,nsw,19620819,8291804 +rec-1856-org,bethany,large,9,hayball place,hawkhurst cottage,mount stuart,6017,nsw,19541211,6608468 +rec-4524-org,michael,coulson,78,mackellar crescent,koah lodge,marsden,3564,vic,19680508,6597953 +rec-3761-org,joshua,ho,23,warragamba avenue,mile beach caravan park,east maitland,3181,nsw,19320427,9710227 +rec-1329-org,ruby,morrison,,nemarang crescent,armidale hospital,whitfield,2100,,19280502,4180920 +rec-2523-org,tyler,edgecombe,9,willoughby crescent,,bray park,2324,vic,19551113,8936270 +rec-4606-org,jessica,campbell,43,deloraine street,,bribie island,2756,vic,19300613,9015825 +rec-4018-org,jessica,radic,1,edmondson street,kimbe,raceview,6280,qld,19120920,7256699 +rec-2920-org,amber,burnell,11,captain cook crescent,fig trees,kilsyth,2283,qld,19820812,3394398 +rec-3638-org,renee,browne,215,vale place,,warrandyte,2251,nsw,19490724,9563421 +rec-654-org,devan,riddell,33,mueller street,,thornleigh,2257,nsw,19391217,4921767 +rec-4357-org,ethan,coleman,64,ragless circuit,,hindmarsh west,4701,nsw,19650701,9807949 +rec-833-org,brianna,lock,202,basedow street,emily farm,blair athol,2580,,19460618,7959981 +rec-3927-org,sophie,rees,5,dangar place,thomond,sylvania,2541,vic,19740419,6279787 +rec-366-org,callum,webb,110,callaghan street,emerald garden,lockleys,3166,vic,19000429,2494767 +rec-3429-org,imogen,camp,14,haines street,roskhill,gretna,4213,,19681214,9359429 +rec-2158-org,jenna,neumann,22,percy crescent,,lennox head,5043,qld,19821024,7587719 +rec-328-org,ronan,zatorski,13,lott place,bobblegigbie,ringwood east,5109,qld,19870107,5925683 +rec-500-org,sonja,clarke,7,carrington street,la rhune,coolaroo,6317,vic,19750513,4511800 +rec-1794-org,sienna,cacciotti,57,nullagine street,avonlea park rmb 4045,parkinson,3168,qld,19770318,1586091 +rec-2476-org,abbey,simmonds,13,greenvale street,haven court,aspley,4069,qld,19141205,2403689 +rec-2498-org,lachlan,geduld,2,karrugang circuit,jacqoona station,mount eliza,4306,vic,19520703,3086091 +rec-1837-org,jacinta,webb,108,rodway street,2nd last on right,elwood,2019,vic,19680215,3880973 +rec-948-org,molly,clapham,25,thring place,watamurra,orbost,3305,nsw,19621123,7549694 +rec-985-org,jordyn,buttrose,10,argyle place,,frankston,6016,qld,19350206,8629525 +rec-2840-org,marianne,kastrappis,,hansen circuit,hotel laguna,seven hills,3175,vic,19490106,2934534 +rec-4814-org,ben,conrick,19,marsden street,the meadows,page,3108,nsw,19760130,5241188 +rec-3275-org,cooper,lemke,2,albermarle place,iron shoe lodge,thornbury,3082,qld,19881107,7332841 +rec-3606-org,flynn,bishop,16,solomon crescent,,burwood,4165,qld,19270515,3604457 +rec-1246-org,koben,ryan,17,foreman place,st francis village,eastwood,3101,nsw,19341114,2722891 +rec-694-org,charlie,kastrappis,81,hedley street,parkland motor village,bonbeach,2515,vic,19330630,7470082 +rec-459-org,joshua,arbalis,60,gabriel place,the meadows,lilydale,2045,vic,19230819,5884108 +rec-497-org,emiily,cobbin,3,knox street,robina,camperdown,2230,wa,19991209,9931751 +rec-2021-org,angelica,capurso,3,heales place,coulter court,toormina,2166,act,19840719,7201624 +rec-2321-org,brody,berry,98,edwards street,medical centre,albion park rail,3660,vic,19620118,4534503 +rec-393-org,alexander,,41,fink crescent,rubicon,orange,3041,nsw,19620324,7933489 +rec-3225-org,kyle,careless,75,mcbryde crescent,rowethorpe cygnet hostel,ivanhoe,6076,sa,19701116,3208751 +rec-219-org,hugh,dorsey,25,sid barnes crescent,rowethorpe,werrington,2144,qld,19000625,5695716 +rec-4698-org,brinley,bauman,14,prout place,amblin caravan park,gaven,3021,vic,19360411,7377453 +rec-4212-org,ryan,sherrington,17,stopford crescent,lvel 2180,caulfield north,4745,qld,19680507,8315298 +rec-4793-org,joshua,blake,5,norman street,broombie stud,taringa,6009,vic,19740218,5842286 +rec-2133-org,brooke,clarke,4,namadgi circuit,emerald garden,ascot vale,5031,vic,19430823,6719097 +rec-1772-org,david,candida,220,hinchcliffe place,arawang,malvern,3146,tas,19781104,6582947 +rec-3302-org,blaize,koopman,17,allison place,aldersyde estate,balwyn north,4650,nsw,19110608,7823755 +rec-2450-org,thomas,wyllie,512,brand street,ferndale,rossmoyne,5042,vic,19040823,9017484 +rec-855-org,louise,thorpe,19,cooper place,lazy acres,curra,3150,wa,19910823,1563881 +rec-629-org,william,lund,8,bridge street,pevensey,bowral,4350,qld,19211017,4144401 +rec-2081-org,daniel,morrison,21,canberra avenue,st columbus retirement centre,como,2007,nsw,19610731,7414976 +rec-3922-org,joshua,millar,4,chowne street,lirambenda,springfield,2088,qld,19410825,6371427 +rec-1885-org,archie,dokas,6,tewksbury circuit,shalvah,malvern east,3163,nsw,19400807,1265030 +rec-3733-org,jacobie,meaney,80,maitland street,north arm,sandgate,2110,nsw,19820219,3123016 +rec-3466-org,benjamin,donnolley,29,downward place,ocean star villas,downer,7320,vic,19881009,7579389 +rec-828-org,renee,musolino,19,spalding street,rosehill,willetton,4820,nsw,19631219,7754049 +rec-4753-org,emiily,van rossen,36,giltinan place,narla vlge,surrey hills,3746,vic,19010822,3981817 +rec-2149-org,mikaela,mccarthy,62,derrington crescent,john curtin hostel,denistone east,3564,vic,19811001,8749270 +rec-4536-org,ruben,weaver,,stevenson street,tallinga park,wahroonga,5280,vic,19190427,1196393 +rec-3823-org,caitlin,terend,47,fullagar crescent,hounbank,broadmeadows,2370,vic,19740828,3463191 +rec-4407-org,rebekah,clarke,5,centaurus street,country house 5 milton park,dianella,2447,nsw,19120407,9439871 +rec-3468-org,elizabeth,browne,11,carina street,ocean pines caravn park,flinders park,2487,vic,19061213,2560358 +rec-3055-org,gabrielle,butt,35,mawson drive,glenmore,,3187,vic,19830918,7581914 +rec-15-org,kyle,brain,8,stillwell place,gillin park,bellambi,2320,,19630812,8358959 +rec-4468-org,tai,stanley,29,blamey crescent,ocean star villas,gordonvale,3915,nsw,19141011,4459842 +rec-4102-org,joshua,donaldson,157,macfarland crescent,boonawah,belmont,2615,qld,,9586561 +rec-3419-org,hayden,piechocki,72,shackleton circuit,calimna,murtoa,3437,vic,19291001,1731879 +rec-1487-org,alex,plumb,41,mcrae place,castlewood,pakenham,4214,nsw,19460521,2390847 +rec-4155-org,georgina,wedmaier,7,duffy street,glendora,eulo,2020,qld,19410630,4581426 +rec-3501-org,caleb,blake,15,hawker street,,adamstown heights,3020,nsw,19530105,6351072 +rec-1623-org,saara,jervis,1,florance place,break-o-day,success,2456,wa,19170712,7788045 +rec-1242-org,jasmyn,marceta,35,cabena court,ascot park,ashfield,5011,wa,19821129,6095474 +rec-4351-org,leon,mandica,25,antill street,upper green farm,laverton,2115,sa,19540826,3910447 +rec-4038-org,nathan,cannell,13,theodore street,iona downs,emerald,2570,nsw,19000823,6294140 +rec-3480-org,kyle,kowtun,69,hambidge crescent,,frankston,3056,wa,19380303,2024772 +rec-4855-org,mystique,linedale,8,finniss crescent,kodootonga,nhill,2795,vic,19160905,3629782 +rec-297-org,alysha,nguyen,7,hurley street,avenue road,brunkerville,3944,nsw,19970304,4977712 +rec-634-org,charlotte,maynard,,mckillop circuit,norley,eden,2339,qld,19420418,7402311 +rec-4372-org,lachlan,mcgregor,29,dexter street,champsaur,acacia ridge,2430,nsw,19140121,2910651 +rec-3297-org,alicia,lamonaca,15,vickers crescent,ballawinna stud,deakin,6701,nsw,19780805,4465146 +rec-1425-org,alysha,reid,747,clive steele avenue,townhouse 5,kiama heights,3170,vic,19940904,7294389 +rec-307-org,macey,pascoe,9,macrobertson street,diamond water cvn,highett,7320,nsw,19470710,5499383 +rec-4044-org,ebony,holme,25,derry street,laure,allambie heights,2024,qld,19340630,1510761 +rec-1994-org,haylee,dolan,49,carrington street,brentwood village,deer park,3047,nsw,19690801,4703920 +rec-369-org,caitlin,dixon,42,leahy close,rowethorpe,midway point,3926,vic,19980907,6375470 +rec-932-org,amber,webb,25,toolambi street,villa 235 henry kendall vlge,helens hill,6156,sa,19470715,7791091 +rec-966-org,alexa-rose,green,30,sawicki place,,montmorency,2150,nsw,19290805,2059593 +rec-2288-org,joel,green,708,wangara street,gallagher house,burpengary,4670,qld,,9018656 +rec-512-org,campbell,colquhoun,143,healy street,lakeview caravn park,greenfield park,3186,vic,19490831,1130272 +rec-49-org,madison,bradshaw,13,jardine street,,norwood,2335,sa,19490115,8836136 +rec-1979-org,lewis,coleman,24,northbourne avenue,our folly,toowoomba,2145,nsw,19341227,4576898 +rec-3250-org,emiily,rau,8,kennedy street,hobbit hole,pappinbarra,3141,tas,19530208,6681232 +rec-4638-org,holly,collinson,195,burn street,rosary village,four mile beach,4221,qld,19671102,7790499 +rec-3370-org,nicholas,malin,2,hearn street,miami,acton,5161,nsw,19020404,6007254 +rec-1753-org,brianna,ranson,143,scott street,blue hills,mitcham,4215,vic,19480409,2774725 +rec-836-org,breony,aujard,166,florence taylor street,clear creek,flinders park,3151,vic,19870124,4700161 +rec-2506-org,teagan,wreford,17,preston street,wollartukkee,forest hill,4413,sa,19410923,2436763 +rec-1965-org,elton,noble,1,molineaux place,willows trees,port vincent,2208,qld,19350729,1466352 +rec-506-org,madeline,hage,15,banner street,oreel,bayswater,4860,nsw,19640929,6710911 +rec-659-org,anneliese,skvaril,24,julia flynn avenue,,batemans bay,2456,nsw,19141122,5572688 +rec-3345-org,bailley,fair,27,lacey place,sunny-brae,auburn,3757,wa,19730509,9201783 +rec-76-org,,miteff,10,tristania street,goldenoaks village,brookvale,3156,nsw,19550618,9393286 +rec-262-org,jake,soden,3,hardwicke place,orange specialist medical centre,bligh park,2852,nsw,19461110,4287888 +rec-1077-org,sarah,dixon,107,corella place,stapleton station,kelmscott,2304,qld,19911101,1565265 +rec-1453-org,zachary,rees,69,ainslie avenue,rainbow end,maryborough,6510,vic,19760322,6740355 +rec-3517-org,dante,priest,18,bamford street,robin's cottage,willetton,2617,nsw,19150225,9740161 +rec-1808-org,gemaley,covino,158,naismith place,doribank,paddington,4551,qld,19060725,6706561 +rec-4287-org,keely,szymczak,17,kosciusko avenue,trevena,kings park,2137,vic,19711125,2525516 +rec-4371-org,jai,riddell,8,jane price crescent,industrial estate,mount helen,2830,nsw,19720618,9147307 +rec-750-org,kiarnee,rees,1,doonkuna street,witsend,robertson,4214,vic,19760907,8222581 +rec-3753-org,holly,spratt,133,spafford crescent,,st clair,3337,nsw,19130210,9895857 +rec-4518-org,jack,ryan,,popplewell place,condor,taigum,3156,wa,19190424,1285717 +rec-4293-org,adriana,jenko,28,samuels crescent,warialda,cambooya,3691,vic,19620402,8518234 +rec-203-org,daniel,hebberman,181,limestone avenue,rowethorpe,sunshine north,6168,qld,19550320,9996479 +rec-2854-org,nathan,bishop,2,osburn drive,noosa village shopping centre,woodhill,2530,vic,19961008,6472175 +rec-3819-org,michael,white,20,ulm street,elmwood,jindalee,6323,vic,19560227,4757924 +rec-4594-org,matilda,bissett,185,gundulu place,bandaroo,taree,5044,wa,19830319,5260083 +rec-182-org,holly,webb,40,kirkland circuit,meemar,wahroonga,3149,sa,19790526,5682368 +rec-64-org,emiily,godfrey,5,federal highway,tannamurra,bundaberg,4065,qld,19281007,8378813 +rec-1580-org,thomas,coleman,35,davies place,apt pc,port elliot,4819,nsw,19660918,6106983 +rec-523-org,,maslich,38,ibis street,wee wilbertree,carine,3337,vic,19360105,3611483 +rec-2326-org,tayah,de lucia,210,eugenia street,electorate office,rainbow beach,4567,qld,19520703,1220730 +rec-3403-org,kyle,butt,7,beaurepaire crescent,brightwater villas,bunbury,4750,nsw,19650102,8272544 +rec-4129-org,nellie,yunupingu,5,pyrie street,afflexian,woongarrah,4556,nsw,19480304,8638954 +rec-4375-org,sascha,burford,1,o'connell street,rowethorpe,berrimah,3212,vic,19801119,2679424 +rec-4757-org,dillon,cranefield,9,loch street,rowethorpe d1,lutwyche,2650,qld,19601109,7417124 +rec-20-org,brody,lowe,100,waller crescent,keanor,armidale,4055,sa,19900409,8444970 +rec-1992-org,daniel,george,28,riley place,colooli village,paddington,2603,nsw,19580820,4862317 +rec-1389-org,alana,reid,1,baume crescent,claymore springs,yarraville,3128,vic,19200219,9147920 +rec-4177-org,hayden,paine,77,neales street,tara hills,richardson,5118,tas,19040321,2360796 +rec-2254-org,bree,beattie,21,kosciusko avenue,somerset cottage,mooloolaba,6210,vic,19460703,1384798 +rec-3211-org,isaac,lowe,3,hemmings crescent,timber haven,williamstown,2380,vic,19880722,2762848 +rec-1226-org,seth,moody,42,scantlebury crescent,the lodge,sippy downs,3156,vic,19270824,6853828 +rec-3557-org,alessandra,druitt,4,frome street,brightwater villas,dunsborough,2795,qld,19810517,7828185 +rec-689-org,joshua,every,14,scoble place,hawkins masonic vlge,gray,4216,nsw,19241220,9182595 +rec-2429-org,dylan,white,8,dirrawan garden,oakdale,manyana,2795,vic,19160414,8832194 +rec-4709-org,jordan,gripton,8,wangara street,navan park,somerset,2070,qld,19701212,3869041 +rec-3988-org,noah,eileen,5,howitt street,rosebery hill,hinchinbrook,6061,vic,19120313,1859126 +rec-33-org,ryan,clarke,42,goodchild street,villa 5,sandy bay,2095,nsw,19940903,9100049 +rec-3300-org,ayden,finlay,6,holyman street,milmilland,cowra,2225,nsw,19740203,5706958 +rec-1223-org,jade,smallacombe,16,beagle street,castle reagh terrace,greenwood,3181,vic,19770726,4529850 +rec-1761-org,jai,hartkop,29,carr crescent,palestine,bangor,3013,sa,19150518,4003978 +rec-1119-org,rachel,george,9,meares place,brentwood village,tuart hill,6008,nsw,19910224,4083414 +rec-709-org,hannah,bennell,154,southwood retreat,walkers orchard,wheeo,4118,qld,19830601,2694324 +rec-2031-org,roisin,white,324,kirkland circuit,r s l retrmnt vlge,thornlands,3178,nsw,19120924,5293853 +rec-4708-org,ellie,hamon,17,lyon place,oxonia,kentucky,6163,vic,19750322,4621557 +rec-635-org,james,thorpe,27,cusack place,rockview,largs north,4580,qld,19410413,3938054 +rec-2279-org,elizabeth,madigan,8,port jackson circuit,rosedale,pannawonica,3182,tas,19200527,7796244 +rec-977-org,jordan,ryan,5,schutt street,euroka,o'connor,4306,vic,19030111,1659852 +rec-3097-org,nathan,chorley,931,mockridge crescent,rosedale,laverton,4061,vic,19300730,6046935 +rec-1160-org,lily,hage,33,piddington street,ocean star villas,ballina,3204,vic,19550103,6486441 +rec-2618-org,kristen,reid,,mckillop circuit,casuarina village,page,3128,qld,19830801,8552844 +rec-161-org,tanyshah,david,3,redcliffe street,northwood park,palana,3166,qld,19680823,6914643 +rec-1141-org,jack,huddy,6,kirkland circuit,willow lodge,blackburn north,6275,vic,19000604,8374407 +rec-2200-org,kiria,pamnany,20,gatton street,cypress garden,beechmont,4301,vic,19040202,8317110 +rec-4648-org,charlie,reid,16,gannon place,bennett chambers,woollahra,2518,tas,19150113,1045143 +rec-4043-org,connor,hope,24,wyselaskie circuit,hidden valley estate,golden bay,3070,vic,19190806,1644424 +rec-2204-org,jordyn,white,103,amess place,tannamurra,toormina,4700,sa,19051210,6149930 +rec-3272-org,zara,white,189,mackey place,doctors flat,hawthorn,4306,wa,19320621,7744887 +rec-4047-org,bradley,offoin,33,mcwhae circuit,west park,scarness,2047,vic,19180420,4715993 +rec-1086-org,william,graue,77,munro street,ellwood,kurri kurri,2200,sa,19301127,7287444 +rec-2037-org,freya,mason,10,barnett close,dianella masonic village (cnr cornwell s,clifton springs,7301,wa,19241109,1571902 +rec-2530-org,harrison,gillard,18,melba street,ningana,loganlea,2162,qld,19840128,8021771 +rec-811-org,lachlan,grosser,68,st clair place,settle downs,st albans,4014,nsw,19330725,5961769 +rec-2069-org,olivia,allanby,9,douglass place,,dalby,6324,vic,19830328,9889496 +rec-2619-org,james,white,134,macdonnell street,bindaree,nollamara,5127,vic,19090530,8089512 +rec-266-org,megan,kristalyn,6,balfour crescent,sunnyview,knockrow,6163,sa,19200816,6619419 +rec-2167-org,sarah,campbell,6,loddon street,lakefield,miami,3227,qld,19321221,5872484 +rec-3341-org,riley,grubb,377,abercrombie circuit,lapstone,burwood,6330,vic,19040327,2728675 +rec-4900-org,charlotte,,8,lendon place,lexington,frankston,6210,nsw,19080713,2597760 +rec-1735-org,holly,alderson,1,chippindall circuit,rockview,broadmeadows,3000,nsw,19770722,3799511 +rec-3037-org,jacob,gillard,25,batchelor street,villa 2,rossmore,3910,vic,19970424,9592273 +rec-2507-org,brooke,burnell,4,pickles street,rowethorpe,woombye,2478,qld,19300112,4694746 +rec-1503-org,jasmine,ryan,49,spofforth street,kirra vista,daylesford,3072,nsw,19161002,7987659 +rec-3625-org,zachary,lowe,10,knox street,myliton,ulverstone,5604,wa,19690408,6750174 +rec-3454-org,heath,menard,89,,yarrimbah,port broughton,2650,nsw,19220820,3136077 +rec-73-org,eloise,afford,188,denny street,fairfield housing bg,caves beach,2118,nsw,19090702,8884493 +rec-326-org,daniel,heron,2,gaunson crescent,munmurra park,jesmond,2456,nsw,19091018,9362456 +rec-1746-org,lucy,callahan,73,bainbridge close,bungarra,rowville,4209,vic,19430602,9663021 +rec-4175-org,daniel,miels,3,tenison-woods circuit,kinross,wyalkatchem,2075,nsw,19260812,8272929 +rec-335-org,noah,reid,10,ellerston avenue,ahwahnee,inglewood,3039,vic,19310305,2293151 +rec-4977-org,marcus,marris,35,heard street,rmbh 884,lilydale,5352,vic,19671112,2643005 +rec-4931-org,rebecca,spark,10,walker crescent,,casino,4121,nsw,19990319,3829447 +rec-1711-org,andrew,wang,9,barrington crescent,summer hill,orford,2795,nsw,19260203,4852197 +rec-4021-org,nicole,clarke,34,tong place,villa 127,point cook,2121,qld,19220519,1665679 +rec-3038-org,xavier,mogavero,10,epenarra close,ramuda,west wollongong,3148,vic,19121210,2534734 +rec-1233-org,,demetriou,4,ballumbir street,zimms corner,bayonet head,2550,qld,19100722,3790130 +rec-4751-org,hannah,quilliam,1,osburn drive,black snake creek,geurie,3121,nsw,19220309,8176103 +rec-360-org,jack,redmond,6,beaver place,john flynn medical centre,surry hills,4165,qld,19321116,4060196 +rec-2819-org,polly,nguyen,278,raiwalla court,willaroo,beaconsfield upper,3029,qld,19260902,8797418 +rec-3462-org,samuel,matthews,42,ferdinand street,eagle rock,east fremantle,2049,nsw,19140402,4593177 +rec-4905-org,elki,fenwick,20,higinbotham street,oakdale,waratah north,6168,qld,19111101,1060379 +rec-986-org,daniel,pryer,9,callister crescent,iowanna,taree,4123,nsw,19380318,4294799 +rec-199-org,william,kammermann,6,clive steele avenue,2nd last on right,newcastle west,2804,vic,19430126,3515659 +rec-487-org,jaggah,estanillo,4,amagula avenue,sec 2128,devonport,2480,nsw,19350318,6334723 +rec-4109-org,louise,bowerman,27,nelson place,,keysborough,3805,vic,19141204,7238468 +rec-1896-org,shaun,campbell,37,mcginness street,bexley,tarnagulla,3802,vic,19831102,4088978 +rec-4475-org,william,reid,7,totterdell street,redlands,metung,6076,nsw,19110103,3661413 +rec-3070-org,talia,lucadou wells,59,de little circuit,kelda park,forrestfield,4740,vic,19560221,2600068 +rec-1700-org,noah,stephenson,1,vagabond crescent,,northbridge,3166,nsw,19511016,4406709 +rec-1347-org,skye,clarke,11,buik place,,northbridge,2225,nsw,19260328,6512778 +rec-1338-org,georgia,benger,1,mccay place,braeburn,pimpama,2153,nsw,19830402,3445535 +rec-3973-org,katie,chorley,99,kangaroo court,tarqua,blakehurst,2738,vic,19380305,4782391 +rec-3281-org,elton,shadbolt,35,finniss crescent,riverbend,bacchus marsh,4179,vic,19031005,1581334 +rec-379-org,chloe,herbert,30,canberra avenue,bombowlee,humpty doo,5068,vic,19791208,1380182 +rec-3150-org,charles,eileen,330,baldwin drive,ferncliff,preston,3155,vic,19841207,9552166 +rec-3845-org,claire,thorpe,13,tunney crescent,rmbh 884,muchea,4510,qld,19640626,8325756 +rec-1187-org,kira,kyriacou,70,hopegood place,rowethorpe,tiaro,5024,vic,19820117,3935956 +rec-1169-org,brody,longman,43,tallara parkway,,memerambi,7310,sa,19000210,5544163 +rec-4023-org,emiily,choi-lundberg,10,moseley place,kokoda hostel,warriewood,2099,vic,19081215,8598033 +rec-2759-org,fergus,byers,11,marlock street,grammar school,west croydon,7011,sa,19350908,6065967 +rec-205-org,samuel,crimes,91,newbu place,gracemere grdns,cecil hills,5351,vic,19551224,2238755 +rec-3766-org,teaha,lowe,3,crocker place,rosetta village,colac,3058,vic,19411021,1890695 +rec-891-org,eboni,timperon,38,bentham street,engelbert wing,berwick,2560,nsw,19531206,1115863 +rec-2724-org,lauren,dent,24,lindrum crescent,hamilton,bidwill,2905,vic,19840916,7699699 +rec-2175-org,brianna,wardle,1,mcdougall street,eastern end,beechboro,3165,nsw,19440826,2063140 +rec-994-org,emma,hoffman,38,blair place,lynden lea,south melbourne,3995,qld,19521207,6762264 +rec-1824-org,liam,webb,559,george street,garden settlement,newmarket,4505,qld,19950329,4718403 +rec-3739-org,jacob,,1,barada crescent,challicum south,bacchus marsh,3206,nsw,19370320,8873242 +rec-1726-org,thomas,butt,,hindmarsh drive,mayflower retrmnt vlge,currans hill,3799,qld,19290620,2143953 +rec-3230-org,jacqueline,macphail,65,maddigan street,oxonia,canterbury,2611,wa,19350403,8001638 +rec-675-org,jacob,margrie,92,moulder court,collaroy,clifton,3840,vic,19130517,4315229 +rec-2608-org,lachlan,groenveld,733,herschell circuit,,graceville,3016,nsw,19770716,8547078 +rec-4210-org,mia,nguyen,30,hackett garden,calliope caravan park,wallsend,5608,wa,19350114,4435167 +rec-3809-org,harry,matthews,2,dalman crescent,timbara,leongatha south,2519,vic,19110203,4984322 +rec-4884-org,nicholas,coffey,41,disney court,siesta caravn park,coonabarabran,2428,act,19960110,9358749 +rec-2690-org,gianni,wiseman,81,jalanga crescent,york house,cooroy,4170,nsw,19651030,2659971 +rec-1683-org,andrew,renfrey,59,dickson shopping centre,margaret river carvn park,swan hill,4740,nsw,,9425075 +rec-220-org,abbey,finlay,14,lipman street,willowcrest,park holme,2680,vic,19711028,2407770 +rec-4258-org,kalli,bishop,36,,moonbi,yarrawonga,2750,wa,19020306,4667624 +rec-2609-org,brooke,egan,93,mcinnes street,,wanniassa,4215,vic,19880417,8165238 +rec-3276-org,joseph,wynne,62,matina street,lucky corner,kirra,7054,nsw,19020302,6433640 +rec-839-org,teegan,gaskin,10,maclagan street,the lodge,spearwood,2765,nsw,19880727,8091072 +rec-4786-org,talissa,passmore,115,lyall crescent,yarrowee farm,ashfield,3152,tas,19621214,2120101 +rec-2767-org,rosie,green,64,martley circuit,orana gardens retirement village,sefton,4740,nsw,19400512,1038720 +rec-1319-org,tuscany,yen,138,sage close,wooloomolan,mundingburra,3174,nsw,19011205,1974035 +rec-2241-org,sara,wilkins,12,boddington crescent,wyseworth rmb 346,naracoorte,5084,qld,19621027,7634727 +rec-4430-org,mason,homann,45,sommers street,professional centre,vaucluse,4873,vic,19130214,7096543 +rec-3352-org,kylie,webb,1,gard place,,findon,3156,nsw,19860814,5234286 +rec-4283-org,marcus,ryan,7,ina gregory circuit,villa 5,stoneville,3977,nsw,19461209,9348856 +rec-1689-org,tess,carosella,35,goodsir place,ocean breeze,para hills,4350,vic,19550517,2262772 +rec-2134-org,maddison,grubb,16,kambalda crescent,villa 2,bonnyrigg,4455,vic,19621019,8441303 +rec-2977-org,fiona,crossman,487,brophy street,,maryborough,4700,qld,19340301,9968811 +rec-2553-org,brayden,coleman,21,paul coe crescent,westfalls,greenwith,5047,vic,19500606,1790784 +rec-1857-org,hugh,bartel,11,brewster place,,bakers creek,4069,nsw,19510315,7516697 +rec-1385-org,joel,bishop,10,french street,cedarview,orange,3223,nt,,1324854 +rec-1109-org,kaleb,mccarthy,34,lamington street,berri cottage hmes,the entrance,2795,qld,,1510564 +rec-1861-org,lucas,corsico,1337,saggers close,tara park,port macquarie,6155,qld,19730826,9722217 +rec-2217-org,alicia,curry,51,macrossan crescent,yarrandoo,loganholme,4118,vic,19340827,2973687 +rec-3432-org,,millar,6,lhotsky street,nunkeri,brighton,5032,nsw,,7148945 +rec-1270-org,elle,matthews,54,maddock place,glenburnie lodge,park orchards,6058,vic,19960904,9253952 +rec-3362-org,adam,nguyen,13,stokes street,bishops creek,weerite,3216,vic,19461223,6333286 +rec-2025-org,tyler,parr,58,gibbes street,adams cottage,salisbury,2850,nsw,19151120,1803541 +rec-482-org,wilson,white,22,bellinger circuit,brentwood vlge,carine,5540,qld,19330625,7471491 +rec-2991-org,aiden,maynard,21,mcclure street,,bellevue hill,2021,nsw,19960105,3310706 +rec-2791-org,ella,hawes,51,stubbs crescent,,kaleen,3195,nsw,19100115,3998567 +rec-4041-org,alaiyah,stephenson,61,captain cook crescent,hd tiparra sec 333,nhill,3204,act,19050712,2910230 +rec-2891-org,tabitha,orchard,2,marsden street,john flynn medical centre,robina,3179,nsw,19230831,1102361 +rec-3680-org,liam,britten,7,vagabond crescent,myliton,alice springs,3046,nsw,19051004,6919659 +rec-4622-org,lachlan,mccarthy,9,william hudson crescent,sheep station,greensborough,2190,qld,19960516,1946829 +rec-4377-org,caitlyn,campbell,39,amagula avenue,delvawood,coolum beach,3714,qld,19930612,3516962 +rec-776-org,maddison,gfarrick,18,derrington crescent,janefield,gunbower,6308,nsw,19021108,5581067 +rec-2054-org,zarlia,glennon,158,florence taylor street,gwandalan,mansfield,4014,qld,19150226,9056397 +rec-1249-org,benjamin,browne,710,beazley crescent,cosy corner,merrimac,2094,nsw,19660327,9379589 +rec-83-org,joshua,stanley,1,weddin circuit,rocklands,cabramatta,7320,nsw,19381229,5425400 +rec-4699-org,daniella,chandler,1226,lewin street,the willows,robertson,4173,vic,19111101,3790237 +rec-1275-org,lucy,crouch,14,wedgewood close,brentwood vlge,dorrigo,2870,,19620929,3002608 +rec-4642-org,judah,simmonds,33,elsey street,summer hill,hamilton,2444,vic,19940414,2036044 +rec-1561-org,roberta,bishop,53,curtis place,rosetta village,balaklava,3393,nsw,19261110,6627562 +rec-4118-org,madison,nguyen,101,brisbane avenue,billsblock,richardson,3658,nsw,19450606,4699715 +rec-1648-org,lily,hick,189,atherton street,goolman street,wangi wangi,2212,nsw,19260617,8984671 +rec-3962-org,simone,campbell,11,priddle street,mungrup stud,doubleview,7009,vic,19721211,1936096 +rec-3507-org,gemma,lowe,77,currie crescent,aptmnt 42,san remo,4208,sa,19730809,7414003 +rec-398-org,judah,boyle,289,mcmillan crescent,sapama park,west kempsey,2225,wa,19000503,8429976 +rec-2318-org,aidan,fysh,165,must circuit,yarrum,forest hill,2132,vic,19330404,1070728 +rec-1113-org,carmen,miles,361,mccormack street,paling south,mona vale,2782,nsw,19220601,4126596 +rec-4960-org,alisha,winfield,17,guerin place,gummy gully,altona north,3561,nsw,19760414,8806168 +rec-171-org,laklynn,mcneill,73,forbes street,peridon vlge,tuart hill,4217,nsw,19690421,8431709 +rec-4584-org,joshua,gohl,38,charteris crescent,locn 3719,sandy bay,4701,qld,19210912,4250931 +rec-2877-org,tori,mcgarrigan,11,hallen close,rosedale,bangor,6004,wa,19841007,5119714 +rec-526-org,bailee,ryan,100,edgar street,little pines,milperra,5680,wa,19410207,7905025 +rec-1789-org,olivia,white,10,spafford crescent,clear creek,pakenham,4059,nsw,19480205,7285108 +rec-337-org,jordan,morrison,45,church lane,killarney park,albany creek,2770,nsw,19850727,4295797 +rec-1895-org,tabitha,prytula,2,totterdell street,rsde 817 wallace,nabawa,4017,sa,19930102,4076797 +rec-4341-org,lucas,white,17,majura avenue,glenbrae,clapham,2131,qld,19420809,6988438 +rec-3478-org,brydon,golder,2,street place,belbee,ramsgate,3179,vic,19651217,1997517 +rec-2862-org,emiily,vimpany,200,langdon avenue,kalamos,calen,3152,qld,19180604,2589251 +rec-4823-org,ethan,rawlings,217,crisp circuit,brentwood vlge,hectorville,3496,nsw,19570525,2496172 +rec-272-org,annabel,thorpe,5,thake place,parry house,mulgrave east,2537,vic,19480708,1654518 +rec-717-org,joshua,raward,26,yambina crescent,thorndale,macgregor,4718,qld,19660409,9086686 +rec-2591-org,,haythorpe,60,heard street,kangaroo ground warrandy road,rosebud,6149,nsw,19010708,6149528 +rec-2968-org,finn,teague,39,empire circuit,wagin medical centre,prospect,2083,qld,19650301,2488065 +rec-1754-org,shai,leon,15,canopus crescent,grant hostel room,metung,2147,nsw,19230106,8789495 +rec-4168-org,,ruolle-ivanov,11,fairweather circuit,,mount low,5290,vic,19661012,4600962 +rec-175-org,james,brain,31,benham street,tagarra,belmont,3162,nsw,19860305,8028191 +rec-3356-org,erin,red,,cornish place,ferndale,renown park,2281,vic,19420519,7078005 +rec-3217-org,neneh,wheatley,73,bunda street,,torquay,3844,nsw,19530310,6451877 +rec-3127-org,alyssa,shepherdson,,wuruma place,the willows,leichhardt,2165,qld,19380508,8856944 +rec-822-org,zachary,goode,39,alroy circuit,,broadmeadows,7250,nsw,19900208,3817430 +rec-1396-org,lara,stanley,89,napper place,cooramin,carlingford,3193,qld,19380827,4712092 +rec-3991-org,eliza,nadin,12,mt warning crescent,tycannah station,preston,3091,qld,19470314,6540403 +rec-3796-org,zac,silo,2,medley street,gundaline,mitcham,2767,vic,19611116,4048723 +rec-2532-org,david,nguyen,95,maurice place,palm grove,,3138,vic,19340626,7414934 +rec-2644-org,sean,bammant,108,yarra street,ulva,yorkeys knob,2154,wa,19650509,6208046 +rec-3132-org,ethan,mcdermid,27,buggy crescent,rsde 817 wallace,eden hills,3287,nsw,19921128,3857387 +rec-1543-org,jasper,isola,,mackie crescent,kindilan,mount annan,6025,vic,19480225,7268907 +rec-4244-org,mitchell,haeusler,55,denny street,yarrawah,geurie,7300,vic,19280613,1941344 +rec-2152-org,emiily,fitzpatrick,,aland place,keralland,rowville,2219,vic,19270130,1148897 +rec-2858-org,amber,ryan,24,mcgill street,sapama park,boulder,2390,nsw,19321018,5050790 +rec-4497-org,benjamin,dola,3,leahy close,killarney,rowville,2430,nsw,19371003,6069398 +rec-1277-org,madison,hope,1,grounds crescent,,narrogin,2330,nsw,19400901,5832856 +rec-3881-org,tayah,zimmermann,,vickery street,kootingal,buddina,6330,vic,19810827,4538744 +rec-4087-org,joshua,hoyland,36,hemmings crescent,solitaire,mount eliza,0828,wa,19090810,7921703 +rec-4907-org,harry,whiteway,14,fernyhough crescent,c f village,loganholme,5062,wa,19310808,6408389 +rec-4066-org,matthew,campbell,4,wybalena grove,,the entrance,4503,nsw,19480209,3117774 +rec-4469-org,josephine,dragheim,3,downard street,lowangreen,malvern east,3142,qld,19560618,2093181 +rec-1716-org,lauren,cloudsdale,4,fred lane crescent,willowbanks,east maitland,3046,qld,19430211,1765101 +rec-4982-org,holly,paterson,48,cowdery place,dragon rising,coodanup,3910,act,19641219,1987760 +rec-2329-org,lachlan,theodore,1304,wenlock street,bells ck,woodhouselee,4817,wa,19840528,7028688 +rec-4307-org,claudia,bihar,33,arabana street,belandean,moe,5025,qld,19150406,8874107 +rec-3597-org,bethany,dixon,25,burraly court,denny downs,culburra,2208,nsw,19850214,5650922 +rec-2419-org,bethany,van der klaauw,10,horne place,,granville,2350,vic,19880416,1515136 +rec-929-org,madison,morrison,38,peacock place,melima,campbelltown,3021,wa,19481214,1967265 +rec-3605-org,amy,hope,24,demaine crescent,canberra centre,port adelaide,2131,nsw,19541110,7206463 +rec-3602-org,trent,bizjak,1,majura avenue,burrawan,northbridge,3189,vic,19950310,4593048 +rec-3064-org,matthew,reid,44,nambucca street,eureka,bundaberg,6111,wa,19020723,6219878 +rec-2572-org,bridget,dudgeon,11,cockcroft avenue,manor park,joondalup,3040,nsw,19740328,7423497 +rec-2468-org,magnus,grainger,7,heath place,carrington retirement,moe,3042,vic,19970829,7094597 +rec-2012-org,riley,white,7,william hudson crescent,brentwood vlge,burnside,3064,qld,19941028,3083448 +rec-2323-org,rachael,yallop,15,fullagar crescent,rsde 668,beenleigh,4860,qld,19760214,1296128 +rec-1787-org,charlie,browne,33,rivers street,rowethorpe,east hills,2539,sa,19360722,3866237 +rec-1261-org,isabella,zimmermann,25,lampard circuit,monto caravan park,patterson lakes,2280,nsw,19080814,4093298 +rec-1131-org,oscar,ovens,15,bennett street,,sheidow park,2606,wa,19060608,3538621 +rec-2783-org,chloe,bryce-watson,9,kelleway avenue,environganic farm,dutton park,2144,nsw,19720802,2226510 +rec-3050-org,victoria,rankine,661,redcliffe street,strathmore vineyard,moranbah,6208,vic,19260809,5842904 +rec-1315-org,calvin,goode,12,chapman street,gleneagle,kings cross,5048,qld,19510916,2447062 +rec-3077-org,jett,mendrin,108,ainsworth street,colooli village,bassendean,3777,nsw,19050414,4009353 +rec-91-org,jacob,clarke,10,ebden street,,loganlea,6061,tas,19181001,9535708 +rec-2988-org,chloe,garnsey,313,sharwood crescent,langley flats,port macquarie,2282,sa,19930709,6811314 +rec-469-org,emiily,eglinton,110,solomon crescent,crowden,bendemeer,2602,vic,19970213,6929273 +rec-2065-org,shana,mavrangelos,3,basedow street,,surrey hills,4655,sa,19860504,3793509 +rec-1615-org,flynn,lydon,79,heard street,sennocke,ashfield,2285,vic,19631207,6564471 +rec-1354-org,ella,wilkins,468,hodgson crescent,currandina,ellenbrook,2615,sa,19010903,2658739 +rec-4860-org,douglas,fitzpatrick,16,booroondara street,shadoof lodge,toodyay,2259,vic,19050428,2826631 +rec-3896-org,,lodge,9,forbes street,glen alvie rsd,birkdale,5118,nsw,19691225,7105186 +rec-3459-org,madison,chandler,29,luckman place,hd tickera,pearl beach,2133,nsw,19551128,8841314 +rec-1690-org,georgia,cother,30,captain cook crescent,whiskers hill,seelands,2220,nsw,19171218,8148701 +rec-3937-org,caleb,campbell,64,rowe place,locn 7560,hamilton,4214,sa,19220922,9117989 +rec-4080-org,danielle,sawczak,180,forbes street,malay vale,oak park,3431,nsw,19410314,8495764 +rec-2721-org,tristan,yani,4,bage place,flt 10,glenbrook,3856,qld,19010515,2833733 +rec-903-org,brianna,barisic,1502,haddon street,parish talowahl,launching place,3220,vic,19750703,5367822 +rec-257-org,daniel,ryan,3,de little circuit,the lakes retirement village,brighton-le-sands,2400,,19920826,6267294 +rec-2132-org,mhary,gaitanis,1,howitt street,thirty creek,mathoura,2830,nsw,19891212,2923514 +rec-578-org,ned,widdowson,33,frost place,kemminup farm,burpengary,6707,qld,19731112,8416181 +rec-4206-org,samuel,bottroff,23,mclarty court,cherrybank,port macquarie,6024,sa,19420214,5990041 +rec-2207-org,lily,aspinall,72,farrer street,business centre,westbrook,6151,vic,19000214,7074916 +rec-2393-org,ruby,symmons,20,miller street,locn 2093,rosslyn park,2069,sa,19301022,3976926 +rec-40-org,finlay,coffey,3,summerland circuit,,auburn,3216,tas,19001106,5825057 +rec-2344-org,rhett,boxer,19,langlands close,rowethorpe,mont albert,5353,qld,19330608,7303507 +rec-3806-org,ethan,goode,262,minnett close,,prospect,3550,nsw,19830302,9757237 +rec-3263-org,jacob,weaver,27,ferguson circuit,braeburn,hoppers crossing,6062,nsw,19231001,4297631 +rec-1429-org,katelyn,dixon,8,melba street,surfside park,auburn,3104,nsw,19730618,2599418 +rec-2648-org,gabriella,pilavci,35,perry drive,medical centre,mooroolbark,2460,wa,19160117,2556284 +rec-4847-org,harvey,fassina,,pope street,oakdale,malvern east,4419,nsw,19840812,5859873 +rec-2046-org,kaitlin,bowerman,16,foskett street,bulala,edensor park,6111,nsw,19140320,6109196 +rec-1891-org,lara,snelling,1,bimbiang crescent,the briar patch,toorak,5049,vic,19610916,8470980 +rec-4516-org,chelsea,blake,35,southern cross drive,ra 290,belconnen,3141,vic,19770311,8747454 +rec-4182-org,george,noble,1188,fawkner street,willandra,ormeau,3199,qld,19430912,7672726 +rec-112-org,lachlan,white,81,gabriel place,,parramatta,3030,qld,19210910,2637042 +rec-618-org,ella,crouch,1710,amadeus place,sec 1,clifton springs,4304,nsw,19870511,5975406 +rec-116-org,annika,mason,50,ainsworth street,legacy units,eaglehawk,5159,sa,19860615,2777725 +rec-3264-org,benjamin,fullwood,4,pulleine crescent,pangani,labrador,2261,wa,19840715,6999348 +rec-3901-org,shane,goldsworthy,9,starritt place,woodsong,new town,6055,wa,19111223,5363583 +rec-2043-org,lewis,boyle,55,cottam place,willyaroo street,bridgewater,2000,nsw,19121105,1190651 +rec-3614-org,zachary,thurlow,28,eldridge street,trefusis,southern cross,4051,nsw,19230305,5024661 +rec-1443-org,harrison,schuster,21,boldrewood street,brambletye vinyard,port macquarie,4069,vic,19851117,4249901 +rec-4079-org,lachlan-john,,26,officer crescent,tabermory,nambour,2395,nsw,19250213,5785896 +rec-4957-org,dayna,tapper,16,roseworthy crescent,gowrie,malvern,4218,vic,19210608,2412058 +rec-1052-org,giaan,everett,32,,sunnyside orchards,wangaratta,4551,tas,19420909,7947853 +rec-2369-org,kaitlin,katarski,6,gidabal street,lawley park,milperra,0820,nsw,19900303,1052599 +rec-1177-org,michael,green,30,jay place,little tinana,cremorne,3564,wa,19461212,1468008 +rec-4399-org,annalise,reid,21,luehmann street,kiandra,halifax,3138,vic,19800504,3499915 +rec-4068-org,matilda,snell,19,grylls crescent,family day care,trevallyn,3186,vic,19870819,3860203 +rec-3979-org,ky,renfrey,9,southwell street,cottage rose,tooperang,4217,vic,19290827,6382127 +rec-197-org,ruby,nguyen,26,barraclough crescent,northbridge park,st peters,4011,qld,19521110,8292725 +rec-4159-org,alexandra,berry,18,mckinley circuit,aronui,tahmoor,2206,nsw,19120808,1881229 +rec-2084-org,anthony,david,1241,goyder street,rosetta village,carnegie,3178,nsw,19200422,8338112 +rec-3628-org,indyana,gazzola,134,trott place,central park,thornbury,3187,nsw,19900905,6670654 +rec-851-org,alana,thredgold,32,rivers street,oakdale ranch,mooloolaba,4715,vic,19250525,2372845 +rec-2384-org,,mcgirr,1170,graham street,hopefield,yangebup,3414,vic,19060702,7139205 +rec-4240-org,solomon,hannagan,10,clemenger street,brookfield,forrestfield,4216,sa,19890520,3944717 +rec-4713-org,channing,haak,8,kevin street,sec 1,bundaberg,6450,wa,19970408,9248677 +rec-1953-org,coby,lukeman,26,hiles place,cherry haven,rosebery,3122,nsw,19040306,3163493 +rec-1068-org,joshua,dolan,16,gabriel place,greglea village,lobethal,5162,qld,19670425,4173804 +rec-4813-org,zarran,eisele,39,national circuit,kojonolokan hills,penguin,5114,tas,19330305,3983917 +rec-2892-org,anthony,berry,12,duterrau crescent,mianga,acacia ridge,6027,vic,19570618,6807657 +rec-1318-org,sara-louise,white,24,maddock place,headland garden,rose bay,2380,qld,19560217,8506035 +rec-4841-org,connor,bergsma,180,tinderry circuit,ferndale,penrith,3047,nsw,19580116,5081459 +rec-4347-org,alice,roman,10,throsby crescent,navillus,bourke,6233,nsw,19991123,3858979 +rec-4202-org,charlie,nguyen,,fraenkel street,harvic,cardiff,3073,tas,19240421,5852654 +rec-4628-org,calvin,white,63,doyle terrace,windara,cardiff,5223,wa,19560731,4551355 +rec-1892-org,hayden,beattie,5,monaro crescent,sandilands,cloverdale,4059,qld,19530424,4745672 +rec-3611-org,cooper,clarke,2,poynton street,,dapto,2479,vic,19871109,4405327 +rec-4834-org,,quast,6,fincham crescent,zimms corner,penrith,2228,vic,19720423,8031551 +rec-1435-org,thomas,dinh,5,jervois street,dugout 65,goonellabah,2077,nsw,19841214,5448033 +rec-4650-org,andrew,marlow,7,,,ashfield,2780,nsw,19550903,4126078 +rec-1599-org,matthew,robson,9,burrendong street,ashell,toukley,4000,nsw,19441016,6090364 +rec-1959-org,jorja,selth,82,arnold place,wooloondool farm,colonel light gardens,4350,nsw,19460602,5599958 +rec-2262-org,gabriel,moyse,12,currie crescent,platina,sefton,3337,wa,19160926,3553783 +rec-3880-org,hayley,moody,1,lambell close,solitaire,jones hill,3103,nsw,19831231,7465219 +rec-338-org,harry,bjorksten,47,crisp circuit,retirement village,fullarton,4101,nsw,19830511,3332626 +rec-1001-org,michael,sroczek,,chaseling street,marella,wellington point,2262,wa,19110110,8407592 +rec-4462-org,danielle,crosswell,8,ranken place,yambira,,3018,vic,19430711,5534097 +rec-1851-org,ava,ryan,59,gratton place,corella,noble park,4184,vic,19710805,9223546 +rec-228-org,oliver,verner,29,mcnicoll street,sunbury,berala,3175,vic,19160819,7677004 +rec-1685-org,tahlia,inglese,39,blakey close,rivoli,lakes entrance,3222,wa,19561220,6197497 +rec-1283-org,lewis,strubbe,7,badenoch crescent,meadow banks,bayview heights,2564,nsw,19900106,7706707 +rec-1138-org,zoe,webb,19,macindoe place,kooyong,tennyson,2079,wa,19101217,1156023 +rec-2022-org,stephanie,tuckwell,6,weddin circuit,hillside farm,scarborough,4152,sa,19920918,9299910 +rec-4857-org,mitchell,paterson,10,boniwell street,kilacloran,point lonsdale,3021,vic,19550830,3431890 +rec-3785-org,abbey,stephenson,,duggan street,makowata siding,elwood,2095,nsw,19520731,3195277 +rec-2570-org,jacob,coppola,3,smeaton circuit,deer farm,williamstown,3400,sa,19211130,8983109 +rec-2853-org,holly,ang,9,pinkerton circuit,professional centre,robina,3919,vic,19300225,1127897 +rec-2013-org,eliza,berry,25,shout place,jingara,eaglehawk,2229,nsw,19381031,3608034 +rec-3376-org,ruby,white,37,archer street,collier park vlge,whyalla,3341,vic,19920824,7891103 +rec-4777-org,amy,steinert,20,werriwa crescent,kangaroo grnd,hillston,5251,nsw,19411122,7428687 +rec-3495-org,nicholas,dixon,60,archibald street,,dalyston,2154,vic,19230212,6851976 +rec-1572-org,joshua,nguyen,11,beattie crescent,altona,casino,3029,vic,19240622,8948695 +rec-793-org,lachlan,hukowskyj,18,laidley place,mariah,adamstown,2137,nsw,19821022,2246928 +rec-145-org,kieren,steers,10,whittell crescent,loma,east innisfail,2280,nsw,19060603,1532338 +rec-1423-org,alexandra,green,13,folingsby street,pint pot,queenscliff,2720,vic,19840808,9788564 +rec-3793-org,lucy,mccarthy,29,charlton street,warrah lea,bundaberg,4061,qld,19940917,6596660 +rec-1554-org,jock,sedunary,466,douglas close,the briar patch,nar nar goon,3015,sa,19970805,3855499 +rec-4545-org,riley,moubarak,,hagen place,noolabi,auburn,6007,vic,19400916,5023399 +rec-4799-org,molly,hanna,18,lewis luxton avenue,tulliallan,salisbury east,2092,vic,19171018,3994290 +rec-4201-org,ruby,buccini,36,embling street,yarras est,springbrook,2290,qld,19951117,7734393 +rec-3814-org,jasper,dorling,155,dowling street,gateway vlge caravn park,upwey,2069,nsw,19470208,2142730 +rec-4590-org,shandril,tinfina,437,stuart street,bodyworks healing centre,glenhaven,4737,nsw,19880220,2185877 +rec-2663-org,tylah,valesic,20,beaumaris street,lift,preston,2795,nsw,19750402,8445597 +rec-4215-org,warrick,golder,38,gormanston crescent,alanvale,dwellingup,6051,sa,19680328,7185543 +rec-1447-org,alexandra,alderson,4,arkell place,toolooa,clarinda,3764,vic,19230610,3671723 +rec-2141-org,alexandra,meixner,42,mannheim street,casablanca,st albans,2913,sa,19030525,3838784 +rec-898-org,annabel,malin,5,findlay street,pacific bay villas,mawson,2099,vic,19291020,4116074 +rec-2155-org,grace,dolliver,28,geils court,north star resort,doyalson,5720,qld,19040326,8625522 +rec-4591-org,carlin,zordan,74,burnie street,kangaroo creek,,2213,nsw,19070620,1373412 +rec-4780-org,amber,coleman,6,matson street,altona,mount isa,2121,wa,19050907,2464697 +rec-2257-org,michael,friebel,40,lawrence wackett crescent,port fairy road,northgate,4109,nsw,19841025,3055957 +rec-4728-org,ebony,penno,62,weingarth street,sheidow park medical centre,minto,2840,qld,19090710,9031641 +rec-4055-org,cameron,dolejs,17,medley street,merrangbauer park,prospect,4812,nsw,19250828,8585817 +rec-1738-org,rebekah,whitters,55,mcginness street,bay city plaza,mckinnon,2076,nsw,19360902,9026077 +rec-4046-org,carla,matthews,3,waramanga place,maculata,humpty doo,3064,wa,19480730,5223185 +rec-3193-org,,finlay,14,castleton crescent,killuke,bundaberg,4670,wa,19600319,1709445 +rec-3767-org,danielle,clarke,7,port jackson circuit,goyder centre,hoppers crossing,6108,nsw,19810727,9407324 +rec-342-org,elli,noble,1,saggers close,tinaroo falls,spearwood,6330,vic,19420501,9762210 +rec-579-org,braedon,bindoff,484,eve place,moreton,hamilton,2099,nsw,,7181006 +rec-4139-org,charlotte,maynard,33,tarrabool street,little shalford,worongary,2068,nsw,19840915,3337218 +rec-135-org,dylan,lomman,1,cockburn street,hyland,taloumbi,2756,vic,19941224,2435246 +rec-4381-org,william,minnican,10,tunney crescent,berkeley vlge,redbank plains,2835,qld,19530313,5016929 +rec-3874-org,jacob,webb,14,hawdon street,aumuller house,forest lodge,6050,nsw,19450315,8971806 +rec-293-org,robert,westhorp,26,kosciusko avenue,oak park,port pirie,3106,vic,19371011,1463700 +rec-4379-org,alisa,tiller,381,marchant circuit,rosetta village,dandenong north,3087,qld,19550719,9314806 +rec-24-org,lauren,mellick,54,lewis luxton avenue,,cooks hill,2161,qld,19561107,9988724 +rec-4564-org,teaha,rawlings,23,charterisville avenue,moonby downs,toowoomba,4006,sa,19601115,9235941 +rec-616-org,ruby,allchin,20,mccarten place,glenhurst,ascot,2106,sa,19470412,1630282 +rec-4635-org,isabella,white,8,cooling place,,rosebud,6151,sa,19990911,2206317 +rec-2092-org,genevieve,bristow,7,schonell circuit,the park,malvern east,3109,nsw,19890119,7811495 +rec-1060-org,belinda,hilton,38,beltana road,villa 2,botany,2171,vic,19640816,6397676 +rec-2795-org,taliah,bunuggurr,18,eldridge street,drayton,wallsend,2031,qld,19760404,1387033 +rec-1575-org,alessia,harrington,36,meredith circuit,gliding gulls,sunshine north,3192,nsw,19561129,5264440 +rec-3514-org,tanyshah,wiemann,68,anne place,sussex farm rmb 3958,strathalbyn,3337,nsw,19640904,8798582 +rec-3383-org,blake,beelitz,26,ranken place,goodrick park,elwood,4740,nsw,19760330,8133663 +rec-4700-org,jared,allsopp,35,theodore street,peroomba,hazelbrook,4121,nsw,19511220,5416662 +rec-4658-org,jack,danby,,thompson place,woorabinda,norwood,2340,vic,19991118,1030908 +rec-1078-org,kyle,genovese,,harrington circuit,anzac house (cnr archer s street,port lincoln,4725,vic,19780802,8478632 +rec-478-org,jack,collinson,4,blowering street,canobolas caravn park,leeton,4221,nsw,19821223,5810985 +rec-3531-org,cassandra,seymour-griffin,29,priddle street,the burren,bayswater,3104,nsw,19961213,6740375 +rec-4025-org,chase,gilbertson,5,tipiloura street,cornvale,gununa,3083,nsw,19760713,9832872 +rec-3545-org,natalia,langrehr,32,calvary clinic,mt annan,narellan vale,5290,nsw,19981015,5685638 +rec-67-org,erin,matthews,10,williamson street,yaraan,kilcoy,4218,qld,19991129,7747845 +rec-2535-org,daniel,lowe,18,stanfield close,,plympton south,2111,vic,19230424,5226883 +rec-415-org,neneh,large,14,onkaparinga crescent,heritage manor est,woollahra,4352,sa,19950725,8160717 +rec-967-org,chelsea,miles,23,illawarra court,rosehill,greensborough,2230,qld,19950926,1751900 +rec-2147-org,zack,spanton,108,sargeant place,waioma,raceview,4500,qld,19680828,1159113 +rec-1661-org,bianca,clarke,59,florence taylor street,circle court,chittaway point,2330,vic,19400401,6129111 +rec-1665-org,sophie,abeywickrama,48,bambridge street,brentwood vlge,leppington,4067,nsw,19570314,9229864 +rec-1405-org,sophie,tertipis,23,walker crescent,furlough house,brighton-le-sands,2340,nsw,19490918,7755180 +rec-4219-org,pearson,goode,23,cane place,culbone,manly vale,2602,vic,19840402,7430736 +rec-2719-org,shantal,negri,159,hagelthorn street,port rush parade,port macquarie,4702,qld,19970221,4740975 +rec-467-org,caitlin,berry,188,roseworthy crescent,whispering pines,toodyay,3150,qld,19400622,2073490 +rec-1907-org,charlotte,coffey,5,hallen close,thurlimbah,ringwood,2560,,19741217,9493726 +rec-195-org,daniel,crook,7,liffey circuit,rajamare,frankston,3266,nsw,19971114,5337955 +rec-4203-org,riley,walls,13,florence taylor street,nepean shores,padstow,3084,qld,19200129,1018744 +rec-808-org,tai,philps,17,burrendong street,el-woodaro,rokeby,6258,nsw,19610906,2863233 +rec-3865-org,isabella,novak,40,ebden street,carinya vlge,mooroolbark,5074,vic,19870905,5546417 +rec-3220-org,michael,chigros,8,beasley street,gypsum pit,murrumbateman,3930,vic,19380317,5018010 +rec-3786-org,nicholas,cochrane,845,olney place,,edithvale,2450,vic,19260717,9800269 +rec-364-org,reganne,mayer,47,,fraser lodge,marsfield,3465,vic,19741017,8978233 +rec-758-org,lily,keelty,117,mcgivern crescent,navan park,port adelaide,3551,qld,19800514,2027365 +rec-1737-org,levi,prideaux,10,beckett street,terra nostra,milperra,6525,wa,19230510,9135299 +rec-2272-org,katelyn,slack-smith,5,mugga way,bundong,marrara,3505,nsw,19990408,3364407 +rec-3139-org,caitlin,coxon,144,evergood close,blue gum park,smithfield,3109,act,19160701,4213502 +rec-4311-org,ty,bradshaw,12,greenhood place,conmurra,lauderdale,3146,qld,19630327,7145468 +rec-886-org,riley,noble,17,thake place,station homestead,matraville,5032,wa,19600221,8713309 +rec-438-org,alison,hearn,4,macdonnell street,cabrini medical centre,adelaide,2720,vic,19191230,2937695 +rec-2463-org,courtney,sennar,60,arinya street,kangaroo grnd,kellyville,7248,act,,9329570 +rec-4800-org,jordan,toms,20,lachlan street,belgrave arcade,plainby,2620,nsw,19760913,3320758 +rec-4758-org,robert,nguyen,26,willoughby crescent,wandendi,dianella,5155,nsw,19381017,4982192 +rec-3180-org,samuel,paterson,4,garran place,sunnyside orchards,yarraville,2111,nsw,19360226,3308420 +rec-2496-org,,whishaw,25,ashcroft crescent,rosebery hill,vaucluse,4670,nsw,19751021,3381395 +rec-2953-org,alex,hanna,146,pocket avenue,scottsdale,yangebup,3941,vic,19040515,7193215 +rec-4605-org,georgia,lowe,7,chipperfield circuit,eastern end,ryde,3500,vic,19141110,1576434 +rec-4199-org,,ryan,42,beazley crescent,shaudell,torquay,0830,sa,19820718,9041824 +rec-1357-org,tiarna,lapienis,47,hunter street,cooralook,ormond,6027,nsw,19971203,3933703 +rec-1330-org,cain,dietrich,40,eugenia street,legacy units,bunbury,3782,tas,19550801,2545231 +rec-3083-org,darcy,hamblin,28,goldfinch circuit,tarqua,geelong south,2320,wa,19141204,7758955 +rec-1285-org,sophie,fitzpatrick,5,longerenong street,briars meadows,kincumber,2450,nsw,19200110,7018366 +rec-3160-org,xanthe,pringle,46,woodfull loop,morven,woori yallock,6110,vic,19250210,4259044 +rec-1293-org,emiily,stronach,555,hodgkinson street,triton units,dapto,3199,tas,19830423,4516064 +rec-631-org,shannon,hope,22,,the broadwalk arcade,tennant creek,4017,vic,19300617,6942665 +rec-241-org,chloe,dunnicliff,10,fraser place,walkabout palms,belgrave,4211,nsw,,9683634 +rec-2168-org,chloe,white,10,madigan street,woodbine homestead,barraba,3055,nsw,19620821,4067329 +rec-4803-org,annabelle,romeyn,18,ferrier place,sec 247,bray park,6155,vic,19350129,2470380 +rec-751-org,emiily,green,47,craig place,rosemeade,ashfield,3095,nsw,19580116,4427524 +rec-3008-org,georgia,green,18,madigan street,kareela,mentone,3137,qld,19341105,5788426 +rec-2866-org,brooklyn,hamley,18,eildon place,flowerpot,woodlands,3013,nsw,19550602,7460551 +rec-1172-org,eleanor,luckman,34,banks street,st francis village,aspendale gardens,4361,wa,19920704,2330095 +rec-4257-org,jasper,trowse,1,kilburn close,the village condo 23,crestmead,4102,qld,19970120,5630769 +rec-2868-org,michael,george,8,burkitt street,halfmoon station,toowoomba,2026,nsw,19350216,3561120 +rec-1143-org,james,rankine,7,beattie crescent,,north hobart,2072,sa,19030624,1444078 +rec-2026-org,ethan,matson,310,worrall street,ben nevis estate,albion park rail,3672,qld,19830111,9201028 +rec-1436-org,joel,waller,12,quiros street,marella,bowral,4670,vic,19740716,8352619 +rec-3778-org,sascha,demarco,3,franks place,tantallon,gracetown,5169,tas,19960906,9430667 +rec-3714-org,tayah,pascoe,211,o'halloran circuit,stonehenge,salisbury east,2285,nsw,19410809,9400248 +rec-2114-org,chloe,lowe,344,phillip avenue,lewin lodge,deagon,4306,wa,19840502,6220613 +rec-642-org,jessica,crook,15,hilder street,legacy units,moyston,3133,qld,19950421,4759618 +rec-3325-org,brooke,gillis,72,hutcheson street,twenty-third avenue pharmacy (cnr mawarr,scarborough,2810,nsw,19680205,6797695 +rec-4501-org,xani,caruana,9,ordell street,lachlan view,wynyard,2170,qld,19840619,2057736 +rec-256-org,arabella,holyoak,49,hughes crescent,b,malvern,4405,wa,19280311,8444431 +rec-1904-org,amelia,cochrane,74,morrow street,riverside professional centre,slacks creek,2048,tas,19220112,5154778 +rec-3842-org,bailey,hai van,10,orkney place,portal cnr hives,emerald,5044,nsw,19710505,4461398 +rec-4852-org,tanyshah,praehofer,15,moogerah street,roseglen,woollahra,3875,nsw,19290421,7881845 +rec-2956-org,harry,hyland,205,ferguson circuit,,herberton,6722,vic,19910709,5231050 +rec-1091-org,mikaela,stanfield,16,giltinan place,stefonair,maryborough,4817,qld,19911222,5549486 +rec-1112-org,noah,tiller,264,miranda place,ivydale (rsd 1820),mullumbimby,3131,nsw,19780216,7578909 +rec-1002-org,joshua,fauser,2,harrington circuit,unt 2,kingsford,2280,nsw,19820606,4981335 +rec-1819-org,lauren,jeffries,154,endeavour street,bangaroo (cnr willowvale r road,patonga,2190,wa,19850503,4934969 +rec-2915-org,zachary,stanley,6,luehmann street,southern cross,berwick,2099,sa,19031015,3379992 +rec-1695-org,abbey,malin,3,burkitt street,malinga,north maclean,2080,vic,19850328,7401540 +rec-3062-org,faith,lowe,1,shepherd street,,st clair,3058,nsw,19140623,2694419 +rec-893-org,tyler,walch,26,pither close,warbinya,st ives,3871,vic,19650916,5533620 +rec-4174-org,shai,lock,20,arabana street,kyeema vineyard,melville,6065,nsw,19820129,9117058 +rec-3243-org,jacobie,white,32,pitcairn street,willowfield,sefton,2565,wa,19940831,6421878 +rec-605-org,jayde,mccarthy,13,bywaters place,chateau tahbilk,prospect,3198,qld,19381120,8148821 +rec-1582-org,hannah,rivers,5,collings street,callatoota,toorak,2487,nsw,19521217,6906828 +rec-4636-org,,reid,147,marr street,walkers orchard,arthurs creek,7330,nsw,19240712,7585720 +rec-2882-org,sarah,eglinton,19,beasley street,bandaroo,naracoorte,4021,nsw,19451107,4310446 +rec-2582-org,madeleine,wang,129,goodsir place,may cottage,devonport,4030,vic,19840516,1358332 +rec-3952-org,noah,herbert,13,beasley street,herbert creek,oak park,4280,sa,19431227,7049548 +rec-4069-org,jeremy,matthews,70,spensley place,pandora orchard,cecil park,3030,act,19700526,6692221 +rec-1525-org,lushia,allchin,940,poynton street,uc-dai-loi,mossman,6014,vic,19870205,5901439 +rec-1040-org,keely,coulson,28,scantlebury crescent,alice downs,toowoon bay,5096,sa,19930412,1189146 +rec-1093-org,sarah,bradshaw,6,hallen close,red tank,mullaloo,2161,vic,19340509,9150146 +rec-202-org,alexander,drymis,47,feltus place,springbanks,highton,2041,nsw,19571119,4370533 +rec-3721-org,gemaley,meadows,42,alarmon crescent,kalang,newham,3146,vic,19230420,5029065 +rec-3177-org,harvey,purser,184,osburn drive,villa 19,mulyandry,2680,,19000823,8501583 +rec-4568-org,,bazley,14,pennefather street,the willows,greensborough,4209,wa,19110509,7072734 +rec-2576-org,thomas,ryan,8,meredith circuit,silk hush,dunsborough,4215,vic,19270407,7468430 +rec-3965-org,noah,george,3,steinwedel street,glendale stud,gumdale,6020,vic,19270723,7682028 +rec-574-org,emma,marcola,7,totterdell street,rosetta village,goonellabah,6018,vic,19641017,7190961 +rec-3730-org,shanaye,navarro,103,frater crescent,central coast van park,dulwich hill,4520,vic,19211104,9601221 +rec-4440-org,ella,richmond,2,investigator street,mynora,crestmead,4306,nsw,19000112,6508977 +rec-3550-org,joshua,white,85,hindmarsh drive,hobbit hole,nambour,3840,vic,19230425,7052918 +rec-1933-org,ella,rollins,31,weston street,blue hills,kelmscott,3304,qld,19930802,6211133 +rec-3892-org,charlee,coulson,7,diamantina crescent,specialist centre,preston west,4740,qld,19100918,3920842 +rec-1801-org,charlee,ponsford,7,hawker street,locn 449,harbord,2234,nsw,19290803,8863899 +rec-1014-org,holly,matthews,47,mountain circuit,,west lakes shore,5085,nsw,19721010,5642441 +rec-4459-org,chloe,egan,132,wattle street,argyle village,mooroolbark,3831,nsw,19910930,5759422 +rec-4661-org,eliza,matthews,10,launceston street,settle downs,carrick,3138,wa,19130330,7623803 +rec-1099-org,kate,garden,9,bettington circuit,robinson road,rochester,3121,nsw,19021008,8610454 +rec-4230-org,jason,fenwick,5,vincent place,glenearra,morphettville,3011,qld,19550520,4178650 +rec-2985-org,coby,braine,14,longmore crescent,clftn waters vlge,gaven,2747,nsw,19491118,3329459 +rec-2800-org,lachlan,crook,16,nardoo crescent,,campbelltown,2325,nsw,19010124,2308429 +rec-2327-org,andrew,hauser,11,wanganeen avenue,,heckenberg,2289,vic,19270207,3336874 +rec-2639-org,liam,scerri,55,benham street,the sycamores,berwick,6155,vic,19320829,9489744 +rec-3731-org,brydee,lamprey,16,bavin street,unt 2,goodwood,3260,nsw,19490504,2250069 +rec-4940-org,ky,green,61,heard street,opal cove resort,kingaroy,5251,nsw,19260320,3138813 +rec-3710-org,alana,morrison,28,namadgi circuit,allanvale,artarmon,6056,vic,19081110,2007717 +rec-4434-org,kody,mewett,9,priddle street,st francis village,bayswater,2518,nsw,19880523,7709827 +rec-3388-org,silas,mccarthy,10,mcintosh street,kiloran,port fairy,6110,nsw,19330313,6901115 +rec-1299-org,dylan,patafta,10,goldner circuit,kilnsey,auburn,3183,vic,19100402,7951303 +rec-803-org,abbey,crisci,23,spence place,gorge creek orchards,cygnet river,7030,,19890327,7400712 +rec-3686-org,riley,webb,5,dent place,,meadow springs,2226,wa,19161013,1897297 +rec-532-org,cade,bishop,2,abrahams crescent,carinya vlge,clayton,4059,vic,19830405,2481294 +rec-3142-org,oakleigh,hoang,72,la perouse street,tiverton,wyong,4817,tas,19680324,6697687 +rec-4157-org,william,demarco,21,shenton crescent,,south perth,3840,nsw,19170802,3018112 +rec-1204-org,indiana,campbell,6,linger place,oakdene,salisbury,7250,wa,19430315,7787158 +rec-359-org,joshua,cloke,11,mcquade close,malinga,kyabram,2650,,19640531,9168763 +rec-4702-org,jamie,paterson,,lindrum crescent,fairlane estate,wangaratta,3104,wa,19860221,5336409 +rec-1218-org,jordan,kondakov,115,fleay place,stockland cairns,clayton,2640,,19270806,9876548 +rec-2178-org,kristin,swiggs,24,calder crescent,villa 3,campbelltown,5690,nsw,19460420,1866967 +rec-3565-org,shai,reid,15,morant circuit,stone oak farm,maitland,2905,vic,19151011,5824638 +rec-2494-org,tiffany,schuster,35,vanzetti crescent,snug beach cvn park,smithfield,2579,wa,19440522,6698734 +rec-4095-org,sophie,campbell,16,belconnen way,hazel hill,,2323,qld,19210520,9011644 +rec-4809-org,marianne,reni,23,bath place,eventide home,casino,5118,sa,19920302,1168729 +rec-2778-org,wilson,morell,74,horrocks street,ulinga,toorak,2000,vic,19371114,2710625 +rec-3239-org,elki,menzies,1,lyster place,booroondoo north,northwood,2585,vic,19980624,4970481 +rec-3837-org,lachlan,girdler,3,tiptree crescent,villa 19,toowoomba,2747,nsw,19070323,9886540 +rec-887-org,braiden,kang,74,bastow circuit,inglewood,rivett,2092,qld,19290221,6533958 +rec-4189-org,jordan,campbell,3,brownless street,lamont park,garbutt,2207,vic,19490816,3930891 +rec-2924-org,tarnee,fitzpatrick,8,conjola close,mirani,st kilda,4421,qld,19950715,8081610 +rec-2332-org,laura,mizon,52,mugga lane,jarrah rd shopping town,penguin,2038,nsw,19510906,9223852 +rec-4185-org,jenna,grosser,7,heagney crescent,fronda,ashwood,2528,nsw,19020713,3312375 +rec-2416-org,ella,chell,16,lawrence close,sec 301,harris park,4650,wa,19230110,9573051 +rec-322-org,ayla,mccarthy,268,weavers crescent,yenda units,lake munmorah,3094,qld,19541018,1627605 +rec-1816-org,mitchell,noyce,5,rosella street,rowethorpe,,2540,wa,19660901,2277894 +rec-791-org,matthew,schuster,14,elmslie place,centrefair plaza,ulladulla,2251,nsw,19890911,9319732 +rec-1686-org,james,clarke,119,moondarra street,de cameron,tweed heads,3095,vic,19061129,6885994 +rec-3262-org,alia,haydock-wilson,6,croton street,kimberley,the entrance,3132,nsw,19901212,3171838 +rec-621-org,jake,blake,212,casson street,longridge,geelong west,3280,nsw,19601009,8244609 +rec-1171-org,blake,kontopoulos,1,genoa street,coolinda,penrith,2763,wa,19181122,4193541 +rec-4161-org,jessica,white,4,levi place,habitat,carlingford,6054,vic,19691105,8241849 +rec-254-org,ebony,webb,21,knox street,crestwood,highgate,2196,nsw,19001231,5875656 +rec-1713-org,abby,tsokas,58,barnard circuit,,bassendean,3165,nsw,19290602,3554799 +rec-4036-org,sophie,colquhoun,11,collocott crescent,locn 2093,port augusta,2605,tas,19431223,8018767 +rec-2927-org,sebastian,sitepa,39,whitton close,wychwood,inneston,2526,nsw,19910429,6906715 +rec-4115-org,jake,simmonds,37,castley circuit,lyndilan,mansfield,6027,nsw,19110310,6453549 +rec-4035-org,chloe,worm,6,brentnall place,donna valley,karloo,3128,nsw,19000814,9383057 +rec-461-org,lucas,portlock,2,mccaw place,greenwood,ascot vale,2680,nsw,19960325,7237519 +rec-3179-org,edward,marshman,4,cambridge street,lykabetos,cabramatta,3201,wa,19521111,5673646 +rec-2298-org,fergus,hendy-pooley,3,stace place,nuffield village,oakden,6108,vic,19160101,5515164 +rec-2154-org,ava,,33,kumm place,the manor garden,harris park,2323,qld,19061113,3155906 +rec-3201-org,annika,campbell,71,totterdell street,the mews royal hotel bldg,laverton south,4359,vic,19290222,3988407 +rec-1886-org,william,parr,46,stieglitz circuit,,coromandel valley,6210,qld,19100815,1269870 +rec-3623-org,taalia,clarke,4,notting court,aboriginal nhulunbuy hostel,lindfield,2196,qld,19260303,8505822 +rec-4598-org,samantha,bereza,52,waddell place,shaudell,piney range,6026,vic,19420813,7631947 +rec-641-org,alisha,reid,89,rosenthal street,blue haven village,rushworth,3293,nsw,19951111,3980129 +rec-3315-org,dominic,jormanainen,,geeves court,greta main,,6025,vic,19880214,7639310 +rec-1552-org,daniel,callahan,119,halifax close,medical centre,smythesdale,2400,nsw,19530309,3925704 +rec-2785-org,zachary,callahan,46,barwell place,rosedale,noble park,2710,tas,19210719,5212104 +rec-2290-org,mila,nguyen,145,clutsam place,autum lodge,findon,3350,tas,19780829,1100570 +rec-952-org,brianna,waterston,8,monaro crescent,parraweena,hoppers crossing,2168,nsw,19571109,4074359 +rec-1232-org,kirra,coppola,33,waugh close,tintagel,warilla,3926,nsw,19531118,9223478 +rec-416-org,harrison,zanelli,62,britten-jones drive,weeroona,exeter,4305,nsw,19870724,8743573 +rec-1140-org,luke,beattie,16,blinkhorn place,lucerne park,corrimal,4118,act,19211118,1702856 +rec-4602-org,jade,white,15,wark street,cypress garden,larras lee,2800,vic,19520712,4303672 +rec-1118-org,tai,saunders'wise,40,bugden avenue,grand central,cressy,4207,nsw,19310719,4524499 +rec-3308-org,jared,white,57,walsh place,dunmunkle lodge,evans head,3124,wa,,8491221 +rec-600-org,john,matthews,55,meriden wallaroo road,ivydale (rsd 1820),empire bay,5063,wa,19380716,1321103 +rec-559-org,olivia,david,78,alabaster street,lindoran,,4035,sa,19210322,8629017 +rec-859-org,macey,lowe,4,butlin place,lotus lodge hostel,enoggera,2680,tas,19081128,3271563 +rec-3215-org,nikita,green,4,greenough circuit,glenmarla rmb 2563,elizabeth south,2540,nsw,19941002,8531091 +rec-1244-org,,oreskovic,16,marrakai street,gooroomon park,ballarat,2035,wa,19710815,4253689 +rec-4412-org,jarryd,reid,144,loftus street,sherwood,bundaberg,0812,qld,19630527,8120709 +rec-2729-org,danika,colquhoun,,summerland circuit,victoria square,willagee,3194,qld,19661116,9078185 +rec-4162-org,mollie,sherriff,9,dalley crescent,tarlinup,newstead,4207,qld,19051216,5596459 +rec-1820-org,liam,cullens,121,chandler street,the burrows,safety bay,3073,qld,19910811,7828812 +rec-4092-org,kelsea,snell,5,petterd street,mac donnells bldg (cnr grafton s street,thornlie,4226,wa,19510210,2775215 +rec-2600-org,oscar,vrlic,10,singleton crescent,toora,robertson,4220,vic,19700526,4539064 +rec-3895-org,dylan,laucht,3,hoddle garden,oakbank,redan,5051,vic,19600107,2156016 +rec-4221-org,megan,wilkins,49,rosella street,nioka,eaglehawk,6011,vic,19590204,9298501 +rec-489-org,brandon,strangway,177,robert campbell road,dryrock gulch,toowoomba,4121,nsw,19220610,4691109 +rec-1960-org,henry,webb,15,kalgoorlie crescent,wearmouth,dunoon,3763,wa,19100626,8261350 +rec-2118-org,xavier,pulford,53,nicolle place,nyarrin cottage,findon,6726,wa,19780903,6072382 +rec-848-org,taylah,clapham,27,heard street,,thornleigh,2478,sa,19780416,9336520 +rec-4326-org,mikhaili,appletree,20,mcwhae circuit,crannog,jacana,4115,vic,19061023,9563099 +rec-614-org,lewis,ryan,10,melba street,binna burra mountain lodge,yerrinbool,5118,vic,19591211,9701047 +rec-3807-org,isabella,ryan,81,ackland place,philip centre,kirwan,4173,qld,19940808,6364020 +rec-1680-org,damien,madigan,92,barringer street,forest edge,montmorency,2226,qld,19700502,7969974 +rec-3639-org,taylah,weller,12,eaglemont retreat,kalang,point vernon,2066,nsw,19111122,4433270 +rec-2737-org,tiana,green,18,grylls crescent,rsl veterans retir,blakehurst,4670,qld,19151215,6565990 +rec-957-org,marcus,white,5,verdon street,golf road,punchbowl,4165,vic,19971124,7116750 +rec-3343-org,holly,simmonds,26,sinclair street,unt 2,sunnycliffs,3141,nsw,19970921,9812796 +rec-3022-org,renee,hanigan,109,epenarra close,aleon,flemington,5048,wa,19070928,2588263 +rec-317-org,amber,nicolakopoulos,38,atkinson street,mount patrick,edgewater,2905,sa,19910707,9220881 +rec-3285-org,matthew,coleman,9,eggers place,carinyah station,lalor,4709,vic,19111230,1110230 +rec-1170-org,grace,morrison,5,groom street,hellemere village,concord,3150,wa,19321010,3352261 +rec-3503-org,lily,hamon,59,clutsam place,villa 444 the village glen,ryde,4717,act,19490707,1603670 +rec-4368-org,jacob,white,43,blackman crescent,torrington,gosford east,6164,nsw,19320606,9898855 +rec-1212-org,jasmine,pavli,44,fellows street,little pines,woodville south,6230,sa,19610408,7668302 +rec-1731-org,tayah,yeatmin,65,edmondson street,cedar oaks,sanctuary point,2541,wa,19960422,8014534 +rec-1706-org,montanna,ryan,174,arndell street,peachtree centre,magill,2126,sa,19340527,7545295 +rec-287-org,kira,hand,64,burnside street,cordial factory,limeburners creek,2646,vic,19890422,8605183 +rec-104-org,daniella,steinbacher,5,brigden crescent,the village condo 7,bridgewater,6101,vic,19360208,7992465 +rec-4630-org,max,clarke,12,playfair place,kanga park,potts point,5608,vic,19360102,5709157 +rec-4963-org,,sherriff,97,rischbieth crescent,berkeley vlge,macquarie fields,4152,nsw,19510502,1541627 +rec-3169-org,madison,mcgregor,15,godfrey street,springdale,mount pleasant,2049,wa,19230420,2493506 +rec-2490-org,jack,mayman,65,hutchins street,the meadows,kinglake west,3260,vic,19900106,6187556 +rec-2597-org,fergus,ryan,238,percy crescent,mariner views,birmingham gardens,2148,nsw,19021227,4783232 +rec-4607-org,sarah,noble,75,perrin circuit,westside,glenside,2016,vic,19010712,3254420 +rec-838-org,jackson,campbell,10,marungal avenue,,kunwarara,2445,qld,19420220,7928114 +rec-1763-org,jacob,george,80,hindmarsh drive,glenview,bundaberg,2021,wa,19631006,3031916 +rec-1781-org,jessica,lomman,49,wallis place,glengariffe,north sydney,3039,sa,19531125,6284781 +rec-2822-org,alexander,dixon,115,gaby place,albion grove,springfield,2902,nsw,19760418,5411978 +rec-332-org,caleb,quill,9,rosebery street,laura pengilly wing,granville,5007,nsw,19040203,8733587 +rec-60-org,tiana,ryan,146,doyle terrace,danric lodge,tottenham,3355,sa,19280723,6141484 +rec-3094-org,jacob,heron,4,stubbs crescent,leebold hill farm,bilgola beach,4401,act,19481125,2421446 +rec-1771-org,sam,matthews,15,parkin street,hawkins masonic vlge,camp hill,4305,vic,19131126,8110517 +rec-3010-org,thomas,quast,6,fiveash street,durraween,st clair,4565,vic,19730804,9009452 +rec-4837-org,charlotte,humphreys,10,hayley street,danica,lennox head,4655,vic,19450417,3763315 +rec-1324-org,ruby,matthiessen,35,strickland crescent,the willows,harbord,6007,nsw,19430527,7279879 +rec-3911-org,ruby,warrior,5,ironbark crescent,margaret river carvn park,airds,3075,vic,19550812,7215752 +rec-3446-org,aikaterina,redington,146,chandler street,ben hill,meadow creek,3624,vic,19160205,4293148 +rec-255-org,dante,campbell,5,vaughan garden,kenley lodge,deer park,2572,vic,19641106,7782097 +rec-2051-org,jayden,clarke,31,balanu place,,rainworth,6151,nsw,19870321,6103878 +rec-3547-org,eliza,vimpany,113,renwick street,lakeview caravn park,st ives,4730,qld,19070323,2705720 +rec-4454-org,damien,garnett,4,narrabundah lane,laure,penola,6168,nsw,19480129,7916610 +rec-167-org,jacqueline,finlay,8,nerli place,moondani,st albans,6084,vic,19831107,6173156 +rec-2625-org,renai,leatham,25,arabana street,glenview,frankston,6751,vic,19370312,8777592 +rec-1625-org,chloe,campbell,26,darcy close,boxgrove,kedron,7249,sa,19210221,3030490 +rec-3629-org,april,campbell,101,clive steele avenue,old hillside,,2913,qld,19890501,2285966 +rec-521-org,courtney,clarke,24,myles connell crescent,weemilah,northgate,4621,nsw,19410813,8144739 +rec-1036-org,blake,crook,169,olympus way,glendower,clovelly,3429,nsw,19001215,9317676 +rec-2998-org,chevonne,purser,32,mayo street,tumbeeluwa,sussex inlet,6210,qld,19461220,5908335 +rec-1986-org,sarah,handel,356,twelve trees crescent,maclee,brooloo,4111,nsw,19311009,8033344 +rec-3963-org,oliver,webb,10,melrose drive,grandview,south perth,3078,vic,19220409,6364419 +rec-4296-org,timothy,crouch,78,hussey cove,swinger hill,katherine,4570,nsw,19410812,7583582 +rec-2487-org,joanna,george,12,bage place,,wantirna,2224,qld,19530111,6565352 +rec-94-org,james,compton,19,brewster place,st john of god hospital,edithvale,2234,nsw,19340309,3926610 +rec-1912-org,mackenzie,sherriff,34,pirani place,,scarborough,2094,nsw,19610123,8088200 +rec-260-org,aleesha,reid,21,cadell street,eventide homes,trafalgar,2582,vic,19840824,6890084 +rec-3743-org,lachlan,kluske,4,perrin circuit,violet creek,lindfield,3978,nsw,19240721,8252947 +rec-1617-org,flynn,mason,11,namatjira drive,wellshot,blackburn north,2756,wa,19110824,2236689 +rec-877-org,reegan,sporn,17,braine street,tongbong sanctuary,port augusta,3070,nsw,19650504,6852017 +rec-3051-org,caitlin,papanotis,1269,de burgh street,aptmn 12,cleveland,2100,wa,19720329,2397064 +rec-2464-org,alexander,preston-stanley,11,proctor street,,mooroolbark,3020,qld,19160502,9012024 +rec-3482-org,kyle,wegman,16,clyde place,parkland motor village,modbury,4213,nsw,19790106,4561101 +rec-4870-org,carlin,garcia,46,von guerard crescent,,clarendon,2140,nsw,19241024,1512461 +rec-2975-org,isabella,mcfadden,133,bennelong crescent,cranbrook,port fairy,2833,qld,19440706,4644493 +rec-3966-org,james,truman,4,knoke avenue,red hills,wallsend,4221,act,19740918,7208464 +rec-3361-org,isabelle,bullock,10,companion crescent,eden park,henty,2212,nsw,19920128,5801283 +rec-3485-org,sarah,white,97,murranji street,,cronulla,2287,wa,19320303,7287941 +rec-1127-org,william,bobbitt,30,woralul street,jingara,woy woy,2340,nsw,19240413,8601795 +rec-3569-org,madeleine,white,50,hunter street,university shores,marlow lagoon,2500,sa,19401228,6386791 +rec-4805-org,kadin,david,20,frater crescent,nareen gardens hostel,ottoway,4218,nsw,19020916,8270473 +rec-2524-org,ryan,moody,7,tyrrell circuit,pooley bridge,nedlands,3809,nsw,19320818,7217442 +rec-4652-org,michaela,mcandrew,25,parker street,,ryde,3128,vic,19170418,2879085 +rec-4555-org,caleb,purbell,53,banksia street,rosevillea,rye,4740,act,19490425,8230410 +rec-1537-org,max,jolly,23,buvelot street,raaf,mooloolaba,3156,wa,19070819,8870856 +rec-1273-org,kane,markijevic,51,maltby circuit,moyola,briar hill,2452,nsw,19310315,5758876 +rec-4914-org,charles,matthews,2,magarey place,rowethorpe,penguin,2560,qld,19150316,5165120 +rec-3292-org,mikayla,siviour,2,steinwedel street,cherrybank,pymble,2037,vic,19850704,2668143 +rec-2183-org,naomi,matthews,81,tate street,kawana shoppingworld medical centre,,2192,vic,19821011,1390365 +rec-2675-org,kobe,buckinghan,47,wrixon street,the willows,kariong,3357,vic,19481019,9604781 +rec-227-org,tayah,kiss,20,bateman street,flower growers,vermont south,6163,vic,19741212,6517742 +rec-3019-org,blayke,browne,1,gosse street,,cape paterson,4215,vic,19210917,7165012 +rec-507-org,ty,white,25,newbery crescent,jillamtong,albany creek,3630,tas,19111216,1390829 +rec-2308-org,sophie,white,251,handcock crescent,,wetherill park,5114,vic,19480529,7242421 +rec-2928-org,harriet,doogue,4,mugga lane,concept,matraville,3194,qld,19091014,4166027 +rec-1613-org,connor,lowe,50,augustus close,corunna,west lakes shore,2071,nsw,19611015,1592036 +rec-2143-org,benjamin,royans,35,bootle place,denmore,floreat,2756,vic,19100121,6512947 +rec-1949-org,benjamin,boccuzzo,1,ashley drive,oyster farm,buckleboo,3165,sa,19730308,5401507 +rec-1734-org,bethany,white,24,horrocks street,hybernia park,bittern,3075,vic,19910219,8903580 +rec-3224-org,nathan,dudley,2,chevalier street,,wantirna,3150,vic,19740724,6423373 +rec-3415-org,grace,telleglou,13,bywaters place,environa,tusmore,3101,sa,19060204,6170642 +rec-2847-org,emiily,boyle,25,bega flats,rose valley farm,loganlea,3141,wa,19220406,5388162 +rec-4282-org,maxin,jolly,8,huxley place,,mooloolaba,2220,wa,19330915,7131922 +rec-226-org,,faehse,65,henry melville crescent,goonahra,wanniassa,2173,vic,19490602,9923153 +rec-1950-org,,mccarthy,24,oliver street,brentwood village,cherrybrook,2880,vic,19350103,5462917 +rec-4366-org,george,neeb,33,goyder street,killarney park,warrell creek,4114,vic,19581231,1539196 +rec-234-org,jack,wyllie,11,parker street,fulham park,daisy hill,2440,nsw,19730825,7977290 +rec-4808-org,lucy,satterley,32,gill street,nepean shores,buninyong,4226,sa,19660516,9616924 +rec-1325-org,hayden,ayres,22,castleton crescent,kojonolokan hills,leongatha,2107,sa,19970513,1502848 +rec-4561-org,april,mccracken,1217,henning place,john flynn hospital,dandenong north,5356,nsw,19170824,9290031 +rec-1940-org,pace,nguyen,352,marquet retreat,joint coal board,labrador,3064,sa,19670320,3133672 +rec-2943-org,tara,,67,beauchamp street,grey oaks,robertson,2213,,19121013,7897903 +rec-4868-org,flynn,dreyer,148,hayden close,hawkesbury natural health acupuncture ce,sanctuary point,3669,,19010221,3597112 +rec-787-org,connor,neumann,302,debenham street,sandalford homestead,the entrance,2774,vic,19790629,1382097 +rec-619-org,harrison,burford,25,paul coe crescent,earl haven,ashgrove,6028,qld,19160131,4722591 +rec-1128-org,alissa,yelds,2,bingley crescent,woodlands house,beaudesert,3012,sa,19881106,8003824 +rec-1175-org,alexandra,margush,15,inkster street,st agnes vlg,carrum,3930,qld,19060712,9221028 +rec-4156-org,andrew,gaskin,17,trenwith close,merrydale,turner,4567,nsw,19021013,1066355 +rec-4250-org,mhary,matthews,26,foxall street,upper yarrowitch,newcastle,6525,vic,19540913,2983255 +rec-2036-org,emiily,capel,1721,burkitt street,locn 1025,ascot vale,4053,nsw,19341111,3160127 +rec-2237-org,ebony,garcia,15,rylah crescent,brbe is retmt vlg,waratah west,7310,tas,19630715,9950832 +rec-1976-org,amy,moyse,17,jackie howe crescent,coulter court,sylvania,2571,vic,19740103,7813497 +rec-4820-org,madeline,harrington,18,coulton road,ashmill park,brighton,2464,vic,19140630,8478957 +rec-4113-org,sophie,au,26,pelham close,locn 2192,sandy bay,3192,vic,,4507512 +rec-3694-org,kylee,pennell,1,chewings street,drypoint,,4570,sa,19000320,4020041 +rec-662-org,lily,kradolfer,12,wanganeen avenue,broughton brook,toowoomba,2750,vic,19501111,2841376 +rec-4944-org,lachlan,couzens,5,salvado place,hobart private hospital (cnr argyle),taree,2211,vic,19690911,1741428 +rec-313-org,amelia,mo,46,,rowethorpe,waterloo,2017,vic,19010613,6555841 +rec-1268-org,,reid,11,alt crescent,green lagoon,camp hill,6026,vic,19671214,5483640 +rec-128-org,jasper,rylands,10,abernethy street,,ingleburn,2784,nsw,19730615,9353426 +rec-89-org,ned,stephenson,46,donohoe place,australia arcade,menangle,2222,vic,19750118,6310028 +rec-3039-org,bodhi,procter,5,box hill avenue,st francis village,broome,2760,vic,,8515756 +rec-3572-org,james,weller,46,bugden avenue,kingaroy garden,hopetoun,2220,vic,19000913,2789546 +rec-3312-org,zara,george,3,legge street,lashbrooke,mount low,3136,qld,19150920,3122448 +rec-3280-org,brock,schembri,71,arkana street,redwood village,colac,3156,wa,19530417,8819783 +rec-95-org,mikayla,webb,144,cooling place,,norwood,0800,sa,19880716,8983519 +rec-3912-org,thomas,grooby,6,noel ryan garden,emu ground,new lambton heights,2460,nsw,19640331,3528341 +rec-3172-org,rachel,dinh,12,kidston crescent,,taigum,2560,wa,19140331,1015158 +rec-4898-org,aidan,dohse,14,dilboong place,sunningdale farm,hurstbridge,4510,tas,19191229,4932448 +rec-2641-org,andrew,ryan,9999,woralul street,fleurbaix,flinders park,2066,nsw,19510328,2922598 +rec-2823-org,james,worsley,1,pike place,melaleuca,broadmeadows,4818,nt,19651211,5706752 +rec-4734-org,anthony,burkevics,1,dryandra street,alexandra racecourse,ballarat,3048,vic,19180927,5593368 +rec-4766-org,samara,campbell,8,packham place,kokoda hostel,burpengary,3136,wa,19010604,6449470 +rec-4851-org,noah,doman,20,boucaut place,oakdale,clarinda,3072,vic,19861126,4747349 +rec-3364-org,jessica,maynard,26,archdall street,alchera vlge,bourke,3141,nsw,19471209,7562694 +rec-2227-org,christian,capurso,106,burkitt street,giniderra,frankston,4103,vic,19210722,2242368 +rec-1673-org,angus,crook,4,shoalhaven avenue,,springwood,2227,nsw,19641105,2959647 +rec-941-org,william,zilm,64,,moonya cottage,east fremantle,2165,act,19430728,8235647 +rec-4061-org,melinda,trent,28,dugdale street,kilwinning,penshurst,4556,qld,19240721,5930609 +rec-3074-org,aleisha,beadle,139,leonard close,broadbridge manor,madora,3025,nt,19160701,3130361 +rec-2983-org,lucy,morrison,3,starke street,sheep station,petersham,2250,nsw,19271205,8707221 +rec-2885-org,max,mayer,36,riley close,braeburn,wyndham,6056,vic,19350817,7515435 +rec-1964-org,sophie,haythorpe,12,bamford street,kioma,alligator creek,6230,sa,19670909,3361594 +rec-978-org,rebecca,riddell,10,glasgow place,fowlers bay,picnic point,2195,tas,19010105,2892366 +rec-590-org,blake,doray,2,muresk street,,st albans,2305,qld,19410221,6927749 +rec-1163-org,mia,burford,4,starling place,dutch care hostel,lawson,2257,vic,19040422,9377441 +rec-3369-org,callum,lowry,52,hallen close,ruglen,picnic point,2000,vic,19971123,3987913 +rec-912-org,leo,george,38,langridge street,greenwood,braidwood,2038,nsw,19631227,2248161 +rec-2102-org,connor,soulsby,53,bussau close,hi pine,mooroolbark,3109,nsw,19750429,7659266 +rec-4748-org,zane,tao,5,cromwell circuit,heversham,lalor,4825,nsw,19631204,7503892 +rec-1918-org,abbey,milburn,18,dixson circuit,the willows,rosebud,5075,qld,19631114,4451215 +rec-331-org,harrison,whaipe,19,westall place,ainslie house,baranduda,3220,qld,19170531,7892154 +rec-1597-org,april,durbridge,20,wilkinson street,,toolleen,3630,sa,19190524,3179675 +rec-1137-org,emiily,mac onochie,6,temperley street,kerradan,andergrove,2326,sa,19440717,6618917 +rec-3553-org,james,stearnes,8,leahy close,,bayswater,3195,nsw,19330802,9900161 +rec-2824-org,riley,noble,23,onkaparinga crescent,bellambi,cabarlah,3959,sa,19130706,1621751 +rec-2930-org,ashley,webb,39,wilkins street,,reynella,7315,wa,19670423,7920236 +rec-3992-org,braedon,spratt,39,chave street,sunbury,oaklands park,4054,nsw,19170824,5276247 +rec-1626-org,katelin,thorpe,93,vagabond crescent,furmiston,cabramatta,4570,nsw,19930611,8939082 +rec-2540-org,giorgia,struck,5,ambalindum street,lazy acres,thornlie,2144,wa,19250507,4468206 +rec-1089-org,malakai,crouch,303,ragless circuit,westbury,paddington,3073,qld,19510719,5426853 +rec-1433-org,solomon,boecke,42,dirrawan garden,,whitfield,2099,qld,19321217,7045068 +rec-3650-org,matthew,clarke,95,crombie place,dandarra,oak flats,3170,nsw,,8347782 +rec-2164-org,channing,genovese,193,fernyhough crescent,cockatoo,clayton,7140,sa,19570424,4371940 +rec-4967-org,james,feast,139,goldstein crescent,kooringle park,beenleigh,4214,vic,19500714,9202596 +rec-3149-org,bethany,jolly,31,melba street,sheep station,paddington,3039,wa,19690622,9831162 +rec-1610-org,brock,nygaard,58,lockyer street,barossa village,kununurra,2079,vic,19730526,4753010 +rec-954-org,noah,shepherd,50,kingscote crescent,tewantin plaza,drillham,4650,vic,19590501,2779286 +rec-1703-org,jett,white,37,marshall street,avalind,greenacre,3500,wa,19141102,4115932 +rec-2447-org,mattheo,godfrey,107,madigan street,tantallon,mayfield,2444,vic,19811231,1967139 +rec-3234-org,jessica,ryan,3,stonehaven crescent,eagleview,edgecliff,6166,nsw,19570904,2097814 +rec-2947-org,,herbert,2,copland drive,booligal,gin gin,3971,nsw,19160928,7114569 +rec-4333-org,anton,marinos,44,geils court,mayflower retrmnt vlge,bridgewater,4066,vic,19510826,7146893 +rec-2448-org,gabrielle,siemers,28,archibald street,seaforth garden,american river,5223,vic,19140203,4388778 +rec-2208-org,lauren,hainke,2,la perouse street,rhode island resort,old erowal bay,4505,qld,19040319,8687104 +rec-3147-org,mia,white,40,dyson street,dishley farm,greenacre,7249,sa,19410125,1462412 +rec-3885-org,louise,campbell,3,clark close,manton's rise,annandale,2360,vic,19871212,6743419 +rec-140-org,thomas,bullock,5,mccawley street,yarrabin,oakleigh,2448,nsw,19260922,2517453 +rec-1281-org,dylan,nguyen,33,macgregor street,nootina,geraldton,3028,nsw,19710131,7703063 +rec-3522-org,bethany,caire,10,mountain creek road,trail view,paddington,3228,wa,19361026,4393661 +rec-2130-org,isobel,dreckow,10,landor place,harlyn,old toongabbie,2650,qld,19101019,2584672 +rec-69-org,shaun,sleath,59,moorhouse street,inverneath,eight mile plains,3805,sa,19580910,2873897 +rec-2148-org,nathan,green,10,franc place,tara park,marsden,3337,qld,19060131,4028347 +rec-3858-org,mitchell,forshaw,6,canning street,karobean,yanakie,2631,nsw,19730626,8308037 +rec-3488-org,emiily,mchenry,1,hurwood place,paramatta park,leeton,2228,nsw,19550504,1357509 +rec-3641-org,jake,willmot,33,,eventide homes,ringwood east,2538,vic,19171002,3406386 +rec-1332-org,benjamin,blake,4,phillimore place,tara park,sutton forest,3300,nsw,19481216,9939498 +rec-1975-org,tegan,whiteley,7,casuarina street,retirement village,oakleigh,5211,nsw,19440305,6180156 +rec-90-org,barnaby,godfrey,18,hopegood place,osters,brighton,5086,nsw,19461029,4625012 +rec-3826-org,wilson,hannagan,25,boolee street,gowen,invergowrie,2290,nsw,19641216,4883777 +rec-2418-org,chloe,mason,62,kinchela crescent,meilene retirement,spotswood,6530,vic,19400204,7931480 +rec-3456-org,lucy,purdon,1,beauchamp street,,maida vale,3153,sa,19510318,1098632 +rec-4390-org,riley,mercorella,16,emery street,yarrambah,kununurra,2048,qld,19541031,6022838 +rec-3399-org,toby,fernando,15,ulm street,quandialla,ashwood,2141,vic,19380511,2977480 +rec-2362-org,isabella,needham,5,ramage place,tantallon,prospect,2151,qld,19621223,9696568 +rec-250-org,lauren,shack,345,rushbrook circuit,research station,warrandyte,4740,tas,19590103,1987058 +rec-3236-org,carla,pegg,56,martens crescent,diamond sands,embleton,2577,qld,19200214,5556197 +rec-1279-org,,kowald,3,hindmarsh drive,green desert,greenwood,2016,sa,19440126,8957090 +rec-291-org,oliver,howie,28,hazel smith crescent,cala sona,paralowie,2120,vic,19510822,1204980 +rec-2096-org,deakin,secomb,10,gelane street,palm lake resort,raby,7052,nsw,19830930,3116371 +rec-3144-org,isabella,flassman,28,mceachern crescent,st vincents hospital,rosebud,2122,qld,19651224,1271090 +rec-2549-org,matthew,roche,67,orchard place,foveaux terraces,mill park,3850,vic,19040419,6928752 +rec-2125-org,chloe,white,22,macgregor street,merimaja,bunbury,2782,nsw,19330113,6064969 +rec-4984-org,thomas,campbell,12,fawkner street,the mews royal hotel bldg,ormond,4104,nsw,19631111,6974163 +rec-4625-org,joshua,seddon,1,murranji street,parkridge villa,slacks creek,2650,qld,19090214,3661114 +rec-519-org,joshua,baillie,8,de baun crescent,,bonython,2173,qld,19650415,6504350 +rec-1184-org,connor,paine,10,adair street,kangarilla,warren,3194,sa,19140306,5213108 +rec-2531-org,isabel,nguyen,8,mccawley street,jarkhellms,campbelltown,2122,vic,19860530,3659521 +rec-2768-org,makenzie,reid,23,sherbrooke street,torbanlea,st ives,2010,qld,19930630,9745948 +rec-1853-org,jade,clarke,63,fred williams crescent,plainview,kitchener,3127,nsw,19350407,4177466 +rec-1211-org,madison,dent,14,mault place,rockwood,gordonvale,0886,wa,19440208,1552323 +rec-3174-org,jasmine,webb,1,duffy street,kildrummie,parkside,2150,vic,19440610,1750989 +rec-2579-org,madalyn,mccarthy,53,lind close,tressing fields,beenleigh,2291,qld,19620612,6626116 +rec-4276-org,tristan,shepherdson,33,benson crescent,allensleigh,brighton,4356,vic,19170129,2179147 +rec-3185-org,shelbey,david,19,stephen street,pine tree,port macdonnell,3172,qld,19810202,3051544 +rec-4090-org,lia,hyland,36,lomatia place,walkers ridge,regents park,3196,nsw,19001225,9557159 +rec-137-org,thomas,paine,215,ina gregory circuit,stone oak farm,kilcoy,7330,wa,19881207,2550718 +rec-2363-org,tara,wiseman,33,goldner circuit,underwood,monbulk,3816,qld,19581001,9605792 +rec-3328-org,,koteschel,3,mayne street,grey oaks,swan view,4305,vic,19430808,1393004 +rec-3875-org,lucas,zimmermann,27,mckail crescent,public school reserve,elsternwick,2443,wa,19340306,9888953 +rec-403-org,marcus,stoneman,273,pankhurst crescent,glenfenzie,joondalup,2126,nsw,19200506,3830720 +rec-1048-org,alexandra,budge,11,outtrim avenue,sec 528,jacana,2096,wa,19590819,3277841 +rec-444-org,alana,zoanetti,19,gudgenby close,,birkdale,2113,sa,19510214,1412351 +rec-3248-org,saara,ljubic,2,tompsitt court,gracewood aged care centre,melville,4575,sa,19970725,3886202 +rec-2398-org,caleb,librandi,48,kidd place,donore,applecross,4865,tas,19730404,5522569 +rec-3775-org,madison,cother,34,kaberry place,camp david,cooloongup,2539,wa,19200710,2827954 +rec-558-org,alicia,white,9,darrell place,,fletcher,2850,vic,19821015,7695489 +rec-4485-org,jarod,lusted,22,prescott street,girrahween homestead,beaumaris,4502,nsw,19321125,6642172 +rec-4048-org,lewis,dorsey,50,schomburgk street,deltroit station,woy woy,2650,vic,,5250955 +rec-4902-org,jarrod,crouch,33,currong street,montrose,st james,7316,nsw,19180503,4588775 +rec-4419-org,jessica,mac neill,13,neeld place,bessy sue,sheffield,3124,act,19160213,6416337 +rec-759-org,coby,mason,220,blandon place,karingah,kangaroo flat,2315,nsw,19641221,4800165 +rec-2225-org,matthew,,29,forbes street,locn 7560,botany,3019,nsw,19291107,9737703 +rec-1583-org,isabella,elferkh,16,moore street,bangor lodge,,3044,vic,19451228,4582565 +rec-1074-org,benjamin,paterson,31,dodwell street,,devonport,2095,nsw,19120913,6303884 +rec-2368-org,liam,katnich,28,sculptor street,villa 2,upwey,2077,nsw,19370824,9117501 +rec-1304-org,sarah,paterson,57,gingana street,st francis village,williamstown,2784,wa,19011215,6278915 +rec-2703-org,alyssa,coleman,9,marsden street,main beach medical centre,rowville,4556,qld,19260829,5376425 +rec-3106-org,finn,kazimir,472,belconnen way,redwood lodge,mackay north,2502,sa,19880315,6526812 +rec-2818-org,deakin,early,8,wells garden,rpc 371031,berwick,2203,nsw,19851002,4961865 +rec-4882-org,charlotte,saltiel,25,discovery street,wanderers rest,long jetty,2135,sa,19291014,4955093 +rec-1681-org,matthew,widdowson,304,shain place,canberra hse,laverton,4878,nsw,19450221,8346142 +rec-4821-org,ethan,fitzpatrick,10,laughton street,manor park,thornbury,6258,vic,19040922,6023201 +rec-2331-org,christian,reid,10,britten-jones drive,honey patch,moe,2250,wa,19870501,2773283 +rec-327-org,aleisha,campbell,4,mackay crescent,,coolamon,5011,sa,19910630,3454612 +rec-573-org,james,bissett,115,ellerston avenue,pepin,hawthorn,3268,sa,19400613,5935841 +rec-4738-org,mitchell,white,2,denovan circuit,bracken leigh,mill park,6210,nsw,19681012,1236544 +rec-4386-org,taylah,rankine,6,kibby place,colooli village,dungog,7179,vic,19530816,8828523 +rec-2231-org,madalyn,noble,21,waddell place,caroona village,mathinna,4051,nsw,19460804,7883652 +rec-4712-org,aidan,webb,14,benny place,,rosewater,6023,vic,19410718,5320865 +rec-799-org,jack,green,,macalpine close,,aspley,6014,wa,19350317,4402882 +rec-560-org,caitlin,bossence,58,aston crescent,greenslopes,condell park,3023,nsw,19040426,7998798 +rec-2166-org,isabelle,geraghty,16,hawdon street,council accomm,theodore,4812,nsw,19861012,4201009 +rec-4586-org,,webb,168,booroondara street,the willows,lakes entrance,3179,vic,19911219,6504363 +rec-200-org,gianni,carrabba,670,bambridge street,grangemore,bassendean,2602,vic,19740108,9777753 +rec-3747-org,ashlie,hanks,11,meares place,coorrabin,mentone,2038,nsw,19380614,4349715 +rec-1063-org,zachariah,schmitzer,5,alford place,rosetta village,budgewoi,5051,wa,19560103,3180656 +rec-4284-org,sophie,finlay,7,badimara street,ewlyamartut farm,ringwood,2046,sa,19230607,3775980 +rec-1649-org,joel,dixon,19,callister crescent,glenmore,burpengary,3190,nsw,19810902,7849806 +rec-3577-org,mitchell,hruby,23,illidge place,milbrodale,crescent head,6225,qld,19790712,3945815 +rec-1831-org,mia,reid,4,le hunte street,marretah,como,3777,vic,19800421,3451673 +rec-1635-org,roberta,laing,23,morrison street,budgereebella,flagstaff hill,4753,vic,19690425,5204352 +rec-4271-org,sam,reid,333,leahy close,lavender farm,cabramatta,2291,vic,19961213,1592375 +rec-2060-org,jacob,ditty,19,woralul street,secatry,morwell,3153,qld,19670501,1212121 +rec-4932-org,ruby,ayres,36,bussell crescent,mountview,margaret river,2765,vic,19210901,5485654 +rec-4683-org,stephanie,heidrich,7,zamia place,cooroora,hyde park,6101,qld,19841214,7559482 +rec-3116-org,hollie,green,7,darlot place,wanneroo central shopping centre,cleveland,2590,wa,19240914,1412872 +rec-980-org,samir,teal,8,baldwin drive,doribank,lilydale,5092,nsw,19600901,6271964 +rec-732-org,renee,chandler,6,kenny place,redgums (rmb 1239),beulah,5075,wa,19360610,8922410 +rec-1590-org,paige,paterson,8,lindrum crescent,miandetta,st james,3805,nsw,19090422,5550381 +rec-524-org,ethan,white,23,chippindall circuit,keralta,moura,4152,wa,19411106,9247028 +rec-158-org,abbey,,17,starke street,gordale,fadden,2286,vic,19150829,6050399 +rec-3111-org,bianca,bishop,96,crozier circuit,linton,wolvi,4812,nsw,19761209,6772943 +rec-3113-org,bailey,pascoe,311,tillyard drive,lindenleigh,hamilton,4030,nsw,19960928,2933911 +rec-3951-org,lachlan,nguyen,23,templestowe avenue,elmwood,o'connor,5046,vic,19931013,8311385 +rec-2693-org,makayla,malpas,255,hallen close,musgrave house,sippy downs,4214,nsw,19361113,9173799 +rec-3829-org,grace,white,27,beagle street,apmnt 203,morwell,4655,sa,19411110,3498158 +rec-3476-org,cameron,matthews,6,blackett crescent,cranbrook,peterborough,4701,qld,19320515,2692792 +rec-2596-org,amber,green,20,tom roberts avenue,kimberley,north ryde,2540,nsw,19530919,3705115 +rec-2802-org,michael,bartel,6,chewings street,buena vista,sea lake,2777,nsw,19550822,9818191 +rec-918-org,jessica,michelmore,103,fimister circuit,swannie,mooroolbark,4174,nsw,19761101,6406097 +rec-1335-org,indiana,jeffries,2,carrodus street,clarkwood,cremorne,2615,nsw,19790628,5993849 +rec-2874-org,hannah,donaldson,25,golding place,lockwood,mcmahons point,4213,qld,19390126,5871551 +rec-2038-org,marlee,boss,16,slessor crescent,north arm,ballarat,2134,sa,19940504,2633944 +rec-3453-org,jasper,ryan,58,clifford crescent,karbar station,brunswick west,2480,vic,19331202,5561624 +rec-2727-org,madison,noyce,13,walker crescent,acadia,penguin,2323,qld,19520621,7975425 +rec-4396-org,brayden,tomney,6,spring range road,killarney,sunnybank,4670,nsw,19031003,3973459 +rec-2622-org,jaden,jessup,,rubbo crescent,glendas,gosford east,5641,qld,19030304,8577794 +rec-510-org,sara,karlsen,6,tarrant crescent,kia-ora cottage,parmelia,2154,vic,19520602,6200753 +rec-1134-org,lachlan,ebert,37,barcoo place,low ponds,corio,3191,sa,19720105,4689114 +rec-1045-org,harrison,hoang,10,mccaughey street,winchester downs,preston,4226,vic,19360225,1076510 +rec-4724-org,brooke,bristow,11,minter place,wilsonton medical centre,ngunnawal,4551,vic,19890212,7893433 +rec-2830-org,jesse,webb,48,pennington crescent,thistledoo,currajong,6112,nsw,19931125,1432305 +rec-1785-org,tiarna,white,1,faucett street,dallyn,childers,4880,qld,19310412,3803605 +rec-1894-org,jake,mccarthy,19,jacobs street,the richard house,hoppers crossing,3021,vic,19501129,9421400 +rec-3666-org,sean,gaskin,51,harris street,waterdale,newmarket,4226,wa,19030720,5111528 +rec-4148-org,gabrielle,richmond,2,ebenezer street,peak view,oakleigh,4352,sa,19941228,5532143 +rec-807-org,jayden,glass,33,henry melville crescent,biboohra downs,sanctuary point,2283,qld,19510331,4079997 +rec-3067-org,joshua,beaty,19,blackwood terrace,the summer house,prospect,6163,vic,19721121,1725695 +rec-1430-org,willow,gowling,39,hannaford street,the briar patch,moama,4570,vic,19690421,9703540 +rec-4232-org,zali,shadbolt,56,tillyard drive,,brown hill,4800,wa,19440205,7276255 +rec-70-org,andrew,boyle,17,curtain place,,picton,3184,qld,19400722,1618417 +rec-2083-org,felicity,white,11,froggatt street,rsm 849,keilor east,3132,nsw,19060724,9227304 +rec-2310-org,isaiah,dixon,6,whitford place,ettalong beach village,bonville,3072,qld,19321222,5795586 +rec-4817-org,marleigh,bishop,191,maltby circuit,lambrook,tammin,3029,wa,19311231,2010323 +rec-2881-org,emiily,paterson,9,wiburd street,parraweena,colac,2021,qld,19881213,6732942 +rec-2293-org,trinity,spark,60,larkin close,moline village,mulgrave east,3023,nsw,19470913,5766734 +rec-3222-org,andrew,reid,51,arndell street,ocean hunter,eastwood,4054,qld,,4475335 +rec-4895-org,kiandra,waller,41,stobie place,west road,rossmoyne,4017,vic,19480123,5588564 +rec-2781-org,andrew,madigan,69,blackwell circuit,tintagel,dianella,0820,sa,19871218,5096835 +rec-1195-org,jessica,blackwell,20,mcgee place,brentwood vlge,ermington,2795,sa,19801015,4099338 +rec-695-org,toby,quill,5,anembo street,sect 329,strathalbyn,5253,vic,19380703,6115722 +rec-2574-org,jacob,hewson,32,hambidge crescent,telooma,tallangatta,2800,qld,19460104,3624543 +rec-3473-org,cooper,geraghty,75,sidaway street,mundine 30 km,berwick,2084,vic,19480422,5034488 +rec-4542-org,crystal,branston,104,officer crescent,section,bar beach,3039,sa,19720329,3133369 +rec-611-org,ella,wisby,91,kingscote crescent,,homebush,2291,wa,19920720,9301098 +rec-3240-org,james,crook,3,antis street,myrrhee,shelley,2711,nsw,19510227,5851238 +rec-1755-org,jayden,white,10,mcclintock street,kinvarra,melville,4380,nsw,19590819,2360230 +rec-4885-org,lia,shelley,102,wisdom street,de cameron,port lincoln,2747,tas,19510313,7625458 +rec-2199-org,emiily,allard,19,kingsbury street,moons farm,broken hill,4218,nsw,19760502,6633337 +rec-1322-org,kiana,harrington,35,boult place,karmont,narrogin,4053,vic,19710705,5786506 +rec-2357-org,kirrah,cannell,560,cherry street,gloccamorra,,4170,nsw,19511103,1567556 +rec-685-org,zachary,clarke,19,melrose drive,jemular downs,whitfield,7000,wa,19680624,3444095 +rec-1257-org,chelsea,clarke,26,namadgi circuit,villa 74 village glen,anglesea,6025,nsw,19230828,3467697 +rec-2261-org,kylie,seppelt,4,tanner place,wearmouth,modbury,4883,qld,19251024,3972497 +rec-1507-org,dominic,woodmansee,500,sculptor street,calleen farm,punchbowl,6111,nsw,19170707,4369787 +rec-14-org,raquel,lodge,60,archibald street,,balwyn north,2025,wa,19280505,9100106 +rec-3015-org,kyle,clarke,19,archibald street,little forest,florey,4109,qld,19380419,6477305 +rec-514-org,chelsea,asher,33,bargang crescent,john flynn medical centre,ascot factory,3976,vic,19710526,1038123 +rec-2504-org,luke,ayres,18,longstaff street,locn 8200,salisbury,4161,wa,19290207,3550340 +rec-663-org,dean,wiseman,27,currong street,palm garden villas,cromer,4305,qld,19740808,1613598 +rec-296-org,tristan,blackwell,36,yarralumla bay,kookaburra village,meadow springs,4805,nsw,19430206,2993599 +rec-2071-org,jack,voskulen,24,mccubbin street,inveraray,toorak,2600,nsw,19540407,6075780 +rec-1484-org,holly,koteschel,1,torrens street,forest hills,toowoomba,6230,wa,19210307,5119507 +rec-2307-org,matthew,gartz,60,cromwell circuit,mari-ma farm,holden hill,0812,nsw,19000327,9274478 +rec-2366-org,samuel,degeorge,2,jefferis street,dorothy genders vlge,nedlands,2206,vic,19510912,1167786 +rec-2744-org,catherine,newport,13,hawkesbury crescent,nedlyn,pinjarra,4870,vic,19580901,1828218 +rec-1574-org,zarran,mcsorley,28,hollway street,orana gardens retirement village,burraneer,7051,nsw,19170409,2480177 +rec-4259-org,samuel,nowers,42,white place,apt 211,murray bridge,6714,nsw,19970522,8136092 +rec-1254-org,ryley,colombini,14,yambina crescent,lourdes hostel,ermington,3148,nsw,19760717,1751137 +rec-4844-org,alessandra,mcneill,364,kelleway avenue,bodyworks healing centre,broken hill,2763,qld,,5866707 +rec-984-org,lucy,bickerstaffe,108,graham street,,marmong point,3153,qld,19860422,2491252 +rec-2628-org,nathan,paterson,47,allambee street,tamaview,barwon heads,2317,vic,19811021,9877542 +rec-714-org,emiily,zeck,7,garanya street,rowethorpe,granville,3226,wa,19000603,9875041 +rec-4163-org,lawson,brooker,6,,cascades,brunswick heads,3218,nsw,19960904,9338356 +rec-1798-org,pace,berry,28,sadlier street,windella downs,nunawading,2135,vic,19170713,2158184 +rec-1376-org,kieren,green,32,brockway circuit,nuffield village,torrensville,4221,nsw,19591115,4867858 +rec-4034-org,jye,blake,19,dixon drive,kordella park,inglewood,3134,qld,19380918,4212518 +rec-1842-org,gabriel,vigneswaran,80,chuculba crescent,,altona meadows,3159,qld,19560125,4243167 +rec-4744-org,grace,mcvicar,39,namatjira drive,,greenacre,4818,vic,19540503,2929679 +rec-965-org,macy,beaty,131,maloney street,cottage rn east,medina,6027,tas,19980531,8216119 +rec-951-org,juliana,clarke,24,jondol place,northwood park,holsworthy,4067,nsw,19970330,5071393 +rec-1770-org,jessica,boyes,27,molloy crescent,sec 1569,scarborough,4551,tas,19610514,7635289 +rec-4880-org,mikaela,webb,18,knoke avenue,lindis faime,lalor park,3163,nsw,19520804,2143157 +rec-1213-org,brendan,whillas,30,horrocks street,bass view,carlingford,6061,qld,19140619,7279575 +rec-4850-org,cooper,rovira,19,maclaurin crescent,suunybrae,broken hill,3144,qld,19121113,8734370 +rec-3363-org,taylor,weaver,100,allambee street,corcoran,preston,2681,nsw,19770725,5276236 +rec-3555-org,thomas,hunting,880,shannon circuit,aboriginal nhulunbuy hostel,port macquarie,2904,vic,19270513,7068400 +rec-4736-org,julia,jolly,59,a'beckett street,millwood,slacks creek,3020,nsw,19820807,7111279 +rec-2910-org,dakota,brokenshire,2,jackie howe crescent,emmaus vlge,pialligo,2024,wa,19861028,7729416 +rec-2181-org,,clarke,13,hicks street,brentwood vlge,broadmeadows,3095,vic,19340818,7285543 +rec-2117-org,chloe,ryan,53,yarra street,balmoral garden,seymour,2905,vic,19450712,4309035 +rec-583-org,reganne,mcveigh,2,souter place,,ermington,2763,vic,19310928,5159705 +rec-1640-org,ned,hamblin,9,bokhara circuit,,ballarat,5022,act,19150226,9945787 +rec-1237-org,jordan,berry,41,anderson street,wilga,moorabbin,2097,vic,19880826,2009434 +rec-718-org,evan,kranz,33,pandanus street,tantallon,bowral,2264,nsw,19330726,6581103 +rec-1267-org,gabriel,is,168,embley street,blueberry hill,burnie,4551,vic,19111213,4120890 +rec-4533-org,lily,berry,77,crofts crescent,railway cottage,rose bay,3340,sa,19590415,6015647 +rec-4918-org,christian,la rance,18,tristania street,the swamp,mermaid waters,6020,nsw,19580426,2857093 +rec-768-org,jasper,kuiters,109,ellenborough street,kalinda park,burwood east,3180,qld,19280512,9150558 +rec-4470-org,tori,reid,244,sellwood street,warwarick,parkinson,6169,vic,19280331,2530021 +rec-1521-org,jack,rulfs,10,suttor street,huongold,mossman,3889,qld,19260612,6246735 +rec-4719-org,kirrah,southwood,137,sugarloaf circuit,coolibah,smithfield,4715,wa,19980504,4827713 +rec-1450-org,polly,perin,4,fellows street,northwood park,belmont,6056,vic,19480215,2564677 +rec-344-org,mitchell,les,8,dexter street,blythelands,upper coomera,2011,nsw,19430227,9870170 +rec-2682-org,taylor,bevis,20,spofforth street,,burwood,3175,nsw,19270430,6848520 +rec-1426-org,lucas,thorpe,25,port jackson circuit,,eimeo,6255,sa,19320715,2374689 +rec-168-org,kaitlin,,4,hawkins close,tullatrundle,eaglehawk,4280,nsw,19671026,9904441 +rec-817-org,isabella,coleman,160,schoales place,court units,berwick,5159,nsw,19930621,7188217 +rec-1512-org,braiden,chandler,34,outtrim avenue,rosetta village,point cook,6056,nsw,19580129,9508953 +rec-3110-org,michael,morden,67,,marjories corner,frankston,4123,qld,19091122,2399236 +rec-2612-org,joshua,white,11,finlayson place,hayfield vlge,the entrance,4178,nsw,19560417,3821555 +rec-1490-org,matthew,apted,18,atherton street,currumbin hill,port macquarie,3183,vic,19590825,9425976 +rec-4089-org,jasmine,blake,7,mugga way,mannibadar,east fremantle,5008,vic,19531120,3831376 +rec-3221-org,naomi,ryan,14,decker place,grandview,paringa,2148,nsw,19720205,2526000 +rec-2336-org,konstantinos,morrison,297,euree street,berkeley vlge,farleigh,2099,nsw,19690128,1191867 +rec-4615-org,kalli,froscio,23,fergusson crescent,wirruna,manyana,6530,wa,19680403,3617186 +rec-810-org,,clarke,6,barangaroo street,apt 8g,blacktown,2615,nsw,19240224,6718271 +rec-2812-org,adam,gilbertson,2,albermarle place,the willows,yarra junction,5252,qld,19570515,8465469 +rec-345-org,emiily,rankine,32,blackham street,sapri,campbelltown,5068,vic,19060404,3688640 +rec-3886-org,joshua,mason,47,crisp circuit,deergarden caravn park,chinchilla,3799,vic,19390402,8753102 +rec-377-org,joselyn,moody,92,bromell circuit,cloverdene,ashfield,2285,sa,19380115,4236077 +rec-2855-org,dominic,papageorgiou,1544,la perouse street,the lakes retirement village,bacchus marsh,3995,nsw,19140218,4660218 +rec-1559-org,jemima,belperio,12,strehlow place,rainbow ridge,margaret river,4012,nsw,19281001,3997984 +rec-3935-org,gianni,white,34,max henry crescent,maf-ue arabians,ballarat,2680,nsw,19501101,4846207 +rec-1243-org,april,snell,87,keartland street,public building,kalamunda,3934,wa,19000422,4988954 +rec-4815-org,connor,kibby,23,antill street,dunmunkle lodge,alice springs,6155,nsw,19740907,3575462 +rec-3713-org,chelsea,clarke,34,marrawah street,koonawarra merino stud,springwood,3912,vic,19560528,1305791 +rec-1388-org,natassia,horsley,12,tanumbirini street,alabama,numeralla,4573,vic,19721029,9492508 +rec-1480-org,owen,green,5,dryandra street,bythorne,campbelltown,3175,vic,19160427,4013988 +rec-1168-org,isabella,jessup,61,downes place,spring ridge,ardeer,3058,nsw,19331204,4702512 +rec-4322-org,sean,hewson,17,christmas street,champsaur,wantirna,2230,nsw,19180917,5004753 +rec-4404-org,nicholas,commons,50,couchman crescent,lochlee,parkdale,5169,sa,19980815,9438920 +rec-2774-org,dylan,herbert,150,andrews street,brentwood vlge,sheidow park,5067,vic,19430105,4521571 +rec-4750-org,aliza,white,356,petterd street,wemyss,mosman,3183,vic,19660226,7732220 +rec-2966-org,heath,tao,1,holden crescent,the willows,merrimac,2594,nsw,19420605,9669484 +rec-3955-org,joshua,wardle,13,pennefather street,greenlake,joondanna,2605,act,19450501,4072887 +rec-2634-org,cambell,croker,4,baldwin drive,wemyss,moodiarrup,0836,act,19741117,1734947 +rec-2826-org,kai,hobson,1985,battersby circuit,,dulwich hill,5573,nsw,19280304,9227124 +rec-1327-org,emma,copperstone,5,decima circuit,crower,avoca north,2166,nsw,19451208,1538637 +rec-3862-org,kiera,lowe,208,acraman place,farm shed,thornbury,2470,qld,19830616,8834013 +rec-2604-org,christopher,frew,10,ringrose crescent,locn 1996,lilydale,4069,tas,19321022,6674665 +rec-3808-org,mitchell,dunnicliff,20,illingworth street,brbe is retmt vlg,penrith,3162,nsw,19350411,5567119 +rec-1832-org,timothy,kinter,29,hawker street,argyle village,quilpie,2594,vic,19190926,7137052 +rec-4869-org,taylah,reid,25,albermarle place,cypress garden,revesby,2210,nsw,19571029,7276846 +rec-564-org,kane,reid,12,arnold place,lakefront retrmnt vlge,seventeen mile rocks,6285,qld,19181209,4118529 +rec-3769-org,jasper,herbert,8,werriwa crescent,lyndilan,mill park,6163,sa,19640905,3048660 +rec-1536-org,dale,sherriff,16,oxley street,brentwood vlge,whitton,2024,vic,19850402,4498530 +rec-3265-org,aaron,baohm,,,locn 316,upper coomera,6016,qld,,7238727 +rec-696-org,james,de chellis,47,kitchener street,rowethorpe,rowan,2833,nsw,19330807,7941748 +rec-2987-org,tiahnee,moody,40,miethke place,winterwood,north ward,3806,nsw,19130426,4744397 +rec-3959-org,james,ryan,14,levien street,cara hill,caulfield,2104,nsw,,5857843 +rec-4346-org,brodee,millar,28,looranah street,glenbrae,tarragindi,3043,qld,19980215,8444455 +rec-138-org,reuben,sette,6,griffiths street,the sandys,valley view,3159,nsw,19880626,4637182 +rec-2335-org,lily,webb,274,conlon crescent,strathalan community,oakleigh,2151,vic,19920411,8994352 +rec-2844-org,lachlan,lanyon,131,,evergreen,malvern east,4715,act,,5173073 +rec-181-org,portia,coumans,14,wakool circuit,silverweir,geurie,3875,qld,19060626,6637994 +rec-1274-org,,mason,19,sheaffe street,,burwood,2570,nsw,19461025,4113226 +rec-3689-org,shantal,hewson,28,jardine street,,salter point,2750,qld,19140410,4042276 +rec-2400-org,mia,ryan,183,waterman place,horse park,cronulla,3976,nsw,19620814,8743474 +rec-3395-org,connor,carbone,,willyama place,kalooca,buddina,2700,nsw,19090228,1119288 +rec-3708-org,reeve,michelmore,17,wambaya crescent,war veterans hme,cooloongup,6112,wa,19940723,8143187 +rec-1381-org,samuel,bullock,6,fuhrman street,avonlea park rmb 4045,casino,4165,nsw,19760505,1377013 +rec-3790-org,melinda,tuckwell,8,stradbroke street,cherry tree,rushworth,2219,qld,19961127,5540986 +rec-1418-org,beau,dallas,19,lange place,,blakeview,0872,vic,19581021,2569822 +rec-2301-org,damien,finlay,150,pethebridge street,rosetta village,samford valley,2119,vic,19020614,3997416 +rec-2024-org,tara,riding,11,allchin circuit,palm lake resort,wanniassa,2262,nsw,19761123,9131364 +rec-797-org,shantal,novak,9,hall street,freonbrae,cleveland,6110,vic,19000303,3342200 +rec-2035-org,mitchell,campbell,28,pokana circuit,,dickson,5097,qld,19950311,7753298 +rec-1863-org,chloe,lamacka,24,harriot road,,beulah park,7310,nsw,19350813,7704327 +rec-1130-org,madeline,spicer,6,meyrick place,the mews royal hotel bldg,marks point,3196,nsw,19430521,1722390 +rec-1825-org,darcy,paterson,290,brand street,the tops,belmont north,2106,act,19050520,5963506 +rec-2887-org,brody,stearnes,7,fincham crescent,binnalong,thornbury,3639,vic,19440417,8363677 +rec-3537-org,joshua,leaver,30,nardoo crescent,diment towers,st lucia,2167,qld,19650306,7912588 +rec-3247-org,jordan,lahz,53,scantlebury crescent,argyl square,hamilton,2153,wa,19760111,1854713 +rec-1183-org,matthew,green,5,tanner place,beltrasna angus stud,oakleigh east,5607,nsw,19650218,1267406 +rec-4916-org,india,nicoll,432,buckmaster crescent,kurrajong,moree,4812,qld,19111101,5165691 +rec-1694-org,mhary,siemon,13,latchford street,mountview,broadmeadows,6170,vic,19020804,9452510 +rec-911-org,jack,lowe,12,lambert street,belongame,lavington,6415,vic,19091212,6247312 +rec-2552-org,hayden,tabrett,31,molesworth street,horse-shoe bend,boulder,6000,tas,19770116,5103849 +rec-632-org,,colquhoun,11,strong place,ocean star villas,modbury,2213,qld,19621022,3058669 +rec-4773-org,cain,berry,50,perry drive,,mont albert,4352,vic,19990822,4009274 +rec-3200-org,jenna,ryan,79,kelleway avenue,arulbin,lutwyche,3182,vic,19330417,9427822 +rec-4330-org,jye,marlow,2,meeson street,barakee,blackall,5223,nsw,19110728,8601970 +rec-1333-org,paris,coulson,82,clianthus street,brentwood village,malabar,2031,wa,19490522,3135420 +rec-1309-org,zoe,szepessy,,creswell street,laguna estate,narooma,2430,nsw,19330122,9920487 +rec-2653-org,lochlan,pendergrast,3,hood place,kenara,loftus,6163,wa,19790831,3095270 +rec-3595-org,tiarna,chestnut,7,lee-steere crescent,river mews,burpengary,3461,nsw,19850302,6789617 +rec-942-org,ashleigh,matthews,40,chippindall circuit,sylvan park,swan view,3072,vic,19110113,2292149 +rec-3846-org,kirra,watkin,29,geelong street,krismark,nicholls,2088,nsw,19700924,1203301 +rec-2671-org,beth,webb,10,doutney place,parkridge villa,leichhardt,2880,vic,19761122,2024248 +rec-2548-org,portia,lette,27,namatjira drive,willyaroo street,rostrevor,3084,wa,19800709,3676482 +rec-3026-org,georgia,goode,27,,,paddington,3141,vic,19621216,7982044 +rec-3114-org,cassidy,morrison,13,a'beckett street,argyle,ardeer,2518,nsw,19160403,6156712 +rec-4270-org,bethany,finlay,353,capella crescent,haigh park,broken hill,2111,vic,19660601,3594609 +rec-59-org,harley,paepke,24,callaghan street,hd allenby,jindalee,7250,nsw,19120621,6421301 +rec-1166-org,jacinta,lomman,30,collings street,the hammond village,ingleside,3162,qld,19061009,6853014 +rec-4037-org,jack,michalatos,26,springvale drive,ratho road,modbury,3250,vic,19921024,4661674 +rec-3377-org,tabitha,weetra,115,marika street,langley flats,woollahra,2483,nsw,19591205,9251852 +rec-55-org,harrison,herbert,9,davidson street,allamby biala street,mulgrave east,4871,nsw,19420918,4129781 +rec-1485-org,joshua,lock,3,,station road,logan reserve,6163,vic,19490619,3058210 +rec-908-org,lucy,rees,14,haddon street,cremona stud,tiddy widdy beach,2469,nsw,19250702,3258771 +rec-1638-org,garth,echevarria,179,solomon crescent,ondyong point,port broughton,2770,vic,19970118,4201581 +rec-1767-org,keaton,webb,2,mckinley circuit,solitaire,lemon tree passage,3943,nsw,19940724,6702216 +rec-2176-org,kaleb,george,35,troughton street,inglewood,aldgate,5159,vic,19980115,1830121 +rec-1037-org,luke,mahony,58,scaddan place,elston,beenleigh,2830,qld,19550621,6013061 +rec-850-org,sean,siviour,44,clavert place,brentwood vlge,williamstown,3909,sa,19990601,2158120 +rec-4013-org,jacob,haren,14,finlayson place,colloca vale,mooroolbark,7000,vic,19180426,5885583 +rec-4002-org,zara,mason,27,o'connor circuit,fm 226,horsley,2256,nsw,19730628,8233098 +rec-3367-org,tara,cother,13,louis loder street,apt 16 the village,rowville,4350,vic,19740806,8528296 +rec-19-org,chloe,radinger,5,chandler street,namarva station,hawthorn,2614,vic,19120808,8644024 +rec-2282-org,erin,delacy,16,cooinda court,rowethorpe,swan hill,2480,vic,19120628,3648623 +rec-841-org,jake,nelsen,10,rosson place,elmwood,,4815,nsw,19300403,7364984 +rec-3081-org,amy,noble,2335,marcus clarke street,oakdale,punchbowl,4695,vic,19470518,8727631 +rec-2621-org,casey,hearn,10,ferrett circuit,watarmark,rowville,6153,sa,19390522,8255871 +rec-3425-org,ashleigh,matthews,2,green street,boxwood hill,winston hills,4885,vic,19140406,3711823 +rec-4755-org,jake,mcneill,33,crozier circuit,legacy units,maroota,6166,nsw,19490119,7072281 +rec-1451-org,jade,stanley,4,baracchi crescent,mlc centre,cranbourne,6111,nsw,19480216,3818853 +rec-1199-org,lucas,tiller,106,stuart street,yarrandale moonee,douglas park,4573,wa,19300831,2715828 +rec-4782-org,charles,sarny,34,esperance street,brentwood vlge,thornbury,3212,qld,19971014,3125264 +rec-1687-org,jaiden,ferris,2,pandanus street,merri banks,coffs harbour,4067,vic,19571024,1900307 +rec-2709-org,montana,blake,24,harcourt street,spring banks,college park,2620,vic,19400808,9535357 +rec-3497-org,thomas,manson,22,birbai place,karsul,frankston,6532,nsw,19160504,3670653 +rec-3567-org,ryan,campbell,45,grimmett close,emerald garden,clayton,2020,sa,19770227,9732798 +rec-356-org,zack,brock,87,top nass,,hyde park,4740,nsw,19130124,8703977 +rec-2702-org,dylan,beal,82,sargood street,st john of god hospital,kingston,2088,qld,19620914,4831404 +rec-211-org,madeline,jolly,6,,crown allot,lilli pilli,2546,nsw,19280509,9133348 +rec-2475-org,karla,wilkins,66,clifford crescent,talgarth,oatlands,2323,nt,19590520,3511629 +rec-4234-org,,lock,9,tauss place,argyle,woodcroft,2028,sa,19130105,6312603 +rec-1416-org,isabella,coffey,21,norfolk street,parraweena,paddington,7330,nsw,19860819,4139219 +rec-1606-org,talan,dietrich,35,hacking crescent,tall pines,mosman,2903,vic,19490712,9469771 +rec-2411-org,james,kullmann,79,deloraine street,strauss,park holme,5009,vic,19120424,9266755 +rec-511-org,olivia,grubb,25,boolee street,berkeley vlge,catalina,2283,nsw,19050616,8765826 +rec-3346-org,byron,white,4,tyson street,rocklea,eaglehawk,3188,sa,19580101,7284710 +rec-341-org,lushia,reid,6,dunn place,hd allenby,karanja,4207,nsw,19111022,1691582 +rec-693-org,rachel,donaldson,9,lee-steere crescent,lake kennedy street,sunshine,3170,nsw,19581218,2248813 +rec-3231-org,hayley,covino,33,von guerard crescent,karingah,oatlands,2380,nsw,19151011,1653948 +rec-1879-org,jacob,kapeller,5,mount vernon drive,crosslands,toowoomba,2216,vic,19361129,5761018 +rec-4976-org,teaha,kyriacou,17,iron place,,tambo upper,2783,nsw,19720829,6810695 +rec-4972-org,zoe,paterson,8,chauncy crescent,heritage est,blayney,6620,qld,19930912,2580670 +rec-772-org,amber,trenchuk,38,sambell place,brentwood vlge,carlingford,4670,qld,19850711,9303779 +rec-2578-org,joshua,chandler,113,companion crescent,parkdale lodge,cleveland,3556,vic,19030124,5666451 +rec-1343-org,jazz,campbell,9,newbery crescent,cullinga park,fairlight,3850,qld,19391218,3106041 +rec-725-org,,,1,william street,woodsong,nickol,6149,qld,19000430,6432290 +rec-3269-org,lucy,lavokovic,8,hobart place,public school reserve,vermont south,2761,sa,19900925,4722145 +rec-2627-org,seth,sherriff,1329,bean crescent,braeburn,the entrance,2153,vic,19320310,1727482 +rec-4816-org,william,tangallpalla,166,lachlan street,minnawarra farm,stanhope gardens,7008,nsw,19320616,9859566 +rec-2454-org,portia,george,9,taronga place,,rosebud,2620,wa,19670721,1688777 +rec-3212-org,kiara,campbell,13,towns crescent,korrelocking,rowville,3188,wa,19630411,9105948 +rec-864-org,shannon,grosskopf,71,noarlunga crescent,bunderry,tweed heads south,3690,vic,19530813,9233063 +rec-1962-org,sophie,mason,101,lendon place,mt pleasant,ashgrove,4005,wa,19411215,9349267 +rec-4988-org,seth,tauj,17,herschell circuit,belvedere,st kilda,5201,qld,19490904,5547361 +rec-4264-org,zac,dixon,101,dodwell street,unt 3,macgregor,4627,wa,19960221,8228346 +rec-661-org,caitlin,portlock,19,tompson street,cherrydell,rochester,4503,act,19110812,1549588 +rec-2707-org,michael,berry,12,canberra avenue,telemon,east melbourne,2259,qld,19110224,5076815 +rec-4920-org,roisin,millar,,robertson street,st francis vlge,helensburgh,3770,sa,19490912,9953494 +rec-493-org,katelyn,blackwell,127,ferrier place,northwood park,chelsea heights,4211,qld,19570409,8541055 +rec-950-org,jackson,alderman,84,maccallum circuit,,penshurst,3192,vic,19870424,5612815 +rec-2697-org,joshua,lowe,15,patton place,redlands,tarcutta,4705,sa,,7132911 +rec-3980-org,nellie,clarke,147,booroomba road,weeroona,christies beach,5345,sa,,3099429 +rec-3706-org,brodie,alves,3,lort place,jillamtong,albury,2773,nsw,19591217,3058450 +rec-1776-org,corey,green,8,blamey crescent,briony downs,cardiff,3121,qld,19961225,6076482 +rec-3594-org,abbey,gonsalex,19,fairweather circuit,meebery,kellyville,3285,vic,19450224,5540735 +rec-1788-org,jacob,durbridge,153,macarthur avenue,little paddocks,albury,4680,nsw,19820308,4922810 +rec-4424-org,jack,bartel,103,bailey place,killarney,christie downs,2228,nsw,19060129,7898705 +rec-1024-org,charlotte,bishop,24,bourne street,dp 808602,port macquarie,3844,sa,19420131,5896457 +rec-4881-org,alexandra,nguyen,44,colebatch place,langley flats,freshwater,3242,nsw,19511004,6416159 +rec-892-org,jack,wieloch,29,mackennal street,,hawkesdale,2261,nsw,19500927,2954380 +rec-4804-org,alessandra,eyles,10,loureiro street,rowethorpe,illabo,2014,nsw,19210630,7014716 +rec-946-org,bianca,liebenberg,82,fishburn street,wombat hill,minto,2086,qld,19880322,9794218 +rec-1943-org,imogen,coffey,,mclaren crescent,kooyong,ormeau,2782,nsw,19250214,4962430 +rec-1464-org,chloe,tennent,12,carstensz street,john curtin hostel,ringwood,2295,vic,19980713,9606434 +rec-1107-org,sybella,shepherd,34,mainwaring rich circuit,retirement village,werrington,2118,tas,19460321,7440143 +rec-1923-org,kalli,rocca,12,mckivat close,leebold hill farm,clayfield,5022,qld,19990423,3214869 +rec-10-org,lachlan,reid,5,carrington road,legacy vlge,yagoona,2464,nsw,19500531,3232033 +rec-323-org,peta,tarsissi,,rivett street,glen alvie rsd,kendall,3128,nsw,19641102,1498722 +rec-3238-org,jamie,snell,36,acraman place,st georges park,deakin,7307,vic,19850205,9378445 +rec-962-org,millane,reinmuth,1,galloway street,agarabi,,4157,nsw,19940519,7590245 +rec-3751-org,annalise,vorrasi,94,millen street,blacksdane private sanctuary,milawa,3106,qld,19700321,8035200 +rec-3046-org,aleesha,hingston,41,epenarra close,compton downs hostel,mentone,4215,nsw,19240921,8948668 +rec-2469-org,riley,nguyen,76,florence taylor street,wacharoo,mill park,3181,nsw,19951106,4237972 +rec-1100-org,bailey,garcia,2,archibald street,kimberley,banyo,3071,act,19351102,2638117 +rec-4447-org,imogen,hope,5,dumaresq street,delmar,beecroft,7307,wa,19770614,8438312 +rec-365-org,ned,kalka,3,tinderry circuit,silverweir,hazelwood north,2040,vic,19820419,7612543 +rec-1956-org,nathan,petersen,4,grant crescent,kenbar,kellyville,5067,nsw,19051226,8942423 +rec-4547-org,benjamin,hyland,14,coxen street,rowethorpe,yaroomba,5046,vic,19921225,8509780 +rec-2832-org,mitchell,cute,161,buntine crescent,murray river queen,lake munmorah,2518,vic,19470802,9610204 +rec-4798-org,bethany,crook,,rumker place,villa 115,thornbury,4380,wa,19701023,3361106 +rec-1530-org,jordan,reimer,12,,brentwood vlge,avondale heights,2261,nsw,19010306,3313488 +rec-3677-org,madison,marous,21,crouch place,heights estate,junee,2444,nsw,19030404,7501014 +rec-2630-org,nicholas,mamarika,15,allambee street,koonawarra merino stud,wantirna,2533,vic,19840311,4175032 +rec-4472-org,william,piazza,219,monfries place,weemilah,pymble,5605,nsw,19150522,8044732 +rec-1387-org,mitchell,berry,2,roope close,larook,torquay,2199,nsw,19190710,1968724 +rec-251-org,benedict,everett,2,bettington circuit,bay city plaza,valla,3802,nsw,19870303,4768278 +rec-126-org,nikki,jaric,13,renmark street,parish lorne,chester hill,2106,nsw,19520401,9272010 +rec-2367-org,,clarke,15,biddell place,laurieton hvn ret,collie,4120,vic,19430622,7449892 +rec-1595-org,gus,white,109,bundey street,ingevale,clayton,6155,vic,19830819,8009311 +rec-2806-org,nicola,grubb,5,derrington crescent,gwandalan,south melbourne,2777,nsw,19520719,8082214 +rec-2859-org,simon,whiteley,52,hardwick crescent,centrefair plaza,kardinya,4017,vic,19010920,7819784 +rec-2673-org,olivia,thorpe,35,lewin street,parry house,mount evelyn,2619,vic,19430807,3939861 +rec-3270-org,blade,mccarthy,313,biggs place,john flynn medical centre,highett,5086,nsw,19431221,1133389 +rec-4067-org,talia,white,,fergusson crescent,budd ridge,brucknell,3810,nt,19980331,4476072 +rec-4999-org,victoria,fitzpatrick,19,clermont street,ambervale,lake tyers,4570,nsw,19810411,2176335 +rec-4290-org,alec,mckerlie,20,short place,macarthur place,sefton,4370,vic,19890714,3276175 +rec-4875-org,annabelle,ebert,20,douglas place,glenhurst,brooklyn,2307,wa,19440813,6811641 +rec-466-org,rhys,stubbs,155,cockle street,teralba caravn park,marsden,3148,qld,19931202,8594688 +rec-2484-org,james,wyllie,7,university of canberra,westfalls,sippy downs,3201,wa,19811112,6047605 +rec-4328-org,rachel,meeking,21,wisdom street,lewin lodge,fisher,3150,qld,19181114,5395262 +rec-3400-org,maddison,newport,139,bingle street,burrendong est,bowen hills,4818,nsw,19590707,5640367 +rec-1186-org,harrison,du,22,cooks street,greenbank,adelong,5244,wa,19320522,6653003 +rec-3999-org,sarah,roller,,wrixon street,weddinview,kedron,4306,qld,19190420,4429848 +rec-3583-org,isabella,buchhorn,28,officer crescent,,oaklands park,5043,vic,19930522,7645759 +rec-2723-org,bertie,white,22,walga place,mt annan,petrie terrace,3012,nsw,19611008,4599672 +rec-2978-org,natalia,bajic,19,delegate street,corcoran,jesmond,3977,wa,19130312,8300817 +rec-3166-org,brianna,ferris,38,couvreur street,fleetwood,keysborough,2026,nsw,19110704,4044151 +rec-1236-org,charles,hassall,1,lansell circuit,marylands,riverwood,3630,nsw,19650120,1934914 +rec-737-org,hannah,liaudinskas,15,hopman place,mt pleasant,orange,2829,sa,19130526,5819558 +rec-3791-org,jacob,callahan,107,lyrebird place,,burwood,6152,wa,19220110,4360694 +rec-2020-org,alissa,ryan,20,,rosehill,malvern,2880,tas,19420405,4676455 +rec-2554-org,madison,shepherd,18,ballumbir street,blue hills,corrimal,3168,wa,19170819,8120482 +rec-3342-org,john,cosenza,54,wentworth avenue,stoney creek,st kilda,4305,nsw,19800116,5521510 +rec-3410-org,nicholas,champion de crespign,8,deuchar close,lanena lodge,ryde,3181,qld,19230403,3235310 +rec-591-org,sarah,brgles,23,torrens street,trewalla,tarragindi,2747,vic,19521019,8447931 +rec-412-org,kyle,pascoe,14,cygnet crescent,shadell,abbotsford,4069,wa,19901202,5389384 +rec-1567-org,campbell,webb,63,wade street,ra 939,mount crosby,3152,nsw,19981022,3000281 +rec-876-org,benjamin,sokic,21,must circuit,,sunshine,2153,vic,19001207,2513200 +rec-2417-org,rourke,roets,14,gruner street,cleveland,kaleen,3227,,19690509,1455274 +rec-4134-org,alexandra,giordano,32,crozier circuit,marsden forest,blacktown,4680,vic,19341104,5423203 +rec-2896-org,blake,de courcey,26,ellerston avenue,rosehill,bowral,3090,qld,19890504,1219082 +rec-3728-org,laura,colthorpe,34,masters place,caravn park,campsie,2325,vic,19490729,7434022 +rec-3824-org,kayla,stanley,378,namatjira drive,campaspe,pullenvale,5007,tas,19480518,4545738 +rec-300-org,matilda,clarke,113,gritten street,gloccamorra,fletcher,3051,vic,19721108,8416016 +rec-1569-org,emiily,matthews,70,jacka crescent,,murgon,3012,nsw,19230603,2611585 +rec-492-org,carly,matthews,14,mcnamara street,henry kendall hostel,aroona,2257,nsw,19460115,6001116 +rec-2055-org,tai,garven,21,finniss crescent,donette downs,pymble,2035,nsw,19930723,6253715 +rec-470-org,harry,bishop,5,darwinia terrace,craigston l1bg,glenmore park,4380,wa,19781114,7781607 +rec-628-org,amaya,skirca,3,heagney crescent,willow lodge,ross,3980,wa,19980122,3780122 +rec-513-org,tara,huddy,14,diggles street,st francis village,park holme,2603,vic,19160630,3611615 +rec-3006-org,benjamin,matthews,5,namatjira drive,buena vista,preston,5290,vic,19531201,3174751 +rec-2765-org,ashlie,cannell,23,lenehan street,blue crane farm,nome,3152,nsw,19210211,2766975 +rec-3411-org,serena,dorrell,22,ayers street,rosehill,normanhurst,5290,vic,19970507,8746575 +rec-2459-org,ned,donaldson,12,anzac park,linton,port lincoln,3221,vic,19170225,3467265 +rec-936-org,eboni,brakel,42,investigator street,emmaus vlge,orange,2061,vic,19180211,3115830 +rec-545-org,tara,plovanic,25,hobler place,port hills,kalamunda,2747,vic,19600401,4207452 +rec-3856-org,claudia,damianos,19,noarlunga crescent,woodcrest,wellard,2230,nsw,19780811,1802317 +rec-906-org,anthea,,1,priestley place,old farm,ingleburn,3220,qld,19611202,5884746 +rec-2086-org,chelsea,sitarenos,2,chevalley loop,argyle,leichhardt,2611,qld,19470522,3656932 +rec-4930-org,nicholas,jolly,181,tullaroop street,federation cove,old toongabbie,2606,wa,19660414,3580537 +rec-2616-org,hari,webb,1,slessor crescent,malmani,springfield,5108,sa,19270216,3864525 +rec-3313-org,thomas,ryan,24,weavell place,coolalie,emerald,4280,vic,19970129,8879018 +rec-3772-org,isabella,lail,20,glover street,sawtell vet hosptl & clnc,nicholls,2251,qld,19770924,8701819 +rec-1406-org,brett,beauman,5,stockdale street,promenade arcade,bonnells bay,2358,vic,19170420,4623290 +rec-1913-org,liam,george,5,lindrum crescent,retirement village,hoppers crossing,3030,vic,19060325,3435395 +rec-4831-org,caleb,thorpe,4,river street,,granville,2641,nsw,19590118,7916934 +rec-934-org,george,lavender,851,earle place,kilmore,elizabeth park,4068,wa,19011207,3461164 +rec-1189-org,nicholas,okely,,hannan crescent,baroona,taree,5244,qld,19350522,2534430 +rec-4671-org,andrew,large,29,swainsona street,buena vista,bicton,6022,qld,19800804,9892920 +rec-4556-org,simon,,151,waddell place,northwest medical centre,palmerston,2913,nsw,19590525,5350801 +rec-1028-org,michael,clarke,37,mcintyre street,sherwood,maryborough,3113,wa,19240223,1886418 +rec-4633-org,cassandra,eng,117,city walk,moondani,sefton,3207,vic,19570716,1718688 +rec-1410-org,kyle,colantuono,8,moynihan street,cosy corner,lennox head,6081,vic,19960130,1684057 +rec-88-org,sebastian,ryan,465,mathews place,don ray,chester hill,4210,nsw,19080114,8520668 +rec-3695-org,emiily,crossman,16,,tulloch,colac,4305,nsw,19641029,4013967 +rec-4083-org,isabelle,coady,32,cooloola street,valencia park,samford,4012,nsw,19250322,2977259 +rec-3956-org,teneille,matthews,13,bugden avenue,civic centre,jesmond,6026,qld,19061230,7584568 +rec-343-org,steven,green,9,duigan place,dunbar heights,pennant hills,7010,qld,19760329,8403741 +rec-625-org,jakob,pagoda,43,garling street,clear creek,bundaberg,4300,nsw,19371008,1115720 +rec-4191-org,liam,ryan,82,freeling crescent,ryhd-talog,murarrie,2650,nsw,19601106,2586667 +rec-3619-org,brooke,ryan,93,brawn place,moorilla,greenacre,3040,nsw,19100427,7392488 +rec-1076-org,lia,voulgaridis,19,kingsford smith drive,glenavon,mosman,6158,nsw,19960531,3691075 +rec-3117-org,georgia,tunstall,30,beadle place,holmleigh,caulfield north,3046,sa,19330720,4656516 +rec-87-org,shandril,flockhart,6,maclean street,seaford,ganmain,7006,vic,19410912,2925713 +rec-2742-org,jaiden,o'flynn,9,eve place,pioneer lodge,goovigen,6163,nsw,19330911,4353748 +rec-218-org,jade,browne,407,sabine close,brentwood vlge,leichhardt,4700,vic,19810923,8107465 +rec-3496-org,elijah,green,76,lane-poole place,rosetta village,malvern,3337,vic,19910131,7588197 +rec-2577-org,noah,reetz,9,ellenborough street,lakes retirement estate,bayswater north,3126,vic,,2350308 +rec-2295-org,luke,tebbutt,5,decker place,section,tweed heads south,4811,wa,19851223,9714537 +rec-1421-org,gillian,kaddatz,27,ivo whitton circuit,woodport hostel,murdoch,2026,qld,19650426,3271990 +rec-2681-org,lucy,van de maele,50,rutledge place,mater professional centre,port lincoln,2304,vic,19770324,4274192 +rec-3251-org,lachlan,de angelis,85,goldfinch circuit,glenarthur,gulnare,2074,vic,19881114,8569316 +rec-604-org,naomi,heron,11,damala street,victoria square,westmeadows,5159,vic,19660531,1400642 +rec-439-org,mia,kamp,55,jardine street,gonzaga,pooraka,2161,sa,19400617,1084495 +rec-4969-org,victoria,zimmermann,37,o'sullivan street,kelgoola,nyah,2842,qld,19240517,7803602 +rec-3301-org,vanessa,bishop,5,pethebridge street,willaroo,burnett heads,6167,qld,19780125,9592570 +rec-3989-org,kobe,brock,4,folingsby street,,coonamble,4575,qld,19941016,6183698 +rec-2603-org,nikita,leditschke,86,sidaway street,parkdale lodge,mirrabooka,2031,vic,19510630,1387001 +rec-2912-org,blakeston,curihual,35,wheadon street,kyree,broadmeadows,3138,vic,19820725,9241622 +rec-3016-org,ellen,armanious,4,summerville crescent,cabrini medical centre,corio,3130,nt,19670816,3732493 +rec-1398-org,kristo,white,,mchale place,evergreen,devonport,2050,qld,19790907,4175137 +rec-2006-org,hunter,wesley-smith,67,antis street,wandella park snowy,chinchilla,6155,vic,19680320,8096012 +rec-107-org,samuel,george,30,dobinson place,grand view,yarrawonga,4170,vic,19070403,8880903 +rec-4956-org,kyle,grbovac,51,alexander mackie circuit,sutton cottage,frankston,3094,vic,19821227,7927536 +rec-3384-org,george,sherriff,25,hemmings crescent,melody cottage,geraldton,3019,qld,19650627,2285850 +rec-602-org,benjamin,green,78,jennings street,botin,terranora,6009,vic,19681029,4718046 +rec-3493-org,india,meddings-blaskett,166,james smith circuit,glenview,hughes,2540,nsw,19730602,7857279 +rec-1946-org,michael,rawlings,1554,millen street,the homestead,coolbellup,2750,sa,19170417,6689349 +rec-446-org,callum,everett,13,grayson street,logan central plaza,willetton,2621,sa,19840331,2551623 +rec-2446-org,brooke,homles,,yiman street,high valley,camira,5043,nsw,19360812,5450160 +rec-378-org,william,margush,14,bindaga street,unt 2,yackandandah,3150,nsw,19780603,3588509 +rec-1870-org,holly,feast,21,dorrit black crescent,the stockyards,burnie,6063,vic,,8284375 +rec-4218-org,melissa,monola,71,giles street,north nowra shopping centre,greenwood,0810,nsw,19730130,3690365 +rec-3784-org,connor,hammill,99,goyder street,burnside,angaston,2304,nsw,19700803,7089797 +rec-686-org,zarlia,hage,69,catchpole street,tryphinia view,casino,3180,vic,19130311,5080759 +rec-1548-org,william,cheers,18,kirwan circuit,ollera,kinross,6026,nsw,19550419,5986242 +rec-571-org,kade,white,14,morduant place,collaroy,ringwood,3356,vic,,5013199 +rec-4101-org,daniel,ballantyne,137,howitt street,timberscombe,noble park,4014,qld,19601102,3529680 +rec-1142-org,joshua,campbell,1,jonsson court,,bayswater,6353,nsw,19261206,6149683 +rec-399-org,teagan,white,54,knoll place,wangaya,padstow,6107,nsw,19210314,9334133 +rec-240-org,seth,jolly,16,reddall close,arrowgrove,colac,4370,qld,19460808,7445552 +rec-3258-org,shana,ryan,30,monaro crescent,ingledell,duncraig,3220,nsw,19000819,4773341 +rec-4186-org,georgia,willing,12,,sunnybank garden,rochedale south,2113,vic,19701121,4356806 +rec-1120-org,angelica,green,5,nash place,palm grove,vaucluse,5242,nsw,19051230,7491589 +rec-552-org,cameron,wilkins,528,bruxner close,iventure,albury,4670,sa,19580516,1334190 +rec-4482-org,ewan,mildren,60,loftus street,,bellevue hill,2010,wa,19941205,6218110 +rec-566-org,kyle,chappel,41,scantlebury crescent,kiaora,belmont,3550,qld,19130405,6485946 +rec-1836-org,flynn,white,26,buntine crescent,berkeley vlge,karara,3550,nsw,19980415,8345957 +rec-115-org,michael,micke,77,rich street,boonoo boonoo,rokeby,5271,sa,19561107,9010254 +rec-766-org,oscar,meadows,5,moore street,eden park,karalee,2155,nsw,19900805,7725660 +rec-1153-org,sam,reid,243,roope close,brentwood vlge,blacktown,6015,nsw,19050930,8900010 +rec-1511-org,jack,bridgland,170,thermeda place,mirreanda,berkeley vale,2286,nsw,19980721,2930436 +rec-2328-org,tara,negrin,493,,unmera,leppington,5251,vic,19381130,4747156 +rec-3233-org,jessica,donaldson,2,mainwaring rich circuit,cliffney park,hamilton,2147,nsw,19361211,5900031 +rec-988-org,jack,andrae,7,cleland street,mundine 30 km,cherrybrook,6025,vic,19260626,3267222 +rec-2629-org,abby,stanley,2,batman street,mannafields farm,mount isa,6021,nsw,19780508,7062701 +rec-3404-org,jessica,hanna,7,jerrabomberra avenue,yaraan,smithfield,2821,nsw,19380407,9277788 +rec-2453-org,samantha,mccracken,162,shackleton circuit,old purrawunda,westbrook,6020,nsw,19730929,3197473 +rec-486-org,emiily,lipscombe,29,fernyhough crescent,carinya vlge,seaton,4503,vic,19031116,2893427 +rec-170-org,isabella,stephenson,38,majura avenue,mafeking,emerald,2212,qld,19840307,6292167 +rec-1877-org,ka,reid,,lipscomb place,karingal hm,kingston,4702,qld,19160621,4440797 +rec-3815-org,sarah,beattie,9,burkitt street,kay's place,ashfield,2047,vic,19500712,9435148 +rec-4133-org,,ryan,480,britten-jones drive,yulgilbah,roxburgh park,7054,nsw,19610512,6344786 +rec-361-org,garth,clarke,11,yampi place,thistledoo,noble park,5608,vic,19760322,9574946 +rec-722-org,lachlan,goldsworthy,5,wanganeen avenue,howie circuit,sheidow park,2031,sa,19380108,4133306 +rec-1208-org,,kars,120,gurrang avenue,alnwick,rosslea,3241,vic,19880426,5932561 +rec-2077-org,sophie,paterson,15,glynn street,family day care,lethbridge,6027,nsw,19850726,3382181 +rec-3223-org,bianca,mccarthy,23,wakefield garden,foster ldge (cnr wallis s street,elizabeth south,3216,vic,19991221,3231146 +rec-3156-org,adam,ewald,61,wentcher place,longstay caravn park,kempsey,5092,nsw,19180203,2268410 +rec-3526-org,lilian,berry,17,goldstein crescent,berowra,maida vale,3103,vic,19030329,3427724 +rec-3511-org,benjamin,rau,119,lenehan street,binnalong,burleigh heads,2065,vic,19040120,8590013 +rec-1893-org,sophie,creagh,39,maplestone place,berkeley vlge,mansfield,5108,vic,19221207,5082702 +rec-1055-org,hayley,white,74,medley street,raymond terrace market place,regents park,2656,vic,19391111,6020101 +rec-80-org,blake,white,198,boldrewood street,winter park,nunawading,2067,sa,19180815,5832531 +rec-191-org,madeline,liteplo,28,mckay garden,kangaroo grnd,creswick,2871,nsw,19640410,9983895 +rec-3104-org,louise,campbell,42,melrose drive,fairholme,king river,2066,qld,19931202,3214176 +rec-3564-org,chloe,clarke,91,hurtle avenue,avonwood,martinsville,4152,act,19760805,6520116 +rec-3329-org,vanessa,bishop,7,kanooka street,dallyn,cooran,2157,wa,19130914,3823695 +rec-39-org,gabrielle,blake,360,hardwick crescent,carramar home,camp hill,2010,qld,19960302,5207765 +rec-3379-org,jack,rudd,4,limestone avenue,orcadia park,hoppers crossing,5007,nsw,19080618,3984278 +rec-143-org,cameron,paterson,27,florey drive,palm springs vlge,dandenong north,6210,qld,19560821,7463970 +rec-3273-org,ryan,dixon,34,newman street,dolphin arcade,upwey,2913,qld,19040202,5468762 +rec-2500-org,mia,pyper,90,paul coe crescent,pine hill,camp hill,4207,,19410921,2154974 +rec-562-org,jasper,webb,7,badimara street,tallow-wood,geelong east,5073,qld,19780525,4462979 +rec-2935-org,thomas,nickolai,17,clode crescent,bendigo retirement village,woy woy,3851,tas,19390429,4414879 +rec-3437-org,ethan,mccarthy,257,chambers street,berkeley vlge,west wollongong,3818,nsw,19020506,4852331 +rec-4987-org,david,lovelock,24,davison place,the park,warramboo,3163,qld,19190717,2747099 +rec-3688-org,alexandra,millar,1,loureiro street,killarney,alice springs,2430,vic,19180327,8677356 +rec-943-org,rosie,karlsen,48,lycett street,cottonwood,redbank plains,3013,nsw,19041101,3233946 +rec-1736-org,jye,dearing,201,matcham place,currimundi garden,bundaberg,5520,qld,19940616,7183071 +rec-2233-org,ty,noble,119,sherbrooke street,coolalinga village,woy woy,2500,nsw,19821125,2989264 +rec-4150-org,joshua,golden,22,mcintosh street,ra 23012,noble park,2753,sa,19940329,1747756 +rec-436-org,jackson,lehane,115,totterdell street,hawksview,balwyn north,2099,wa,19390312,2738637 +rec-3884-org,lucas,bishop,14,oldfield circuit,the points holsteins,woodville gardens,7212,qld,19210425,2795703 +rec-1206-org,alissa,priest,7,lawley street,locn 5885,granville,4113,qld,19241102,1113130 +rec-4943-org,timothy,hilton,,coventry close,killuke,goonellabah,5034,nsw,19241018,8085483 +rec-3257-org,tayah,noble,10,city walk,george forbes house,merino,5096,vic,19250315,8376614 +rec-698-org,silas,constance,15,coventry close,omeo,wahroonga,3079,qld,19620628,4562356 +rec-42-org,sarah,pringle,49,pitcairn street,riverside park,meadow springs,3305,qld,,1621253 +rec-1550-org,livia,miles,15,stewart crescent,rosetta village,thornbury,3851,act,19760903,9683666 +rec-535-org,lauren,white,53,collings street,wollumbi,pacific paradise,3041,nsw,,9250255 +rec-2926-org,danika,charman,9,embling street,amelia,sheidow park,6168,nsw,19330313,1161308 +rec-2480-org,james,spall,28,alabaster street,inglewood,orange,5214,vic,19750720,5050590 +rec-3028-org,aaron,barsoum,46,ashby circuit,moodwood angus stud,kangaroo flat,6012,nsw,19730330,9626981 +rec-1448-org,teal,donaldson,,o'sullivan street,willow lodge,springwood,7030,nsw,19241229,8492921 +rec-4344-org,marcus,roddick,46,fullerton crescent,stonehouse,cashmere,2753,vic,19381222,7785247 +rec-1620-org,zachary,michelmore,11,brisbane avenue,oakdale,warrane,6330,qld,19430124,2800552 +rec-2810-org,rachel,ryan,98,knox street,ashdown,wangaratta,4105,sa,19491218,5164957 +rec-149-org,carla,hofhuis,7,mcculloch street,wytaliba,south brisbane,4066,nsw,19660816,3472110 +rec-4389-org,simone,,31,girdlestone circuit,split solitary caravn park,exmouth,3016,nsw,19960610,6137393 +rec-2379-org,jacqueline,malinauskas,4,jabanungga avenue,longplain,bundanoon,4878,vic,19840808,5856134 +rec-4754-org,ava,fuda,11,dines place,kings apmts,rostrevor,3250,tas,19580912,9818747 +rec-406-org,chelsea,,186,spofforth street,,clare,2750,vic,19560408,9709885 +rec-4889-org,hugh,fenwick,,totterdell street,mariner views,west perth,4814,nsw,19621028,8578252 +rec-2015-org,arabella,sorsa,29,corringle close,mari-ma farm,mulgrave east,4871,qld,19450119,2313601 +rec-2900-org,annika,boyle,10,macgregor street,,paddington,3175,qld,,7187050 +rec-3464-org,maggie,webb,5,eucumbene drive,hawkins masonic vlge,elwood,2265,nsw,19060830,3505267 +rec-286-org,kiara,drechsler,2,shackleton circuit,glenview,bulimba,4064,tas,19590816,4345746 +rec-1307-org,danielle,campbell,582,paul coe crescent,ningana,bronte,3156,nsw,19531121,9708458 +rec-2443-org,stephanie,mason,11,preddey way,combogolong,parmelia,2605,nsw,19340302,7871353 +rec-81-org,daniele,burford,71,waddell place,pine view,junee,4055,qld,,3005084 +rec-1902-org,andrew,dunstone,2,hodgson crescent,homevale,nambour,2121,nsw,19230326,6824396 +rec-3883-org,amber,webb,1,biddlecombe street,cedarview,trevallyn,3777,qld,19920815,2423271 +rec-653-org,nicholas,pontt,15,bulli place,wattle mount,new farm,2750,vic,19570101,3411264 +rec-3878-org,briley,sheldon,16,ellerston avenue,melaleuca,hamilton,4226,vic,19200327,8538359 +rec-368-org,ned,feeney,2,barringer street,holmeleigh,brighton,3165,vic,19071029,1440128 +rec-4460-org,aidan,rees,27,ferguson circuit,,camp hill,2207,nsw,19060524,3860536 +rec-1000-org,victoria,zbierski,70,wybalena grove,inverneath,paralowie,5065,nsw,19720503,1267612 +rec-2741-org,mattheo,hazell,13,palmer street,jarrah,harbord,4116,qld,19240211,2546491 +rec-3544-org,jessica,belchel,9,irvine street,st francis vlge,port macdonnell,2029,sa,19700610,5379753 +rec-4529-org,hayden,needham,1,daintree crescent,kiouwa,corrimal,3218,nsw,19020930,4674771 +rec-2841-org,madeleine,sideris,6,rose scott circuit,brunton,glendale,4670,nsw,19851113,4355459 +rec-1496-org,gabriella,shadbolt,10,tenison-woods circuit,villa 5,maitland,3918,vic,19100320,1897470 +rec-684-org,miller,matthews,23,arndell street,myalpa,athelstone,2483,nsw,19680122,3203561 +rec-1515-org,chloe,pamalia,10,balanu place,hornsbie,orange,5037,nsw,19210412,6788630 +rec-4575-org,jordan,rosa,99,dobson street,ben nevis estate,berwick,2145,qld,19180519,4793062 +rec-465-org,hannah,gluck,63,noble close,,kolodong,4352,vic,19760710,9951963 +rec-3314-org,jaden,brammy,22,blackett crescent,parry house,keilor east,4810,tas,19620916,3934199 +rec-2684-org,rebecca,dimauro,54,narrabundah lane,rowethorpe,oakleigh,2540,vic,19970111,6763318 +rec-484-org,nathan,white,113,chewings street,ballawinna stud,oak park,4118,nsw,19981116,2568695 +rec-1908-org,chloe,white,91,phillip avenue,avenel,toowoomba,3550,qld,19520722,2709559 +rec-4807-org,nathan,asher,1582,collings street,dalmoora,scarborough,2305,nsw,19591112,1760594 +rec-4680-org,zac,vincent,19,sturt avenue,grandview,brighton-le-sands,6024,nsw,19250320,4898468 +rec-3421-org,hayley,dixon,32,ashkanasy crescent,enderlee,cohuna,2069,nsw,19300303,6355088 +rec-35-org,kiandra,lock,33,dampier crescent,kalang,cardiff,3500,qld,19330410,1004953 +rec-1867-org,madeline,schembri,12,burhop close,girrahween homestead,ngunnawal,5158,qld,19550429,2492474 +rec-1813-org,louise,butt,20,chirnside circuit,robina,mclaren vale,7004,vic,19250204,4646918 +rec-4140-org,patrick,tomney,49,smiths road,tillabudgery,ascot vale,2340,qld,19390509,4461989 +rec-4196-org,luke,cowle,51,dampier crescent,glenevie,vermont south,4721,qld,19160724,3612406 +rec-4939-org,fraser,hebberman,28,henderson street,kalinda park,cowra,3429,qld,19900809,9636276 +rec-1646-org,charlotte,maier,30,mountain creek road,frost mews,eight mile plains,4160,,19820325,2565331 +rec-2712-org,abbey,oats,116,sabine close,kiloran,camp hill,3930,qld,19471031,7179281 +rec-431-org,jack,wastell,91,bromell circuit,mount beauty,springwood,3184,nsw,19030130,1134532 +rec-1766-org,james,hayball,30,hemmings crescent,,tiaro,2117,qld,19720110,6438283 +rec-4554-org,jamie,wardle,1,shakespeare crescent,youralla,harris park,2720,nsw,19990726,4283546 +rec-232-org,nicholas,george,10,hall street,rhode island resort,brighton,3264,nsw,19920715,3273376 +rec-325-org,ruby,nguyen,4,wheatley street,glenfyne angus stud,keilor east,6008,wa,19400526,8118562 +rec-1124-org,lily,clarke,25,emerton street,eight mile,woodville south,4223,nsw,19690612,4559335 +rec-21-org,abbey,hoffman,6,colmer street,rosetta village,keilor,4285,nsw,19070925,4455111 +rec-4679-org,christopher,neville,20,talbot street,cliffney park,waterloo,4173,qld,19820525,8644857 +rec-2284-org,nicholas,kaukov,295,jervois street,dodonaea wing,wamberal,4077,qld,19070128,8401381 +rec-1858-org,alice,campbell,16,de little circuit,unt 1,bonville,2118,,19130416,2353372 +rec-615-org,emiily,nguyen,10,noble close,hillbyrne,naradhan,6151,nsw,19550413,5771309 +rec-4688-org,jamie,cloke,124,kosciusko avenue,,springwood,3125,nsw,19891008,3390421 +rec-4225-org,ruby,mcphie,12,hambidge crescent,namarva station,ballarat,4868,nsw,19470101,3454863 +rec-3371-org,thomas,alderson,4,temperley street,camelot est,rosslea,2195,nsw,19380411,1125721 +rec-917-org,carly,georgetti,155,lockyer street,langi,rowville,2087,qld,19740602,7008776 +rec-1241-org,lucy,krzempek,9,heysen street,macarthur place,sandy bay,3337,vic,19170123,5598578 +rec-3816-org,charlotte,dalli,62,debenham street,sattwa park,kings cross,5170,vic,19921022,8847906 +rec-4086-org,thomas,crofton,21,battersby circuit,phillip lodge,old reynella,4810,nsw,19120925,6433953 +rec-456-org,jaxson,ryan,51,staunton place,wilderness,greenacre,6430,vic,19270613,7731951 +rec-4678-org,jessie,donkin,68,mackennal street,ferndale,port macquarie,2573,nsw,19900906,3358033 +rec-2777-org,jake,mazurkiewicz,7,ashcroft crescent,millard centre,tannum sands,3971,vic,19580122,8132590 +rec-1792-org,layla,ban,17,howitt street,oaklane,kirwan,4210,sa,19201015,4834950 +rec-124-org,joel,finlay,3,budyan court,mountain view village,adamstown heights,2095,nsw,19171215,5425013 +rec-3183-org,jack,akkermans,149,spofforth street,willera,broken hill,5157,wa,19130710,8370439 +rec-4903-org,hannah,mihal,,aspinall street,dma offices (cnr wales s street,nyah west,6060,vic,,7161412 +rec-4261-org,anthony,hope,136,buckmaster crescent,locn 2655,numeralla,3138,nsw,19330922,3443364 +rec-4245-org,mia,leane,3,hobart avenue,budgerie,ballarat,4068,qld,19841029,4638734 +rec-1253-org,cambell,clarke,99,jardine street,alexander's folly,lower templestowe,2114,wa,19250326,2467909 +rec-271-org,abby,sporn,29,nivison place,key,joyner,2340,sa,19830505,5733964 +rec-2668-org,ethan,hage,62,livingston avenue,enderlee,nunawading,3350,nsw,19210108,4440855 +rec-351-org,tara,maczkowiack,24,kleinig street,brentwood village,kennington,3058,nsw,19490204,3912484 +rec-598-org,james,hebberman,26,phillis place,twenty-third avenue pharmacy (cnr mawarr,ettalong,2326,vic,19760410,1748689 +rec-712-org,emma,geue,1220,rumker place,milbrodale,woodend,2429,nsw,19941224,3886398 +rec-3337-org,dylan,reimers,140,peacock place,tulloch,st albans,3585,qld,19211103,3790788 +rec-1850-org,macormack,clarke,215,giblin street,argyle village,leongatha,3335,vic,19180705,3112446 +rec-1468-org,aaliyah,ottens,17,mullan street,hinton brook,ascot vale,3199,sa,19181214,3004031 +rec-1344-org,sebastian,blissenden,16,mataranka street,the homestead,ashfield,2758,wa,19750320,4893136 +rec-3589-org,patrick,wasley,8,barwon street,llangollen,winmalee,2538,nsw,19860312,9514502 +rec-3283-org,gregory,bujtas,,badimara street,tourist park,killara,4285,nsw,19581002,6763771 +rec-1245-org,amelie,lohe,107,coghill close,gurnamunya,port macquarie,2021,vic,19200613,6372043 +rec-4692-org,annabelle,dixon,4,fitzroy street,,dulwich hill,3666,vic,19770517,4868604 +rec-4491-org,warrick,plane,41,lingiari court,miowera,noosa river heights,5108,vic,19860411,3214712 +rec-3827-org,warrick,farragher,1,therry place,dental 3 garden city shopping centre,rose bay,3175,nsw,19920222,6909540 +rec-4583-org,lucas,daysh,11,bolger place,blackrange road,andrews,4130,vic,19701026,7306086 +rec-1762-org,hayley,mort,7,namatjira drive,nioka,iluka,6027,qld,19150115,8448786 +rec-387-org,alexander,eglinton,1,grampians street,ben hill,birkenhead,3885,vic,19700511,2618040 +rec-999-org,jacob,lowe,179,parkhill street,brigalow court,arundel,2167,vic,19761225,8295931 +rec-553-org,nicola,bishop,60,knox street,nyngan,hurstville south,3116,wa,19770427,2727947 +rec-3048-org,jack,colquhoun,17,,glenburn,cambroon,2000,nsw,19660816,1194516 +rec-1502-org,niamh,tuckwell,2,richman place,,campbelltown,2154,nsw,19090106,2794307 +rec-4954-org,james,krollig,15,orchard place,donnachaidh,rosebud,6064,nsw,19430421,4244938 +rec-2867-org,katelyn,satterley,28,newman morris circuit,carrington garden,belmont,2074,nsw,19730919,1989082 +rec-2753-org,jessica,osfield,6,woinarski place,,paddington,7010,qld,19830206,9942050 +rec-3608-org,jessica,winfield,47,fullagar crescent,shopping centre,taylors bay,4301,sa,19761107,9277281 +rec-4004-org,amalia,brookhouse,878,,hilton house,belmont,3844,nsw,19370722,1915625 +rec-1311-org,,klemm,43,clem hill street,,st kilda,4205,qld,19751020,5119969 +rec-4927-org,daniel,glass,8,roe street,rowethorpe,williamstown,2026,tas,19170309,4569679 +rec-2525-org,erin,excell,15,waller crescent,bindaree,west swan,2539,qld,19460622,5466287 +rec-3864-org,mya,ayres,56,thornton place,rockleigh cottage,nedlands,2642,vic,19220730,5645315 +rec-386-org,bradley,crook,140,jacka crescent,locn 1699,south brisbane,4380,nsw,19480319,4421582 +rec-4592-org,elizabeth,noble,167,rosebery street,glenmore,eatons hill,2485,vic,19820730,7294023 +rec-3781-org,nathan,nguyen,12,staaten crescent,yarrabee,moura,3170,qld,19961006,4794269 +rec-1190-org,kale,tschirn,100,waldock street,garaweh,bayswater,3350,vic,,6637214 +rec-1547-org,abbey,rawlings,46,john young crescent,glen rock,eastwood,3144,qld,19861016,8663646 +rec-4418-org,charlotte,scattini,4,miller street,sunset,south melbourne,6011,nsw,19540114,4866579 +rec-4867-org,gabrielle,tarquinio,24,lind close,,frankston,4505,vic,19650419,4738861 +rec-3844-org,luke,wotton,36,gleeson place,birch grove,westlake,3189,vic,19780117,6707270 +rec-3891-org,,hilton,25,heard street,craiglyn,blue haven,2614,wa,19550612,2455796 +rec-2438-org,ashley,clutterbuck,26,freda gibson circuit,,cabramatta,3029,vic,19920810,4483745 +rec-3025-org,hannah,sinoch,9,blackwell circuit,st francis vlge,broadmeadows,2650,vic,19770628,4760009 +rec-3685-org,benjamin,lowe,45,macrossan crescent,koyo,kingston,6057,nsw,19250611,5513136 +rec-4997-org,kane,george,351,gosse street,balala station,minnamoolka,4061,vic,19571204,9672746 +rec-1676-org,joel,lamprey,12,twynam street,alanvale,revesby,2537,qld,19200815,2877737 +rec-1358-org,connor,bishop,450,earle street,coorrabin,broken hill,7320,vic,19261223,7015666 +rec-2286-org,lachlan,ryan,21,alberga street,tathra,forest hill,3150,qld,19070322,9772701 +rec-1151-org,courtney,gilbertson,35,maccallum circuit,barley hill,granville,2646,qld,19910105,5257049 +rec-3551-org,talena,richmond,25,hopetoun circuit,tricorne (cnr scone r road,south melbourne,3055,nsw,19621215,1051084 +rec-4836-org,maddison,weidenhofer,28,dinnison circuit,,bray park,2484,qld,19781125,6273334 +rec-786-org,courtney,okulewicz,12,hodgson crescent,goldenvale farm,forrestfield,4214,tas,19990419,1581871 +rec-350-org,jayden,death,13,lyle place,omearas farm,leeton,2111,vic,19880218,2543380 +rec-2171-org,lachlan,mcdermid,8,finniss crescent,ettalong beach village,kellyville,4220,vic,19400318,8407575 +rec-4286-org,carly,honeychurch,4,dalley crescent,john flynn medical centre,oakville,4700,sa,19510713,3359709 +rec-745-org,tahlia,white,8,black street,the haven pole,wantirna,4350,sa,19570317,4436806 +rec-2287-org,lucas,pascoe,163,tepper circuit,aldersyde estate,corlette,4213,nsw,19350308,5399636 +rec-270-org,sophie,weidenhofer,,owen dixon drive,rosebrook,cremorne,2170,sa,19750525,7013216 +rec-921-org,william,apted,101,woralul street,brentwood vlge,padstow,5290,nsw,19770910,2734917 +rec-4176-org,matthew,dukic,20,ebeling court,sec 1,manly vale,4107,qld,19290219,1480466 +rec-3805-org,leah,swoboda,33,macnaughton street,woodrose,tweed heads,6069,vic,19821102,9528232 +rec-3600-org,brooke,rabbitt,46,cockcroft avenue,swanleigh,coolum beach,6110,wa,19080421,6122971 +rec-2580-org,charlie,white,76,kavel street,posetto,campbelltown,6110,sa,19070917,3793652 +rec-74-org,sonja,nguyen,2,eyre street,,lake clarendon,5023,nt,19591021,6742110 +rec-2959-org,isabella,green,11,boothby place,sefton park,pooraka,2102,vic,19281105,6738971 +rec-4395-org,jessica,andretzke,14,chowne street,st francis village,lilydale,3134,qld,19340225,6331022 +rec-771-org,xanthe,maynard,2,blackman crescent,rosa blanca,yeoval,2196,qld,19110520,6072195 +rec-2762-org,chloe,white,101,goldstein crescent,brentwood vlge,stoneyford,2212,nsw,19181228,5862107 +rec-2213-org,timothy,gilley,29,coghlan street,vinder lodge,magill,2197,nsw,19790709,5268628 +rec-3170-org,skye,heenan,9,hadleigh circuit,nunkeri,blue haven,3072,vic,19911002,3918522 +rec-1145-org,luke,harrington,80,jaeger circuit,montrose,hughes,4215,nsw,19340611,4560409 +rec-3107-org,emiily,braithwaite,86,beasley street,belmont bayview park,st agnes,4814,nsw,19140328,4464915 +rec-4877-org,jack,roles,22,musson close,glen ayre,coledale,3977,wa,19650917,8518344 +rec-2161-org,connor,no,11,barunga street,jim holm hostel,rothwell,6168,sa,19171023,4958150 +rec-98-org,,mchenry,80,gurnai place,umavale,eaton,4215,vic,19340302,4214409 +rec-538-org,lucy,eglinton,5,jefferis street,,midway point,3057,wa,19070301,3897066 +rec-4356-org,jack,dunnicliff,63,tristania street,legacy vlge,sale,2428,vic,19760618,4815066 +rec-3235-org,noah,van de kamp,39,feathertop street,argyl square,heckenberg,5072,vic,19180723,8217720 +rec-622-org,joshua,avdic,8,archdall street,nioka,nunawading,3134,nsw,19200415,9571448 +rec-4675-org,miranda,,4,banner street,parraweena,mitcham,2615,qld,19940321,7871784 +rec-4721-org,ethan,steed,38,williamson street,wilga,greensborough,2074,vic,19091116,5384988 +rec-840-org,noah,nguyen,8,carroll street,locn 10045,eastwood,7053,sa,19101127,2142666 +rec-334-org,nicolas,bartel,160,furphy place,bridgewater estate,ekibin,3630,nt,19890220,2422771 +rec-1859-org,angie,arbuckle,14,mcinnes street,,ballarat,4808,nsw,19890525,7610312 +rec-450-org,harrison,stanley,69,macalister crescent,applewoods,thornlie,5063,qld,19871206,4461645 +rec-1022-org,bridget,knopf,67,shackleton circuit,bridle bit,naracoorte,5255,qld,19760317,5405822 +rec-3997-org,jessica,beams,19,griffiths street,glenburn,toorak,5540,nsw,19040321,7839655 +rec-2206-org,ambrosia,shorrock,2,amess place,arlington,macmasters beach,3523,nsw,19921231,8411190 +rec-4573-org,jamie,death,2,galway place,wylarah,werribee south,3356,nsw,19650829,3127934 +rec-2902-org,charlize,gani,95,bramston street,,modbury heights,5013,qld,19830412,1175982 +rec-2410-org,sarah,tuckwell,39,dines place,raycroft,daisy hill,6149,vic,19100817,8854990 +rec-2620-org,brooklyn,mercorella,41,endeavour street,knox retirement village,concord west,2083,nsw,19050705,7877973 +rec-3704-org,john,finlay,108,kuhn place,,,3081,qld,19771208,9133711 +rec-3610-org,zac,mashberg,32,barraclough crescent,mowbray,ballina,3184,nsw,19680330,8938791 +rec-4802-org,liam,wilkins,2,hansen circuit,forestdale,sadleir,5018,sa,19530304,6164019 +rec-4466-org,aidan,white,16,brunton street,rosetta village,frankston,2800,vic,19731009,6366377 +rec-3088-org,sachin,,85,sparkes close,villa 36 sovereign garden,cairns,7250,vic,19820717,8721401 +rec-3934-org,kai,rachwal,128,ardlethan street,glenavon,edgewater,4217,wa,19100330,5698267 +rec-3735-org,jye,churches,1,fraser court,wirruna,labrador,4151,vic,19200210,2271081 +rec-1932-org,seanna,pendle,20,mcleod place,hawkins masonic vlge,kogarah,4600,nsw,19670602,8149220 +rec-1419-org,caitlin,alessi,1,davies place,bindana downs,tungamull,2060,vic,19410721,6485512 +rec-2763-org,ruben,reid,12,shannon circuit,windalea,hackham west,5159,nsw,19021019,4450079 +rec-2815-org,april,lock,4,paul coe crescent,maf-ue arabians,auburn,5035,nsw,19760203,7696268 +rec-3707-org,hayden,mortlock,5,,alice downs,kulikup,4805,qld,19570219,3860930 +rec-4522-org,brooke,reid,27,skertchly place,santa lucille,rye,4116,qld,19431227,3146566 +rec-4362-org,macormack,wilkins,30,sexton street,raaf,buxton,4123,vic,19081026,4698984 +rec-3118-org,emma,rook,11,chauvel circle,westside,boyanup,4221,nsw,19650302,9822954 +rec-1742-org,amber,crouch,75,crisp street,manning village,kyabram,2648,vic,19010309,2336725 +rec-4730-org,isabella,campbell,1,,glen wilga,broadmeadows,4350,vic,19520421,3865943 +rec-273-org,isabella,stanley,9,spofforth street,the falls,sherwood,3150,nsw,19381021,7253600 +rec-2101-org,tahlia,herbert,28,dolling crescent,curra park,kingston beach,3840,nt,19790724,6559247 +rec-3998-org,annabelle,webb,105,eyre street,alcarana,turner,4157,nsw,19020930,2019510 +rec-75-org,lachlan,webb,19,national circuit,,safety bay,7250,qld,19370423,4001224 +rec-3320-org,mia,mihaylov,1,igera place,glenview,gawler east,2093,nsw,19480330,3359084 +rec-577-org,william,ryan,33,limbunya street,cherrybank,new farm,4105,nsw,19550514,5451157 +rec-991-org,millie,clarke,16,darcy close,marjories corner,greenwith,3150,nsw,19160503,5080999 +rec-82-org,alice,godfrey,2919,florence taylor street,wilga,kempsey,2761,vic,19910330,3541229 +rec-1337-org,ella,sztolc,29,berrigan crescent,,rivett,3094,qld,19481217,6141781 +rec-3795-org,peta,stanley,17,,callatoota,northwood,2217,nsw,19450829,7849495 +rec-3859-org,leo,waterfall,1,mockridge crescent,aptmn 12,malvern east,4157,vic,19430408,8187145 +rec-4965-org,william,daish,500,osburn drive,pink lake caravan park,eastwood,3058,nsw,19311114,8646353 +rec-1013-org,gillian,pighin,123,hilder street,iron bark ridge,cooma,4508,nsw,19990501,6489570 +rec-2364-org,ella,reinhard,128,woolls street,deswod,ulverstone,6024,wa,19310610,7101829 +rec-1774-org,kayla,lomman,11,barber crescent,springetts arcade,south arm,2101,nsw,19970818,5339302 +rec-17-org,william,dixon,89,longman street,fernlea,rosebud,3315,nsw,19960927,7060978 +rec-1984-org,travis,whale,2,sutton place,trumalon,terrigal,3976,sa,19320724,1928625 +rec-1897-org,rosie,plane,29,porteous crescent,,black rock,2062,vic,19630926,7058877 +rec-282-org,flynn,van heythuysen,,shepherdson place,nunkeri,rose bay,2121,nsw,19780418,3254370 +rec-4495-org,connor,belperio,15,louisa lawson crescent,,ryde,2570,nsw,19170518,5394641 +rec-3033-org,benjamin,rankine,34,anstey street,forest hills,broome,3140,nsw,19120704,2412111 +rec-3524-org,lachlan,matthews,6,mcmillan crescent,corcoran,miriam vale,2009,nsw,19420818,7138643 +rec-2655-org,kelsey,ovens,63,biraban place,eventide homes,st albans,2470,act,19891030,4850685 +rec-479-org,joshua,webb,10,beetaloo street,tongeroo,brighton,6110,qld,19040213,5702764 +rec-1883-org,georgia,rau,12,wolff crescent,mt derriwong,greendale,3805,qld,19451104,7297422 +rec-872-org,joel,wanders,453,louis loder street,hilltop view motel,avoca,2284,qld,19120509,3198280 +rec-3968-org,charlie,furfari,132,wellington street,balfron station,harbord,3166,nsw,19410505,2381712 +rec-4181-org,nicholas,singleton,,lanley square,henry kendall bayside,malabar,4560,qld,19430819,7737769 +rec-2803-org,abigail,paterson,2,bega flats,bowen park,blakehurst,4151,tas,19021218,4253487 +rec-3570-org,jaxson,selth,1,moonta place,walhalla,maryborough,2066,qld,19130707,7238580 +rec-4172-org,robbie,harbord,3,wrixon street,darjeeling,myall,2299,sa,19760411,2936318 +rec-740-org,prudence,reid,13,ashkanasy crescent,victoria mill estate,kirribilli,6163,vic,19950117,6754135 +rec-3853-org,brianna,dixon,18,staaten crescent,buckhobble,greensborough,3013,nsw,19860928,4919547 +rec-4496-org,hari,warnock,8,jansz crescent,brentwood vlge,broadmeadows,2486,qld,19350219,7539077 +rec-570-org,taylah,oats,87,federal highway,scotch college,armidale,2125,nsw,19300715,9175271 +rec-533-org,luke,harrington,1539,macdonnell street,glenmarla rmb 2563,cloverdale,4573,,19020202,8262052 +rec-1345-org,zachary,coffey,21,fellows street,brigalow court,christies beach,5031,qld,19240219,4912880 +rec-2040-org,phoebe,dixon,,theodore street,swanleigh,gordonvale,2800,act,19180515,9639024 +rec-2932-org,zachary,kermeen,7,powell street,tourist park,yass,5162,qld,19131006,1784799 +rec-4537-org,mia,miles,54,beirne street,pacific palms caravn park,windsor,3268,nsw,19720726,3671331 +rec-4274-org,marleigh,white,1,fink crescent,dunbar,hackham,2165,qld,19900720,6423331 +rec-2365-org,fraser,burford,39,davidson street,riverbend,kingston,3183,qld,19310910,6160407 +rec-2265-org,benedict,vincent,27,mcclaughry place,k mart plaza,cunnamulla,5047,qld,19721119,3291682 +rec-3855-org,beau,green,45,darwinia terrace,kilburnie,brunswick west,2770,nsw,19150621,5567610 +rec-1920-org,mathilde,cookson,8,shakespeare crescent,burrawang,safety bay,5158,nsw,19570319,4257072 +rec-1872-org,naomi,reid,6,jamieson crescent,locn 2192,unanderra,2031,qld,19980521,6918953 +rec-194-org,jayden,sekulitch,872,casuarina street,cottage rose,yagoona,4503,nsw,19310401,6055233 +rec-1456-org,damien,couzens,32,paul coe crescent,mount beauty,greensborough,3206,qld,19940415,7719637 +rec-2958-org,lily,clarke,66,,sun village,magill,3204,vic,19200906,6916349 +rec-582-org,benjamin,ayres,32,french street,red cedars motel,,3021,qld,19150927,1244940 +rec-303-org,maria,dun,28,sheaffe street,brookvale,midway point,2229,wa,19990308,2567879 +rec-4453-org,samuel,peachey,28,waratah street,goonahra,wanniassa,2750,vic,19531113,2548288 +rec-4241-org,chloe,steane,13,blacket street,perisher valley,kyabram,2232,nsw,19790905,5378031 +rec-626-org,lauren,moorby,29,rapanea street,new chum,leongatha,3146,nsw,19820530,1758831 +rec-3287-org,william,white,3,stanbury close,,hawthorn,5092,wa,19120603,6104386 +rec-1534-org,noah,mason,15,morehead street,fingal park,duncraig,3350,nsw,19890129,5247400 +rec-1133-org,annabelle,berry,40,rowntree crescent,cherry haven,tongala,6028,wa,19430705,2510289 +rec-1797-org,jessica,regalado,,clive steele avenue,edge hill,devonport,6076,qld,19441202,2223697 +rec-2088-org,andrew,webb,,lukin place,craiglea,south brisbane,2500,vic,19001025,2313225 +rec-4306-org,levi,hunting,203,euree street,northern tablelands tennis academy,condell park,4207,wa,19580418,7383570 +rec-2179-org,thomas,kinnane,10,centaurus street,water view,bondi junction,2010,nsw,19700907,9269196 +rec-1730-org,kyle,straczek,1,hardwick crescent,the willows,blacktown,2100,vic,19160506,4665343 +rec-753-org,micah,jolly,38,lefroy street,,yass,3088,nsw,19970605,3265234 +rec-3357-org,keaton,lutz,20,ragless circuit,st agnes retrmnt vlge,north sydney,6007,wa,19670911,6728130 +rec-672-org,sophie,rivera,9,burkitt street,lake chatsworth,sheidow park,2089,qld,19830203,1376770 +rec-4056-org,matilda,satterley,5,eugenia street,strathlea,kedron,3056,qld,,7200837 +rec-539-org,macy,donaldson,17,laseron place,barossa village,altona meadows,2767,vic,,6788131 +rec-2857-org,angie,hyland,1,wardell place,port fairy road,beaumaris,4650,wa,19770803,7407973 +rec-1088-org,bethany,belonoha,17,carstensz street,greenhills,samford,6023,vic,19870512,9824396 +rec-4394-org,hana,nirta,113,mcburney crescent,caroona village,glen eden,4814,qld,19940127,5873271 +rec-3554-org,kate,mcmullen,24,,fairholme,port macquarie,2470,qld,19940928,1366439 +rec-3175-org,alexandra,bishop,2,black street,leetsvale caravan park,huonville,3885,nsw,19610813,8253150 +rec-4616-org,joshua,green,32,kingscote crescent,retirement village,korora,2617,vic,19351228,4876691 +rec-4180-org,finn,leslie,7,longmore crescent,the lodge,woodcroft,7250,qld,19670715,7668675 +rec-3533-org,tynan,laning,325,neeld place,rockview,lalor,6071,qld,,5239410 +rec-2356-org,harrison,blackwell,50,leist street,ruffenuff,christies beach,3977,vic,19570321,6072506 +rec-2028-org,zachary,minter,2,miller street,,port adelaide,2300,nsw,19580309,7193282 +rec-3310-org,tristan,lombardi,3,morduant place,duck creek,kingaroy,4171,tas,19280422,8584160 +rec-4094-org,michael,boesten,7,dannevig place,leumeah,floreat,4702,qld,19991004,6078871 +rec-4336-org,chelsea,shepherd,4,stow place,blueberry farm est,ringwood east,2447,qld,19170310,4730733 +rec-1434-org,sarah,mccarthy,38,nealie place,sunny braes,north ward,4017,qld,19130115,6518105 +rec-1961-org,alicia,beaty,6,fred williams crescent,thomas scott village,mackay north,2074,nsw,19591014,7678577 +rec-2586-org,carlin,sherriff,190,hardman street,ocean park towers,cambridge,6059,vic,19651125,5986787 +rec-2113-org,jaxin,jolly,114,llewellyn crescent,merrimac heights,bull creek,4017,sa,19250202,7133472 +rec-131-org,joshua,beatton,118,nunan crescent,kimbe,bundaberg,2171,sa,19090913,2110769 +rec-1162-org,jack,webb,87,hodgkinson street,rabbit warren,st kilda east,2216,nsw,19730327,4227791 +rec-1417-org,brooke,berryman,430,damala street,wallaces ck,glengarry,2460,vic,19500517,9772693 +rec-2182-org,zachary,ebert,16,rounsevell street,lake road,mount gravatt,2112,nsw,19261127,1502014 +rec-2030-org,chloe,white,7,myall street,yallanbee,north maclean,2066,vic,19830207,7105783 +rec-997-org,madeline,whithear,5,eggleston crescent,tinaroo falls,bunbury,4069,vic,19090324,8752227 +rec-2095-org,ben,armiento,17,burnell place,john flynn hospital,fairlight,3630,qld,,8511174 +rec-4911-org,marlee,ryan,,brittlebank circuit,yulunga,ringwood,7248,sa,19180126,4573130 +rec-3516-org,miller,browne,46,chuculba crescent,gullamurra,belrose,3015,act,19671017,7983195 +rec-2107-org,harrison,snelling,50,sproule circuit,yalkara,emerald,4226,nsw,19410412,1348871 +rec-2964-org,logan,bishop,1,tanjil loop,colombo plains,inglewood,2113,qld,19000423,1698144 +rec-1650-org,mitchell,wilkins,3,rowe place,osborne house,hampstead gardens,4560,nsw,19291123,8024092 +rec-4327-org,thomas,shepherd,12,newdegate street,dorothy genders vlge,lalor,2830,nsw,19100812,1744115 +rec-411-org,thomas,egan,374,tipping place,timbara,peterborough,3585,tas,19430730,4456007 +rec-2123-org,bryce,dixon,178,graves place,mt forrest,kelmscott,5088,vic,19301007,4462693 +rec-2659-org,elise,padbury,137,bennett street,sunny-brae,labrador,3630,vic,19400826,9441828 +rec-1407-org,nicholas,huxley,315,blackbutt street,burnside,unanderra,2213,vic,19761203,8423125 +rec-309-org,eliza,campbell,113,dines place,villa 74 village glen,figtree,2770,nsw,19651205,1754771 +rec-1915-org,shawn,boothroyd,19,melrose drive,rowethorpe,oak park,2166,sa,19700418,8329531 +rec-4149-org,chevonne,montalvo,42,baskerville street,kangaroo grnd,ventnor,2130,vic,19620511,7935536 +rec-2646-org,amy,sommariva,26,fernie place,glenfine station,surrey hills,6167,nsw,19920303,8853255 +rec-4493-org,,braithwaite,136,kemsley place,john flynn medical centre,bellevue hill,2234,qld,19730806,8732209 +rec-2302-org,lachlan,pacey,180,wilshire street,cypress garden,wendouree,2770,,19711111,4723081 +rec-2370-org,wil,eyles,157,totterdell street,rowethorpe,st kilda,2602,nsw,19060606,3998859 +rec-3065-org,robbie,lowe,27,woolnough street,tintagel,armidale,4558,nsw,19680428,6788571 +rec-1072-org,samuel,dixon,13,appel crescent,mulvra,orchard hills,3073,wa,19840925,4689881 +rec-3658-org,ruby,mccarthy,9,halford crescent,clear creek,minto,3305,qld,19490728,9370792 +rec-106-org,elysse,mason,12,zeitz court,cleveland waters,bayswater,3840,qld,19730217,9809705 +rec-3085-org,jasper,tsialafos,,stutchbury street,st francis vlge,cook,2233,nsw,19220428,8232480 +rec-426-org,robert,clarke,42,miller street,central highlands medical centre,port macquarie,3337,vic,19601221,8342535 +rec-2992-org,noah,bruhn,23,boas place,engelbert wing,lilydale,4390,nsw,19590207,8815164 +rec-154-org,joel,bowran,16,port arthur street,laure,bundaberg,3927,wa,19670412,3484624 +rec-3624-org,,manzie,33,hemmant street,lasswade,ormond,3150,qld,19560714,7289058 +rec-4746-org,gabrielle,fargahry-tolba,10,northbourne avenue,pia place,st georges basin,2011,vic,19640424,7326839 +rec-4227-org,emiily,miles,21,andrea place,apt 211,kingsford,2576,nsw,19841130,4117135 +rec-3164-org,william,markellos,13,hartog street,homewood,mansfield,3029,qld,19770717,1866346 +rec-4703-org,olivia,campbell,3,arkana street,,moree,3165,nsw,19640320,5484153 +rec-447-org,april,mcgregor,4,launceston street,hawkins masonic vlge,kardinya,2207,wa,19541028,8809810 +rec-1764-org,katelyn,lodge,36,gregson place,congreave court,kingsford,3089,vic,19840309,6085755 +rec-4656-org,marco,volpato,57,rabnor place,kurajong,spearwood,4224,nsw,19750312,4101153 +rec-277-org,rachel,freeborn,16,may maxwell crescent,melinda lodge,kilsyth,7325,wa,19250411,6206529 +rec-1207-org,kyle,clarke,27,bradfield street,parklands village,lennox head,4061,nt,19150609,7434508 +rec-2951-org,matthew,tombleson,10,ross smith crescent,corandirk,broken hill,3046,nsw,19410702,4972641 +rec-3637-org,kayden,colquhoun,17,kitson place,glenfern park,bourke,2526,nsw,19110330,8761839 +rec-3978-org,,babic,1,totterdell street,cooingale,st albans,4060,sa,19450403,4779301 +rec-1365-org,kane,tiller,19,verbrugghen street,karana homestead,kardinya,2122,vic,19680109,4091125 +rec-4455-org,alexa-rose,vatavuk,,tytherleigh street,flt 10,casino,4670,vic,19620825,5598767 +rec-4667-org,ella,clarke,53,stumm place,booroondoo north,westmeadows,5115,vic,19500203,9535984 +rec-1668-org,caleb,weaver,7,arabana street,ashell,harden,7171,vic,19300527,2414397 +rec-815-org,holly,campbell,21,casey crescent,nestor,westmead,4573,qld,19911007,4424335 +rec-385-org,eliza,schwidder,49,ashley drive,,homebush,4740,vic,19071013,5457556 +rec-4224-org,christopher,felmingham,192,tallara parkway,the provincial,moree,2195,sa,19600327,7478108 +rec-4952-org,madalyn,korfia,114,vansittart crescent,bombowlee,cherrybrook,2147,qld,19690312,4293980 +rec-246-org,rosie,morrison,35,kirkwood crescent,villa 183,springwood,2396,vic,19000326,8113043 +rec-3902-org,,oreilly,,paul coe crescent,wylarah,tuart hill,3219,vic,19500925,4201497 +rec-422-org,talia,rees,13,lethbridge street,,bronte,3038,nsw,19800402,4895894 +rec-4514-org,hamish,beams,102,mackellar crescent,rosedale,,3340,,19670422,5928661 +rec-105-org,breony,webb,10,lewis luxton avenue,court units,duncraig,4216,nsw,19680529,8214196 +rec-3894-org,george,snelling,18,,,paterson,6163,nsw,19800918,5346441 +rec-1064-org,georgia,reid,15,flower place,rainmore,forest hill,7301,nsw,19970612,7201701 +rec-4343-org,jordan,paterson,63,grono place,tarqua,orange,2607,nsw,19420219,2467275 +rec-2110-org,harrison,mason,132,kingstown street,toomba,hobartville,2234,wa,,9269850 +rec-2292-org,ryan,wehr,51,marconi crescent,lasswade,robertson,2165,qld,19990627,6787650 +rec-4049-org,shane,landau,5,miller street,fenner hall,richlands,2640,vic,19430101,4023866 +rec-890-org,benjamin,matthews,3,enderby street,byron van village caravan park,coorabell,2221,sa,19720501,8872778 +rec-2962-org,ethan,ryan,20,eaglemont retreat,melody cottage,camperdown,2615,nsw,19320524,2653664 +rec-233-org,kirra,bahnisch,74,seaborn place,pleasant acres,arundel,3073,nsw,19781119,3690427 +rec-1082-org,imogen,green,1,trickett place,nullo mntain,coromandel valley,7027,,19770615,3231911 +rec-2451-org,stephanie,baptist,30,dalley crescent,,winthrop,4055,nsw,19700503,3846199 +rec-1238-org,joel,londesborough,108,arthur circle,vlla 18 pacific bay resort,kings park,5606,sa,19480110,6254331 +rec-3040-org,zane,webb,21,mackinolty street,mayflower retrmnt vlge,ganmain,6018,vic,19190523,1897310 +rec-4050-org,jamie,hashemizadeh,17,julia flynn avenue,st johns retirement village,gorokan,4205,vic,19231030,4092093 +rec-2027-org,oliver,bissett,6,carnegie crescent,cromdale,kingston,2110,vic,19020522,1262608 +rec-4739-org,jory,chandler,5,wearing street,,chester hill,2113,nsw,19381011,2421676 +rec-4039-org,talissa,macgowan,31,fairfax street,rosetta village,mitcham,5290,qld,19481101,7084722 +rec-1164-org,imogen,vincent,78,brazel street,,penrith,5280,qld,19130303,9001480 +rec-1462-org,aleesha,rashley,93,wybalena grove,,bayswater,3047,nsw,19500413,7372274 +rec-2567-org,lushia,george,15,faithfull circuit,tynwall,cranbourne,5083,nsw,19180219,9545129 +rec-1010-org,zali,shepherd,308,solly place,fairway,valla,2138,sa,,8924972 +rec-4644-org,andrew,white,12,hyndes crescent,sawtell vet hosptl & clnc,blair athol,6070,wa,19620801,6464292 +rec-2163-org,ella,riddell,7,springvale drive,retirement village,melville,5012,nsw,19640405,5082521 +rec-3627-org,paul,maksim,35,blazey place,elouera park,kingston,3143,vic,19280108,2229267 +rec-1320-org,emiily,boulter,12,drevermann street,manila,currimundi,3030,nsw,19770628,4873584 +rec-1588-org,jye,humberdross,37,coles place,de cameron,kingaroy,6230,qld,19510505,8884850 +rec-3326-org,jarryd,george,83,gilmore crescent,,wellard,3071,qld,19320810,4392990 +rec-1968-org,john,coxon,5,paterick place,rosetta village,elizabeth park,6152,qld,,1984934 +rec-4309-org,dylan,yen,83,duffy street,apt 2005,keilor,6056,nsw,19890827,5035246 +rec-65-org,benjamin,moody,34,fernyhough crescent,huongold,port augusta,3192,vic,19180612,4887764 +rec-2745-org,clain,jeffries,12,thurlow place,hawksview,mount eliza,3930,qld,19060706,8877669 +rec-3777-org,lachlan,ricard,40,maribyrnong avenue,tintagel,bowral,4158,sa,19471123,6012074 +rec-2391-org,dylan,covino,63,mcgowan place,pine creek rubyvale,camden south,2280,wa,19880205,9610572 +rec-3513-org,sienna,adhikari,,dodwell street,villa 32,st peters,6215,wa,19370112,3509302 +rec-3181-org,izaac,stubbs,158,serpentine street,grasmere park,magill,5290,nsw,19511101,8604811 +rec-1047-org,alexandra,zolyniak,131,somerset street,wandana,giralang,4285,qld,19421008,7197883 +rec-1251-org,lauren,ryan,115,jardine street,adelaide dental hospital,broadbeach waters,4207,vic,19420313,6195510 +rec-4279-org,alexander,crouch,56,spinifex street,cresden 12182,kedron,5214,vic,19110123,3012627 +rec-4361-org,matthew,ryan,17,darwinia terrace,swinton,acacia ridge,4214,nsw,19510905,4210560 +rec-1471-org,dylan,robson,60,grimshaw street,wallendoon station,colac,3199,sa,19741003,4302323 +rec-3936-org,dakota,jeffries,27,redcliffe street,drayton villas,ringwood north,5113,wa,19050412,5624716 +rec-3876-org,zali,clutterbuck,13,twelve trees crescent,colbes,taringa,4178,vic,19821023,9384648 +rec-3599-org,hannah,mason,23,smeaton circuit,dalkeith cottage,greensborough,2020,qld,19341211,7259553 +rec-189-org,madison,warneke,24,hopkins street,urara,ballarat,2444,nsw,19861016,9508340 +rec-2726-org,charlie,thorpe,775,edman close,kandahar,bull creek,2066,vic,19620923,4837521 +rec-1023-org,harry,mason,42,jabanungga avenue,crown reserve,ryde,4490,wa,19650607,9577264 +rec-3441-org,luke,trenerry,6,shepherd street,scotch college,leongatha,5355,sa,19800424,1086821 +rec-3381-org,ruby,beattie,2,,gnorang,bayonet head,3021,nt,19400303,8128223 +rec-4894-org,jack,salt,71,blaxland crescent,,atherton,5075,nsw,19550406,1176207 +rec-2825-org,pakita,scarce,15,mckinley circuit,killarney,connellys marsh,5067,qld,19600506,9865461 +rec-1678-org,isobel,campbell,17,,yarrandoo,strathalbyn,2770,vic,19470921,3176931 +rec-973-org,mackenzie,reid,37,ebden street,unt 2,malabar,2233,vic,19550203,8091055 +rec-2706-org,imogen,rees,5,ewing street,austral farm,diggers rest,4034,qld,19160829,9643284 +rec-4732-org,robert,tiller,14,parfitt crescent,mariner views,ringwood,2540,wa,19590714,1579290 +rec-3439-org,zack,novak,23,burara crescent,poppa downs,,4311,sa,19591026,2536498 +rec-4312-org,imogen,alderson,,merriman crescent,,kinross,2528,nsw,19041128,2621570 +rec-2466-org,amelia,millar,2,coglin place,hmas cerberus,burrum heads,4157,vic,19361218,5479529 +rec-1955-org,tanyshah,jolly,462,finnerty place,belvedere,alice springs,3167,nsw,19861204,2562045 +rec-3296-org,isaac,white,15,jarman place,sherwood,o'sullivan beach,2303,nsw,19460105,6983162 +rec-3012-org,hannah,witkin,32,mcinnes street,,lewiston,3134,sa,19690707,2339019 +rec-1465-org,kasey,jolly,1946,bettington circuit,mater professional centre,whitton,7140,nsw,19450319,8287398 +rec-249-org,lachlan,shepherd,1,grainger circuit,willandra,adaminaby,7250,nsw,19080122,3139543 +rec-4142-org,samantha,bellon,262,rosenthal street,anzac house (cnr archer s street,beaconsfield upper,3099,vic,19661212,1850361 +rec-3152-org,ethan,reuter,55,rivers street,haven caravn park,balcolyn,4751,nsw,19391123,3818774 +rec-1664-org,annabel,farndell,28,mowle place,don ray,st james,2257,qld,19561214,7860148 +rec-3002-org,charlie,cure,44,eugenia street,marlin cove,potts point,3031,vic,19290418,7251588 +rec-4338-org,alexandra,hyland,34,bimbiang crescent,wandearah,woy woy,3148,nsw,19381024,7191959 +rec-4826-org,jock,loukes,13,phillipson crescent,mount tongbong,tallong,2099,sa,19220113,2561584 +rec-1890-org,james,laverty,8,hovea street,mosman park,somerton park,2913,nsw,19161031,8889937 +rec-4247-org,dylan,landau,14,togo place,wattandee,whalan,4310,nsw,19771213,3431616 +rec-1-org,isabella,everett,25,pike place,rowethorpe,marsden,2152,nsw,19110816,6653129 +rec-4169-org,luke,dixon,14,,roskhill,barmera,6027,vic,19710422,8114472 +rec-3027-org,danielle,moody,21,owen crescent,redlands,burwood east,4701,nsw,19850616,8727753 +rec-4192-org,jack,couzens,33,macgregor street,,hastings,4506,vic,19481027,8436523 +rec-3487-org,emiily,white,26,marr street,grangemouth,lower templestowe,3161,vic,19290127,4621716 +rec-4810-org,kyle,miles,10,michell street,tallinga park,hinchinbrook,2575,tas,19160202,6888097 +rec-491-org,courtney,petersen,9,abercrombie circuit,myross,canterbury,2200,vic,19331227,9627876 +rec-919-org,liam,kayvas,61,biffin street,,blacktown,2221,nsw,19970528,6098354 +rec-169-org,nicola,leonardi,22,port arthur street,crown chambers,ryde,2299,nsw,19170219,3568632 +rec-4790-org,pearson,ryan,38,leven street,pyramid caravn park,bulimba,2251,qld,19010120,7889345 +rec-2594-org,ellie,green,3,walker crescent,nanum,mirboo north,6056,sa,19080611,5986644 +rec-1401-org,dylan,compton,40,neville place,eagle crest,st albans,6285,wa,19600602,3323170 +rec-4796-org,mollie,berry,51,perry drive,beulah estate,,3043,act,19520323,8496716 +rec-25-org,joel,campbell,16,savige street,glenmore,arana hills,3152,nsw,19880824,5412397 +rec-3699-org,julia,velzeboer,796,ewart street,,hackham west,5045,tas,19930613,2222450 +rec-3131-org,samuel,crofts,613,banjine street,kurrajong vlge,penguin,2230,qld,19410531,4467228 +rec-1747-org,annabelle,,6,dethridge street,the castle,oakville,2526,vic,19350712,1214735 +rec-2923-org,matthew,carbone,7,carr crescent,bexley,matraville,2452,nsw,19801216,8840510 +rec-3284-org,hayley,stephenson,8,allawah flats,john flynn medical centre,willetton,3021,qld,19580408,5609345 +rec-4457-org,charlotte,hathaway,5,hartung crescent,anzac house (cnr archer s street,broken hill,6060,qld,19740418,2652077 +rec-1492-org,macormack,campbell,21,shipard place,demountable bldg,brighton,2546,qld,19640101,3116298 +rec-681-org,mikhayla,dennes,8,eggleston crescent,greenways,bundaberg,5158,qld,19280616,8579616 +rec-4153-org,jack,noble,60,marrawah street,trewilga,bondi junction,2031,qld,19960409,3790542 +rec-3242-org,jordan,godfrey,19,bettington circuit,raycroft,merricks north,2229,nsw,19380817,1480851 +rec-4520-org,aliza,lloydd-wright,42,port jackson circuit,grnny flt,brisbane,3078,qld,19800509,1628855 +rec-4686-org,amber,dudley,14,pethebridge street,lorrachael park,cowra,6054,qld,19050703,5970471 +rec-1441-org,harry,blake,36,cowlishaw street,sommerset park,kahibah,3073,qld,19521004,2348791 +rec-4193-org,jasmyn,white,1,clemenger street,ningana retirement,bomaderry,0810,nsw,19210402,3207379 +rec-2911-org,james,,2,frome street,diacos caravn prk,sylvania,5203,vic,,2532680 +rec-1114-org,max,stanley,20,whitford place,,manly vale,3095,nsw,19870211,8658470 +rec-1350-org,james,reid,30,snodgrass crescent,diablo,belmont,2261,qld,19790129,2073967 +rec-868-org,lewis,hursey,6,mawson drive,yengola,,4221,vic,19080210,6791213 +rec-1793-org,,della-verde,113,rivett street,glen eden,figtree,2606,vic,19010217,8895395 +rec-4016-org,emiily,hingston,15,paul coe crescent,hawkesbury road,mooroolbark,2565,sa,19711219,6897463 +rec-4973-org,jesse,sarnyai,67,sandover circuit,morris towers,ballarat,2071,qld,19350511,7047460 +rec-4116-org,angelina,wheatley,65,slessor crescent,kalga,batemans bay,6014,wa,19380508,5827434 +rec-3209-org,catherine,david,109,ijong street,nedlyn,mallacoota,2316,qld,19620212,1973270 +rec-3059-org,william,webb,,lambell close,whispering pines,sorell,7322,qld,19131101,2839312 +rec-3102-org,jake,tweedie,12,flinders way,guest vlge,texas,2022,vic,19460308,5178030 +rec-2695-org,angelica,domkus,9,stanfield close,bowser,modbury heights,2232,qld,19690820,8976049 +rec-4233-org,joshua,dixon,60,croton street,ethnam farm,surrey hills,2617,nsw,19481014,5540614 +rec-1121-org,jack,raward,125,eaves street,berkeley vlge,ridgeway,6233,act,19800919,7286272 +rec-4603-org,lilly,sorn,4,herschell circuit,wongon,box hill south,2913,sa,19441009,9287185 +rec-3427-org,jackson,herbert,15,gooreen street,ripple brook station,highett,4870,vic,19170311,2630363 +rec-2793-org,braiden,parr,15,raiwalla court,st francis village,kirwan,2444,vic,19960327,7031748 +rec-522-org,finn,hoang,86,fremantle drive,rathdangan,boulder,2099,vic,19101022,2016540 +rec-879-org,samantha,barre,14,gouger street,cedar bay,balwyn north,2150,wa,19640121,2801474 +rec-38-org,aiden,thorpe,45,chauvel circle,eureka,rowville,2767,nsw,19270407,6959840 +rec-3800-org,catherine,gawthrop,16,westbury circuit,black snake creek,arundel,3162,qld,19151003,3517894 +rec-1751-org,isabella,block,34,petterd street,westella,st albans,6149,nsw,19111028,2274401 +rec-196-org,taylah,polak,17,majura avenue,palm lake resort,waverley,2770,nsw,19330303,3652195 +rec-1334-org,adele,morrison,3,woollum street,riverside professional centre (cnr banks,ormond,6059,wa,19101205,7729842 +rec-3017-org,joshua,carmody,19,shakespeare crescent,kellhaven,edensor park,3250,qld,19050227,6686589 +rec-3151-org,harry,gully,81,templeton street,navan park,toowong,6023,vic,19450926,4903149 +rec-599-org,joshua,fitzpatrick,10,groveland crescent,toolebewong farm,carrum,3012,vic,19390806,2933121 +rec-288-org,georgia,browne,19,arthur circle,aminya hmes,murrabit,2010,vic,19960923,9940324 +rec-4717-org,georgia,demetriou,17,canberra avenue,glen brae,ballina,3871,nsw,19200828,1391870 +rec-3740-org,zane,campbell,3,mather street,orana gardens retirement village,dickson,2357,wa,19950219,3468552 +rec-541-org,monique,green,330,ashcroft crescent,clapham farms,mount beauty,5355,wa,19181031,8543795 +rec-404-org,connor,petrillo,46,roebuck street,oakdale,boronia heights,7051,vic,19400425,8000924 +rec-1286-org,jasmine,ryan,10,piddington street,,sunshine beach,2108,nsw,19621124,4721073 +rec-2106-org,molly,hannagan,15,pickworth street,the stockyards,ballarat,6027,nsw,19241115,9178151 +rec-1556-org,kayden,hochuli,15,william webb drive,tamwell centre,wangaratta,2293,nsw,19891108,2978402 +rec-2676-org,jack,carbone,22,echo place,folscoit,loganholme,2749,wa,19400114,1449566 +rec-2509-org,joshua,browne,28,paul coe crescent,the pinnacle,williamstown,2261,vic,19091031,4631516 +rec-3486-org,jake,clarke,5,cutlack street,grandview,ashfield,3724,qld,19480526,7030512 +rec-3397-org,indiana,goode,4,galibal street,antanoff' south,east maitland,3183,vic,19420313,5648189 +rec-3857-org,ambrosia,samplton,51,moorehead place,merrydale,goodwood,4701,sa,19400426,1298044 +rec-3043-org,jasmine,rundle,1,elkedra close,clairemont,maryborough,5018,nsw,19231231,9749288 +rec-4835-org,tristan,green,4,solly place,leisure living vlge,booragul,3356,vic,19640221,9034172 +rec-1549-org,william,portors,11,donnelly road,medical centre,murray bridge,2125,nsw,19321223,1315964 +rec-3701-org,jenna,burleigh,59,flora place,glenfine station,chisholm,3231,wa,19151113,9906150 +rec-3667-org,alicia,lenartowicz,47,jane price crescent,kildrummie,cloverdale,3065,vic,19291029,2790792 +rec-1871-org,thomas,webb,7,scottsdale street,locn 3439,brighton,6052,vic,19990815,9760969 +rec-1364-org,jack,fitzpatrick,16,norman street,lort heights,scarborough,2527,,19190814,5911934 +rec-938-org,aidan,bradshaw,56,carr crescent,coolac hotel,lilydale,2176,qld,19380606,6853689 +rec-4859-org,kailey,stubbs,94,house circuit,moreton island,gwynneville,4551,qld,19230318,1819847 +rec-1800-org,emiily,maida,27,beaney street,blue gum park,padstow,3340,qld,19790818,7320684 +rec-3122-org,lilly,millar,,castlereagh crescent,berkeley vlge,orchard hills,2285,qld,19350722,6991931 +rec-940-org,zachary,brain,31,cornish place,the meadows,whitfield,2675,vic,19120327,3343445 +rec-1657-org,jayden,gazzola,23,temperley street,star court arcade,dorrigo,2035,qld,19560809,7207945 +rec-100-org,hayden,stapley,38,tindale street,villa 2,cromer heights,4125,vic,,4620080 +rec-2465-org,emiily,campbell,13,beazley crescent,cameroo,leichhardt,2759,qld,19250103,2816217 +rec-3717-org,tyler,siviour,1,ina gregory circuit,oivi,blakeview,3630,qld,19030131,6849394 +rec-3839-org,kimberly,coleman,53,abbott street,willow dene,tarragindi,3122,qld,19570828,8790959 +rec-1978-org,emiily,millar,3,river street,canberra hse,nunawading,3340,vic,19380318,2340041 +rec-880-org,bryce,morrison,1,clavert place,rowethorpe,parramatta park,3214,nsw,19080915,8125144 +rec-731-org,robert,etherington,23,caley crescent,locn 217,emerald,2250,vic,19140926,3623767 +rec-1427-org,brigette,rankine,47,chewings street,gostwyck,west lakes,2229,qld,19750725,5214389 +rec-4527-org,april,nguyen,7,,mungrup stud,branxton,2018,qld,19210113,1634109 +rec-3647-org,natalia,gilles,32,rapanea street,locn 3439,alice springs,4121,qld,19520330,2026502 +rec-1469-org,tristan,mckinnell,125,lumholtz place,norillee,bayonet head,3939,tas,19730618,7140664 +rec-3588-org,kydan,siviour,18,galibal street,the willows,,2327,nsw,19830421,8231850 +rec-1445-org,paige,webb,,arthaldo court,stoney creek,mount hutton,5023,vic,19341104,6388140 +rec-3971-org,emiily,kutschki,1,ebden street,colleton,elwood,2425,nsw,19451004,3187789 +rec-3831-org,katie,kerslake,5,were street,shopping centre,narre warren north,3977,vic,19591030,1600754 +rec-3408-org,caleb,bersable,13,parkhill street,myola street,mount pleasant,7248,tas,19510311,5036866 +rec-546-org,adam,hingston,249,jacka crescent,upper ross medical centre,kotara,2195,nsw,19980612,4962368 +rec-3665-org,harvey,webb,7,lindsay street,dovers flat,brighton,3139,nsw,19091228,6664660 +rec-41-org,lucy,drought,1,solander place,janefield,moonah west,4879,vic,19230101,7649261 +rec-1945-org,hana,dudley,16,lochee place,portland house,rose bay,3085,nsw,19590211,3088000 +rec-1495-org,lachlan,cicconi,17,waite street,,loftus,3108,vic,19200324,1514534 +rec-4541-org,channing,richardon,8,de graaff street,wattle place,tuart hill,4551,nsw,19840528,8184905 +rec-4863-org,jaime,whisson,,davenport street,,joondanna,6062,qld,19140828,3039182 +rec-1540-org,isabelle,thorpe,20,rischbieth crescent,north star resort,ross creek,2444,nsw,19720731,6747384 +rec-2714-org,taylor,,17,kerkeri close,,south perth,4650,nt,19740805,4419884 +rec-72-org,keira,lowe,15,morant circuit,wilding,warburton,4061,qld,19900523,4044906 +rec-3084-org,kaitlyn,dreckow,17,currie crescent,gumview,regents park,2166,vic,19230224,6671690 +rec-536-org,aleisha,lowe,9,cavanaugh street,koobeja,mulgrave east,2445,wa,19731203,3335374 +rec-4892-org,joel,warneke,10,walsh place,corra-lynn,carrick,2529,nsw,19160910,4818906 +rec-3434-org,alex,clarke,12,fiveash street,emerald garden,homebush,2321,nsw,19840627,7280280 +rec-4752-org,phoebe,millar,31,rayment place,concept,morwell,4064,qld,19230111,6425281 +rec-746-org,sophie,dakin,11,correa street,upstairs flat,beachlands,5241,sa,19760414,2342666 +rec-865-org,abbey,paine,55,meehan garden,braeburn,murray bridge,4390,qld,19080127,3792626 +rec-4552-org,sophie,mason,22,sturgess place,acadia,pacific paradise,3215,nsw,19790301,2531438 +rec-3266-org,ashlie,vavic,62,blamey crescent,paling south,kyogle,3170,wa,19410903,5394712 +rec-4033-org,andrew,iovino,21,seddon place,civic centre,millers point,2763,nsw,19560823,3865428 +rec-651-org,nicholas,hoyland,45,shirlow place,jewells medical centre,wantirna,5049,vic,19200610,4052512 +rec-706-org,talia,dhara,81,kirkham place,lochenfels,bidwill,4160,wa,19700715,9048094 +rec-3655-org,samantha,paterson,8,kellick place,berri cottage hmes,belrose,6030,tas,19460814,7611475 +rec-2442-org,michael,webb,22,karrugang circuit,brentwood village,bokarina,2280,nsw,19571020,3226586 +rec-4651-org,dylan,bullock,33,kingsmill street,legacy vlge,duncraig,3126,vic,19130412,6578982 +rec-4706-org,aidyn,eisner,60,melrose drive,stoney creek,shelley,6063,sa,19101228,6588394 +rec-2121-org,sophie,masolatti,67,lyndon street,locn 217,wynnum west,2022,sa,19320713,4414033 +rec-2965-org,tiarna,harrington,1,crisp circuit,magpie downs,mannum,5264,nsw,19060622,1436628 +rec-4064-org,elizabeth,asche,2,cochrane crescent,st helens pastoral co,boyne island,6149,vic,19260316,8036732 +rec-728-org,olivia,iacopetta,45,arnot place,windellama est,point turton,4556,qld,19740702,5166554 +rec-3711-org,abii,hedaux,26,sparkes close,willera,bribie island,5322,sa,19390824,1171524 +rec-3752-org,logan,green,19,langdon avenue,villa 2,malvern east,3183,sa,19060101,8619374 +rec-2519-org,jenna,goode,49,hedland circuit,kela,kingaroy,3156,nsw,19920828,4224901 +rec-2584-org,juliana,dingo,2,lance hill avenue,rosemount,whitfield,4207,qld,19120203,3093917 +rec-3288-org,harry,grosser,30,chambers street,lake road,albion park,4560,nsw,19420607,7537775 +rec-3566-org,michael,ryan,114,hopetoun circuit,oakdene,sussex inlet,3020,qld,19130121,4530596 +rec-2146-org,luke,barisic,4,macarthur place,kurrajong,windsor,5345,nsw,19510612,6325283 +rec-357-org,chelsea,blackwell,37,grounds crescent,c/o post office,emerald,4210,sa,19390203,6074956 +rec-4045-org,gemma,coulson,22,pickworth street,berragoon,beenleigh,2192,sa,19220905,2163031 +rec-3726-org,keeley,slape,10,arthaldo court,glenore grove,kogarah,6012,nsw,19301222,9981980 +rec-1252-org,andrew,matthews,14,dexter street,caprice,nowra,6306,qld,19340330,7762803 +rec-2195-org,samuel,scamoni,56,daly street,bradshaw crt kirkbrae village,wahroonga,4020,nsw,19740814,6876315 +rec-4888-org,caitlyn,pallot,149,pine island road,nuffield village,highton,2792,nsw,19660115,3051696 +rec-3277-org,yasmin,green,12,diggles street,st john of god hospital,rushworth,5280,nsw,19750129,3139028 +rec-4912-org,caresse,milburn,41,tyson street,mannibadar,salisbury plain,3860,qld,19380920,3636635 +rec-3646-org,dante,lowe,16,light street,tullatoola,kingsthorpe,2122,nsw,19970128,3816506 +rec-1509-org,ben,white,466,louis loder street,parry hse,wakeley,3796,qld,19670921,9376814 +rec-4450-org,keegan,berry,28,hattersley court,gundamain,corrimal east,3073,qld,19230913,8103633 +rec-3676-org,jeremy,le messurier,20,daly place,emerald agrigultural college,san remo,4810,tas,19070627,7041684 +rec-4026-org,blake,smithson,31,cavanaugh street,holmleigh,canley vale,4170,wa,19550815,2675546 +rec-3438-org,olivia,mcneill,1,alberga street,gulmarrad street,lue,6107,nsw,19100419,6664512 +rec-4216-org,lauren,harrington,17,leibnitz place,rosetta village,granville,6066,vic,19550719,2207203 +rec-1188-org,luke,hyrycz,12,mclachlan crescent,pines drive,burwood,4122,sa,19670909,2186299 +rec-4526-org,emiily,bramble,7,collyburl crescent,arcadia,stratford,5087,vic,19290305,1960201 +rec-4983-org,hayley,tu,5,holland street,manresa,ventnor,5039,qld,19571024,3333835 +rec-4208-org,maya,bibby,40,monaro crescent,learning earth farm,deer park,3148,qld,19720418,1185491 +rec-1386-org,hayley,carmody,5,duigan street,aberglasslyn cottage,emerald,2321,act,19611012,1756595 +rec-304-org,zoe,wastell,530,mount vernon drive,bandera,burwood,3350,vic,19981215,6868962 +rec-3652-org,michael,pestka,27,fisken crescent,tabbagong,seven hills,3204,nsw,19610803,4973970 +rec-964-org,sean,singleton,41,clisby close,rockdan,toowoomba,4055,vic,19150122,7148269 +rec-2042-org,hannah,insley,4,wanganeen avenue,plumpton park,drysdale,3199,vic,19921024,3031015 +rec-1202-org,zachary,dixon,18,couchman crescent,yarrimbah,wantirna,2132,vic,19400312,6746706 +rec-3508-org,jacob,campain,7,logan street,bimbadoon,toowoomba,4551,qld,19520416,1591935 +rec-2551-org,ned,ryan,3,carpenter close,burrawong park,cowell,2010,vic,19020623,1816092 +rec-4629-org,tiarna,burghof,1,,delmar,keysborough,2550,vic,19911125,8808422 +rec-819-org,jessica,bastiaans,130,beazley crescent,sun valley caravan park,ingleburn,3028,qld,19270912,7965000 +rec-813-org,tanar,huxley,,ashcroft crescent,kilfeacle,bray park,2046,vic,19700512,5171988 +rec-3783-org,alannah,newport,7,wakefield avenue,glenmore,moree,4662,qld,19401219,4895884 +rec-4263-org,samantha,crouch,,crisp circuit,medical centre,roselands,3199,nsw,19280914,9016486 +rec-1221-org,kailey,herbert,40,popplewell place,rp 24089,wahroonga,7470,vic,19381017,7131960 +rec-1642-org,erin,krollig,68,wells road,rosehill,auburn,5068,sa,19421210,5690708 +rec-1740-org,oliver,beattie,68,brigden crescent,mortlach,matraville,6164,vic,19030824,4461623 +rec-3138-org,jacob,delfos,61,morgan crescent,valicare,geurie,4557,act,19510208,4071052 +rec-4422-org,,ryan,20,ashburton circuit,wilderness,cressy,2580,vic,19890211,3864187 +rec-2914-org,juliana,white,39,osburn drive,kilfenora,st kilda east,6701,vic,19171013,3450613 +rec-4000-org,jasper,morrish,6,mirrool street,bristin,mosman,2745,nsw,19640228,1807750 +rec-3871-org,jessica,kranz,,brunton street,the mews royal hotel bldg,norwood,5159,sa,19880226,7412923 +rec-1981-org,william,ryan,1,fortitude street,hd of solomon,atherton,2200,qld,19520613,8994180 +rec-778-org,gianni,jolly,38,glencross street,locn 10045,booval,2260,wa,19740903,3082635 +rec-3504-org,ethan,mccombe,624,mcnamara street,copely,tailem bend,4740,wa,19020126,1088335 +rec-1663-org,jaden,zepina,23,hawkesbury crescent,mayflower retrmnt vlge,narellan,6053,tas,19030610,4672007 +rec-1044-org,riley,lamprey,22,embley street,,hinchinbrook,3199,vic,19851029,8710851 +rec-1108-org,lachlan,murton,191,barraclough crescent,medcl cntr (cnr queen s street,east hills,2770,nsw,19770527,2068877 +rec-2253-org,blake,matthews,40,perrin circuit,broadwater caravn park,kedron,2466,vic,19670914,1826915 +rec-2424-org,sam,reeh,275,forbes street,,alligator creek,2167,wa,19060718,3497084 +rec-664-org,tyron,mahon,45,albermarle place,ulinga,colo vale,7250,nsw,19470129,8336319 +rec-2239-org,makenzi,weller,31,copland drive,gwandalan,erskine,4214,wa,19500810,1011936 +rec-1230-org,kate,tantschev,99,knox street,fronda,buronga,5158,qld,19870422,6536232 +rec-1050-org,nikki,neik,180,balfour crescent,brentwood village,charlestown,2228,wa,19840720,7106885 +rec-423-org,william,corrie,17,degraves crescent,sec 1,parkinson,4741,nsw,19610614,5150424 +rec-4449-org,olivia,boyle,37,chauncy crescent,cygnet river schoolhouse,plumpton,2460,nsw,19581017,8738461 +rec-1201-org,jayden,blake,3,kemsley place,mlc centre,kariong,2210,qld,19020112,7106228 +rec-875-org,danielle,tomasevic,18,amangu street,fronda,kedron,2380,nsw,19270622,9306292 +rec-1499-org,emiily,witthoeft,,galmarra street,villa 5,kurri kurri,2065,nsw,19421209,5224776 +rec-3802-org,emiily,de michele,23,lawrence crescent,manila,mount alford,2577,nsw,19530522,7400612 +rec-1457-org,robert,waller,4,cutlack street,glenview,wellard,3000,vic,19891004,4754283 +rec-4408-org,aidan,bishop,36,mcintyre street,unt 2,sidmouth,3011,nsw,19490620,1383389 +rec-3972-org,charlotte,mason,16,ratcliffe crescent,baroona,hackham,5073,vic,19060923,6430306 +rec-2341-org,kane,webb,23,majura avenue,lyndan,childers,2155,wa,19311112,6223324 +rec-1378-org,liam,cowle,132,burbidge crescent,valicare,pomborneit,3824,nsw,19801112,5015237 +rec-3228-org,harrison,stirland-mitchell,176,badimara street,wirreanda vlge,port augusta,2196,qld,19040106,3551585 +rec-3852-org,talia,brooker,30,bellchambers crescent,rowethorpe,hawthorn,2033,sa,19561107,4841722 +rec-3229-org,lily,absenger,193,brinsmead street,morrells park,ryde,5073,qld,19091001,3481813 +rec-2746-org,jarod,morrison,13,broadsmith street,spylaw farm,caulfield,3614,wa,19201230,3314025 +rec-4105-org,jake,vigneswaran,24,franklin street,westside,geelong west,4114,vic,19700129,2559983 +rec-3295-org,nathan,ottens,1625,sanford place,howie circuit,little mountain,2448,nsw,19511207,6076799 +rec-734-org,scott,hoggan,6,zox circuit,strageath,northmead,5031,qld,19781105,2063442 +rec-1833-org,william,matthews,154,victoria street,,hughes,2134,wa,19940831,2176052 +rec-3204-org,,colpo,2,trigg place,southern cross,clarinda,6018,vic,19280716,4186527 +rec-4787-org,vanessa,morrison,16,meehan garden,eventide homes,condell park,5113,nsw,19951015,6047960 +rec-3593-org,marleigh,sideris,42,henry melville crescent,bocking,morpeth,3039,sa,19251227,6987405 +rec-2481-org,levi,carraill,48,griffiths street,rosehill,quilpie,5108,nsw,19071031,8145441 +rec-821-org,chloe,condo,36,yabsley place,munmurra park,mackay north,5082,nsw,19170115,7153959 +rec-4211-org,daniel,mason,9,derrington crescent,el pedro caravan park,sunnybank,4305,vic,19500705,5525378 +rec-4873-org,sam,blake,72,stockdale street,yarrandale moonee,sandgate,2262,nsw,19511223,4671131 +rec-3576-org,damien,nguyen,107,jerrabomberra avenue,,noble park,2031,wa,19670919,8598019 +rec-719-org,madison,penberthy,12,dunbar street,wal 53581,villawood,4621,nsw,19931005,4607576 +rec-2150-org,charles,tkachuk,1,hannan crescent,nyngan,elwood,5068,nsw,19620625,9782270 +rec-3227-org,niamh,kingsley,36,badimara street,warrowitue,eastwood,2220,vic,19060707,5893180 +rec-1658-org,leah,averis,27,macrobertson street,brentwood vlge,mona vale,2076,nsw,19150220,1890261 +rec-894-org,,clarke,133,amagula avenue,fourmile,coodanup,2117,nsw,19280117,4243188 +rec-4031-org,karissa,cannell,30,arrietta close,pindara medical centre,harris park,3153,nsw,19600508,7035862 +rec-3578-org,jasmine,mariager,21,medley street,pine hill,evans head,4020,nsw,19180202,1051531 +rec-3129-org,ava,ahier,8,crowder circuit,peridon vlge,long jetty,4871,nsw,19270309,6824379 +rec-2243-org,ned,herbert,6,vonwiller crescent,,albury east,3163,nsw,19310822,6246038 +rec-2224-org,stephanie,vorrasi,10,giblin street,pine hill,flagstaff hill,6285,wa,19420803,6155719 +rec-4694-org,hayden,richmond,59,louis loder street,wattagan,craigmore,2192,nsw,19670619,1098844 +rec-701-org,mitchell,clarke,57,hurley street,weemilah,tallebudgera,4021,vic,19010403,4822857 +rec-2651-org,william,buhagiar,127,mataranka street,retirement village,mundingburra,5211,nsw,19350212,5998949 +rec-3350-org,jacqueline,grillett,10,wandoo street,braemore,tuart hill,2031,vic,19241218,3043851 +rec-4513-org,caitlin,harjanta,5,darling street,,wantirna,4404,act,19340210,4039838 +rec-3727-org,hugo,mccarthy,154,chauvel street,ohio station,port fairy,3840,nsw,19550609,5250727 +rec-702-org,barnaby,fleet,4,martley circuit,peak view,ascot vale,3930,sa,19360907,9383837 +rec-173-org,andrew,renfrey,23,woolner circuit,mindaree,salisbury,3844,nsw,19490115,9309636 +rec-4632-org,ewan,stephenson,106,bowden crescent,kinglake central,kings park,6244,nsw,19480830,4749458 +rec-1901-org,shelby,white,23,britten-jones drive,finis river,brighton,5159,vic,19090729,3656655 +rec-1413-org,brielle,spears,8,tunney crescent,hd blanche sec 28,rosslyn park,3350,wa,19890201,3140493 +rec-4165-org,emma,araujo,225,nepean place,kinross,lake cathie,2032,vic,19140124,5500784 +rec-3087-org,talena,blackwell,,onkaparinga crescent,,elsternwick,4702,wa,19230602,5796259 +rec-180-org,thomas,white,42,cochrane crescent,balmoral garden,sefton,3136,qld,19800413,1153372 +rec-3821-org,chloe,pennell,3,medley street,noolabi,ringwood north,5092,vic,19530710,1249545 +rec-801-org,chelsea,mccarthy,17,la perouse street,arcadia,ballarat,4007,nsw,19921130,4620249 +rec-2374-org,,nguyen,9,chaseling street,,burwood east,2122,qld,19400119,4833200 +rec-1701-org,georgia,laria,1,oxley street,townview,allambie,5127,qld,19170818,2152599 +rec-3746-org,marleigh,paterson,28,canopus crescent,kirklands,devonport,2800,vic,19820824,7472468 +rec-3086-org,blakeston,lock,59,bonnor close,redlands,mentone,7140,wa,19010422,6335558 +rec-1296-org,joshua,george,24,rose scott circuit,ponderossa,goonellabah,2464,nsw,19250202,6419725 +rec-835-org,lily,egan,526,louis loder street,,alfords point,3031,sa,19610514,2519145 +rec-455-org,mia,shepherd,7,churchill way,greenslopes,seven hills,2449,vic,19760830,3991319 +rec-4477-org,blake,ryan,5,,town & country caravn park,bundaberg north,2484,nsw,19850601,6826301 +rec-2334-org,jasmyn,lowe,48,toohey place,grand central,bicton,3058,nsw,19320918,1430128 +rec-2790-org,carla,gasparin,122,fitchett street,marx hill street,burrum heads,3022,nsw,19511229,7746397 +rec-2050-org,ella,blake,14,mckinlay street,cape hawke hosptl medcl centre,wendouree,2060,sa,19770427,9846556 +rec-4006-org,mackenzi,dogg,30,paisley street,,berwick,2259,vic,19710709,9203314 +rec-4890-org,georgia,gilkes,16,eagle circuit,hornsbie,wantirna,2251,wa,19241007,7326444 +rec-1675-org,brigette,marlow,56,binya place,toowoomba,frankston,2263,qld,19981021,6603838 +rec-2372-org,nicholas,colantoni,2,illingworth street,mallee downs,st albans,2518,vic,19651019,4914391 +rec-3698-org,michael,bulmeister,4,lewis luxton avenue,kiola,melton south,3101,nsw,19720805,7224448 +rec-305-org,timothy,elphick,28,waratah street,main beach medical centre,maida vale,6069,vic,19391124,3887226 +rec-190-org,,alias,24,elkington street,pangani,isle of capri,2145,sa,19650429,8261472 +rec-1058-org,juliana,wilde,20,westall place,portland house,eden,4880,wa,19381207,3048642 +rec-707-org,emma,webb,16,manning street,craiglee station,montmorency,6155,nsw,19560630,6562713 +rec-319-org,juliana,campbell,18,nicholls place,illuka park,ridleyton,6720,nsw,19540308,2165254 +rec-3365-org,mackenzie,rendulic,7,auburn street,lonesome dove,blackbutt,4271,nsw,19700812,5371450 +rec-1869-org,anari,burrill,41,burrinjuck crescent,craiglea,east fremantle,2537,wa,19671115,7891299 +rec-4195-org,katelin,campbell,16,sid barnes crescent,,forestdale,2450,wa,19240716,7296237 +rec-735-org,mark,nicolle,20,florence taylor street,greenacres caravan park,cloverdale,5090,wa,19780420,5862681 +rec-1921-org,michael,degasperi,43,rushbrook circuit,lyndale,hamilton north,2228,vic,19951012,2192076 +rec-3568-org,wilson,coleman,35,weavers crescent,knmre street,kelmscott,4805,sa,19880715,5954966 +rec-3158-org,michelle,dearing,183,riordan street,dunbar heights,coomera,3219,wa,19000323,4082175 +rec-4313-org,lauren,mcveigh,,bremer street,werribee plaza,cranbourne north,2039,act,19591216,4278721 +rec-3465-org,jaggah,ryan,105,hurley street,,kurri kurri,3170,tas,19230112,4660081 +rec-153-org,jake,reid,25,agnew street,sunnyview,toowoomba,3450,vic,19230613,2239660 +rec-1021-org,nathan,rees,5,lucy gullett circuit,tintagel,pascoe vale south,4112,wa,19210220,6141854 +rec-1621-org,alexandra,hyland,20,brassey street,unt 3,bundaberg,3047,qld,19030202,9741543 +rec-1084-org,alexander,ryan,19,grayson street,medical centre,beecroft,5343,nsw,19720528,7898665 +rec-4187-org,matisse,mccaffrey,164,throssell street,argyle,woy woy,6012,vic,19961123,3108714 +rec-1097-org,joshua,clarke,4,ragless circuit,,sylvania,3136,vic,19110818,5574844 +rec-3601-org,alexandra,newberry,69,earle place,broome vacation village,wallsend,3749,nsw,19691006,5799594 +rec-4945-org,catherine,crouch,23,jindivik place,shiloah,mosman,3953,nsw,19890926,4741965 +rec-608-org,mitchell,white,72,lambrigg street,kelgoola,broadbeach waters,3150,vic,19620216,9731855 +rec-2322-org,sophie,morrison,11,waller crescent,hmas cerberus,loganlea,3175,vic,19420302,7721195 +rec-4832-org,carlin,flannery,67,namadgi circuit,regal oaks retirement vlge,swan hill,4101,vic,19240419,3896653 +rec-2538-org,lynton,leonavicius,7,mcilwraith close,leitrim,kolora,4405,wa,19511227,8167665 +rec-3521-org,spencer,bates-brownsword,151,pinkerton circuit,tora,smithfield,4860,nsw,19810308,5402648 +rec-3868-org,jassim,rybak,16,newman morris circuit,brookfield,ormond,2281,vic,19840706,8822389 +rec-1925-org,nathan,simmonds,86,aspinall street,southwold,,3556,nsw,19230105,8217104 +rec-3115-org,benjamin,miles,15,totterdell street,poplar bend,acton,6317,qld,19830303,4385595 +rec-2669-org,emiily,roff,5,darwinia terrace,loma,hawthorn,3173,sa,19600518,9178046 +rec-2677-org,alicia,riddei,11,elvire place,swanleigh,allawah,2440,qld,19620629,2718027 +rec-3339-org,katharine,white,10,kirkwood crescent,glenapp,wahroonga,4670,wa,19130608,7824077 +rec-2139-org,emiily,campbell,26,oakwood place,the wedge,bogangar,4214,nsw,19810407,5373209 +rec-2317-org,lydia,heiland,12,roope close,garden est,yass,2454,nsw,19130103,6703072 +rec-2184-org,tahlia,fenwick,6,pandanus street,brentwood vlge,north curl curl,4825,qld,19430604,8360325 +rec-4122-org,tess,battisson,1,wyola place,malsah,west wollongong,2210,nsw,19230918,3152618 +rec-572-org,courtney,white,4,green street,armidale private hospital,launching place,2800,nsw,,6763868 +rec-4662-org,james,jolly,,fihelly street,leumeah,woodville north,2155,vic,19081030,5908468 +rec-508-org,adam,hendricks,10,merv waite street,manacumble,downer,2582,wa,19581007,3204460 +rec-2250-org,cooper,humphreys,1,kulgera street,villa 3,st albans,4413,nsw,19300226,7614633 +rec-2389-org,courtney,weller,35,florence taylor street,flt 61,vermont,4352,vic,19910120,7615385 +rec-1866-org,nathan,campbell,14,la perouse street,st francis room,glengowrie,6148,qld,19060719,2639541 +rec-1351-org,nicholas,jolly,8,piddington street,rosehill,burnside,0872,nsw,19011217,7662074 +rec-4437-org,harry,beattie,91,watson street,yengola,kempsey,2536,nsw,19831227,6262171 +rec-2922-org,jordan,allegretto,22,stacy street,b,bonnyrigg,2069,nsw,19380915,1390998 +rec-3079-org,benjamin,donaldson,34,dunoon street,westwood homestead,st albans,2611,nsw,19331111,2281465 +rec-3458-org,jessica,cadman,102,aronson crescent,lamington national,carlingford,2089,vic,19431126,7278796 +rec-795-org,eboni,,11,de burgh street,tamarama,keiraville,3356,vic,19000607,4335060 +rec-1444-org,thomas,martinovic,24,ivo whitton circuit,the stockyards,greenwith,7307,qld,19801111,4222783 +rec-2266-org,toby,chater,16,holland street,innes est,keysborough,2880,vic,19440624,2828200 +rec-3128-org,jairus,compton,92,huelin circuit,mamaregu,boyne island,2760,wa,19960806,1381082 +rec-2078-org,nikki,green,25,chisholm street,lazy acres,balwyn north,4413,wa,19630816,8182676 +rec-239-org,liam,jolly,10,endeavour street,pinnacles caravn park,mansfield,7310,qld,19931105,2505329 +rec-2340-org,zachary,ban,4,maurice place,cabbage tree,moore,6011,sa,19710105,4571622 +rec-1693-org,cooper,nguyen,,burrinjuck crescent,dawlish,,6059,qld,19700104,2035745 +rec-2972-org,imogen,polmear,102,macedon crescent,rowethorpe,port macquarie,2847,sa,19241217,6794742 +rec-4519-org,macormack,kastrappis,41,preddey way,concept,scarborough,3660,nsw,19171116,8170262 +rec-2592-org,flynn,banham,164,starke street,stonehouse,carlingford,2444,sa,19890221,3189743 +rec-1017-org,roy,paterson,24,gleadow street,st francis vlge,wahroonga,3501,nsw,19641002,2532475 +rec-4063-org,aiden,roche,48,eppalock street,elmwood,port lincoln,4573,wa,19400329,6195026 +rec-1980-org,caitlin,cheel,,herron crescent,glen rock,bligh park,3735,nsw,19640519,3957302 +rec-3254-org,xanthe,hipkiss,33,luke street,,port lincoln,2122,nsw,19890508,5654602 +rec-1198-org,lucas,white,56,hacke place,carlow,prospect,4650,vic,19400902,2640399 +rec-4062-org,kylee,shepherd,6,fitchett street,woodburn pastoral,paralowie,2229,nsw,19420817,7307571 +rec-2205-org,nicole,schmook,3,grounds crescent,alice street,logan reserve,3840,tas,19860822,4490353 +rec-1779-org,brooklyn,white,362,o'loghlen street,mirrimbah,toowoomba south,2259,wa,19410904,7203797 +rec-4463-org,isabella,,576,grimshaw street,brentwood vlge,tara,2099,qld,19440214,5901255 +rec-2174-org,abbey,green,6,aspinall street,rosedale,st albans,3012,vic,19300314,5453075 +rec-1662-org,travis,egan,62,rochford street,shamrock vale,yanco,3241,nsw,19490603,2814414 +rec-752-org,georgia,weidenbach,4,marou place,blueberry,innaloo,4068,vic,19280919,5368200 +rec-1247-org,alannah,santi,125,maribyrnong avenue,,boulder,4207,qld,19341230,2296017 +rec-4647-org,elizabeth,malcolmson,43,gaunson crescent,jormaizee,werrington,2540,wa,19550528,4104314 +rec-910-org,sophie,bradshaw,18,kidston crescent,rowethorpe,geraldton,4069,vic,19380426,2830844 +rec-1696-org,kydan,edson,,lexcen avenue,wirraway,tuart hill,2154,vic,19581231,6695038 +rec-2098-org,cameron,mcgargil,42,jardine street,blythelands,port pirie,2135,qld,19410208,2461277 +rec-1504-org,kailey,gazzola,2,napier close,bandera,sanctuary point,2830,nsw,19340729,5402689 +rec-2337-org,sara,schiansky,40,fullerton crescent,tabbagong,llandilo,3020,nsw,19450822,4913489 +rec-1718-org,christopher,gazzola,10,franks place,citi centre,alice springs,6009,qld,19630524,4662409 +rec-3693-org,ruby,finlay,39,alabaster street,parklands village,aldinga beach,5076,qld,19780302,4984170 +rec-3205-org,michael,mainsbridge,12,cazaly close,earl haven,colac,3199,wa,19110409,9927051 +rec-43-org,sarah,neylon,8,wilkinson street,,guilderton,2481,nsw,19100224,3794258 +rec-530-org,jamie,wojciechowski,13,crofts crescent,rosetta village,meringandan,2095,qld,19241023,7357292 +rec-1200-org,sara,bibrowicz,46,kingscote crescent,rowethorpe,smiths beach,2026,nsw,19120602,4090488 +rec-1944-org,zac,george,7,fitzroy street,keonbyrne,bayswater,2560,nsw,19830315,5417788 +rec-2886-org,,garanggar,28,may maxwell crescent,springetts arcade,forest hill,2324,vic,19921016,1366884 +rec-2883-org,jackson,clarke,1,cargelligo street,summerset,bellevue hill,3835,qld,19571105,7943648 +rec-888-org,caitlin,berry,29,carr crescent,bletchly park,corrimal east,4075,sa,19780804,2225444 +rec-1156-org,jackson,simmonds,4,raymond street,ainslie house,tongala,2166,nsw,19020519,8651617 +rec-826-org,chloe,white,33,gadali crescent,rondayvoo,loganlea,3029,vic,19331024,8293735 +rec-4539-org,isabella,longman,7,eucumbene drive,kooyong,lalor,5157,vic,19460810,4725516 +rec-4294-org,alexandra,melham,21,kingscote crescent,kerry street,elizabeth vale,2663,wa,19911210,5648275 +rec-101-org,dillon,coleman,8,paul coe crescent,clinton caravan park,yarraville,3260,nsw,19531117,1835941 +rec-3213-org,rhiannon,bishop,39,rossarden street,oakdale,clayton,2037,qld,19080513,6284110 +rec-4027-org,kayla,twigg-patterson,3,mcclelland avenue,craigie-lea,ringwood east,2071,nsw,19290118,7885517 +rec-4015-org,lily,poskey,38,moore place,kenbar,lower templestowe,2474,nsw,19210315,8556979 +rec-4099-org,harrison,george,,woronora street,south melbourne market,kangaroo flat,2450,nsw,19370115,3711821 +rec-2259-org,hayley,hanna,240,burhop close,peridon vlge,ryde,2077,nsw,19491020,3697216 +rec-4550-org,anastasia,longman,10,wassell place,glenarthur,coffs harbour,0812,qld,19390813,7175344 +rec-1630-org,amber,manson,370,barada crescent,wiltshire,hawks nest,6070,nsw,19890213,9785319 +rec-1929-org,wilson,sporn,5,barnett close,sherwood,bowral,2008,tas,19311113,3629982 +rec-2273-org,chelsea,tuckwell,48,atherton street,pine hill,invermay,4868,qld,19391105,9172674 +rec-1705-org,alessia,smithson,,shandon place,amarillo,boorowa,6020,vic,19421105,6639770 +rec-292-org,oliver,clarke,84,macrobertson street,white lodge,toowoomba,4077,qld,19180825,5422013 +rec-3575-org,harrison,coulson,119,backler place,,toowoomba,4350,vic,19300517,5222388 +rec-2559-org,emiily,binns,24,howell place,sec 142 hd rounsevell,ryde,2627,wa,19941108,8919080 +rec-3612-org,benjamin,mcclelland,16,brodribb street,villa 18,noble park,6714,vic,19470605,5728937 +rec-79-org,joel,rundle,108,rosebery street,st vincents hospital,dunsborough,2317,nsw,19780403,8984765 +rec-3126-org,jasmine,mcfadden,46,noongale court,rosetta village,marshdale,4215,sa,19760927,6401287 +rec-1688-org,benjamin,lette,34,condamine street,arcadia,silverdale,4670,nsw,19600502,7770680 +rec-4989-org,rosie,dixon,28,chataway crescent,burramunda,penshurst,2558,nsw,19960211,3496771 +rec-34-org,mollie,castellari,5,jackie howe crescent,,ardmona,3976,wa,19760616,1378454 +rec-1341-org,harry,cure,4,sugarloaf circuit,beaudesert caravan park,parkdale,2448,vic,19601222,1947985 +rec-3252-org,,campbell,4,dunbar street,delicate nobby street,cloverdale,2528,vic,19480406,8607518 +rec-844-org,charlotte,crossman,19,collings street,ahc house,botany,6564,nsw,19221220,3932172 +rec-3854-org,natalee,nguyen,11,harbison crescent,riverside professional centre (cnr banks,calista,5043,nsw,19211203,1824456 +rec-3182-org,luke,abrahamson,56,vowles road,deepdale farm,taringa,5330,nsw,19170625,4386896 +rec-2688-org,riley,uyttenhove,2,outtrim avenue,gowrie,crows nest,2260,sa,19571231,1679030 +rec-1361-org,clement,white,4,knox street,bimby vale,campsie,6060,nsw,19960916,8856376 +rec-4508-org,harrison,mcneill,1,geeves court,brannigans,highett,2319,qld,19280108,6287203 +rec-245-org,taylah,meaney,60,lumholtz place,cordelia state,torquay,2282,vic,19470106,1744252 +rec-4853-org,jacqueline,coady,20,borrowdale street,garden creek,nambour,4570,nsw,19220503,6945746 +rec-3448-org,makayla,cochrane,9,tillyard drive,the willows,coffs harbour,5089,nsw,19951205,3164154 +rec-4305-org,yana,noble,76,costello circuit,the manor braeside,bicton,2290,qld,19710327,9357658 +rec-3860-org,alexander,crossman,31,spinifex street,binnawee,texas,3068,sa,,7807999 +rec-3787-org,john-paul,burford,36,jardine street,warrawong,robertson,3044,nsw,19340912,9627130 +rec-3768-org,tara,radulescu,83,carslaw street,croydon,inglewood,2118,nsw,19960701,7082968 +rec-4998-org,alicia,fergus,67,gidabal street,felbrigg,wialki north,2251,sa,19971215,9245698 +rec-3090-org,meggie,george,16,alleyne close,greenlake,lucknow,5267,qld,19111227,1040139 +rec-2144-org,isabella,kelley,9,covington crescent,march rising,east maitland,2343,tas,19090918,2297084 +rec-2066-org,tahlia,wotton,11,darby street,greenacres caravan park,lindfield,2206,nsw,19250907,1825836 +rec-4749-org,jackson,campbell,2,carpenter close,mountview,dungog,3033,qld,19110826,8656075 +rec-3498-org,alysha,maier,2,kerrigan street,craigie-lea,morphettville,3124,qld,19480111,8215736 +rec-4147-org,bethany,webb,3,cullen street,sunning,narellan vale,3630,qld,19431219,4827546 +rec-473-org,amalia,lowe,242,cobbett place,walnut grove estate,mooroolbark,2153,qld,19490507,9275399 +rec-2425-org,jasmin,kammermann,12,edman close,targonga,barcaldine,6028,nsw,19000812,3954979 +rec-1560-org,kane,campbell,8,scarfe close,bega flats,elermore vale,3226,nsw,19281207,3391391 +rec-3622-org,laura,huddy,,maltby circuit,destiny park,moorabbin,3195,tas,19720627,5832871 +rec-3443-org,jake,elphick,26,olympus way,melita,burnett heads,2064,qld,19070201,4724453 +rec-2470-org,henry,dichiera,34,pomeroy street,tower hill,orange,5680,nsw,19000910,7446545 +rec-4071-org,laklynn,white,30,french street,mari-ma farm,eleebana,4655,nsw,19040312,2842344 +rec-4840-org,imogen,pun,12,templestowe avenue,peak view,belconnen,4214,nsw,19400709,4490158 +rec-4093-org,dylan,eglinton,11,nambucca street,woodleigh,arthurton,2870,sa,19660115,8227230 +rec-2801-org,mitchell,ryan,462,badimara street,ainslie house,broken hill,5501,nsw,19580222,8797284 +rec-2270-org,charlotte,valasakis,12,kohlhagen street,gsala view,scarborough,2660,wa,19750220,7975898 +rec-4251-org,cameron,shepherd,91,mckinlay street,pindara medical centre,bonnyrigg,2075,nsw,19690127,6756281 +rec-1937-org,nicholas,wilde,46,renny place,golden ponds,leongatha,4153,vic,19961119,7886527 +rec-2072-org,kelsey,bacskai,7,northbourne avenue,kooyong,como,2541,qld,19700110,3814852 +rec-755-org,deakyn,blake,251,middleton circuit,rowethorpe,avalon beach,5171,nsw,19540831,2780999 +rec-1784-org,bethany,reid,9,totterdell street,kingaroy garden,deniliquin,2800,qld,19080203,5554694 +rec-2665-org,erin,te kawau,5,namatjira drive,glen ayre,magill,2324,qld,19641126,6335645 +rec-2108-org,nicholas,coffey,12,conder street,kangaroo grnd,cranbourne,2762,qld,19530924,2701477 +rec-4436-org,pia,abat,16,tardent street,blue hills,sale,6100,tas,19030803,9804900 +rec-275-org,joshua,berryman,91,summerville crescent,medical centre,mount colah,4221,vic,19070709,6570397 +rec-2373-org,amy,hawes,68,hyne place,kiola,mentone,6022,nsw,19400129,5599177 +rec-854-org,arren,leonardos,106,eggleston crescent,hidden valley estate,east maitland,3220,vic,19171029,8849722 +rec-2835-org,lucy,braithwaite,65,ellerston avenue,marx garden world,munno para west,2750,qld,19580501,6060746 +rec-2455-org,talia,green,130,groom street,killuke,medina,3500,wa,19800109,7656892 +rec-1209-org,courtney,hyland,12,barwon street,sec 1,cobar,2263,vic,19511001,9099158 +rec-122-org,bianca,ryan,67,de little circuit,march rising,westmead,6163,wa,19091028,4864427 +rec-3765-org,sophie,nicolle,93,flinders way,hilltop hostel rowethorpe,upwey,3350,vic,19990623,1307303 +rec-4076-org,dimitri,slavvjevic,5,bellinger circuit,pangani,mount isa,6230,vic,19770927,8191221 +rec-2949-org,daniel,ryan,8,gordon close,blue springs,hamilton,6230,qld,19540105,3698795 +rec-1408-org,kierra,harrington,45,shepherdson place,oakdale,rye,4127,qld,19700127,9648034 +rec-4795-org,michaela,wasley,10,lake place,faringdon village,coombabah,2192,nsw,19560410,5571708 +rec-4415-org,travis,wang,10,hawken street,drayton villas,airlie beach,4121,vic,19810617,5809880 +rec-3684-org,luke,boyle,1525,fawkner street,,roxburgh park,2343,nsw,19701125,2420976 +rec-4996-org,brayden,pragt,24,melba street,villa 3,st ives,5171,nsw,19561029,7716405 +rec-476-org,kyle,armiento,266,jaeger circuit,kookaburra village,springwood,7307,vic,19570728,3494623 +rec-1305-org,robert,hanna,48,,yarrandoo,magill,3036,sa,19490528,6830679 +rec-184-org,tiana,worthington-eyre,24,hassell place,governors resort,corrimal,6112,qld,19171101,3674431 +rec-543-org,eliza,mason,33,schonell circuit,john flynn medical centre,mount warren park,2039,sa,19271018,5422520 +rec-4901-org,annabella,goldsworthy,32,quandong street,,dalby,3219,nsw,19880902,1074106 +rec-762-org,,rees,45,badimara street,easedale lodge,sanctuary point,2257,nsw,19720228,3996047 +rec-483-org,eva,leppard,,kurrama close,casuarina village,port macquarie,5280,nsw,19370728,8035602 +rec-1210-org,amber,kerslake-ling,5,glencross street,lumley,ballarat,4817,sa,19031228,1079968 +rec-4619-org,isabel,godfrey,14,bellchambers crescent,glenumbral,warnbro,2039,sa,19680509,1302707 +rec-4398-org,,camp,58,dowling street,executive arcade,farrer,2519,qld,19460723,5604647 +rec-3662-org,benjamin,yen,43,kambalda crescent,elmwood,findon,3807,nsw,19850706,7843492 +rec-2820-org,millie,neville,38,menzies court,,toowoomba,2066,nsw,19950511,8251642 +rec-656-org,hannah,jolly,89,,palm lake resort,joondalup,3550,nsw,19020625,2585701 +rec-2349-org,marcus,parr,11,hilder street,glenmore,braidwood,4810,vic,19460725,4267000 +rec-4022-org,phoebe,sedgwick,24,hobby place,st francis vlge,cabramatta west,2060,nsw,19470817,3134424 +rec-1780-org,ellen,mitton,58,glencross street,mount marion,orchard hills,4214,nsw,19190501,4549940 +rec-1783-org,samantha,bellamy,123,hawkesbury crescent,bristin,pallara,2756,nsw,19091019,9345240 +rec-705-org,shane,oxenbridge,457,mceachern crescent,illoura glass studio,macquarie fields,6168,sa,19841208,7598821 +rec-3134-org,erin,embrey,31,arabana street,caloundra family medical practice trinit,caves beach,4000,vic,19990704,7556655 +rec-3479-org,makenzie,michelmore,8,marcus clarke street,leitrim,ivanhoe,2198,vic,19081127,5210533 +rec-2679-org,thomas,brain,108,brewster place,geelong grove,eight mile plains,2114,qld,19851127,8873329 +rec-2556-org,seanna,radic,37,morgan crescent,emu hill,mannering park,2207,sa,19850309,6650779 +rec-1865-org,hayley,blake,4,dickson chiropractic dickson chambers,goughs bay,coffs harbour,3079,qld,19391107,1285867 +rec-3187-org,gabriel,tippins,6,kirby place,moranbah,wentworth falls,4655,nsw,19660608,3840632 +rec-2571-org,eleni,bartel,11,maribyrnong avenue,montrose,toowoomba,2063,qld,19491112,4998898 +rec-160-org,emiily,gnesel,,antill street,trewilga,croydon north,2641,nsw,,5249754 +rec-1395-org,grace,okubo,7,reynolds street,corinella,greenacres,0812,nsw,19140315,3936339 +rec-4737-org,sascha,matthews,5,canopus crescent,willalooka,asquith,7250,act,19670719,7320513 +rec-1715-org,holly,drayson,509,schlich street,st francis vlge,bittern,3150,qld,19801205,1349437 +rec-4528-org,jean-claude,ryan,4,gledden street,henry kendall bayside,swan hill,3136,nsw,19150420,2261900 +rec-51-org,ella,blunden,37,freda gibson circuit,croyde,paddington,2770,sa,19401209,3593307 +rec-4494-org,thomas,montalvo,209,trainer court,medical centre,wanniassa,2905,sa,19020302,9993328 +rec-452-org,riley,kelley,8185,edmond close,leisure living vlge,mount stuart,2760,wa,19390207,9887277 +rec-4697-org,alexandra,mcneill,119,maidment place,the sandys,dungog,5075,vic,19080127,2706283 +rec-3941-org,mattheo,crouch,5,crisp circuit,brentwood vlge,hurlstone park,2710,wa,19120531,4393719 +rec-2960-org,joshua,edmeades,10,bonney street,,birkdale,3730,nsw,19350621,1358747 +rec-4334-org,,webb,,degraves crescent,marriott downs,maryborough,6151,nsw,19130715,5325666 +rec-3741-org,rebecca,coulson,31,groote place,rosemount,aldgate,3053,sa,19700209,5885868 +rec-2427-org,ebony,wynne,261,teague street,fleetview,harris park,4350,act,19070922,2766218 +rec-1228-org,liam,maclennan,6,wrixon street,glenmore,highett,5125,vic,19170908,3268350 +rec-1224-org,harry,reid,15,kalgoorlie crescent,aldersyde estate,new town,2077,sa,19460708,5924879 +rec-3748-org,iain,noble,84,rischbieth crescent,the big tree,albany creek,6391,qld,19500616,2205130 +rec-2280-org,hugh,campbell,66,keith street,ocean star villas,beenleigh,6107,vic,19550703,6047972 +rec-2955-org,d'arcy,webb,3,ebenezer street,ravensfield,cressy,2443,wa,19901222,8604852 +rec-968-org,aidan,blake,15,namatjira drive,cooramin,dromana,4074,vic,19270928,4317464 +rec-1301-org,sienna,manskey,90,mckinley circuit,ocean hunter,plympton south,5108,vic,19071112,2774041 +rec-4771-org,kayla,kerkham,29,cobb crescent,beach house,denmark,2318,qld,19130824,4646463 +rec-1660-org,jessica,goode,24,devonport street,gundamain,springwood,6104,qld,19620120,3222738 +rec-268-org,phoenix,mason,19,fawkner street,diablo,,6258,sa,19630713,2078364 +rec-713-org,alison,feeney,13,loban court,the mews royal hotel bldg,barabba,6260,nsw,19280604,1316297 +rec-2283-org,madeleine,nevin,85,carlile street,rocklands,st kilda east,2092,sa,19230620,3536031 +rec-3096-org,keeley,moolenaar,18,tangari street,sec 1,mosman,4680,nsw,19240130,2647421 +rec-3375-org,jayden,rees,41,beaufort retreat,ramano estate locn 1,black rock,5253,qld,19350102,8170572 +rec-430-org,joshua,fogliano,522,hawdon street,francis chambers,bonville,6167,qld,19290927,3505678 +rec-866-org,emiily,stanley,,anthony rolfe street,clarence village,st kilda east,3765,tas,19051127,2491635 +rec-1353-org,irene,alderman,9,tumbleton place,,wahroonga,3226,nsw,19670316,7471765 +rec-1573-org,sam,hage,1,sweet place,woodlands surgery centre,port macquarie,3206,qld,19430116,1799750 +rec-3923-org,kaitlin,egan,28,hayward place,glentryst,geraldton,2074,vic,19410610,3120103 +rec-4827-org,emma,maynard,18,chillagoe street,little springhurst,lower mitcham,4051,vic,19931210,8245281 +rec-1263-org,jacob,ryan,5,wheeler crescent,melrose clinic,coolaroo,3198,nsw,19581209,8497762 +rec-3259-org,laura,newey,6,archibald street,,harris park,3006,wa,19570428,5725917 +rec-1438-org,nicola,orchard,12,mollison street,nelsons lake,cherrybrook,3915,nsw,19530103,1330482 +rec-2136-org,silas,painter,6,parkhill street,glendora,st peters,3338,vic,19280710,4164696 +rec-4887-org,taylor-saige,tiller,27,macdonnell street,tesbury,mooroolbark,2142,qld,19230531,9914740 +rec-2973-org,thomas,brain,22,holmes crescent,anstee court,hackham west,3465,vic,19711119,6218887 +rec-4465-org,lachlan,penno,5,britten-jones drive,,williamstown,3127,vic,19630929,2510563 +rec-2165-org,holly,matthews,5,bingley crescent,strathalynne,beaudesert,6158,nsw,19610114,5757476 +rec-2082-org,chelsea,pontt,91,gellibrand street,shelomith,petersham,2166,vic,19181115,3454949 +rec-374-org,chelsea,ryan,13,myles close,,stonyfell,5159,nsw,19510812,5489594 +rec-889-org,jordan,lock,27,tallara parkway,retirement village,manly vale,7250,vic,19070222,9835720 +rec-2226-org,oscar,bitmead,4,ellerston avenue,glenview,deer park,4020,qld,19191217,5440118 +rec-3057-org,sophie,paine,1,yambina crescent,sefton park,ruse,6210,nsw,19440101,3325291 +rec-1227-org,robert,carbone,77,james smith circuit,galloway,st kilda east,5038,qld,19141107,6153085 +rec-1290-org,kirra,browne,26,shoalhaven avenue,loormeah park,surry hills,3042,tas,19430407,8370048 +rec-4350-org,aneka,milburn,267,wilkins street,clisby farm,kuraby,2715,qld,19171108,4533360 +rec-2192-org,ellie,fearnall,31,fishburn street,colbara,cherrybrook,5171,wa,,7745948 +rec-1881-org,emma,fitzpatrick,190,maltby circuit,avonleigh,broadmeadows,2489,nsw,19930629,6950798 +rec-4141-org,courtney,mcgregor,14,dianella street,queens lake village,bassendean,3218,nsw,19830529,5272719 +rec-3669-org,zac,ryan,38,naas close,willandra village,applecross,7249,nsw,19340605,9433767 +rec-4323-org,annalise,ma,6,namatjira drive,point cook home,stroud,6535,nsw,19270608,2160321 +rec-2664-org,emiily,penaluna,23,boolee street,gumnut cottage,boondall,5114,vic,19370502,2528591 +rec-2588-org,thomas,tsonis,33,de little circuit,arndilly,rye,5024,sa,19130119,9807073 +rec-62-org,jake,coleman,1,sturt avenue,rivonia,sunshine north,3058,nsw,19450706,6061178 +rec-3907-org,timothy,botham,21,grund place,brentwood vlge,robina,2603,vic,19200714,2476704 +rec-534-org,riley,son,11,duffy street,toora,caulfield north,2486,nsw,19851219,8480884 +rec-1420-org,sam,green,43,leita court,strathmore vineyard,geelong east,4350,nsw,19040618,1956745 +rec-4374-org,anton,navalli,21,cambridge street,west park,underdale,5723,vic,19740929,8760134 +rec-4325-org,juliana,roman,61,mana place,tinaroo falls,yagoona,5523,nsw,19140705,8963464 +rec-2510-org,harriet,clarke,6,tanumbirini street,r s l retrmnt vlge,burleigh waters,2305,nsw,19590810,5578997 +rec-3148-org,christian,littlely,3,meyers place,burtons lookout,maryvale,5268,wa,19001019,4011513 +rec-4609-org,sophie,crisci,17,woolner circuit,sefton park,eastern heights,4165,wa,19480428,8614805 +rec-4856-org,jack,wang,,elliott street,stoney creek,norwood,2147,nsw,19790913,5004938 +rec-4569-org,cheree,bowerman,55,tregear close,northwood park,st peters,3191,qld,19091213,3770036 +rec-2193-org,keaton,green,47,salvado place,racecourse,palinyewah,7008,nsw,19040705,3688006 +rec-2989-org,anton,goode,11,lalor street,killara homestead,taree,2195,vic,19081025,3128289 +rec-1644-org,teileah,panagaris,5,hannan crescent,st george,bonnyrigg,2785,nsw,19160809,2039630 +rec-1115-org,isabelle,berry,71,scarlett street,yakatoon,clarinda,3194,qld,19010210,5294123 +rec-2091-org,caitlin,khammash,359,carbeen street,salimtal,elsternwick,2430,nsw,19810113,7990656 +rec-4948-org,dylan,czoloszynski,55,templestowe avenue,rocklea,regents park,2065,wa,19740614,3880965 +rec-878-org,elton,rushby,2,charleston street,toowoomba,wyoming,4382,nsw,19320419,3833752 +rec-2568-org,kristo,mckinnell,14,,salmaldo caravan park,sunshine,2571,qld,19081106,1212914 +rec-3061-org,hamish,boulter,16,longstay caravn park,top spot,warkton,2429,nsw,19170530,6954052 +rec-1375-org,jye,bradshaw,28,wyles place,normanhurst,homebush,2036,wa,19900905,7164427 +rec-276-org,jai,kyriacou,32,garanya street,entry daniels s street,cleveland,2486,nsw,19140906,5490391 +rec-3633-org,ryleh,sleath,9,archdall street,boxwood hill,sandy bay,2484,nsw,19550126,1791300 +rec-1508-org,lia,maynard,15,hensman street,under silos,modbury heights,3169,nsw,19250717,9947782 +rec-981-org,laklynn,chandler,7,bangalay crescent,carisbrook,mount gravatt,4122,nsw,19371103,3919587 +rec-3830-org,nathan,samuniuk,53,burkitt street,forestdale,hindmarsh west,5540,nsw,19831213,3693831 +rec-3475-org,william,everett,12,callabonna street,fernbank,bull creek,7184,tas,19921006,2805780 +rec-1116-org,jessica,millane,,windeyer street,mt martin,ridleyton,7275,,19120708,8511839 +rec-1256-org,emiily,mees,31,campbell street,lingard,elwood,3805,wa,19301201,4611758 +rec-846-org,connor,camp,29,egerton close,gwandalan,riverhills,2170,vic,19190905,5237893 +rec-3072-org,heather,paulsen,1,ahern place,unt 3,mulgrave east,2540,qld,19840615,3281035 +rec-2177-org,georgia,mcvilly,34,gardiner street,cadogan,bayview heights,4370,nsw,19830221,2711924 +rec-830-org,chelsea,baillie,93,keane place,villa 36 sovereign garden,st ives,3875,vic,19040318,3338604 +rec-3184-org,jarod,feleppa,63,badimara street,tudor,frenchs forest,4821,nsw,19610421,8535978 +rec-3380-org,kade,hindmarch,16,ross smith crescent,,goonellabah,2116,vic,19400708,3431636 +rec-1724-org,caitlin,rider,73,morgan crescent,,oak flats,6330,vic,19580428,2527146 +rec-2838-org,jessica,wiseman,23,spowers circuit,woodbine homestead,carnegie,2018,nsw,19641123,4608861 +rec-974-org,caitlin,luckens,180,ortloff place,brokenspoke,ryde,4051,qld,19640720,3391457 +rec-1240-org,kyle,kyriacou,6,brigalow street,kilacloran,surfers paradise,2528,vic,19560704,6294045 +rec-1402-org,flynn,guduguntla,44,ballumbir street,coolibah,terranora,6057,nsw,19211004,6413064 +rec-2606-org,emiily,benjamin,8,holman street,kersey' south,coutts crossing,2287,vic,19490214,7996561 +rec-3811-org,yasmin,george,12,crisp circuit,abbotsley cottage,keilor lodge,3023,vic,19290223,5237340 +rec-716-org,hannah,birkin,7,tregear close,highfields specialist centre,port macquarie,6065,nsw,19140127,3152369 +rec-2940-org,samantha,harrington,42,beaver place,,toukley,6751,vic,19471114,1272559 +rec-3930-org,isaac,sherriff,6,britten-jones drive,wyuna,greendale,3976,tas,19330719,7424128 +rec-1255-org,stella,rogan,22,wattle street,flr 5 john flynn medical centre,strathalbyn,2289,qld,19690311,1379241 +rec-4417-org,sebastian,demarco,9,cotter road,kelman vineyard,wyongah,4670,,19050730,3478101 +rec-998-org,bailey,green,76,jackie howe crescent,glengara village,murgon,3340,nsw,19960416,9882349 +rec-3651-org,lucas,white,4,preston street,ben hill,wahroonga,2230,wa,19161007,3053568 +rec-2694-org,ebony,piniros,16,ashby circuit,myross,melton south,2913,nsw,19030607,6804193 +rec-584-org,renee,renfrey,24,serpentine street,retmnt vlge,winchelsea,2176,wa,19690305,5153203 +rec-193-org,ethan,nguyen,1932,lodder place,tobruk hse,clayfield,4405,tas,19971105,1140575 +rec-1591-org,jasmine,clarke,489,,cambooya,noble park,3413,vic,19741020,9562970 +rec-704-org,michael,goldsworthy,2,forbes street,wdgee street,tarragindi,2604,vic,19540317,3675381 +rec-873-org,joshua,ottens,3,mugga way,macsview,gosford east,5163,qld,19410514,3579690 +rec-3905-org,jessica,mccarthy,42,moynihan street,railway cottage,st lucia,4806,qld,19770301,6423000 +rec-1498-org,katie,fitzpatrick,37,duffy street,donore,hurlstone park,6108,vic,19380621,7125161 +rec-1336-org,max,britten,2,schlam place,gowrie,dungog,5075,wa,19441213,9043323 +rec-3801-org,sophie,hage,18,riley close,rocklea,seaforth,3215,nsw,19771204,9725410 +rec-1414-org,zali,eglinton,14,adcock place,trewilga,woodlands,2122,qld,19300914,7126898 +rec-1954-org,jessica,blake,112,gardiner street,jemaree,cronulla,6525,qld,19871021,2057337 +rec-1428-org,alicia,widdowson,69,dinnison circuit,tourist park,port pirie,3551,qld,19300510,1675302 +rec-2061-org,dylan,millar,58,,the willows,woodburn,2034,nsw,19330911,8113457 +rec-3584-org,riley,pascoe,86,lexcen avenue,brentwood vlge,south brisbane,7053,sa,19380905,1815088 +rec-2799-org,sophie,otto-coats,19,clancy street,inglewood,springwood,2600,wa,19690527,5566144 +rec-2814-org,rachel,pusz,17,chewings street,mowbray,seymour,6066,sa,19351221,7559316 +rec-2869-org,pace,hindmarch,12,clisby close,florina park,bondi junction,4034,nsw,19140616,9203492 +rec-3023-org,bridget,hand,210,bunton place,flt 10,parkinson,2705,nsw,19391228,3815665 +rec-2269-org,serena,webb,9,,aptmnt 2,tin can bay,2540,qld,19770422,3504192 +rec-587-org,lauren,musolino,35,beattie crescent,,bangor,2869,act,19891021,6356434 +rec-7-org,jasmine,silvestro,41,nott street,tathra river est,middleton beach,3173,nsw,19560720,9873948 +rec-597-org,aidan,leslie,45,jacka crescent,villa 5,oakleigh,4151,qld,19710804,4216793 +rec-496-org,alicia,heron,262,verbrugghen street,oxley's way,mount helen,2560,qld,19320131,7028101 +rec-3939-org,thomas,tippins,4,glencross street,mehelu,hinchinbrook,3201,nsw,19890111,9250708 +rec-4207-org,lachlan,shepherd,9,dalley crescent,grand view,suffolk park,3550,tas,19900821,8396396 +rec-3168-org,hayley,bishop,9,lindsay street,lindis faime,blackmans bay,4163,wa,19210517,3857962 +rec-3125-org,griffin,webb,545,oliver street,,shoal point,4511,vic,19140703,9124566 +rec-4521-org,eliza,liddy,32,buik place,huntington,burwood,6006,act,19461223,9954230 +rec-715-org,mia,lock,42,morrow street,,woodburn,2810,nsw,19650307,6006824 +rec-674-org,kylee,clarke,57,pethebridge street,lansdowne,normanville,2034,qld,19000930,3275236 +rec-1916-org,ruby,purdon,356,downward place,st columbus retirement centre,forrestfield,2617,qld,19020131,8807072 +rec-2756-org,evan,heerey,74,banjine street,ochre,gawler east,2750,nsw,19170811,7838600 +rec-1849-org,jordyn,grafton,6,springvale drive,fernbank,sunshine,3186,vic,19350919,3481992 +rec-4715-org,caitlyn,clarke,,streeter place,riverside plaza,port lincoln,2090,sa,19420124,1250298 +rec-2792-org,anita,afford,19,andamooka street,,lilydale,5631,,19391104,6863258 +rec-2613-org,hayley,hassall,53,morton street,mckinnon glen,taringa,5082,nsw,19170113,5401135 +rec-2235-org,kiria,ryan,41,rumsey place,mount marion,hayborough,2289,wa,19081205,1490347 +rec-3877-org,vendula,forgie-wendt,11,mccabe crescent,parry house,allingham,2484,nsw,19650317,1609478 +rec-1622-org,bethanie,menzies,120,archibald street,krismark,belmont,2287,nsw,19871019,8046929 +rec-2153-org,annabel,grierson,97,mclachlan crescent,lantana lodge,broome,2480,nsw,19840224,7676186 +rec-1604-org,sienna,musolino,22,smeaton circuit,pangani,mckinnon,2700,nsw,19890525,4971506 +rec-1003-org,bradley,matthews,2,jondol place,horseshoe ck,jacobs well,7018,sa,19481122,8927667 +rec-4883-org,brodee,egan,88,axon street,greenslopes,wamberal,2067,qld,19121113,6039042 +rec-66-org,koula,houweling,3,mileham street,old airdmillan road,williamstown,2350,nsw,19440718,6375537 diff --git a/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/resources/rbf_resultset.json b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/resources/rbf_resultset.json new file mode 100644 index 000000000..9d2cc6af1 --- /dev/null +++ b/dsf-pseudonymization/dsf-pseudonymization-ttp/src/test/resources/rbf_resultset.json @@ -0,0 +1,43 @@ +{ + "meta" : { + "_href" : "http://test.com", + "_type" : "RESULTSET", + "_schema_version" : "1.0.0", + "_created" : "2017-08-19T00:25:47.568+02:00", + "_generator" : "DIPS.OpenEhr.ResultSets.Serialization.Json.ResultSetJsonWriter (5.0.0.0)", + "_executed_aql" : "SELECT e FROM EHR(e)" + }, + "name" : "<the name/identifier of the stored query that was executed>", + "q" : "select e/ehr_id/value, c/context/start_time/value as startTime, c/uid/value as cid, c/name from EHR e contains Composition c limit 2", + "columns" : [ + { + "name" : "startTime", + "path" : "/context/start_time/value" + }, + { + "name" : "cid", + "path" : "/uid/value" + }, + { + "name" : "#3", + "path" : "/name" + }, + { + "name" : "MEDICID", + "path" : "/medic_id/value" + }, + { + "name" : "RBF", + "path" : "/rbf/value" + } + ], + "rows" : [ + [ + "YGAAgOqx908gXjJn6RIrp6pyk7P4TxSR7RWojqgXy/WZknsdvoqT86UcWsniVvhpqHwaCZh03vuPalHgviChjtgTew==", + "8Ftk411ME9aj5stoI6OGsFMym2QFjLV2bTRLkuWy/xk5QZosWE9FqwtEVt9KlA1kjTksrtVtOhZ71M7nWXrtE3ky43Lx+YHnIGdFJw7oKnS1rZI=", + "4HvOulQ1VVt3+JtvI7RM7hq7TDcKUGHQGQH9jag5gn/YSYlSOnZ8VnJ9eAxcYdoW9bzOcww3vycXwzsOJh3Gb4m0/Q==", + "NJuCb7E2yc+D7ueSWvL3U18t85PazF8TklK/HPtAfyluPDd4", + "MgoMgpvA6DtR0VhBAUIigDVVC4CgEjKNIjFaoQYdnCyThKaCtAmChaHB0cSl8QDkG1SWFm3oLTUQlYHFB9qnhgguQH20pcJ8oK0EisQgKYQYQrZcYCgoM2AB4CiOOAUJFIGGZBgBwVSCgghDoFziMCkCAQJEITlgIglAGtngEmIUgcSAJU+YEKAnFI0AxAUWeISiAU2wGAkEAIIggmyACRYIBcgJVCAJSpBFCtFF5TRAAGsIosIgzIABAoSAQnhEgFEQggMtnhTLnOVxipYAhLCFFPVKEAa9gKAAikIJkgwC" + ] + ] +} \ No newline at end of file diff --git a/dsf-pseudonymization/pom.xml b/dsf-pseudonymization/pom.xml index 45bf0fb84..e5459e507 100644 --- a/dsf-pseudonymization/pom.xml +++ b/dsf-pseudonymization/pom.xml @@ -8,7 +8,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <modules> @@ -21,7 +21,6 @@ <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> - <version>2.10.1</version> </dependency> <!-- Logging --> @@ -56,6 +55,12 @@ <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.highmed.dsf</groupId> + <artifactId>dsf-mpi-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-openehr-model</artifactId> diff --git a/dsf-tools/dsf-tools-build-info-reader/pom.xml b/dsf-tools/dsf-tools-build-info-reader/pom.xml index b3476aa90..51072418c 100644 --- a/dsf-tools/dsf-tools-build-info-reader/pom.xml +++ b/dsf-tools/dsf-tools-build-info-reader/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-tools-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> diff --git a/dsf-tools/dsf-tools-bundle-generator/pom.xml b/dsf-tools/dsf-tools-bundle-generator/pom.xml index 3924937a5..b8ac4f8a9 100755 --- a/dsf-tools/dsf-tools-bundle-generator/pom.xml +++ b/dsf-tools/dsf-tools-bundle-generator/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-tools-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> @@ -20,5 +20,21 @@ <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-fhir-structures-r4</artifactId> </dependency> + <dependency> + <groupId>ca.uhn.hapi.fhir</groupId> + <artifactId>hapi-fhir-structures-r5</artifactId> + </dependency> + <dependency> + <groupId>ca.uhn.hapi.fhir</groupId> + <artifactId>hapi-fhir-validation</artifactId> + </dependency> + <dependency> + <groupId>ca.uhn.hapi.fhir</groupId> + <artifactId>hapi-fhir-validation-resources-r4</artifactId> + </dependency> + <dependency> + <groupId>ca.uhn.hapi.fhir</groupId> + <artifactId>hapi-fhir-validation-resources-r5</artifactId> + </dependency> </dependencies> </project> \ No newline at end of file diff --git a/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleEntryFileVisitor.java b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleEntryFileVisitor.java index 188cad42c..28935273f 100755 --- a/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleEntryFileVisitor.java +++ b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleEntryFileVisitor.java @@ -17,13 +17,15 @@ public class BundleEntryFileVisitor implements FileVisitor<Path> private final Path baseFolder; private final BundleEntryPutReader putReader; + private final BundleEntryPostReader postReader; private Class<Resource> resource; - public BundleEntryFileVisitor(Path baseFolder, BundleEntryPutReader putReader) + public BundleEntryFileVisitor(Path baseFolder, BundleEntryPutReader putReader, BundleEntryPostReader postReader) { this.baseFolder = baseFolder; this.putReader = putReader; + this.postReader = postReader; } @Override @@ -66,14 +68,29 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO if (resource != null && file.getFileName().toString().endsWith(".xml")) { Path putFile = file.resolveSibling(file.getFileName().toString() + ".put"); - if (!Files.isReadable(putFile)) + Path postFile = file.resolveSibling(file.getFileName().toString() + ".post"); + if (!Files.isReadable(putFile) && !Files.isReadable(postFile)) { - logger.error("Put file for {} at {} not readable. Redable file {} expected", resource.getSimpleName(), - file.toString(), putFile.toString()); - throw new IOException("Put file " + putFile.toString() + " not readable"); + logger.error("put or post file for {} at {} not readable. Redable file {} or {} expected", + resource.getSimpleName(), file.toString(), putFile.toString(), postFile.toString()); + throw new IOException( + "put file " + putFile.toString() + " or post file " + postFile.toString() + " not readable"); } - else + else if (Files.isReadable(putFile) && Files.isReadable(postFile)) + { + logger.error("put and post file for {} at {} readable. One redable file {} or {} expected", + resource.getSimpleName(), file.toString(), putFile.toString(), postFile.toString()); + throw new IOException( + "put file " + putFile.toString() + " and post file " + postFile.toString() + " readable"); + } + else if (Files.isReadable(putFile)) + { putReader.read(resource, file, putFile); + } + else if (Files.isReadable(postFile)) + { + postReader.read(resource, file, postFile); + } } else logger.debug("Ignoring {}", file.toString()); diff --git a/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleEntryPostReader.java b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleEntryPostReader.java new file mode 100644 index 000000000..09f0cc39c --- /dev/null +++ b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleEntryPostReader.java @@ -0,0 +1,10 @@ +package org.highmed.dsf.tools.generator; + +import java.nio.file.Path; + +import org.hl7.fhir.r4.model.Resource; + +public interface BundleEntryPostReader +{ + void read(Class<? extends Resource> resource, Path resourceFile, Path putFile); +} diff --git a/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleGenerator.java b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleGenerator.java index 29651f12d..ea2238b9c 100755 --- a/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleGenerator.java +++ b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/BundleGenerator.java @@ -9,17 +9,24 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.Comparator; import java.util.UUID; +import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; +import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleType; import org.hl7.fhir.r4.model.Bundle.HTTPVerb; import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.ValueSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.DefaultProfileValidationSupport; +import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.parser.IParser; public class BundleGenerator @@ -57,7 +64,7 @@ public Bundle generateBundle() throws IOException BundleEntryPutReader putReader = (resource, resourceFile, putFile) -> { - logger.info("Reading {} at {} with put file {}", resource.getSimpleName(), resourceFile.toString(), + logger.debug("Reading {} at {} with put file {}", resource.getSimpleName(), resourceFile.toString(), putFile.toString()); try (InputStream in = Files.newInputStream(resourceFile)) @@ -76,7 +83,29 @@ public Bundle generateBundle() throws IOException } }; - FileVisitor<Path> visitor = new BundleEntryFileVisitor(baseFolder, putReader); + BundleEntryPostReader postReader = (resource, resourceFile, postFile) -> + { + logger.info("Reading {} at {} with post file {}", resource.getSimpleName(), resourceFile.toString(), + postFile.toString()); + + try (InputStream in = Files.newInputStream(resourceFile)) + { + Resource r = newXmlParser().parseResource(resource, in); + String ifNoneExistValue = Files.readString(postFile); + + BundleEntryComponent entry = bundle.addEntry(); + entry.setFullUrl("urn:uuid:" + UUID.randomUUID().toString()); + entry.setResource(r); + entry.getRequest().setMethod(HTTPVerb.POST).setUrl(r.getResourceType().name()) + .setIfNoneExist(ifNoneExistValue); + } + catch (IOException e) + { + logger.error("Error while parsing {} from {}", resource.getSimpleName(), resourceFile.toString()); + } + }; + + FileVisitor<Path> visitor = new BundleEntryFileVisitor(baseFolder, putReader, postReader); Files.walkFileTree(baseFolder, visitor); return bundle; @@ -91,29 +120,71 @@ private void saveBundle(Bundle bundle) throws IOException } } - public static void main(String[] args) throws IOException + private void generateStructureDefinitionSnapshots(Bundle bundle, IValidationSupport validationSupport) { - BundleGenerator bundleGenerator = new BundleGenerator(getBaseFolder(args)); + SnapshotGenerator generator = new SnapshotGenerator(fhirContext, validationSupport); + + bundle.getEntry().stream().map(e -> e.getResource()).filter(r -> r instanceof StructureDefinition) + .map(r -> (StructureDefinition) r).sorted(Comparator.comparing(StructureDefinition::getUrl).reversed()) + .forEach(s -> + { + if (!s.hasSnapshot()) + generator.generateSnapshot(s); + }); + } - Bundle bundle; - try - { - logger.info("Generating bundle at " + bundleGenerator.getBundleFilename() + " ..."); - bundle = bundleGenerator.generateBundle(); - } - catch (IOException e) - { - logger.error("Error while generating bundle", e); - throw e; - } + private void expandValueSets(Bundle bundle, ValidationSupportChain validationSupport) + { + ValueSetExpander valueSetExpander = new ValueSetExpander(fhirContext, validationSupport); + + bundle.getEntry().stream().map(e -> e.getResource()).filter(r -> r instanceof ValueSet).map(r -> (ValueSet) r) + .forEach(v -> + { + if (!v.hasExpansion()) + valueSetExpander.expand(v); + }); + } + + public static void main(String[] args) throws Exception + { try { - bundleGenerator.saveBundle(bundle); - logger.info("Bundle saved at " + bundleGenerator.getBundleFilename()); + BundleGenerator bundleGenerator = new BundleGenerator(getBaseFolder(args)); + + Bundle bundle; + try + { + logger.info("Generating bundle at " + bundleGenerator.getBundleFilename() + " ..."); + bundle = bundleGenerator.generateBundle(); + } + catch (IOException e) + { + logger.error("Error while generating bundle", e); + throw e; + } + + ValidationSupportChain validationSupport = new ValidationSupportChain( + new InMemoryTerminologyServerValidationSupport(bundleGenerator.fhirContext), + new ValidationSupportWithCustomResources(bundleGenerator.fhirContext, bundle), + new DefaultProfileValidationSupport(bundleGenerator.fhirContext)); + + bundleGenerator.expandValueSets(bundle, validationSupport); + bundleGenerator.generateStructureDefinitionSnapshots(bundle, validationSupport); + + try + { + bundleGenerator.saveBundle(bundle); + logger.info("Bundle saved at " + bundleGenerator.getBundleFilename()); + } + catch (IOException e) + { + logger.error("Error while generating bundle", e); + throw e; + } } - catch (IOException e) + catch (Exception e) { - logger.error("Error while generating bundle", e); + e.printStackTrace(); throw e; } } diff --git a/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/SnapshotGenerator.java b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/SnapshotGenerator.java new file mode 100644 index 000000000..abbdf748e --- /dev/null +++ b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/SnapshotGenerator.java @@ -0,0 +1,71 @@ +package org.highmed.dsf.tools.generator; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.hl7.fhir.r4.conformance.ProfileUtilities; +import org.hl7.fhir.r4.context.IWorkerContext; +import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; + +public class SnapshotGenerator +{ + private static final Logger logger = LoggerFactory.getLogger(SnapshotGenerator.class); + + private final IWorkerContext worker; + + public SnapshotGenerator(FhirContext fhirContext, IValidationSupport validationSupport) + { + worker = createWorker(fhirContext, validationSupport); + } + + protected HapiWorkerContext createWorker(FhirContext context, IValidationSupport validationSupport) + { + HapiWorkerContext workerContext = new HapiWorkerContext(context, validationSupport); + workerContext.setLocale(context.getLocalizer().getLocale()); + return workerContext; + } + + public StructureDefinition generateSnapshot(StructureDefinition differential) + { + Objects.requireNonNull(differential, "differential"); + + StructureDefinition base = worker.fetchResource(StructureDefinition.class, differential.getBaseDefinition()); + + if (base == null) + logger.warn("Base definition with url {} not found", differential.getBaseDefinition()); + else if (!base.hasSnapshot()) + generateSnapshot(base); + + logger.info("Generating snapshot for StructureDefinition with url {}, version {}, base {}", + differential.getUrl(), differential.getVersion(), differential.getBaseDefinition()); + + /* ProfileUtilities is not thread safe */ + List<ValidationMessage> messages = new ArrayList<>(); + ProfileUtilities profileUtils = new ProfileUtilities(worker, messages, null); + profileUtils.generateSnapshot(base, differential, "", "", null); + + if (messages.isEmpty()) + logger.debug("Snapshot generated for StructureDefinition url {}, version {}", differential.getUrl(), + differential.getVersion()); + else + { + logger.warn("Snapshot not generated for StructureDefinition with url {}, version {}", differential.getUrl(), + differential.getVersion()); + messages.forEach(m -> logger.warn("Issue while generating snapshot: {} - {} - {}", m.getDisplay(), + m.getLine(), m.getMessage())); + + throw new RuntimeException("Error while generating Snapshot for StructureDefinition with url " + + differential.getUrl() + ", version " + differential.getVersion() + ": " + messages.toString()); + } + + return differential; + } +} diff --git a/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/ValidationSupportWithCustomResources.java b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/ValidationSupportWithCustomResources.java new file mode 100644 index 000000000..ef30874fd --- /dev/null +++ b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/ValidationSupportWithCustomResources.java @@ -0,0 +1,102 @@ +package org.highmed.dsf.tools.generator; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.StructureDefinition; +import org.hl7.fhir.r4.model.ValueSet; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; + +public class ValidationSupportWithCustomResources implements IValidationSupport +{ + private final FhirContext context; + + private final Map<String, StructureDefinition> structureDefinitionsByUrl = new HashMap<>(); + private final Map<String, CodeSystem> codeSystemsByUrl = new HashMap<>(); + private final Map<String, ValueSet> valueSetsByUrl = new HashMap<>(); + + public ValidationSupportWithCustomResources(FhirContext context, Bundle bundle) + { + this.context = context; + + bundle.getEntry().stream().map(e -> e.getResource()) + .filter(r -> r instanceof StructureDefinition || r instanceof CodeSystem || r instanceof ValueSet) + .forEach(r -> + { + if (r instanceof StructureDefinition) + { + StructureDefinition sd = (StructureDefinition) r; + + structureDefinitionsByUrl.put(sd.getUrl(), sd); + if (sd.hasVersion()) + structureDefinitionsByUrl.put(sd.getUrl() + "|" + sd.getVersion(), sd); + } + else if (r instanceof CodeSystem) + { + CodeSystem cs = (CodeSystem) r; + codeSystemsByUrl.put(cs.getUrl(), cs); + if (cs.hasVersion()) + codeSystemsByUrl.put(cs.getUrl() + "|" + cs.getVersion(), cs); + } + else if (r instanceof ValueSet) + { + ValueSet vs = (ValueSet) r; + valueSetsByUrl.put(vs.getUrl(), vs); + if (vs.hasVersion()) + valueSetsByUrl.put(vs.getUrl() + "|" + vs.getVersion(), vs); + } + }); + } + + @Override + public FhirContext getFhirContext() + { + return context; + } + + @SuppressWarnings("unchecked") + @Override + public List<StructureDefinition> fetchAllStructureDefinitions() + { + return new ArrayList<>(structureDefinitionsByUrl.values()); + } + + @Override + public StructureDefinition fetchStructureDefinition(String url) + { + return structureDefinitionsByUrl.getOrDefault(url, null); + } + + public void addOrReplace(StructureDefinition s) + { + structureDefinitionsByUrl.put(s.getUrl(), s); + } + + @Override + public CodeSystem fetchCodeSystem(String url) + { + return codeSystemsByUrl.getOrDefault(url, null); + } + + public void addOrReplace(CodeSystem s) + { + codeSystemsByUrl.put(s.getUrl(), s); + } + + @Override + public ValueSet fetchValueSet(String url) + { + return valueSetsByUrl.getOrDefault(url, null); + } + + public void addOrReplace(ValueSet s) + { + valueSetsByUrl.put(s.getUrl(), s); + } +} diff --git a/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/ValueSetExpander.java b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/ValueSetExpander.java new file mode 100644 index 000000000..73cafa269 --- /dev/null +++ b/dsf-tools/dsf-tools-bundle-generator/src/main/java/org/highmed/dsf/tools/generator/ValueSetExpander.java @@ -0,0 +1,53 @@ +package org.highmed.dsf.tools.generator; + +import java.util.Objects; + +import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext; +import org.hl7.fhir.r4.model.ValueSet; +import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent; +import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome; +import org.hl7.fhir.r4.terminologies.ValueSetExpanderSimple; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; + +public class ValueSetExpander +{ + private static final Logger logger = LoggerFactory.getLogger(ValueSetExpander.class); + + private final HapiWorkerContext workerContext; + + public ValueSetExpander(FhirContext fhirContext, IValidationSupport validationSupport) + { + workerContext = createWorkerContext(fhirContext, validationSupport); + } + + protected HapiWorkerContext createWorkerContext(FhirContext fhirContext, IValidationSupport validationSupport) + { + HapiWorkerContext workerContext = new HapiWorkerContext(fhirContext, validationSupport); + workerContext.setLocale(fhirContext.getLocalizer().getLocale()); + return workerContext; + } + + public ValueSet expand(ValueSet valueSet) + { + Objects.requireNonNull(valueSet, "valueSet"); + + logger.info("Generating expansion for ValueSet url {}, version {}", valueSet.getUrl(), valueSet.getVersion()); + + // ValueSetExpanderSimple can't be reused + ValueSetExpanderSimple valueSetExpander = new ValueSetExpanderSimple(workerContext); + + ValueSetExpansionOutcome outcome = valueSetExpander.expand(valueSet, null); + if (outcome.getValueset() == null) + throw new RuntimeException( + "Error while generating Expansion for ValueSet with url " + valueSet.getUrl() + ", version " + + valueSet.getVersion() + ": " + outcome.getError() + " (" + outcome.getErrorClass() + ")"); + + ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion(); + valueSet.setExpansion(expansion); + return valueSet; + } +} diff --git a/dsf-tools/dsf-tools-bundle-generator/src/main/resources/log4j2.xml b/dsf-tools/dsf-tools-bundle-generator/src/main/resources/log4j2.xml index 44e6b15ee..ace9b54b1 100755 --- a/dsf-tools/dsf-tools-bundle-generator/src/main/resources/log4j2.xml +++ b/dsf-tools/dsf-tools-bundle-generator/src/main/resources/log4j2.xml @@ -3,12 +3,12 @@ <Appenders> <Console name="CONSOLE" target="SYSTEM_OUT"> - <PatternLayout pattern="%p\t%t - %C{1}.%M(%L) | %m%n"/> + <PatternLayout pattern="%p\t%C{1}.%M(%L) | %m%n"/> </Console> </Appenders> <Loggers> - <Logger name="org.highmed" level="DEBUG"/> + <Logger name="org.highmed" level="INFO"/> <logger name="de.rwh" level="INFO"/> <Root level="WARN"> diff --git a/dsf-tools/dsf-tools-db-migration/pom.xml b/dsf-tools/dsf-tools-db-migration/pom.xml index 35bf59682..ef6e8ec18 100755 --- a/dsf-tools/dsf-tools-db-migration/pom.xml +++ b/dsf-tools/dsf-tools-db-migration/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-tools-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> diff --git a/dsf-tools/dsf-tools-proxy-test/pom.xml b/dsf-tools/dsf-tools-proxy-test/pom.xml index a3337574d..000def5fc 100755 --- a/dsf-tools/dsf-tools-proxy-test/pom.xml +++ b/dsf-tools/dsf-tools-proxy-test/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-tools-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> diff --git a/dsf-tools/dsf-tools-test-data-generator/pom.xml b/dsf-tools/dsf-tools-test-data-generator/pom.xml index 1fdb19218..3e5a33ad1 100755 --- a/dsf-tools/dsf-tools-test-data-generator/pom.xml +++ b/dsf-tools/dsf-tools-test-data-generator/pom.xml @@ -7,7 +7,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-tools-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <dependencies> diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/java/org/highmed/dsf/tools/generator/BundleGenerator.java b/dsf-tools/dsf-tools-test-data-generator/src/main/java/org/highmed/dsf/tools/generator/BundleGenerator.java index b68b64d7f..594b002d1 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/java/org/highmed/dsf/tools/generator/BundleGenerator.java +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/java/org/highmed/dsf/tools/generator/BundleGenerator.java @@ -9,6 +9,8 @@ import java.nio.file.Paths; import java.util.Map; +import org.highmed.dsf.fhir.service.ReferenceCleaner; +import org.highmed.dsf.fhir.service.ReferenceCleanerImpl; import org.highmed.dsf.fhir.service.ReferenceExtractor; import org.highmed.dsf.fhir.service.ReferenceExtractorImpl; import org.highmed.dsf.tools.generator.CertificateGenerator.CertificateFiles; @@ -28,6 +30,7 @@ public class BundleGenerator private final FhirContext fhirContext = FhirContext.forR4(); private final ReferenceExtractor extractor = new ReferenceExtractorImpl(); + private final ReferenceCleaner cleaner = new ReferenceCleanerImpl(extractor); private Bundle testBundle; private Bundle medic1Bundle; @@ -35,11 +38,14 @@ public class BundleGenerator private Bundle medic3Bundle; private Bundle ttpBundle; - private Bundle readBundle(Path bundleTemplateFile) + private Bundle readAndCleanBundle(Path bundleTemplateFile) { try (InputStream in = Files.newInputStream(bundleTemplateFile)) { - return newXmlParser().parseResource(Bundle.class, in); + Bundle bundle = newXmlParser().parseResource(Bundle.class, in); + + // FIXME hapi parser can't handle embedded resources and creates them while parsing bundles + return cleaner.cleanReferenceResourcesIfBundle(bundle); } catch (IOException e) { @@ -75,7 +81,7 @@ public void createTestBundle(Map<String, CertificateFiles> clientCertificateFile { Path testBundleTemplateFile = Paths.get("src/main/resources/bundle-templates/test-bundle.xml"); - testBundle = readBundle(testBundleTemplateFile); + testBundle = readAndCleanBundle(testBundleTemplateFile); Organization organization = (Organization) testBundle.getEntry().get(0).getResource(); Extension thumbprintExtension = organization @@ -83,25 +89,9 @@ public void createTestBundle(Map<String, CertificateFiles> clientCertificateFile thumbprintExtension.setValue(new StringType( clientCertificateFilesByCommonName.get("test-client").getCertificateSha512ThumbprintHex())); - removeReferenceEmbeddedResources(testBundle); - writeBundle(Paths.get("bundle/test-bundle.xml"), testBundle); } - // FIXME hapi parser can't handle embedded resources and creates them while parsing bundles - private void removeReferenceEmbeddedResources(Bundle bundle) - { - bundle.getEntry().stream().map(e -> e.getResource()).forEach(res -> - { - logger.debug("Extracting references from {} resource", res.getResourceType()); - extractor.getReferences(res).forEach(ref -> - { - logger.debug("Setting reference embedded resource to null at {}", ref.getReferenceLocation()); - ref.getReference().setResource(null); - }); - }); - } - public void copyJavaTestBundle() { Path javaTestBundleFile = Paths.get("../../dsf-fhir/dsf-fhir-server-jetty/conf/bundle.xml"); @@ -128,7 +118,7 @@ private void createDockerTestMedic1Bundle(Map<String, CertificateFiles> clientCe { Path medic1BundleTemplateFile = Paths.get("src/main/resources/bundle-templates/medic1-bundle.xml"); - medic1Bundle = readBundle(medic1BundleTemplateFile); + medic1Bundle = readAndCleanBundle(medic1BundleTemplateFile); Organization organizationTtp = (Organization) medic1Bundle.getEntry().get(0).getResource(); Extension organizationTtpThumbprintExtension = organizationTtp @@ -142,8 +132,6 @@ private void createDockerTestMedic1Bundle(Map<String, CertificateFiles> clientCe organizationMedic1thumbprintExtension.setValue(new StringType( clientCertificateFilesByCommonName.get("medic1-client").getCertificateSha512ThumbprintHex())); - removeReferenceEmbeddedResources(medic1Bundle); - writeBundle(Paths.get("bundle/medic1-bundle.xml"), medic1Bundle); } @@ -151,7 +139,7 @@ private void createDockerTestMedic2Bundle(Map<String, CertificateFiles> clientCe { Path medic2BundleTemplateFile = Paths.get("src/main/resources/bundle-templates/medic2-bundle.xml"); - medic2Bundle = readBundle(medic2BundleTemplateFile); + medic2Bundle = readAndCleanBundle(medic2BundleTemplateFile); Organization organizationTtp = (Organization) medic2Bundle.getEntry().get(0).getResource(); Extension organizationTtpThumbprintExtension = organizationTtp @@ -165,8 +153,6 @@ private void createDockerTestMedic2Bundle(Map<String, CertificateFiles> clientCe organizationMedic2thumbprintExtension.setValue(new StringType( clientCertificateFilesByCommonName.get("medic2-client").getCertificateSha512ThumbprintHex())); - removeReferenceEmbeddedResources(medic2Bundle); - writeBundle(Paths.get("bundle/medic2-bundle.xml"), medic2Bundle); } @@ -174,7 +160,7 @@ private void createDockerTestMedic3Bundle(Map<String, CertificateFiles> clientCe { Path medic3BundleTemplateFile = Paths.get("src/main/resources/bundle-templates/medic3-bundle.xml"); - medic3Bundle = readBundle(medic3BundleTemplateFile); + medic3Bundle = readAndCleanBundle(medic3BundleTemplateFile); Organization organizationTtp = (Organization) medic3Bundle.getEntry().get(0).getResource(); Extension organizationTtpThumbprintExtension = organizationTtp @@ -188,8 +174,6 @@ private void createDockerTestMedic3Bundle(Map<String, CertificateFiles> clientCe organizationMedic3thumbprintExtension.setValue(new StringType( clientCertificateFilesByCommonName.get("medic3-client").getCertificateSha512ThumbprintHex())); - removeReferenceEmbeddedResources(medic3Bundle); - writeBundle(Paths.get("bundle/medic3-bundle.xml"), medic3Bundle); } @@ -197,7 +181,7 @@ private void createDockerTestTtpBundle(Map<String, CertificateFiles> clientCerti { Path medic3BundleTemplateFile = Paths.get("src/main/resources/bundle-templates/ttp-bundle.xml"); - ttpBundle = readBundle(medic3BundleTemplateFile); + ttpBundle = readAndCleanBundle(medic3BundleTemplateFile); Organization organizationTtp = (Organization) ttpBundle.getEntry().get(0).getResource(); Extension organizationTtpThumbprintExtension = organizationTtp @@ -223,8 +207,6 @@ private void createDockerTestTtpBundle(Map<String, CertificateFiles> clientCerti organizationMedic3thumbprintExtension.setValue(new StringType( clientCertificateFilesByCommonName.get("medic3-client").getCertificateSha512ThumbprintHex())); - removeReferenceEmbeddedResources(ttpBundle); - writeBundle(Paths.get("bundle/ttp-bundle.xml"), ttpBundle); } diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic1-bundle.xml b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic1-bundle.xml index afabce9b2..822f1b6b7 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic1-bundle.xml +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic1-bundle.xml @@ -32,8 +32,9 @@ </Organization> </resource> <request> - <method value="PUT"/> - <url value="Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_TTP"/> + <method value="POST"/> + <url value="Organization"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_TTP"/> </request> </entry> <entry> @@ -64,8 +65,9 @@ </Organization> </resource> <request> - <method value="PUT"/> - <url value="Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_MeDIC_1"/> + <method value="POST"/> + <url value="Organization"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_MeDIC_1"/> </request> </entry> <entry> @@ -87,13 +89,9 @@ <system value="http://terminology.hl7.org/CodeSystem/endpoint-connection-type"/> <code value="hl7-fhir-rest"/> </connectionType> - <name value="Test TTP Endpoint"/> <managingOrganization> + <reference value="urn:uuid:bb73165c-c7b9-4342-8e28-531f07fa7735"/> <type value="Organization"/> - <identifier> - <system value="http://highmed.org/fhir/NamingSystem/organization-identifier"/> - <value value="Test_TTP"/> - </identifier> </managingOrganization> <payloadType> <coding> @@ -101,14 +99,13 @@ <code value="Task"/> </coding> </payloadType> - <payloadMimeType value="application/fhir+json"/> - <payloadMimeType value="application/fhir+xml"/> <address value="https://ttp/fhir"/> </Endpoint> </resource> <request> - <method value="PUT"/> - <url value="Endpoint?identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_TTP_Endpoint"/> + <method value="POST"/> + <url value="Endpoint"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_TTP_Endpoint"/> </request> </entry> </Bundle> \ No newline at end of file diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic2-bundle.xml b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic2-bundle.xml index 1a5eb6915..02e960d01 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic2-bundle.xml +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic2-bundle.xml @@ -32,8 +32,9 @@ </Organization> </resource> <request> - <method value="PUT"/> - <url value="Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_TTP"/> + <method value="POST"/> + <url value="Organization"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_TTP"/> </request> </entry> <entry> @@ -64,8 +65,9 @@ </Organization> </resource> <request> - <method value="PUT"/> - <url value="Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_MeDIC_2"/> + <method value="POST"/> + <url value="Organization"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_MeDIC_2"/> </request> </entry> <entry> @@ -87,13 +89,9 @@ <system value="http://terminology.hl7.org/CodeSystem/endpoint-connection-type"/> <code value="hl7-fhir-rest"/> </connectionType> - <name value="Test TTP Endpoint"/> <managingOrganization> + <reference value="urn:uuid:bb73165c-c7b9-4342-8e28-531f07fa7735"/> <type value="Organization"/> - <identifier> - <system value="http://highmed.org/fhir/NamingSystem/organization-identifier"/> - <value value="Test_TTP"/> - </identifier> </managingOrganization> <payloadType> <coding> @@ -101,14 +99,13 @@ <code value="Task"/> </coding> </payloadType> - <payloadMimeType value="application/fhir+json"/> - <payloadMimeType value="application/fhir+xml"/> <address value="https://ttp/fhir"/> </Endpoint> </resource> <request> - <method value="PUT"/> - <url value="Endpoint?identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_TTP_Endpoint"/> + <method value="POST"/> + <url value="Endpoint"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_TTP_Endpoint"/> </request> </entry> </Bundle> \ No newline at end of file diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic3-bundle.xml b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic3-bundle.xml index 946a1206a..b111367d6 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic3-bundle.xml +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/medic3-bundle.xml @@ -32,8 +32,9 @@ </Organization> </resource> <request> - <method value="PUT"/> - <url value="Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_TTP"/> + <method value="POST"/> + <url value="Organization"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_TTP"/> </request> </entry> <entry> @@ -64,8 +65,9 @@ </Organization> </resource> <request> - <method value="PUT"/> - <url value="Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_MeDIC_3"/> + <method value="POST"/> + <url value="Organization"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_MeDIC_3"/> </request> </entry> <entry> @@ -87,13 +89,9 @@ <system value="http://terminology.hl7.org/CodeSystem/endpoint-connection-type"/> <code value="hl7-fhir-rest"/> </connectionType> - <name value="Test TTP Endpoint"/> <managingOrganization> + <reference value="urn:uuid:bb73165c-c7b9-4342-8e28-531f07fa7735"/> <type value="Organization"/> - <identifier> - <system value="http://highmed.org/fhir/NamingSystem/organization-identifier"/> - <value value="Test_TTP"/> - </identifier> </managingOrganization> <payloadType> <coding> @@ -101,14 +99,13 @@ <code value="Task"/> </coding> </payloadType> - <payloadMimeType value="application/fhir+json"/> - <payloadMimeType value="application/fhir+xml"/> <address value="https://ttp/fhir"/> </Endpoint> </resource> <request> - <method value="PUT"/> - <url value="Endpoint?identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_TTP_Endpoint"/> + <method value="POST"/> + <url value="Endpoint"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_TTP_Endpoint"/> </request> </entry> </Bundle> \ No newline at end of file diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/test-bundle.xml b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/test-bundle.xml index bb257b0b1..7e4f18bf1 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/test-bundle.xml +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/test-bundle.xml @@ -8,7 +8,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-organization"/> </meta> <extension url="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint"> <valueString value="TODO"/> @@ -26,14 +27,15 @@ </type> <name value="Test Organization"/> <endpoint> - <type value="Endpoint"/> <reference value="urn:uuid:b879e904-d666-45de-a995-accdd4429b79"/> + <type value="Endpoint"/> </endpoint> </Organization> </resource> <request> - <method value="PUT"/> - <url value="Organization?identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_Organization"/> + <method value="POST"/> + <url value="Organization"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/organization-identifier|Test_Organization"/> </request> </entry> <entry> @@ -44,7 +46,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint"/> </meta> <identifier> <system value="http://highmed.org/fhir/NamingSystem/endpoint-identifier"/> @@ -57,8 +60,8 @@ </connectionType> <name value="Test Endpoint"/> <managingOrganization> - <type value="Organization"/> <reference value="urn:uuid:bb73165c-c7b9-4342-8e28-531f07fa7735"/> + <type value="Organization"/> </managingOrganization> <payloadType> <coding> @@ -72,8 +75,9 @@ </Endpoint> </resource> <request> - <method value="PUT"/> - <url value="Endpoint?identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_Endpoint"/> + <method value="POST"/> + <url value="Endpoint"/> + <ifNoneExist value="identifier=http://highmed.org/fhir/NamingSystem/endpoint-identifier|Test_Endpoint"/> </request> </entry> </Bundle> \ No newline at end of file diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/ttp-bundle.xml b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/ttp-bundle.xml index 5982c9796..67a9124f9 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/ttp-bundle.xml +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/bundle-templates/ttp-bundle.xml @@ -8,7 +8,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-organization"/> </meta> <extension url="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint"> <valueString value="TODO"/> @@ -44,7 +45,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-organization"/> </meta> <extension url="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint"> <valueString value="TODO"/> @@ -80,7 +82,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-organization"/> </meta> <extension url="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint"> <valueString value="TODO"/> @@ -116,7 +119,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-organization"/> </meta> <extension url="http://highmed.org/fhir/StructureDefinition/certificate-thumbprint"> <valueString value="TODO"/> @@ -152,7 +156,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint"/> </meta> <identifier> <system value="http://highmed.org/fhir/NamingSystem/endpoint-identifier"/> @@ -165,11 +170,8 @@ </connectionType> <name value="Test TTP Endpoint"/> <managingOrganization> + <reference value="urn:uuid:bb73165c-c7b9-4342-8e28-531f07fa7735"/> <type value="Organization"/> - <identifier> - <system value="http://highmed.org/fhir/NamingSystem/organization-identifier"/> - <value value="Test_TTP"/> - </identifier> </managingOrganization> <payloadType> <coding> @@ -195,7 +197,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint"/> </meta> <identifier> <system value="http://highmed.org/fhir/NamingSystem/endpoint-identifier"/> @@ -208,11 +211,8 @@ </connectionType> <name value="Test MeDIC 1 Endpoint"/> <managingOrganization> + <reference value="urn:uuid:cf62edc2-cc5d-43ed-ac0e-caf09f7326c3"/> <type value="Organization"/> - <identifier> - <system value="http://highmed.org/fhir/NamingSystem/organization-identifier"/> - <value value="Test_MeDIC_1"/> - </identifier> </managingOrganization> <payloadType> <coding> @@ -238,7 +238,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint"/> </meta> <identifier> <system value="http://highmed.org/fhir/NamingSystem/endpoint-identifier"/> @@ -251,11 +252,8 @@ </connectionType> <name value="Test MeDIC 2 Endpoint"/> <managingOrganization> + <reference value="urn:uuid:55901940-02db-40bf-9a6e-bdfdd0ddb7bf"/> <type value="Organization"/> - <identifier> - <system value="http://highmed.org/fhir/NamingSystem/organization-identifier"/> - <value value="Test_MeDIC_2"/> - </identifier> </managingOrganization> <payloadType> <coding> @@ -281,7 +279,8 @@ <tag> <system value="http://highmed.org/fhir/CodeSystem/authorization-role"/> <code value="REMOTE"/> - </tag> + </tag> + <profile value="http://highmed.org/fhir/StructureDefinition/highmed-endpoint"/> </meta> <identifier> <system value="http://highmed.org/fhir/NamingSystem/endpoint-identifier"/> @@ -294,11 +293,8 @@ </connectionType> <name value="Test MeDIC 3 Endpoint"/> <managingOrganization> + <reference value="urn:uuid:a49a45d2-88cc-4830-a028-413d68d9a439"/> <type value="Organization"/> - <identifier> - <system value="http://highmed.org/fhir/NamingSystem/organization-identifier"/> - <value value="Test_MeDIC_3"/> - </identifier> </managingOrganization> <payloadType> <coding> diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic1-fhir-config.properties b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic1-fhir-config.properties index f4d5d6f4d..61ead85de 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic1-fhir-config.properties +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic1-fhir-config.properties @@ -18,7 +18,7 @@ org.highmed.dsf.fhir.init.bundle.file=conf/bundle.xml org.highmed.dsf.fhir.webservice.keystore.p12file=conf/medic1-client_certificate.p12 org.highmed.dsf.fhir.webservice.keystore.password=password -org.highmed.dsf.fhir.remote.webservice.readTimeout=5000 +org.highmed.dsf.fhir.remote.webservice.readTimeout=10000 org.highmed.dsf.fhir.remote.webservice.connectTimeout=2000 org.highmed.dsf.fhir.cors.origins=http://localhost:8080 \ No newline at end of file diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic2-fhir-config.properties b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic2-fhir-config.properties index 9a31cd851..5a798dcc4 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic2-fhir-config.properties +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic2-fhir-config.properties @@ -18,7 +18,7 @@ org.highmed.dsf.fhir.init.bundle.file=conf/bundle.xml org.highmed.dsf.fhir.webservice.keystore.p12file=conf/medic2-client_certificate.p12 org.highmed.dsf.fhir.webservice.keystore.password=password -org.highmed.dsf.fhir.remote.webservice.readTimeout=5000 +org.highmed.dsf.fhir.remote.webservice.readTimeout=10000 org.highmed.dsf.fhir.remote.webservice.connectTimeout=2000 org.highmed.dsf.fhir.cors.origins=http://localhost:8080 \ No newline at end of file diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic3-fhir-config.properties b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic3-fhir-config.properties index a373390f0..5b4f939ee 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic3-fhir-config.properties +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-medic3-fhir-config.properties @@ -18,7 +18,7 @@ org.highmed.dsf.fhir.init.bundle.file=conf/bundle.xml org.highmed.dsf.fhir.webservice.keystore.p12file=conf/medic3-client_certificate.p12 org.highmed.dsf.fhir.webservice.keystore.password=password -org.highmed.dsf.fhir.remote.webservice.readTimeout=5000 +org.highmed.dsf.fhir.remote.webservice.readTimeout=10000 org.highmed.dsf.fhir.remote.webservice.connectTimeout=2000 org.highmed.dsf.fhir.cors.origins=http://localhost:8080 \ No newline at end of file diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-ttp-fhir-config.properties b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-ttp-fhir-config.properties index a2592c9e7..6fd0647c4 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-ttp-fhir-config.properties +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/config-templates/docker-test-ttp-fhir-config.properties @@ -18,7 +18,7 @@ org.highmed.dsf.fhir.init.bundle.file=conf/bundle.xml org.highmed.dsf.fhir.webservice.keystore.p12file=conf/ttp-client_certificate.p12 org.highmed.dsf.fhir.webservice.keystore.password=password -org.highmed.dsf.fhir.remote.webservice.readTimeout=5000 +org.highmed.dsf.fhir.remote.webservice.readTimeout=10000 org.highmed.dsf.fhir.remote.webservice.connectTimeout=2000 org.highmed.dsf.fhir.cors.origins=http://localhost:8080 \ No newline at end of file diff --git a/dsf-tools/pom.xml b/dsf-tools/pom.xml index 29583a31e..ae8a6abb9 100755 --- a/dsf-tools/pom.xml +++ b/dsf-tools/pom.xml @@ -8,7 +8,7 @@ <parent> <groupId>org.highmed.dsf</groupId> <artifactId>dsf-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> </parent> <modules> diff --git a/pom.xml b/pom.xml index a1dd330dc..4ad5e82fc 100755 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ <groupId>org.highmed.dsf</groupId> <artifactId>dsf-pom</artifactId> - <version>0.1.0</version> + <version>0.2.0</version> <packaging>pom</packaging> <modules> @@ -13,6 +13,7 @@ <module>dsf-tools</module> <module>dsf-openehr</module> <module>dsf-pseudonymization</module> + <module>dsf-mpi</module> </modules> <properties> @@ -21,14 +22,15 @@ <compileTarget>11</compileTarget> <slf4j.version>1.8.0-beta4</slf4j.version> - <log4j.version>2.13.0</log4j.version> + <log4j.version>2.13.3</log4j.version> - <jetty.version>9.4.26.v20200117</jetty.version> - <jersey.version>2.30.1</jersey.version> - <tyrus.version>1.15</tyrus.version> - <spring.version>5.2.3.RELEASE</spring.version> + <jetty.version>9.4.30.v20200611</jetty.version> + <jersey.version>2.31</jersey.version> + <tyrus.version>1.17</tyrus.version> + <spring.version>5.2.7.RELEASE</spring.version> - <hapi.version>4.2.0</hapi.version> + <hapi.fhir.version>5.0.2</hapi.fhir.version> + <hapi.hl7v2.version>2.3</hapi.hl7v2.version> </properties> <name>highmed-dsf</name> @@ -82,6 +84,18 @@ <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> </dependency> + <!-- async logging --> + <dependency> + <groupId>com.lmax</groupId> + <artifactId>disruptor</artifactId> + <version>3.4.2</version> + </dependency> + <!-- smtp appender --> + <dependency> + <groupId>javax.mail</groupId> + <artifactId>mail</artifactId> + <version>1.4.7</version> + </dependency> <!-- testing --> <dependency> @@ -92,7 +106,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>3.1.0</version> + <version>3.3.3</version> </dependency> <!-- database --> @@ -104,34 +118,34 @@ <dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> - <version>3.8.7</version> + <version>3.10.0</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> - <version>42.2.10</version> + <version>42.2.14</version> </dependency> <!-- hhn rwh --> <dependency> <groupId>de.hs-heilbronn.mi</groupId> <artifactId>jetty-utils</artifactId> - <version>0.6.0</version> + <version>0.8.0</version> </dependency> <dependency> <groupId>de.hs-heilbronn.mi</groupId> <artifactId>crypto-utils</artifactId> - <version>2.4.0</version> + <version>2.6.0</version> </dependency> <dependency> <groupId>de.hs-heilbronn.mi</groupId> <artifactId>log4j2-utils</artifactId> - <version>0.5.0</version> + <version>0.7.0</version> </dependency> <dependency> <groupId>de.hs-heilbronn.mi</groupId> <artifactId>db-test-utils</artifactId> - <version>0.6.0</version> + <version>0.8.0</version> </dependency> <dependency> @@ -181,6 +195,11 @@ <artifactId>jersey-media-json-jackson</artifactId> <version>${jersey.version}</version> </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>2.11.1</version> + </dependency> <!-- tyrus --> <dependency> @@ -198,7 +217,7 @@ <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> - <version>2.3.2</version> + <version>2.3.3</version> </dependency> <!-- spring --> @@ -249,32 +268,55 @@ <dependency> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-fhir-jaxrsserver-base</artifactId> - <version>${hapi.version}</version> + <version>${hapi.fhir.version}</version> </dependency> <dependency> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-fhir-client</artifactId> - <version>${hapi.version}</version> + <version>${hapi.fhir.version}</version> </dependency> <dependency> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-fhir-structures-r4</artifactId> - <version>${hapi.version}</version> + <version>${hapi.fhir.version}</version> + </dependency> + <dependency> + <groupId>ca.uhn.hapi.fhir</groupId> + <artifactId>hapi-fhir-structures-r5</artifactId> + <version>${hapi.fhir.version}</version> </dependency> <dependency> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-fhir-validation</artifactId> - <version>${hapi.version}</version> + <version>${hapi.fhir.version}</version> </dependency> <dependency> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-fhir-validation-resources-r4</artifactId> - <version>${hapi.version}</version> + <version>${hapi.fhir.version}</version> </dependency> <dependency> - <groupId>com.helger</groupId> - <artifactId>ph-schematron</artifactId> - <version>5.2.0</version> + <groupId>ca.uhn.hapi.fhir</groupId> + <artifactId>hapi-fhir-validation-resources-r5</artifactId> + <version>${hapi.fhir.version}</version> + </dependency> + + <!-- HL7 V2 --> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-base</artifactId> + <version>${hapi.hl7v2.version}</version> + </dependency> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-structures-v25</artifactId> + <version>${hapi.hl7v2.version}</version> + </dependency> + + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-csv</artifactId> + <version>1.8</version> </dependency> </dependencies> </dependencyManagement> @@ -311,7 +353,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> - <version>3.2.3</version> + <version>3.3.0</version> <configuration> <archive> <manifest> @@ -328,27 +370,27 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> - <version>3.2.0</version> + <version>3.2.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> - <version>3.1.1</version> + <version>3.2.0</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> - <version>3.0.0-M4</version> + <version>3.0.0-M5</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> - <version>3.2.2</version> + <version>3.2.4</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> - <version>3.2.0</version> + <version>3.3.0</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -363,7 +405,7 @@ <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> - <version>1.6.0</version> + <version>3.0.0</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId>