Lots of work on new subscription model

This commit is contained in:
James Agnew 2017-09-13 19:05:29 -07:00
parent 415f2bc72d
commit 97b44965ce
19 changed files with 92449 additions and 92425 deletions

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.igpacks.parser; package ca.uhn.fhir.igpacks.parser;
/*-
* #%L
* hapi-fhir-igpacks
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* 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.
* #L%
*/
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.igpacks.parser; package ca.uhn.fhir.igpacks.parser;
/*-
* #%L
* hapi-fhir-igpacks
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* 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.
* #L%
*/
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport; import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
import org.hl7.fhir.dstu3.model.CodeSystem; import org.hl7.fhir.dstu3.model.CodeSystem;

View File

@ -28,9 +28,9 @@ import java.util.List;
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -28,9 +28,9 @@ import java.util.List;
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -169,9 +169,8 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
@PostConstruct @PostConstruct
public void postConstruct() { public void postConstruct() {
{ if (getProcessingChannel() == null) {
myProcessingExecutorQueue = new LinkedBlockingQueue<>(1000); myProcessingExecutorQueue = new LinkedBlockingQueue<>(1000);
RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() { RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
@Override @Override
public void rejectedExecution(Runnable theRunnable, ThreadPoolExecutor theExecutor) { public void rejectedExecution(Runnable theRunnable, ThreadPoolExecutor theExecutor) {
@ -199,15 +198,17 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
myProcessingExecutorQueue, myProcessingExecutorQueue,
threadFactory, threadFactory,
rejectedExecutionHandler); rejectedExecutionHandler);
setProcessingChannel(new ExecutorSubscribableChannel(myProcessingExecutor));
} }
{
if (getDeliveryChannel() == null) {
myDeliveryExecutorQueue = new LinkedBlockingQueue<>(1000); myDeliveryExecutorQueue = new LinkedBlockingQueue<>(1000);
BasicThreadFactory threadFactory = new BasicThreadFactory.Builder() BasicThreadFactory threadFactory = new BasicThreadFactory.Builder()
.namingPattern("subscription-delivery-%d") .namingPattern("subscription-delivery-%d")
.daemon(false) .daemon(false)
.priority(Thread.NORM_PRIORITY) .priority(Thread.NORM_PRIORITY)
.build(); .build();
RejectedExecutionHandler rejectedExecutionHandler2 = new RejectedExecutionHandler() { RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
@Override @Override
public void rejectedExecution(Runnable theRunnable, ThreadPoolExecutor theExecutor) { public void rejectedExecution(Runnable theRunnable, ThreadPoolExecutor theExecutor) {
ourLog.info("Note: Executor queue is full ({} elements), waiting for a slot to become available!", myDeliveryExecutorQueue.size()); ourLog.info("Note: Executor queue is full ({} elements), waiting for a slot to become available!", myDeliveryExecutorQueue.size());
@ -228,35 +229,30 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
TimeUnit.MILLISECONDS, TimeUnit.MILLISECONDS,
myDeliveryExecutorQueue, myDeliveryExecutorQueue,
threadFactory, threadFactory,
rejectedExecutionHandler2); rejectedExecutionHandler);
}
if (getProcessingChannel() == null) {
setProcessingChannel(new ExecutorSubscribableChannel(myProcessingExecutor));
}
if (getDeliveryChannel() == null) {
setDeliveryChannel(new ExecutorSubscribableChannel(myDeliveryExecutor)); setDeliveryChannel(new ExecutorSubscribableChannel(myDeliveryExecutor));
} }
if (mySubscriptionActivatingSubscriber == null) { if (mySubscriptionActivatingSubscriber == null) {
mySubscriptionActivatingSubscriber = new SubscriptionActivatingSubscriber(getSubscriptionDao(), getChannelType(), this); mySubscriptionActivatingSubscriber = new SubscriptionActivatingSubscriber(getSubscriptionDao(), getChannelType(), this);
} }
getProcessingChannel().subscribe(mySubscriptionActivatingSubscriber);
if (mySubscriptionCheckingSubscriber == null) {
mySubscriptionCheckingSubscriber = new SubscriptionCheckingSubscriber(getSubscriptionDao(), getChannelType(), this);
}
getProcessingChannel().subscribe(mySubscriptionCheckingSubscriber);
registerSubscriptionCheckingSubscriber();
registerDeliverySubscriber(); registerDeliverySubscriber();
initSubscriptions(); initSubscriptions();
} }
protected void registerSubscriptionCheckingSubscriber() {
if (mySubscriptionCheckingSubscriber == null) {
mySubscriptionCheckingSubscriber = new SubscriptionCheckingSubscriber(getSubscriptionDao(), getChannelType(), this);
}
getProcessingChannel().subscribe(mySubscriptionCheckingSubscriber);
}
@SuppressWarnings("unused") @SuppressWarnings("unused")
@PreDestroy @PreDestroy
public void preDestroy() { public void preDestroy() {
getProcessingChannel().unsubscribe(mySubscriptionActivatingSubscriber);
getProcessingChannel().unsubscribe(mySubscriptionCheckingSubscriber); getProcessingChannel().unsubscribe(mySubscriptionCheckingSubscriber);
unregisterDeliverySubscriber(); unregisterDeliverySubscriber();
@ -298,16 +294,10 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
submitResourceModified(msg); submitResourceModified(msg);
} }
private void submitResourceModified(final ResourceModifiedMessage theMsg) { protected void submitResourceModified(final ResourceModifiedMessage theMsg) {
/* final GenericMessage<ResourceModifiedMessage> message = new GenericMessage<>(theMsg);
* We only actually submit this item work working after the mySubscriptionActivatingSubscriber.handleMessage(message);
*/ getProcessingChannel().send(message);
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
getProcessingChannel().send(new GenericMessage<>(theMsg));
}
});
} }
protected abstract void unregisterDeliverySubscriber(); protected abstract void unregisterDeliverySubscriber();

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.subscription; package ca.uhn.fhir.jpa.subscription;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* 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.
* #L%
*/
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;

View File

@ -50,7 +50,7 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseSubscriptionRestHo
try { try {
retVal.setStatus(org.hl7.fhir.r4.model.Subscription.SubscriptionStatus.fromCode(subscription.getStatus())); retVal.setStatus(org.hl7.fhir.r4.model.Subscription.SubscriptionStatus.fromCode(subscription.getStatus()));
retVal.setBackingSubscription(theSubscription); retVal.setBackingSubscription(theSubscription);
retVal.setChannelType(org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType.fromCode(subscription.getStatus())); retVal.setChannelType(org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType.fromCode(subscription.getChannel().getType()));
retVal.setCriteriaString(subscription.getCriteria()); retVal.setCriteriaString(subscription.getCriteria());
retVal.setEndpointUrl(subscription.getChannel().getEndpoint()); retVal.setEndpointUrl(subscription.getChannel().getEndpoint());
retVal.setHeaders(subscription.getChannel().getHeader()); retVal.setHeaders(subscription.getChannel().getHeader());

View File

@ -62,7 +62,7 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseSubscriptionRestHo
try { try {
retVal.setStatus(org.hl7.fhir.r4.model.Subscription.SubscriptionStatus.fromCode(subscription.getStatus().toCode())); retVal.setStatus(org.hl7.fhir.r4.model.Subscription.SubscriptionStatus.fromCode(subscription.getStatus().toCode()));
retVal.setBackingSubscription(theSubscription); retVal.setBackingSubscription(theSubscription);
retVal.setChannelType(org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType.fromCode(subscription.getStatus().toCode())); retVal.setChannelType(org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType.fromCode(subscription.getChannel().getType().toCode()));
retVal.setCriteriaString(subscription.getCriteria()); retVal.setCriteriaString(subscription.getCriteria());
retVal.setEndpointUrl(subscription.getChannel().getEndpoint()); retVal.setEndpointUrl(subscription.getChannel().getEndpoint());
retVal.setHeaders(subscription.getChannel().getHeader()); retVal.setHeaders(subscription.getChannel().getHeader());

View File

@ -86,10 +86,7 @@ public class RestHookSubscriptionR4Interceptor extends BaseSubscriptionRestHookI
} }
EventDefinition def = theEventDefinitionDao.read(ref.getReferenceElement()); EventDefinition def = theEventDefinitionDao.read(ref.getReferenceElement());
for (TriggerDefinition next : def.getTrigger()) { retVal.addTrigger(def.getTrigger());
retVal.addTrigger(next);
}
} }
return retVal; return retVal;

View File

@ -34,9 +34,13 @@ public class WebSocketSubscriptionR4Interceptor extends BaseSubscriptionWebsocke
@Qualifier("mySubscriptionDaoR4") @Qualifier("mySubscriptionDaoR4")
private IFhirResourceDao<org.hl7.fhir.r4.model.Subscription> mySubscriptionDao; private IFhirResourceDao<org.hl7.fhir.r4.model.Subscription> mySubscriptionDao;
@Autowired
@Qualifier("myEventDefinitionDaoR4")
private IFhirResourceDao<org.hl7.fhir.r4.model.EventDefinition> myEventDefinitionDao;
@Override @Override
protected CanonicalSubscription canonicalize(IBaseResource theSubscription) { protected CanonicalSubscription canonicalize(IBaseResource theSubscription) {
return RestHookSubscriptionR4Interceptor.doCanonicalize(theSubscription); return RestHookSubscriptionR4Interceptor.doCanonicalize(theSubscription, myEventDefinitionDao);
} }
@Override @Override

View File

@ -47,9 +47,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -50,9 +50,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -6,6 +6,7 @@ import static org.junit.Assert.*;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import java.io.IOException;
import java.util.*; import java.util.*;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@ -80,7 +81,24 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
} }
} }
@Test
public void testSaveAndReturnCollectionBundle() throws IOException {
String input = IOUtils.toString(FhirResourceDaoR4Test.class.getResourceAsStream("/r4/collection-bundle.json"));
Bundle inputBundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
myBundleDao.update(inputBundle);
Bundle outputBundle = myBundleDao.read(new IdType("cftest"));
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(outputBundle));
for (BundleEntryComponent next : outputBundle.getEntry()) {
assertTrue(next.getResource().getIdElement().hasIdPart());
}
}
@Before @Before
public void beforeDisableResultReuse() { public void beforeDisableResultReuse() {
myDaoConfig.setReuseCachedSearchResultsForMillis(null); myDaoConfig.setReuseCachedSearchResultsForMillis(null);

View File

@ -3,20 +3,17 @@ package ca.uhn.fhir.jpa.subscription.r4;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test; import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test;
import ca.uhn.fhir.jpa.subscription.SocketImplementation; import ca.uhn.fhir.jpa.subscription.SocketImplementation;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import org.eclipse.jetty.websocket.api.Session; import com.google.common.collect.Lists;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; import org.hl7.fhir.instance.model.api.IIdType;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.*;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger; import org.slf4j.Logger;
import java.net.URI; import java.util.ArrayList;
import java.util.concurrent.Future; import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -41,32 +38,53 @@ import static org.junit.Assert.*;
public class FhirSubscriptionWithEventDefinitionR4Test extends BaseResourceProviderR4Test { public class FhirSubscriptionWithEventDefinitionR4Test extends BaseResourceProviderR4Test {
private static final Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSubscriptionWithEventDefinitionR4Test.class); private static final Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSubscriptionWithEventDefinitionR4Test.class);
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
private static List<String> ourContentTypes = new ArrayList<>();
private static List<String> ourHeaders = new ArrayList<>();
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
private String myPatientId; private String myPatientId;
private String mySubscriptionId; private String mySubscriptionId;
private WebSocketClient myWebSocketClient; private List<IIdType> mySubscriptionIds = new ArrayList<>();
private SocketImplementation mySocketImplementation;
@Override @Override
@After @After
public void after() throws Exception { public void after() throws Exception {
super.after(); super.after();
myDaoConfig.setSubscriptionEnabled(new DaoConfig().isSubscriptionEnabled()); myDaoConfig.setSubscriptionEnabled(new DaoConfig().isSubscriptionEnabled());
myDaoConfig.setSubscriptionPollDelay(new DaoConfig().getSubscriptionPollDelay());
} }
@After
public void afterUnregisterRestHookListener() {
for (IIdType next : mySubscriptionIds) {
ourClient.delete().resourceById(next).execute();
}
mySubscriptionIds.clear();
myDaoConfig.setAllowMultipleDelete(true);
ourLog.info("Deleting all subscriptions");
ourClient.delete().resourceConditionalByUrl("Subscription?status=active").execute();
ourClient.delete().resourceConditionalByUrl("Observation?code:missing=false").execute();
ourLog.info("Done deleting all subscriptions");
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
ourRestServer.unregisterInterceptor(getRestHookSubscriptionInterceptor());
}
@Override @Override
@Before @Before
public void before() throws Exception { public void before() throws Exception {
super.before(); super.before();
myDaoConfig.setSubscriptionEnabled(true); myDaoConfig.setSubscriptionEnabled(true);
myDaoConfig.setSubscriptionPollDelay(0L);
}
@Test
public void testSubscriptionAddedTrigger() {
/* /*
* Create patient * Create patient
*/ */
Patient patient = FhirR4Util.getPatient(); Patient patient = FhirR4Util.getPatient();
MethodOutcome methodOutcome = ourClient.create().resource(patient).execute(); MethodOutcome methodOutcome = ourClient.create().resource(patient).execute();
myPatientId = methodOutcome.getId().getIdPart(); myPatientId = methodOutcome.getId().getIdPart();
@ -76,9 +94,18 @@ public class FhirSubscriptionWithEventDefinitionR4Test extends BaseResourceProvi
*/ */
EventDefinition eventDef = new EventDefinition(); EventDefinition eventDef = new EventDefinition();
eventDef
.setPurpose("Monitor all admissions to Emergency")
.setTrigger(new TriggerDefinition()
.setType(TriggerDefinition.TriggerType.DATAADDED)
.setEventCondition(new TriggerDefinition.TriggerDefinitionEventConditionComponent()
.setDescription("Encounter Location = emergency (active/completed encounters, current or previous)")
.setLanguage("text/fhirpath")
.setExpression("(this | %previous).location.where(location = 'Location/emergency' and status in {'active', 'completed'}).exists()")
)
);
*/ /*
/*
* Create subscription * Create subscription
*/ */
Subscription subscription = new Subscription(); Subscription subscription = new Subscription();
@ -92,85 +119,21 @@ public class FhirSubscriptionWithEventDefinitionR4Test extends BaseResourceProvi
methodOutcome = ourClient.create().resource(subscription).execute(); methodOutcome = ourClient.create().resource(subscription).execute();
mySubscriptionId = methodOutcome.getId().getIdPart(); mySubscriptionId = methodOutcome.getId().getIdPart();
/*
* Attach websocket
*/
myWebSocketClient = new WebSocketClient();
mySocketImplementation = new SocketImplementation(mySubscriptionId, EncodingEnum.JSON);
myWebSocketClient.start();
URI echoUri = new URI("ws://localhost:" + ourPort + "/websocket/r4");
ClientUpgradeRequest request = new ClientUpgradeRequest();
ourLog.info("Connecting to : {}", echoUri);
Future<Session> connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request);
Session session = connection.get(2, TimeUnit.SECONDS);
ourLog.info("Connected to WS: {}", session.isOpen());
} }
@After @Before
public void afterCloseWebsocket() throws Exception { public void beforeRegisterRestHookListener() {
ourLog.info("Shutting down websocket client"); ourRestServer.registerInterceptor(getRestHookSubscriptionInterceptor());
myWebSocketClient.stop();
}
@Test
public void createObservation() throws Exception {
Observation observation = new Observation();
CodeableConcept codeableConcept = new CodeableConcept();
observation.setCode(codeableConcept);
Coding coding = codeableConcept.addCoding();
coding.setCode("82313006");
coding.setSystem("SNOMED-CT");
Reference reference = new Reference();
reference.setReference("Patient/" + myPatientId);
observation.setSubject(reference);
observation.setStatus(Observation.ObservationStatus.FINAL);
MethodOutcome methodOutcome2 = ourClient.create().resource(observation).execute();
String observationId = methodOutcome2.getId().getIdPart();
observation.setId(observationId);
ourLog.info("Observation id generated by server is: " + observationId);
int changes = mySubscriptionDao.pollForNewUndeliveredResources();
ourLog.info("Polling showed {}", changes);
assertEquals(1, changes);
Thread.sleep(2000);
ourLog.info("WS Messages: {}", mySocketImplementation.getMessages());
assertThat(mySocketImplementation.getMessages(), contains("bound " + mySubscriptionId, "ping " + mySubscriptionId));
} }
@Test @Before
public void createObservationThatDoesNotMatch() throws Exception { public void beforeReset() {
Observation observation = new Observation(); ourCreatedObservations.clear();
CodeableConcept codeableConcept = new CodeableConcept(); ourUpdatedObservations.clear();
observation.setCode(codeableConcept); ourContentTypes.clear();
Coding coding = codeableConcept.addCoding(); ourHeaders.clear();
coding.setCode("8231");
coding.setSystem("SNOMED-CT");
Reference reference = new Reference();
reference.setReference("Patient/" + myPatientId);
observation.setSubject(reference);
observation.setStatus(Observation.ObservationStatus.FINAL);
MethodOutcome methodOutcome2 = ourClient.create().resource(observation).execute();
String observationId = methodOutcome2.getId().getIdPart();
observation.setId(observationId);
ourLog.info("Observation id generated by server is: " + observationId);
int changes = mySubscriptionDao.pollForNewUndeliveredResources();
ourLog.info("Polling showed {}", changes);
assertEquals(0, changes);
Thread.sleep(2000);
ourLog.info("WS Messages: {}", mySocketImplementation.getMessages());
assertThat(mySocketImplementation.getMessages(), contains("bound " + mySubscriptionId));
} }
} }

View File

@ -0,0 +1,42 @@
{
"resourceType": "Bundle",
"id": "cftest",
"type": "collection",
"entry": [
{"resource": {
"resourceType": "Condition",
"text": {
"status": "generated",
"div": "<div xmlns='http://www.w3.org/1999/xhtml'><a name='mm'/><\/div>"
},
"id": "cf-1505178568463",
"subject": {"reference": "Patient/2344"},
"clinicalStatus": "active",
"code": {"coding": [{
"system": "http://snomed.info/sct",
"code": "170631002",
"display": "Asthma disturbing sleep (finding)"
}]}
}},
{"resource": {
"resourceType": "Patient",
"id": "2344",
"meta": {
"versionId": "1",
"lastUpdated": "2017-09-11T19:43:52.666+12:00"
},
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">Peter hay<\/div>"
},
"name": [{
"use": "official",
"text": "Peter hay",
"family": "hay",
"given": ["Peter"]
}],
"gender": "male",
"birthDate": "1982-10-31"
}}
]
}

View File

@ -29,7 +29,7 @@ package org.hl7.fhir.r4.model;
*/ */
// Generated on Sat, Jul 8, 2017 23:19+1000 for FHIR v3.1.0 // Generated on Fri, Aug 11, 2017 07:23+1000 for FHIR v3.1.0
import java.util.*; import java.util.*;
@ -124,11 +124,11 @@ public class EventDefinition extends MetadataResource {
/** /**
* The trigger element defines when the event occurs. * The trigger element defines when the event occurs.
*/ */
@Child(name = "trigger", type = {TriggerDefinition.class}, order=10, min=0, max=Child.MAX_UNLIMITED, modifier=false, summary=false) @Child(name = "trigger", type = {TriggerDefinition.class}, order=10, min=1, max=1, modifier=false, summary=false)
@Description(shortDefinition="\"when\" the event occurs", formalDefinition="The trigger element defines when the event occurs." ) @Description(shortDefinition="\"when\" the event occurs", formalDefinition="The trigger element defines when the event occurs." )
protected List<TriggerDefinition> trigger; protected TriggerDefinition trigger;
private static final long serialVersionUID = -809799868L; private static final long serialVersionUID = 1396769290L;
/** /**
* Constructor * Constructor
@ -140,9 +140,10 @@ public class EventDefinition extends MetadataResource {
/** /**
* Constructor * Constructor
*/ */
public EventDefinition(Enumeration<PublicationStatus> status) { public EventDefinition(Enumeration<PublicationStatus> status, TriggerDefinition trigger) {
super(); super();
this.status = status; this.status = status;
this.trigger = trigger;
} }
/** /**
@ -1221,54 +1222,25 @@ public class EventDefinition extends MetadataResource {
/** /**
* @return {@link #trigger} (The trigger element defines when the event occurs.) * @return {@link #trigger} (The trigger element defines when the event occurs.)
*/ */
public List<TriggerDefinition> getTrigger() { public TriggerDefinition getTrigger() {
if (this.trigger == null) if (this.trigger == null)
this.trigger = new ArrayList<TriggerDefinition>(); if (Configuration.errorOnAutoCreate())
throw new Error("Attempt to auto-create EventDefinition.trigger");
else if (Configuration.doAutoCreate())
this.trigger = new TriggerDefinition(); // cc
return this.trigger; return this.trigger;
} }
/**
* @return Returns a reference to <code>this</code> for easy method chaining
*/
public EventDefinition setTrigger(List<TriggerDefinition> theTrigger) {
this.trigger = theTrigger;
return this;
}
public boolean hasTrigger() { public boolean hasTrigger() {
if (this.trigger == null) return this.trigger != null && !this.trigger.isEmpty();
return false;
for (TriggerDefinition item : this.trigger)
if (!item.isEmpty())
return true;
return false;
}
public TriggerDefinition addTrigger() { //3
TriggerDefinition t = new TriggerDefinition();
if (this.trigger == null)
this.trigger = new ArrayList<TriggerDefinition>();
this.trigger.add(t);
return t;
}
public EventDefinition addTrigger(TriggerDefinition t) { //3
if (t == null)
return this;
if (this.trigger == null)
this.trigger = new ArrayList<TriggerDefinition>();
this.trigger.add(t);
return this;
} }
/** /**
* @return The first repetition of repeating field {@link #trigger}, creating it if it does not already exist * @param value {@link #trigger} (The trigger element defines when the event occurs.)
*/ */
public TriggerDefinition getTriggerFirstRep() { public EventDefinition setTrigger(TriggerDefinition value) {
if (getTrigger().isEmpty()) { this.trigger = value;
addTrigger(); return this;
}
return getTrigger().get(0);
} }
protected void listChildren(List<Property> children) { protected void listChildren(List<Property> children) {
@ -1295,7 +1267,7 @@ public class EventDefinition extends MetadataResource {
children.add(new Property("contact", "ContactDetail", "Contact details to assist a user in finding and communicating with the publisher.", 0, java.lang.Integer.MAX_VALUE, contact)); children.add(new Property("contact", "ContactDetail", "Contact details to assist a user in finding and communicating with the publisher.", 0, java.lang.Integer.MAX_VALUE, contact));
children.add(new Property("copyright", "markdown", "A copyright statement relating to the event definition and/or its contents. Copyright statements are generally legal restrictions on the use and publishing of the event definition.", 0, 1, copyright)); children.add(new Property("copyright", "markdown", "A copyright statement relating to the event definition and/or its contents. Copyright statements are generally legal restrictions on the use and publishing of the event definition.", 0, 1, copyright));
children.add(new Property("relatedArtifact", "RelatedArtifact", "Related resources such as additional documentation, justification, or bibliographic references.", 0, java.lang.Integer.MAX_VALUE, relatedArtifact)); children.add(new Property("relatedArtifact", "RelatedArtifact", "Related resources such as additional documentation, justification, or bibliographic references.", 0, java.lang.Integer.MAX_VALUE, relatedArtifact));
children.add(new Property("trigger", "TriggerDefinition", "The trigger element defines when the event occurs.", 0, java.lang.Integer.MAX_VALUE, trigger)); children.add(new Property("trigger", "TriggerDefinition", "The trigger element defines when the event occurs.", 0, 1, trigger));
} }
@Override @Override
@ -1323,7 +1295,7 @@ public class EventDefinition extends MetadataResource {
case 951526432: /*contact*/ return new Property("contact", "ContactDetail", "Contact details to assist a user in finding and communicating with the publisher.", 0, java.lang.Integer.MAX_VALUE, contact); case 951526432: /*contact*/ return new Property("contact", "ContactDetail", "Contact details to assist a user in finding and communicating with the publisher.", 0, java.lang.Integer.MAX_VALUE, contact);
case 1522889671: /*copyright*/ return new Property("copyright", "markdown", "A copyright statement relating to the event definition and/or its contents. Copyright statements are generally legal restrictions on the use and publishing of the event definition.", 0, 1, copyright); case 1522889671: /*copyright*/ return new Property("copyright", "markdown", "A copyright statement relating to the event definition and/or its contents. Copyright statements are generally legal restrictions on the use and publishing of the event definition.", 0, 1, copyright);
case 666807069: /*relatedArtifact*/ return new Property("relatedArtifact", "RelatedArtifact", "Related resources such as additional documentation, justification, or bibliographic references.", 0, java.lang.Integer.MAX_VALUE, relatedArtifact); case 666807069: /*relatedArtifact*/ return new Property("relatedArtifact", "RelatedArtifact", "Related resources such as additional documentation, justification, or bibliographic references.", 0, java.lang.Integer.MAX_VALUE, relatedArtifact);
case -1059891784: /*trigger*/ return new Property("trigger", "TriggerDefinition", "The trigger element defines when the event occurs.", 0, java.lang.Integer.MAX_VALUE, trigger); case -1059891784: /*trigger*/ return new Property("trigger", "TriggerDefinition", "The trigger element defines when the event occurs.", 0, 1, trigger);
default: return super.getNamedProperty(_hash, _name, _checkValid); default: return super.getNamedProperty(_hash, _name, _checkValid);
} }
@ -1354,7 +1326,7 @@ public class EventDefinition extends MetadataResource {
case 951526432: /*contact*/ return this.contact == null ? new Base[0] : this.contact.toArray(new Base[this.contact.size()]); // ContactDetail case 951526432: /*contact*/ return this.contact == null ? new Base[0] : this.contact.toArray(new Base[this.contact.size()]); // ContactDetail
case 1522889671: /*copyright*/ return this.copyright == null ? new Base[0] : new Base[] {this.copyright}; // MarkdownType case 1522889671: /*copyright*/ return this.copyright == null ? new Base[0] : new Base[] {this.copyright}; // MarkdownType
case 666807069: /*relatedArtifact*/ return this.relatedArtifact == null ? new Base[0] : this.relatedArtifact.toArray(new Base[this.relatedArtifact.size()]); // RelatedArtifact case 666807069: /*relatedArtifact*/ return this.relatedArtifact == null ? new Base[0] : this.relatedArtifact.toArray(new Base[this.relatedArtifact.size()]); // RelatedArtifact
case -1059891784: /*trigger*/ return this.trigger == null ? new Base[0] : this.trigger.toArray(new Base[this.trigger.size()]); // TriggerDefinition case -1059891784: /*trigger*/ return this.trigger == null ? new Base[0] : new Base[] {this.trigger}; // TriggerDefinition
default: return super.getProperty(hash, name, checkValid); default: return super.getProperty(hash, name, checkValid);
} }
@ -1431,7 +1403,7 @@ public class EventDefinition extends MetadataResource {
this.getRelatedArtifact().add(castToRelatedArtifact(value)); // RelatedArtifact this.getRelatedArtifact().add(castToRelatedArtifact(value)); // RelatedArtifact
return value; return value;
case -1059891784: // trigger case -1059891784: // trigger
this.getTrigger().add(castToTriggerDefinition(value)); // TriggerDefinition this.trigger = castToTriggerDefinition(value); // TriggerDefinition
return value; return value;
default: return super.setProperty(hash, name, value); default: return super.setProperty(hash, name, value);
} }
@ -1486,7 +1458,7 @@ public class EventDefinition extends MetadataResource {
} else if (name.equals("relatedArtifact")) { } else if (name.equals("relatedArtifact")) {
this.getRelatedArtifact().add(castToRelatedArtifact(value)); this.getRelatedArtifact().add(castToRelatedArtifact(value));
} else if (name.equals("trigger")) { } else if (name.equals("trigger")) {
this.getTrigger().add(castToTriggerDefinition(value)); this.trigger = castToTriggerDefinition(value); // TriggerDefinition
} else } else
return super.setProperty(name, value); return super.setProperty(name, value);
return value; return value;
@ -1517,7 +1489,7 @@ public class EventDefinition extends MetadataResource {
case 951526432: return addContact(); case 951526432: return addContact();
case 1522889671: return getCopyrightElement(); case 1522889671: return getCopyrightElement();
case 666807069: return addRelatedArtifact(); case 666807069: return addRelatedArtifact();
case -1059891784: return addTrigger(); case -1059891784: return getTrigger();
default: return super.makeProperty(hash, name); default: return super.makeProperty(hash, name);
} }
@ -1624,7 +1596,8 @@ public class EventDefinition extends MetadataResource {
return addRelatedArtifact(); return addRelatedArtifact();
} }
else if (name.equals("trigger")) { else if (name.equals("trigger")) {
return addTrigger(); this.trigger = new TriggerDefinition();
return this.trigger;
} }
else else
return super.addChild(name); return super.addChild(name);
@ -1688,11 +1661,7 @@ public class EventDefinition extends MetadataResource {
for (RelatedArtifact i : relatedArtifact) for (RelatedArtifact i : relatedArtifact)
dst.relatedArtifact.add(i.copy()); dst.relatedArtifact.add(i.copy());
}; };
if (trigger != null) { dst.trigger = trigger == null ? null : trigger.copy();
dst.trigger = new ArrayList<TriggerDefinition>();
for (TriggerDefinition i : trigger)
dst.trigger.add(i.copy());
};
return dst; return dst;
} }