Pages

Saturday, December 11, 2010

Resize an image in Java

Given below is a reusable method in Java for image resizing. I’ll walk you through the code explaining what is done by each code line and will give for better understanding. for this method original image name with path and extension should be fed as an argument. Size of a side of the resized image is also required as an argument for this resizeImage method which returns the state of the image resizing action as a boolean.

public boolean resizeImage(String pathAndNameWithExtention, int sizeOfASideAfterResize){
        int size = sizeOfASideAfterResize;
        String name = pathAndNameWithExtention;
        //format name
        String path = "";
        String nameTxt = "";
        String ext = "";
        if(name!=null){
            //get path
            int tempIndex1 = name.lastIndexOf("\\");
            int tempIndex2 = name.lastIndexOf("/");
            if(tempIndex1==-1 && tempIndex2!=-1){
                path = name.substring(0, tempIndex2);
            }else if(tempIndex1!=-1 && tempIndex2==-1){
                path = name.substring(0, tempIndex1);
            }else if(tempIndex1!=-1 && tempIndex2!=-1){
                if(tempIndex1>tempIndex2){
                    path = name.substring(0, tempIndex1);
                }else{
                    path = name.substring(0, tempIndex2);
                }
            }else{
                System.out.println("ERROR! Path Information is wrong.");
                return false;
            }
            //get name
            int tempIndex3 = name.lastIndexOf(".");
            if(tempIndex3!=-1){
                nameTxt = name.substring(path.length(), tempIndex3);
                ext = name.substring(tempIndex3+1);
            }else{
                System.out.println("ERROR! Image name extension is wrong.");
                return false;
            }
        }
        //read original image
        BufferedImage originalImg;
        try {
            originalImg= ImageIO.read(new File(name));
            //get original image width and height
            int width = originalImg.getWidth(null);
            int height = originalImg.getHeight(null);

            //calculate resized width and height to avoid distortion
            if(width>height){
                height = (int)(((float)height/(float)width)*size);
                width = size;
            }else{
                width= (int)(((float)width/(float)height)*size);
                height= size;
            }
            boolean flag = false;
            //create the resized Image
            BufferedImage resizedImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = resizedImg.getGraphics();
            flag = g.drawImage(originalImg, 0, 0, width, height, Color.WHITE, null);
            //save the image
            File outFile = new File(path+"/"+nameTxt+"_resized."+ext);
            ImageIO.write(resizedImg, ext, outFile);
            return flag;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

Majority of the code lines has been devoted to retrieve the image path, name text and the extension of the image name argument of this method. Then the original image is retrieved using the given parameters to a BufferedImage by using ImageIO.read Please note that this image read needs to be handled within a try-catch as given in above complete code.

BufferedImage originalImg= ImageIO.read(new File(name));

Then a small calculation is performed to get the resized image dimensions, by considering the original image width, height and required size of the resized image to avoid distortion. Code segment that follows this calculation is as follows,

if(width>height){
    height = (int)(((float)height/(float)width)*size);
    width = size;
}else{
     width= (int)(((float)width/(float)height)*size);
     height= size;
}

Then the image is redrawn to the calculated width and height as follows by using the Graphic class of Java. Color given in the drawImage method is the background color of the drawn image.

BufferedImage resizedImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = resizedImg.getGraphics();
flag = g.drawImage(originalImg, 0, 0, width, height, Color.BLACK, null);

Finally the resized image is written back to the read location with a modified file name as “<name>_resized.<extension>” using ImageIO.write method.

The Java packages that need to be imported for this method to work are as follows,

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

To test this method I have created a new class named Test and included the above resizeImage method and the below main method to it.

public static void main(String[] arg){
        Test t = new Test();
        boolean b = t.resizeImage("F:\\testFolder\\TestImage.jpg", 300);
        System.out.println(b);
}

Running this Test class results in creating a new image named TestImage_resized.jpg with max side size of 300px in “F:\testFolder”.

Java Tips

How to Center the JFrame/JDialog in the screen

In the JFrame/JDialog initialize method add the following code lines along with the correct dimensions of your container instead of values 300, 200.

private void initialize() {
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        int x = (dim.width - 300)/2;
        int y = (dim.height - 200)/2;
        this.setLocation(x, y);
        this.setSize(300, 200);
        ……
}

In the first line it gets the Screen Size to a variable named dim. Please note that the example container’s width is 300px and height is 200px. Using these values we can calculate the x, y positions for the container to appear in the center of the screen. Then the calculated x, y values are fed to the component using setLocation method while dimensions of the container is fed using setSize method inside initialize method of the container.

 

How to get the working directory in java

It is a quite simple, yet very useful feature provided by Java.

System.getProperty("user.dir");

This will return the current working directory as a string and comes very handy to define relative paths inside Java programs.

 

How to add an image to a Java container

This can be achieved by adding a new label with the required image’s size, to the container and setting the label’s icon to point the image that is required to be added to the container.

private JPanel getJContentPane() {
        if (jContentPane == null) {
            lbl_Img = new JLabel();
            lbl_Img.setBounds(new Rectangle(101, 9, 164, 16));
            lbl_Img.setIcon(new ImageIcon(System.getProperty("user.dir")+"/icons/edit.png"));
            ……
        }
        ……
}

This code will display  the ‘edit.png’ image in the icons folder of the working directory of the program. Please note that if the image is lager than the label bounds, this will display only the upper left corner of the image to the extent of the defined label bounds. Please refer the “Resize a given image in Java” blog entry to learn how to resize an image in java.

Sunday, October 10, 2010

Java Native Interface

Java Native Interface or JNI is used to define methods in java which will be implemented in C/C++ code. This is very useful to implement some low level functionality which are not supported by Java.
For an example consider that we are creating a java project named “HelloWorldJNI” which has the following structure and location. 
Class Name: HelloWorldJNI
Structure:
HelloWorldJNI
\src
\bin
.settings
.classpath
.project

Package:
test.HelloWorld
Location:
C:\workspace\HelloWorldJNI

Steps in the JNI programming

Step #1: JNI requires the native methods to be declared in java as,
public class HelloWorld{
       public native void displayHelloWorld();
       static{
             System.loadLibrary("HelloWorldDLL");
       }

}
Step #2: compile the class using jdk’s javac compiler as follows,
C:\workspace\HelloWorldJNI>javac.exe src\test\HelloWorld.java
Step #3: Using jdk’s javah.exe create the header file in C/C++ code by invoking following command from the command prompt.
C:\workspace\HelloWorldJNI>javah -jni -o src\test\HelloWorld.h -classpath C:\workspace\HelloWorldJNI\src test.HelloWorldhere “–o” will define the output file name where “–classpath” will define the working path and “test.HelloWorld” will give the input file name.
Step #4: create a Win32 DLL in C/C++ named HelloWorldDLL and copy the DLL file to the C:\workspace\HelloWorldJNI\src location.
Step #5: create a main method in test.TestApp class in java as follows,
public class TestApp{
     public static vois main(String[] arg){
          HelloWorld hd = new HelloWorld();
          hd.displayHelloWorld();
     }
}
Step #6: in the command prompt run the program as
C:\workspace\HelloWorldJNI>java HelloWorldJNI
This entire process is illustrated in the following diagram which was taken from the The JNI Programmer’s Guide. Finally the result will be displayed in the command prompt as “Hello World!” as shown in the below diagram.

A complete JNI learning experience can be gained through going through The Java Native Interface Programmer’s Guide and Specification. Hope this article helped you to do a simple Hello World application correctly which has a packaging structure.


Named Pipes for Inter Process Communication

What is Inter Process Communication (IPC)?

Inter process communication refers to passing of information between processes. These processes can be located either on a single host or on multiple hosts in a network. According to the context in which they operate techniques used for inter process communication should differ to obtain the maximum performance. Given below are some of the popular inter process communication methods.

Different techniques of IPC

Not all operating systems support all IPC techniques. The IPC techniques mentioned below also have different speeds of execution, convenience, reliability levels and security levels. It’s interesting and important to have a good understanding about other alternatives before analyzing one approach of inter process communication in detail. Some of the widely used IPC techniques and the OS support they have are mentioned below,

  • Files:  Supported by all Operating Systems. Very primitive mechanism. Not efficient and highly vulnerable.
  • Message Passing: Used in Java RMI, CORBA, etc. Has lot of limitations.
  • Shared Memory: Supported by all POSIX Systems and Windows Systems. Faster than both Pipes and Sockets.                
  • Sockets: Supported by all Operating Systems. Efficient in server client communication in a network environment.
  • Pipes and Named Pipes: Supported by all POSIX Systems and Windows Systems. Slightly faster than Sockets.

Pipes as an Inter Process Communication Technique

Pipe communication is a effective server/client communication mechanism which enables communication between a server and 1 or more clients. Pipes has 2 forms which has different characteristics. They are,

  1. "Anonymous pipes" (or "Unnamed pipes")
  2. "Named Pipes".

Let’s look at both forms separately. But main focus of this article is to introduce you Named Pipes in detail.

Anonymous Pipes

Anonymous Pipes are used to transfer information between related processes. It should be noted that Anonymous pipes cannot be used to communicate among processes over a network. Unnamed pipes are also unidirectional by nature. Hence to enable bidirectional communication between server and a client, 2 separate pipes need to be created. Normally to satisfy server/client communication between 2 processes, 2 dedicated pipes are created one for reading and one for writing in this scenario. The lifespan of the unnamed pipe is tightly bounds with the lifespan of the process that creates the pipe.

Usage: This is an efficient mechanism to redirect standard inputs or outputs of a child process with its parent process within the same host.

Named Pipes

Named Pipes in the other hand are used to exchange information between related or unrelated processes, within a single host or within multiple hosts over a network. Name of the pipe is assumed to be well known. And any process can access the pipe if it knows the name and has the right privileges. Lifespan of a named pipe is not tightly bound to the lifespan of the process that creates the pipe and hence needed to be explicitly closed at the end of communication. Most important fact about named pipes is that not like anonymous pipes, the same named pipe can act as a server and a client at different occasions. Hence all named pipe peers are equal. 

Named Pipe Example Code

Since pipes behave similar to files, any mechanism used to create or access files can be used for creating or accessing pipes. But we need to keep in mind that the inputs and outputs of a pipe are always byte streams.

There are 4 important methods to implement when using Named pipes for IPC. They are,

  • StartClient
  • ReadPipe
  • WritePipe
  • StopClient

Approach #1 will demonstrate how we can implement a Named Pipe Client which has all these methods and uses 2 separate pipes to establish communication.

public class NamedPipeClient {
    private static InputStream pipeIn;
    private static OutputStream pipeOut;

    public NamedPipeClient() {
           public void StartClient()
    }

    public void StopClient() {
        pipeIn = null;
        pipeOut = null;
    }
    public void StartClient() {
            //initialize the pipe after a small sleep time
            File pipe = new File(“\\\\.\\pipe\\testpipe”);

            try{
                 pipeOut = new FileOutputStream(pipe);
                 pipeIn = new FileInputStream(pipe);
            }catch(FileNotFoundException e){
                 e.printStackTrace();
            }
    }
        public boolean Write(byte[] m_pTxDataBuffer, short totalpktLength) {
        boolean wSuccess = false;
        try {
            pipeOut.write(m_pTxDataBuffer, 0, totalpktLength);
            pipeOut.flush();
            wSuccess = true;
        } catch (NullPointerException e) {
            System.out.println("Exception! Write buffer is null.");
            e.printStackTrace();
        }catch(IndexOutOfBoundsException e){
            System.out.println("Exception! Write length exceeds write buffer size or total packets to write contain a invalid value.");
            e.printStackTrace();
        }catch (IOException e){
            System.out.println("IOException while writing to the pipe.");
            e.printStackTrace();
        }
        return wSuccess;
    }

    public int Read(byte[] pchBuff, int inBufferSize) {
        int byteTransfer = 0;
        byteTransfer = pipeIn.read(pchBuff, 0, inBufferSize);
        } catch (NullPointerException e) {
            System.out.println("Exception! Read buffer is null.");
            e.printStackTrace();
        }catch (IndexOutOfBoundsException e) {
            System.out.println("Exception! Read length exceeds read buffer size.");
            e.printStackTrace();
        }catch (IOException e) {
            System.out.println("IO Exception while reading from the pipe.");
            e.printStackTrace();
        }
        return byteTransfer;
    }
}

Approach #2 will demonstrate how we can implement a simple Named Pipe Client which has all these methods and uses a single bidirectional pipe to establish communication.

public class NamedPipeClient {

    RandomAccessFile rafPipe = null;

    public NamedPipeClient() {
        StartClient();
    }

public void StopClient() {
        try {
            rafPipe.close();
        } catch (IOException e) {
            System.out.println("IOException while closing the pipe streams");
            e.printStackTrace();
        }
        rafPipe = null;
    }

    public void StartClient() {
            //create the pipe
            try {
                rafPipe = new RandomAccessFile( pipeName, "rws");
            } catch (FileNotFoundException e) {
                System.out.println("FileNotFound exception while creating the pipe...");
                e.printStackTrace();
            }
    }
    public boolean write(byte[] m_pTxDataBuffer, short totalpktLength) {
        boolean wSuccess = false;
        try {
            rafPipe.write(m_pTxDataBuffer, 0, totalpktLength);
            wSuccess = true;
        }catch (IOException e){
            System.out.println("IOException while writing to the pipe...");
            e.printStackTrace();
        }
        return wSuccess;
    }

    public int Read(byte[] pchBuff, int inBufferSize) {
        int byteTransfer = 0;
        try {
            byteTransfer = rafPipe.read(pchBuff, 0, inBufferSize);
        }catch (IOException e) {
            System.out.println("IO Exception while reading from the pipe.");
            e.printStackTrace();
        }
        return byteTransfer;
    }
}

Approach #3 will demonstrate how we can improve the Named Pipe Client mentioned in Approach #2 to support non-blocking reads. If explained further, in above example the read function get blocked until at least one byte is read from the pipe. Hence when reading from the pipe is performed continuously from a separate thread, even writes can get blocked when there is nothing to read. For this I have used the length() method available with RandomAccessFile which will provide the pipe data length in a non blocking way. Since StopClient() and StartClient() methods are identical to what is given in Approach #2, I’ll not include them here. In adding to introducing non-blocking read functionality I have introduced locking scheme to prevent deadlocks.

public class NamedPipeClient {

    RandomAccessFile rafPipe = null;
   
static long curLength;
    static boolean writeNotify = false;
    static boolean wrote = false;
    static boolean readNotify = false;

    public boolean write(byte[] m_pTxDataBuffer, short totalpktLength) {
        boolean wSuccess = false;
        if(totalpktLength<0){
            totalpktLength = 0;
        }
        try {
            while(readNotify){}//wait for read to finished
            writeNotify = true;
            rafPipe.write(m_pTxDataBuffer, 0, totalpktLength);
            wrote = true;
        }catch (IOException e){
            System.out.println("IOException while writing to the pipe...");
            e.printStackTrace();
        }finally{
            writeNotify = false;
        }
        return wSuccess;
    }

    public int Read(byte[] pchBuff, int inBufferSize){
        int byteTransfer = -1;
        if(inBufferSize<0){
            inBufferSize = 0;
        }
        try{
            curLength = rafPipe.length();
        }catch(IOException e){
            curLength = -1;
        }
        //handle exceptions
        if(curLength == -1){
            return byteTransfer;
        }
        //handle functionality
        if(!wrote && curLength==0){
            //nothing happened
            return byteTransfer;
        }else if(!wrote && curLength>0){
            //incoming stream. read now
            try{
                while(writeNotify){}//wait for write to finish
                readNotify = true;
                byteTransfer = rafPipe.read(pchBuff, 0, inBufferSize);
            }catch (IOException e) {
                System.out.println("IO Exception while reading from the pipe.");
                e.printStackTrace();
            }finally{
                readNotify = false;
            }
        }else if(wrote && curLength==0){
            //read possible. But not yet available. wait till timeout.
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return byteTransfer;
        }else if(wrote && curLength>0){
            //input stream available. read now
            try{
                while(writeNotify){}//wait for write to finish
                readNotify = true;
                byteTransfer = rafPipe.read(pchBuff, 0, inBufferSize);
            }catch (IOException e) {
                System.out.println("IO Exception while reading from the pipe.");
                e.printStackTrace();
            }finally{
                wrote = false;
                readNotify = false;
            }
        }else{
            //unknown condition
        }
    return byteTransfer;
    }
}

Hope this article helped you to get a better idea on Named Pipes which will help you in your future work..

Friday, July 16, 2010

Internet Backbone and Route Servers

Autonomous Systems (AS) are large networks usually belongs to different Internet Service Providers (ISP). AS’s are connected to each other through Internet Exchange Points (IX or IXP) which reside at virtual edges of Autonomous Systems. BGP routing protocol, handles the communication among these different AS’s creating the backbone of the internet.

Accordingly at an IXP, many ISPs are connected to each other by external BGP peering. Normally these external BGP connections are done by full mesh method. This creates a scaling problem. Route Server mechanism is one heavily adapted method to resolve this problem. Each ISP's BGP router only peers to Route Server. Route Server serves as BGP information exchange to other BGP routers. By applying this method, numbers of BGP connections is can be reduced [1].

Some of the ISP’s allow restricted public access to their route servers using telnet. Most often they allow the remote users to issue commands such as

  • ping
  • traceroute
  • show ip bgp

without login into the router. These are very useful for taking various measurements of latency, packet failure ratios, etc of the internet. For a list of such route severs with public access capabilities are listed below [2].

Hostname

Location

Provider

IP Address to telnet

AS

Peers

Type

route-server.twtelecom.net

Littleton, CO 80124, US

Time Warner Telecom

66.162.47.58

4323

2059

Cisco 7200 12.1(2)T

route-server.eu.gblx.net

Phoenix, AZ 85044, US

Global Crossing - Europe

67.17.81.187

3549

2035

Cisco

route-server.gblx.net

Phoenix, AZ 85044, US

Global Crossing

67.17.81.28

3549

2035

Cisco

route-server.ip.tiscali.net

Cagliari, 14 -, Italy

Tiscali

213.200.64.94

3257

806

Cisco

route-server.gt.ca

Montreal QC H3E 3B3 Canada

GT Group Telecom

216.18.63.214

6539

295

Cisco

route-server-east.gt.ca

Montreal QC H3E 3B3 Canada

GT Group Telecom

216.18.63.214

6539

295

Cisco

route-server-west.gt.ca

Montreal QC H3E 3B3, Canada

GT Group Telecom

66.59.190.81

6539

295

Cisco

route-views.optus.net.au

Sydney, Australia

Optus Australia

203.202.125.6

7474

293

Cisco

route-views.on.bb.telus.com

Burnaby, BC v5h 3z7, Canada

Telus - Eastern Canada

154.11.63.86

852

179

Cisco

route-views.ab.bb.telus.com

Burnaby, BC v5h 3z7, Canada

Telus - Western Canada

154.11.98.18

852

179

Cisco

route-server.east.allstream.com

Toronto, ON m5v 3g2, Canada

Allstream - East

216.191.14.250

15290

146

Cisco

route-server.west.allstream.com

Toronto, ON m5v 3g2, Canada

Allstream - West

209.82.88.118

15290

146

Cisco

route-server.central.allstream.com

Toronto, ON m5v 3g2, Canada

Allstream - Central

216.191.167.134

15290

146

Cisco

public-route-server.is.co.za

Edenvale, South Africa

Internet Solution

196.4.160.227

3741

85

Cisco

route-server.videotron.net

Montreal, QC H3C4M8, Canada

VIDEOTRON LTEE / QMI

216.113.14.121

5769

59

 

route-server.eastlink.ca

Bedford, NS, Canada

Eastlink

24.137.100.8

2610:170:ffff::8

11260

21

Cisco

route-server.belwue.de

Stuttgart, Germany

BelWue

193.196.190.135
129.143.103.78

553

20

Cisco

route-server.cerf.net

Alpharetta, GA 30005, US

CERFnet

12.129.193.235

17233

5

Cisco 7200 12.0(22)S2e

For information on router locations and other information visit here.

Some Important Links to Visit

References

[1] “Route Server” Available at: http://www.zebra.org/zebra/Route-Server.html

[2] “Route Servers”, Available at: http://www.lerfjhax.com/route_servers

Tuesday, May 25, 2010

Create Shortcut Specification for IzPack

In IzPack software, operating system specific shortcut specification must be provided along with the common configuration specification to support the shortcuts. This is caused by the OS specific nature of shortcuts’ operation. In other, words today we will discuss how to write the shortcutSpec.xml that is required to accommodate shortcuts in the Windows environment.
Platform: Windows
File Name: shortcutSpec.xml
The root element of this xml document is <shortcuts>.This xml document has 3 other important sub elements under this tag. they are <skipIfNotSupported/>, <programGroup/> and <defaultCurrentUser/>. <skipIfNotSupported/> allows the panel to be silent on a non-supporting system. <defaultCurrentUser/> allows the “current user” to be the default selection for the panel. If this element is not present, the default selection is “all users”. <programGroup/> allows to specify the name of the menu under which shortcuts to be specified.
<skipIfNotSupported/>
<programGroup defaultName="Jefe" location="applications"/>
After these 3 elements, comes the most important functionality providers of the specification. <shortcut> tags each per shortcut, will provides the OS specific details to the installer to create the shortcuts.
Given below is the code for a shortcut to execute a startup.bat of a Tomcat bundle. This will create a desktop shortcut specified by desktop="yes" attribute and a shortcut in the program group specified by programGroup="yes" attribute, under the name Jefe which is defined in <programGroup> tag. In this shortcut configuration data name of the shortcut appears as Jefe – Startup and the required bat file to execute is located in the path given in the target attribute. While name and target attributes are essential to be specified in a short cut, all other attributes are optional. workingDirectory specify the folder in which the startup.bat is located.  iconFile will specify the location and the name of the icon to use for this shortcut, which will appear in both desktop and the program group. description attribute will give a brief description about the shortcut when it is been requested. initialState=”noShow” will hide command prompt opening when bat files are requested to execute. Since I need to monitor the command prompt information at startup of the Tomcat I used the initialState as “normal”. Even though all the attributes expect name and the target are considered optional, programGroup, desktop, startMenu and startup are considered as semi-optional attributes. There value is either yes or no. Any other value other than these two are interpreted as no. createForPack another important child element of shortcut. It will specify under which pack this shortcut is installed. If this pack is not selected while installation, the respective shortcut is omitted automatically.
<shortcut
        name="Jefe - Startup"
        target="$INSTALL_PATH\core\liferay-portal-5.2.3\tomcat-6.0.18\bin\startup.bat"
        commandLine=""
        workingDirectory="$INSTALL_PATH\core\liferay-portal-5.2.3\tomcat-6.0.18\bin"
        description="Jefe Server Startup"
        iconFile="$INSTALL_PATH\images\startup.ico"
        iconIndex="0"
        initialState="normal"
        programGroup="yes"
        desktop="yes"
        applications="no"
        startMenu="no"
        startup="no">

       <createForPack name="core"/>
</shortcut>
Similarly I have created another shortcut to execute the shutdown.bat in the same folder to shutdown the Tomcat server. I’ll not discuss this since it is just a replacement for the word startup by shutdown. Now let’s take a look on how to create a shortcut to execute the uninstall.jar created by the IzPack installer for the Jefe installer.
<shortcut
        name="Jefe - Uninstaller"
        target="$INSTALL_PATH\uninstaller\uninstall.bat"
        commandLine=""
        workingDirectory="$INSTALL_PATH\uninstaller"
        description="Jefe Server will be completely Uninstalled"
        iconFile="$INSTALL_PATH\images\uninstall.ico"
        iconIndex="0"
        initialState="noShow"
        programGroup="yes"
        desktop="no"
        applications="no"
        startMenu="no"
        startup="no">

       <createForPack name="core"/>
</shortcut>
The difference in this shortcut to the one discussed earlier is that we are using a a bat file given below to execute the jar file and has configured following 2 attributes differently to how they were configured previously. initialState=”noShow” and desktop=”no”. The bat file I’m using for this operation is as given bellow,
@Echo Uninstalling…
java –jar uninstall.jar
@Echo Successfully Uninstalled
The full description of the different attributes are given in the IzPack manual under Desktop Shortcuts section. The same shortcuts created for the Unix base system in also given as an example in the IzPack manual under the sub section A simple shortcut specification for Unix under the Section Desktop Shortcuts.

Thursday, May 6, 2010

Installing Ant and Maven

Installing Ant

Installing Ant is very very simple. Following are the steps for that,
Step 1: Download the latest ant binary from http://ant.apache.org/bindownload.cgi
Step 2: Extract it to folder in your machine. In my case C:\ant
Step 3: Set the following environmental variables in your machine
  • JAVA_HOME : path/to/your/jdk (eg: C:\Java)
  • ANT_HOME : path to folder where you extracted your ant copy (eg: C:\ant\apache-ant-1.8.0)
  • PATH : %PATH%;%ANT_HOME%\bin
Step 4: To check whether the installation was successful, in command prompt type “ant” if it displays “build failed” then ant installation is successfully installed to your machine. But if it says it can not identify the command ant then there is a problem in the installation.

Installing Maven 2

Installing Maven is so simple, and is very much similar to the ant installation process. Given below is the maven installation process,
Step 1: Download the latest maven binary from http://maven.apache.org/download.html
Step 2: Extract it to folder in your machine. In my case C:\maven
Step 3: Set the following environmental variables in your machine
  • JAVA_HOME : path/to/your/jdk (eg: C:\Java)
  • M2_HOME : path to folder where you extracted your maven copy (eg: C:\maven\apache-maven-2.2.1)
  • Set the following user variables in your machine (just above the environmental variables). M2 : %M2_HOME%\bin
  • PATH : %PATH%;%JAVA_HOME%\bin;%M2%
Step 4: To check whether the installation was successful, in command prompt type “mvn --version” if it displays the version information then the maven installation is successfully installed in your machine. But if it says it can not identify the command mvn then there is a problem in the installation.

Monday, May 3, 2010

Write an installer with IzPack

Features and Drawbacks of Using IzPack

Because of the following reasons I chose IzPack to create the installer for my application, from all other free and open source installer software. The reasons which helped me to make my decision are as follows,
  • IzPack is Open Source
  • It has attractive GUI
  • Great Customizability
  • It is a Cross-Platform Installer
  • Automatic Uninstaller Creation
The drawback of using IzPack is, it doesn’t contain enough documentation or working examples for a beginner to use it and get the job done easily.
Because of this reason I thought of discussing and guiding you on how to use IzPack to create an Installer today in this blog.

How IzPack Installer Operates

All what we have to do to make the installer is write an xml file stating all the necessary configuration information and compile it using the compiler provided by the IzPack. Then according to our xml, an installer file named install.jar will be created by the IzPack. It will wrap all the files and folder structure from the end user. Then a separate application should be used to convert this jar file to a windows executable or a Mac application. For this example I’m using a software named Launch4j for this purpose.
Download and Install IzPack latest version from: http://izpack.org/
Download and Install Launch4j latest version from: http://launch4j.sourceforge.net/

Creating an install.xml file

This xml file has a root element as “installation” which has an attribute named “version”. i.e. all other tags of the xml file should be placed somewhere inside the main tag of <installation version=”1.0></installation>
The first configuration data to appear inside these installation tag is the data of information section.
<info>
        <appname>Jefe</appname>
        <appversion>1.0</appversion>
        <authors>
            <author name="Ms. K.M.L. Sureshika" email=""/>
            <author name="Ms. A.P. Pathirage" email=""/>
            <author name="Ms. S.P. Mendis" email=""/>
            <author name="Mr. S. Nirathan" email=""/>
        </authors>
        <javaversion>1.5</javaversion>
        <requiresjdk>no</requiresjdk>
        <url>
http://www.jefe-sdwms.com/</url>
        <uninstaller name="uninstall.jar" path="${INSTALL_PATH}/uninstaller" write="yes"/>
        <summarylogfilepath>$INSTALL_PATH/InstallationSummary.htm</summarylogfilepath>
        <writeinstallationinformation>no</writeinstallationinformation>
</info>

Information in the appname, appversion,authors and url tags will be used to display on the HelloPanel. javaversion will be used to specify the minimum java version required for your application to work. requirejdk has the values yes and no which will enforce the user to install a java jdk of minimum java version specified or above. uninstaller tag will allow you to specify the location where the uninstaller should be created and its name. summarylogfilepath will be used to store a html file of installation summary after successful installation. writeinstallainformation has values yes or no. If yes is given it gives the user the ability to generate an installation script for further installations.
The next section in my install.xml is “guiprefs”. It will allow me to change the appearance of the ultimate installer of my application.
<guiprefs width="600" height="480" resizable="no">
        <modifier key="layoutAnchor" value="CENTER"/>
        <modifier key="useHeadingPanel" value="yes"/>
        <modifier key="useHeadingForSummary" value="yes"/>
        <modifier key="headingImageOnLeft" value="yes"/>
        <modifier key="headingLineCount" value="2"/>
        <modifier key="headingFontSize" value="1.5"/>
        <modifier key="headingBackgroundColor" value="0x00ffffff"/>
        <modifier key="headingPanelCounter" value="text"/>
        <modifier key="headingPanelCounterPos" value="inHeading"/>
</guiprefs>

Here I’m specifying the width and the height of the gui and restricting it from resizing which will be problematic since I’m using two images in the installer. I’m also placing a layout anchor for the gui and instructing it that I’m using a header panel and heading image on the left.
According to the IzPack manual, you can specify various new variables other than the default variables as $INSTALL_PATH and $JAVA_HOME. In my code I have used the following variable to use in the shortcut panel.
<variables>
        <variable name="DesktopShortcutCheckboxEnabled" value="true"/>
</variables>

We can also specify many languages for the installer to operates. For my installer I only specified English. Because there aren’t any choice the initial panel for language selection is not appearing in my installer. All the language codes needed for configuring this option is given in the IzPack manual clearly
<locale>
    <langpack iso3="eng"/>
</locale>

Next comes an important section in the install.xml. Resources tag will contain information and location of all the additional files in the installation other than the install.xml itself.
<resources>
        <res id="shortcutSpec.xml" src="shortcutSpec.xml"/>
        <res id="HTMLInfoPanel.readme" src="Readme.html"/>
        <res id="HTMLLicencePanel.licence" src="Licence.html"/>
        <res id="Heading.image" src="images/heading-image.png"/>
       <res id="Installer.image" src="images/side-image.png"/>
</resources>

In here, shortcutSpec.xml file, Readme.html file and Licence.html file are located on the root of the installation folder. But header image and side image are located inside a folder named images which is located on the root. Likewise you can specify any resource used for the installation process, located anywhere with respect to the installation folder. For all the resources you also need to give a unique id which can be used later for identifying the resource. And remember to include all the files you have mentioned under resources with exact names and locations unless you need half a dozen compilation errors.
Panel section will be used to specify the different panels you need to show in your installation and their order of appearance. All different panels are given in the manual. These are what I’m using for my installation in the order they required to appear.
<panels>
        <panel classname="HelloPanel"/>
        <panel classname="HTMLInfoPanel" id="readme"/>
        <panel classname="HTMLLicencePanel" id="licence"/>
        <panel classname="TargetPanel"/>
        <panel classname="TreePacksPanel"/>
        <panel classname="SummaryPanel"/>
        <panel classname="InstallPanel"/>
        <panel classname="ShortcutPanel"/>
        <panel classname="FinishPanel"/>
</panels>

For your information I’ll include GUIs of the above panels in the above order.










Then next most important section of our install.xml is the packs section, which define what need to be installed, to where and how. This implements the core of the installation process. Since the code of the packs section of my installer is so lengthy I will include the code of one pack only.
<packs>
        <pack name="core" required="yes">
            <description>This will include the necessary processing of Liferay framework and other core files used in the jefe solution.</description>
            <file src="Readme.html" targetdir="$INSTALL_PATH"/>
            <file src="Licence.html" targetdir="$INSTALL_PATH"/>
            <fileset dir="images" targetdir="$INSTALL_PATH\images">
                <include name="**"/>
            </fileset>
            <file src="liferay-portal-tomcat-6.0-5.2.3.zip" targetdir="$INSTALL_PATH\core" unpack="true"/>
            <executable targetfile="$INSTALL_PATH/liferay-portal-5.2.3/tomcat-6.0.18/bin/startup.bat" stage="never" />
            <executable targetfile="$INSTALL_PATH/liferay-portal-5.2.3/tomcat-6.0.18/bin/shutdown.bat" stage="never" />   
    </pack>
    …
    …
</packs>

Installation process is divided into many parts according to packs. As you can see in the 5th image since pack give in the above code is set as “required=yes” user does not get the opportunity to select or deselect it according to his requirements. Hence this is a good option to include all the required and essential features of the application under this pack. So I have used this pack named core to copy the Readme file, Licence file and images folder to the root of the installation location and i have also unzipped the zip file named “liferay-portal-tomcat-6.0-5.2.3.zip” to the folder “core” in the root. After unzipping I’m specifying 2 runnable bat file locations in it which I need to run later. But here I’m asking the installer not to run these files by specifying the stage as never. The other alternatives to the stage are postinstall and uninstall which will be called soon after installation and at the time of uninstalling respectively. Description will appear when you click on a pack.
You can also list packs that appears inside some other packs as in image 5. For this, you can code your packs as follows.
<pack name="stack" required="no" preselect="yes">
            <description>This is custom portlet stack provided by the jefe solution.</description>
</pack>

            <pack name="Document Repository" required="no" parent="stack">
                  <description>This will include all the document repository plugins to the core.</description>
            </pack>

Parent pack needs not contain any special tags for this functionality to implement. But the child pack need to have an attribute named parent with the name of its parent pack as the value. When compared to previous pack code this code has some more changes. I have stated the attribute “required=no” giving the user the flexibility to choice and added a new attribute “preselect=yes” to persuade the user to install this pack too.
I  have also used an listener for windows users, to catch the summary log of the installer. The code for the following segment represent the inclusion of the above listener.
<listeners>
      <listener installer="SummaryLoggerInstallerListener">
          <os family="windows"/>
      </listener>
</listeners>

Native packs are also required to include in your installation xml file to implement the installer functionality. The code for the above native pack is included below.
<native type="izpack" name="ShellLink.dll"/>
<native type="izpack" name="ShellLink_x64.dll"/>
<native type="3rdparty" name="COIOSHelper.dll" stage="both">
    <os family="windows"/>
</native>

The code of the completed install.xml file is attached here: install.xml
The code of the completed shortcutSpec.xml file is attached here: shortcutSpec.xml
 

Creating an install.jar out of install.xml

install.xml file alone will not lead you to any where. So let’s make a cross-platform install.jar file that will build your actual installer. For this,

  1. Create a new folder and include all the resource files to it in the exact location mentioned in the resources tag.

  2. Now save the install.xml file the root of the same folder.

  3. Go to the IzPack installation folder and then to IzPack bin using command prompt with Administration privileges and type the following command
    E:\IzPack\bin>compile E:\jefeInst\install.xml -b E:\jefeInst
This will compile your install.xml file to a install.jar file. For this command after the key word “compile” you are required to give the path of the install.xml file then –b and then the path to which the install.jar file need to be saved.
After creating the install.jar file, you can once again navigate to the location where you saved it in the command prompt and execute the following command to launch your installer as how you launch any other .jar file.
E:\jefeInst>java -jar install.jar

Creating install.exe out of install.jar

Start the Launch4j and create an new project in it.
  1. In the Basic tab input the output file name and location where you need your executable file to be saved in “*Output file”.
  2. In the Basic tab again under “*Jar” browse and give the install.jar file you just created using IzPack.
  3. In the Basic tab you can also give a custom icon for the executable installer you are going to create.
  4. In the JRE tab under “Min JRE Version” include the minimum JRE version needed for your application to work.
  5. Now save the file and build the wrapper from the menu.
You are now having a complete single file windows executable for your application!

How to configure a SVN repository

Platform: Windows 7 (64bit) OS
SVN Client: TortoiseSVN
These few steps will guide you on how to install your own basic SVN repository on a windows machine using the client, TortoiseSVN.

Step 1:

Go to TortoiseSVN download page at http://tortoisesvn.net/ and download the latest version of the application. In my case it was TortoiseSVN-1.8.4.24972-x64-svn-1.8.5.msi

Step 2:

Double click the installer and follow the wizard to set up the TortoiseSVN client application. This application can be installed to any location in the machine. For this example I’ll install it to E:\svn At the end of installation process restart will be requested. After rebooting the machine go for the Step 3.

Step 3:

Now go to the location where you installed the application (i.e. E:\svn) and create a new folder named ‘repository’.

Step 4:

Right click on this new folder and choose ‘TortoiseSVN’ –> ‘Create repository here’. Now your SVN repository is successfully created.

Step 5:

To upload your first set of files to the repository, in my case first folder with some documentation right click on the desktop and select ‘TortoiseSVN’ –> ‘Repo-browser’.
Then give the path to the newly created repository as file://path/to/the/repository
This is a view of your SVN repository created at the given location. Now right click on the middle and select Add folder as below and browse the folder you need to upload to the repository and then proceed with ok.
Now you can see your first set of files in the repository successfully.

Step 6:

For any further uploads to the repository you can proceed with right clicking the folder you need to upload and select ‘TortoiseSVN’ –> ‘Import’ and to download a working copy from the SVN, you can proceed by creating a new folder and then right clicking to select ‘SVN checkout…’. After modifying a checked out copy you can commit it back to the repository by right clicking and selecting ‘commit…’.

Step 7:

Until now there aren’t any users created to restrict the access to the repository. You can manually set the users by editing the ‘passwd’ file at following location ‘E:\svn\repository\conf\’ (w.r.t. this installation example).
When this file is opened in a text editor you can see the following lines.
[users]
# harry = harryssecret
# sally = sallyssecret
According to this, a user can be created as ‘harry’ with the login password as ‘harryssecret’ by un-commenting the line by removing the ‘#’ sign in the beginning of it and saving the file. Likewise any number of users can be created to use the repository.

Tuesday, April 27, 2010

Create a Batch file to Archive or Extract using WinRAR

This will be a short article on how to program a simple batch file that will archive or extract files and folders using WinRAR software. This can be also used as command line syntax to do the same thing.

For this to work your WinRAR installation (default location: C:\Program Files\WinRAR) should have rar.exe and unrar.exe files which are installed by default when installing WinRAR software.

For this Example my document structure is as follows,
\core
abc.rar

Given bellow is the example code for extracting a rar file named abc into the folder called core. Commands marked in bold will actually perform the operation.

  • First we must set the path to rar.exe or unrar.exe which we are going to use. In this case its unrar.exe
    set path="C:\Program Files\WinRAR\";%path%
  • Then we must give the path into which your rar file should be extracted.
    cd /d C:\WinRAR_Test\core 
  • Then we must give the location of the rar file to be extracted.
    unrar x ../abc.rar
    In here if we use the command as 'unrar e' all the files in all the folders of the rar file will be extraced to the folder mentioned in the step 2. But if we use the command as 'unrar x' we will be able to preserve the folder structure while extracting.
Given below is the completed batch program which need to be saved in a text file and renamed as somename.bat and double clicked to execute.

@echo off
@echo Extracting the file..
set path="C:\Program Files\WinRAR\";%path%
cd /d $INSTALL_PATH\core
unrar x ../abc.rar
@echo all files extracted
Hope you enjoyed this piece of code as much as I do!
Reference: http://www.respower.com/page_tutorial_unrar

Thursday, March 25, 2010

Installing and configuring Hudson CI

Hudson
Hudson is a very user friendly Continuous Integration Server Software that can be used to monitor any type of project and inform you the status in many different ways. Hudson being an open source software, has an active community and has frequent releases when compared to many other open source projects with added features. It has a huge plug-in base that provides the capability to Hudson CI to be integrated to many other relevant applications.

Installing Hudson

To install Hudson you only need a Servlet/JSP container like Tomcat installed. The Servlet Container needs not to be limited only to Tomcat. But for this tutorial I’m going to use Apache Tomcat.
Tomcat bundle can be downloaded from http://tomcat.apache.org/download-60.cgi


After installing Tomcat you can download Hudson from http://hudson-ci.org/ as a single war file and can be deployed to Tomcat by a single click.

Configuring Hudson for use

Once you go to the Hudson Dashboard all the configurations can be done from ‘Manage Hudson’ link as follows,
figure :1
Once you are inside the ‘Manage Hudson’ link, you can see a screen as follows whether you must go to the ‘Configure System’ link to do the actual configuration.
figure :2
Essential Configuration Settings
Before building any java application we have to do 2 key configurations in ‘Configure System’ link. Those are to provide the JDK path and a build tool path. For this example we are using Ant as the build tool. Both JDK (downloadable from: http://java.sun.com/javase/downloads/widget/jdk6.jsp) and the Ant (downloadable from: http://ant.apache.org/bindownload.cgi) should be installed and tested before doing this step for easy isolation of faults at latter time.
figure :3
Create Users
Hudson doesn’t require users or user groups to be defined before using it to build jobs. But it is always better to define privileges to avoid unnecessary meddling from anonymous users.

To define users first check the ‘Enable Security’ option and select “Hudson’s own user database” and check ‘Allow users to sign up’ option. In the Authorization sub heading, select ‘Matrix base security’ where you can provide privileges to users. I have created ‘Guest’ user for demonstration purposes. Guest was marked with an error symbol because we have not created the Guest user yet, even though we set the privileges to the Guest user. Make sure you give at least one user all the administration privileges which can be used later to setup other configurations. After creating few users, save the settings from the ‘save’ button provided at the end of the page. This will redirect you to a login page.
figure :4
From the login page go to the link named, ‘Create an account’ to create a Guest account as follows,
figure :5
Create a java job
Go to ‘New Job’ tab to create a new job. Then enter a name and select ‘Build a free-style software project’ and click ‘Ok’.
figure :6
Then a job called ‘Test’ is created and the user is directed to job’s configuration page. In here we have to specify the Source Code Management tool path that we are using for this particular project and some additional features like which Build tool to use and the command to archive the artifacts.

As the source code management tool, I’m using Subversion. So I selected ‘Subversion’ under the SCM heading and gave the repository URL to my Test job, which is the repository URL for my project named ‘Welcome’.

Since ‘Welcome’ is a java web application, under the Build heading I selected Invoke Ant because I want Ant to build my java project. After selecting Invoke Ant from the drop down menu, specify the ‘Ant version’ from ‘Default’ to the Ant setup name, you created in the initial system configuration.

In ‘Post-Build Action’ we can program the CI Server to do many other operations other than building the project. Here I have checked ‘Archive the Artifacts’, which will save a working executable file along with the build. For this option it is required to correctly specify which file to be archived.

In ‘Post-Build Action’ it is also possible to set email notifications after every build. This option I have not shown here because I have not configured Email settings in system configuration.
figure :7
Building a .NET project in Hudson
Before creating a job to build a .NET project there is a small system configuration to be done in ‘Configure System’ page. In this page now choose the ‘Manage Plug-ins’ link. After going to that page in the ‘Available’ tag under the heading ‘Build Tools’ check MSBuild option and click ‘Install’ button in the bottom right corner of the same page. After that through internet the plug-in will be downloaded and installed automatically. Once the plug-in is installed, Hudson CI is needed to be restarted.

figure :8
Once the server is restarted, in the ‘Configure System’ page there is a new heading named, ‘MSBuild Builder’. In this, we have to provide the path to MSBuild installation in your machine which is an inbuilt tool shipped with Visual Studio setup and can be usually found in location C:\Windows\Microsoft.NET\framework\version.
figure :9
After performing this we can now create a job to monitor and build a .NET project as same as any java project job as follows,

figure :10
But now in the ‘Build’ heading we have to select ‘Build a Visual Studio project or solution using MSBuild’ option from the drop down instead of ‘Invoke Ant’. For the ‘MSBuild version’ we need to specify the Installation name we provided in the system configuration. And the build file is a file in your .NET project usually having the extension as .sln As the Command Line Arguments you can input the following line or an argument relevant to your project. Other two settings are as the same as for any java job. Now your .NET project job is ready for building. 
figure :11
Integrate Hudson with Jira
For this I used ‘Marvelution’ plug-in which can be used and downloaded for free. The steps in integrating this plug-in clearly explained in its home page http://www.marvelution.com/atlassian/jira-hudson-integration/integration/installation.html