JHipster with MDHT library - jhipster

I included MDHT in pom.xml
<dependency>
<groupId>org.openehealth.ipf.oht.mdht</groupId>
<artifactId>ipf-oht-mdht-uml-cda-ccd</artifactId>
<version>1.2.0.201212201425</version>
</dependency>
And I have created a method in resource as below where I wanted to load patients profile information
#GetMapping("/patients/profile/{id}")
#Timed
public ResponseEntity<PatientProfileDTO> getPatientProfile(#PathVariable Long id) {
try {
PatientProfileDTO patientProfileDTO = new PatientProfileDTO();
CDAUtil.loadPackages();
ContinuityOfCareDocument ccDocument = (ContinuityOfCareDocument) CDAUtil.load(new FileInputStream("patient_ccd.xml"));
//set patientProfileDTO here by reading patient_ccd.xml
return ResponseUtil.wrapOrNotFound(Optional.ofNullable(patientProfileDTO));
} catch (Exception e) {
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "Error", "An exception occured while reading patient profile")).body(null);
}
}
I get exception org.openhealthtools.mdht.uml.cda.impl.ClinicalDocumentImpl cannot be cast to org.openhealthtools.mdht.uml.cda.ccd.ContinuityOfCareDocument on line ContinuityOfCareDocument ccDocument = (ContinuityOfCareDocument) CDAUtil.load(new FileInputStream("patient_ccd.xml"));
Has anyone encountered such issue or can suggest any any solution? I had been struggling for two days...

Related

How to connect to Azure ServiceBus in Quarkus

I want to connect to ServiceBus subscription from Quarkus. I found this article, which suggests to use ServiceBusJmsConnectionFactory and I am trying to make it work with smallrye
So far I tried:
import com.microsoft.azure.servicebus.jms.ServiceBusJmsConnectionFactory
import com.microsoft.azure.servicebus.primitives.ConnectionStringBuilder
import javax.enterprise.context.ApplicationScoped
import javax.enterprise.inject.Produces
import javax.jms.ConnectionFactory
#ApplicationScoped
class ConnectionFactoryBean {
#Produces
fun factory(): ConnectionFactory {
var connectionStringBuilder = ConnectionStringBuilder("Endpoint=sb://mynamespace.servicebus.windows.net/;SharedAccessKeyName=NAME;SharedAccessKey=KEY");
return ServiceBusJmsConnectionFactory(connectionStringBuilder, null)
}
}
Then in my application.properties:
mp.messaging.incoming.my_topic_name.connector=smallrye-jms
And finally to receive messages:
#Incoming("my_topic_name")
protected suspend fun receiveMyEvent(myEvent: String) {
//process
}
In terms of versions:
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>service-bus-jms-connection-factory</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-reactive-messaging-jms</artifactId>
<version>3.4.0</version>
</dependency>
It is failing with "An API incompatibility" error.
What is the correct way to receive messages using Kotlin/Quarkus from Azure ServiceBus?
UPDATE
I also tried to follow approach from Reactive messaging AMQP and Service Bus with Open Liberty
For that I dropped 2 listed dependencies, replaced them with
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-reactive-messaging-amqp</artifactId>
</dependency>
And completely removed ConnectionFactoryBean.
For that I face
javax.net.ssl.SSLHandshakeException: Failed to create SSL connection
error. Adding quarkus.tls.trust-all=true or quarkus.ssl.native=true to properties did not work...
And it is still unclear, how to connect to the subscription? Will it be a change to the #Incoming attribute?
You can use Azure SDK libraries (maven artefact - com.azure.messaging.servicebus) to connect to Service Bus subscription.
For that you will need to create a ServiceBusProcessorClient connect to your namespace using usual connection string (available from the azure portal
under access policies), specify topicName and subscriptionName of it and then wait for messages. Here is an example code:
#ApplicationScoped
class ServiceBusClient() {
private val scope = CoroutineScope(SupervisorJob())
fun onStart(#Observes event: StartupEvent) {
scope.startClient()
}
fun onStop(#Observes event: ShutdownEvent) {
scope.cancel()
}
private fun CoroutineScope.startClient() = launch {
val processorClient: ServiceBusProcessorClient = ServiceBusClientBuilder()
.connectionString("CONNECTION_STRING")
.processor()
.topicName("TOPIC_NAME")
.subscriptionName("SUBSCRIPTION_NAME")
.processMessage { receivedMessageContext -> onMessage(receivedMessageContext) }
.processError { errorContext -> onError(errorContext) }
.buildProcessorClient()
processorClient.start()
}
private fun onMessage(context: ServiceBusReceivedMessageContext) {
//Process message
}
private fun onError(context: ServiceBusErrorContext) {
//Handle errors
}
}
You could get the content of the message using context.message.applicationProperties["PROPERTY_NAME"], context.message.body or context.message.subject as required.

Class exception when trying to move a email using the spring integration message payload

Hi I have configured the default filter as below and if some emails have a certain subject or from address I try to move them to specific folders using java mail api as below:
Filter implementation:
#Bean(name = ImapAdaptersUtil.DEFAULT_FILTER_BEAN_NAME)
#Scope(WebApplicationContext.SCOPE_APPLICATION)
public MessageSelector defaultFilter() {
return message -> {
if (message.getPayload() instanceof MimeMessage) {
try {
String from = Optional.ofNullable(((InternetAddress) ((MimeMessage) message.getPayload()).getFrom()[0]).getAddress()).orElse(GeneralConst.EMPTY_STRING);
String subject = Optional.ofNullable(((MimeMessage) message.getPayload()).getSubject()).orElse(GeneralConst.EMPTY_STRING);
if (!from.matches(DELIVERY_ERROR_FROM)
&& !from.matches(SPAM_FROM)
&& !subject.matches(DELIVERY_ERROR_SUBJECT)
&& !subject.matches(OUT_OF_OFFICE)
&& !subject.matches(SPAM_SUBJECT)) {
return true;
}
} catch (MessagingException me) {
throw new ApplicationBusinessException(ApplicationBusinessException.ApplicationBusinessExceptionType.FUNCTIONAL_VIOLATION,
"Could not filter incoming email: " + me.getMessage());
}
}
try {
this.moveMessage(((MimeMessage) message.getPayload()));
} catch (MessagingException me) {
throw new ApplicationBusinessException(ApplicationBusinessException.ApplicationBusinessExceptionType.FUNCTIONAL_VIOLATION,
"Could not move incoming email: " + me.getMessage());
}
return false;
};
}
Move to folder implementation:
private void moveMessage(MimeMessage message) throws MessagingException {
Folder folder = message.getFolder();
Store store = folder.getStore();
Folder[] folders = store.getDefaultFolder().list("*");
for (Folder folder1 : folders) {
LOGGER.info("folder name {}", folder1.getName());
}
Folder deliveryErrorFolder = store.getFolder("Delivery error");
if (!deliveryErrorFolder.exists()) {
if (deliveryErrorFolder.create(Folder.HOLDS_MESSAGES)) {
deliveryErrorFolder.setSubscribed(true);
move(message, folder, deliveryErrorFolder);
LOGGER.info("Delivery error created");
}
} else {
move(message, folder, deliveryErrorFolder);
}
}
private void move(MimeMessage message, Folder folder, Folder spamFolder) throws MessagingException {
List<javax.mail.Message> tempList = new ArrayList<>();
tempList.add(message);
javax.mail.Message[] tempMessageArray = tempList.toArray(new javax.mail.Message[0]);
folder.copyMessages(tempMessageArray, spamFolder);
LOGGER.info("message moved");
}
ImapMailReceiver configured as an Integration flow :
public static IntegrationFlow getImapAdapterIntegrationFlow(String imapsUrl, MessageSelector filter, QueueChannelSpec channelSpec) {
return IntegrationFlows
.from(Mail.imapInboundAdapter(imapsUrl)
.userFlag("testSIUserFlag")
.simpleContent(false)
.autoCloseFolder(false)
.shouldMarkMessagesAsRead(true)
.javaMailProperties(getPropertiesBuilderConsumer()),
e -> e.autoStartup(true)
.poller(p -> p.fixedDelay(1000)))
.filter(filter)
.channel(channelSpec)
.get();
}
I get this exception :
Caused by: java.lang.ClassCastException: class org.springframework.integration.mail.AbstractMailReceiver$IntegrationMimeMessage cannot be cast to class com.sun.mail.imap.IMAPMessage (org.springframework.integration.mail.AbstractMailReceiver$IntegrationMimeMessage and com.sun.mail.imap.IMAPMessage are in unnamed module of loader 'app')
at com.sun.mail.imap.Utility.toMessageSet(Utility.java:85)
Yeah... What you are looking for is available starting with version 5.4: https://docs.spring.io/spring-integration/docs/current/reference/html/mail.html#mail-inbound
Starting with version 5.4, it is possible now to return a MimeMessage as is without any conversion or eager content loading. This functionality is enabled with this combination of options: no headerMapper provided, the simpleContent property is false and the autoCloseFolder property is false.
So, all good in your config - only what you need to to upgrade your project to the latest Spring Integration. Directly with the 5.4.5 or via respective latest Spring Boot.

jHipster mongock migration

I am migrating off of mongobee to mongock so we can use Atlas. I've followed the commits on the suggested changes that have been merged into master and have modified CloudDatabaseConfiguration, DatabaseConfiguration, and InitialSetupMigration classes. I've also updated the pom to import the mongock 4.1.17 dependencies.
Running the app there seems to be no issues. I've tested the change log and everything operates as it should. When i run my tests, however, i am getting an error stating it cannot find the class org/springframework/data/mongodb/MongoDatabaseFactory.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongockInitializingBeanRunner' defined in class path resource [com/ioi/helpdesk/gateway/config/DatabaseConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: org/springframework/data/mongodb/MongoDatabaseFactory
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
<dependency>
<groupId>com.github.cloudyrock.mongock</groupId>
<artifactId>mongock-spring-v5</artifactId>
<version>4.1.17</version>
</dependency>
<dependency>
<groupId>com.github.cloudyrock.mongock</groupId>
<artifactId>mongodb-springdata-v3-driver</artifactId>
<version>4.1.17</version>
</dependency>
I have not changed the starter data dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
#Configuration
#EnableMongoRepositories("com.ioi.helpdesk.gateway.repository")
#Profile("!" + JHipsterConstants.SPRING_PROFILE_CLOUD)
#Import(value = MongoAutoConfiguration.class)
#EnableMongoAuditing(auditorAwareRef = "springSecurityAuditorAware")
public class DatabaseConfiguration {
private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
#Bean
public ValidatingMongoEventListener validatingMongoEventListener() {
return new ValidatingMongoEventListener(validator());
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(DateToZonedDateTimeConverter.INSTANCE);
converters.add(ZonedDateTimeToDateConverter.INSTANCE);
return new MongoCustomConversions(converters);
}
#Bean
public MongockSpring5.MongockInitializingBeanRunner mongockInitializingBeanRunner(ApplicationContext springContext,
MongoTemplate mongoTemplate,
#Value("${mongock.lockAcquiredForMinutes:5}") long lockAcquiredForMinutes,
#Value("${mongock.maxWaitingForLockMinutes:3}") long maxWaitingForLockMinutes,
#Value("${mongock.maxTries:3}") int maxTries) {
try {
log.info("INITIALIZING MONGOCK!");
SpringDataMongo3Driver driver = SpringDataMongo3Driver.withLockSetting(mongoTemplate, lockAcquiredForMinutes, maxWaitingForLockMinutes, maxTries);
MongockSpring5.MongockInitializingBeanRunner runner = MongockSpring5.builder()
.setDriver(driver)
.addChangeLogsScanPackage("com.ioi.helpdesk.gateway.config.dbmigrations")
.setSpringContext(springContext)
.buildInitializingBeanRunner();
log.info("MONGOCK INITIALIZED!");
return runner;
} catch(Exception e) {
log.info("Error during Mongock initalization - " + ExceptionUtils.getStackTrace(e));
}
return null;
}
}
Am I missing a test dependency or incorrectly included one?

Autofac - ForAllOtherMembers - Mapper not used

I have implemented the CaseInsensitiveFromStringDictionaryMapper as proposed here https://github.com/AutoMapper/AutoMapper/issues/3243
I also have registered this mapper into autofac with the following code
protected void ConfigureAutomapper(ContainerBuilder builder)
{
var config = new MapperConfiguration(cfg =>
{
foreach (var assembly in GetAssemblies(CustomAssembliesPrefix))
{
cfg.AddMaps(assembly);
}
cfg.Mappers.Insert(0, new CaseInsensitiveFromStringDictionaryMapper());
});
try
{
config.AssertConfigurationIsValid();
}
catch (AutoMapperConfigurationException ex)
{
var message = new StringBuilder();
message.AppendLine("Automapper configuration error");
Exception exception = ex;
while (exception != null)
{
message.AppendLine($"Message: {ex.Message}");
message.AppendLine($"Stack trace: ");
message.AppendLine($"{ex.StackTrace}");
message.AppendLine($"");
exception = exception.InnerException;
}
EventLogProvider.LogEvent(EventType.ERROR, nameof(WebContainer), "Automapper configuration error", message.ToString());
throw;
}
builder.Register(c => new Mapper(config))
.As<IMapper>()
.SingleInstance();
}
if I just do that, I am able to execute the following code and it maps all the properties of my target object perfectly:
mapper.Map<ReferenceSearchResultDocument>(documentSearchResult.Document)
But I need to some specific stuffs on some members so I have created a Profile and a mapping for those members but I would like to have the default behavior (so watching case insensitively in my dictionary) for my other members.
I have tested the following code:
.ForAllOtherMembers(opt => opt.MapFrom(src => src[opt.DestinationMember.Name]))
but of course it isn't the same as letting the mappers doing they jobs.
How could I fix it?
Regards,
Benjamin

MOXy: Efficient deep copy of JAXBElement

docx4j v3.3.0 uses the following code to clone a JAXB object:
public static <T> T deepCopy(T value, JAXBContext jc) {
if (value==null) {
throw new IllegalArgumentException("Can't clone a null argument");
}
try {
#SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) value.getClass();
JAXBElement<T> contentObject = new JAXBElement<T>(new QName(clazz.getSimpleName()), clazz, value);
JAXBSource source = new JAXBSource(jc, contentObject);
JAXBElement<T> elem = jc.createUnmarshaller().unmarshal(source, clazz);
T res;
if (value instanceof JAXBElement<?>) {
#SuppressWarnings("unchecked")
T resT = (T) elem;
res = resT;
} else {
#SuppressWarnings("unchecked")
T resT = (T) elem.getValue();
res = resT;
}
return res;
} catch (JAXBException ex) {
throw new IllegalArgumentException(ex);
}
}
With MOXy v2.5.2 (which we use, since it supports Java 6) and the latest 2.6.3, attempting to clone a JAXBElement, for example:
public void testIssue212() {
CTBookmark bookmark = Context.getWmlObjectFactory().createCTBookmark();
JAXBElement<CTBookmark> el =Context.getWmlObjectFactory().createBodyBookmarkStart(bookmark);
Object o = XmlUtils.deepCopy(el);
}
results in:
[Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor for class javax.xml.bind.JAXBElement was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.]
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:980)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:303)
at org.docx4j.XmlUtils.deepCopy(XmlUtils.java:974)
... 25 more
Caused by: Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor for class javax.xml.bind.JAXBElement was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.
at org.eclipse.persistence.exceptions.XMLMarshalException.descriptorNotFoundInProject(XMLMarshalException.java:140)
at org.eclipse.persistence.internal.oxm.Context$ContextState.getSession(Context.java:145)
at org.eclipse.persistence.oxm.XMLContext$XMLContextState.getSession(XMLContext.java:795)
at org.eclipse.persistence.oxm.XMLContext$XMLContextState.getSession(XMLContext.java:1)
at org.eclipse.persistence.internal.oxm.Context.getSession(Context.java:466)
at org.eclipse.persistence.oxm.XMLContext.getSession(XMLContext.java:364)
at org.eclipse.persistence.oxm.XMLContext.getSession(XMLContext.java:1)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:466)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:695)
at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:655)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:301)
... 26 more
We can workaround this with something like:
JAXBElement<T> elem;
if (Context.getJaxbImplementation().equals(JAXBImplementation.ECLIPSELINK_MOXy)
&& value instanceof JAXBElement<?>) {
elem = (JAXBElement<T>) value;
Class<?> valueClass = elem.getDeclaredType();
Marshaller mar = jc.createMarshaller();
ByteArrayOutputStream bout = new ByteArrayOutputStream(256);
mar.marshal(elem, bout);
Unmarshaller unmar = jc.createUnmarshaller();
elem = (JAXBElement<T>)unmar.unmarshal(new StreamSource(new ByteArrayInputStream(
bout.toByteArray())), valueClass);
}
but is there a better way?
Disclaimer: I'm the author of JAXB2-Basics that includes the Copyable PluginĀ“ which I think fits the task pretty well.
You may be interested Copyable Plugin, it generates reflection-free strategic copy methods.
Activation in Maven (see also Using JAXB2 Basics Plugins):
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<configuration>
<extension>true</extension>
<args>
<arg>-Xcopyable</arg>
</args>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
</plugin>
</plugins>
</configuration>
</plugin>
The plugin then generates deep, reflection-free and strategy-based clone and copyTo methods (see below). This gives you very efficient copying. You can also "copy" to an existing instance or customize what and how should be copied by specifying your own strategy. For instance, you may want to avoid copying id fields or something like that. Generated code also knows how to deal with JAXBElement.
This is a kind of code generated:
public Object clone() {
return copyTo(createNewInstance());
}
public Object copyTo(Object target) {
final CopyStrategy2 strategy = JAXBCopyStrategy.INSTANCE;
return copyTo(null, target, strategy);
}
public Object copyTo(ObjectLocator locator, Object target, CopyStrategy2 strategy) {
final Object draftCopy = ((target == null)?createNewInstance():target);
if (draftCopy instanceof IssueJIIB35) {
final IssueJIIB35 copy = ((IssueJIIB35) draftCopy);
{
Boolean nameShouldBeCopiedAndSet = strategy.shouldBeCopiedAndSet(locator, this.isSetName());
if (nameShouldBeCopiedAndSet == Boolean.TRUE) {
String sourceName;
sourceName = this.getName();
String copyName = ((String) strategy.copy(LocatorUtils.property(locator, "name", sourceName), sourceName, this.isSetName()));
copy.setName(copyName);
} else {
if (nameShouldBeCopiedAndSet == Boolean.FALSE) {
copy.name = null;
}
}
}
// ...
}
return draftCopy;
}
public Object createNewInstance() {
return new IssueJIIB35();
}
Might look a bit weird/cumbersome but it takes quite a few JAXB peculiarities into account.
Turns out the docx4j code introduced in https://github.com/plutext/docx4j/pull/163 had issues copying a JAXBElement, whether using MOXy or Sun/Oracle reference implementation.
https://github.com/plutext/docx4j/commit/b5d8b4722e814945e502da9f0516d59c498b64bb fixes it

Resources