In our project we have a task of sending notification to some user after some task is completed.
Following is the code written in the BPMN2.0 xml -
<serviceTask id="notifyPartner" name="Notify Partner" flowable:type="mail">
<documentation>Notify Partner about the assignment.</documentation>
<extensionElements>
<flowable:field name="to">
<flowable:string><![CDATA[testemail#some.com]]></flowable:string>
</flowable:field>
<flowable:field name="from">
<flowable:string><![CDATA[testemail#some.com]]></flowable:string>
</flowable:field>
<flowable:field name="subject">
<flowable:string><![CDATA[Notify Partner]]></flowable:string>
</flowable:field>
<flowable:field name="text">
<flowable:string><![CDATA[Notify Partner about the assignment.]]></flowable:string>
</flowable:field>
</extensionElements>
</serviceTask>
With a application.properties as -
spring.flowable.mailServerHost=smtp.gmail.com
spring.flowable.mailServerPort=587
spring.flowable.mailServerUserName=testemail#some.com
spring.flowable.mailServerPassword=****
spring.flowable.mailServerUseTls=true
But all this results in no success. It gives the following error -
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
I even tried setting up all the properties in flowable.cfg.xml also
<property name="mailServerHost" value="smtp.gmail.com" />
<property name="mailServerPort" value="587" />
<property name="mailServerUseTls" value="true" />
<property name="mailServerUsername" value="testemail#some.com" />
<property name="mailServerPassword" value="****" />
Is there any other configuration missing?
Flowable version used is 6.2.1.
In case you are using the Spring Boot starter for Flowable 6.2.1 you will need to remove the leading spring. from your properties.
Your properties should look like:
flowable.mailServerHost=smtp.gmail.com
flowable.mailServerPort=587
flowable.mailServerUserName=testemail#some.com
flowable.mailServerPassword=****
flowable.mailServerUseTls=true
When using Spring Boot the flowable.cfg.xml is not being used to configure the engine.
NOTE: When migrating to Flowable 6.3.x the properties have slightly changed and they need to look like:
flowable.mail.server.host=smtp.gmail.com
flowable.mail.server.port=587
flowable.mail.server.username=testemail#some.com
flowable.mail.server.password=****
flowable.mail.server.use-tls=true
I am using spring container in a batch operation that realize many calls to an remote EJB. When the operation is single-thread everything works fine but when try to use multi-threading to gain performance it throws:
Exception in thread "taskExecutor-1" javax.ejb.EJBException: java.io.IOException: Channel Channel ID e9c80c0d (outbound) of Remoting connection 18f42160 to servername/ip:port has been closed
My stand-alone cliente dependecy is:
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-ejb-client-bom</artifactId>
<type>pom</type>
<version>7.2.0.Final</version>
</dependency>
I'm also using spring's SimpleRemoteStatelessSessionProxyFactory to inject the lookup beans
<bean id="jndiProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="file:/path/jboss-ejb-client.properties" />
</bean>
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment" ref="jndiProperties" />
</bean>
<bean id="operation" class="org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean">
<property name="jndiName" value="ejb:remote/interface/location" />
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="businessInterface" value="com.MyBussinesInterfae" />
</bean>
In my tests I verified that if a Thread-A creates the InitContext and does the JNDI EJB lookup and creates the instance of the EJB remote inferface (under the SRSSPFBean) it can invoke methods via the EJB remote interface, but if an Thread-B gets the reference of the EJB remote interface and tries to invoke a method the exception is thrown.
The only similiar problem found on my search is here and seems related to bugs on Jboss AS 7. I am using Jboss eap 6.2.
Thanks in advance for any help.
Background:
I have a relatively old application that uses Websphere MQ for messaging. It runs on WAS (Websphere Application Server) and uses MDBs (Message Driven Beans). I was successfully able to replace all MDBs using Spring Integration - JMS. My next step is try to see if I can port it out of WAS so that it can run on any other servlet container with a non-IBM JRE (I am trying: apache tomcat). Note that securing channels using SSL is a requirement. I prefer using JNDI.
End Goal:
To decouple my application from the application server (WAS) and other infrastructure like messaging (MQ). But taking this out of WAS onto tomcat is the first step. Next comes the task of updating my messaging infrastructure with something more scalable. This allows me to update individual components of the infrastructure that my app relies on, one thing at a time (app server, messaging layer, datastore) without disrupting my application too much, as I go.
Question:
Now, my challenge is to define JNDI resources on tomcat that can access Websphere MQ. I have made some progress on this using non-SSL channels that I defined in the context.xml file like so:
<Resource
name="jms/qcf_sandbox"
auth="Container"
type="com.ibm.mq.jms.MQQueueConnectionFactory"
factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory for sending messages"
HOST="localhost"
PORT="1414"
CHAN="CHANNEL_SANDBOX"
TRAN="1"
QMGR="QM_SANDBOX"/>
<Resource
name="jms/SandboxQ"
auth="Container"
type="com.ibm.mq.jms.MQQueue"
factory="com.ibm.mq.jms.MQQueueFactory"
description="JMS Queue"
QU="SANDBOX_Q"/>
My next step is to get this to work with SSL channels. I understand the part that involves setting up the keystores (kdb file and cert generation and exchanging), configuring the SSL channels on the QM etc. I have all that working already. How do I get tomcat to use my keystore, cipher suite etc? Pointers or a working example would be great!
Note: I am using Spring Integration 4.2, Websphere MQ v8, Tomcat v9, currently.
I must add that I did try everything without the JNDI first. So here's my spring jms non-ssl config without the JNDI, that works:
<bean id="mq-jms-cf-sandbox"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory">
<ref bean="mqQueueConnectionFactory" />
</property>
</bean>
<bean id="mqQueueConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="localhost" />
<property name="port" value="1414" />
<property name="queueManager" value="QM_SANDBOX" />
<property name="transportType" value="1" />
<property name="channel" value="CHANNEL_SANDBOX" />
</bean>
<bean id="jms-destination-sandbox" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="SANDBOX_Q" />
<property name="baseQueueManagerName">
<value>QM_SANDBOX</value>
</property>
<property name="baseQueueName">
<value>SANDBOX_Q</value>
</property>
</bean>
I think I finally figured out how to pull this off... here's a brief description of the steps. If you need more details let me know.
Pre-reqs:
Websphere MQ Server installed (at least v 8.0.0.2)
Configure the QM, SSL and non-SSL channels, create Qs and all that good stuff you need.
Needless to say, you need the Websphere MQ jars. Be mindful of any licensing restrictions.
Step 1: Get the direct connection working with no SSL, no JNDI. You will need to use these beans to configure your spring based JMS listeners and JMS Templates etc.
<bean id="mq-jms-cf-sandbox"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory">
<ref bean="mqQueueConnectionFactory" />
</property>
</bean>
<bean id="mqQueueConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="localhost" />
<property name="port" value="1414" />
<property name="queueManager" value="QM_SANDBOX" />
<property name="transportType" value="1" />
<property name="channel" value="NON_SSL_CHANNEL" />
</bean>
<bean id="jms-destination-sandbox" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="SANDBOX_Q" />
<property name="baseQueueManagerName">
<value>QM_SANDBOX</value>
</property>
<property name="baseQueueName">
<value>SANDBOX_Q</value>
</property>
</bean>
Step 2: Get the direct connection working with SSL, no JNDI. I found setting this up a little tricky.
2a. Since I was using a non-IBM JRE, I had to make sure the cipher specs & cipher suites needed to be configured according to the mappings specified here:
http://www-01.ibm.com/support/docview.wss?uid=swg1IV66840
This obviously means that we at least have to have our Websphere MQ upgraded to 8.0.0.2. In my case I used ECDHE_RSA_AES_256_GCM_SHA384 on the SSL channel and configured the jms beans within application to use TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, like so:
<bean id="mq-jms-cf-sandbox"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory">
<ref bean="mqQueueConnectionFactory" />
</property>
</bean>
<bean id="mqQueueConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="localhost" />
<property name="port" value="1414" />
<property name="queueManager" value="QM_SANDBOX" />
<property name="transportType" value="1" />
<property name="channel" value="SSL_CHANNEL" />
<property name="SSLCipherSuite" value="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"/>
</bean>
<bean id="jms-destination-sandbox" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="SANDBOX_Q" />
<property name="baseQueueManagerName">
<value>QM_SANDBOX</value>
</property>
<property name="baseQueueName">
<value>SANDBOX_Q</value>
</property>
</bean>
2b. Create certs, keystores (kdbs), exchange certs etc. There are many ways to do this. But be mindful that you will need to stash passwords, the key label for the queue manager must be ‘ibmwebspheremqqmgr’ – all in lower case, no spaces, (without quotes), the key label must be like ‘ibmwebspheremquserid’ – all in lower case, no spaces, (without quotes) where userid is the userid that runs tomcat. If you need more details on exactly how I did it using self signed certs, let me know.
2c. Now you have to get the JVM that tomcat runs, to read your keystores. There are many ways but here's how I did it:
Create a setenv.bat file in the tomcat bin folder, with the following contents (debugging SSL is optional)
set JAVA_OPTS="-Djavax.net.ssl.trustStore=C:\path-to-keystore\key.jks" "-Djavax.net.ssl.trustStorePassword=topsecret" "-Djavax.net.ssl.keyStore=C:\path-to-keystore\key.jks" "-Djavax.net.ssl.keyStorePassword=topsecret" "-Djavax.net.debug=ssl" "-Dcom.ibm.mq.cfg.useIBMCipherMappings=false"
2d. Start tomcat using the following command:
catalina.bat run > ..\logs\tomcat.log 2>&1
To stop, just press ctrl+c (on windows). Whichever way you do it, make sure that setenv.bat is used during start up. Or use JAVA_OPTS to set the keystore properties.
2e. Verify that the using the SSL channel works.
Step 3: Get a JNDI connection working with non-SSL, JNDI
There are many was to set up JNDI on tomcat. Here's how I did it: Within the web application create a file META-INF/Context.xml with the following contents:
<Resource
name="jms/qcf_sandbox"
auth="Container"
type="com.ibm.mq.jms.MQQueueConnectionFactory"
factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory for sending messages"
HOST="localhost"
PORT="1414"
CHAN="NON_SSL_CHANNEL"
TRAN="1"
QMGR="QM_SANDBOX"/>
<Resource
name="jms/SandboxQ"
auth="Container"
type="com.ibm.mq.jms.MQQueue"
factory="com.ibm.mq.jms.MQQueueFactory"
description="JMS Queue"
QU="SANDBOX_Q"/>
Now in your spring config, instead of the direct configurations, all you have to do is:
<jee:jndi-lookup id="mq-jms-cf-sandbox" jndi-name="java:/comp/env/jms/qcf_sandbox" resource-ref="false" />
<jee:jndi-lookup id="jms-destination-sandbox" jndi-name="java:/comp/env/jms/SandboxQ" resource-ref="false" />
Note that for brevity, I just didn't use resource references. In case you do, there a few additional steps which are straight forward.
Step 4: Now the final step is to use an SSL channel and JNDI. Assuming you have done step 2, this is easy. Modify the META-INF/Context.xml with the following contents:
<Resource
name="jms/qcf_sandbox"
auth="Container"
type="com.ibm.mq.jms.MQQueueConnectionFactory"
factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory for sending messages"
HOST="localhost"
PORT="1414"
CHAN="SSL_CHANNEL"
TRAN="1"
QMGR="QM_SANDBOX"
SCPHS="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"/>
<Resource
name="jms/SandboxQ"
auth="Container"
type="com.ibm.mq.jms.MQQueue"
factory="com.ibm.mq.jms.MQQueueFactory"
description="JMS Queue"
QU="SANDBOX_Q"/>
Note the line with SCPHS="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384". If you need to set other such parameters, see the "Short Form" column in this link:
https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.dev.doc/q111800_.htm%23jm10910_?lang=en
Hopefully all this works for you. Good luck!
Once this configuration works, sending messages is pretty straight forward. But this is how you can listen for a message on a queue using Spring JMS
Reference: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/jms.html
Step 1: Use Spring's DefaultMessageListenerContainer and configure your beans in an xml file like so (spring-beans.xml):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<!-- this is the Message Driven POJO (MDP) -->
<bean id="messageListener" class="jmsexample.ExampleListener" />
<!-- and this is the message listener container -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="mq-jms-cf-sandbox"/>
<property name="destination" ref="jms-destination-sandbox"/>
<property name="messageListener" ref="messageListener" />
</bean>
</beans>
Step 2: Add this to your web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context/spring-beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Step 3: Write a Message Listener class like so:
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
public class ExampleListener implements MessageListener {
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
System.out.println(((TextMessage) message).getText());
}
catch (JMSException ex) {
throw new RuntimeException(ex);
}
}
else {
throw new IllegalArgumentException("Message must be of type TextMessage");
}
}
}
Alternatively, instead of step 3, if you are using spring integration, you can do something like so:
<int:channel id="jms-inbound"/>
<int-jms:message-driven-channel-adapter
id="jms-inbound-adapter" container="jmsContainer" channel="jms-inbound"
extract-payload="true" acknowledge="transacted"
message-converter="messagingMessageConverter" />
<beans:bean id="messagingMessageConverter" class="org.springframework.jms.support.converter.MessagingMessageConverter">
</beans:bean>
i'm using Apache CXF web services and Spring Integration and i don't now how to invoke a Spring Integration application from your CXF endpoint.
I have experience working on Apache Camel and is very easy to resolve this problem...but in Spring Integration i don't have any idea....
My lines code are:
In webservices-definition-beans.xml:
<!-- Load CXF modules from cxf.jar -->
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<!--Exposing the HelloWorld service as a SOAP service -->
<bean id="jaxbBean"
class="org.apache.cxf.jaxb.JAXBDataBinding"
scope="prototype"/>
<bean id="jaxws-and-aegis-service-factory"
class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean"
scope="prototype">
<property name="dataBinding" ref="jaxbBean"/>
<property name="serviceConfigurations">
<list>
<bean class="org.apache.cxf.jaxws.support.JaxWsServiceConfiguration"/>
<bean class="org.apache.cxf.aegis.databinding.AegisServiceConfiguration"/>
<bean class="org.apache.cxf.service.factory.DefaultServiceConfiguration"/>
</list>
</property>
</bean>
<jaxws:endpoint id="helloWorld"
serviceName="HelloWorldService"
implementorClass="com.datys.cxf.HelloWorldService"
address="/HelloWorld">
<jaxws:serviceFactory>
<ref bean="jaxws-and-aegis-service-factory"/>
</jaxws:serviceFactory>
</jaxws:endpoint>
In service-definition-beans.xml:
<gateway id="HelloWorldService"
default-request-channel="requestStrings"
default-reply-channel="replyStrings"
service-interface="com.datys.cxf.HelloWorldService">
<method name="sayHello"/>
</gateway>
<channel id="requestStrings"/>
<channel id="replyStrings"/>
<!--<channel id="filesOut"/>-->
<service-activator input-channel="requestStrings"
output-channel="filesOut"
ref="handler" method="handleString"/>
<file:outbound-channel-adapter id="filesOut"
directory="file:D:/OUTPUT"/>
<beans:bean id="handler" class="org.springframework.integration.samples.filecopy.Handler"/>
But when i deploy and call web services with client-webservices return this error:
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Could not instantiate service class com.datys.cxf.HelloWorldService because it is an interface.
at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:171)
at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:94)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:240)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:210)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:103)
at $Proxy29.sayHello(Unknown Source)
Probably the simplest option is to configure a <gateway>. That allows you to provide any interface that you can inject into your endpoint and invoke it to initiate a message flow. Under the covers, the interface is implemented in the same way as other "ProxyFactoryBean" implementations in Spring (e.g. remoting via RMI, HttpInvoker, etc).
Here's a relevant section from the reference manual:
http://static.springsource.org/spring-integration/docs/2.1.x/reference/htmlsingle/#gateway-proxy
I'm trying to use an Mx4j agent (and Spring Framework 3.0.5) to expose some POJOs in my Mule-ESB (Mule 3.1.2) application as an HTTP service. The agent is configured in mule-config.xml as follows:
<management:jmx-mx4j-adaptor jmxAdaptorUrl="http://0.0.0.0:9990" />
Also, I use the Spring MBeanExporter to expose the desired POJOs:
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="assembler" ref="assembler" />
<property name="namingStrategy" ref="namingStrategy" />
<property name="autodetect" value="true" />
</bean>
<bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
<bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource" />
</bean>
<bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
<property name="attributeSource" ref="jmxAttributeSource" />
</bean>
Everything works fine in my desktop environment, which runs in Jetty. When I deploy the EAR to our WebSphere 7 Server, however, the application doesn't start, raising the following exception:
[3/30/12 16:33:58:858 BRT] 00000038 webapp I com.ibm.ws.webcontainer.webapp.WebApp log SRVE0296E: [BaseApp#BaseApp.war][/context][Servlet.LOG]:.Failed to invoke lifecycle phase "start" on object: org.mule.module.management.agent.Mx4jAgent#13ef13ef:.org.mule.api.lifecycle.LifecycleException: Failed to invoke lifecycle phase "start" on object: org.mule.module.management.agent.Mx4jAgent#13ef13ef
at org.mule.lifecycle.phases.DefaultLifecyclePhase.applyLifecycle(DefaultLifecyclePhase.java:236)
at org.mule.lifecycle.RegistryLifecycleManager$RegistryLifecycleCallback.onTransition(RegistryLifecycleManager.java:276)
...
...
Caused by: org.mule.module.management.agent.JmxManagementException: Failed to start Mx4j agent
at org.mule.module.management.agent.Mx4jAgent.start(Mx4jAgent.java:205)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at org.mule.lifecycle.phases.DefaultLifecyclePhase.applyLifecycle(DefaultLifecyclePhase.java:225)
... 67 more
Caused by: javax.management.InstanceNotFoundException: Mule.BaseApp.6:name=Mx4jHttpAdapter
at java.lang.Throwable.<init>(Throwable.java:67)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getMBean(DefaultMBeanServerInterceptor.java:1094)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getMBeanInfo(DefaultMBeanServerInterceptor.java:1384)
at com.sun.jmx.mbeanserver.JmxMBeanServer.getMBeanInfo(JmxMBeanServer.java:892)
at com.ibm.ws.management.AdminServiceImpl.getMBeanInfo(AdminServiceImpl.java:1524)
at com.ibm.ws.management.AdminServiceImpl.checkForOpDeprecation(AdminServiceImpl.java:2662)
at com.ibm.ws.management.AdminServiceImpl.preInvoke(AdminServiceImpl.java:2284)
at com.ibm.ws.management.AdminServiceImpl$1.run(AdminServiceImpl.java:1309)
at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
at com.ibm.ws.management.AdminServiceImpl.invoke(AdminServiceImpl.java:1225)
at com.ibm.ws.management.PlatformMBeanServer.invoke(PlatformMBeanServer.java:743)
at org.mule.module.management.agent.Mx4jAgent.start(Mx4jAgent.java:201)
Looking at the second (and last) stack trace cause, there seem to be some confusion or assumption about the JMX Server Instance Name. However, I have no control on that (and I can't figure why it works fine in Jetty and not in WAS 7).
Has anyone stepped through that before? Am I doing something wrong? Am I missing something here?
Thanks a lot for any response!
For WAS using JMX is not that straightforward. Complications are:
Security - one can't access JMX endpoint by default without further security configuration (out of scope for this discussion).
Websphere's JMX server implementation actually modifies MBean domain names to be prefixed with WAS Node and Cell. There is a WAS-specific API that can get you those, but the takeaway is this can't be done without further coding.
Andrew