Clean up email subscription type
This commit is contained in:
parent
59975948b2
commit
15ba0dff03
|
@ -28,6 +28,7 @@
|
|||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Only required for narrative generator support -->
|
||||
|
|
|
@ -59,6 +59,11 @@
|
|||
</dependency>
|
||||
|
||||
<!-- Unit test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
|
@ -125,4 +130,4 @@
|
|||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
@ -74,6 +74,11 @@
|
|||
</dependency>
|
||||
|
||||
<!-- Unit test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
|
|
|
@ -32,6 +32,12 @@
|
|||
<version>3.5</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.sf.saxon</groupId>
|
||||
<artifactId>Saxon-HE</artifactId>
|
||||
|
|
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.jpa.graphql.JpaStorageServices;
|
|||
import ca.uhn.fhir.jpa.search.*;
|
||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||
import ca.uhn.fhir.jpa.sp.SearchParamPresenceSvcImpl;
|
||||
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
||||
import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor;
|
||||
import ca.uhn.fhir.jpa.subscription.websocket.SubscriptionWebsocketInterceptor;
|
||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||
|
@ -93,15 +94,6 @@ public class BaseConfig implements SchedulingConfigurer {
|
|||
return new StaleSearchDeletingSvcImpl();
|
||||
}
|
||||
|
||||
// @PostConstruct
|
||||
// public void wireResourceDaos() {
|
||||
// Map<String, IDao> daoBeans = myAppCtx.getBeansOfType(IDao.class);
|
||||
// List bean = myAppCtx.getBean("myResourceProvidersDstu2", List.class);
|
||||
// for (IDao next : daoBeans.values()) {
|
||||
// next.setResourceDaos(bean);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Bean
|
||||
@Lazy
|
||||
public SubscriptionRestHookInterceptor subscriptionRestHookInterceptor() {
|
||||
|
@ -114,15 +106,23 @@ public class BaseConfig implements SchedulingConfigurer {
|
|||
return new SubscriptionWebsocketInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: If you're going to use this, you need to provide a bean
|
||||
* of type {@link ca.uhn.fhir.jpa.subscription.email.IEmailSender}
|
||||
* in your own Spring config
|
||||
*/
|
||||
@Bean
|
||||
@Lazy
|
||||
public SubscriptionEmailInterceptor subscriptionEmailInterceptor() {
|
||||
return new SubscriptionEmailInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TaskScheduler taskScheduler() {
|
||||
ConcurrentTaskScheduler retVal = new ConcurrentTaskScheduler();
|
||||
retVal.setConcurrentExecutor(scheduledExecutorService().getObject());
|
||||
retVal.setScheduledExecutor(scheduledExecutorService().getObject());
|
||||
return retVal;
|
||||
// ThreadPoolTaskScheduler retVal = new ThreadPoolTaskScheduler();
|
||||
// retVal.setPoolSize(5);
|
||||
// return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -184,7 +184,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
StopWatch w = new StopWatch();
|
||||
final String searchUuid = UUID.randomUUID().toString();
|
||||
|
||||
ourLog.info("Registering new search {}", searchUuid);
|
||||
ourLog.debug("Registering new search {}", searchUuid);
|
||||
|
||||
Class<? extends IBaseResource> resourceTypeClass = myContext.getResourceDefinition(theResourceType).getImplementingClass();
|
||||
final ISearchBuilder sb = theCallingDao.newSearchBuilder();
|
||||
|
@ -206,7 +206,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
|
||||
if (theParams.isLoadSynchronous() || loadSynchronousUpTo != null) {
|
||||
|
||||
ourLog.info("Search {} is loading in synchronous mode", searchUuid);
|
||||
ourLog.debug("Search {} is loading in synchronous mode", searchUuid);
|
||||
|
||||
// Execute the query and make sure we return distinct results
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
|
@ -561,25 +561,25 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
public List<Long> getResourcePids(int theFromIndex, int theToIndex) {
|
||||
ourLog.info("Requesting search PIDs from {}-{}", theFromIndex, theToIndex);
|
||||
|
||||
CountDownLatch latch = null;
|
||||
synchronized (mySyncedPids) {
|
||||
if (mySyncedPids.size() < theToIndex && mySearch.getStatus() == SearchStatusEnum.LOADING) {
|
||||
int latchSize = theToIndex - mySyncedPids.size();
|
||||
ourLog.trace("Registering latch to await {} results (want {} total)", latchSize, theToIndex);
|
||||
latch = new CountDownLatch(latchSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (latch != null) {
|
||||
while (latch.getCount() > 0 && mySearch.getStatus() == SearchStatusEnum.LOADING) {
|
||||
try {
|
||||
ourLog.trace("Awaiting latch with {}", latch.getCount());
|
||||
latch.await(500, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
// ok
|
||||
boolean keepWaiting;
|
||||
do {
|
||||
synchronized (mySyncedPids) {
|
||||
keepWaiting = false;
|
||||
if (mySyncedPids.size() < theToIndex && mySearch.getStatus() == SearchStatusEnum.LOADING) {
|
||||
keepWaiting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keepWaiting) {
|
||||
ourLog.info("Waiting, as we only have {} results", mySyncedPids.size());
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException theE) {
|
||||
// ignore
|
||||
}
|
||||
} else {
|
||||
ourLog.info("Proceeding, as we have {} results", mySyncedPids.size());
|
||||
}
|
||||
} while (keepWaiting);
|
||||
|
||||
ArrayList<Long> retVal = new ArrayList<>();
|
||||
synchronized (mySyncedPids) {
|
||||
|
|
|
@ -156,13 +156,11 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
|
|||
try {
|
||||
from = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_EMAIL_FROM);
|
||||
subjectTemplate = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE);
|
||||
bodyTemplate = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_BODY_TEMPLATE);
|
||||
} catch (FHIRException theE) {
|
||||
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
||||
}
|
||||
retVal.getEmailDetails().setFrom(from);
|
||||
retVal.getEmailDetails().setSubjectTemplate(subjectTemplate);
|
||||
retVal.getEmailDetails().setBodyTemplate(bodyTemplate);
|
||||
}
|
||||
|
||||
} catch (FHIRException theE) {
|
||||
|
@ -191,13 +189,11 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
|
|||
try {
|
||||
from = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_EMAIL_FROM);
|
||||
subjectTemplate = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE);
|
||||
bodyTemplate = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_BODY_TEMPLATE);
|
||||
} catch (FHIRException theE) {
|
||||
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
|
||||
}
|
||||
retVal.getEmailDetails().setFrom(from);
|
||||
retVal.getEmailDetails().setSubjectTemplate(subjectTemplate);
|
||||
retVal.getEmailDetails().setBodyTemplate(bodyTemplate);
|
||||
}
|
||||
|
||||
List<org.hl7.fhir.r4.model.Extension> topicExts = subscription.getExtensionsByUrl("http://hl7.org/fhir/subscription/topics");
|
||||
|
|
|
@ -131,10 +131,12 @@ public class CanonicalSubscription implements Serializable {
|
|||
return myHeaders;
|
||||
}
|
||||
|
||||
public void setHeaders(String theHeaders) {
|
||||
public void setHeaders(List<? extends IPrimitiveType<String>> theHeader) {
|
||||
myHeaders = new ArrayList<>();
|
||||
if (isNotBlank(theHeaders)) {
|
||||
myHeaders.add(theHeaders);
|
||||
for (IPrimitiveType<String> next : theHeader) {
|
||||
if (isNotBlank(next.getValueAsString())) {
|
||||
myHeaders.add(next.getValueAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,12 +191,10 @@ public class CanonicalSubscription implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
public void setHeaders(List<? extends IPrimitiveType<String>> theHeader) {
|
||||
public void setHeaders(String theHeaders) {
|
||||
myHeaders = new ArrayList<>();
|
||||
for (IPrimitiveType<String> next : theHeader) {
|
||||
if (isNotBlank(next.getValueAsString())) {
|
||||
myHeaders.add(next.getValueAsString());
|
||||
}
|
||||
if (isNotBlank(theHeaders)) {
|
||||
myHeaders.add(theHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,16 +212,6 @@ public class CanonicalSubscription implements Serializable {
|
|||
private String myFrom;
|
||||
@JsonProperty("subjectTemplate")
|
||||
private String mySubjectTemplate;
|
||||
@JsonProperty("bodyTemplate")
|
||||
private String myBodyTemplate;
|
||||
|
||||
public String getBodyTemplate() {
|
||||
return myBodyTemplate;
|
||||
}
|
||||
|
||||
public void setBodyTemplate(String theBodyTemplate) {
|
||||
myBodyTemplate = theBodyTemplate;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return myFrom;
|
||||
|
|
|
@ -69,15 +69,16 @@ public class SubscriptionActivatingSubscriber {
|
|||
final String requestedStatus = Subscription.SubscriptionStatus.REQUESTED.toCode();
|
||||
final String activeStatus = Subscription.SubscriptionStatus.ACTIVE.toCode();
|
||||
if (requestedStatus.equals(statusString)) {
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
status.setValueAsString(activeStatus);
|
||||
ourLog.info("Activating and registering subscription {} from status {} to {}", theSubscription.getIdElement().toUnqualified().getValue(), requestedStatus, activeStatus);
|
||||
mySubscriptionDao.update(theSubscription);
|
||||
mySubscriptionInterceptor.registerSubscription(theSubscription.getIdElement(), theSubscription);
|
||||
}
|
||||
});
|
||||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
activateSubscription(status, activeStatus, theSubscription, requestedStatus);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
activateSubscription(status, activeStatus, theSubscription, requestedStatus);
|
||||
}
|
||||
} else if (activeStatus.equals(statusString)) {
|
||||
if (!mySubscriptionInterceptor.hasSubscription(theSubscription.getIdElement())) {
|
||||
ourLog.info("Registering active subscription {}", theSubscription.getIdElement().toUnqualified().getValue());
|
||||
|
@ -91,6 +92,13 @@ public class SubscriptionActivatingSubscriber {
|
|||
}
|
||||
}
|
||||
|
||||
private void activateSubscription(IPrimitiveType<?> theStatus, String theActiveStatus, IBaseResource theSubscription, String theRequestedStatus) {
|
||||
theStatus.setValueAsString(theActiveStatus);
|
||||
ourLog.info("Activating and registering subscription {} from status {} to {}", theSubscription.getIdElement().toUnqualified().getValue(), theRequestedStatus, theActiveStatus);
|
||||
mySubscriptionDao.update(theSubscription);
|
||||
mySubscriptionInterceptor.registerSubscription(theSubscription.getIdElement(), theSubscription);
|
||||
}
|
||||
|
||||
|
||||
public void handleMessage(RestOperationTypeEnum theOperationType, IIdType theId, final IBaseResource theSubscription) throws MessagingException {
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ package ca.uhn.fhir.jpa.subscription.email;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EmailDetails {
|
||||
|
@ -27,6 +29,7 @@ public class EmailDetails {
|
|||
private String myBodyTemplate;
|
||||
private List<String> myTo;
|
||||
private String myFrom;
|
||||
private IIdType mySubscription;
|
||||
|
||||
public String getBodyTemplate() {
|
||||
return myBodyTemplate;
|
||||
|
@ -52,6 +55,14 @@ public class EmailDetails {
|
|||
mySubjectTemplate = theSubjectTemplate;
|
||||
}
|
||||
|
||||
public IIdType getSubscription() {
|
||||
return mySubscription;
|
||||
}
|
||||
|
||||
public void setSubscription(IIdType theSubscription) {
|
||||
mySubscription = theSubscription;
|
||||
}
|
||||
|
||||
public List<String> getTo() {
|
||||
return myTo;
|
||||
}
|
||||
|
|
|
@ -22,11 +22,11 @@ package ca.uhn.fhir.jpa.subscription.email;
|
|||
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.mail.SimpleMailMessage;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||
import org.thymeleaf.context.Context;
|
||||
import org.thymeleaf.spring4.SpringTemplateEngine;
|
||||
|
@ -35,6 +35,9 @@ import org.thymeleaf.templatemode.TemplateMode;
|
|||
import org.thymeleaf.templateresolver.StringTemplateResolver;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -42,9 +45,9 @@ import java.util.List;
|
|||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.trim;
|
||||
|
||||
public class EmailSender implements IEmailSender {
|
||||
public class JavaMailEmailSender implements IEmailSender {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(EmailSender.class);
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(JavaMailEmailSender.class);
|
||||
private String mySmtpServerHost;
|
||||
private int mySmtpServerPort = 25;
|
||||
private JavaMailSenderImpl mySender;
|
||||
|
@ -61,7 +64,8 @@ public class EmailSender implements IEmailSender {
|
|||
|
||||
@Override
|
||||
public void send(EmailDetails theDetails) {
|
||||
ourLog.info("Sending email to recipients: {}", theDetails.getTo());
|
||||
String subscriptionId = theDetails.getSubscription().toUnqualifiedVersionless().getValue();
|
||||
ourLog.info("Sending email for subscription {} to recipients: {}", subscriptionId, theDetails.getTo());
|
||||
StopWatch sw = new StopWatch();
|
||||
|
||||
StringTemplateResolver templateResolver = new StringTemplateResolver();
|
||||
|
@ -80,12 +84,18 @@ public class EmailSender implements IEmailSender {
|
|||
String body = engine.process(theDetails.getBodyTemplate(), context);
|
||||
String subject = engine.process(theDetails.getSubjectTemplate(), context);
|
||||
|
||||
SimpleMailMessage email = new SimpleMailMessage();
|
||||
email.setFrom(trim(theDetails.getFrom()));
|
||||
email.setTo(toTrimmedStringArray(theDetails.getTo()));
|
||||
email.setSubject(subject);
|
||||
email.setText(body);
|
||||
email.setSentDate(new Date());
|
||||
MimeMessage email = mySender.createMimeMessage();
|
||||
|
||||
try {
|
||||
email.setFrom(trim(theDetails.getFrom()));
|
||||
email.setRecipients(Message.RecipientType.TO, toTrimmedCommaSeparatedString(theDetails.getTo()));
|
||||
email.setSubject(subject);
|
||||
email.setText(body);
|
||||
email.setSentDate(new Date());
|
||||
email.addHeader("X-FHIR-Subscription", subscriptionId);
|
||||
} catch (MessagingException e) {
|
||||
throw new InternalErrorException("Failed to create email messaage", e);
|
||||
}
|
||||
|
||||
mySender.send(email);
|
||||
|
||||
|
@ -106,13 +116,14 @@ public class EmailSender implements IEmailSender {
|
|||
mySmtpServerPort = theSmtpServerPort;
|
||||
}
|
||||
|
||||
private static String[] toTrimmedStringArray(List<String> theTo) {
|
||||
private static String toTrimmedCommaSeparatedString(List<String> theTo) {
|
||||
List<String> to = new ArrayList<>();
|
||||
for (String next : theTo) {
|
||||
if (isNotBlank(next)) {
|
||||
to.add(next);
|
||||
}
|
||||
}
|
||||
return to.toArray(new String[to.size()]);
|
||||
|
||||
return StringUtils.join(to, ",");
|
||||
}
|
||||
}
|
|
@ -54,32 +54,29 @@ public class SubscriptionDeliveringEmailSubscriber extends BaseSubscriptionDeliv
|
|||
List<String> destinationAddresses = new ArrayList<>();
|
||||
String[] destinationAddressStrings = StringUtils.split(endpointUrl, ",");
|
||||
for (String next : destinationAddressStrings) {
|
||||
next = trim(defaultString(next));
|
||||
if (next.startsWith("mailto:")) {
|
||||
next = next.substring("mailto:".length());
|
||||
}
|
||||
if (isNotBlank(next)) {
|
||||
destinationAddresses.add(trim(next));
|
||||
destinationAddresses.add(next);
|
||||
}
|
||||
}
|
||||
|
||||
String from = defaultString(subscription.getEmailDetails().getFrom(), provideDefaultFrom());
|
||||
String from = defaultString(subscription.getEmailDetails().getFrom(), mySubscriptionEmailInterceptor.getDefaultFromAddress());
|
||||
String subjectTemplate = defaultString(subscription.getEmailDetails().getSubjectTemplate(), provideDefaultSubjectTemplate());
|
||||
String bodyTemplate = defaultString(subscription.getEmailDetails().getBodyTemplate(), provideDefaultBodyTemplate());
|
||||
|
||||
EmailDetails details = new EmailDetails();
|
||||
details.setTo(destinationAddresses);
|
||||
details.setFrom(from);
|
||||
details.setBodyTemplate(bodyTemplate);
|
||||
details.setBodyTemplate(subscription.getPayloadString());
|
||||
details.setSubjectTemplate(subjectTemplate);
|
||||
details.setSubscription(subscription.getIdElement(getContext()));
|
||||
|
||||
IEmailSender emailSender = mySubscriptionEmailInterceptor.getEmailSender();
|
||||
emailSender.send(details);
|
||||
}
|
||||
|
||||
private String provideDefaultBodyTemplate() {
|
||||
return "A subscription update has been received";
|
||||
}
|
||||
|
||||
private String provideDefaultFrom() {
|
||||
return "unknown@sender.com";
|
||||
}
|
||||
|
||||
private String provideDefaultSubjectTemplate() {
|
||||
return "HAPI FHIR Subscriptions";
|
||||
|
|
|
@ -20,28 +20,51 @@ package ca.uhn.fhir.jpa.subscription.email;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.subscription.BaseSubscriptionInterceptor;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.List;
|
||||
|
||||
public class SubscriptionEmailInterceptor extends BaseSubscriptionInterceptor {
|
||||
private SubscriptionDeliveringEmailSubscriber mySubscriptionDeliverySubscriber;
|
||||
|
||||
/**
|
||||
* This is set to autowired=false just so that implementors can supply this
|
||||
* with a mechanism other than autowiring if they want
|
||||
*/
|
||||
@Autowired(required = false)
|
||||
private IEmailSender myEmailSender;
|
||||
private String myDefaultFromAddress = "noreply@unknown.com";
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType getChannelType() {
|
||||
return org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType.EMAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "from" address to use for any sent emails that to not explicitly specity a from address
|
||||
*/
|
||||
public String getDefaultFromAddress() {
|
||||
return myDefaultFromAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "from" address to use for any sent emails that to not explicitly specity a from address
|
||||
*/
|
||||
public void setDefaultFromAddress(String theDefaultFromAddress) {
|
||||
Validate.notBlank(theDefaultFromAddress, "theDefaultFromAddress must not be null or blank");
|
||||
myDefaultFromAddress = theDefaultFromAddress;
|
||||
}
|
||||
|
||||
public IEmailSender getEmailSender() {
|
||||
return myEmailSender;
|
||||
}
|
||||
|
||||
@Required
|
||||
/**
|
||||
* Set the email sender (this method does not need to be explicitly called if you
|
||||
* are using autowiring to supply the sender)
|
||||
*/
|
||||
public void setEmailSender(IEmailSender theEmailSender) {
|
||||
myEmailSender = theEmailSender;
|
||||
}
|
||||
|
@ -54,12 +77,12 @@ public class SubscriptionEmailInterceptor extends BaseSubscriptionInterceptor {
|
|||
getDeliveryChannel().subscribe(mySubscriptionDeliverySubscriber);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
Validate.notNull(myEmailSender, "emailSender has not been configured");
|
||||
|
||||
super.start();
|
||||
}
|
||||
// @PostConstruct
|
||||
// public void start() {
|
||||
// Validate.notNull(myEmailSender, "emailSender has not been configured");
|
||||
//
|
||||
// super.start();
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected void unregisterDeliverySubscriber() {
|
||||
|
|
|
@ -24,8 +24,20 @@ public class JpaConstants {
|
|||
|
||||
public static final String EXT_SP_UNIQUE = "http://hapifhir.io/fhir/StructureDefinition/sp-unique";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This extension should be of type <code>string</code> and should be
|
||||
* placed on the <code>Subscription.channel</code> element
|
||||
* </p>
|
||||
*/
|
||||
public static final String EXT_SUBSCRIPTION_EMAIL_FROM = "http://hapifhir.io/fhir/StructureDefinition/subscription-email-from";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This extension should be of type <code>string</code> and should be
|
||||
* placed on the <code>Subscription.channel</code> element
|
||||
* </p>
|
||||
*/
|
||||
public static final String EXT_SUBSCRIPTION_SUBJECT_TEMPLATE = "http://hapifhir.io/fhir/StructureDefinition/subscription-email-subject-template";
|
||||
public static final String EXT_SUBSCRIPTION_BODY_TEMPLATE = "http://hapifhir.io/fhir/StructureDefinition/subscription-email-body-template";
|
||||
|
||||
}
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.email.IEmailSender;
|
||||
import ca.uhn.fhir.jpa.subscription.email.JavaMailEmailSender;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement()
|
||||
|
@ -30,11 +32,6 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
|||
static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestDstu3Config.class);
|
||||
private Exception myLastStackTrace;
|
||||
|
||||
@Bean()
|
||||
public DaoConfig daoConfig() {
|
||||
return new DaoConfig();
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public BasicDataSource basicDataSource() {
|
||||
BasicDataSource retVal = new BasicDataSource() {
|
||||
|
@ -49,7 +46,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
|||
ourLog.error("Exceeded maximum wait for connection", e);
|
||||
logGetConnectionStackTrace();
|
||||
// if ("true".equals(System.getProperty("ci"))) {
|
||||
fail("Exceeded maximum wait for connection: "+ e.toString());
|
||||
fail("Exceeded maximum wait for connection: " + e.toString());
|
||||
// }
|
||||
// System.exit(1);
|
||||
retVal = null;
|
||||
|
@ -99,20 +96,33 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public DaoConfig daoConfig() {
|
||||
return new DaoConfig();
|
||||
}
|
||||
|
||||
@Bean()
|
||||
@Primary()
|
||||
public DataSource dataSource() {
|
||||
|
||||
DataSource dataSource = ProxyDataSourceBuilder
|
||||
.create(basicDataSource())
|
||||
.create(basicDataSource())
|
||||
// .logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
|
||||
.logSlowQueryBySlf4j(1000, TimeUnit.MILLISECONDS)
|
||||
.countQuery()
|
||||
.build();
|
||||
.logSlowQueryBySlf4j(1000, TimeUnit.MILLISECONDS)
|
||||
.countQuery()
|
||||
.build();
|
||||
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IEmailSender emailSender() {
|
||||
JavaMailEmailSender retVal = new JavaMailEmailSender();
|
||||
retVal.setSmtpServerHost("localhost");
|
||||
retVal.setSmtpServerPort(3025);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
|
||||
|
|
|
@ -303,7 +303,7 @@ public abstract class BaseJpaTest {
|
|||
|
||||
public static void waitForSize(int theTarget, List<?> theList) {
|
||||
StopWatch sw = new StopWatch();
|
||||
while (theList.size() != theTarget && sw.getMillis() < 10000) {
|
||||
while (theList.size() != theTarget && sw.getMillis() <= 15000) {
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException theE) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test;
|
|||
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
||||
import ca.uhn.fhir.jpa.subscription.resthook.SubscriptionRestHookInterceptor;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
|
@ -58,6 +59,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
protected static SearchParamRegistryDstu3 ourSearchParamRegistry;
|
||||
protected static DatabaseBackedPagingProvider ourPagingProvider;
|
||||
protected static SubscriptionRestHookInterceptor ourRestHookSubscriptionInterceptor;
|
||||
protected static SubscriptionEmailInterceptor ourEmailSubscriptionInterceptor;
|
||||
protected static ISearchDao mySearchEntityDao;
|
||||
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||
|
||||
|
@ -111,13 +113,9 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
ourWebApplicationContext = new GenericWebApplicationContext();
|
||||
ourWebApplicationContext.setParent(myAppCtx);
|
||||
ourWebApplicationContext.refresh();
|
||||
// ContextLoaderListener loaderListener = new ContextLoaderListener(webApplicationContext);
|
||||
// loaderListener.initWebApplicationContext(mock(ServletContext.class));
|
||||
//
|
||||
proxyHandler.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ourWebApplicationContext);
|
||||
|
||||
DispatcherServlet dispatcherServlet = new DispatcherServlet();
|
||||
// dispatcherServlet.setApplicationContext(webApplicationContext);
|
||||
dispatcherServlet.setContextClass(AnnotationConfigWebApplicationContext.class);
|
||||
ServletHolder subsServletHolder = new ServletHolder();
|
||||
subsServletHolder.setServlet(dispatcherServlet);
|
||||
|
@ -150,6 +148,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
mySearchCoordinatorSvc = wac.getBean(ISearchCoordinatorSvc.class);
|
||||
mySearchEntityDao = wac.getBean(ISearchDao.class);
|
||||
ourRestHookSubscriptionInterceptor = wac.getBean(SubscriptionRestHookInterceptor.class);
|
||||
ourEmailSubscriptionInterceptor = wac.getBean(SubscriptionEmailInterceptor.class);
|
||||
ourSearchParamRegistry = wac.getBean(SearchParamRegistryDstu3.class);
|
||||
|
||||
myFhirCtx.getRestfulClientFactory().setSocketTimeout(5000000);
|
||||
|
|
|
@ -163,7 +163,7 @@ public class SearchCoordinatorSvcImplTest {
|
|||
params.add("name", new StringParam("ANAME"));
|
||||
|
||||
List<Long> pids = createPidSequence(10, 800);
|
||||
Iterator<Long> iter = new SlowIterator<Long>(pids.iterator(), 2);
|
||||
Iterator<Long> iter = new SlowIterator<Long>(pids.iterator(), 1);
|
||||
when(mySearchBuider.createQuery(Mockito.same(params), any(String.class))).thenReturn(iter);
|
||||
|
||||
doAnswer(loadPids()).when(mySearchBuider).loadResourcesByPid(any(List.class), any(List.class), any(Set.class), anyBoolean(), any(EntityManager.class), any(FhirContext.class), same(myCallingDao));
|
||||
|
|
|
@ -2,9 +2,7 @@ package ca.uhn.fhir.jpa.subscription;
|
|||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.provider.BaseResourceProviderDstu2Test;
|
||||
import ca.uhn.fhir.jpa.subscription.email.EmailDetails;
|
||||
import ca.uhn.fhir.jpa.subscription.email.EmailSender;
|
||||
import ca.uhn.fhir.jpa.subscription.email.IEmailSender;
|
||||
import ca.uhn.fhir.jpa.subscription.email.JavaMailEmailSender;
|
||||
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
||||
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||
|
@ -14,9 +12,6 @@ import ca.uhn.fhir.model.dstu2.valueset.ObservationStatusEnum;
|
|||
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionChannelTypeEnum;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import com.icegreen.greenmail.imap.ImapConstants;
|
||||
import com.icegreen.greenmail.store.MailFolder;
|
||||
import com.icegreen.greenmail.store.Store;
|
||||
import com.icegreen.greenmail.util.GreenMail;
|
||||
import com.icegreen.greenmail.util.GreenMailUtil;
|
||||
import com.icegreen.greenmail.util.ServerSetupTest;
|
||||
|
@ -62,7 +57,7 @@ public class EmailSubscriptionDstu2Test extends BaseResourceProviderDstu2Test {
|
|||
public void before() throws Exception {
|
||||
super.before();
|
||||
|
||||
EmailSender emailSender = new EmailSender();
|
||||
JavaMailEmailSender emailSender = new JavaMailEmailSender();
|
||||
emailSender.setSmtpServerHost("localhost");
|
||||
emailSender.setSmtpServerPort(3025);
|
||||
emailSender.start();
|
||||
|
@ -129,7 +124,7 @@ public class EmailSubscriptionDstu2Test extends BaseResourceProviderDstu2Test {
|
|||
|
||||
@Test
|
||||
public void testSubscribeAndDeliver() throws Exception {
|
||||
String payload = "application/json";
|
||||
String payload = "A subscription update has been received";
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
|
||||
|
@ -153,12 +148,12 @@ public class EmailSubscriptionDstu2Test extends BaseResourceProviderDstu2Test {
|
|||
ourLog.info("Received: " + GreenMailUtil.getWholeMessage(messages[msgIdx]));
|
||||
assertEquals("HAPI FHIR Subscriptions", messages[msgIdx].getSubject());
|
||||
assertEquals(1, messages[msgIdx].getFrom().length);
|
||||
assertEquals("unknown@sender.com", ((InternetAddress) messages[msgIdx].getFrom()[0]).getAddress());
|
||||
assertEquals("noreply@unknown.com", ((InternetAddress) messages[msgIdx].getFrom()[0]).getAddress());
|
||||
assertEquals(2, messages[msgIdx].getAllRecipients().length);
|
||||
assertEquals("to1@example.com", ((InternetAddress) messages[msgIdx].getAllRecipients()[0]).getAddress());
|
||||
assertEquals("to2@example.com", ((InternetAddress) messages[msgIdx].getAllRecipients()[1]).getAddress());
|
||||
assertEquals(1, messages[msgIdx].getHeader("Content-Type").length);
|
||||
assertEquals("text/plain; charset=UTF-8", messages[msgIdx].getHeader("Content-Type")[0]);
|
||||
assertEquals("text/plain; charset=us-ascii", messages[msgIdx].getHeader("Content-Type")[0]);
|
||||
String foundBody = GreenMailUtil.getBody(messages[msgIdx]);
|
||||
assertEquals("A subscription update has been received", foundBody);
|
||||
|
||||
|
|
|
@ -72,6 +72,8 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
|
|||
public void beforeReset() {
|
||||
ourCreatedObservations.clear();
|
||||
ourUpdatedObservations.clear();
|
||||
|
||||
ourRestHookSubscriptionInterceptor.initSubscriptions();
|
||||
}
|
||||
|
||||
private void waitForQueueToDrain() throws InterruptedException {
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.subscription.email;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.BaseResourceProviderDstu3Test;
|
||||
import ca.uhn.fhir.jpa.subscription.RestHookTestDstu2Test;
|
||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.icegreen.greenmail.store.FolderException;
|
||||
import com.icegreen.greenmail.util.GreenMail;
|
||||
import com.icegreen.greenmail.util.ServerSetupTest;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test the rest-hook subscriptions
|
||||
*/
|
||||
public class EmailSubscriptionDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(EmailSubscriptionDstu3Test.class);
|
||||
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
|
||||
private static int ourListenerPort;
|
||||
private static RestfulServer ourListenerRestServer;
|
||||
private static Server ourListenerServer;
|
||||
private static String ourListenerServerBase;
|
||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
||||
private static List<String> ourContentTypes = new ArrayList<>();
|
||||
private static GreenMail ourTestSmtp;
|
||||
private List<IIdType> mySubscriptionIds = new ArrayList<>();
|
||||
|
||||
@After
|
||||
public void afterUnregisterEmailListener() {
|
||||
ourLog.info("**** Starting @After *****");
|
||||
|
||||
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(ourEmailSubscriptionInterceptor);
|
||||
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeRegisterEmailListener() throws FolderException {
|
||||
ourTestSmtp.purgeEmailFromAllMailboxes();;
|
||||
ourRestServer.registerInterceptor(ourEmailSubscriptionInterceptor);
|
||||
|
||||
ourEmailSubscriptionInterceptor.setDefaultFromAddress("123@hapifhir.io");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
ourTestSmtp.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourTestSmtp = new GreenMail(ServerSetupTest.SMTP);
|
||||
ourTestSmtp.start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Subscription createSubscription(String theCriteria, String thePayload, String theEndpoint) throws InterruptedException {
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.REQUESTED);
|
||||
subscription.setCriteria(theCriteria);
|
||||
|
||||
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
|
||||
channel.setType(Subscription.SubscriptionChannelType.EMAIL);
|
||||
channel.setPayload(thePayload);
|
||||
channel.setEndpoint("mailto:foo@example.com");
|
||||
subscription.setChannel(channel);
|
||||
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();
|
||||
subscription.setId(methodOutcome.getId().getIdPart());
|
||||
mySubscriptionIds.add(methodOutcome.getId());
|
||||
|
||||
waitForQueueToDrain();
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
private Observation sendObservation(String code, String system) {
|
||||
Observation observation = new Observation();
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode(code);
|
||||
coding.setSystem(system);
|
||||
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(observation).execute();
|
||||
|
||||
String observationId = methodOutcome.getId().getIdPart();
|
||||
observation.setId(observationId);
|
||||
|
||||
return observation;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmailSubscriptionNormal() throws Exception {
|
||||
String payload = "This is the body";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
waitForQueueToDrain();
|
||||
|
||||
sendObservation(code, "SNOMED-CT");
|
||||
waitForQueueToDrain();
|
||||
|
||||
List<MimeMessage> received = Arrays.asList(ourTestSmtp.getReceivedMessages());
|
||||
waitForSize(1, received);
|
||||
|
||||
assertEquals(1, received.get(0).getFrom().length);
|
||||
assertEquals("123@hapifhir.io", ((InternetAddress)received.get(0).getFrom()[0]).getAddress());
|
||||
assertEquals(1, received.get(0).getAllRecipients().length);
|
||||
assertEquals("foo@example.com", ((InternetAddress)received.get(0).getAllRecipients()[0]).getAddress());
|
||||
assertEquals("text/plain; charset=us-ascii", received.get(0).getContentType());
|
||||
assertEquals("This is the body", received.get(0).getContent().toString().trim());
|
||||
assertEquals(mySubscriptionIds.get(0).toUnqualifiedVersionless().getValue(), received.get(0).getHeader("X-FHIR-Subscription")[0]);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEmailSubscriptionWithCustom() throws Exception {
|
||||
String payload = "This is the body";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
Subscription sub1 = createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
|
||||
Subscription subscriptionTemp = ourClient.read(Subscription.class, sub1.getId());
|
||||
Assert.assertNotNull(subscriptionTemp);
|
||||
subscriptionTemp.getChannel().addExtension()
|
||||
.setUrl(JpaConstants.EXT_SUBSCRIPTION_EMAIL_FROM)
|
||||
.setValue(new StringType("myfrom@from.com"));
|
||||
subscriptionTemp.getChannel().addExtension()
|
||||
.setUrl(JpaConstants.EXT_SUBSCRIPTION_SUBJECT_TEMPLATE)
|
||||
.setValue(new StringType("This is a subject"));
|
||||
subscriptionTemp.setIdElement(subscriptionTemp.getIdElement().toUnqualifiedVersionless());
|
||||
ourClient.update().resource(subscriptionTemp).withId(subscriptionTemp.getIdElement()).execute();
|
||||
waitForQueueToDrain();
|
||||
|
||||
|
||||
sendObservation(code, "SNOMED-CT");
|
||||
waitForQueueToDrain();
|
||||
|
||||
List<MimeMessage> received = Arrays.asList(ourTestSmtp.getReceivedMessages());
|
||||
waitForSize(1, received);
|
||||
|
||||
assertEquals(1, received.size());
|
||||
assertEquals(1, received.get(0).getFrom().length);
|
||||
assertEquals("myfrom@from.com", ((InternetAddress)received.get(0).getFrom()[0]).getAddress());
|
||||
assertEquals(1, received.get(0).getAllRecipients().length);
|
||||
assertEquals("foo@example.com", ((InternetAddress)received.get(0).getAllRecipients()[0]).getAddress());
|
||||
assertEquals("text/plain; charset=us-ascii", received.get(0).getContentType());
|
||||
assertEquals("This is a subject", received.get(0).getSubject().toString().trim());
|
||||
assertEquals("This is the body", received.get(0).getContent().toString().trim());
|
||||
assertEquals(mySubscriptionIds.get(0).toUnqualifiedVersionless().getValue(), received.get(0).getHeader("X-FHIR-Subscription")[0]);
|
||||
}
|
||||
|
||||
private void waitForQueueToDrain() throws InterruptedException {
|
||||
RestHookTestDstu2Test.waitForQueueToDrain(ourEmailSubscriptionInterceptor);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startListenerServer() throws Exception {
|
||||
ourListenerPort = PortUtil.findFreePort();
|
||||
ourListenerRestServer = new RestfulServer(FhirContext.forDstu3());
|
||||
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();
|
||||
}
|
||||
|
||||
public static class ObservationListener implements IResourceProvider {
|
||||
|
||||
@Create
|
||||
public MethodOutcome create(@ResourceParam Observation theObservation, HttpServletRequest theRequest) {
|
||||
ourLog.info("Received Listener Create");
|
||||
ourContentTypes.add(theRequest.getHeader(Constants.HEADER_CONTENT_TYPE).replaceAll(";.*", ""));
|
||||
ourCreatedObservations.add(theObservation);
|
||||
return new MethodOutcome(new IdType("Observation/1"), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Observation.class;
|
||||
}
|
||||
|
||||
@Update
|
||||
public MethodOutcome update(@ResourceParam Observation theObservation, HttpServletRequest theRequest) {
|
||||
ourUpdatedObservations.add(theObservation);
|
||||
ourContentTypes.add(theRequest.getHeader(Constants.HEADER_CONTENT_TYPE).replaceAll(";.*", ""));
|
||||
ourLog.info("Received Listener Update (now have {} updates)", ourUpdatedObservations.size());
|
||||
return new MethodOutcome(new IdType("Observation/1"), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
package ca.uhn.fhir.jpa.subscription.email;
|
||||
|
||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||
import com.icegreen.greenmail.util.GreenMail;
|
||||
import com.icegreen.greenmail.util.GreenMailUtil;
|
||||
import com.icegreen.greenmail.util.ServerSetup;
|
||||
import com.icegreen.greenmail.util.ServerSetupTest;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
@ -15,21 +18,23 @@ import java.util.Arrays;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class EmailSenderTest {
|
||||
public class JavaMailEmailSenderTest {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(EmailSenderTest.class);
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(JavaMailEmailSenderTest.class);
|
||||
private static GreenMail ourTestSmtp;
|
||||
private static int ourPort;
|
||||
|
||||
@Test
|
||||
public void testSend() throws Exception {
|
||||
EmailSender sender = new EmailSender();
|
||||
JavaMailEmailSender sender = new JavaMailEmailSender();
|
||||
sender.setSmtpServerHost("localhost");
|
||||
sender.setSmtpServerPort(3025);
|
||||
sender.setSmtpServerPort(ourPort);
|
||||
sender.start();
|
||||
|
||||
String body = "foo";
|
||||
|
||||
EmailDetails details = new EmailDetails();
|
||||
details.setSubscription(new IdType("Subscription/123"));
|
||||
details.setFrom("foo@example.com ");
|
||||
details.setTo(Arrays.asList(" to1@example.com", "to2@example.com "));
|
||||
details.setSubjectTemplate("test subject");
|
||||
|
@ -46,7 +51,7 @@ public class EmailSenderTest {
|
|||
assertEquals("to1@example.com", ((InternetAddress)messages[0].getAllRecipients()[0]).getAddress());
|
||||
assertEquals("to2@example.com", ((InternetAddress)messages[0].getAllRecipients()[1]).getAddress());
|
||||
assertEquals(1, messages[0].getHeader("Content-Type").length);
|
||||
assertEquals("text/plain; charset=UTF-8", messages[0].getHeader("Content-Type")[0]);
|
||||
assertEquals("text/plain; charset=us-ascii", messages[0].getHeader("Content-Type")[0]);
|
||||
String foundBody = GreenMailUtil.getBody(messages[0]);
|
||||
assertEquals("foo", foundBody);
|
||||
}
|
||||
|
@ -58,7 +63,10 @@ public class EmailSenderTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourTestSmtp = new GreenMail(ServerSetupTest.SMTP);
|
||||
ourPort = RandomServerPortProvider.findFreePort();
|
||||
ServerSetup smtp = new ServerSetup(ourPort, null, ServerSetup.PROTOCOL_SMTP);
|
||||
smtp.setServerStartupTimeout(2000);
|
||||
ourTestSmtp = new GreenMail(smtp);
|
||||
ourTestSmtp.start();
|
||||
}
|
||||
|
|
@ -34,6 +34,9 @@ public class IncomingRequestAddressStrategy implements IServerAddressStrategy {
|
|||
|
||||
@Override
|
||||
public String determineServerBase(ServletContext theServletContext, HttpServletRequest theRequest) {
|
||||
if (theRequest == null) {
|
||||
return null;
|
||||
}
|
||||
String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI());
|
||||
|
||||
String servletPath;
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class IncomingRequestAddressStrategyTest {
|
||||
|
||||
@Test
|
||||
public void testRequestWithNull() {
|
||||
IncomingRequestAddressStrategy s = new IncomingRequestAddressStrategy();
|
||||
String result = s.determineServerBase(null, null);
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,11 @@
|
|||
<!--
|
||||
Test dependencies on other optional parts of HAPI
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2.1</artifactId>
|
||||
|
|
|
@ -23,6 +23,11 @@
|
|||
<!--
|
||||
Test dependencies on other optional parts of HAPI
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||
|
|
|
@ -101,6 +101,11 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-client</artifactId>
|
||||
|
@ -122,6 +127,7 @@
|
|||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
|
|
|
@ -29,6 +29,11 @@
|
|||
<!--
|
||||
Test dependencies on other optional parts of HAPI
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||
|
|
|
@ -29,6 +29,11 @@
|
|||
<!--
|
||||
Optional dependencies from RI codebase
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>es.nitaur.markdown</groupId>
|
||||
<artifactId>txtmark</artifactId>
|
||||
|
|
|
@ -100,6 +100,11 @@
|
|||
</dependency>
|
||||
|
||||
<!-- Test Deps -->
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-converter</artifactId>
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
</ul>
|
||||
]]>
|
||||
</action>
|
||||
|
||||
<action type="fix">
|
||||
The Android client module has been restored to working order, and no longer
|
||||
requires a special classifier or an XML parser to be present in order to
|
||||
|
|
Loading…
Reference in New Issue