Monday, November 9, 2009

Riding the swing

Only because of Sun Developer exam I had to consider swing coding. Much to my disappointment though according to the assignment text use of any third party libraries was prohibited resulting no possible use of a WYSIWYG tool like NetBeans. I resorted to learning the fundamentals and going through the APIs. By the looks of the assignment I thought the implementation of the functionality that was limited to edit and read was going to be easy. Once I actually started working on that, however, I realized the complexities in JFC APIs. For instance, to create a basic Frame with Menu I do not have a handy utility class and method. For getting a parent frame from a MenuItem I do not have a straight forward one line method call. For each one of such instance, I had to write several lines of code. My toughest challenge - or should I say that the worst nightmare - was the laying out of the GUI components on  the frame using the Layout Manager. Anyhow, finally, I am able to create a few utility methods/class myself that I would be briefing on.
1. Acting on a JTable based on event on a MenuItem:
a> Register an event listener to the menu item.
b> Implement actionPerformed contract to take whatever action on the table you want.
c> Now, to obtain the table mentioned in the above point write method or a class. The way I have been doing this is writing an utility class that will take care of such concerns.

      /**
         * This method obtains the Parent Frame window of the Menu Item.

 * @param menuItem where the action was taken
* @return JFrame  parent frame
      **/


public JFrame getMainFrame(JMenuItem menuItem) {
JPopupMenu popupMenu = (JPopupMenu) menuItem.getParent();
JMenu menu = (JMenu) popupMenu.getInvoker();
JComponent component = (JComponent) menu;
JFrame frame = (JFrame) component.getTopLevelAncestor();
return frame;
}

        /**
           * Make use of the Reflection APIs and recursion to grab the wanted component from the frame
           * @param container - Container like JPanel, JScrollPane.
           *               className - Class name of the component to be obtained - javax.swing.JTable, etc
           * @return JComponent Object of the class mentioned inside the container passed.


public static JComponent getComponent(Container container, String className) throws ClassNotFoundException{
if (container != null){
Class cl = Class.forName(className);
Component[] components = container.getComponents();
for (int i = 0; i < components.length; ++i){
Component c = components[i];
if (c.getClass().getName().equals(className)){
component = (JComponent)c;
}else if (c instanceof Container){
getComponent((Container)c, className);
}
}
}
return component;
}

Now what if you need a set of several similar components? For example, grab me a list of all the text fields present inside a container.
Use the similar recursive approach with a little modification. Instead of calling this method directly, call an intercepting method. This will, after resetting the instance Collection field, in turn, call the aforementioned method that may be considered to be of private scope. Hence it would go something like this:



public List getComponents(Container container, String className) throws ClassNotFoundException{
componentList = new ArrayList(); //Reset\initialize the Collection
return getComponentList(container, className); //Call the method that internally calls itself
}


private List getComponentList(Container container, String className) throws ClassNotFoundException{
if (container != null){
Class cl = Class.forName(className);
Component[] components = container.getComponents();
for (int i = 0; i < components.length; ++i){
Component c = components[i];
if (c.getClass().getName().equals(className)){
component = (JComponent)c;
componentList.add(component);
}else if (c instanceof Container){
isRecursiveCall = true;
getComponents((Container)c, className);
}
}
}
return componentList;
}

Method to obtain the root panel (JDialog or JFrame):
public Container getMainFrame(JButton button){ Container container = button.getParent(); while(true){ System.out.println(container); if (container instanceof JFrame){ return (JFrame)container; }else if (container instanceof JDialog){ return (JDialog)container; } else{ container = container.getParent(); System.out.println("Container: " + container); } } }


Sunday, August 16, 2009

Marathon Mania

This was probably be my last MM. Like the last time, preparation was almost the same - not up to the mark. I should have gone for 35ks practice session a couple of more times and must have around 80-85k per week in the peak training periods and not just 65-70k. However, unlike the last time, I had a better race strategy and worse pair of shoes. Did not miss even a single drink station this time. Right from the beginning, gulped a glass of Getorade and 1 water. Did take some cadbury snakes this time with me. About 16 k and I could feel the thumps straight on my left foot not to mention the hurting ankle. I had the tapes in my two little fingers of my left toe to prevent them from friction and blistering that I generally encountered in my long training runs. Got Gu gel at around 17k that boosted me immediately.
At around 19k got hold of someone running at my pace and had a good chat with her for another 3k and then lost contact. At around 22-23 got 2 snakes out of my pocket and chewed them and got another boost. Drink stations helped me going easily until 30. Then applied the remaining snakes and thought this time I am gonna beat 4 hrs mark. It was St Kilda road (back) and I was quite surprised by my "strong" speed, while I was thinking how come this can end so quickly. No, it wouldn't as we took a turn towards the Kings way and up the hill towards the botanical garden - The most painful moment. I took notice of the ks left - and it was 6 MORE TO GO!! To hell with this.. and I started walking - my toe fingers were already giving me excruciating pain. When 5 left - started jogging again (after passing a drink station) and thought its just about 25 minutes of slow jog and I will be home. But, the last 5k of marathon is equivalent to first 15. During the last 2k, I had to literally drag myself to finish. After 40 I had to stop again and walk for around 5-600 meters continuously. At last could beat the last time only by 15 minutes. - 4:16:xx :( not good enough.
http://www.marathon-photos.com/scripts/event_entry.py?event=Sports/2009/Melbourne%20Marathon;match=3352

Tuesday, June 30, 2009

Java tool for Web Service load testing

Scenarios where real-time communication with a web service-end user is imminent, it is imperative to test the service for its ability to take up the load. This may have the following benefits:

1. More scalable and robust service design: If a service's threshold limit of fulfilling the simultaneous requests is, say n, that may respond to the end user(s) in a reasonable amount of time, any extra user will be timed-out/errored out by the service. This problem can be alleviated, if not fully eliminated, by increasing the server's resources and hence reserving extra memory/processes to serve those "extra" users.
2. Business benefits: Any such load testing will ensure a seamless integration between the systems in the context for a set number of "extra" loads on the service. As it is true with most of the successful integration solution, this will make the concerned business process more effecient and smooth leading to increased revenue. This can be explained by an example:
If a CRM application, which is being operated by an end user GUI application, is trying to use back-end web service for submissions/queries, multiple users can hit the "Submit" button simultaneuously. All of the users, must get the response within a reasonable wating time for this integration to be successful.

Technical Details:
Following is the brief summary of what this tool does technically:
1. Reads a property file to get the information like: host, end-point, authentication information, request file(s) location, response file(s) location, log file(s) location, etc.
2. Creates n number of threads (Based on the number of request files). Initialize each one of them with the details mentioned in the above point. Also, as each thread reads exactly one request file, wrap it up with SOAP message.
3. Once the threads are initialized as mentioned above, each of them is run at one go.
4. Each thread will then tries to contact the host and push the HTTP requests at the same time.

The details follow:
I have used the following special Java APIs to build the said tool:
- Java 5 multithreading API: to make sure that once all the client threads are created, they (try) to hit the service at one go. this utilises the CountDownLatch object.
- Java Networking API: to connect any of the threads with the remote server and communicate with the service end-point. At first, I tried using the SOAP API but failed as some of the HTTP messages being returned by the server was not in the SOAP format but in the HTML format.

Main highlights of the classes used: Following are the lists of the custom classes and some (not all) of their properties and methods.

  • Main Class:
GenericWSClientThreadExecutor: Has main method to prepare the worker threads for their tasks.

Attributes:
- java.util.Properties props //Reading propery file and extracting the configuration information.
- int threads //Number of threads or requests to be sent at a time.

Methods:
- init() //Initialize the config parameters from the file.
- execute() //Create threads and start them. Also contact a logger to log the performances.

  • Thread Class:
GenericWSClientThread implements Runnable: Represents one worker.

Attributes:
//Keep track of the number of threads created and those that have finished the job.
- CountDownLatch startLatch, endLatch
- HTTPClient client //An object that will make the actual communication with the server.

Methods:
- parseResponse(String response) //Parses the response to look for the HTTP status.
- createResponseFile(String fileName) //To create the correspondiong thread's response file.
- run() // Implementation of Runnable.run. This reads the request, initialise HTTPClient object and communicates with end-point using the other properties set for this thread.
//Handle the exceptions and HTTP status code appropriately.

  • Communicator Class:
HTTPClient: To communicate with server.

Attributes:
- int connectionTimeout //Timeout while contacting host.
- int readTimeout //Timeout while reading response from stream sent by the host.

Methods:
- encode(String source) //To encode authentication information string into Base64 Encoding.
- String invokeWS(String SOAPURL, byte[] payloadRequest, String SOAPAction, String user, String passCode) //Prepare HTTPConnection, set request headers and body and send to host.
//Also throws appropriate exception to the worker thread.

  • Other Utility Classes:
1. PerformanceTestRecorder - Once all the threads are finished, open a file stream and record the performance of each thread along-with their IDs and names.
2. ThreadRecord - A bean that may represent one thread record in the aforementioned performance record file.
3. PropertyReader - To read simple or XML property file.
4. WSUtil - To convert String to SOAPMessage, SOAPMessage object to string, etc.
5. Exception classes - Meaningful exceptions like, RetryException, MovedPermanentlyException, etc can be formed based on the HTTP response code.

Improvements needed:
1. Problem handling the status code 301: The client loses authentication information while it is being re-directed to specific URL by the internal implementation of HTTPURLConnection. This eventually results in HTTP error code 401 Unauthorized. I tried to get to the level of Socket API to formulate requests and response, but the performance became worse and the connection was getting timed out every 30 seconds. On top of this, because it is not the part of the IOException when using sockets, the client would never know what is happening to its specific request, even if it tries multiple times. It is possible that the request is being proessed in the background while the client keeps sending the request again and again.

Welcome to my blogs

The contents here are my independent point of view. They reflect my thoughts, experience in my professional and social life.

Search This Blog