Apache ZooKeeper

I don’t know why management of firms that deal with financial data tend to be very conservative about new technology in my part of the world. There are varied reasons for this but the lack of experience of executives is high on the list. The vision to support large-scale deployments of mission critical software is just not there.

Company honchos should read Joel Spolsky’s opinion about the role of the executives in shaping the technology roadmap of the company.

I recently explored options to monitor and operate a simple cluster of Java socket programs and came across ZooKeeper. It is not strictly a requirement for a distributed application but these individual socket programs need to be managed and some may need to be restarted.

Initially I thought of using Google protobuffer and send simple information about the number of messages and load to the centralized ZooKeeper instance so that some decision can be taken based on it. This idea is not fully explored yet but the sample program that uses ZooKeeper nodes and proto buffer messages is shown below.

The messages sent and received from ZooKeeper nodes can be serialized in any way and here proto buffer is used for that.

Producer stores messages in the node


import com.google.protobuf.InvalidProtocolBufferException;
import message.Message;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;

public class DistributedProducer {

    private ZooKeeperCoordinator zkc;

    private String root = "/Protocol Buffer";

    {
        try {
            zkc =
            new ZooKeeperCoordinator( "localhost:2181",
                                      root );
            zkc.connect();
            zkc.setUpRoot();
        } catch (InterruptedException e) {

            System.out.println( "InterruptedException" );

        } catch (IOException e) {

            System.out.println( "IOException" );
        }

    }

    public void send() throws IOException, InterruptedException, KeeperException {

        if( null != zkc ){
            ZooKeeper zk = zkc.getZookeeper();
            Stat stat =
            zk.setData( root + "/protocolbuffer",
                       getData(),
                       -1
                      );
            System.out.println( "Stat is  [" + stat + "]");
        }
    }

    private byte[] getData() throws InvalidProtocolBufferException {
        Message.Load message = Message.Load.newBuilder().setType(
                                 ( Message.Load.LoadType.HIGH)).build();
        Message.Load message1 = Message.Load.parseFrom( message.toByteArray() );
        System.out.println( "Distributed value is [" + message1.getType().toString() +"]");
        return message.toByteArray();
    }
}

Consumer consumes it.


import com.google.protobuf.InvalidProtocolBufferException;
import message.Message;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class DistributedConsumer {

    private ZooKeeperCoordinator zkc;

    private String root = "/Protocol Buffer";

    {
        try {
            zkc =
            new ZooKeeperCoordinator( "localhost:2181",
                                      root );
            zkc.connect();
        } catch (InterruptedException e) {

            System.out.println( "InterruptedException" );

        } catch (IOException e) {

            System.out.println( "IOException" );
        }

    }

    public void receive() throws IOException, InterruptedException, KeeperException {

        Stat stat = null;

            if( null != zkc ){
                ZooKeeper zk = zkc.getZookeeper();
                if( null != zk ){
                    byte[] value =
                    zk.getData( root + "/protocolbuffer",
                               false,
                               stat
                              );
                    getData( value );
                }
            }
    }

    private void getData( byte[] value ){

        try {
            Message.Load message = Message.Load.parseFrom( value );
            System.out.println( "Distributed value is  [" + message.getType().toString() + "]");

        } catch (InvalidProtocolBufferException e) {

            System.out.println( "InvalidProtocolBufferException" + e.getMessage() );
            e.printStackTrace();

        }
    }
}

A client that connects to and sets up ZooKeeper


import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

public class ZooKeeperCoordinator {
    
    private String host;
    
    private String root;

    private Stat stat;

    public ZooKeeper getZookeeper() {
        return zookeeper;
    }

    private ZooKeeper zookeeper;

    public ZooKeeperCoordinator( String host,
                                 String root ){

        this.host = host;
        this.root = root;

    }

    public void setUpRoot(){

        System.out.println( "Set up root" );
        try {
            stat = zookeeper.exists( root,
                                     false );
            if( null == stat ){
                 zookeeper.create( root,
                                   new byte[ 0 ],
                                   ZooDefs.Ids.OPEN_ACL_UNSAFE,
                                   CreateMode.PERSISTENT);
            }
        } catch (KeeperException e) {
            System.out.println( "KeeperException" );

        } catch (InterruptedException e) {
            System.out.println( "InterruptedException" );
        }
    }

    public void connect() throws InterruptedException, IOException {

        System.out.println( "connect" );
        final CountDownLatch latch = new CountDownLatch( 1 );

        Watcher watcher = new Watcher(){

            public void process(WatchedEvent watchedEvent) {

                if( watchedEvent.getState() == Event.KeeperState.SyncConnected ){
                    latch.countDown();
                }
            }
        };

        zookeeper = new ZooKeeper( host, 1000, watcher );
        latch.await();
        System.out.println( "Awaiting connection" );
    }

    public void close() throws InterruptedException {
        zookeeper.close();
    }
}

The Protocol Buffers documentation has instructions to compile this simple .proto data structure

package message;

message Load {

  enum LoadType {
    HIGH = 0;
    MEDIUM = 1;
    LOW = 2;
  }


  optional LoadType type = 1 [default = MEDIUM];

}

Java Path Finder

Java Path Finder(JPF) is a model checker for Java programs and can check concurrent programs for deadlocks and data races which are more serious in muti-core environments. Java threads used by concurrent programs are context switched by the OS scheduler at run-time when we ‘yield’ a thread or due to some other reason. Even though it might be possible to test these scenarios extensively by profiling a few possible combinations of thread interleavings, it is quite tedious. So JPF tests this type of code by exploring all the code using algorithms to find errors.

JPF has quite a number of plug points and gov.nasa.jpf.jvm.VMListener is one such interface. I have implemented it to get data about the number of BLOCKED threads that the System Under Test(SUT) has and the monitor that they are blocked at. The data is still not clear but it is reasonable. I am not able to get clear data showing how many threads are blocked for a particular monitor to be released at a point in time. I think the code has to be refined.

JPF can be downloaded from http://babelfish.arc.nasa.gov/trac/jpf/ by using a mercurial eclipse plugin and it is quite easy to build and use.

I implemented gov.nasa.jpf.jvm.VMListener and added the classpath entry pointing to the class file to jpf-core.native_classpath

gov.nasa.jpf.jvm.VMListener based on JPF source code

public class LockContentionListener implements VMListener{


	@Override
	public void threadStarted(JVM vm) {
		printLocks( vm );
	}


	/**
	 * Thread and lock status.
	 * @param vm
	 */

	    private void printLocks( JVM jvm ){

		StringBuffer locksAndThreads = new StringBuffer();

		for ( ThreadInfo tf : jvm.getThreadList().getThreads()) {

		    ElementInfo ei = tf.getLockObject();
		    if (ei != null) {
		      if (tf.getState() == ThreadInfo.State.WAITING ||
				  tf.getState() == ThreadInfo.State.BLOCKED ) {
			  locksAndThreads.append( "\n");
			  locksAndThreads.append(tf.getStateDescription());
			  locksAndThreads.append(ei);
			  locksAndThreads.append(" \n Lock Count (" +                 ei.getMonitor().getNumberOfBlockedThreads()+ ")");

			    LinkedList locks = tf.getLockedObjects();
			    if (locks.isEmpty()) {
				locksAndThreads.append("  call stack:");
				    for (StackFrame frame : tf){
				      if (!frame.isDirectCallFrame()) {
					  locksAndThreads.append("\tat \n ");
					  locksAndThreads.append(frame.getStackTraceInfo());
				      }
				    }
			    }
				System.out.println( "Locks owned by Threads[ " + locksAndThreads + " \n ]");

		  }
		 }
		}
	    }

SUT

public class LockContention{
	
	private static final int NUM_THREADS = 2;
	
	
	public  static void main( String... argv ) throws InterruptedException {
		
		Thread[] readThreads = new Thread[ NUM_THREADS ];

		Locker locker = new Locker();
		
		for(  int i = 0 ; i < readThreads.length; i ++ ){
			
			readThreads[ i ] = new Thread( new ReadLockContention( locker ) ){
				
				public String getName(){
					return "LockContention (Reader)[ " + getId() + " ]";
				}
				
				
			};
		}

		Thread[] writeThreads = new Thread[ NUM_THREADS ];

		for( int i = 0 ; i < writeThreads.length; i ++ ){
			writeThreads[ i ] = new Thread( new WriteLockContention( locker ) ){

				public String getName(){
					return "LockContention (Writer)[" + getId() + " ]";
				}
				
			};
		}
		
		for( Thread t : readThreads ){
			t.start();
		}
		for( Thread t : writeThreads ){
			t.start();
		}
		for( Thread t : readThreads ){
			t.join();
		}

		for( Thread t : writeThreads ){
			t.join();
		}
		
	}


}

class ReadLockContention implements Runnable{
	
	private Locker locker;
	
	public ReadLockContention( Locker locker ){
		this.locker = locker;
	}

	@Override
	public void run() {
		locker.contendForReadLock();
		
	}

}

class WriteLockContention implements Runnable{
	
	private Locker locker;
	
	public WriteLockContention( Locker locker ){
		this.locker = locker;
	}

	@Override
	public void run() {
		locker.contendForWriteLock();
		
	}

}

class Locker{
	
	private final String lock = new String();

	/**
	 * Consider this as a read lock
	 */
	void contendForReadLock(){
			synchronized( lock ){
				try {
					Thread.sleep(50000);
				} catch (InterruptedException e) {
					System.out.println( "InterruptedException" );
			    }
				
			}
	}
	
	/**
	 * Consider this as a write lock
	 */
	void contendForWriteLock(){
			synchronized( lock ){
				
			}
	}
	
}

Output

The command

jpf +listener+=LockContentionListener LockContention.jpf

produces

Threads blocked on Locks[
thread id=2,name=Thread-2,status=BLOCKED,priority=5,lockCount=0,suspendCount=0java.lang.String@137
Lock Count (1) call stack: at
Locker.contendForReadLock(LockContention.java:97) at
ReadLockContention.run(LockContention.java:67)
]
Threads blocked on Locks[
thread id=1,name=Thread-1,status=BLOCKED,priority=5,lockCount=0,suspendCount=0java.lang.String@137
Lock Count (1) call stack: at
Locker.contendForReadLock(LockContention.java:97) at
ReadLockContention.run(LockContention.java:67)
]

The monitor is shown in bold. I want to know how many threads are blocked for a lock to be released.
It seems that these messages indicate that two threads(Thread-1,Thread-2) are blocked on the same monitor but I think this has to be investigated further. There is no reply to my forum question about this.

Sangam 2011

I recently visited bangalore to speak about Java Concurrency and a different set of problems like ‘False Sharing’, CAS instructions etc. Even model checkers like Java Path Finder was in the agenda. I spent quite a number of hours on the slides and the white paper. On the whole it was enlightening to investigate how Java programs are affected by multiple cores and shared memory and cache coherency.

The turnout for the conference was extremely poor but this affected only the Java tracks. It seems that the Java user groups in India are sometimes at loggerheads with each other and oneupmanship is not uncommon among the JUG’s.

I was mainly interested in the way Java problems perform on multi-core systems because there are so many tutorials on the net that show examples of other more common Java API’s. Hard problems like concurrency have their own attraction because we do not generally profile and investigate our commercial applications using Java Path Finder.

I am happy that I learnt quite a lot about relaxed memory models, java.util.concurrent and many other such topics. There is more to write about later in the blog about all this.

Fork Join

These are simple programs that might help one understand how to use java.util.concurrent.RecursiveAction which uses the ForkJoin framework. I am trying to analyze how this framework employs the work stealing algorithm so that the programs use multiple cores more efficiently.

The innards of this algorithm and its variataions do not seem to be so simple and I did not find any cheap tools that will help me understand how the cores are more efficiently used. I am looking for a way to visualize this algorithm in a simpler way. JavaFX looks appealing but the problem is that the actual algorithm should drive the UI instead of a visually appealing show that does not reveal the way the code behaves in a certain multi-core environment. So I am trying to manipulate the UI exactly when a task is stolen but how this type of code interacts with the framework is not known at this time.

MergeSort

 

public class SortTask {
	
    long[] aux = new long[ 40 ];

    static long[] list = new long[ 40 ];

    private void mergeSort( int lo, int hi){
 
    	if( lo < hi ){
    		
        	int mid = ( lo + hi )/ 2;
        	
        	mergeSort( lo, mid );
        	
        	mergeSort( mid + 1, hi );
        	
        	merge( lo, mid, hi );
    	}
    	
    }
    
	private void merge( int lo,
    		            int mid,
    		            int hi ){
    	 int i = lo, j = mid + 1;
    	 
    	 int k = lo;
    	 
    	 for( ; k <= hi ; k ++ ){
    		aux[ k ] = list[ k ];
    	 }
    	 k = lo;
    	 while( i <= mid && j <= hi){
    		 if( aux[i] < aux[j]){
    			 list[k++] = aux[i++];
    		 }else{
    			 list[k++] = aux[j++];
    		 }
    	 }
    	 while( i <= mid ){
			 list[k++] = aux[i++];
    	 }
     }
     
     private static long[] getArray(){
   	 
    	 Random random = new Random();
    	 
    	 for( int i = 0 ; i < list.length ; i ++ ){
    		 list[ i ] = random.nextInt(1000);
    	 }
    	 
    	 return list;
    	 
     }
     
     private void printArray(){
    	 for( int i = 0 ; i < list.length ; i ++ ){
    		 System.out.printf( "%2s ", list[ i ]);
    	 }
   		 System.out.printf( "%n");
     }
     
     public  static void main( String... argv ){
    	 list = SortTask.getArray();
    	 SortTask st = new SortTask();
    	 st.printArray();
    	 st.mergeSort( 0, list.length - 1 );
    	 st.printArray();
     }
     
}

MergeSort using ForkJoin

 

 
public class ForkJoinSortTask extends RecursiveAction{
	
	private static final long serialVersionUID = 1070860898589424509L;

	long[] aux = new long[ 40 ];

	private int lo;

	private int hi;

    long[] list = new long[ 40 ];

    public ForkJoinSortTask( long[] list, int lo, int hi ){
    	this.list = list;
    	this.lo = lo;
    	this.hi = hi;
    }
    
	public ForkJoinSortTask() {
   	    this.list = getArray();
    	this.lo = 0;
    	this.hi = list.length - 1;
	}

  
	private void merge( int lo,
    		            int mid,
    		            int hi ){
    	 int i = lo, j = mid + 1;
    	 
    	 int k = lo;
    	 
    	 for( ; k <= hi ; k ++ ){
    		aux[ k ] = list[ k ];
    	 }
    	 k = lo;
    	 while( i <= mid && j <= hi){
    		 if( aux[i] < aux[j]){
    			 list[k++] = aux[i++];
    		 }else{
    			 list[k++] = aux[j++];
    		 }
    	 }
    	 while( i <= mid ){
			 list[k++] = aux[i++];
    	 }
     }
     
     private long[] getArray(){
   	 
    	 Random random = new Random();
    	 
    	 for( int i = 0 ; i < list.length ; i ++ ){
    		 list[ i ] = random.nextInt(1000);
    	 }
    	 
    	 return list;
    	 
     }
     
     private void printArray(){
    	 for( int i = 0 ; i < list.length ; i ++ ){
    		 System.out.printf( "%2s ", list[ i ]);
    	 }
   		 System.out.printf( "%n");
     }
     
     public  static void main( String... argv ){
    	 ForkJoinSortTask st = new ForkJoinSortTask();
    	 st.printArray();
    	 ForkJoinPool fjp = new ForkJoinPool();
    	 fjp.invoke( st );
    	 st.printArray();
     }

	@Override
	protected void compute() {

    	if( lo < hi ){
    		
        	int mid = ( lo + hi )/ 2;
        	
            invokeAll( new ForkJoinSortTask(list, lo, mid),
                       new ForkJoinSortTask(list, mid + 1, hi));
        	
        	merge( lo, mid, hi );
    	}

	}
     
}

EasyMock IArgumentMatcher

When EasyMock is used to set expectations we might need to specify what parameters are used to call a method on the mock object. An ‘IArgumentMatcher’ is used for this purpose as this section from the EasyMock documentation describes.

Sometimes it is desirable to define own argument matchers. Let’s say that an argument matcher is needed that matches an exception if the given exception has the same type and an equal message. It should be used this way:

 
     IllegalStateException e = new IllegalStateException("Operation not allowed.")
     expect(mock.logThrowable(eqException(e))).andReturn(true);

I wanted to specifically check if the argument matcher matches a parameterized java.util.Set with a certain number of elements in it. This is how I am able to do it.

So here I pass the expected size of the Set as a constructur parameter but I use Generics reflection to get the raw type for comparison. The idea to use an anonymous class in the line

 

   SetReturnTest<ObjectInstance> returnTest = new SetReturnTest<ObjectInstance>( set.size() ){};


to preserve the raw type at run-time is from Neil Gafter.

It does seem that not all raw types are erased in all cases. This is still hard to do and I believe I get Generics wrong in many cases.


package com.monitor.test.suite.mock;

import org.easymock.EasyMock;
import org.easymock.IArgumentMatcher;

import javax.management.ObjectInstance;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Set;



public class SetReturnTest<T> implements IArgumentMatcher {


    /**
     * The expected reflective type of objects in the returned java.util.Set
     */
    Type objectTypeExpected;
    /**
     * The expected size of the returned java.util.Set
     */
    protected int size;
    /**
     * The reflective type of objects in the returned java.util.Set
     */
    protected Type type;

    /**
     * The type and number of the objects in the java.util.Set
     * .
     */
    public SetReturnTest( int size ) {
        /**How many are expected in the java.util.Set?*/
        this.size = size;
        /**
         * The  parameterized type is matched
         * with the actual type expected at run-time.
         *
         */
        ParameterizedType pt =
                    (ParameterizedType) (getClass().getGenericSuperclass());
        type = pt.getActualTypeArguments()[ 0 ];
    }

    /**
     * EasyMock via the static method reportMatcher(IArgumentMatcher matcher), 
     * and return a value so that it may be used inside the call (typically 0, null or false). 
     */
    public Set eqSet( Type type, Set set ) {
        objectTypeExpected = type;
        SetReturnTest<ObjectInstance> returnTest = new SetReturnTest<ObjectInstance>( set.size() ){};
        EasyMock.reportMatcher( returnTest );
        return null;
    }


    /**
     * The actual java.util.Set is compared with the
     * one expected by the mock test. There are unchecked
     * warnings here but this seems to be the best possible attempt.
     */
    public boolean matches( Object actual ) {

        /** Unchecked is a potential problem*/
        @SuppressWarnings("unchecked")
        SetReturnTest setReturnTest = (SetReturnTest) actual;

        if( setReturnTest.size != size ){
            return false;
        }
        Type clazz1 = setReturnTest.type;
        Class clazz2 = (Class)objectTypeExpected;

        boolean match =
                clazz2.isAssignableFrom( (Class)clazz1 );

        return match;
    }

    /**
     * Append a simple error to identify which
     * matcher was used.
     */
    public void appendTo(StringBuffer buffer) {
        buffer.append( "SetReturnTest matcher" );
    }
}

Mock tests for JMX

There is not much scope for this blog if code is posted without explanation but I can explain only what I understand. There is magic going on behind this code.

I had to write mocks for some JMX classes for a project that I could not convince the management to use. JMX is a useful toolkit to monitor complex pipelines of processes and is integral to DevOps. So firms that want to leverage this idea should think differently.

Does it seem logical ?

This argument fell flat on its face.

This code mocks “ManagementFactory.getPlatformMBeanServer()” and in doing so I exercised EasyMock. It is not easy to mock statics but these EasyMock annotations help. So I am able to set the expectations and make the Platform Bean Server return a mock of the MBeanServer. This is very useful because now I can register MBeans and write more mock tests.

@RunWith(PowerMockRunner.class)
@PrepareForTest(ManagementFactory.class)
@PowerMockIgnore(value = {"javax.management.*"})
public class MBeanQueryTestCase  extends MonitorTestCase {


    private MBeanServer mBeanServerMock;

    private final String CLASSNAME = this.getClass().getName();

    @Before
    public void setUp() throws Exception {
        mockStatic(ManagementFactory.class);
        expect( ManagementFactory.getPlatformMBeanServer() ).
                                    andReturn( EasyMock.createMock(MBeanServer.class) );

        replayAll();
        mBeanServerMock = ManagementFactory.getPlatformMBeanServer();
        verifyAll();

    }
}

Mock testing is another useful toolkit in the arsenal of a hardy developer but that is another idea that fell flat on its face.

Habit of reading source code

Reading code can be very enlightening but I have been following this practice only recently.One might come across nuggets that explain a particular code pattern clearly when one reads code.
Twitter has open-sourced its ‘Commons’ library and I came across the Curiously Recurring Generic Pattern and the Self-bounding pattern in it. These two are discussed in ‘Thinking in Java’ by Bruce Eckel. He also gives an exercise at the end of Page 709.

Exercise 34: Create a self-bounded generic type that contains an
abstract method that takes an argument of the generic type parameter and
produces a return value of the generic type parameter. In a non-abstract
method of the class, call the abstract method and return its result. Inherit
from the self-bounded type and test the resulting class

The code for this exercise could be

public abstract class SelfBound< T extends SelfBound<T>>{

    public abstract T get( T t );

    public T getValue( T t){
         return get( t );
    }

public class SubSelfBound extends SelfBound{

    
    public SubSelfBound get(SubSelfBound subSelfBound) {
        return this;
    }

    public static void  main( String[] argv ){

        SubSelfBound subSelfBound = new  SubSelfBound();

        subSelfBound.test();
    }

    private void test() {

        SubSelfBound subSelfBound = new  SubSelfBound();

        subSelfBound =  getValue( subSelfBound );//The sub-class's inherited method is forced
                                                 //to take only the derived type as parameter
                                                 //and not the base type. The parameter varies
                                                 //and matches the derived type( Covariant )
        
        SelfBound selfBound =  getValue( subSelfBound );//It also returns the super type.
                                                        //This is related to the covariant
                                                        //return types according to the book.

    }
}

Even though I might not have the absolutely correct solution here the idea is clear and it is that the Curiously Recurring Generic Pattern and the Self-bounding pattern are similar and the Self-bounding pattern permits a type of covariant argument types.

I used to think only covariant return types are possible in J2SE 5 but there seems to be a way to implement covariant argument types also though the practical applications of this concept could stupify the developers because not many are
used to advanced generics.

I understood all of this by reading the Twitter Commons source code that has used self-bounding types like this.

public interface Unit<U extends Unit<U>>;{

  double multiplier();
}



If one is not used to thinking about Java generics deeply this type of code will be
hard to understand and implement.

JoinPoint Matching Covariant methods

AspectJ JoinPoint matches methods with Covariant return types. The ‘declare warning’ construct seems to be a useful way of testing because the eclipse markers show the match.

Eclipse View

Aspect

declare warning: execution(Collection<? extends Test> *.test( .. )) : "Covariant";


package com.test;

import java.util.Collection;

public class CovariantSub extends CovariantSuper{

	public Collection<Test> test(){
		return null;
	}
	
	@SuppressWarnings("unchecked")
	public Class test1(){
		return null;
	}

}

package com.test;

import java.util.Collection;

public class CovariantSuper {

	public Collection<? extends Test> test(){
		return null;
	}

	public Class<?> test1(){
		return null;
	}

}

Commodity software or expensive tool

We use a scheduler/file transfer tool from a smaller vendor to avoid costs and huge upfront investments. This financial project has very strict SLA’s. Would a more expensive solution help ?

There are many open-source tools that can do the same thing. We used WebSphere portal that works but I have also seen a open-source stack built using open-source WSRP etc. that can be used to build portals.

Actually there is one more fundamental problem. That is the company’s technology culture. If the culture is not conducive to technical software development or testing then good quality or scalability cannot be ensured.

Basically I think that delivering good SLA’s means clusters, performance testing, HA etc.

Not an expensive tool. Even a very expensive tool needs strong testing teams and a test environment that matches the production environment. So when the management does not understand fundamental testing principles we are going to be in trouble.

Recently we faced one of the many problems that are stopping us from delivering our software. The scheduler that we use is from Flux. Due to a browser upgrade issue the web console of this tool would not open in our production servers. Monitoring became harder.

Red tape ensured that this situation could not be overcome easily. Usually tools have facilities to manipulate the runtime through backend code.

WebSphere Portal has XMLAccess. The Flux engines forming a cluster can be accessed using
the following Java code. This code was able to recover a failed Flow chart and saved the day.

I feel that if the people who we are working with are not good, the best and the most expensive tools in the world cannot help us deliver good software.

So in the end it was working code that fixed the problem.

package com.test;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;

import flux.Cluster;
import flux.Engine;
import flux.EngineException;
import flux.EngineInfo;
import flux.Factory;
import flux.FlowChart;
import flux.FlowChartIterator;

public class LookupEngine {

	public static void main( String... argv ) throws IllegalArgumentException, RemoteException, NotBoundException, EngineException{
		assert( null != argv[ 0 ] );
		assert( null != argv[ 1 ] );
		assert( null != argv[ 2 ] );
	    Factory factory = Factory.makeInstance();
	    LookupEngine le = new LookupEngine();
	    le.
	    lookupCluster( factory,
	    		       argv[ 0 ],
	    		       argv[ 1 ],
	    		       argv[ 2 ]);
	}
	
	private void lookupCluster( Factory factory,
			                    String host,
			                    String namespace,
			                    String bindName ) throws IllegalArgumentException,
			                       		       NotBoundException,
                                                               EngineException,
                                                               RemoteException{
		Cluster cluster =
		    factory.lookupCluster( host,
		                           1099,
		                           bindName,
		                           "user",
		                           "password" );
        Engine engines = null;
	for( Object engine : cluster.getEngines() ){
		System.out.println( engine );
                engines = ((EngineInfo)engine).createEngineReference();
	}
        FlowChartIterator iterator = null;
	for( iterator = engines.get() ; iterator.hasNext() ; ){
                          //Get FlowChart name
		System.out.println( (( FlowChart )iterator.next() ).getName());
        }
        
        
        iterator.close();
        //So once we find the name of the FlowChart we can recover it.
        //engines.recover( "/NameSpace/FlowChart" );
                
                 
	}
	
}

Enum value matching using AspectJ

I wrote an Aspect to advise a particular constant-specific method.

What is a constant-specific method ?

The J2SE 5 documentation explains it.

“You can declare the method abstract in the enum type and override it with a concrete method in each constant. Such methods are known as constant-specific methods.”

There is an example here.

The enum is

package com.test.generics;

import java.util.Collection;
import java.util.List;
import java.util.Set;

public enum TestEnum {
    Value1{
        public <T> List<T> getValue(){ return null; }
        public <T> List<T> getSameValue(){ return null; }
   },
   Value2{
        public <T> Set <T>getValue(){ return null; }
        public <T> List<T> getSameValue(){ return null; }
   };

   abstract <T> Collection<T> getValue();

   abstract <T> Collection<T> getSameValue();

	public static void main(String[] args) {
		System.out.println( Value1.getSameValue() );
		System.out.println( Value2.getSameValue() );
	}

}
package com.test;

import java.util.List;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import com.test.generics.TestEnum;

@Aspect()
public class EnumAspect {

              /*
                  Matches a particular method of all enum values
               */             
	@Pointcut(
	"execution(List<T> getValue())" )
	public void testPointcut(){};

	@Before("testPointcut()")
	public void test() {
		System.out.println( "Generics aspect" );
	}

                /*
                  Matches a method of a particular enum values
               */   

	@Pointcut(
	"execution(List<T> getSameValue()) && target(testEnum) && if()")
	public static boolean testPointcut1( TestEnum testEnum ){
		return testEnum == TestEnum.Value2;
	}

	@Before("testPointcut1(testEnum)")
	public void test1( TestEnum testEnum ) {
		System.out.println( "Generics aspect [" + testEnum.ordinal() + "]" );
	}

}

The if() pointcut expression with an empty body is used and the testPointcut1 methods tests for the value of the enum. There does not seem to be a JoinPoint matching pattern to pick out certain enum values automatically. It looks like a pattern would be useful.

Update : Raised an enhancement request.

Follow

Get every new post delivered to your Inbox.