Monday, April 21, 2014

Using Logback logging framework in Eclipse - Simple example/tutorial

Logback is a logging architecture that is very popular and customizable. It is intended as a successor of log4j. Long story short, use logback instead of log4j for your new projects. (The author is the same for both log4j and logback frameworks. Look at the links at the end of the tutorial if you are interested in finding out the history, which framework is better etc.).

In this tutorial, we will learn on how to setup logback in a Java project, how to create appenders and how to write the logs to a specific location. This tutorial uses RSA (Rational Software Architect), but you can use Eclipse or any other IDE of your choice.

Go to File -> New -> Web -> Dynamic Web Project


 Give it a name and add the project to an EAR using the Wizard screen as shown below. (If you are not using Websphere, you can use any other server or any other Project wizard of your choice)


Click Next, Next and click Finish (you can check the ‘Generate web.xml deployment descriptor’ if you want to)

A new Web project is created by now with the above steps.

To run logback in your project, we need a façade for the logback framework. We use slf4 as the façade in this example.

JAR files needed (Use one of the three methods mentioned below to get the jar files)

We need to have the following jar files in your Project’s build path
  1. slf4j-api.jar
  2. logback-classic.jar
  3. logback-core.jar


 Method 1: If you have Ivy setup, you can add the following dependencies (Refer to http://runningexample.blogspot.com/2014/02/Using-Ivy-for-dependency-management.html on how to setup Ivy. I STRONGLY RECOMMEND SETTING UP IVY ONCE AND FOR ALL) 

<dependency org="org.slf4j" name="slf4j-api" rev="1.7.5"  />
<dependency org="ch.qos.logback" name="logback-classic" rev="1.0.13" transitive="false"/>
<dependency org="ch.qos.logback" name="logback-core" rev="1.0.13" transitive="false"/>
 Method 2: If you have Maven setup, you can add the following dependencies (Refer to http://runningexample.blogspot.com/2011/01/apache-maven-tutorial-basic-setup.html on how to setup Maven)

<properties>
 <slf4j.version>1.7.5</slf4j.version>
 <logback.version>1.0.13</logback.version>
</properties>

<dependencies>

 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>${slf4j.version}</version>
 </dependency>

 <dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>${logback.version}</version>
 </dependency>

 <dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-core</artifactId>
  <version>${logback.version}</version>
 </dependency>

</dependencies>
 Method 3: Download the jars manually from:
      http://www.slf4j.org/download.html  (this is for slf4j-api.jar)
      http://logback.qos.ch/download.html (this is for the two logback jars logback-classic and logback-core)

     Now that the jar files are in the classpath, let’s write a simple servlet that says “Hello World”. 

       Using File -> New -> Servlet, create a new Servlet and name it LogbackTestServlet




    Add the following imports to the created Servlet.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

      Create a new Logger object using the following line of code at the beginning of the class
private static final Logger logger = 
LoggerFactory.getLogger(LogbackTestServlet.class);

     Add the following code to the doGet method in the Servlet
logger.debug("Inside the doGet method");
String message = "Hello World";
// Set response content type
response.setContentType("text/html");

logger.debug("Before writing the output");
// Actual logic goes here.
PrintWriter out = response.getWriter();
out.println("<h1>" + message + "</h1>");

    The Servlet class should look something like this




    We created the code to write the log statements.
    Now comes the part where we need to create the logback configuration file (where the log levels, log location etc. are specified)

     For logback to run, the ONLY file we need to have is logback.xml, that we need to place is on the classpath (In this example, we will create a new file called logback.xml at the src level of the Project Structure in the Web Project).

    Create a new file using File -> New -> File and name it logback.xml. See the below picture to see where the file is created in the Package Explorer




     Copy paste the following code into that file.  (SNIPPET 1)
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>LogbackTutorial.log</file>
    <append>true</append>
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>
 
 <root level="debug">
  <appender-ref ref="FILE" />
 </root>
</configuration>

    I will explain the logback configuration file entries now.

    First, the debug=’true’ in line number 2 of this file will help to find out what logback is doing (whether it is starting fine or not etc. on to the console or System.out log ). Always use this flag and it will save you a lot of time.
   We create something called an ‘Appender’ to write the log statements. Think of Appenders like handles that do that logging tasks. You create one or more Appenders and those will perform the logging based on the properties you set on them.
    In the code above, we created an Appender, named it to ‘FILE’ (we named it FILE as we are writing the logs to a File and not to the Console).  We asked the Appender to create a logfile named ‘LogbackTutorial.log’.  To specify the Pattern of the log statement, (for example: 15:15:24.273 [WebContainer : 0] DEBUG LogbackTestServlet - Inside the doGet method), we use the <pattern> tag inside the <encoder> tags.

   After the Appender is created, we set the loglevel to ‘debug’ and associate the appender.

  Now, run the Servlet by going to the URL
   http://localhost:9080/LogbackTutorial/LogbackTestServlet (change the host name/ports as needed)

   Go to the default log file location (Websphere/AppServer/Profiles/AppSrv01) or your server’s default log location and there you will find the LogbackTutorial.log created. It will have the following entries:
15:15:24.273 [WebContainer : 0] DEBUG LogbackTestServlet - Inside the doGet method
15:15:24.276 [WebContainer : 0] DEBUG LogbackTestServlet - Before writing the output

    That’s it !! Logback is up and logging your log statements. 


  BONUS:
  For writing logs to a specific location based on a Websphere name space binding. (SNIPPET 2):


  SKIP THIS SNIPPET IF YOU WANT THE DEFAULT LOG LOCATION.

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
 <insertFromJNDI env-entry-name="cell/persistent/LOGFOLDER" as="logFolder"/> 
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">

  <if condition='property("logFolder").contains("log")'>
   <then>
    <file>${logFolder}/Tutorials/LogbackTutorial.log</file>
   </then>
   <else>
    <file>LogbackTutorial.log</file> 
   </else>
  </if>
    <append>true</append>
    <encoder>
      <pattern>>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>
 
 <root level="debug">
  <appender-ref ref="FILE" />
 </root>
</configuration>
   The <insertFromJNDI> tag is useful if you want to write to the log file to a particular location dynamically without changing the code and redeploying. For this to happen, in Websphere, you need to create a name space binding called LOGFOLDER and set it to any folder that you want to write the logs to. In my case, on Websphere Admin console, I went to ‘Name Space bindings’ and created a binding called ‘LOGFOLDER’ and set the String value to /dev/waslogs. If you run the Servlet, the logs will be written to the location that you wanted it to. In the future, if you wanted to write the logs to a different location, without changing the application code, just change value of the name space binding and restart the server. The application should write the logs to the new file location.


   Other useful links/reads:

   http://logback.qos.ch/reasonsToSwitch.html

 Please leave your comments if you find this article helpful !




Friday, February 14, 2014

Using Ivy for dependency management - IvyDE on Eclipse Tutorial

In this running example, you will understand what Ivy dependency management is and how to use it in Eclipse (I am using Rational RSA IDE in this example which is built on the top of eclipse) using the IvyDE plugin.

In one of my previous posts, I explained a few concepts about Maven (http://runningexample.blogspot.com/2011/01/apache-maven-tutorial-basic-setup.html ). Maven has the capacity to do dependency management along with a host of other things. However, if your requirement is JUST TO MANAGE JAVA JAR DEPENDENCIES (and not worry about project/shared code management, build.xml configuration, continuous integration etc. ), Ivy might be the tool for you.

Example scenario: You are building a simple project and you need some classes from a shared Apache jar (commons or codec or whatever). To use the jar file in your project, you can manually download the jar file from a server/internet. However, if you need a different version of that jar later or if you need many jars later in the project  it makes sense to set up a system where all you need to is declare the jar files you need and that system/mechanism downloads the jars (the exact versions that you need) from a server/internet.

The key concepts in Ivy:

1.  Ivy settings file: This is where you specify the repository paths from where the jar files that you need will be downloaded. We manually create this file JUST ONCE and save it in a folder. You can have only one settings file for all your projects across your organization.
Explanation: Repository paths are the places where the jar files are stored in a particular structure according to the versions. These repositories can be the ones that are maintained by open source/commerical project servers(Apache/JBoss etc.) or the ones that are hosted by your organization.

2.  Ivy.xml:  This is the back bone of this mechanism. This class has the jar file declarations that you need in your project. This is also called the Ivy configuration file.  Each project will have it’s own ivy.xml file. We can manually create this file or we can have the IvyDE plugin generate this file for us. 

In this post, we let the plugin generate the file for us. A few sample lines from a sample file

 <dependencies>
 <dependency org="commons-validator" name="commons-validator" rev="1.3.1" transitive="false" />
                </dependencies>



In this example, to use Ivy in Eclipse, we use the IvyDE plugin.
To setup IvyDE, go to Help à Install New Software



Click on Add. Enter the following
Name: IvyDE
Click OK.


IvyDE will install as a plugin for Eclipse. You might need to restart your workspace for this to take effect.
After that, go to Window à Preferences à Ivy -à Settings



Here you can point the Ivy Settings path to your custom settings file. (A sample settings file below. You can create the below sample files and save them to your file location and point the path here),

Sample ivysettings.xml.
<ivysettings>
 <settings defaultResolver="default"/>
 <include url="ivysettings-public.xml"/>
 <include url="ivysettings-shared.xml"/>
 <include url="ivysettings-local.xml"/>
 <include url="ivysettings-main-chain.xml"/>
 <include url="ivysettings-default-chain.xml"/>
</ivysettings>
This settings file can have the pointers to multiple settings files.

Please note: In the above settings file, you can delete the entries that you don’t have. Such separation of entries will help manage local jars/ shared jars in your organization on a shared drive, jars on the internet respositories etc. If you plan to download the jars from the public respositories on the internet, you can retain just the ivysettings-public.xml entry and delete the remaining lines. Create a new file like the one shown below.
Sample ivysettings-public.xml
<?xml version="1.0" encoding="UTF-8"?>
<ivysettings>
    <resolvers>
        <chain name="public">
            
            <ibiblio name="ibiblio" m2compatible="true"/>
                                                <ibiblio name="JbossCommunityRepository" root="http://repository.jboss.org/nexus/content/groups/public/" m2compatible="true"/>
                                
        </chain>
    </resolvers>
</ivysettings>
Note: Keep both the files in the same folder.

Create a new Dynamic Web Project (or any other project as per your preference).


Right click on the Web Project, Select New à Ivy file (You may have to click on Show All Wizards checkbox at the bottom if you don’t see this option)



Enter your application specific details:




This creates the ivy.xml file for your project.

<?xml version="1.0" encoding="ISO-8859-1"?>
<ivy-module version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
    <info
        organisation="com.test"
        module="Tutorial"
        status="integration">
                </info>
</ivy-module>

Let us create a sample class. Right click on the Web Project à New à Class


In this class, we do a simple validation to check if an email string is of a valid format. We use Apache’s GenericValidator class that is inside the commons-validator jar.
package com.test;
public class Sample {

                public void emailValidation()
                {
                                String email = "test@test.com";

                                if(! GenericValidator.isEmail(email))
                                {
                                                System.out.println("Not a valid email");
                                }
                               
                }
}

To resolve the Apache’s GenericValidator class,add the following lines to the ivy.xml file manually:
<dependencies>
  <dependency org="commons-validator" name="commons-validator" rev="1.3.1" transitive="false" />
</dependencies>

Save the file.

After that in any view (Package Explorer/Navigator etc.), right click on the ivy.xml file and select Add Ivy Library. This step will do the magic and download the jar file from the repository that we specified in the ivy settings file (ivysettings-public.xml to be more specific)

If you look the Package explore view (or other views), you will see that the jar file is downloaded and kept under the ivy.xml java library.


Configure the build path in this step if you are still getting Compilation errors. If not, ignore this step. Right click on the Web Project à Build Path à Add Libraries à IvyDE Managed Dependencies


Now go to the class Sample.java and press Ctrl+Space at the compilation error. This will bring up the list of suggested classes, one of which is the desired Apache’s class

That’s pretty much it. Now, just keep adding as many entries in the ivy.xml file as you need when you need any jar file.

Note: The transitive=”false” at the end of the entry in the ivy.xml file is used to prevent downloading all the dependent jars for any specific jar. If you need ALL the dependent jars downloaded, remove the transitive=”false”. But, my suggestion is use it by default and remove when necessary.

BONUS:
After you are done testing and when you export the EAR file, you might want the jars that were resolved by Ivy bundled in your EAR. To do this, right click on the Web project à Properties à Deployment Assembly



Click on Add à Java Build Path Entries


Click on Next and select ivy.xml




Click Finish.

All the Ivy jars will now become a part of WEB-INF/lib when you export the EAR file.




Thursday, September 29, 2011

Create Stacked Bar Charts in Java using JFreeChart

In this running example, I will show you how to create a Stacked Bar chart using just Java (JFreeChart API).

A stacked bar chart is one of those bar graphs where the parts are compared to the whole.




In this particular example, we will create a Stacked bar chart of some fictional read/write times on X-axis and some Timestamps on the Y axis. I will explain the important parts of the code during this process.

If you are using Eclipse(or Rational Software Architect as shown in the screenshots), you can create a simple project in your workspace(existing or new workspace) very fast.

Go to File -> New -> Java Project


Choose the default setting and click on Finish. The project gets created in the workspace.

Go to Package Explorer (if you can't see this, go to Window -> Show View -> Package Explorer to enable it) and right click on src folder and do New -> Package. Name the package 'test'


This will create a package with the name 'test'.

Now, right click on the test package, do New -> Class and give it the name 'StackedBarChartDemo'


Now, we have to add the jar files that are needed by the program to draw the charts. You can download the JFreeChart jar files from the link http://www.jfree.org/jfreechart/download.html
After you download the zip file containing the jar files, copy the two jar files jcommon.jar and jfreechart.jar (whatever version you download at your point of time) to a particular folder like C:\supportingJars.
In Eclipse, in Package Explorer view, right click on the project StackedBarChartExample -> Build Path -> Configure Build Path. In the window that pops up, select the Libraries tab, click on Add External JARs button and select the two jar files in the above folder.



Now, we have the necessary Jar files needed. So, lets put in some code.

Similar to creating a new Java class(StackedBarChartDemo.java), create three new classes - WITHOUT the main method. Name them RowKey.java, ColumnKey.java, ChartObject.java.


Your project should like something like this:



Copy the following code to RowKey.java
package test;

public class RowKey implements Comparable<String> {
 private String operation;

 public RowKey(String oper)
 {
  this.operation = oper;
 }
 public int compareTo(String arg0) {
  return operation.compareTo(arg0);
 }
 
 @Override
 public String toString()
 {
  return this.operation;
 }
}



Copy the following code to ColumnKey.java
package test;

public class ColumnKey implements Comparable<String> {
 private String time;
 public ColumnKey(String time)
 {
  this.time = time;
 }

 public int compareTo(String o) {
  return time.compareTo(o);
 }
 
 @Override
 public String toString()
 {
  return this.time;
 }
}
Copy the following code to ChartObject.java
package test;

public class ChartObject {

 private double readTime;
 private double writeTime;
 private String timeDetails;
 
 public ChartObject(double r, double w, String t)
 {
  this.readTime = r;
  this.writeTime = w;
  this.timeDetails = t;
 }
 public double getReadTime() {
  return readTime;
 }

 public void setReadTime(double readTime) {
  this.readTime = readTime;
 }

 public double getWriteTime() {
  return writeTime;
 }

 public void setWriteTime(double writeTime) {
  this.writeTime = writeTime;
 }

 public String getTimeDetails() {
  return timeDetails;
 }

 public void setTimeDetails(String timeDetails) {
  this.timeDetails = timeDetails;
 }
}
Here is the big picture:
We create RowKey class objects that represent the bars on the graph (read and write values in this particular example). These RowKey values will show up as the legend on the X-axis. ColumnKey objects represent the values on Y axis (timestamps in this case).

Copy the following code to StackedBarChartDemo.java
package test;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

public class StackedBarChartDemo extends ApplicationFrame {

 private static final long serialVersionUID = -7166735925893038359L;

 public static void main(final String[] args) {
  // Call the Constructor with the title of the Chart
  final StackedBarChartDemo demo = new StackedBarChartDemo(
    "Read-Write times Chart");
  // The window is drawn and shown to the User using the below 3 
  //lines.
  demo.pack();
  RefineryUtilities.centerFrameOnScreen(demo);
  demo.setVisible(true);
 }

 /**
  * This constructor creates some dummy ChartObjects first with 
  * some sample read time, write time and timestamps Then it 
  * invokes createDataset method to get a CategoryDataset 
  * object. Then it invokes the createChart method that uses 
  * the above dataset. Later, the dimensions of the window drawn
  * etc. are set
  * 
  * @param title
  */
 public StackedBarChartDemo(String title) {
  super(title);

  try {
   // Create sample ChartObjects with read time, write time 
   //and TimeStamp as constructor parameters
   ChartObject chartObject1 = new ChartObject(0.123, 0.123,
     "TimeStamp1");
   ChartObject chartObject2 = new ChartObject(0.234, 0.234,
     "TimeStamp2");
   ChartObject chartObject3 = new ChartObject(0.345, 0.345,
     "TimeStamp3");
   ChartObject chartObject4 = new ChartObject(0.456, 0.456,
     "TimeStamp4");
   List<ChartObject> chartObjectList = 
    new ArrayList<ChartObject>();
   chartObjectList.add(chartObject1);
   chartObjectList.add(chartObject2);
   chartObjectList.add(chartObject3);
   chartObjectList.add(chartObject4);

   final CategoryDataset dataset = 
    createDataset(chartObjectList);
   final JFreeChart chart = createChart(dataset);
   final ChartPanel chartPanel = new ChartPanel(chart);
   chartPanel.setPreferredSize
   (new java.awt.Dimension(900, 800));
   setContentPane(chartPanel);

  } catch (Exception e) {
   e.printStackTrace();
   return;
  }
 }

 /**
  * This method takes the List of ChartObjects as a parameter 
  * and creates three objects needed by the createCategoryDataset 
  * method of the DatasetUtilities class. The createCategoryDataset 
  * method needs 3 parameters. The first and second ones are 
  * Comparable[] and the third one is a double[][]. Since we 
  * created RowKey and ColumnKey objects to implement Comparable
  * interface, we use those objects to create the first two
  * parameters. The actual read/write values are used to populate 
  * a two dimensional  double[][].
  * 
  * @param chartObjectList
  * @return
  */
 private CategoryDataset createDataset
 (List<ChartObject> chartObjectList) {
  int chartObjectListSize = chartObjectList.size();

  // This is the Comparable[] that is used as the first 
  //parameter to the createCategoryDataset method
  // These values show up as the legend on the X-axis
  RowKey[] operations = 
   new RowKey[2];
  operations[0] = new RowKey("Read");
  operations[1] = new RowKey("Write");

  // This is the Comparable[] that is used as the second
  //parameter to the createCategoryDataset method
  ColumnKey[] timeStampArray = 
   new ColumnKey[chartObjectListSize];

  // These two double[] are used to populate a two 
  //dimensional double[][] that is used as the
  // third parameter to the createCategoryDataset method
  double[] readTimes = new double[chartObjectListSize];
  double[] writeTimes = new double[chartObjectListSize];

  // In this loop, the arrays are populated
  for (int i = 0; i < chartObjectListSize; i++) {
   timeStampArray[i] = 
    new ColumnKey(chartObjectList.get(i)
     .getTimeDetails());
   readTimes[i] = chartObjectList.get(i).getReadTime();
   writeTimes[i] = chartObjectList.get(i).getWriteTime();
  }

  // Populate the two dimensional double[][] using the 
  //two double[] created above
  double[][] data = new double[][] {readTimes,writeTimes};

  // Invoke the createCategoryDataset method by passing 
  //the three required parameters
  return DatasetUtilities.createCategoryDataset
  (operations, timeStampArray, data);
 }

 private JFreeChart createChart(final CategoryDataset dataset)
 {
  // Use the dataset created in the above method and get the
  // JFreeChartObject.
  // The PlotOrienation can be set to HORIZONTAL or VERTICAL.
  // The tooltip is shown if the second last boolean is
  // set to true. This tooltip shows the deails when the 
  // cursor is hovered over a particular bar in the chart
  final JFreeChart chart = 
   ChartFactory.createStackedBarChart(
    "Read/Write times", "TimeStamp", 
    "Time in Seconds", dataset,
    PlotOrientation.HORIZONTAL, true, true, false);

  chart.setBackgroundPaint(new Color(249, 231, 236));

  // Set colors etc. here
  CategoryPlot plot = chart.getCategoryPlot();
  plot.getRenderer()
   .setSeriesPaint(0, new Color(128, 0, 0));
  plot.getRenderer()
  .setSeriesPaint(1, new Color(0, 0, 255));
  return chart;

 }

}


Exhaustive comments are added in the above class. The gist:
In the main method, you invoke the Constructor that creates some sample ChartObjects with read/write times and timestamps. Then the main method invokes the local createDataset method to get a CategoryDataset object(of the JFreeChart API). Then it invokes the local createChart method that uses the above dataset and invokes the JFreeChartAPI's createStackedBarChart method.

The createCategoryDataset method needs 3 parameters. The first and second ones are Comparable[] and the third one is a double[][]. Since we created RowKey and ColumnKey objects to implement Comparable interface, we use those objects to create the first two parameters. The actual read/write values are used to populate a two dimensional double[][].

Build the project in eclipse (Ctrl+B). Right click on the StackedBarChartDemo.java class and Run As -> Java Application. If everything goes well, you should see a stacked bar chart like this below.



Links:

http://www.jfree.org/jfreechart/download.html


Monday, January 10, 2011

How to select file types in a File Chooser window (Java SWING)

The below tutorial explains how to select some particular file formats (like .jpg, .doc, .cer etc.) in the File Chooser window using Java SWING GUI. Detailed code snippets are interspersed along with the explanation.




First of all we need to have a JLabel, JTextField and JButton fields on the screen similar to the below screenshot. The JButton field is the button image with “…” text on it. Once you click the button, a popup window shows up to select the files (similar to the above screenshot). Whatever the User selects on the screen will be captured into the parent window’s JTextField (C:\Program Files\Common Files\Adobe\Updater6\AdobeUpdate.cer in the below example)


//JLabel:
JLabel certificatePath = new JLabel();
certificatePath.setText("Certificate Path");

//JTextField:
JTextField certificateDir = new JTextField(PropertyReader.get("certificateDir"));
certificateDir.setToolTipText("Location of the certificate file");

//JButton:
JButton browseCertificate = new JButton();
                                browseCertificate.setSize(24, 19);
                                browseCertificate.setPreferredSize(new java.awt.Dimension(24,19));
                                browseCertificate.setToolTipText("Browse and select the location of the cer file(ex: C:\\adobe.cer)");
                                browseCertificate.setText("...");
                                browseCertificate.addActionListener(new ActionListener() {
                                                public void actionPerformed(ActionEvent evt) {
                                                                browseCertificateActionPerformed(evt);
                                                }
                                });


In the above code, we added a listener that invokes a method on the click of the JButton. File selection filtering happens in the listener method.

I’m going to give a little explanation of the fields set in the listener method here. You can skip to the code directly if you just need a screen similar to the below image.

Java SWING provides a class called JFileChooser that allows us to set various properties on the ‘File Select’ popup.

  • The dialogTitle property shows the title on the popup window (“Select the certificate file” on the below screen)
  • The acceptAllFileFilterUsed Boolean is used to show the “All Files” value in the “Files of Type” dropdown. If the value is false, “All Files” option will not be shown.  (set to false on the below screen. Only *.cer value is shown)
  • The fileSelectionmode allows us to set the selection values to Files or Directories or both (set to Files only on the below screen)

To filter the files to show only some particular types of file Types, we create a new FileFilter class and override the two methods getDescription and accept.

  1. In the getDescription method, we return a String (something like “*.cer”). This value will be shown in the Files of Type dropdown.
  1. In the accept method, we write the logic to allow some particular file formats. For example, in the below code, we get the extension of the files using a utility method. If the extension equals “cer” we show it to the User. The important thing here is that we have to include the code if(f.isDirectory()){return true;} in the accept method. This will make sure that when we traverse across folders, we show the directories as well as the “cer” files. If we remove the isDirectory() block, we will not be able to traverse across folders.
Code snippets:
private void browseCertificateActionPerformed(ActionEvent evt) {

                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setDialogTitle("Select the Certificate file");
                fileChooser.setAcceptAllFileFilterUsed(Boolean.FALSE);
                fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
               
                fileChooser.setFileFilter(new FileFilter() {
                                                @Override
                                                public String getDescription() {
                                                                return "*.cer";
                                                }
                                               
                                                @Override
                                                public boolean accept(File f) {
                                                                if (f.isDirectory()) {
                                                                                return true;
                                                                    }
                                                                String extension = getExtension(f);
                                                    if (extension != null) {
                                                                if (extension.equals("cer")) {
                                                                        return true;
                                                                } else {
                                                                    return false;
                                                                }
                                                    }

                                                    return false;
                                                }
                                });
               
                int selection = fileChooser.showDialog(null, "Select");
                if(selection == JFileChooser.APPROVE_OPTION) {
                                certificateDir.setText(fileChooser.getSelectedFile().getAbsolutePath());
                }

}//end of browseCertificateActionPerformed method

This is the utility method to find the extension of the file
/*
     * Get the extension of a file.
     */ 
    private static String getExtension(File f) {
        String ext = null;
        String s = f.getName();
        int i = s.lastIndexOf('.');

        if (i > 0 &&  i < s.length() - 1) {
            ext = s.substring(i+1).toLowerCase();
        }
        return ext;
    }

References/Links:
  1. http://download.oracle.com/javase/tutorial/uiswing/components/filechooser.html#filters


Tags: Java SWING File Chooser file formats types JFileChooser Basic tutorial popup running example code GUI

Schedule Jobs in Java using Quartz (Java Job scheduling tutorial)

How to schedule Jobs in Java using Quartz (Java Job scheduling tutorial)


This tutorial is intended for Users who are looking to automate job scheduling in Java using Quartz. For example, if you would like to run a particular Java program at a particular point of time and date (and at regular frequencies) automatically, you can use the Quartz API to achieve this.

I will provide a simple example that covers the basics of the Quartz API to perform the scheduling.

Quartz API has the following basic objects.

SchedulerFactory
Scheduler
JobDetail
Trigger.

If you are using Apache Maven,  just add the following dependency in your pom.xml

      
                           org.quartz-scheduler
                           quartz
                           1.8.4
      
If you are not using Maven(or don’t know what Maven is), download the Quartz API from www.quartzscheduler.org and include it in your application’s build path. Btw, I strongly recommend you to start using Maven for your projects if you haven’t already. Off topic, but it is a wonderful dependency management tool (among various other features)

The concept is that you create a Scheduler object using the SchedulerFactory (Factory pattern if you know what I mean. I will show the related code below). And then you create a JobDetail object(by assigning the job a name and a group). Finally, you create a Trigger object that tells the scheduler on when to run the Job.

The trigger schedule can be set using CRON. If you are not sure what CRON is, it is just a expression (which is essentially a string) that tells the second/minute/hour/day of month/month/day of week/year in a regex format. The first 6 fields are mandatory and the last one(year) is optional.

A cron expression is a string comprised of 6 or 7 fields(explained above) separated by white space. Fields can contain any of the allowed values, along with various combinations of the allowed special characters for that field.

Just look at the following expression.

10 * * * * ?

This means that on the 10th second(1st field - 10)of every minute(2nd field - *) of every hour (3rd field - *)of every day(4th field - *)  of every month (5th field - *), the job will be run. The 6th field was marked as ? as there is no specific useful value for that. I mean if we are running the job everyday, there is no point in mentioning it to run on Sun/Mon/Tue etc. Also, if in another CRON expression we want to run on the 15th of every month and we don’t care what day of the week it is (Sun/Mon etc.), we can mark the 6th field as ?. I think you get the idea. The 7th field is the year, which is an optional field, which I haven’t used in the above expression. Another example:

0 0 0 1 1 ? *

On the 0th second of the 0th minute of the 0th hour of the 1st day of the 1st month of each year, do something. Like partying for a new year?

Ok, enough of CRON. There are a lot of other ways to use/customize CRON, which you can read in the related links at the end of the post.  Now back to the Quartz scheduler program.

Create a new Java class named QuartzTesting. This has to implement the Job interface, and thereby the execute method. Once the below program is run, the code in the execute method will be invoked at the regular frequency specified as per the CRON expression.
package com.abc.quartz.testing;

import java.text.ParseException;

import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;

public class QuartzTesting implements Job{

                /** The sched fact. */
                private static SchedulerFactory schedFact = new StdSchedulerFactory();
               
                /** The sched. */
                private static Scheduler sched;
               
                static
                {
                                try {
                                                sched = schedFact.getScheduler();
                                } catch (SchedulerException e) {
                                                System.out.println("Exception in static block of QuartzTesting class, Exiting the program " +e);
                                                System.exit(-1);
                                }
                }

                /**
                 * @param args
                 */
                public static void main(String[] args) {
                               
                                try {
                                                //start the scheduler
                                                sched.start();

                                                //Create the JobDetail object and the CronTrigger
                                                JobDetail jobDetail = new JobDetail("Name",
                                                                                "Group", QuartzTesting.class);

                                                CronTrigger trigger = new CronTrigger("Name", "Group");
                                               
                                                //Set the CRON expression as per the desired frequency
                                                trigger.setCronExpression("*/10 * * * * ?");
                                               
                                                //schedule the job
                                                sched.scheduleJob(jobDetail, trigger);
                                } catch (SchedulerException e) {
                                                e.printStackTrace();
                                                System.exit(-1);
                                } catch (ParseException e) {
                                                e.printStackTrace();
                                                System.exit(-1);
                                }

                }

                public void execute(JobExecutionContext cntxt) throws JobExecutionException {

                                try {
                                                                //insert the code here that needs to be performed at the intervals scheduled using CRON trigger
                                                                //like making a Webservice call or running a report etc.
                                                                System.out.println("Running the code in the execute method");
                                                }
                                                                catch (Exception ex) {
                                                                                System.out.println(
                                                                                                                "Exception occured in execute method " +ex);
                                                                }
                                               
                                                }
}
Now, if you compile and run the above program, you will see a Java process running in your task manager. You should the Sysout at the intervals specified as per CRON (on the 10th  second of each minute in the above example. Please note that you see Sysouts every one minute and not every 10 seconds. If you want Sysouts every 10 seconds change the CRON expression to */10 * * * * ? )

If you were wondering what the name and Group are for the JobDetail/Trigger objects, they are used to identify the jobs if you have multiple jobs/triggers. In those multiple job scenarios, you can refer to the particular jobs using their names. Something like,

      //Delete if the job already exists and then schedule the job
                sched.deleteJob(“Sending Job”, “Send Group”);
References/Useful links:

  1. www.quartzscheduler.org
  2. http://oreilly.com/pub/a/java/archive/quartz.html?page=1
  3. http://www.quartz-scheduler.org/docs/tutorials/crontrigger.html

Tags: Java Job scheduling Quartz CRON trigger frequency timer regular intervals example basic tutorial

Sunday, January 9, 2011

Apache Maven Tutorial - Basic setup (Eclipse)

In this post, I will show how to setup Apache Maven in Eclipse and to run a basic program by using Maven.

First of all, what is Maven? In my own words, Maven is a project management, dependency management and build tool. I will explain it further a little bit.
Lets say in your organization, you have various teams and there is a possibility that each team might use the code written by other teams. If the code written for various projects by all the teams follow a particular folder structure/setup, it becomes really easy to build those projects and setup continuous integration etc.
Lets say Team A writes a java application and bundles it as a jar file. Team B writes a JEE application and bundles it as a war/ear file. Team C wants to reuse some methods and classes in Team A's jar file.

Team A sets up its project structure using Maven's standard folder structure. Example would be putting all the java classes in src/main/java folder. It would put all of its properties files under src/main/resources etc. And then there is pom.xml, which is the file that manages the project. This xml is the heart of each project and explains what other jar files are needed for building this project, how to package the code (as a jar/war etc.) and some other details.
In short, Team A creates a Maven project following the standard directory structure and creates a pom.xml. After finishing coding the java classes, there are some commands that can be invoked which read the xml and generate the jar/war file and install them in a repository somewhere.

Now Team C, also creates its own project by following the standard directory structure. Now, instead of writing the Utility classes again, it just adds the Project A's jar file as a dependency in it's(Project C's) pom.xml. So, when the build commands are invoked, Maven download's Project A's jar file from the repository so that Project C can use them(using imports in java classes).

Please note that the above example is just one aspect of Maven.

Ok, enough talk. Lets start with an example.

Im going to use eclipse for this tutorial. You can download eclipse from http://www.eclipse.org/downloads/

Download the latest version of Maven from http://maven.apache.org/download.html. Extract to a folder like C:\Maven

In Eclipse, install the Maven plugin:
Go to Help -> Install New Software and then Click on Add button and enter the following URL for the update site
http://m2eclipse.sonatype.org/installing-m2eclipse.html
Follow the instructions on the screen and finish the plugin installation

After the plugin is installed, in Eclipse, click on File -> New -> Maven -> Maven Project. Click on Next. On this page, select the first checkbox (Create a simple project). Click Next.
Enter the groupId, ArtifactId, Name, Descpription etc. GroupId is something like your organization name(enter abc), ArtifactId is something like a project name(enter Sample). Click Next and click Finish. Voila. You now have your first Maven project setup. The plugin automatically creates a lot of default folder using the standard maven directory structure.
If you look at the Project Explorer for the 'Sample' project, you can see src/main/java, src/main/resources, some other folders and target, pom.xml.
You can open pom.xml and look at the xml file. It contains the details that we provided during the project creation.

Now, let us create a simple java class in this project. In Package explore, right click on src/main/java folder and click on New -> Class. Enter a package name as code and class name as . SampleClass. Check the checkbox to create a main method. Click on Finish.

We now have the SampleClass.java that has the following code.
package code;
public class SampleClass {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated
}
}

Now, lets say in this class we want to do some functionality. Like copying the contents of a directory to another directory. Instead of writing the code to do the copy the contents, we will use Maven's ability to download the jar files that has the code to do the copying. For example, we know that the FileUtils class of the commons-io utility package provides a lot of File Utility functions. So, all we need to do is go to our pom.xml and add the following lines.
 
   org.apache.commons
   commons-io
   1.3.2
  
Add these between <dependencies> tags.

So, the contents of sample/pom.xml should be something like:


 4.0.0
 abc
 sample
 0.0.1-SNAPSHOT
 sample
 Sample project

 
  
   org.apache.commons
   commons-io
   1.3.2
  
 



Click on Project -> Build in Eclipse. On the console, you will see that a lot of jar files are downloaded from some repositories. You can find what all jars are downloaded by going to the location .m2\repository somewhere in your C drive(this default location is specified in settings.xml in your initially downloaded Maven zip file)

That's it! Now, you have the commons-io jar at your disposal !

Go to SampleClass.java and type FileUtils and press Ctrl+Space. This will automatically import the class org.apache.commons.io.FileUtils. Now you can use the methods in the FileUtils class


Add the code so that the java class looks like below:
package code;

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;

public class SampleClass {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
File srcDir = new File("C:\\srcDir");
File destDir = new File("C:\\destDir");

FileUtils.copyDirectory(srcDir, destDir);
} catch (IOException e) {
e.printStackTrace();
}

}

}


Save, build and run the Java class using Run -> Run as Java application (You can change the srcDir, destDir paths in the java class to match your folders)

You have used Apache's FileUtils class just by adding the dependency in your pom.xml file.

If I get enough feedback, I will write more tutorials on how to use Maven to install/package your projects and how to use repositories and continuous integrations.

Hopefully, the above simple example will initiate some interest in using Maven for your projects.


References and useful links:

http://maven.apache.org/guides/getting-started/index.html

Saturday, November 20, 2010

Java: Comparable/Comparator

Sometimes, in Java, you have a List or some other collection, that you would like to sort. However, the List might be a List of objects with each object possessing multiple properties(fields). Ok, Cut to the Chase.

You have a 'Man' object with the fields, name, height, weight. You would like to sort an ArrayList of men according to one of those fields. I tried telling Java that all Men are born equal, but it didn't work.

There are two ways to do this. In both of these ways, we use the sort method of the Collections class. However, the parameters of the overloaded sort method differ. I will explain more in detail below.

1. Change the Man class to implement the Comparable interface. Then, you would have to implement the compare method(with one parameter). If you want to sort the "Man" objects based on their weight (say, if you are going for NFL picks), put the code in the compare method to compare based on the weights.


Here below, the 'Man' class that implements Comparable interface


package main.java.testing;
public class Man implements Comparable{

//fields
private String name;
private int height;
private int weight; 

//Constructor
public Man(String name, int height, int weight) {
this.name = name;
this.height = height;
this.weight = weight;
}

//This method compares based on the weight of the two "Man" objects
@Override
public int compareTo(Man o) {
return this.height - o.height;
}

//Getters and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
The Example class with the main method and sample data to sort.

package main.java.testing;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ManSortingExample {

public static void main(String[] args)
{

List<Man> manList = new ArrayList<Man>();
manList.add(new Man("Shipley, Jordan", 71, 193));
manList.add(new Man("Alem, Rahim", 75, 251));
manList.add(new Man("Beadles, Zane", 76, 310));
manList.add(new Man("Capers, Selvish", 76, 308));
manList.add(new Man("McCoy, Colt", 73, 216));
manList.add(new Man("Peek, Colin", 77, 254));
manList.add(new Man("Verner, Alterraun", 70, 189));

System.out.println("--------------------------------------------------");
System.out.println("BEFORE SORT USING COMPARABLE METHOD OF THE OBJECT");
for(Man m:manList)
{
System.out.println(m.getName() + " " +m.getHeight() + " " +m.getWeight());
}

//Use the sort method of the Collections class
Collections.sort(manList);

System.out.println("--------------------------------------------------");
System.out.println("AFTER SORT USING COMPARABLE OF THE OBJECT(WEIGHT)");
for(Man m:manList)
{
System.out.println(m.getName() + " " +m.getHeight() + " " +m.getWeight());
}
}
}

To sort, we use the one of the sort method of the Collections class. It takes a List(that implements comparable) as a parameter and sorts the List based on that method.
Run the example program and you will get the List sorted by weights(that we coded in the compare method).

The output would be
--------------------------------------------------
BEFORE SORT USING COMPARABLE METHOD OF THE OBJECT
Shipley, Jordan 71 193
Alem, Rahim 75 251
Beadles, Zane 76 310
Capers, Selvish 76 308
McCoy, Colt 73 216
Peek, Colin 77 254
Verner, Alterraun 70 189
--------------------------------------------------
AFTER SORT USING COMPARABLE OF THE OBJECT(WEIGHT)
Verner, Alterraun 70 189
Shipley, Jordan 71 193
McCoy, Colt 73 216
Alem, Rahim 75 251
Beadles, Zane 76 310
Capers, Selvish 76 308
Peek, Colin 77 254


However, after a few days, if you want to sort the List based on Name, you would have to change the Employee Class' compare method again. If you don't want to do that, then you can follow the second approach.

2. In this approach, the objects that we want to sort need not implement any interface. Instead, we write another class that implements the Comparator interface and use that class as a parameter to another of the Collections.sort methods. Example below.

Create, the so called sorting class by implementing the Comparator interface. You would have to override the compare method (with two parameter objects)

Now, change you Example class to add the sorting based on Name too.

package main.java.testing;

import java.util.Comparator;

public class ManSortByName implements Comparator{

@Override
public int compare(Man o1, Man o2) {
return o1.getName().compareTo(o2.getName()); }

}

And now for testing this change:
package main.java.testing;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ManSortingExample {

public static void main(String[] args)
{

List manList = new ArrayList();
manList.add(new Man("Shipley, Jordan", 71, 193));
manList.add(new Man("Alem, Rahim", 75, 251));
manList.add(new Man("Beadles, Zane", 76, 310));
manList.add(new Man("Capers, Selvish", 76, 308));
manList.add(new Man("McCoy, Colt", 73, 216));
manList.add(new Man("Peek, Colin", 77, 254));
manList.add(new Man("Verner, Alterraun", 70, 189));

System.out.println("--------------------------------------------------");
System.out.println("BEFORE SORT USING COMPARABLE METHOD OF THE OBJECT");
for(Man m:manList)
{
System.out.println(m.getName() + " " +m.getHeight() + " " +m.getWeight());
}

//Use the sort method of the Collections class
Collections.sort(manList);

System.out.println("--------------------------------------------------");
System.out.println("AFTER SORT USING COMPARABLE OF THE OBJECT(WEIGHT)");
for(Man m:manList)
{
System.out.println(m.getName() + " " +m.getHeight() + " " +m.getWeight());
}

//Sort method that takes two parameters, the second being the comparator class
Collections.sort(manList, new ManSortByName());

System.out.println("--------------------------------------------------");
System.out.println("AFTER SORT USING COMPARATOR CLASS (NAME)");
for(Man m:manList)
{
System.out.println(m.getName() + " " +m.getHeight() + " " +m.getWeight());
}

}

}
The output would be:
--------------------------------------------------
BEFORE SORT USING COMPARABLE METHOD OF THE OBJECT
Shipley, Jordan 71 193
Alem, Rahim 75 251
Beadles, Zane 76 310
Capers, Selvish 76 308
McCoy, Colt 73 216
Peek, Colin 77 254
Verner, Alterraun 70 189
--------------------------------------------------
AFTER SORT USING COMPARABLE OF THE OBJECT(WEIGHT)
Verner, Alterraun 70 189
Shipley, Jordan 71 193
McCoy, Colt 73 216
Alem, Rahim 75 251
Beadles, Zane 76 310
Capers, Selvish 76 308
Peek, Colin 77 254
--------------------------------------------------
AFTER SORT USING COMPARATOR CLASS (NAME)
Alem, Rahim 75 251
Beadles, Zane 76 310
Capers, Selvish 76 308
McCoy, Colt 73 216
Peek, Colin 77 254
Shipley, Jordan 71 193
Verner, Alterraun 70 189



To sort, we use another of the sort method of the Collections class. It takes a List(that NEED NOT implement comparable) as the first parameter and the Comparator class(ManSortByName in this case) and sorts the List based on that compare method of the Comparator class(ManSortByName in this case).
Run the example program and you will get the List sorted by name(that we coded in the compare method of ManSortByName class).
That's it. Now you can just change the compare method of the ManSortByName class if you need to change the sort criteria or create another class that implements the Comparator class (say ManSortByHeight) and use it as a parameter to the Collections.sort method.

I carefully selected 'Man' object instead of 'Woman' object as people would think I am objectifying women. You are welcome.