What's New Here?

apache-camel-logo

Circuit Breaker Pattern in Apache Camel

Camel is very often used in distributed environments for accessing remote resources. Remote services may fail for various reasons and periods. For services that are temporarily unavailable and recoverable after short period of time, a retry strategy may help. But some services can fail or hang for longer period of time making the calling application unresponsive and slow. A good strategy to prevent from cascading failures and exhaustion of critical resources is the Circuit Breaker pattern described by Michael Nygard in the Release It! book. Circuit Breaker is a stateful pattern that wraps the failure-prone resource and monitors for errors. Initially the Circuit Breaker is in closed state and passes all calls to the wrapped resource. When the failures reaches a certain threshold, the circuit moves to open state where it returns error to the caller without actually calling the wrapped resource. This prevents from overloading the already failing resource. While at this state, we need a mechanism to detect whether the failures are over and start calling the protected resource. This is where the third state called half-open comes into play. This state is reached after a certain time following the last failure. At this state, the calls are passed through to the protected resource, but the result of the call is important. If the call is successful, it is assumed that the protected resource has recovered and the circuit is moved into closed state, and if the call fails, the timeout is reset, and the circuit is moved back to open state where all calls are rejected. Here is the state diagram of Circuit Breaker from Martin Fowler’s post:How Circuit Breaker is implemented in Camel? Circuit Breaker is available in the latest snapshot version of Camel as a Load balancer policy. Camel Load Balancer already has policies for Round Robin, Random, Failover, etc. and now also CircuiBreaker policy. Here is an example load balancer that uses Circuit Breaker policy with threshold of 2 errors and halfOpenAfter timeout of 1 second. Notice also that this policy applies only to errors caused by MyCustomException new RouteBuilder() { public void configure() { from("direct:start").loadBalance() .circuitBreaker(2, 1000L, MyCustomException.class) .to("mock:result"); } }; And here is the same example using Spring XML DSL: <route> <from uri="direct:start"/> <loadBalance> <circuitBreaker threshold="2" halfOpenAfter="1000"> <exception>MyCustomException</exception> </circuitBreaker> <to uri="mock:result"/> </loadBalance> </route>Reference: Circuit Breaker Pattern in Apache Camel from our JCG partner Bilgin Ibryam at the OFBIZian blog....
java-logo

10 Books Every Java Developer Should Read

I have read my share of software development books and I have noticed that it is very rare to find a book which I want to read more than once. However, once in a while I find a book which teaches me new things every time when I read it. This blog post is a tribute to these rare gems. And now, without further delay, I present to you ten books which have earned a special place in my bookshelf:      Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin teaches you three things: how to write good code, how to tell the difference between good code and bad code, and how to transform bad code into good code. These are essential skills for every developer. That is why you should read this book. Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides is a true classic. It presents elegant solutions to common design problems. If you want to learn the basics of writing elegant object-oriented code, this is the book you should read. Domain Driven Design: Tacking the Complexity in the Heart of Software by Eric Evans is a book for developers who want to understand how they can transform the knowledge of domain experts into a useful domain model. If you have noticed that often it is hard to find a natural place for “business logic”, you should do yourself a favour and read this book. Effective Java by Joshua Bloch is a book that requires no introduction. If you want to write more robust Java code, you have 78 reasons to read this book. Effective Unit Testing: A guide for Java developers by Lasse Koskela is the second testing book of Lasse Koskela, and it helps you to improve the quality of your test suite. Reading this book helped me to write cleaner and more maintainable tests. I guess you could say that this book helped me to realize that tests have no value if they don’t express the intention of each test. I think that this is a valuable lesson, and that is why you should read this book too. Patterns of Enterprise Application Architecture by Martin Fowler has a “boring” title but you shouldn’t let it scare you. Reading this book gave me a better understanding about the basic building blocks of the “enterprise” frameworks which I use every day. If you want to understand your tools, this is the book you should read. Refactoring: Improving the Design of Existing Code by Martin Fowler is another timeless classic. It describes more than 40 different refactorings which can be used to improve the design of existing code. Every software developer should have good refactoring skills and reading this book will take you one step closer to that goal. SQL Antipatterns: Avoiding the Pitfalls of Database Programming by Bill Karwin is a book that is very useful to all developers who use relational databases. This book helps you to avoid the most common design antipatterns, query antipatterns, and application development antipatters. To be honest, I have to admit that I have made a few mistakes described in this book. That is why I am extremely happy that I read it and learned how I can avoid making the same mistakes in the future. SQL Performance Explained by Markus Winand promises that it will teach you everything you need to know about SQL performance. That is a very bold tagline and I was very happy when I realized that this book keeps its promise. I think that you should read this book for two reasons: it proves that relational databases aren’t slow, and it explains how you can make your SQL queries as fast as possible (they can faster than you ever imagined). Test Driven: TDD and Acceptance TDD for Java Developers by Lasse Koskela is the first testing book which I have ever read, and that is why it has a special place in my heart. It is a very good introduction to TDD, but you can learn a few testing tricks from this book even if you aren’t a TDD fanboy. That is why this book is a very good addition to your bookshelf.This list is based on my (subjective) opinion and it is very likely that your list will look completely different. If you think that I missed a book which should be in this list, share your opinion in the comment section.Reference: 10 Books Every Java Developer Should Read from our JCG partner Petri Kainulainen at the Petri Kainulainen blog....
apache-activemq-logo

Using ActiveMQ – “Master/Slave” configuration with failover protocol

Introduction ActiveMQ broker(s) tends to be a core piece of messaging infrastructure in an enterprise. It is vital for this messaging infrastructure to be highly available and scalable. Please read this link in order to learn more about creating network of brokers to support various use cases. One of the popular use case for ActiveMQ is the Master/Slave configuration with shared database. When this configuration is used, the message consumers and producers can operate without interruptions as they use ActiveMQ’s connection factory with failover protocol. The failover protocol insulates the consumers and producers from having to deal with any potential downtime or application level reconnection logic when slave ActiveMQ node takes over to become the master which happens if the current master node goes down for any reason. I must caution that this configuration must not be used to mask any issues which take out the master node. We should iron out any causes that result in an unplanned master node outage. Overview In this blog, I will demonstrate the following:Run 2 ActiveMQ nodes in a Master/Slave configuration with a shared KahaDB file based database. Configure ActiveMQ web console hosted in a Tomcat instance to point to whichever node is Master node in the cluster. Failover scenarios. Message publisher and consumer behavior oblivious to the failover.PrerequisitesInstall ActiveMQ version 5.8.0 Download ActiveMQ version 5.8.0 web console war from here Install Tomcat version 7.0.35 – To host the ActiveMQ Web Console applicationDeep Dive We will create a 2 node ActiveMQ cluster on the same Windows 7 machine. We will need to configure the ports (TCP & JMX) such that there is no conflict. ActiveMQ provides a script called “activemq-admin.bat” which helps in running multiple instances of ActiveMQ using the same binaries, very much like Tomcat. Let’s go ahead and create broker-1 and broker-2 instances. command: activemq-admin create <DIR-for-ActiveMQ-node> C:\apache-activemq-5.8.0\bin>activemq-admin create ..\cluster\broker-1Java Runtime: Sun Microsystems Inc. 1.6.0_31 C:\Program Files\Java\jdk1.6.0_31\jre   Heap sizes: current=125632k  free=124976k  max=1864192k     JVM args: -Dactivemq.classpath=C:\apache-activemq-5.8.0\bin\..\conf;C:\apache-activemq-5.8.0\bin\..\data; -Dactivemq.home=C:\apache-activemq-5.8.0 \bin\.. -Dactivemq.base=C:\apache-activemq-5.8.0\bin\.. -Dactivemq.data=C:\apache-activemq-5.8.0\bin\..\data -Djava.io.tmpdir=C:\apache-activemq-5.8.0 \bin\..\data\tmp -Dactivemq.conf=C:\apache-activemq-5.8.0\bin\..\conf Extensions classpath:   [C:\apache-activemq-5.8.0\bin\..\lib,C:\apache-activemq-5.8.0\bin\..\lib\camel,C:\apache-activemq-5.8.0\bin\..\lib\optional,C:\apache-activemq-5.8.0 \bin\..\lib\web,C:\apache-activemq-5.8.0\bin\..\lib\extra] ACTIVEMQ_HOME: C:\apache-activemq-5.8.0\bin\.. ACTIVEMQ_BASE: C:\apache-activemq-5.8.0\bin\.. ACTIVEMQ_CONF: C:\apache-activemq-5.8.0\bin\..\conf ACTIVEMQ_DATA: C:\apache-activemq-5.8.0\bin\..\data Running create broker task... Creating directory: C:\apache-activemq-5.8.0\cluster\broker-1 Creating directory: C:\apache-activemq-5.8.0\cluster\broker-1\bin Creating directory: C:\apache-activemq-5.8.0\cluster\broker-1\conf Creating new file: C:\apache-activemq-5.8.0\cluster\broker-1\bin\broker-1.bat Creating new file: C:\apache-activemq-5.8.0\cluster\broker-1\bin\broker-1 Copying from: C:\apache-activemq-5.8.0\conf\activemq.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-command.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-command.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-demo.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-demo.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-dynamic-network-broker1.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-dynamic-network-broker1.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-dynamic-network-broker2.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-dynamic-network-broker2.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-jdbc.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-jdbc.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-scalability.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-scalability.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-security.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-security.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-specjms.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-specjms.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-static-network-broker1.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-static-network-broker1.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-static-network-broker2.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-static-network-broker2.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-stomp.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-stomp.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-throughput.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\activemq-throughput.xml Copying from: C:\apache-activemq-5.8.0\conf\broker-localhost.cert           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\broker-localhost.cert Copying from: C:\apache-activemq-5.8.0\conf\broker.ks           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\broker.ks Copying from: C:\apache-activemq-5.8.0\conf\broker.ts           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\broker.ts Copying from: C:\apache-activemq-5.8.0\conf\camel.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\camel.xml Copying from: C:\apache-activemq-5.8.0\conf\client.ks           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\client.ks Copying from: C:\apache-activemq-5.8.0\conf\client.ts           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\client.ts Copying from: C:\apache-activemq-5.8.0\conf\credentials-enc.properties           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\credentials-enc.properties Copying from: C:\apache-activemq-5.8.0\conf\credentials.properties           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\credentials.properties Copying from: C:\apache-activemq-5.8.0\conf\jetty-demo.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\jetty-demo.xml Copying from: C:\apache-activemq-5.8.0\conf\jetty-realm.properties           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\jetty-realm.properties Copying from: C:\apache-activemq-5.8.0\conf\jetty.xml           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\jetty.xml Copying from: C:\apache-activemq-5.8.0\conf\jmx.access           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\jmx.access Copying from: C:\apache-activemq-5.8.0\conf\jmx.password           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\jmx.password Copying from: C:\apache-activemq-5.8.0\conf\log4j.properties           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\log4j.properties Copying from: C:\apache-activemq-5.8.0\conf\logging.properties           to: C:\apache-activemq-5.8.0\cluster\broker-1\conf\logging.properties Now let’s create broker-2 instance… C:\apache-activemq-5.8.0\bin>activemq-admin create ..\cluster\broker-2Java Runtime: Sun Microsystems Inc. 1.6.0_31 C:\Program Files\Java\jdk1.6.0_31\jre   Heap sizes: current=125632k  free=124976k  max=1864192k     JVM args: -Dactivemq.classpath=C:\apache-activemq-5.8.0\bin\..\conf;C:\apache-activemq-5.8.0\bin\..\data; -Dactivemq.home=C:\apache-activemq-5.8.0 \bin\.. -Dactivemq.base=C:\apache-activemq-5.8.0\bin\.. -Dactivemq.data=C:\apache-activemq-5.8.0\bin\..\data -Djava.io.tmpdir=C:\apache-activemq-5.8.0 \bin\..\data\tmp -Dactivemq.conf=C:\apache-activemq-5.8.0\bin\..\conf Extensions classpath:   [C:\apache-activemq-5.8.0\bin\..\lib,C:\apache-activemq-5.8.0\bin\..\lib\camel,C:\apache-activemq-5.8.0\bin\..\lib\optional,C:\apache-activemq-5.8.0 \bin\..\lib\web,C:\apache-activemq-5.8.0\bin\..\lib\extra] ACTIVEMQ_HOME: C:\apache-activemq-5.8.0\bin\.. ACTIVEMQ_BASE: C:\apache-activemq-5.8.0\bin\.. ACTIVEMQ_CONF: C:\apache-activemq-5.8.0\bin\..\conf ACTIVEMQ_DATA: C:\apache-activemq-5.8.0\bin\..\data Running create broker task... Creating directory: C:\apache-activemq-5.8.0\cluster\broker-2 Creating directory: C:\apache-activemq-5.8.0\cluster\broker-2\bin Creating directory: C:\apache-activemq-5.8.0\cluster\broker-2\conf Creating new file: C:\apache-activemq-5.8.0\cluster\broker-2\bin\broker-2.bat Creating new file: C:\apache-activemq-5.8.0\cluster\broker-2\bin\broker-2 Copying from: C:\apache-activemq-5.8.0\conf\activemq.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-command.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-command.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-demo.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-demo.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-dynamic-network-broker1.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-dynamic-network-broker1.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-dynamic-network-broker2.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-dynamic-network-broker2.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-jdbc.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-jdbc.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-scalability.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-scalability.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-security.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-security.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-specjms.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-specjms.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-static-network-broker1.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-static-network-broker1.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-static-network-broker2.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-static-network-broker2.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-stomp.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-stomp.xml Copying from: C:\apache-activemq-5.8.0\conf\activemq-throughput.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\activemq-throughput.xml Copying from: C:\apache-activemq-5.8.0\conf\broker-localhost.cert           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\broker-localhost.cert Copying from: C:\apache-activemq-5.8.0\conf\broker.ks           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\broker.ks Copying from: C:\apache-activemq-5.8.0\conf\broker.ts           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\broker.ts Copying from: C:\apache-activemq-5.8.0\conf\camel.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\camel.xml Copying from: C:\apache-activemq-5.8.0\conf\client.ks           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\client.ks Copying from: C:\apache-activemq-5.8.0\conf\client.ts           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\client.ts Copying from: C:\apache-activemq-5.8.0\conf\credentials-enc.properties           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\credentials-enc.properties Copying from: C:\apache-activemq-5.8.0\conf\credentials.properties           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\credentials.properties Copying from: C:\apache-activemq-5.8.0\conf\jetty-demo.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\jetty-demo.xml Copying from: C:\apache-activemq-5.8.0\conf\jetty-realm.properties           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\jetty-realm.properties Copying from: C:\apache-activemq-5.8.0\conf\jetty.xml           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\jetty.xml Copying from: C:\apache-activemq-5.8.0\conf\jmx.access           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\jmx.access Copying from: C:\apache-activemq-5.8.0\conf\jmx.password           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\jmx.password Copying from: C:\apache-activemq-5.8.0\conf\log4j.properties           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\log4j.properties Copying from: C:\apache-activemq-5.8.0\conf\logging.properties           to: C:\apache-activemq-5.8.0\cluster\broker-2\conf\logging.properties You may have noticed the following properties above: ACTIVEMQ_BASE: C:\apache-activemq-5.8.0\bin\.. ACTIVEMQ_CONF: C:\apache-activemq-5.8.0\bin\..\conf ACTIVEMQ_DATA: C:\apache-activemq-5.8.0\bin\..\dataThese properties need to be fixed as we’d like ACTIVEMQ_BASE and ACTIVEMQ_CONF to be different for both broker-1 and broker-2. We need to edit the following files:broker-1.bat in C:\apache-activemq-5.8.0\cluster\broker-1\bin directoryset ACTIVEMQ_HOME=”C:/apache-activemq-5.8.0″ set ACTIVEMQ_BASE=”C:/apache-activemq-5.8.0/cluster/broker-1″ set ACTIVEMQ_CONF=%ACTIVEMQ_BASE%/confbroker-2.bat in C:\apache-activemq-5.8.0\cluster\broker-2\bin directoryset ACTIVEMQ_HOME=”C:/apache-activemq-5.8.0″ set ACTIVEMQ_BASE=”C:/apache-activemq-5.8.0/cluster/broker-2″ set ACTIVEMQ_CONF=%ACTIVEMQ_BASE%/confYou may observe that both broker-1 and broker-2 nodes share the same ACTIVEMQ_DATA folder. Since we are using the in-built KahaDB for persistence, both broker-1 and broker-2 will share this. We need to differentiate the tcp ports for broker-1 and broker-2 and also enable JMX and configure  JMX ports for remote monitoring. Let’s edit the activemq.xml for broker-1 to fix tcp port: <transportConnectors> <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB --> <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&wireformat.maxFrameSize=104857600"/> <!--<transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&wireformat.maxFrameSize=104857600"/>--> </transportConnectors> Let’s edit the activemq.xml for broker-1 to enable JMX monitoring, notice useJMX=”true” attribute below. <broker xmlns="http://activemq.apache.org/schema/core" brokerName="broker-1" dataDirectory="${activemq.data}" useJmx="true"> Let’s configure the JMX port <managementContext> <managementContext createConnector="true" connectorPort="1099"/> </managementContext> Repeat the same for broker-2. set TCP port to 61626 and JMX port to 2099. Start broker-1.  C:\apache-activemq-5.8.0\cluster\broker-1\bin>broker-1.bat Java Runtime: Sun Microsystems Inc. 1.6.0_31 C:\Program Files\Java\jdk1.6.0_31\jre Heap sizes: current=1004928k free=994439k max=1004928k JVM args: -Dcom.sun.management.jmxremote -Xms1G -Xmx1G -Djava.util.logging.config.file=logging.properties -Dactivemq.classpath=C:/apache-activemq- 5.8.0/cluster/broker-1/conf;C:/apache-activemq-5.8.0/cluster/broker-1/conf;C:/apache-activemq-5.8.0/conf; -Dactivemq.home=C:/apache-activemq-5.8.0 -Da ctivemq.base=C:/apache-activemq-5.8.0/cluster/broker-1 -Dactivemq.conf=C:/apache-activemq-5.8.0/cluster/broker-1/conf -Dactivemq.data=C:/apache-active mq-5.8.0\data -Djava.io.tmpdir=C:/apache-activemq-5.8.0\data\tmp Extensions classpath: [C:\apache-activemq-5.8.0\cluster\broker-1\lib,C:\apache-activemq-5.8.0\lib,C:\apache-activemq-5.8.0\cluster\broker-1\lib\camel,C:\apache-activemq-5 .8.0\cluster\broker-1\lib\optional,C:\apache-activemq-5.8.0\cluster\broker-1\lib\web,C:\apache-activemq-5.8.0\cluster\broker-1\lib\extra,C:\apache-act ivemq-5.8.0\lib\camel,C:\apache-activemq-5.8.0\lib\optional,C:\apache-activemq-5.8.0\lib\web,C:\apache-activemq-5.8.0\lib\extra] ACTIVEMQ_HOME: C:\apache-activemq-5.8.0 ACTIVEMQ_BASE: C:\apache-activemq-5.8.0\cluster\broker-1 ACTIVEMQ_CONF: C:\apache-activemq-5.8.0\cluster\broker-1\conf ACTIVEMQ_DATA: C:\apache-activemq-5.8.0\data Loading message broker from: xbean:activemq.xml INFO | Refreshing org.apache.activemq.xbean.XBeanBrokerFactory$1@71060478: startup date [Tue Jul 09 16:59:15 CDT 2013]; root of context hierarchy INFO | PListStore:[C:\apache-activemq-5.8.0\data\broker-1\tmp_storage] started INFO | Using Persistence Adapter: KahaDBPersistenceAdapter[C:\apache-activemq-5.8.0\data\kahadb] INFO | JMX consoles can connect to service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi INFO | KahaDB is version 4 INFO | Recovering from the journal ... INFO | Recovery replayed 1 operations from the journal in 0.028 seconds. INFO | Apache ActiveMQ 5.8.0 (broker-1, ID:AKUNTAMU-1-27777-1373407157813-0:1) is starting INFO | Listening for connections at: tcp://AKUNTAMU-1:61616?maximumConnections=1000&wireformat.maxFrameSize=104857600 INFO | Connector openwire Started INFO | Apache ActiveMQ 5.8.0 (broker-1, ID:AKUNTAMU-1-27777-1373407157813-0:1) started INFO | For help or more information please see: http://activemq.apache.org WARN | Store limit is 102400 mb, whilst the data directory: C:\apache-activemq-5.8.0\data\kahadb only has 38889 mb of usable space ERROR | Temporary Store limit is 51200 mb, whilst the temporary data directory: C:\apache-activemq-5.8.0\data\broker-1\tmp_storage only has 38889 mb o f usable space INFO | Web console type: embedded INFO | ActiveMQ WebConsole initialized. INFO | Initializing Spring FrameworkServlet 'dispatcher' INFO | jolokia-agent: No access restrictor found at classpath:/jolokia-access.xml, access to all MBeans is allowed Start broker-2. You will observe that broker-2 is unable to acquire the lock since broker-1 already grabbed it. broker-2 will keep retrying to acquire the lock every 10 seconds.  C:\apache-activemq-5.8.0\cluster\broker-2\bin>broker-2.bat Java Runtime: Sun Microsystems Inc. 1.6.0_31 C:\Program Files\Java\jdk1.6.0_31\jre Heap sizes: current=1004928k free=994439k max=1004928k JVM args: -Dcom.sun.management.jmxremote -Xms1G -Xmx1G -Djava.util.logging.config.file=logging.properties -Dactivemq.classpath=C:/apache-activemq- 5.8.0/cluster/broker-2/conf;C:/apache-activemq-5.8.0/cluster/broker-2/conf;C:/apache-activemq-5.8.0/conf; -Dactivemq.home=C:/apache-activemq-5.8.0 -Da ctivemq.base=C:/apache-activemq-5.8.0/cluster/broker-2 -Dactivemq.conf=C:/apache-activemq-5.8.0/cluster/broker-2/conf -Dactivemq.data=C:/apache-active mq-5.8.0\data -Djava.io.tmpdir=C:/apache-activemq-5.8.0\data\tmp Extensions classpath: [C:\apache-activemq-5.8.0\cluster\broker-2\lib,C:\apache-activemq-5.8.0\lib,C:\apache-activemq-5.8.0\cluster\broker-2\lib\camel,C:\apache-activemq-5 .8.0\cluster\broker-2\lib\optional,C:\apache-activemq-5.8.0\cluster\broker-2\lib\web,C:\apache-activemq-5.8.0\cluster\broker-2\lib\extra,C:\apache-act ivemq-5.8.0\lib\camel,C:\apache-activemq-5.8.0\lib\optional,C:\apache-activemq-5.8.0\lib\web,C:\apache-activemq-5.8.0\lib\extra] ACTIVEMQ_HOME: C:\apache-activemq-5.8.0 ACTIVEMQ_BASE: C:\apache-activemq-5.8.0\cluster\broker-2 ACTIVEMQ_CONF: C:\apache-activemq-5.8.0\cluster\broker-2\conf ACTIVEMQ_DATA: C:\apache-activemq-5.8.0\data Loading message broker from: xbean:activemq.xml INFO | Refreshing org.apache.activemq.xbean.XBeanBrokerFactory$1@420f9c40: startup date [Tue Jul 09 17:02:55 CDT 2013]; root of context hierarchy INFO | PListStore:[C:\apache-activemq-5.8.0\data\broker-2\tmp_storage] started INFO | Using Persistence Adapter: KahaDBPersistenceAdapter[C:\apache-activemq-5.8.0\data\kahadb] INFO | Database C:\apache-activemq-5.8.0\data\kahadb\lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOExceptio n: File 'C:\apache-activemq-5.8.0\data\kahadb\lock' could not be locked. INFO | JMX consoles can connect to service:jmx:rmi:///jndi/rmi://localhost:2099/jmxrmi INFO | Database C:\apache-activemq-5.8.0\data\kahadb\lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOExceptio n: File 'C:\apache-activemq-5.8.0\data\kahadb\lock' could not be locked. INFO | Database C:\apache-activemq-5.8.0\data\kahadb\lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOExceptio n: File 'C:\apache-activemq-5.8.0\data\kahadb\lock' could not be locked. Now let’s configure the ActiveMQ web console. By default, ActiveMQ distribution contains admin web console but in the Master/Slave configuration, it is unknown which node is the master. So it is doesn’t make sense to use the embedded web console. Hence it is best to have ActiveMQ web console outside of the ActiveMQ nodes. You can disable the embedded ActiveMQ Web Console in each node by commenting the following line in activemq.xml in conf directory of each ActiveMQ node. <!--<import resource="jetty.xml"/>--> For our example, we will deploy ActiveMQ Web Console web application in Tomcat container and then configure ActiveMQ web console application to intelligently point to the master node in ActiveMQ cluster. so let’s copy the activemq-web-console-5.8.0.war to webapps directory of Tomcat. Add the following line to catalina.bat set JAVA_OPTS=-Dwebconsole.type=properties -Dwebconsole.jms.url=failover:(tcp://localhost:61616,tcp://localhost:61626) -Dwebconsole.jmx.url=service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi,service:jmx:rmi:///jndi/rmi://localhost:2099/jmxrmiNow let’s start Tomcat. C:\apache-tomcat-7.0.35\bin>.\catalina.bat run Using CATALINA_BASE: "C:\apache-tomcat-7.0.35" Using CATALINA_HOME: "C:\apache-tomcat-7.0.35" Using CATALINA_TMPDIR: "C:\apache-tomcat-7.0.35\temp" Using JRE_HOME: "C:\Program Files\Java\jdk1.6.0_31" Using CLASSPATH: "C:\apache-tomcat-7.0.35\bin\bootstrap.jar;C:\apache-tomcat-7.0.35\bin\tomcat-juli.jar" Jul 9, 2013 5:28:08 PM org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["http-bio-8080"] Jul 9, 2013 5:28:08 PM org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["ajp-bio-8009"] Jul 9, 2013 5:28:08 PM org.apache.catalina.startup.Catalina load INFO: Initialization processed in 635 ms Jul 9, 2013 5:28:08 PM org.apache.catalina.core.StandardService startInternal INFO: Starting service Catalina Jul 9, 2013 5:28:08 PM org.apache.catalina.core.StandardEngine startInternal INFO: Starting Servlet Engine: Apache Tomcat/7.0.35 Jul 9, 2013 5:28:08 PM org.apache.catalina.startup.HostConfig deployWAR INFO: Deploying web application archive C:\apache-tomcat-7.0.35\webapps\activemq-web-console-5.8.0.war SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/C:/apache-tomcat-7.0.35/webapps/activemq-web-console-5.8.0/WEB-INF/lib/activemq-all-5.8.0.jar!/org/slf4j/impl/Stati cLoggerBinder.class] SLF4J: Found binding in [jar:file:/C:/apache-tomcat-7.0.35/webapps/activemq-web-console-5.8.0/WEB-INF/lib/slf4j-log4j12-1.6.6.jar!/org/slf4j/impl/Stat icLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory] 2013-07-09 17:28:13,389 [ost-startStop-1] INFO WebConsoleStarter - Web console type: properties 2013-07-09 17:28:13,960 [ost-startStop-1] INFO WebConsoleStarter - ActiveMQ WebConsole initialized. 2013-07-09 17:28:14,095 [ost-startStop-1] INFO ndingBeanNameUrlHandlerMapping - Mapped URL path [/createDestination.action] onto handler '/createDest ination.action' 2013-07-09 17:28:14,096 [ost-startStop-1] INFO ndingBeanNameUrlHandlerMapping - Mapped URL path [/deleteDestination.action] onto handler '/deleteDest ination.action' 2013-07-09 17:28:14,097 [ost-startStop-1] INFO ndingBeanNameUrlHandlerMapping - Mapped URL path [/createSubscriber.action] onto handler '/createSubsc riber.action' 2013-07-09 17:28:14,098 [ost-startStop-1] INFO ndingBeanNameUrlHandlerMapping - Mapped URL path [/deleteSubscriber.action] onto handler '/deleteSubsc riber.action' 2013-07-09 17:28:14,099 [ost-startStop-1] INFO ndingBeanNameUrlHandlerMapping - Mapped URL path [/sendMessage.action] onto handler '/sendMessage.acti on' 2013-07-09 17:28:14,100 [ost-startStop-1] INFO ndingBeanNameUrlHandlerMapping - Mapped URL path [/purgeDestination.action] onto handler '/purgeDestin ation.action' 2013-07-09 17:28:14,101 [ost-startStop-1] INFO ndingBeanNameUrlHandlerMapping - Mapped URL path [/deleteMessage.action] onto handler '/deleteMessage. action' 2013-07-09 17:28:14,103 [ost-startStop-1] INFO ndingBeanNameUrlHandlerMapping - Mapped URL path [/copyMessage.action] onto handler '/copyMessage.acti on' 2013-07-09 17:28:14,104 [ost-startStop-1] INFO ndingBeanNameUrlHandlerMapping - Mapped URL path [/moveMessage.action] onto handler '/moveMessage.acti on' 2013-07-09 17:28:14,105 [ost-startStop-1] INFO ndingBeanNameUrlHandlerMapping - Mapped URL path [/deleteJob.action] onto handler '/deleteJob.action' Jul 9, 2013 5:28:14 PM org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory C:\apache-tomcat-7.0.35\webapps\docs Jul 9, 2013 5:28:14 PM org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory C:\apache-tomcat-7.0.35\webapps\examples Jul 9, 2013 5:28:14 PM org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory C:\apache-tomcat-7.0.35\webapps\host-manager Jul 9, 2013 5:28:14 PM org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory C:\apache-tomcat-7.0.35\webapps\manager Jul 9, 2013 5:28:14 PM org.apache.catalina.startup.HostConfig deployDirectory INFO: Deploying web application directory C:\apache-tomcat-7.0.35\webapps\ROOT Jul 9, 2013 5:28:14 PM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["http-bio-8080"] Jul 9, 2013 5:28:14 PM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["ajp-bio-8009"] Jul 9, 2013 5:28:14 PM org.apache.catalina.startup.Catalina start INFO: Server startup in 6642 ms Let’s access the web console: http://localhost:8080/activemq-web-console-5.8.0 Use admin/admin for username/password if prompted. These are default security settings. Refer jetty.xml and jetty-realm.properties in conf directory.As shown above, “broker-1″ is the current master broker. Now, if you were to shutdown broker-1. Hit Control+C on Terminal window running broker-1, you’d notice that broker-2 acquires the lock and becomes the master. INFO | Database C:\apache-activemq-5.8.0\data\kahadb\lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOExceptio n: File 'C:\apache-activemq-5.8.0\data\kahadb\lock' could not be locked. INFO | Database C:\apache-activemq-5.8.0\data\kahadb\lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOExceptio n: File 'C:\apache-activemq-5.8.0\data\kahadb\lock' could not be locked. INFO | Database C:\apache-activemq-5.8.0\data\kahadb\lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOExceptio n: File 'C:\apache-activemq-5.8.0\data\kahadb\lock' could not be locked. INFO | Database C:\apache-activemq-5.8.0\data\kahadb\lock is locked... waiting 10 seconds for the database to be unlocked. Reason: java.io.IOExceptio n: File 'C:\apache-activemq-5.8.0\data\kahadb\lock' could not be locked. INFO | KahaDB is version 4 INFO | Recovering from the journal ... INFO | Recovery replayed 2 operations from the journal in 0.022 seconds. INFO | Apache ActiveMQ 5.8.0 (broker-2, ID:AKUNTAMU-1-28147-1373409767675-0:1) is starting INFO | Listening for connections at: tcp://AKUNTAMU-1:61626?maximumConnections=1000&wireformat.maxFrameSize=104857600 INFO | Connector openwire Started INFO | Apache ActiveMQ 5.8.0 (broker-2, ID:AKUNTAMU-1-28147-1373409767675-0:1) started INFO | For help or more information please see: http://activemq.apache.org WARN | Store limit is 102400 mb, whilst the data directory: C:\apache-activemq-5.8.0\data\kahadb only has 38888 mb of usable space ERROR | Temporary Store limit is 51200 mb, whilst the temporary data directory: C:\apache-activemq-5.8.0\data\broker-2\tmp_storage only has 38888 mb o f usable space INFO | Web console type: embedded INFO | ActiveMQ WebConsole initialized. INFO | Initializing Spring FrameworkServlet 'dispatcher' INFO | jolokia-agent: No access restrictor found at classpath:/jolokia-access.xml, access to all MBeans is allowed Let’s refresh the web consoleAs you may observe, now the master node is broker-2. Now that we have seen seamless switch over between the nodes during a failover scenario using an external web console, let’s see the same from the perspective of a message producer and consumer. I will publish 50 persistent messages to a queue using a simple message publisher and have an asynchronous consumer receive those 50 messages. I will introduce a bit of a delay in sending the messages so we can take the master down a few times and create a few failover scenarios. The objective is to see how the failover protocol makes the node failover completely transparent and thus shields the application from having to deal with any reconnection logic. Here is a simple producer using ActiveMQConnectionFactory with failover protocol. Notice the highlighted failover protocol URL in the code snippet below. package com.akuntamukkala.amqms; import javax.jms.Connection; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.log4j.Logger; public class Producer { private static final Logger log = Logger.getLogger(Producer.class); public static void main(String[] args) throws Exception { // Create a ConnectionFactory ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory( "failover:(tcp://localhost:61616,tcp://localhost:61626)"); for (int i = 0; i < 50; i++) { log.info("Establishing connection"); // Create a Connection Connection connection = connectionFactory.createConnection(); connection.start(); log.info("Connection established"); // Create a Session Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // Create the destination (Topic or Queue) Destination destination = session.createQueue("TEST.FOO"); // Create a MessageProducer from the Session to the Topic or Queue MessageProducer producer = session.createProducer(destination); producer.setDeliveryMode(DeliveryMode.PERSISTENT); // Create a messages String text = "Message Counter : " + i; TextMessage message = session.createTextMessage(text); log.info("Sending message : " + text); producer.send(message); log.info("Sent message : " + text); // Clean up session.close(); connection.close(); Thread.sleep(1000); } } } Here are the logs from execution while I shutdown broker-1 and broker-2 alternatively a few times. 2013-07-10 11:26:32 INFO Producer:25 - Establishing connection 2013-07-10 11:26:33 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:33 INFO Producer:30 - Connection established 2013-07-10 11:26:33 INFO Producer:47 - Sending message : Message Counter : 0 2013-07-10 11:26:33 INFO Producer:49 - Sent message : Message Counter : 0 2013-07-10 11:26:34 INFO Producer:25 - Establishing connection 2013-07-10 11:26:35 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:35 INFO Producer:30 - Connection established 2013-07-10 11:26:35 INFO Producer:47 - Sending message : Message Counter : 1 2013-07-10 11:26:35 INFO Producer:49 - Sent message : Message Counter : 1 2013-07-10 11:26:35 INFO Producer:25 - Establishing connection 2013-07-10 11:26:36 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:36 INFO Producer:30 - Connection established 2013-07-10 11:26:36 INFO Producer:47 - Sending message : Message Counter : 2 2013-07-10 11:26:36 INFO Producer:49 - Sent message : Message Counter : 2 2013-07-10 11:26:37 INFO Producer:25 - Establishing connection 2013-07-10 11:26:37 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:37 INFO Producer:30 - Connection established 2013-07-10 11:26:37 INFO Producer:47 - Sending message : Message Counter : 3 2013-07-10 11:26:37 INFO Producer:49 - Sent message : Message Counter : 3 2013-07-10 11:26:37 INFO Producer:25 - Establishing connection 2013-07-10 11:26:38 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:38 INFO Producer:30 - Connection established 2013-07-10 11:26:38 INFO Producer:47 - Sending message : Message Counter : 4 2013-07-10 11:26:38 INFO Producer:49 - Sent message : Message Counter : 4 2013-07-10 11:26:39 INFO Producer:25 - Establishing connection 2013-07-10 11:26:39 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:39 INFO Producer:30 - Connection established 2013-07-10 11:26:39 INFO Producer:47 - Sending message : Message Counter : 5 2013-07-10 11:26:39 INFO Producer:49 - Sent message : Message Counter : 5 2013-07-10 11:26:39 INFO Producer:25 - Establishing connection 2013-07-10 11:26:39 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:39 INFO Producer:30 - Connection established 2013-07-10 11:26:39 INFO Producer:47 - Sending message : Message Counter : 6 2013-07-10 11:26:39 INFO Producer:49 - Sent message : Message Counter : 6 2013-07-10 11:26:40 INFO Producer:25 - Establishing connection 2013-07-10 11:26:40 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:40 INFO Producer:30 - Connection established 2013-07-10 11:26:40 INFO Producer:47 - Sending message : Message Counter : 7 2013-07-10 11:26:40 INFO Producer:49 - Sent message : Message Counter : 7 2013-07-10 11:26:40 INFO Producer:25 - Establishing connection 2013-07-10 11:26:40 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:40 INFO Producer:30 - Connection established 2013-07-10 11:26:40 INFO Producer:47 - Sending message : Message Counter : 8 2013-07-10 11:26:40 INFO Producer:49 - Sent message : Message Counter : 8 2013-07-10 11:26:41 INFO Producer:25 - Establishing connection 2013-07-10 11:26:41 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:41 INFO Producer:30 - Connection established 2013-07-10 11:26:41 INFO Producer:47 - Sending message : Message Counter : 9 2013-07-10 11:26:41 INFO Producer:49 - Sent message : Message Counter : 9 2013-07-10 11:26:41 INFO Producer:25 - Establishing connection 2013-07-10 11:26:41 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:41 INFO Producer:30 - Connection established 2013-07-10 11:26:41 INFO Producer:47 - Sending message : Message Counter : 10 2013-07-10 11:26:41 INFO Producer:49 - Sent message : Message Counter : 10 2013-07-10 11:26:42 INFO Producer:25 - Establishing connection 2013-07-10 11:26:43 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:43 INFO Producer:30 - Connection established 2013-07-10 11:26:43 INFO Producer:47 - Sending message : Message Counter : 11 2013-07-10 11:26:43 INFO Producer:49 - Sent message : Message Counter : 11 2013-07-10 11:26:43 INFO Producer:25 - Establishing connection 2013-07-10 11:26:43 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:26:43 WARN FailoverTransport:255 - Transport (tcp://127.0.0.1:61616) failed, reason: java.net.SocketException: Software caused connection abort: recv failed, attempting to automatically reconnect 2013-07-10 11:26:50 INFO FailoverTransport:1032 - Successfully reconnected to tcp://localhost:61626 2013-07-10 11:26:50 INFO Producer:30 - Connection established 2013-07-10 11:26:50 INFO Producer:47 - Sending message : Message Counter : 12 2013-07-10 11:26:50 INFO Producer:49 - Sent message : Message Counter : 12 2013-07-10 11:26:51 INFO Producer:25 - Establishing connection 2013-07-10 11:26:52 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:26:52 INFO Producer:30 - Connection established 2013-07-10 11:26:52 INFO Producer:47 - Sending message : Message Counter : 13 2013-07-10 11:26:52 INFO Producer:49 - Sent message : Message Counter : 13 2013-07-10 11:26:52 INFO Producer:25 - Establishing connection 2013-07-10 11:26:53 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:26:53 INFO Producer:30 - Connection established 2013-07-10 11:26:53 INFO Producer:47 - Sending message : Message Counter : 14 2013-07-10 11:26:53 INFO Producer:49 - Sent message : Message Counter : 14 2013-07-10 11:26:54 INFO Producer:25 - Establishing connection 2013-07-10 11:26:54 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:26:54 INFO Producer:30 - Connection established 2013-07-10 11:26:54 INFO Producer:47 - Sending message : Message Counter : 15 2013-07-10 11:26:54 INFO Producer:49 - Sent message : Message Counter : 15 2013-07-10 11:26:54 INFO Producer:25 - Establishing connection 2013-07-10 11:26:55 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:26:55 INFO Producer:30 - Connection established 2013-07-10 11:26:55 INFO Producer:47 - Sending message : Message Counter : 16 2013-07-10 11:26:55 INFO Producer:49 - Sent message : Message Counter : 16 2013-07-10 11:26:56 INFO Producer:25 - Establishing connection 2013-07-10 11:26:57 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:26:57 INFO Producer:30 - Connection established 2013-07-10 11:26:57 INFO Producer:47 - Sending message : Message Counter : 17 2013-07-10 11:26:57 INFO Producer:49 - Sent message : Message Counter : 17 2013-07-10 11:26:57 INFO Producer:25 - Establishing connection 2013-07-10 11:26:58 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:26:58 INFO Producer:30 - Connection established 2013-07-10 11:26:58 INFO Producer:47 - Sending message : Message Counter : 18 2013-07-10 11:26:58 INFO Producer:49 - Sent message : Message Counter : 18 2013-07-10 11:26:59 INFO Producer:25 - Establishing connection 2013-07-10 11:26:59 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:26:59 INFO Producer:30 - Connection established 2013-07-10 11:26:59 INFO Producer:47 - Sending message : Message Counter : 19 2013-07-10 11:26:59 INFO Producer:49 - Sent message : Message Counter : 19 2013-07-10 11:26:59 INFO Producer:25 - Establishing connection 2013-07-10 11:26:59 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:26:59 INFO Producer:30 - Connection established 2013-07-10 11:26:59 INFO Producer:47 - Sending message : Message Counter : 20 2013-07-10 11:26:59 INFO Producer:49 - Sent message : Message Counter : 20 2013-07-10 11:27:00 INFO Producer:25 - Establishing connection 2013-07-10 11:27:01 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:01 INFO Producer:30 - Connection established 2013-07-10 11:27:01 INFO Producer:47 - Sending message : Message Counter : 21 2013-07-10 11:27:01 INFO Producer:49 - Sent message : Message Counter : 21 2013-07-10 11:27:01 INFO Producer:25 - Establishing connection 2013-07-10 11:27:01 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:01 INFO Producer:30 - Connection established 2013-07-10 11:27:01 INFO Producer:47 - Sending message : Message Counter : 22 2013-07-10 11:27:01 INFO Producer:49 - Sent message : Message Counter : 22 2013-07-10 11:27:02 INFO Producer:25 - Establishing connection 2013-07-10 11:27:02 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:02 INFO Producer:30 - Connection established 2013-07-10 11:27:02 INFO Producer:47 - Sending message : Message Counter : 23 2013-07-10 11:27:02 INFO Producer:49 - Sent message : Message Counter : 23 2013-07-10 11:27:02 INFO Producer:25 - Establishing connection 2013-07-10 11:27:02 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:02 INFO Producer:30 - Connection established 2013-07-10 11:27:02 INFO Producer:47 - Sending message : Message Counter : 24 2013-07-10 11:27:02 INFO Producer:49 - Sent message : Message Counter : 24 2013-07-10 11:27:03 INFO Producer:25 - Establishing connection 2013-07-10 11:27:03 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:03 INFO Producer:30 - Connection established 2013-07-10 11:27:03 INFO Producer:47 - Sending message : Message Counter : 25 2013-07-10 11:27:03 INFO Producer:49 - Sent message : Message Counter : 25 2013-07-10 11:27:03 INFO Producer:25 - Establishing connection 2013-07-10 11:27:03 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:03 INFO Producer:30 - Connection established 2013-07-10 11:27:03 INFO Producer:47 - Sending message : Message Counter : 26 2013-07-10 11:27:03 INFO Producer:49 - Sent message : Message Counter : 26 2013-07-10 11:27:04 INFO Producer:25 - Establishing connection 2013-07-10 11:27:04 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:06 WARN FailoverTransport:255 - Transport (tcp://127.0.0.1:61626) failed, reason: java.net.SocketException: Software caused connection abort: recv failed, attempting to automatically reconnect 2013-07-10 11:27:15 INFO FailoverTransport:1032 - Successfully reconnected to tcp://localhost:61616 2013-07-10 11:27:15 INFO Producer:30 - Connection established 2013-07-10 11:27:15 INFO Producer:47 - Sending message : Message Counter : 27 2013-07-10 11:27:15 INFO Producer:49 - Sent message : Message Counter : 27 2013-07-10 11:27:16 INFO Producer:25 - Establishing connection 2013-07-10 11:27:17 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:17 INFO Producer:30 - Connection established 2013-07-10 11:27:17 INFO Producer:47 - Sending message : Message Counter : 28 2013-07-10 11:27:17 INFO Producer:49 - Sent message : Message Counter : 28 2013-07-10 11:27:17 INFO Producer:25 - Establishing connection 2013-07-10 11:27:18 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:18 INFO Producer:30 - Connection established 2013-07-10 11:27:18 INFO Producer:47 - Sending message : Message Counter : 29 2013-07-10 11:27:18 INFO Producer:49 - Sent message : Message Counter : 29 2013-07-10 11:27:19 INFO Producer:25 - Establishing connection 2013-07-10 11:27:20 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:20 INFO Producer:30 - Connection established 2013-07-10 11:27:20 INFO Producer:47 - Sending message : Message Counter : 30 2013-07-10 11:27:20 INFO Producer:49 - Sent message : Message Counter : 30 2013-07-10 11:27:20 INFO Producer:25 - Establishing connection 2013-07-10 11:27:20 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:20 INFO Producer:30 - Connection established 2013-07-10 11:27:20 INFO Producer:47 - Sending message : Message Counter : 31 2013-07-10 11:27:20 INFO Producer:49 - Sent message : Message Counter : 31 2013-07-10 11:27:21 INFO Producer:25 - Establishing connection 2013-07-10 11:27:22 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:22 INFO Producer:30 - Connection established 2013-07-10 11:27:22 INFO Producer:47 - Sending message : Message Counter : 32 2013-07-10 11:27:22 INFO Producer:49 - Sent message : Message Counter : 32 2013-07-10 11:27:22 INFO Producer:25 - Establishing connection 2013-07-10 11:27:22 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:22 INFO Producer:30 - Connection established 2013-07-10 11:27:22 INFO Producer:47 - Sending message : Message Counter : 33 2013-07-10 11:27:22 INFO Producer:49 - Sent message : Message Counter : 33 2013-07-10 11:27:23 INFO Producer:25 - Establishing connection 2013-07-10 11:27:23 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:23 INFO Producer:30 - Connection established 2013-07-10 11:27:23 INFO Producer:47 - Sending message : Message Counter : 34 2013-07-10 11:27:23 INFO Producer:49 - Sent message : Message Counter : 34 2013-07-10 11:27:23 INFO Producer:25 - Establishing connection 2013-07-10 11:27:24 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:24 INFO Producer:30 - Connection established 2013-07-10 11:27:24 INFO Producer:47 - Sending message : Message Counter : 35 2013-07-10 11:27:24 INFO Producer:49 - Sent message : Message Counter : 35 2013-07-10 11:27:25 INFO Producer:25 - Establishing connection 2013-07-10 11:27:27 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:27 INFO Producer:30 - Connection established 2013-07-10 11:27:27 INFO Producer:47 - Sending message : Message Counter : 36 2013-07-10 11:27:27 INFO Producer:49 - Sent message : Message Counter : 36 2013-07-10 11:27:27 INFO Producer:25 - Establishing connection 2013-07-10 11:27:28 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:28 INFO Producer:30 - Connection established 2013-07-10 11:27:28 INFO Producer:47 - Sending message : Message Counter : 37 2013-07-10 11:27:28 INFO Producer:49 - Sent message : Message Counter : 37 2013-07-10 11:27:29 INFO Producer:25 - Establishing connection 2013-07-10 11:27:30 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:30 INFO Producer:30 - Connection established 2013-07-10 11:27:30 INFO Producer:47 - Sending message : Message Counter : 38 2013-07-10 11:27:30 INFO Producer:49 - Sent message : Message Counter : 38 2013-07-10 11:27:30 INFO Producer:25 - Establishing connection 2013-07-10 11:27:31 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:27:33 WARN FailoverTransport:255 - Transport (tcp://127.0.0.1:61616) failed, reason: java.net.SocketException: Software caused connection abort: recv failed, attempting to automatically reconnect 2013-07-10 11:27:38 INFO FailoverTransport:1032 - Successfully reconnected to tcp://localhost:61626 2013-07-10 11:27:38 INFO Producer:30 - Connection established 2013-07-10 11:27:38 INFO Producer:47 - Sending message : Message Counter : 39 2013-07-10 11:27:38 INFO Producer:49 - Sent message : Message Counter : 39 2013-07-10 11:27:39 INFO Producer:25 - Establishing connection 2013-07-10 11:27:39 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:39 INFO Producer:30 - Connection established 2013-07-10 11:27:39 INFO Producer:47 - Sending message : Message Counter : 40 2013-07-10 11:27:39 INFO Producer:49 - Sent message : Message Counter : 40 2013-07-10 11:27:39 INFO Producer:25 - Establishing connection 2013-07-10 11:27:40 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:40 INFO Producer:30 - Connection established 2013-07-10 11:27:40 INFO Producer:47 - Sending message : Message Counter : 41 2013-07-10 11:27:40 INFO Producer:49 - Sent message : Message Counter : 41 2013-07-10 11:27:41 INFO Producer:25 - Establishing connection 2013-07-10 11:27:42 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:42 INFO Producer:30 - Connection established 2013-07-10 11:27:42 INFO Producer:47 - Sending message : Message Counter : 42 2013-07-10 11:27:42 INFO Producer:49 - Sent message : Message Counter : 42 2013-07-10 11:27:42 INFO Producer:25 - Establishing connection 2013-07-10 11:27:42 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:42 INFO Producer:30 - Connection established 2013-07-10 11:27:42 INFO Producer:47 - Sending message : Message Counter : 43 2013-07-10 11:27:42 INFO Producer:49 - Sent message : Message Counter : 43 2013-07-10 11:27:43 INFO Producer:25 - Establishing connection 2013-07-10 11:27:44 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:44 INFO Producer:30 - Connection established 2013-07-10 11:27:44 INFO Producer:47 - Sending message : Message Counter : 44 2013-07-10 11:27:44 INFO Producer:49 - Sent message : Message Counter : 44 2013-07-10 11:27:44 INFO Producer:25 - Establishing connection 2013-07-10 11:27:45 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:45 INFO Producer:30 - Connection established 2013-07-10 11:27:45 INFO Producer:47 - Sending message : Message Counter : 45 2013-07-10 11:27:45 INFO Producer:49 - Sent message : Message Counter : 45 2013-07-10 11:27:46 INFO Producer:25 - Establishing connection 2013-07-10 11:27:47 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:47 INFO Producer:30 - Connection established 2013-07-10 11:27:47 INFO Producer:47 - Sending message : Message Counter : 46 2013-07-10 11:27:47 INFO Producer:49 - Sent message : Message Counter : 46 2013-07-10 11:27:48 INFO Producer:25 - Establishing connection 2013-07-10 11:27:48 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:48 INFO Producer:30 - Connection established 2013-07-10 11:27:48 INFO Producer:47 - Sending message : Message Counter : 47 2013-07-10 11:27:48 INFO Producer:49 - Sent message : Message Counter : 47 2013-07-10 11:27:48 INFO Producer:25 - Establishing connection 2013-07-10 11:27:49 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:49 INFO Producer:30 - Connection established 2013-07-10 11:27:49 INFO Producer:47 - Sending message : Message Counter : 48 2013-07-10 11:27:49 INFO Producer:49 - Sent message : Message Counter : 48 2013-07-10 11:27:50 INFO Producer:25 - Establishing connection 2013-07-10 11:27:51 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61626 2013-07-10 11:27:51 INFO Producer:30 - Connection established 2013-07-10 11:27:51 INFO Producer:47 - Sending message : Message Counter : 49 2013-07-10 11:27:51 INFO Producer:49 - Sent message : Message Counter : 49 Here is the web console showing 50 messages enqueued.Don’t bother the #Messages Enqueued = 0 in the above screenshot. This count represents the number of messages enqueued since this node started. Since I had restarted the node after the 50 messages were already enqueued, the count shows as 0. Now lets try to consume these messages using an asynchronous consumer using ActiveMQ connection factory with failover protocol. Here is simple asynchronous consumer with ActiveMQConnectionFactory using failover protocol. package com.akuntamukkala.amqms; import javax.jms.Connection; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.log4j.Logger; public class Consumer implements MessageListener { private static final Logger log = Logger.getLogger(Consumer.class); public static void main(String[] args) throws Exception { ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory( "failover:(tcp://localhost:61616,tcp://localhost:61626)"); // Create a Connection Connection connection = connectionFactory.createConnection(); connection.start(); // Create a Session Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // Create the destination (Topic or Queue) Destination destination = session.createQueue("TEST.FOO"); // Create a MessageConsumer from the Session to the Queue MessageConsumer consumer = session.createConsumer(destination); consumer.setMessageListener(new Consumer()); // asynchronous listener Thread.sleep(120000); // long wait to keep program running consumer.close(); session.close(); connection.close(); } /** * asynchronous message listener */ public void onMessage(Message message) { try { log.info(((TextMessage) message).getText()); Thread.sleep(500); } catch (JMSException e) { log.error(e); } catch (InterruptedException e) { log.error(e); } } } Here are the logs from the execution. I switched the master nodes a few times as evident in the logs. 2013-07-10 11:46:01 INFO FailoverTransport:1030 - Successfully connected to tcp://localhost:61616 2013-07-10 11:46:01 INFO Consumer:49 - Message Counter : 0 2013-07-10 11:46:02 INFO Consumer:49 - Message Counter : 1 2013-07-10 11:46:02 INFO Consumer:49 - Message Counter : 2 2013-07-10 11:46:03 INFO Consumer:49 - Message Counter : 3 2013-07-10 11:46:03 INFO Consumer:49 - Message Counter : 4 2013-07-10 11:46:04 INFO Consumer:49 - Message Counter : 5 2013-07-10 11:46:04 INFO Consumer:49 - Message Counter : 6 2013-07-10 11:46:05 INFO Consumer:49 - Message Counter : 7 2013-07-10 11:46:05 INFO Consumer:49 - Message Counter : 8 2013-07-10 11:46:06 INFO Consumer:49 - Message Counter : 9 2013-07-10 11:46:06 INFO Consumer:49 - Message Counter : 10 2013-07-10 11:46:07 INFO Consumer:49 - Message Counter : 11 2013-07-10 11:46:07 WARN FailoverTransport:255 - Transport (tcp://127.0.0.1:61616) failed, reason: java.io.EOFException, attempting to automatically reconnect 2013-07-10 11:46:18 INFO FailoverTransport:1032 - Successfully reconnected to tcp://localhost:61626 2013-07-10 11:46:18 WARN ActiveMQMessageConsumer:1348 - Duplicate dispatch on connection: ID:AKUNTAMU-1-2141-1373474760280-1:1 to consumer: ID:AKUNTAMU-1-2141-1373474760280-1:1:1:1, ignoring (auto acking) duplicate: MessageDispatch {commandId = 0, responseRequired = false, consumerId = ID:AKUNTAMU-1-2141-1373474760280-1:1:1:1, destination = queue://TEST.FOO, message = ActiveMQTextMessage {commandId = 5, responseRequired = true, messageId = ID:AKUNTAMU-1-1739-1373473592152-1:12:1:1:1, originalDestination = null, originalTransactionId = null, producerId = ID:AKUNTAMU-1-1739-1373473592152-1:12:1:1, destination = queue://TEST.FOO, transactionId = null, expiration = 0, timestamp = 1373473603281, arrival = 0, brokerInTime = 1373473603281, brokerOutTime = 1373474778676, correlationId = null, replyTo = null, persistent = true, type = null, priority = 4, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = null, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 0, properties = null, readOnlyProperties = true, readOnlyBody = true, droppable = false, text = Message Counter : 11}, redeliveryCounter = 0} 2013-07-10 11:46:18 INFO Consumer:49 - Message Counter : 12 2013-07-10 11:46:19 INFO Consumer:49 - Message Counter : 13 2013-07-10 11:46:19 INFO Consumer:49 - Message Counter : 14 2013-07-10 11:46:20 INFO Consumer:49 - Message Counter : 15 2013-07-10 11:46:20 INFO Consumer:49 - Message Counter : 16 2013-07-10 11:46:21 INFO Consumer:49 - Message Counter : 17 2013-07-10 11:46:21 INFO Consumer:49 - Message Counter : 18 2013-07-10 11:46:22 INFO Consumer:49 - Message Counter : 19 2013-07-10 11:46:22 INFO Consumer:49 - Message Counter : 20 2013-07-10 11:46:23 INFO Consumer:49 - Message Counter : 21 2013-07-10 11:46:23 INFO Consumer:49 - Message Counter : 22 2013-07-10 11:46:24 INFO Consumer:49 - Message Counter : 23 2013-07-10 11:46:24 INFO Consumer:49 - Message Counter : 24 2013-07-10 11:46:25 INFO Consumer:49 - Message Counter : 25 2013-07-10 11:46:25 INFO Consumer:49 - Message Counter : 26 2013-07-10 11:46:26 INFO Consumer:49 - Message Counter : 27 2013-07-10 11:46:26 INFO Consumer:49 - Message Counter : 28 2013-07-10 11:46:27 INFO Consumer:49 - Message Counter : 29 2013-07-10 11:46:27 INFO Consumer:49 - Message Counter : 30 2013-07-10 11:46:28 INFO Consumer:49 - Message Counter : 31 2013-07-10 11:46:28 INFO Consumer:49 - Message Counter : 32 2013-07-10 11:46:29 INFO Consumer:49 - Message Counter : 33 2013-07-10 11:46:29 INFO Consumer:49 - Message Counter : 34 2013-07-10 11:46:30 INFO Consumer:49 - Message Counter : 35 2013-07-10 11:46:30 INFO Consumer:49 - Message Counter : 36 2013-07-10 11:46:31 INFO Consumer:49 - Message Counter : 37 2013-07-10 11:46:31 INFO Consumer:49 - Message Counter : 38 2013-07-10 11:46:32 INFO Consumer:49 - Message Counter : 39 2013-07-10 11:46:32 WARN FailoverTransport:255 - Transport (tcp://127.0.0.1:61626) failed, reason: java.io.EOFException, attempting to automatically reconnect 2013-07-10 11:46:43 INFO FailoverTransport:1032 - Successfully reconnected to tcp://localhost:61616 2013-07-10 11:46:43 WARN ActiveMQMessageConsumer:1348 - Duplicate dispatch on connection: ID:AKUNTAMU-1-2141-1373474760280-1:1 to consumer: ID:AKUNTAMU-1-2141-1373474760280-1:1:1:1, ignoring (auto acking) duplicate: MessageDispatch {commandId = 0, responseRequired = false, consumerId = ID:AKUNTAMU-1-2141-1373474760280-1:1:1:1, destination = queue://TEST.FOO, message = ActiveMQTextMessage {commandId = 5, responseRequired = true, messageId = ID:AKUNTAMU-1-1739-1373473592152-1:40:1:1:1, originalDestination = null, originalTransactionId = null, producerId = ID:AKUNTAMU-1-1739-1373473592152-1:40:1:1, destination = queue://TEST.FOO, transactionId = null, expiration = 0, timestamp = 1373473658595, arrival = 0, brokerInTime = 1373473658599, brokerOutTime = 1373474803745, correlationId = null, replyTo = null, persistent = true, type = null, priority = 4, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = null, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 0, properties = null, readOnlyProperties = true, readOnlyBody = true, droppable = false, text = Message Counter : 39}, redeliveryCounter = 0} 2013-07-10 11:46:43 INFO Consumer:49 - Message Counter : 40 2013-07-10 11:46:44 INFO Consumer:49 - Message Counter : 41 2013-07-10 11:46:44 INFO Consumer:49 - Message Counter : 42 2013-07-10 11:46:45 INFO Consumer:49 - Message Counter : 43 2013-07-10 11:46:45 INFO Consumer:49 - Message Counter : 44 2013-07-10 11:46:46 INFO Consumer:49 - Message Counter : 45 2013-07-10 11:46:46 INFO Consumer:49 - Message Counter : 46 2013-07-10 11:46:47 INFO Consumer:49 - Message Counter : 47 2013-07-10 11:46:47 INFO Consumer:49 - Message Counter : 48 2013-07-10 11:46:48 INFO Consumer:49 - Message Counter : 49 Let’s check out the ActiveMQ web console:You may find the # Messages Dequeued = 11 very interesting. This is the number of messages dequeued from the current ActiveMQ master node since it started. Conclusion We have thus seen the following in action:Run 2 ActiveMQ nodes in a Master/Slave configuration with a shared KahaDB file based database. Configure ActiveMQ web console hosted in a Tomcat instance to point to whichever node is Master node in the cluster Failover scenario Message publisher and consumer behavior oblivious to the failoverIn future blogs, I will post some other interesting ActiveMQ configurations. Stay tuned. Happy ActiveMQ’ing! Resources:http://activemq.apache.org/ http://www.jakubkorab.net/category/technology/activemqReference: Using ActiveMQ – “Master/Slave” configuration with failover protocol from our JCG partner Ashwini Kuntamukkala at the Ashwini Kuntamukkala – Technology Enthusiast blog....
apache-activemq-logo

Temp, Store and Memory Percent Usage in ActiveMQ

In order to effectively use ActiveMQ, it is very important to understand how ActiveMQ manages memory and disk resources to handle non-persistent and persistent messages. ActiveMQ has three key parameters which need to be kept under check.Temp Percent UsageThis is the % of assigned disk storage that has been used up to spool non-persistent messages Non persistent messages are those that don’t survive broker restartStore Percent UsageThis is the % of assigned disk space that has been used up to store persistent messagesMemory Percent UsageThis is the % of assigned memory of the broker that has been used up to keep track of destinations, cache messages etc. This value needs to be lesser than -Xmx  (Max JVM heap size)This blog attempts to clarify how store,temp and memory % usage of a single node ActiveMQ broker instance are calculated. We are using ActiveMQ version 5.8.0 for this explanation. Once we gain clarity on how ActiveMQ operates these values, we can fine tune ActiveMQ using key configuration settings in order to handle the following use cases.Large number of destinations (queues/topics)The destinations could be created/deleted as neededSlow consumersThis is huge issue when consumers are unable to keep up with the rate at which messages are being produced.Message BurstRapid influx of large number of messages with huge payload size for a brief period of timeInappropriate Resource utilizationFew destinations chewing up resources causing others to starveScaling Strategies If you are interested to know how ActiveMQ can be scaled horizontally, please refer to a slide deck created by Bosanac Dejan. You can find it here It contains different ActiveMQ topologies which can be used effectively to meet volume throughput in addition to various parameters to tune ActiveMQ. I found it extremely useful. Let’s dig right in… The following XML snippet is taken from configuration activemq.xml. The values specified for memoryUsage, storeUsage and tempUsage are for discussion purposes only. <systemUsage> <systemUsage> <memoryUsage> <memoryUsage limit="256 mb"/> </memoryUsage> <storeUsage> <storeUsage limit="512 mb"/> </storeUsage> <tempUsage> <tempUsage limit="256 mb"/> </tempUsage> </systemUsage> </systemUsage>Memory Usage256MB of JVM memory is available for the broker. Not to be confused with -Xmx parameter.Store Usage:This is the disk space used by persistent messages (using KahaDB)Temp Usage:This is the disk space used by non-persistent message, assuming we are using default KahaDB. ActiveMQ spools non-persistent messages to disk in order to prevent broker running out of memoryUnderstanding Temp Usage Broker availability is critical for message infrastructure. Hence producer flow control is a protection mechanism that prevents a runaway producer from pumping non-persistent messages into a destination when there are no consumers or when consumer(s) is unable to keep up with the rate at which messages are being produced into the destination. Let’s take an example of producing non-persistent messages having 1MB payload size into a destination “foo.bar” in a local broker instance C:\apache-activemq-5.8.0\example>ant producer -Durl=tcp://localhost:61616 -Dtopic=false -Dsubject=foo.bar -Ddurable=false -DmessageSize=1048576 The producer eventually hangs as temp % usage hits 100%Since the messages are non-persistent, they are going to be stored in tmp_storage on the diskActiveMQ provides mechanism to tune memory usage per destination. Here we have a generic policy for all queues where producer flow control is enabled and destination memory limit is 100MB (again this is only for illustration purposes). <policyEntry queue=">" optimizedDispatch="true" producerFlowControl="true" cursorMemoryHighWaterMark="30" memoryLimit="100 mb" > The temp % usage is calculated as follows: (Size of the tmp_storage folder / temp usage memory limit ) * 100 So in our case: 265,025,856/(256*1024*1024) * 100 = 99.8 ~ 100% as shown in the broker console. The following log message shows up in activemq.log INFO | Usage(default:temp:queue://foo.bar:temp) percentUsage=99%, usage=268535808, limit=268435456, percentUsageMinDelta=1%;Parent:Usage(default:temp ) percentUsage=100%, usage=268535808, limit=268435456, percentUsageMinDelta=1%: Temp Store is Full (99% of 268435456). Stopping producer (ID:AKUNTAMU- 1-61270-1388528939599-1:1:1:1) to prevent flooding queue://foo.bar. See http://activemq.apache.org/producer-flow-control.html for more info (blockingfor: 1421s) Let’s take another example… Consider the following system usage configuration. We have reduced tempUsage to 50MB while keeping the same destination level policy. <systemUsage> <systemUsage> <memoryUsage> <memoryUsage limit="256 mb"/> </memoryUsage> <storeUsage> <storeUsage limit="512 mb"/> </storeUsage> <tempUsage> <tempUsage limit="50 mb"/> </tempUsage> </systemUsage></systemUsage> In this case we find that temp usage balloons to 191%temp_storage stops growing at close to 96MB and producer hangs..Temp percent usage is 191% because (95.5MB / 50 MB)*100 where 95.5 MB is size of the folder and 50MB is temp usage limit. The destination has a limit of 100MB so the temp_storage didn’t grow past it. It is sort of confusing which is caused by the fact that temp usage limit is less that per destination memory limit. Store Usage Let’s repeat the same test with persistent messages. The system usage is configured as follows: <systemUsage> <systemUsage> <memoryUsage> <memoryUsage limit="256 mb"/> </memoryUsage> <storeUsage> <storeUsage limit="512 mb"/> </storeUsage> <tempUsage> <tempUsage limit="256 mb"/> </tempUsage> </systemUsage></systemUsage>Per destination policy is as follows: <policyEntry queue=">" optimizedDispatch="true" producerFlowControl="true" cursorMemoryHighWaterMark="30" memoryLimit="100 mb" >Let’s produce 1MB persistent messages into a queue named “foo.bar” C:\apache-activemq-5.8.0\example>ant producer -Durl=tcp://localhost:61616 -Dtopic=false -Dsubject=foo.bar -Ddurable=true -DmessageSize=1048576Producer hangs after 512 messages The following log statement appears in broker log file INFO | Usage(default:store:queue://foo.bar:store) percentUsage=99%, usage=537210471, limit=536870912, percentUsageMinDelta=1%;Parent:Usage(default:st ore) percentUsage=100%, usage=537210471, limit=536870912,percentUsageMinDelta=1%: Persistent store is Full, 100% of 536870912. Stopping producer (ID: AKUNTAMU-1-31754-1388571228628-1:1:1:1) to prevent flooding queue://foo.bar. See http://activemq.apache.org/producer-flow-control.html for more info ( blocking for: 155s) Broker store usage is 100% as shown below.Since the messages are persistent, they need to be saved onto the file system. Store usage limit is 512MB.The above screenshot shows the kahadb folder where persistent messages is 543 MB (512MB for the messages and other database related files) Memory Usage In the above example, the memory usage percentage is 11. How did that come about? As per the destination policy, the memory allocated per destination is 100MB and the cursorMemoryHighWaterMark is specified to be 30. So 30% of 100MB is 30MB. Hence 30MB is used to store messages in memory for faster processing in addition to be being stored in the KahaDB. . The memory usage limit is configured to be 256MB. So 30MB is ~ 11% of 256 (30/256) * 100 ~ 11% So if we were to have 9 such queues where similar situation was to occur then we would have exhausted broker memory usage as 11 % * 9 = 99% ~ 100% Memory usage is the amount of memory used by the broker for storing messages. Many a times, this can become a bottleneck as once this space is full, the broker will stall the producers.  There are trade-offs between fast processing and effective memory management. If we keep more messages in memory, the processing is faster. However the memory consumption will be very high. On the contrary, if messages are kept on the disk then processing will become slow. Conclusion We have seen in this blog how store, temp and memory usage work in ActiveMQ. % of store and temp usage cannot be configured per destination while % of memory usage can be because of cursorMemoryHighWaterMark. Hope you found this information useful. The examples given here are for explanation purposes only and not meant to be production ready. You will need to do proper capacity planning and determine your broker topology for optimal configuration. Feel free to reach out if any comments! Resourceshttp://blog.raulkr.net/2012/08/demystifying-producer-flow-control-and.html http://tmielke.blogspot.com/2011/02/observations-on-activemqs-temp-storage.html http://activemq.apache.org/javalangoutofmemory.html http://www.slideshare.net/dejanb/advanced-messaging-with-apache-activemq -Bosanac Dejan http://www.pepperdust.org/?p=150 http://stackoverflow.com/questions/2361541/how-do-you-scale-your-activemq-vertically Reference: Temp, Store and Memory Percent Usage in ActiveMQ from our JCG partner Ashwini Kuntamukkala at the Ashwini Kuntamukkala – Technology Enthusiast blog....
java-logo

Java 8 Friday: No More Need for ORMs

At Data Geekery, we love Java. And as we’re really into jOOQ’s fluent API and query DSL, we’re absolutely thrilled about what Java 8 will bring to our ecosystem. Java 8 Friday Every Friday, we’re showing you a couple of nice new tutorial-style Java 8 features, which take advantage of lambda expressions, extension methods, and other great stuff. You’ll find the source code on GitHub. No More Need for ORMs Debates about the usefulness of ORM (Object-Relational Mapping) have been going on for the last decade. While many people would agree that Hibernate and JPA solve a lot of problems very well (mostly the persistence of complex object graphs), others may claim that the mapping complexity is mostly overkill for data-centric applications. JPA solves mapping problems by establishing standardised, declarative mapping rules through hard-wired annotations on the receiving target types. We claim that many data-centric problems should not be limited by the narrow scope of these annotations, but be solved in a much more functional way. Java 8, and the new Streams API finally allow us to do this in a very concise manner! Let’s start with a simple example, where we’re using H2′s INFORMATION_SCHEMA to collect all tables and their columns. We’ll want to produce an ad-hoc data structure of the type Map<String, List<String>> to contain this information. For simplicity of SQL interaction, we’ll use jOOQ (as always, a shocker on this blog). Here’s how we prepare this: public static void main(String[] args) throws Exception { Class.forName("org.h2.Driver"); try (Connection c = getConnection( "jdbc:h2:~/sql-goodies-with-mapping", "sa", "")) {// This SQL statement produces all table // names and column names in the H2 schema String sql = "select table_name, column_name " + "from information_schema.columns " + "order by " + "table_catalog, " + "table_schema, " + "table_name, " + "ordinal_position";// This is jOOQ's way of executing the above // statement. Result implements List, which // makes subsequent steps much easier Result<Record> result = DSL.using(c) .fetch(sql) } } Now that we’ve set up this query, let’s see how we can produce the Map<String, List<String>> from the jOOQ Result: DSL.using(c) .fetch(sql) .stream() .collect(groupingBy( r -> r.getValue("TABLE_NAME"), mapping( r -> r.getValue("COLUMN_NAME"), toList() ) )) .forEach( (table, columns) -> System.out.println(table + ": " + columns) ); The above example produces the following output: FUNCTION_COLUMNS: [ALIAS_CATALOG, ALIAS_SCHEMA, ...] CONSTANTS: [CONSTANT_CATALOG, CONSTANT_SCHEMA, ...] SEQUENCES: [SEQUENCE_CATALOG, SEQUENCE_SCHEMA, ...] How does it work? Let’s go through it step-by-step DSL.using(c) .fetch(sql)// Here, we transform a List into a Stream .stream()// We're collecting Stream elements into a new // collection type .collect(// The Collector is a grouping operation, producing // a Map groupingBy(// The grouping operation's group key is defined by // the jOOQ Record's TABLE_NAME value r -> r.getValue("TABLE_NAME"),// The grouping operation's group value is generated // by this mapping expression... mapping(// ... which is essentially mapping each grouped // jOOQ Record to the Record's COLUMN_NAME value r -> r.getValue("COLUMN_NAME"),// ... and then collecting all those values into a // java.util.List. Whew toList() ) ))// Once we have this List<String, List<String>> we // can simply consume it with the following Consumer // lambda expression .forEach( (table, columns) -> System.out.println(table + ": " + columns) ); Got it? These things are certainly a bit tricky when playing around with it for the first time. The combination of new types, extensive generics, lambda expressions can be a bit confusing at first. The best thing is to simply practice with these things until you get a hang of it. After all, the whole Streams API is really a revolution compared to previous Java Collections APIs. The good news is: This API is final and here to stay. Every minute you spend practicing it is an investment into your own future. Note that the above programme used the following static import: import static java.util.stream.Collectors.*; Note also, that the output was no longer ordered as in the database. This is because the groupingBy collector returns a java.util.HashMap. In our case, we might prefer collecting things into a java.util.LinkedHashMap, which preserves insertion / collection order: DSL.using(c) .fetch(sql) .stream() .collect(groupingBy( r -> r.getValue("TABLE_NAME"),// Add this Supplier to the groupingBy // method call LinkedHashMap::new, mapping( r -> r.getValue("COLUMN_NAME"), toList() ) )) .forEach(...); We could go on with other means of transforming results. Let’s imagine, we would like to generate simplistic DDL from the above schema. It’s very simple. First, we’ll need to select column’s data type. We’ll simply add it to our SQL query: String sql = "select " + "table_name, " + "column_name, " + "type_name " + // Add the column type "from information_schema.columns " + "order by " + "table_catalog, " + "table_schema, " + "table_name, " + "ordinal_position"; I have also introduced a new local class for the example, to wrap name and type attributes: class Column { final String name; final String type;Column(String name, String type) { this.name = name; this.type = type; } } Now, let’s see how we’ll change our Streams API method calls: result .stream() .collect(groupingBy( r -> r.getValue("TABLE_NAME"), LinkedHashMap::new, mapping(// We now collect this new wrapper type // instead of just the COLUMN_NAME r -> new Column( r.getValue("COLUMN_NAME", String.class), r.getValue("TYPE_NAME", String.class) ), toList() ) )) .forEach( (table, columns) -> {// Just emit a CREATE TABLE statement System.out.println( "CREATE TABLE " + table + " (");// Map each "Column" type into a String // containing the column specification, // and join them using comma and // newline. Done! System.out.println( columns.stream() .map(col -> " " + col.name + " " + col.type) .collect(Collectors.joining(",\n")) );System.out.println(");"); } ); The output couldn’t be more awesome! CREATE TABLE CATALOGS( CATALOG_NAME VARCHAR ); CREATE TABLE COLLATIONS( NAME VARCHAR, KEY VARCHAR ); CREATE TABLE COLUMNS( TABLE_CATALOG VARCHAR, TABLE_SCHEMA VARCHAR, TABLE_NAME VARCHAR, COLUMN_NAME VARCHAR, ORDINAL_POSITION INTEGER, COLUMN_DEFAULT VARCHAR, IS_NULLABLE VARCHAR, DATA_TYPE INTEGER, CHARACTER_MAXIMUM_LENGTH INTEGER, CHARACTER_OCTET_LENGTH INTEGER, NUMERIC_PRECISION INTEGER, NUMERIC_PRECISION_RADIX INTEGER, NUMERIC_SCALE INTEGER, CHARACTER_SET_NAME VARCHAR, COLLATION_NAME VARCHAR, TYPE_NAME VARCHAR, NULLABLE INTEGER, IS_COMPUTED BOOLEAN, SELECTIVITY INTEGER, CHECK_CONSTRAINT VARCHAR, SEQUENCE_NAME VARCHAR, REMARKS VARCHAR, SOURCE_DATA_TYPE SMALLINT ); Excited? The ORM era may have ended just now This is a strong statement. The ORM era may have ended. Why? Because using functional expressions to transform data sets is one of the most powerful concepts in software engineering. Functional programming is very expressive and very versatile. It is at the core of data and data streams processing. We Java developers already know existing functional languages. Everyone has used SQL before, for instance. Think about it. With SQL, you declare table sources, project / transform them onto new tuple streams, and feed them either as derived tables to other, higher-level SQL statements, or to your Java program. If you’re using XML, you can declare XML transformation using XSLT and feed results to other XML processing entities, e.g. another XSL stylesheet, using XProc pipelining. Java 8′s Streams are nothing else. Using SQL and the Streams API is one of the most powerful concepts for data processing. If you add jOOQ to the stack, you can profit from typesafe access to your database records and query APIs. Imagine writing the previous statement using jOOQ’s fluent API, instead of using SQL strings.The whole method chain could be one single fluent data transformation chain as such: DSL.using(c) .select( COLUMNS.TABLE_NAME, COLUMNS.COLUMN_NAME, COLUMNS.TYPE_NAME ) .from(COLUMNS) .orderBy( COLUMNS.TABLE_CATALOG, COLUMNS.TABLE_SCHEMA, COLUMNS.TABLE_NAME, COLUMNS.ORDINAL_POSITION ) .fetch() // jOOQ ends here .stream() // Streams start here .collect(groupingBy( r -> r.getValue(COLUMNS.TABLE_NAME), LinkedHashMap::new, mapping( r -> new Column( r.getValue(COLUMNS.COLUMN_NAME), r.getValue(COLUMNS.TYPE_NAME) ), toList() ) )) .forEach( (table, columns) -> { // Just emit a CREATE TABLE statement System.out.println( "CREATE TABLE " + table + " (");// Map each "Column" type into a String // containing the column specification, // and join them using comma and // newline. Done! System.out.println( columns.stream() .map(col -> " " + col.name + " " + col.type) .collect(Collectors.joining(",\n")) );System.out.println(");"); } ); Java 8 is the future, and with jOOQ, Java 8, and the Streams API, you can write powerful data transformation APIs. I hope we got you as excited as we are! Stay tuned for more awesome Java 8 content on this blog.Reference: Java 8 Friday: No More Need for ORMs from our JCG partner Lukas Eder at the JAVA, SQL, AND JOOQ blog....
agile-logo

Design Your Agile Project, Part 3

What do you do  for geographically distributed teams, if you want to move to agile? First question: does the team want to move to agile? Or, does the management want to move to agile? I am serious. I might take the same actions, but for different different reasons. In either case, the team needs to learn about what agile and lean means, and how to do agile. In both cases, the team needs help and protection from management.       Why Does a Geographically Distributed Team Need Help and Protection from Management?Managers create geographically distributed teams for many reasons. Some reasons are that there are smart people all over the world. In that case, managers create feature teams. When managers create dispersed teams, teams with one and two people in disparate locations in far-flung locations (more than 60 meters away), managers are under the impression that “experts” can perform jobs better than teams can. When managers think that “experts” can perform jobs better, they create bottlenecks in the work. Bottlenecks prevent flow. Bottlenecks prevent agile or lean from working. It does not matter if you want agile or lean. You won’t get either with a bottleneck. You have to overcome the bottleneck. Can you make a geographically distributed team work in an agile way? Yes. Let’s go back to the principles. Our principles of agile or lean:You need to see all the work in progress. You want to flow work through the entire team. You want to see working software, sooner, rather than later.If you, like me, don’t care how we get there, we have options. How Could a Team Take These Principles and Create Their Own Agile Approach? Let’s take one thing at a time. Let’s assume the team is not accustomed to working on small items of value. If you are like many of my clients, this is the case. What would it take for the team to start working on small features that deliver value? Let’s think about the product again:What kind of potential for release frequency does the team have? That colors the team’s thinking. The more potential for continuous deployment, the easier it is to work on small items of value. This is where I like to introduce the notion of spikes and timeboxes. I ask the team to take their smallest feature, and work together on it. They don’t always have any notion of “together,” either. They say things such as, “We need …” and list the impediments to their ability to work together. Now we see the need for management support. Project Management is Not a Dirty Word; Neither is Management I know that some of you dislike the idea of agile project managers. I know some of you positively hate the idea of management in agile organizations. Let me suggest that for teams transitioning to agile, there is a place for management. That place is creating an environment in which the team learns how to self-manage. There is no place for command-and-control project managers—never has been, never will be. Unless it’s time for lunch. Sometimes, teams need people to say, “Lunch-time!” But even that isn’t command-and-control. That’s someone saying, “I’m taking care of my need to eat. Want to come along?” It’s the same thing for a team with a lot of risk and a lot of unknowns. A team where the normal, out-of-the-box agile solutions don’t work. Why would you let a team like that flounder? That team needs everyone to lead. And, it often, but not always, needs someone to represent that team to management. Why? Because management doesn’t understand agile yet. That part might come now, and it might come later. But in an agile transition with many unknowns, it almost never happens at the beginning, even if management is saying, “Please go agile.” A geographically distributed team needs management support. It does not need command-and-control. That team does need support. That’s when I ask the person working as the project manager to start removing impediments. The team creates their own visual board. (Yes, a distributed team almost always needs a tool. I like to start with cards on a wall first, take pictures of it. Once a team knows how they like to work, then they choose a tool.) The team decides what the length of their timebox is for this feature, if they want to use iterations. They decide how to spike it. They start making decisions. That team especially needs to understand the problem of bottlenecks, experts, and how to stop needing experts. After they practice this a couple of times, they have the confidence they need to do this more times on their project. They can call this agile, but it might not have a real name. It’s a mishmash of timeboxes and kanban, but it works for them. Does it matter what it’s called? The Team Needs Management to Remove Obstacles Teams might need management support. For example, I often discover geographically distributed teams don’t have enough testers. Well, you say, that team flunks the “we have all the cross-functional roles to do the work” part of agile. Yes, and what if they don’t know that? What if they want to try agile? What if they want to work through their obstacles and impediments? They need someone to represent them to their management, while they try to test as they proceed, right? You could substitute “database admin” or “GUI designer” or whatever it is you need for tester in the above paragraph. Whenever you need someone to advocate on behalf of the team to management, you might want an agile project manager. Not someone to say, “When is the project going to be done?” Nope, not that kind of a PM. Someone to say, “What does the team need? I can help acquire that.” PMs who provide servant leadership to the team, and represent what the team has accomplished to the rest of management can be invaluable. They can help the team understand its process and facilitate what the team can do if the team gets stuck. These are agile project management skills. At this point, the team can try several approaches I suggested in these posts:Agile Lifecycles for Geographically Distributed Teams, Part 1 is for iterations and silo’d teams and a project manager. Agile Lifecycles for Geographically Distributed Teams, Part 2 is for kanban and silo’d teams and a project manager. Agile Lifecycles for Geographically Distributed Teams, Part 3 is for iterations and kanban and silo’d teams and a project manager.You might have an even better alternative than the ones I suggested. Do you need a project manager? No. Do you need a servant leader? In my experience, yes. Maybe in your experience, no. I would love to hear from you, if you have a geographically distributed team that does not have a servant leader. How Does This Team Evolve? Some of my clients who are committed to agile have evolved their dispersed teams to be feature teams in multiple places. That has worked very well for them. That has allowed each team to transition from the Complex to the Complicated. They now have collocated agile or lean teams. They can design their agile projects, as in Part 1. They retain the value of smart people all over the world. They don’t have the aggravation of trying to meet in different time zones for a project. They still have it for the program. Some of my clients are still trying to make the dispersed teams work. It’s really hard. You might want to read my paper about the common problems on these teams. Where are we now? In Design Your Agile Project, Part 1, we discussed a straight-on approach to using whatever approach to agile, because it was obvious where you were. In Design Your Agile Project, Part 2, we discussed looking at your system of work, and thinking about your unknowns. You need to think about your risks, and consider what you need to experiment with, to design your own agile project. This part, part 3, is a continuation of part 2. It matters because you might need a servant leader who might be called a project manager. The title matters, because especially on a geographically distributed team, you are bridging the gap and the culture between the old way of working and the new way of working. I still think it’s Complex. Some of my clients think it’s Chaotic because they have so many impediments. Whatever it is, you need data to take your next step.Reference: Design Your Agile Project, Part 3 from our JCG partner Johanna Rothman at the Managing Product Development blog....
career-logo

How to Level Up

I regularly hear from and read about technologists in a career rut. Unless one is both lucky and adept at predicting the future, experiencing some temporary stall can happen to professionals at any career stage. It may be the feeling of being stuck in an unchallenging role, feeling burdened by an undesirable skill set, or trapped in a company that seems difficult to escape. Career stagnation in technology could be defined as a prolonged period characterized by limited project variety, no advancement or even lateral movement, few tangible accomplishments, and little exposure to any emerging trends. Some managers are aware that workers in these situations generally leave, so the managers may proactively try to satisfy staff by shuffling teams and providing more interesting tasks. Many managers have to focus on deliverables and may give little thought to the career development of their charges, perhaps throwing money at retention problems instead of providing challenges.To “level up” could mean a promotion into management or technical leadership, a new start at a firm with increased opportunity, a role with autonomy and decision-making responsibility, or the ability to make significant improvements to skills and marketability. People that think about the leveling up concept often know what they want (or sometimes what they don’t want), but don’t necessarily see the best paths to get there. Leverage the skills you have to get the skills you want Most professionals view their current skills as a means to getting new jobs, but it’s useful to also think about skills as the key to acquiring other new skills. This tactic is most relevant when a skill set is dated and a previously strong marketability level is now questionable. Some will attempt to make a clean and immediate break from their old technologies or responsibilities into the new, usually with mixed results. As an example, many COBOL programmers tried to enter the stronger Java job market following Y2K. Some applied to jobs with no Java experience hoping their COBOL years would be deemed transferrable, while others pursued certifications and self-study to ideally be viewed as a somewhat “experienced” hire. One overlooked strategy was to approach companies that were using both COBOL and Java in some capacity, with the understanding that the candidate was willing to write COBOL if provided the ability to also work with Java. Most job seeking technologists have at least one ability that will help them contribute immediately to any other team or organization. It could be an obscure technical skill, leadership experience, or domain knowledge. Even if the skill is not something the person wants to use forever, it could be a key component to getting hired. Try to identify companies that may be looking for some specific expertise you can provide, even if it isn’t the most attractive tool in your bag, and be transparent about your willingness to do that less desirable work in exchange for exposure to skills that are in demand. DIY For those in the most stagnant of technical environments, taking on independent projects or open source may be the best way to gain experience and increase marketability. It’s usually preferable to learn new things on the job (because money), but being proactive about your career and keeping abreast of current marketable technologies will also show initiative to potential employers. The level up from personal projects almost always comes from an employment change. Sometimes to level up you need to take a step back – or sideways Careers aren’t always linear, and the expectation that trajectory needs to follow a strict continuous and incremental level of responsibilities is perhaps naive and potentially dangerous. Job seekers are often prone to placing too much weight on a position’s salary or (gasp) title without fully considering the position’s potential opportunity as it relates to future marketability and career development. Somewhat frequent movement between jobs is accepted in our industry, so positions can be viewed as stepping stones to future opportunities. When evaluating new roles, whether with a current employer or another firm, imagine what a three or four year tenure in that role at that company will look like on future résumés. Will the skills likely to be acquired or improved in that role be marketable and transferrable to other firms? Accepting positions that come with lateral responsibility and compensation is usually a wise long-term decision when provided a more favorable learning and growth environment.Reference: How to Level Up from our JCG partner Dave Fecak at the Job Tips For Geeks blog....
software-development-2-logo

Open Source Completely Underestimates Contributor License Agreements

Reddit’s /r/ProgrammerHumor has recently treated us to this politically incorrect and quite childish little Open Source rant                Obviously, like most “discussions” on reddit and specifically those discussions about Open Source, things got quickly very serious with people referring to Richard Stallman and how these critiques are childish and immature and what’s-wrong-with-our-industry™ etc. Let’s not delve into useless polemics but let’s have another look at a real problem in Open Source: Two types of Open Source There are essentially two types of Open Source:Hobbyist’s Open Source Professional Open SourceHobbyist’s Open Source Hobbyist’s Open Source projects are geeky side-projects by some engineers / hackers / script kiddies / etc. who have fun experimenting with 1-2 things and who are hoping to have “the public” comment / use / profit from their work. They most often have no interest in money / fame / rewards. They’re just doing it for the fun. Most often, they also choose funny licenses, like the Beer License. There’s nothing wrong with that. Professional Open Source Professional Open Source may evolve from the above (as in our case), or it may be conceived as professional Open Source from the beginning (as most Apache, Red Hat, or Oracle projects). When doing professional Open Source, choosing the right license is of the essence, as it is almost impossible to change that license again. Why? Because all contributors effectively own their copyrights of their contributions under the terms of the original license or worse under their own terms. This is less of a problem if you’re choosing a license like the ASL 2.0, which also manages contributions (and any trademarks, patents foregoing a contribution) in section 5: 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. However, you may still not change the license form ASL 2.0 to anything else (like GPL, or commercial) without the express permission of all your contributors. At least not for the contributed code. Managing contribution restrictions with CLAs At Data Geekery, we want to stay in full control of both source code maintenance, but also copyright. We take copyright very seriously, which is why we have bought / internalised all essential contributions by our contributors through a CLA (Contributor License Agreement). This allows us to continue publishing our jOOQ code under the terms of the ASL 2.0 and our more restrictive commercial license. Few Open Source projects / platforms actually do this. Among the most famous ones areThe Free Software Foundation The Eclipse Foundation The jQuery Foundation Joyent (Node.js) The Apache Foundation Our own (jooq.org)If you’re serious about your Open Source project, do take due diligence seriously as well. Copyright is not an option, you have to get this right, also in the best of interest of your customers / users. If you do not agree on contributor license terms with your contributors (e.g. by blindly merging all sorts of pull requests in your GitHub repository), you will:Restrict yourself to the current license forever … this includes not being able to dual-license your software … this includes not being able to commercially license your software … this may include the risk of having to pay royalties later on (not with ASL 2.0) … this may include the risk of your users having to pay royalties later on (not with ASL 2.0)CLAs on GitHub GitHub has become the number one hosting service for Open Source projects, world-wide. Yet, many projects are not getting licensing right. While GitHub offers a simple way to specify a popular license for your repository, there is currently no easy way to have your contributors sign CLAs. I’ve recently had a short discussion on Twitter with Assaf Arkin and Stefan Tilkov: If you fork a repository, submit a pull request that doesn’t change the license, do you still need a CLA? — Assaf Arkin (@assaf) March 22, 2014We all agreed that this is currently not handled correctly, in most cases. I have thus sent off a feature request to GitHub: I would like to enable a checkbox which all contributors have to check (after reading a document), to confirm that they’re complying with the contribution terms. You already have a similar feature with licenses when creating a new repository, which is great. But many people inevitably run into due dilience cases, because they just blindly merge all pull requests offered by anyone. So it would be useful to have a couple of default texts to chose from, and a possibility to create our own. Right now, I’m sending off PDFs by E-Mail for a signature. I hadn’t thought of Google Docs, yet, good idea. One source of inspiration could be the Eclipse Foundation, which has a fully automated CLA process, integrated into BugZilla. If a user submits a patch, you can immediately see if they have already signed the Eclipse Foundation CLA. I think that this would be a killer feature for GitHub, at least for the more professional OSS repositories. This feature request was well-received with GitHub support. If you think that this is a good idea, send them some love as well. It would really be great to finally get this right. Conclusion If you’re a user of Open Source software, beware of the above. Don’t just integrate any geeky script / tool that you happened to have found on the internet in your corporate, enterprise software. You are putting your employer at great legal risk if you do so. Open Source is not an excuse to pretend everything is free (of charge and of obligations). It is as well-defined a business as anything else. We cannot say this enough: Choose wisely when integrating third-party software. Even if it is Open SourceReference: Open Source Completely Underestimates Contributor License Agreements from our JCG partner Lukas Eder at the JAVA, SQL, AND JOOQ blog....
software-development-2-logo

Services, Microservices, Nanoservices – oh my!

Apparently there’s this new distributed architecture thing called microservices out and about – so last week I went ahead and read Martin Fowler’s & James Lewis’s extensive article on the subject . and my reaction to this was basically:       I guess it is easier to use a new name (Microservices) rather than say that this is what SOA actually meant – re http://t.co/gvhxDfDWLG — Arnon Rotem-Gal-Oz (@arnonrgo) March 16, 2014Similar arguments (nothing new here) were also expressed after Martin’s tweet of his article e.g. Clemens Vasters’ comment: @martinfowler @boicy but these are the very principles of SOA before vendors does pushed the hub in the middle, i.e. ESB — Clemens Vasters (@clemensv) March 16, 2014Or Steve Jones’ post “Microservices is SOA, for those who know what SOA is.” Autonomy, smart endpoints, events etc. that the article talks about are all SOA concepts – If you happen to have read my book and you read this article you’ve probably identified these as patterns like inversion of communication, Service Host,Service Instance, Service Watchdog and others. So microservices as they appear from Martin’s & James’s article is pretty much service orientation without some of the bad misconception that tied into the SOA moniker like WS*, ESBs as a must, etc. -perhaps that’s a good enough reason for a new name but personally I doubt it. However, the story doesn’t end here there are various other opinions as to what microservices are such as Chris Ford’s view who says that “My own opinion is that microservice architectures can be understood through a single abstract architectural constraint which can be interpreted along many different degrees of freedom. X can be varied independently of the rest of the system.” The idea that something is separate  and can be varied independently from the rest of the system is  good but I would hardly say it is a definition of anything or at least anything new. CSCI (Computer Software Configuration Item) which I first heard of as part  of  DOD-STD-2167A (published in 1988) essentially means the same thing a CSCI is a component that can be varied independently from the rest of the system. In 2167A eyes it also means a very detailed , waterfall,  documentation laden process,  which isn’t what anyone thinks service or microservices should entail but it does demonstrate that “being varied independently” doesn’t mean much. I am sure some reader goes something like “but wait, we’re talking about micro-services here  - so they should also be small”  - indeed  there are posts like James Hughes’s on microservice with a quote like “First things first what actually is a micro service? Well there really isn’t a hard and fast definition but from conversations with various people there seems to be a consensus that a micro service is a simple application that sits around the 10-100 LOC mark.” (truth be told is that in the next sentence James says that LOC is an atrocious way to compare implementations but I thought it was worth repeating due to the use of the  words “there seems to be a consensus”) So how can you have 100 LOC services? you can get there if you rely on frameworks (like Finagle or Sinatra James mention) generate serialization/deserialization code (protobuff, thrift, avro etc.)  - this is essentially building on a smart service host. Another example for this would be developing in Erlang with its supervisor hierarchies which also brings us to another way to reduce LOC by use languages that are less verbose (like the aforementioned Erlang,  python or scala vs. say, Java). I would say., however, that if you find you have a 10  lines of code service, you are more likely than not, implementing a function as a service and you don’t have a real service micro or not- e.g. I can’t see you having a decentralized storage (and autonomy) as mentioned in Martin’s and Lewis’s article above or having monitoring and instrumentation that Hughes mention. You should also keep in mind that while better and cheaper networks allow us to push the limits – the fallacies of distributed computing still exist furthermore having a lot of small services that you need to manage along with the performance hits for serializations and deserializations, security etc. may very well mean that you moved from valid smaller “micro” services into the realm of headache which I called “Nano services” “Nanoservice is an antipattern where a service is too fine-grained. A nanoservice is a service whose overhead (communications, maintenance, and so on) outweighs its utility.” So there we have it, for the most part microservices is just another name for the principle of SOA, anther name might have been appropriate in the hype days of SOA, but I think these days most of that vapor has cleared and people understand better what’s needed. Furthermore if we do want to name proper SOA by a new name I think microservices is a poor term as it leads toward the slippery slope into nano-services and 10 lines of code which are just your old web-service method executed by a fancy chic host using a hot serialization format. Micro or not, services should be more useful than the overhear they incur.Reference: Services, Microservices, Nanoservices – oh my! from our JCG partner Arnon Rotem Gal Oz at the Cirrus Minor blog....
java-logo

Oracle Drops Collection Literals in JDK 8

In a posting on the OpenJDK JEP 186 Oracle’s Brian Goetz informs that Oracle will not be pursuing collection literals as a language feature in JDK8. A collection literal is a syntactic expression form that evaluates to an aggregate type as an array, List or Map. Project Coin proposed collection literals, which also complements the library additions in Java SE8. The assumption was that collection literals would increase productivity, code readability, and code safety. As an alternative Oracle suggests a library-based proposal based on the concept of static methods on interfaces. The Implementation would ideally be via new dedicated immutable classes. Following are the major points behind this library-based approach.The basic solution of this feature works only for Sets, Lists and Maps so it is not very satisfying or popular. The advanced solution to cover an extensible set of other collection types is open-ended, messy, and virtually guaranteed to way overrun its design budget. The library-based changes would remove much of the requirement for the “collection literals” change discussed in Project Coin. The library-based approach gives X% of the benefit for 1% of the cost, where X >> 1. The value types are coming and the behavior of this new feature (collection literals) with the value types is not known. It is better not to try collection literal before the value types. It is better off focusing Oracle’s language-design bandwidth on addressing foundational issues underlying a library-based version. This includes more efficient varargs, array constants in the constant pool, immutable arrays, and support for caching (and reclaiming under pressure) intermediate immutable results.According to Oracle’s Brian Goetz, the real pain is in Maps not Lists, Sets or Arrays. The library-based solutions are more acceptable for Lists, Sets and Arrays. But this approach still lacks a reasonable way to describe pair literals as Maps. The Static methods in an interface make the library-based solution more practical. The value types make library-based solutions for Map far more practical too. The proof of concept patch for the library-based solution is also available.Reference: Oracle Drops Collection Literals in JDK 8 from our JCG partner Kaushik Pal at the TechAlpine – The Technology world blog....
Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books
Get tutored by the Geeks! JCG Academy is a fact... Join Now
Hello. Add your message here.