diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoComposition.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoComposition.java index 0025d608859..e9e17007b23 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoComposition.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoComposition.java @@ -19,9 +19,9 @@ import javax.servlet.http.HttpServletRequest; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCompositionDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCompositionDstu3.java index f1c719352b5..12781bccd86 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCompositionDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoCompositionDstu3.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao.dstu3; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderCompositionDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderCompositionDstu2.java index 17d9585d968..f568919ff67 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderCompositionDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderCompositionDstu2.java @@ -29,9 +29,9 @@ import org.springframework.http.ResponseEntity; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderCompositionDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderCompositionDstu3.java index 12fe396dbd8..871d05d7fe6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderCompositionDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/BaseJpaResourceProviderCompositionDstu3.java @@ -31,9 +31,9 @@ import java.util.List; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderCompositionR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderCompositionR4.java index a48cc0efdbd..ca98bb6834d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderCompositionR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderCompositionR4.java @@ -29,9 +29,9 @@ import java.util.List; * 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. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/BaseSubscriptionInterceptor.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/BaseSubscriptionInterceptor.java index 019bf8e66b8..0e04cd4d082 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/BaseSubscriptionInterceptor.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/BaseSubscriptionInterceptor.java @@ -339,54 +339,64 @@ public abstract class BaseSubscriptionInterceptor exten return new ArrayList<>(myIdToSubscription.values()); } - public boolean hasSubscription(IIdType theId) { + public CanonicalSubscription hasSubscription(IIdType theId) { Validate.notNull(theId); Validate.notBlank(theId.getIdPart()); - return myIdToSubscription.containsKey(theId.getIdPart()); + return myIdToSubscription.get(theId.getIdPart()); } /** * Read the existing subscriptions from the database */ @SuppressWarnings("unused") - @Scheduled(fixedDelay = 10000) + @Scheduled(fixedDelay = 60000) public void initSubscriptions() { if (!myInitSubscriptionsSemaphore.tryAcquire()) { return; } try { - ourLog.debug("Starting init subscriptions"); - SearchParameterMap map = new SearchParameterMap(); - map.add(Subscription.SP_TYPE, new TokenParam(null, getChannelType().toCode())); - map.add(Subscription.SP_STATUS, new TokenOrListParam() - .addOr(new TokenParam(null, Subscription.SubscriptionStatus.REQUESTED.toCode())) - .addOr(new TokenParam(null, Subscription.SubscriptionStatus.ACTIVE.toCode()))); - map.setLoadSynchronousUpTo(MAX_SUBSCRIPTION_RESULTS); - - RequestDetails req = new ServletSubRequestDetails(); - req.setSubRequest(true); - - IBundleProvider subscriptionBundleList = getSubscriptionDao().search(map, req); - if (subscriptionBundleList.size() >= MAX_SUBSCRIPTION_RESULTS) { - ourLog.error("Currently over " + MAX_SUBSCRIPTION_RESULTS + " subscriptions. Some subscriptions have not been loaded."); - } - - List resourceList = subscriptionBundleList.getResources(0, subscriptionBundleList.size()); - - Set allIds = new HashSet<>(); - for (IBaseResource resource : resourceList) { - String nextId = resource.getIdElement().getIdPart(); - allIds.add(nextId); - mySubscriptionActivatingSubscriber.activateOrRegisterSubscriptionIfRequired(resource); - } - - unregisterAllSubscriptionsNotInCollection(allIds); - ourLog.trace("Finished init subscriptions - found {}", resourceList.size()); + doInitSubscriptions(); } finally { myInitSubscriptionsSemaphore.release(); } } + public Integer doInitSubscriptions() { + ourLog.debug("Starting init subscriptions"); + SearchParameterMap map = new SearchParameterMap(); + map.add(Subscription.SP_TYPE, new TokenParam(null, getChannelType().toCode())); + map.add(Subscription.SP_STATUS, new TokenOrListParam() + .addOr(new TokenParam(null, Subscription.SubscriptionStatus.REQUESTED.toCode())) + .addOr(new TokenParam(null, Subscription.SubscriptionStatus.ACTIVE.toCode()))); + map.setLoadSynchronousUpTo(MAX_SUBSCRIPTION_RESULTS); + + RequestDetails req = new ServletSubRequestDetails(); + req.setSubRequest(true); + + IBundleProvider subscriptionBundleList = getSubscriptionDao().search(map, req); + if (subscriptionBundleList.size() >= MAX_SUBSCRIPTION_RESULTS) { + ourLog.error("Currently over " + MAX_SUBSCRIPTION_RESULTS + " subscriptions. Some subscriptions have not been loaded."); + } + + List resourceList = subscriptionBundleList.getResources(0, subscriptionBundleList.size()); + + Set allIds = new HashSet<>(); + int changesCount = 0; + for (IBaseResource resource : resourceList) { + String nextId = resource.getIdElement().getIdPart(); + allIds.add(nextId); + boolean changed = mySubscriptionActivatingSubscriber.activateOrRegisterSubscriptionIfRequired(resource); + if (changed) { + changesCount++; + } + } + + unregisterAllSubscriptionsNotInCollection(allIds); + ourLog.trace("Finished init subscriptions - found {}", resourceList.size()); + + return changesCount; + } + @SuppressWarnings("unused") @PreDestroy public void preDestroy() { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/CanonicalSubscription.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/CanonicalSubscription.java index dd21add9ed4..8115ff8309e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/CanonicalSubscription.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/CanonicalSubscription.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.subscription; * 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. @@ -72,18 +72,6 @@ public class CanonicalSubscription implements Serializable { myTrigger = theTrigger; } - @Override - public boolean equals(Object theO) { - if (this == theO) return true; - - if (theO == null || getClass() != theO.getClass()) return false; - - CanonicalSubscription that = (CanonicalSubscription) theO; - - return new EqualsBuilder() - .append(getIdElementString(), that.getIdElementString()) - .isEquals(); - } public Subscription.SubscriptionChannelType getChannelType() { return myChannelType; @@ -120,6 +108,15 @@ public class CanonicalSubscription implements Serializable { return myHeaders; } + public void setHeaders(List> theHeader) { + myHeaders = new ArrayList<>(); + for (IPrimitiveType next : theHeader) { + if (isNotBlank(next.getValueAsString())) { + myHeaders.add(next.getValueAsString()); + } + } + } + public void setHeaders(String theHeaders) { myHeaders = new ArrayList<>(); if (isNotBlank(theHeaders)) { @@ -171,19 +168,41 @@ public class CanonicalSubscription implements Serializable { } @Override - public int hashCode() { - return new HashCodeBuilder(17, 37) - .append(getIdElementString()) - .toHashCode(); + public boolean equals(Object theO) { + if (this == theO) return true; + + if (theO == null || getClass() != theO.getClass()) return false; + + CanonicalSubscription that = (CanonicalSubscription) theO; + + EqualsBuilder b = new EqualsBuilder(); + b.append(myIdElement, that.myIdElement); + b.append(myCriteriaString, that.myCriteriaString); + b.append(myEndpointUrl, that.myEndpointUrl); + b.append(myPayloadString, that.myPayloadString); + b.append(myHeaders, that.myHeaders); + b.append(myChannelType, that.myChannelType); + b.append(myStatus, that.myStatus); + b.append(myTrigger, that.myTrigger); + b.append(myEmailDetails, that.myEmailDetails); + b.append(myRestHookDetails, that.myRestHookDetails); + return b.isEquals(); } - public void setHeaders(List> theHeader) { - myHeaders = new ArrayList<>(); - for (IPrimitiveType next : theHeader) { - if (isNotBlank(next.getValueAsString())) { - myHeaders.add(next.getValueAsString()); - } - } + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(myIdElement) + .append(myCriteriaString) + .append(myEndpointUrl) + .append(myPayloadString) + .append(myHeaders) + .append(myChannelType) + .append(myStatus) + .append(myTrigger) + .append(myEmailDetails) + .append(myRestHookDetails) + .toHashCode(); } public void setIdElement(IIdType theIdElement) { @@ -234,6 +253,28 @@ public class CanonicalSubscription implements Serializable { myDeliverLatestVersion = theDeliverLatestVersion; } + @Override + public boolean equals(Object theO) { + if (this == theO) return true; + + if (theO == null || getClass() != theO.getClass()) return false; + + RestHookDetails that = (RestHookDetails) theO; + + return new EqualsBuilder() + .append(myStripVersionId, that.myStripVersionId) + .append(myDeliverLatestVersion, that.myDeliverLatestVersion) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(myStripVersionId) + .append(myDeliverLatestVersion) + .toHashCode(); + } + public boolean isStripVersionId() { return myStripVersionId; } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionActivatingSubscriber.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionActivatingSubscriber.java index 24fb1bccf89..fba4f162aef 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionActivatingSubscriber.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionActivatingSubscriber.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.subscription; * 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. @@ -70,7 +70,7 @@ public class SubscriptionActivatingSubscriber { Validate.notNull(theTaskExecutor); } - public synchronized void activateOrRegisterSubscriptionIfRequired(final IBaseResource theSubscription) { + public synchronized boolean activateOrRegisterSubscriptionIfRequired(final IBaseResource theSubscription) { // Grab the value for "Subscription.channel.type" so we can see if this // subscriber applies.. String subscriptionChannelType = myCtx @@ -79,7 +79,7 @@ public class SubscriptionActivatingSubscriber { .getValueAsString(); boolean subscriptionTypeApplies = BaseSubscriptionSubscriber.subscriptionTypeApplies(subscriptionChannelType, myChannelType); if (subscriptionTypeApplies == false) { - return; + return false; } final IPrimitiveType status = myCtx.newTerser().getSingleValueOrNull(theSubscription, BaseSubscriptionInterceptor.SUBSCRIPTION_STATUS, IPrimitiveType.class); @@ -121,25 +121,28 @@ public class SubscriptionActivatingSubscriber { } } }); + return true; } else { - activateSubscription(activeStatus, theSubscription, requestedStatus); + return activateSubscription(activeStatus, theSubscription, requestedStatus); } } else if (activeStatus.equals(statusString)) { - registerSubscriptionUnlessAlreadyRegistered(theSubscription); + return registerSubscriptionUnlessAlreadyRegistered(theSubscription); } else { // Status isn't "active" or "requested" - unregisterSubscriptionIfRegistered(theSubscription, statusString); + return unregisterSubscriptionIfRegistered(theSubscription, statusString); } } - protected void unregisterSubscriptionIfRegistered(IBaseResource theSubscription, String theStatusString) { - if (mySubscriptionInterceptor.hasSubscription(theSubscription.getIdElement())) { + protected boolean unregisterSubscriptionIfRegistered(IBaseResource theSubscription, String theStatusString) { + if (mySubscriptionInterceptor.hasSubscription(theSubscription.getIdElement()) != null) { ourLog.info("Removing {} subscription {}", theStatusString, theSubscription.getIdElement().toUnqualified().getValue()); mySubscriptionInterceptor.unregisterSubscription(theSubscription.getIdElement()); + return true; } + return false; } - private void activateSubscription(String theActiveStatus, final IBaseResource theSubscription, String theRequestedStatus) { + private boolean activateSubscription(String theActiveStatus, final IBaseResource theSubscription, String theRequestedStatus) { IBaseResource subscription = mySubscriptionDao.read(theSubscription.getIdElement()); ourLog.info("Activating subscription {} from status {} to {} for channel {}", subscription.getIdElement().toUnqualified().getValue(), theRequestedStatus, theActiveStatus, myChannelType); @@ -147,11 +150,13 @@ public class SubscriptionActivatingSubscriber { SubscriptionUtil.setStatus(myCtx, subscription, theActiveStatus); subscription = mySubscriptionDao.update(subscription).getResource(); mySubscriptionInterceptor.submitResourceModifiedForUpdate(subscription); + return true; } catch (final UnprocessableEntityException e) { ourLog.info("Changing status of {} to ERROR", subscription.getIdElement()); SubscriptionUtil.setStatus(myCtx, subscription, "error"); SubscriptionUtil.setReason(myCtx, subscription, e.getMessage()); mySubscriptionDao.update(subscription); + return false; } } @@ -186,14 +191,25 @@ public class SubscriptionActivatingSubscriber { }); } - private void registerSubscriptionUnlessAlreadyRegistered(IBaseResource theSubscription) { - if (mySubscriptionInterceptor.hasSubscription(theSubscription.getIdElement())) { + protected boolean registerSubscriptionUnlessAlreadyRegistered(IBaseResource theSubscription) { + CanonicalSubscription existingSubscription = mySubscriptionInterceptor.hasSubscription(theSubscription.getIdElement()); + CanonicalSubscription newSubscription = mySubscriptionInterceptor.canonicalize(theSubscription); + + if (existingSubscription != null) { + if (newSubscription.equals(existingSubscription)) { + // No changes + return false; + } + } + + if (existingSubscription != null) { ourLog.info("Updating already-registered active subscription {}", theSubscription.getIdElement().toUnqualified().getValue()); mySubscriptionInterceptor.unregisterSubscription(theSubscription.getIdElement()); } else { ourLog.info("Registering active subscription {}", theSubscription.getIdElement().toUnqualified().getValue()); } mySubscriptionInterceptor.registerSubscription(theSubscription.getIdElement(), theSubscription); + return true; } @VisibleForTesting diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BaseResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BaseResourceProviderR4Test.java index d9453cca5e7..3f8149b8c1a 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BaseResourceProviderR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BaseResourceProviderR4Test.java @@ -62,6 +62,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test { private static Server ourServer; protected IGenericClient ourClient; protected ResourceCountCache ourResourceCountsCache; + protected static SubscriptionRestHookInterceptor ourReskHookSubscriptionInterceptor; private TerminologyUploaderProviderR4 myTerminologyUploaderProvider; private Object ourGraphQLProvider; private boolean ourRestHookSubscriptionInterceptorRequested; @@ -70,72 +71,6 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test { super(); } - @AfterClass - public static void afterClassClearContextBaseResourceProviderR4Test() throws Exception { - ourServer.stop(); - ourHttpClient.close(); - ourServer = null; - ourHttpClient = null; - myValidationSupport.flush(); - myValidationSupport = null; - ourWebApplicationContext.close(); - ourWebApplicationContext = null; - TestUtil.clearAllStaticFieldsForUnitTest(); - } - - public static int getNumberOfParametersByName(Parameters theParameters, String theName) { - int retVal = 0; - - for (ParametersParameterComponent param : theParameters.getParameter()) { - if (param.getName().equals(theName)) { - retVal++; - } - } - - return retVal; - } - - public static ParametersParameterComponent getParameterByName(Parameters theParameters, String theName) { - for (ParametersParameterComponent param : theParameters.getParameter()) { - if (param.getName().equals(theName)) { - return param; - } - } - - return new ParametersParameterComponent(); - } - - public static List getParametersByName(Parameters theParameters, String theName) { - List params = new ArrayList<>(); - for (ParametersParameterComponent param : theParameters.getParameter()) { - if (param.getName().equals(theName)) { - params.add(param); - } - } - - return params; - } - - public static ParametersParameterComponent getPartByName(ParametersParameterComponent theParameter, String theName) { - for (ParametersParameterComponent part : theParameter.getPart()) { - if (part.getName().equals(theName)) { - return part; - } - } - - return new ParametersParameterComponent(); - } - - public static boolean hasParameterByName(Parameters theParameters, String theName) { - for (ParametersParameterComponent param : theParameters.getParameter()) { - if (param.getName().equals(theName)) { - return true; - } - } - - return false; - } - @After public void after() throws Exception { myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE); @@ -219,6 +154,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test { mySearchCoordinatorSvc = wac.getBean(ISearchCoordinatorSvc.class); mySearchEntityDao = wac.getBean(ISearchDao.class); ourSearchParamRegistry = wac.getBean(SearchParamRegistryR4.class); + ourReskHookSubscriptionInterceptor = wac.getBean(SubscriptionRestHookInterceptor.class); myFhirCtx.getRestfulClientFactory().setSocketTimeout(5000000); @@ -274,4 +210,70 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test { Thread.sleep(500); } + @AfterClass + public static void afterClassClearContextBaseResourceProviderR4Test() throws Exception { + ourServer.stop(); + ourHttpClient.close(); + ourServer = null; + ourHttpClient = null; + myValidationSupport.flush(); + myValidationSupport = null; + ourWebApplicationContext.close(); + ourWebApplicationContext = null; + TestUtil.clearAllStaticFieldsForUnitTest(); + } + + public static int getNumberOfParametersByName(Parameters theParameters, String theName) { + int retVal = 0; + + for (ParametersParameterComponent param : theParameters.getParameter()) { + if (param.getName().equals(theName)) { + retVal++; + } + } + + return retVal; + } + + public static ParametersParameterComponent getParameterByName(Parameters theParameters, String theName) { + for (ParametersParameterComponent param : theParameters.getParameter()) { + if (param.getName().equals(theName)) { + return param; + } + } + + return new ParametersParameterComponent(); + } + + public static List getParametersByName(Parameters theParameters, String theName) { + List params = new ArrayList<>(); + for (ParametersParameterComponent param : theParameters.getParameter()) { + if (param.getName().equals(theName)) { + params.add(param); + } + } + + return params; + } + + public static ParametersParameterComponent getPartByName(ParametersParameterComponent theParameter, String theName) { + for (ParametersParameterComponent part : theParameter.getPart()) { + if (part.getName().equals(theName)) { + return part; + } + } + + return new ParametersParameterComponent(); + } + + public static boolean hasParameterByName(Parameters theParameters, String theName) { + for (ParametersParameterComponent param : theParameters.getParameter()) { + if (param.getName().equals(theName)) { + return true; + } + } + + return false; + } + } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/subscription/r4/RestHookTestR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/subscription/r4/RestHookTestR4Test.java index b0f55ac9fcd..00b0f31eda1 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/subscription/r4/RestHookTestR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/subscription/r4/RestHookTestR4Test.java @@ -52,33 +52,6 @@ public class RestHookTestR4Test extends BaseResourceProviderR4Test { private List mySubscriptionIds = new ArrayList<>(); private CountingInterceptor myCountingInterceptor; - @BeforeClass - public static void startListenerServer() throws Exception { - ourListenerPort = PortUtil.findFreePort(); - ourListenerRestServer = new RestfulServer(FhirContext.forR4()); - ourListenerServerBase = "http://localhost:" + ourListenerPort + "/fhir/context"; - - ObservationListener obsListener = new ObservationListener(); - ourListenerRestServer.setResourceProviders(obsListener); - - ourListenerServer = new Server(ourListenerPort); - - ServletContextHandler proxyHandler = new ServletContextHandler(); - proxyHandler.setContextPath("/"); - - ServletHolder servletHolder = new ServletHolder(); - servletHolder.setServlet(ourListenerRestServer); - proxyHandler.addServlet(servletHolder, "/fhir/context/*"); - - ourListenerServer.setHandler(proxyHandler); - ourListenerServer.start(); - } - - @AfterClass - public static void stopListenerServer() throws Exception { - ourListenerServer.stop(); - } - @After public void afterUnregisterRestHookListener() { for (IIdType next : mySubscriptionIds) { @@ -180,6 +153,19 @@ public class RestHookTestR4Test extends BaseResourceProviderR4Test { assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0)); } + @Test + public void testActiveSubscriptionShouldntReActivate() throws Exception { + String criteria = "Observation?code=111111111&_format=xml"; + String payload = "application/fhir+json"; + createSubscription(criteria, payload, ourListenerServerBase); + + waitForRegisteredSubscriptionCount(1); + for (int i = 0; i < 5; i++) { + Integer changes = ourReskHookSubscriptionInterceptor.doInitSubscriptions(); + assertEquals(0, changes.intValue()); + } + } + @Test public void testRestHookSubscriptionNoopUpdateDoesntTriggerNewDelivery() throws Exception { String payload = "application/fhir+json"; @@ -233,7 +219,7 @@ public class RestHookTestR4Test extends BaseResourceProviderR4Test { .addExtension(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION, new BooleanType("true")); ourLog.info("** About to update subscription"); ourClient.update().resource(subscription1).execute(); - waitForSize(modCount + 1, ()->myCountingInterceptor.getSentCount()); + waitForSize(modCount + 1, () -> myCountingInterceptor.getSentCount()); ourLog.info("** About to send observation"); Observation observation1 = sendObservation(code, "SNOMED-CT"); @@ -400,7 +386,6 @@ public class RestHookTestR4Test extends BaseResourceProviderR4Test { Assert.assertFalse(observation2.getId().isEmpty()); } - @Test public void testUpdateSubscriptionToMatchLater() throws Exception { String payload = "application/xml"; @@ -586,4 +571,31 @@ public class RestHookTestR4Test extends BaseResourceProviderR4Test { } + @BeforeClass + public static void startListenerServer() throws Exception { + ourListenerPort = PortUtil.findFreePort(); + ourListenerRestServer = new RestfulServer(FhirContext.forR4()); + ourListenerServerBase = "http://localhost:" + ourListenerPort + "/fhir/context"; + + ObservationListener obsListener = new ObservationListener(); + ourListenerRestServer.setResourceProviders(obsListener); + + ourListenerServer = new Server(ourListenerPort); + + ServletContextHandler proxyHandler = new ServletContextHandler(); + proxyHandler.setContextPath("/"); + + ServletHolder servletHolder = new ServletHolder(); + servletHolder.setServlet(ourListenerRestServer); + proxyHandler.addServlet(servletHolder, "/fhir/context/*"); + + ourListenerServer.setHandler(proxyHandler); + ourListenerServer.start(); + } + + @AfterClass + public static void stopListenerServer() throws Exception { + ourListenerServer.stop(); + } + } diff --git a/hapi-fhir-jpaserver-uhnfhirtest/derby_maintenance.txt b/hapi-fhir-jpaserver-uhnfhirtest/derby_maintenance.txt index 5c38a909b06..8899c04f40f 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/derby_maintenance.txt +++ b/hapi-fhir-jpaserver-uhnfhirtest/derby_maintenance.txt @@ -230,3 +230,46 @@ DELETE FROM TRM_CODESYSTEM_VER; DELETE FROM TRM_CODESYSTEM; delete from hfj_resource; + + + +# Delete All (Oracle) +DROP TABLE HFJ_FORCED_ID CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_res_ver CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_resource CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_history_tag CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_res_ver CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_forced_id CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_res_link CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_res_link CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_spidx_coords CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_spidx_date CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_spidx_number CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_spidx_quantity CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_spidx_string CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_spidx_token CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_spidx_uri CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_res_tag CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_search_result CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_res_param_present CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_idx_cmp_string_uniq CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_subscription_stats CASCADE CONSTRAINTS PURGE; +DROP TABLE TRM_CONCEPT_MAP_GRP_ELM_TGT CASCADE CONSTRAINTS PURGE; +DROP TABLE TRM_CONCEPT_MAP_GRP_ELEMENT CASCADE CONSTRAINTS PURGE; +DROP TABLE TRM_CONCEPT_MAP_GROUP CASCADE CONSTRAINTS PURGE; +DROP TABLE TRM_CONCEPT_MAP CASCADE CONSTRAINTS PURGE; +DROP TABLE TRM_CONCEPT_DESIG CASCADE CONSTRAINTS PURGE; +DROP TABLE TRM_CONCEPT_PC_LINK CASCADE CONSTRAINTS PURGE; +DROP TABLE TRM_CONCEPT_PROPERTY CASCADE CONSTRAINTS PURGE; +DROP TABLE TRM_CONCEPT CASCADE CONSTRAINTS PURGE; +DROP TABLE TRM_CODESYSTEM_VER CASCADE CONSTRAINTS PURGE; +DROP TABLE TRM_CODESYSTEM CASCADE CONSTRAINTS PURGE; +DROP TABLE hfj_resource CASCADE CONSTRAINTS PURGE; +DROP TABLE HFJ_SEARCH_RESULT CASCADE CONSTRAINTS PURGE; +DROP TABLE HFJ_SEARCH_PARM CASCADE CONSTRAINTS PURGE; +DROP TABLE HFJ_SEARCH_INCLUDE CASCADE CONSTRAINTS PURGE; +DROP TABLE HFJ_SEARCH CASCADE CONSTRAINTS PURGE; +DROP TABLE HFJ_SUBSCRIPTION CASCADE CONSTRAINTS PURGE; +DROP TABLE HFJ_SUBSCRIPTION_FLAG_RES CASCADE CONSTRAINTS PURGE; +DROP TABLE HFJ_TAG_DEF CASCADE CONSTRAINTS PURGE; +