In camel how to generate alert mail when active mq is down - apache-camel

I am using apache camel 2.x and active amq version 5.x
I have an amq where I am putting some message. Now I want to trigger an alert mail using camel when ever the amq is down .
here is my configuration details:
Code in bean
<bean id="activeMQ" class="org.apache.activemq.camel.component.ActiveMQComponent" lazy- init="true">
<property name="brokerURL" value="some url" />
</bean>
Broker URL :failover:(tcp://abc.abc:56789,tcp://abc.abc:1234)?randomize=true

Related

Camel + Tomcat + Datasource + JNDI = Impossible

I have a Spring app that runs in Tomcat and connects okay to a JNDI configured datasource. I'm trying to get my Apache Camel app to do the same.
Tomcat context.xml
<ResourceLink global="jdbc/deapplication-datasource" name="jdbc/deapplication-datasource" type="javax.sql.DataSource"/>
Tomcat server.xml
<Resource name="jdbc/deapplication-datasource"
auth="Container"
type="javax.sql.DataSource"
maxTotal="50" maxIdle="30" maxWaitMillis="10000"
username="yada" password="nada"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:#//test-cluster:1521/foo.bar.ca"/>
camel-config.xml
<!-- JNDI connection fails with Tomcat localhost (works in our testing/WebLogic environment -->
<bean id="dataSourceHello" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/deapplication-datasource"/>
</bean>
<!-- manual config works
<bean id="dataSourceHello" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#//test-cluster:1521/foo.bar.ca" />
<property name="username" value="yada" />
<property name="password" value="nada" />
</bean>
-->
Java/Camel code:
from("direct:healthCheckDb")
.log("0")
.setBody(simple("select * from dual"))
.log("1")
.to("jdbc:dataSourceHello")
.log("2")
Tomcat log:
2022-06-13 12:07:49,879 INFO - 0
2022-06-13 12:07:49,881 INFO - 1
2022-06-13 12:07:50,444 ERROR - Failed delivery for (MessageId: ID-IT-DEV-VM-112-1655147269874-0-1 on ExchangeId: ID-IT-DEV-VM-112-1655147269874-0-1). On delivery attempt: 0 caught: org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[ID-IT-DEV-VM-112-1655147269874-0-1]
2022-06-13 12:07:50,456 ERROR - null org.apache.camel.CamelExecutionException Exception occurred during execution on the exchange: Exchange[ID-IT-DEV-VM-112-1655147269874-0-1]
Tomcat and the app start up okay, but when I hit the restful path to test healthCheckDb it fails after log 1 but before log 2 (as you probably noticed above). The same statement works if I use the manual configured datasource. But I'd prefer to use the same setup as we use for WebLogic so I don't have to keep uncommenting and commenting the camel-config.xml file.
(Side note: after hours of research, have not seen 2 web pages agree on how to configure Tomcat JNDI for a datasource).
Possible to get Camel working with JNDI?

Steps to setup distributed transaction management in JBoss

I am trying to implement a distributed transaction (XA) in JBoss EAP 6.2 application server so that multiple datastores can be accessed in a single coordinated atomic transaction. To be more precise, I'd like my transactional service method to write to a database table and to a message queue in such a way that these two operations are either both committed or both rolled back consistently (all or nothing).
My approach is based on the following:
Use Spring JTA Transaction Manager
Configure the entity manager to use an XA JDBC datasource, defined in JBoss application server and accessed via a JNDI name
Use ActiveMQ XA Connection Factory for messaging
The problem I am facing is that only the database operation is rolled back. The message written to ActiveMQ queue is always commited regardless of the transaction being rolled back or not.
Key elements of my configuration:
<tx:jta-transaction-manager/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xaDataSource" />
...
<property name="jpaProperties">
<props>
...
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
</props>
</property>
</bean>
<jee:jndi-lookup id="xaDataSource" jndi-name="xaDataSource"/>
<bean id="xaConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<property name="brokerURL">
<value>tcp://localhost:61616</value>
</property>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="xaConnectionFactory" />
<property name="defaultDestinationName" value="TEST_QUEUE" />
<property name="sessionTransacted" value="true"/>
</bean>
I finally got this working. The key was to configure the JMS connection factory within a JBoss Resource Adapter. Detailed steps below:
1. Install Apache ActiveMQ
Version used: 5.11.3
Detailed install instructions can be found here.
Once ActiveMQ installed, Create a queue named TEST_QUEUE (use admin console: http://127.0.0.1:8161/admin/index.jsp)
2. Set up Spring application context
Key elements:
Use Spring JTA Transaction Manager tag: this will prompt the use of
the app server transaction manager;
Configure the datasource bean to use the XA datasource defined in the app server (see XA JDBC datasource setup);
Wire the jtaDataSource attribute of the Entity Manager Factory to the XA datasource;
Set Hibernate property manager_lookup_class to JBossTransactionManagerLookup;
Configure the connection factory bean to use the XA connection factory bean defined in the app server (see XA Connection Factory setup);
Set property transactedSession of connection factory bean to false.
e
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:jms="http://www.springframework.org/schema/jms" xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<jpa:repositories base-package="com.company.app.repository" />
<context:component-scan base-package="com.company.app" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:jta-transaction-manager/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xaDataSource" />
<property name="packagesToScan" value="com.company.app.domain" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
</props>
</property>
</bean>
<jee:jndi-lookup id="xaDataSource" jndi-name="jdbc/xaDataSource"/>
<bean id="xaConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="activemq/ConnectionFactory" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="xaConnectionFactory" />
<property name="defaultDestinationName" value="TEST_QUEUE" />
<property name="sessionTransacted" value="false"/>
</bean>
3. Set up application server (JBoss)
For a distributed transaction to work, all the datasources involved must be of type XA. JBoss supports JDBC XA datasource (xa-datasource tag) out of the box. The XA configuration for JMS datasource is achieved by defining appropriate Resource Adapter.
3.1. XA JDBC datasource
In standalone.xml under <subsystem xmlns="urn:jboss:domain:datasources:1.1"> <datasources> add an XA JDBC datasource:
<xa-datasource jndi-name="java:/jdbc/xaDataSource" pool-name="jdbc/xaDataSource" enabled="true">
<xa-datasource-property name="URL">
jdbc:oracle:thin:#<hostname>:<port_number>/<SID>
</xa-datasource-property>
<xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
<driver>ojdbc6-11.2.0.3.jar</driver>
<security>
<user-name>db_user</user-name>
<password>password</password>
</security>
</xa-datasource>
3.2. XA Conncection Factory
Resource adapters are a concept from the J2EE Connector Architecture (JCA) and are used to interface with Enterprise Information Systems, i.e. systems external to the application server (e.g., relational databases, mainframes, Message-Oriented Middleware, accounting systems, etc.).
First you need to install ActiveMQ RAR (Resource adapter ARchive) in JBoss, by dropping the appropriate RAR file from maven central under \standalone\deployments. Then, in standalone.xml, under <subsystem xmlns="urn:jboss:domain:resource-adapters:1.1"> add the following:
<resource-adapters>
<resource-adapter id="activemq-rar.rar">
<archive>
activemq-rar-5.11.3.rar
</archive>
<transaction-support>XATransaction</transaction-support>
<config-property name="Password">
admin
</config-property>
<config-property name="UserName">
admin
</config-property>
<config-property name="ServerUrl">
tcp://localhost:61616?jms.rmIdFromConnectionId=true
</config-property>
<connection-definitions>
<connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/activemq/ConnectionFactory" enabled="true" pool-name="ConnectionFactory">
<xa-pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>20</max-pool-size>
<prefill>false</prefill>
<is-same-rm-override>false</is-same-rm-override>
</xa-pool>
</connection-definition>
</connection-definitions>
</resource-adapter>
</resource-adapters>
For further details about installing ActiveMQ RAR in JBoss, refer to RedHat documentation.
4. Make your Service method Transactional
#Service
public class TwoPhaseCommitService {
#Autowired
private EmployeeRepository employeeRepository;
#Autowired
private JmsTemplate jmsTemplate;
#Transactional
public void writeToDbAndQueue() {
final Employee employee = new Employee();
employee.setFirstName("John");
employee.setLastName("Smith");
// persist entity to database
employeeRepository.save(employee);
// write message to TEST_QUEUE
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(employee.getFirstName());
}
});
// To test rollback uncomment code below:
// throw new RuntimeException("something went wrong. Transaction must be rolled back!!!");
}
}

ActiveMQ with Camel basics

I already googled for a while looking for step by step tutorials explaining setup and integration of ActiveMQ with Camel, but had little success to find a basic tutorial.
I already have a running and configured ActiveMQ server but I just can't get the Camel Component up and running. It always creates a separate broker and I just can't make Camel connect to the existing broker instance.
Any hints where I can find basic tutorials on how to integrate Camel and develop a better understanding on how those two work together?
Please do not refere to Camel-Website, as this along with the docs for ActiveMQ where my primary source to fight through the stuff, but it helped only a little on setup, configuration and through understanding of both packages.
Thanks
Following is configuration of Active MQ with camel.
<bean id="jmsConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
<bean id="pooledConnectionFactory"
class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" destroy-method="stop">
<property name="maxConnections" value="8"/>
<property name="connectionFactory" ref="jmsConnectionFactory"/>
</bean>
<bean id="jmsConfig"
class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="concurrentConsumers" value="10"/>
</bean>
<bean id="activemq"
class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig"/>
</bean>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="*****">
<from uri="+++++++++" />
<choice>
<to uri="activemq:queue:**********"/>
</choice>
</route>
</camelContext>
You can consider some of the Camel books which has extensive information about all sorts of stuff with Camel, also how to use it with JMS and AMQ.
http://camel.apache.org/books
And there is some examples from AMQ you can look at as well: https://github.com/apache/camel/tree/master/examples
And you can try to find some 3rd party blogs or articles that cover AMQ with Camel: http://camel.apache.org/articles
And recently there was this article about AMQ with Camel:
http://www.puretechy.com/blog/apache-camel-activemq-example

Activemq Not Starting with HTTP uri

I am using activemq with camel for consuming messages from a queue and send them to a http server. I am using following camel configuration :-
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="activemq:queue:Consumer.A.VirtualTopic.Orders"/>
<to uri="http://localhost:8080/" />
<!-- <to uri="file:///Users/vinod/activemq.txt"/> -->
<!-- <to uri="activemq:queue:sssss"/> -->
</route>
</camelContext>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent" >
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost?create=false"/>
</bean>
</property>
</bean>
In first block creates a route which consumer messages from activemq:queue:Consumer.A.VirtualTopic.Orders queue and send them to server at http://localhost:8080/. The other two commented destinations are working fine, but when I start activemq with above configuration for sending messages over http, the server stops without throwing any error message. Activemq log for this is https://gist.github.com/kumar003vinod/1e5944cb246edb74c47fef7a0b433387
Please provide some insight.
Make sure to include camel-http and camel-http-common JARs in the ActiveMQ lib/camel directory. You may also need to include the transitive dependencies from camel-http in that directory so ActiveMQ has all the needed JARs in its classpath.
That would be commons-httpclient and commons-codec JARs but I think they are already included in lib/optional.

Liferay 5.1.1 solr plugin ClassCastException

I had Solr 1.2 up and running at port 8983 and using liferay 5.1.1 the question is how to configure solr to search at liferay JournalArticle table I've already installed solr-web plugin for liferay but it throws this exception
[SolrIndexSearcherImpl:79] Error while sending request to Solr
java.lang.ClassCastException: com.liferay.portal.kernel.util.HttpUtil cannot be cast to com.liferay.portal.kernel.util.HttpUtil
at com.liferay.portal.kernel.util.HttpUtil._getUtil(HttpUtil.java:317)
at com.liferay.portal.kernel.util.HttpUtil.getHttp(HttpUtil.java:96)
at com.liferay.portal.kernel.util.HttpUtil.addParameter(HttpUtil.java:68)
at com.liferay.portal.search.solr.SolrIndexSearcherImpl.search(SolrIndexSearcherImpl.java:71)
at com.liferay.portal.search.solr.SolrSearchEngineUtil.search(SolrSearchEngineUtil.java:78)
at com.liferay.portal.search.solr.messaging.SolrReaderMessageListener.doCommandSearch(SolrReaderMessageListener.java:92)
at com.liferay.portal.search.solr.messaging.SolrReaderMessageListener.doReceive(SolrReaderMessageListener.java:75)
at com.liferay.portal.search.solr.messaging.SolrReaderMessageListener.receive(SolrReaderMessageListener.java:46)
at com.liferay.portal.kernel.messaging.InvokerMessageListener.receive(InvokerMessageListener.java:69)
at com.liferay.portal.kernel.messaging.ParallelDestination$1.run(ParallelDestination.java:59)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
16:08:16,174 ERROR [SolrReaderMessageListener:49] Unable to process message com.liferay.portal.kernel.messaging.Message#2c591d98
com.liferay.portal.kernel.search.SearchException: java.lang.ClassCastException: com.liferay.portal.kernel.util.HttpUtil cannot be cast to com.liferay.portal.kernel.util.HttpUtil
at com.liferay.portal.search.solr.SolrIndexSearcherImpl.search(SolrIndexSearcherImpl.java:81)
at com.liferay.portal.search.solr.SolrSearchEngineUtil.search(SolrSearchEngineUtil.java:78)
at com.liferay.portal.search.solr.messaging.SolrReaderMessageListener.doCommandSearch(SolrReaderMessageListener.java:92)
at com.liferay.portal.search.solr.messaging.SolrReaderMessageListener.doReceive(SolrReaderMessageListener.java:75)
at com.liferay.portal.search.solr.messaging.SolrReaderMessageListener.receive(SolrReaderMessageListener.java:46)
at com.liferay.portal.kernel.messaging.InvokerMessageListener.receive(InvokerMessageListener.java:69)
at com.liferay.portal.kernel.messaging.ParallelDestination$1.run(ParallelDestination.java:59)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
and BTW here is my solr-web solr-spring.xml
<beans>
<bean id="indexSearcher" class="com.liferay.portal.search.solr.SolrIndexSearcherImpl">
<property name="serverURL" value="http://localhost:8983/solr/select" />
</bean>
<bean id="indexWriter" class="com.liferay.portal.search.solr.SolrIndexWriterImpl">
<property name="serverURL" value="http://localhost:8983/solr/update" />
</bean>
<bean id="searchEngine" class="com.liferay.portal.search.solr.SolrSearchEngineImpl">
<property name="name" value="Solr" />
<property name="searcher" ref="indexSearcher" />
<property name="writer" ref="indexWriter" />
<property name="indexReadOnly" value="false" />
</bean>
<bean id="searchEngineUtil" class="com.liferay.portal.search.solr.SolrSearchEngineUtil" lazy-init="false">
<constructor-arg ref="searchEngine" />
<constructor-arg ref="searchReaderMessageListener" />
<constructor-arg ref="searchWriterMessageListener" />
</bean>
and what would the schema.xml would looklike in this case
Seems you must have more than one portal-kernel.jar file in your app server.
This jar cannot be duplicated within the context of at least the ear containing the portal app and plugins in an app server, or the global classpath if running in a servlet container like tomcat.
he HttpUtils Class was actually altered to suite the requirements so the solution to this one was to replace original kernel class with the one we modified

Resources