How to enable web console on ActiveMq embedded broker - spring

I've configured an ActiveMQ 5.8.0 embedded broker using Spring 3.2.5
This is my jmsconfiguration.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:amq="http://activemq.apache.org/schema/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
<amq:broker brokerName="localhost" dataDirectory="./data" useJmx="true" persistent="true">
<amq:persistenceAdapter>
<amq:kahaDB directory="./kahadb" checksumJournalFiles="true" checkForCorruptJournalFiles="true" />
</amq:persistenceAdapter>
<amq:transportConnectors>
<amq:transportConnector name="websocket" uri="ws://0.0.0.0:61614"/>
<amq:transportConnector name="stomp" uri="stomp://0.0.0.0:61613"/>
<amq:transportConnector name="openwire" uri="tcp://0.0.0.0:61616"/>
</amq:transportConnectors>
</amq:broker>
<amq:connectionFactory id="jmsFactory" brokerURL="vm://localhost" />
</beans>
It would be very nice and useful to be able to access web console ... however i've been trying to enable it without success.
Does anyone knows how to configure it?

You can try hawtio instead - http://hawt.io/
It allows to be installed independent of where the broker resides, and can look inside the JVM to find the broker, and still be used as web console to manage the broker.
hawtio is included out of the box in ActiveMQ 5.9 onwards, and is to replace the old console (the old console is deprecated but still included, but will be removed in a future release).
hawtio can also manage other stuff in the JVM such as Camel, and show JMX, and whatnot.
If you want to include the old web console in your current spring application, then that can be tough as you would need to include all its html/jps content and whatnot. Its not an easy task to do. And then setup your web.xml to include what the old console needs, and so forth.

Related

Apache Camel integration with Activiti6 beta4

I'm trying to use Camel with Activiti6 beta4 using only the UI (activiti-app).
But in the log of the execution of my process model I get the error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myContext' is defined
It seems that the UI is unable to find my applicationContext.xml and/or "myContext" (the camel context inside applicationContext.xml).
My applicationContext.xml is in the /WEB-INF and has this content:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<camelContext id="myContext" xmlns="http://camel.apache.org/schema/spring">
<route>
:::::::MY ROUTE::::::
</route>
</camelContext>
</beans>
Would anyone tell me what is missing?
The name and location of "applicationContext.xml" are correct?
TIA,
Wanderlan
I can't speak to using Activiti 6 beta with Camel, but I have it working on th 5.x engine and Activiti Enterprise Edition (with some hacking).
The default Camel Context that is installed is called camelContext, I see you have declared a Camel context called myContext. For some reason that bean has not instantiated or cannot be found.
Try using he default id of camelContext and see if your behavior changes.
Greg

how can I configure RedisHttpSessionConfigure to fallback if redis is not online

I'm using spring-session + redis as documented here:
http://docs.spring.io/spring-session/docs/current/reference/html5/guides/httpsession-xml.html
How can I configure RedisHttpSessionConfigure such that for local development, redis is not needed and the application will simply default to the container session handling?
Generally this isn't recommended because you are differing your development environment from your production environment. It should be quite trivial to point your dev machine to a Redis instance.
If you need to support it, you can use Spring profiles. For example, with XML you can use something like:
<beans profile="dev">
<bean id="springSessionRepositoryFilter" class="org.springframework.web.filter.CharacterEncodingFilter"/>
</beans>
<beans profile="production">
<context:annotation-config/>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
<bean class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"/>
</beans>
The key is to ensure that your dev environment also has a Bean that implements Filter named springSessionRepositoryFilter. In this example, I used CharacterEncodingFilter which should do nothing since the encoding property is not set but feel free to replace with whatever you like.
The next thing you will need to do is activate your environments. For example, you can use
-Dspring.profiles.active="production"

Using Gateway from another application

I am using spring-boot, spring-integration and hornetq.
I have a central messaging bridge project "app-bridge" and a number of other projects that request information from the bridge. All projects are deployed as "war" files to a tomcat server.
I need to create a synchronous request from "app-1" to the "app-bridge" application ("app-bridge" makes an MQ request to a remote application for the response and I don't want to expose the way it gets the data to each individual application. ie only "app-bridge" should know how to get the response).
In "app-bridge" I have the following gateway defined.
<int:gateway service-interface="org.company.SendAndReceive"
default-request-channel="synchronousOutChannel"
default-reply-channel="synchronousInChannel"
default-reply-timeout="30000"
default-request-timeout="30000">
</int:gateway>
This works fine when run from the "app-bridge" project.
#Autowired
private final SendAndReceive sendAndReceive;
...
#Scheduled(fixedDelay = 30000L)
public void testing() {
sendAndReceive.send("HELLO");
String resposne = sendAndReceive.receive();
System.out.println(resposne); //prints the response or null if a timeout occurred
}
The problem is that I need to run this from the "app-1" project.
How can I achieve this?
UPDATE for #Gary
integration xml file in the app-bridge project.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-file="http://www.springframework.org/schema/integration/file"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-4.1.xsd
http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file-4.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
<!--************************* SENDING ********************************-->
<!-- handle errors -->
<int:channel id="as400SynchronousOutFailedChannel" />
<int-jms:outbound-channel-adapter
id="as400SynchronousOutFailed"
destination-name="as400.synchronous.out.failed"
channel="as400SynchronousOutFailedChannel"
connection-factory="jmsConnectionFactory"/>
<!-- Read local messages from hornet -->
<int:channel id="as400SynchronousOutChannel" />
<int-jms:message-driven-channel-adapter
id="jmsSynchronousAS400Out"
acknowledge="transacted"
destination-name="as400.synchronous.out"
channel="as400SynchronousOutChannel"
connection-factory="jmsConnectionFactory"
error-channel="as400SynchronousOutFailedChannel"
concurrent-consumers="1"
pub-sub-domain="false" />
<!-- Send messages to AS/400 -->
<int-jms:outbound-channel-adapter
id="jmsSynchronousOut"
destination="as400SynchronousOutQueue"
channel="as400SynchronousOutChannel"
jms-template="as400JmsTemplate">
<int-jms:request-handler-advice-chain>
<int:retry-advice max-attempts="3">
<int:exponential-back-off initial="2000" multiplier="2" />
</int:retry-advice>
</int-jms:request-handler-advice-chain>
</int-jms:outbound-channel-adapter>
<!-- Connection to remote AS/400 Queue -->
<bean id="as400SynchronousOutQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="AS400.SYNCHRONOUS.IN" />
<property name="targetClient">
<bean id="com.ibm.mq.jms.JMSC.MQJMS_CLIENT_NONJMS_MQ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>
</property>
</bean>
<!-- Place to put messages that have failed -->
<int-jms:outbound-channel-adapter
id="jmsAS400SynchronousOutFailed"
destination-name="as400.synchronous.out.failed"
channel="as400SynchronousOutFailedChannel"
connection-factory="jmsConnectionFactory"/>
<!--************************* RECEIVING ********************************-->
<!-- handle errors -->
<int:channel id="as400SynchronousInFailedChannel" />
<int-jms:outbound-channel-adapter
id="as400SynchronousInFailed"
destination-name="as400.synchronous.in.failed"
channel="as400SynchronousInFailedChannel"
connection-factory="jmsConnectionFactory"/>
<!-- Receive messages from AS/400 -->
<int:channel id="as400SynchronousInChannel">
<int:rendezvous-queue/>
</int:channel>
<int-jms:message-driven-channel-adapter
id="jmsAS400SynchronousIn"
acknowledge="transacted"
destination="as400SynchronousInQueue"
channel="as400SynchronousInChannel"
connection-factory="as400ConnectionFactory"
error-channel="as400SynchronousInFailedChannel"/>
<!-- Connection to remote AS/400 Queue -->
<bean id="as400SynchronousInQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="AS400.SYNCHRONOUS.OUT" />
</bean>
<int:gateway service-interface="com.example.bridge.as400.As400SendAndReceive"
default-request-channel="as400SynchronousOutChannel"
default-reply-channel="as400SynchronousInChannel"
default-reply-timeout="30000"
default-request-timeout="30000">
</int:gateway>
</beans>
com.example.bridge.as400.As400SendAndReceive java class.
public interface As400SendAndReceive {
public void send(final String message);
public String receive();
}
So I want all my other war applications (app-1, app-2, app-3) to be able to call the "com.example.bridge.as400.As400SendAndReceive" gateway somehow that is defined in the "app-bridge" war. It is also important that if say both "app-1" and "app-2" request a message, it is sent back to the correct requestor. The As400 message does not support HEADERS so it is being sent as a plain MQSTR.
The <int:gateway/> generates a local java API; you can't use it alone for requests to a remote system.
Your app-bridge should have a <int-jms:inbound-gateway/> to service requests over JMS.
The other apps would use an <int:gateway/> wired to send requests to an <int-jms:outbound-gateway/> configured to send messages to the same destination the app-1 inbound gateway is listening on.
EDIT:
The remote apps can't "call" the gateway in app-bridge; it's a simple java object that's only visible within app-bridge.
You need some kind of external communication between app-n and app-bridge. You can choose the technology of your choice, JMS, RMI, RabbitMQ, HTTP, etc, etc.
You need an <int-x:outbound-gateway/> in app-n and an <int-x:inbound-gateway/> in app-bridge.
Where x is whatever you choose to use for the communication. Explore the documentation to make your choice. Given you are already using JMS to talk to the AS/400, maybe JMS would be the best choice (but you need different queues).

Switching between jms providers

I would like to do a SPRING (3.2.1) setup where I can switch the underlying JMS provider depending on the environment you are in e.g. dev, test, prod. I am no expert but have come across #Profile annotation of Spring. I don't really know how to use it. So what I need to do is in DEV environment I want to use ActiveMQ and in PRODUCTION I want to use IBM MQ. Is this possible? If so, would appreciate it if you could provide some config or code to do this. Thanks in advance.
http://static.springsource.org/spring-framework/docs/3.2.1.RELEASE/spring-framework-reference/html/new-in-3.1.html#new-in-3.1-bean-definition-profiles
For XML config, see this blog... http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/
See this blog about #Profile: http://blog.springsource.com/2011/02/14/spring-3-1-m1-introducing-profile/ for using profiles with #Configuration.
It boils down to this...
When using XML configuration, simply add <beans/> elements at the end of your spring config files...
<beans ...>
<bean... />
<beans profile="DEV">
<bean ... // my ActiveMQ config .../>
</beans?
<beans profile="default">
<bean ... // my IBM (or JNDI) config .../>
<beans/>
</beans>
Then run in dev with -Dspring-profiles-active=DEV.
Similarly #Profile can be added to #Configuration classes to limit their use to particular active profiles.

How do I make the JMS transport for CXF repost failed QPid messages? Alternately, is there a better solution that I'm missing?

I'm writing an emailer webservice for my company. One of the main requirements is guaranteed delivery, so we have a thin HTTP layer over the JMS transport, using a persistent QPid queue.
One of the issues I'm running into is the handling of errors during processing. If I simply roll back the transaction when there's an error, the message goes to the head of the queue. If the error is pervasive enough, this can lock up the entire queue until someone intervenes manually, and we would like to avoid this by posting back to the head so that messages can be processed in the meantime.
However, therein lie my problems. First, while AMQP has a mechanism to "reject and requeue" a message atomically instead of acknowledging it, JMS doesn't seem to have any analog for this feature, so the only way to access it is by casting, which ties me to a specific JMS implementation. Further, the JMS transport for CXF doesn't seem to have any means of overriding or injecting behavior at the transport level, which means I'm stuck either writing a bytecode agent or changing the code and recompiling just to get the behavior I want.
To work around the issue, I've toyed with the idea of implementing a fault handler in CXF that simply reconstructs the JMS message from the CXF message, and re-queues it. But then I can't use the transacted session, because the fault causes a rollback which I can't override, and then I'll wind up with a copy of the message on the head (from the rollback) and on the tail (from the re-queue). And I can't use CLIENT_ACKNOWLEDGE, because the JMS transport acknowledges the message before submitting it for processing, which means if the server goes down at the wrong time, I could lose a message.
So basically, as long as I'm stuck accepting the default behavior of the JMS transport, it seems impossible to get the behavior I want (requeueing of failed messages) without compromising data integrity.
A coworker has suggested eschewing the JMS transport entirely, and invoking the queue directly. The service implementation would then be a skeleton class that exists solely to put messages on the queue, and another process would implement a message listener. To me, this solution is sub-optimal because I lose the elegance of an agnostic web service, and I lose some scalability by coupling my implementation to the underlying technology.
I've also considered just writing a CXF transport for AMQP using the RabbitMQ client library. It would take longer but it would be something our company could continue using going forward, and perhaps something that could be contributed back to the CXF project. That said, I'm not wild about this idea either because of the amount of time involved writing, running and testing the code.
Here's my beans.xml for CXF:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:jms="http://cxf.apache.org/transports/jms"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://cxf.apache.org/transports/jms http://cxf.apache.org/schemas/configuration/jms.xsd">
<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" />
<context:component-scan base-package="com.edo" />
<bean id="jmsConnectionFactory" class="org.apache.qpid.client.AMQConnectionFactory">
<constructor-arg name="broker" value="tcp://localhost:5672"/>
<constructor-arg name="username" value="guest"/>
<constructor-arg name="password" value="guest"/>
<constructor-arg name="clientName" value=""/>
<constructor-arg name="virtualHost" value=""/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate" p:explicitQosEnabled="true" p:deliveryMode="1" p:timeToLive="5000" p:connectionFactory-ref="jmsConnectionFactory" p:sessionTransacted="false" p:sessionAcknowledgeModeName="CLIENT_ACKNOWLEDGE" />
<bean id="jmsConfig" class="org.apache.cxf.transport.jms.JMSConfiguration" p:connectionFactory-ref="jmsConnectionFactory" p:wrapInSingleConnectionFactory="false" p:jmsTemplate-ref="jmsTemplate" p:timeToLive="500000" p:sessionTransacted="false" p:concurrentConsumers="1" p:maxSuspendedContinuations="0" p:maxConcurrentConsumers="1" />
<jms:destination id="jms-destination-bean" name="{http://test.jms.jaxrs.edo.com/}HelloWorldImpl.jms-destination">
<jms:address jndiConnectionFactoryName="ConnectionFactory" jmsDestinationName="TestQueue">
<jms:JMSNamingProperty name="java.naming.factory.initial" value="org.apache.activemq.jndi.ActiveMQInitialContextFactory"/>
<jms:JMSNamingProperty name="java.naming.provider.url" value="tcp://localhost:5672"/>
</jms:address>
<jms:jmsConfig-ref>jmsConfig</jms:jmsConfig-ref>
</jms:destination>
<jaxrs:server id="helloWorld" address="/HelloWorld" transportId="http://cxf.apache.org/transports/jms">
<jaxrs:serviceBeans>
<ref bean="helloWorldBean"/>
</jaxrs:serviceBeans>
<jaxrs:inInterceptors>
<bean class="com.edo.jaxrs.jms.test.FlowControlInInterceptor" p:periodMs="1000" p:permitsPerPeriod="18" />
</jaxrs:inInterceptors>
<jaxrs:providers>
<bean class="org.apache.cxf.jaxrs.provider.JSONProvider">
<property name="produceMediaTypes" ref="jsonTypes"/>
<property name="consumeMediaTypes" ref="jsonTypes"/>
</bean>
</jaxrs:providers>
</jaxrs:server>
<bean id="http-jms-config" class="com.edo.jaxrs.jms.test.HttpOverJmsConfig"
p:jmsFactory-ref="jmsConnectionFactory"
p:jmsDestinationName="TestQueue" />
<util:list id="jsonTypes">
<value>application/json</value>
<value>application/jettison</value>
</util:list>
</beans>
Is there something simple I'm missing? Or is there a better way to go about this that would sidestep the problem?
So - I'm taking my coworker's advice and not using the JMS transport for the web service. Instead, we're going to create a thin web service layer over Spring Integration. This should allow us the granularity of control we need without unnecessarily exposing the messaging layer.

Resources