Saturday, April 23, 2011

Dissection of Java Process

Dissection of Java Process


Every process occupies OS resources and each process has a unique process identifiers. Operating system is  responsible for managing and allocating process ids. To access the list of process currently manage by the OS is varying from one OS to other.
List of process currently running on windows operating system can be obtain by executing tasklist.exe command.

If we want only those processes which is running under JVM then we have to filter the output generated by tasklist.exe out as follow
Tasklist.exe /M java*                                                           

When we run the JConsole.exe (A Utility program which is available in JDK), a Connection dialog of JConsole will list all (process which is accessible to the logged in user) java processes running on current JVM (there is provision to connect remote JVM and obtain the list of process running on remote machine by passing appropriate credentials).




Similarly we can obtain the same list of process by running JPS.exe utility available in JDK.


 On Linux operating system the list of process can be obtain by executing ps commands.



Java provides standard way to access process relate information irrespective to the underlying OS using java.lang.management package.
The ManagementFactory class is a factory class for getting managed beans for the Java platform. This class consists of static methods each of which returns one or more platform MXBean(s) representing the management interface of a component of the Java virtual machine.

Retrieve Process & JVM related information associated with current process.


ManagementFactory factory provides a static method ManagementFactory.getRuntimeMXBean()  to obtain the runtime beans. Process id required to analyze the memory footprint with the help of JConsole.exe.

Code Snippet 1:

Partial code snippet to generate the Process Tab
protected JComponent makeProcessPanel() throws UnsupportedLookAndFeelException
    {

        JPanel panel = new JPanel(false);
        panel.setLayout(new GridLayout(0, 1, 0, 0));

RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();

        String[] name = runtimeMXBean.getName().split("@");
        JLabel label_1 = new JLabel("Process Id : " + name[0]);
        label_1.setHorizontalAlignment(SwingConstants.CENTER);
        label_1.setFont(new Font("Segoe UI", Font.BOLD, 14));
        panel.add(label_1);

        JLabel label_2 = new JLabel("Process Running on : " + name[1]);
        label_2.setHorizontalAlignment(SwingConstants.CENTER);
        label_2.setFont(new Font("Segoe UI", Font.BOLD, 14));
        panel.add(label_2);

        JLabel label = new JLabel("VM Name : " + runtimeMXBean.getVmName());
        label.setHorizontalAlignment(SwingConstants.CENTER);
        label.setFont(new Font("Segoe UI", Font.BOLD, 14));
        panel.add(label);

JLabel label_3 = new JLabel("VM Version : " + runtimeMXBean.getVmVersion());
        label_3.setHorizontalAlignment(SwingConstants.CENTER);
        label_3.setFont(new Font("Segoe UI", Font.BOLD, 14));
        panel.add(label_3);

JLabel label_4 = new JLabel("VM Vendor : " + runtimeMXBean.getVmVendor());
        label_4.setHorizontalAlignment(SwingConstants.CENTER);
        label_4.setFont(new Font("Segoe UI", Font.BOLD, 14));
        panel.add(label_4);

        return panel;
    }

Retrieve Operating System related information associated with current process.


ManagementFactory factory provides a static method ManagementFactory.getOperatingSystemMXBean() by which we obtain the platform specific manage beans. The name of operating system, Architectural details of the processor, Number of processor etc. cab be obtain using operating system bean.
Example:
1)      Display OS details on about dialog.
2)      Application needs auto configuration as per the type of the operating system and number of processor and type of processor architecture etc.

Code Snippet 2:

Partial code snippet to generate the OS Tab
protected JComponent makeOSPanel()
    {
        JPanel panel = new JPanel(false);
        panel.setLayout(new GridLayout(4, 1));

 OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();

JLabel lnlOsName = new JLabel("Operating System :" + operatingSystemMXBean.getName());
        lnlOsName.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lnlOsName.setHorizontalAlignment(SwingConstants.CENTER);
        panel.add(lnlOsName);
        JLabel lblArch = new JLabel("Architecture : " + operatingSystemMXBean.getArch());
        lblArch.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblArch.setHorizontalAlignment(SwingConstants.CENTER);
        panel.add(lblArch);
        JLabel lblProcessor = new JLabel("Number of Processor :" + operatingSystemMXBean.getAvailableProcessors());
        lblProcessor.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblProcessor.setHorizontalAlignment(SwingConstants.CENTER);
        panel.add(lblProcessor);

        return panel;
    }

Retrieve Heap memory status associated with current process.


Each process requires memory to execute the task. When new object is created a memory is allocated to the object. Once the object out of scope and no more references to the heap object then garbage collector free the memory allocated to the object. ManagementFactory factory provides a static method ManagementFactory.getMemoryMXBean to obtain the MemoryMXBean by which we can access the Heap and Non Heap memory usage.



Code Snippet 3:

Partial code snippet to generate the Memory Tab
private JComponent makeMemoryPanel()
    {
        JPanel panel = new JPanel(false);
        panel.setLayout(new GridLayout(0, 2));
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
      
        JLabel lblHeapMemory = new JLabel("Heap Memory Usage  " );
        lblHeapMemory.setBackground(new Color(255, 255, 255));
        lblHeapMemory.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblHeapMemory.setHorizontalAlignment(SwingConstants.CENTER);
        panel.add(lblHeapMemory);
      
        JPanel heappanel = new JPanel();
        heappanel.setLayout(new GridLayout(0, 1, 0, 0));
  
        memoryUsage(heappanel, memoryMXBean.getHeapMemoryUsage());
        panel.add(heappanel);
       
        panel.add(new JLabel(""));
        panel.add(new JLabel(""));
       
        JLabel lblNonHeapMemory = new JLabel("Non Heap Memory Usage  " );
        lblNonHeapMemory.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblNonHeapMemory.setHorizontalAlignment(SwingConstants.CENTER);
        panel.add(lblNonHeapMemory);
       
        JPanel nonheapPanel = new JPanel();
        nonheapPanel.setLayout(new GridLayout(0, 1, 0, 0));
        memoryUsage(nonheapPanel, memoryMXBean.getNonHeapMemoryUsage());
       
        panel.add(nonheapPanel);
        return panel;
    }

private void memoryUsage(JPanel panel, MemoryUsage heapMemoryUsage)
    {
     
        JLabel lblinit = new JLabel("Init : " +heapMemoryUsage.getInit());
        lblinit.setBackground(new Color(255, 255, 255));
        lblinit.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblinit.setHorizontalAlignment(SwingConstants.LEFT);
        panel.add(lblinit);
       
        JLabel lblUsed = new JLabel("Used : " +heapMemoryUsage.getUsed());
        lblUsed.setBackground(new Color(255, 255, 255));
        lblUsed.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblUsed.setHorizontalAlignment(SwingConstants.LEFT);
        panel.add(lblUsed);                                  
       
JLabel lblCommited = new JLabel("Committed : " + heapMemoryUsage.getCommitted());
        lblCommited.setBackground(new Color(255, 255, 255));
        lblCommited.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblCommited.setHorizontalAlignment(SwingConstants.LEFT);
        panel.add(lblCommited);
       
        JLabel lblMax = new JLabel("Committed : " +heapMemoryUsage.getMax());
        lblMax.setBackground(new Color(255, 255, 255));
        lblMax.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblMax.setHorizontalAlignment(SwingConstants.LEFT);
        panel.add(lblMax);
    }

Retrieve Thread information associated with current process.

Java provides Software Level threading. . ManagementFactory factory provides a static method ManagementFactory.getThreadMXBean() to obtain the ThreadMXBean by which we can access the thread related information like number of thread currently running, Current Thread CPU Time and Current Thread User Time etc.

Code Snippet 4:

Partial code snippet to generate the Thread Tab
private JComponent makeThreadPanel()
    {

        JPanel panel = new JPanel(false);
        panel.setLayout(new GridLayout(4, 1));
         ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        JLabel lblThreadCount = new JLabel("Thread Count:" + threadMXBean.getThreadCount());
        lblThreadCount.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblThreadCount.setHorizontalAlignment(SwingConstants.CENTER);
        panel.add(lblThreadCount);
      
        JLabel lblCurrentThreadCpuTime = new JLabel("Current Thread CPU Time:" + threadMXBean.getCurrentThreadCpuTime()+"");
        lblCurrentThreadCpuTime.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblCurrentThreadCpuTime.setHorizontalAlignment(SwingConstants.CENTER);
        panel.add(lblCurrentThreadCpuTime);

JLabel lblCurrentThreadUserTime = new JLabel("Current Thread User Time:" + threadMXBean.getCurrentThreadUserTime()+"");
lblCurrentThreadUserTime.setFont(new Font("Segoe UI", Font.BOLD, 14));
        lblCurrentThreadUserTime.setHorizontalAlignment(SwingConstants.CENTER);
        panel.add(lblCurrentThreadUserTime);
       
        return panel;
   
    }


Click here to download complete source code.


Monday, April 18, 2011

Annotation, A journey Novice to Ninja


                                                                                                                             

Annotation, A journey Novice to Ninja

Annotation

Annotation is similar to interface which marked with @ symbol. Annotation extends the semantic of the normal class, variables and methods declaration.   Annotations are metadata which provides additional information for the class, instance and class fields/variable and methods.
Now days, majority of framework builds based on Annotation to simplify the coding part as well as configuration part required specific to the framework. If basic concept of Object Orient is good then, it is very easy to switch from any other technology and programming language which is based on Object Oriented principle. Each object oriented language differs in terms of syntax but concept remains the same. Similarly, if we know the basic concept of annotation then learning any framework based on annotation is very easy. We have to learn the purpose of annotation provided by the underlying framework and its applicability nothing else.
Let’s begin with simple annotation used by java to discourage the use of any method and class which is deprecated/obsolete in new release. Best example of discourage the use of class; method, fields can be annotated using @Deprecated annotation.
Code snippet 1       

This code demonstrates the use of Deprecated annotation. Deprecated annotation discourages the use of deprecated /obsolete methods in code.  Compiler generates the appropriate warnings to avoid use of deprecated methods, fields and classes.
/**
 * DemoAnnotaion.java
 * Created on Apr 16, 2011
 */

package com.novice.annotation;

/**
 * @author Ashish.Chudasama
 * @deprecated This is deprecated class. Check NinjaAnnotation class for more details.
 */
@Deprecated
public class DemoAnnotaion
{
    @Deprecated
    int id ;
   
    public void findById(Integer id)
    {
    }
    /**
     *  @deprecated This is deprecated method. Use findById(Integer id).
     */
    @Deprecated
    public void findById(Object id)
    {
    }
}

If you observer carefully @deprecated and @Deprecated annotation used in above code one for documentation purpose whereas second one is to provide intelligence to the compiler to generate the appropriate warnings during compilation time .

Custom annotations

Declaration of custom annotation:


Declare Remark annotation by which developer can put appropriate remarks for each of the program elements.
Code snippet 2

package com.novice.annotation;

public @interface Remark
{
    public String author();
    public String shortDescription();
    public String reviewBy() default "";
}

Key points:
1)      @interface indicates that Remark is custom annotation and not an interface.
2)      If you forget to write @ before the interface keyword then its interface not an annotation.
3)      Default value can be assign within property/method declaration. Default value for the reviewBy() is empty string.
4)      Only primitive type, String, Class, annotation, enumeration are permitted or 1-dimensional arrays are permitted as a Return type.
5)      By default retention policy of a custom annotation is class. (explain later)
Code snippet 3

This code snippet describes how to use the @Remark annotation                          
package com.ninja.annotationhelper;

import com.novice.annotation.Remark;

// Apply at class level
@Remark(author="Ashish", reviewBy="TL", shortDescription="Remark for class.")
public class HelperTemplate
{     
// Apply at variable level
    @Remark(author="Ashish", reviewBy="TL", shortDescription="Remark for variable.")
    int variable;
   
//apply at method level
    @Remark(author="Ashish" ,reviewBy="TL",shortDescription="This method builds Select statements from the from Clause.")
    public String selectQuery( String fromClause){ return null;}
}

Remark annotation applies for every class elements (variable, methods, constructor etc...) but this is not the applicable for all types of annotation.
There are specific annotations which can only be used in the context of annotations. These annotations are target, retention, documented and inherited.

Target Annotation


Target annotation helps to specify the applicability of the annotation on program elements. If a Target meta-annotation is not present on an annotation type declaration, the declared type may be used on any program element. If such a meta-annotation is present, the compiler will enforce the specified usage restriction.
@Target(ElementType[])
ElementType
TYPE
Class, interface, or enum (not annotation)
FIELD
Member field
METHOD
Class methods
PARAMETER
Parameters to the method
CONSTRUCTOR
Constructor
LOCAL_VARIABLE
Instance variable of the class
ANNOTATION_TYPE
Annotation types
PACKAGE
Java package

Retention Annotation


Retention annotation describes where and how long annotation is available.
@Retention(RetentionPolicy)
RetentionPolicy
SOURCE
Annotation available only for source code. Java compiler discards the annotation during the compilation time.
CLASS
Annotation available on .class file. Java class loader discards the annotation during the class loading time.
RUNTIME
Annotation available during the runtime.

Documentation annotation          

This annotation used to include the annotation related information in to the Java doc.
@Documented

Inherited annotation         


This annotation used to inherit the annotation thought the hierarchy. If annotation is not marked as @inherited then annotation applied for the super class does not inherit by the derived class.
@Inherited
Code snippet 4

Example
Define Query Type
package com.novice.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Query
{
    public String type() default "";
}

Create abstract SQL query class
package com.novice.examples;

import com.novice.annotation.Query;

@Query(type="SQL")
public abstract class SQLQuery
{
}


Implement abstract SQL query class into SQL Template
package com.novice.examples;
public class SQLTemplate extends SQLQuery
{
}

Test stub to demonstrate the purpose of @inherited annotation

public class TestInheritedAnnotation
{

    public static void main(String[] args)
    {
        Class<?> clz = SQLTemplate.class;
        Annotation[] annotations = clz.getAnnotations();
        for (Annotation annotation : annotations)
        {
            System.out.println(annotation);
        }
    }

}

Output
@com.novice.annotation.Query(type=SQL)

If you remove the @Inherited from the Query annotation then output is as follow
NO output … because annotation is not inherited on sub class. Query annotation is only available on abstract SQLQuery class.

           

This is all about to the Annotation… now it’s time to become ninja in Annotation.

Dissection of ORM


Now a days hibernate and other framework builds based on annotations, let’s try to understand how ORM tool works (explaining completely is out of scope of this blog but try to simulate the annotation based SQL statement generation)
Framework annotations
@Table
Describe the database table
Optional tablename property .if table name is not specify the class name consider as the table name
@Column
Describe the table column ,If columnname property is not specify then field  name consider as the column name
@PrimaryKey
Specify the primary key of the table

Code snippet 5

This class represents the User table.
/**
 * User.java
 * Created on Apr 16, 2011
 */
package com.novice.examples;


import com.novice.annotation.Column;
import com.novice.annotation.PrimaryKey;
import com.novice.annotation.Table;

/**
 * @author Ashish.Chudasama
 */
@Table
public class User
{

    @PrimaryKey(keyName = "user_id")
    String userId;

    @Column(columnName = "first_name")
    String firstName;

    @Column
    String lastName;

    @Column
    String dob;

    public void setUserId(String userId)
    {
        this.userId = userId;
    }

}

Code snippet 6
// import statements are remove from the code snippet
package com.novice.annotation;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table
{
    public String getTableName() default "";
}
Code snippet 7
// import statements are remove from the code snippet

package com.novice.annotation;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column
{
   public String columnName() default "";
}

Code snippet 8
// import statements are remove from the code snippet
package com.novice.annotation;


@Target({ElementType.FIELD,ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PrimaryKey
{
  public  String keyName();
}


Code snippet 9

This class generates the SQL statements by reading annotation from the requested pojo.

package com.ninja.annotationhelper;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

import com.novice.annotation.Column;
import com.novice.annotation.PrimaryKey;
import com.novice.annotation.Table;

public class ORMHelperTemplate
// I have avoided delegation of responsibility for the sake of example
    public String findAll(Class<?> clz) throws Exception
    {
        // First retrieve the from clause i.e. TableName
        Table annotation = clz.getAnnotation(Table.class);
        StringBuilder strSQLQuery = new StringBuilder();
        strSQLQuery.append("SELECT ");
        if (annotation != null)
        {
            // Retrieve all column name
            strSQLQuery.append(buildSelectColumn(clz.getDeclaredFields()));
            strSQLQuery.append(" From ");
            if (!annotation.getTableName().equals(""))
            {
                strSQLQuery.append(annotation.getTableName());
            }
            else
            {
                strSQLQuery.append(clz.getSimpleName());
            }

        }
        else
        {
            // invalid pojo class
throw new Exception("Invalid pojo class <missing @table Annotation>");
        }

        return strSQLQuery.toString();
    }
  

    private String buildSelectColumn(Field[] declaredFields) throws Exception
    {

        StringBuilder selectClause = new StringBuilder();
        for (Field field : declaredFields)
        {
            Annotation[] annotations = field.getAnnotations();
            for (Annotation annotation : annotations)
            {
                if (annotation instanceof Column)
                {
                    Column col = (Column) annotation;
                    if (!col.columnName().equals(""))
                    {
                        selectClause.append(col.columnName()).append(" , ");
                    }
                    else
                    {
                        selectClause.append(field.getName()).append(" , ");
                    }
                    break;
                }
                else if (annotation instanceof PrimaryKey)
                {
                    PrimaryKey pk = (PrimaryKey) annotation;
                    if (!pk.keyName().equals(""))
                    {
                        selectClause.append(pk.keyName()).append(" , ");
                    }
                    else
                    {
                        selectClause.append(field.getName()).append(" , ");
                    }
                    break;
                }
            }

        }
        if (selectClause.length() > 0)
        {
            return selectClause.substring(0, selectClause.lastIndexOf(" , ")).toString();
        }
        else
        {
throw new Exception("No Column to select < @PrimaryKey and/or @Column  annotation missing>");
        }
    }
// this method prepare SQL which retrieve records using PK.
    // for simplicity only string type is implemented as id
    public String findById(Object id) throws Exception
    {
        // First retrieve the from clause i.e. TableName
        Class<?> clz = id.getClass();
        Table annotation = clz.getAnnotation(Table.class);
        StringBuilder strSQLQuery = new StringBuilder();
        strSQLQuery.append("SELECT ");
        if (annotation != null)
        {
            // Retrieve all column name
            Field[] declaredFields = clz.getDeclaredFields();
            strSQLQuery.append(buildSelectColumn(declaredFields));
            strSQLQuery.append(" From ");
            if (!annotation.getTableName().equals(""))
            {
                strSQLQuery.append(annotation.getTableName());
            }
            else
            {
                strSQLQuery.append(clz.getSimpleName());
            }

strSQLQuery.append("  WHERE   ").append(buildWhereClause(declaredFields, id));
        }
        else
        {
            // invalid pojo class
throw new Exception("Invalid pojo class <missing @table Annotation>");
        }

        return strSQLQuery.toString();
    }

  // String special handling is not implemented
private String buildWhereClause(Field[] declaredFields, Object obj) throws Exception
    {
        StringBuilder selectClause = new StringBuilder();
        for (Field field : declaredFields)
        {
            Annotation[] annotations = field.getAnnotations();
            for (Annotation annotation : annotations)
            {
                if (annotation instanceof PrimaryKey)
                {
                    PrimaryKey pk = (PrimaryKey) annotation;
                    if (pk != null)
                    {
                        // actually we can used getter or setter
                        // for sake of demo i have used field access
                        boolean isAccessible = field.isAccessible();
                        field.setAccessible(true);
                        if (!pk.keyName().equals(""))
                        {
                            selectClause.append(pk.keyName()).append(" = ");

                        }
                        else
                        {
                            selectClause.append(field.getName()).append(" = ");
                        }

                        Object object = field.get(obj);
                        field.setAccessible(isAccessible);

                        if (object != null)
                        {
                            selectClause.append("'").append(object).append("' and ");
                        }
                        else
                        {
                            throw new Exception("PK Can't be null");
                        }

                    }
                    break;
                }
            }

        }
        if (selectClause.length() > 0)
        {
            return selectClause.substring(0, selectClause.lastIndexOf(" and ")).toString();
        }
        else
        {
throw new Exception("No Column to select < @PrimaryKey and/or @Column  annotation missing>");
        }
    }
}


Code snippet 10

Test the Custom ORM annotations

/**
 * TestORMHelper.java
 * Created on Apr 17, 2011
 */

package com.novice.examples;

import com.ninja.annotationhelper.ORMHelperTemplate;

/**
 * @author Ashish.Chudasama
 */
public class TestORMHelper
{

    public static void main(String[] args) throws Exception
    {
        ORMHelperTemplate template = new ORMHelperTemplate();
        System.out.println(template.findAll(User.class));
       
        User user=new User();
        user.setUserId("Ashis.Chudasama");
        System.out.println(template.findById(user));
    }

}

Output:

SELECT user_id , first_name , lastName , dob From User

SELECT user_id , first_name , lastName , dob From User Where user_id = 'Ashis.Chudasama'


I have just shown the power of annotation to build ORM tool. This is just the demo not the real ORM tool code snippets. In real life ORM tool uses may design pattern to process the user request as well as query parser parse the query and validate the query before generating database specific query.