Sunday, October 25, 2009

Java Swing Example: Image dimension from url

This code can be used to get the dimension of any image using its url. Minor tweaks can be made to get localized image dimensions too.Hope this helps.


import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JFrame;

public class ImageDimensions extends JFrame {
 
 protected static Toolkit tool = Toolkit.getDefaultToolkit();
 
 public ImageDimensions() {
 }

 protected void calculateHeightWidth()
   throws InterruptedException {
  Image image = null;
  try {
   image = tool.createImage(new URL("Image URL"));
   
  } catch (MalformedURLException e) {
   e.printStackTrace();
  }catch(Exception e1){
   e1.printStackTrace();
  }
  
  MediaTracker mTracker = new MediaTracker(this);
  mTracker.addImage(image, 1);
  int i = 0;
  do {
   mTracker.waitForID(1);
   //added counter and break for the 404 or bad url 
   i++;
   if (i==5) break;
  } while (mTracker.statusID(1, true) != MediaTracker.COMPLETE);

System.out.println(image.getHeight(null));
System.out.println(image.getWidth(null));
 }
 
 public static void main(String[] args) {
 try {
  new ImageDimensions().calculateHeightWidth();
 } catch (InterruptedException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 } 
 }
 
}





Wednesday, October 21, 2009

Date to calendar,date utils... a simple example

Sometimes in you application you will require the calendar logic. In java the Date class methods are mostly deprecated and usage of Calendar class is encouraged. This utility class will do the operations using the Calendar api. This also can be use as Date to calendar converter or calendar to date converter. The methods are synchronized, so are threadsafe. I didn't make the calendar static, you can do that is required.


import java.util.Calendar;
import java.util.Date;

/**
 * This class will operate as a calendar. First set a date.
 * Then change the day,month or year as require. 
 * Then get the date back. There is also a feature of getting the current date, if needed,
 * which you can set as the base date again and do operations. 
 * Only date operations are permitted. 
 * Add logic, if you want the time related operations too.
 */
public class CustomCalendar {

private Calendar date;
private static final int BASEYEAR = 1900;
//Set the date before operation. Converts date to calendar for easier operation
public CustomCalendar(Date date) {
 super();
  this.date = Calendar.getInstance();
  this.date.setTime(date);
}

public CustomCalendar(Calendar date) {
 super();
 this.date = date;
}

//sets the prev year relative to the date already set(In constructor).
public  synchronized void prevYear() {
 int year = date.get(Calendar.YEAR)-BASEYEAR;
 date.set(Calendar.YEAR, year + BASEYEAR - 1);
}

//sets the next year relative to the date already set(In constructor).
public synchronized void nextYear() {
 int year = date.get(Calendar.YEAR)-BASEYEAR;
 date.set(Calendar.YEAR, year + BASEYEAR + 1);
}

//sets the prev month relative to the date already set(In constructor).
public synchronized void prevMon() {
int month = date.get(Calendar.MONTH);
date.set(Calendar.MONTH, month - 1);
}

//sets the next month relative to the date already set(In constructor).
public synchronized void nextMon() {
 int month = date.get(Calendar.MONTH);
 date.set(Calendar.MONTH, month + 1);
}

//sets the prev day relative to the date already set(In constructor).
public synchronized void prevDay() {
 int day = date.get(Calendar.DAY_OF_MONTH);
 date.set(Calendar.DAY_OF_MONTH, day - 1);
}

//sets the next day relative to the date already set(In constructor).
public synchronized void nextDay() {
 int day = date.get(Calendar.DAY_OF_MONTH);
 date.set(Calendar.DAY_OF_MONTH, day + 1);
}

//sets the current system date, in case it is needed.
public static synchronized Date currentSystemDate() {
 return new Date();
}

//returns the date, after all the year,month,day operation.
public  synchronized Date getDate() {
 return date.getTime();
}
}

Tuesday, October 13, 2009

Log4j Custom Performance Logger.

If you are a java coder, logging is indispensable part of your life. Often in your life you may have been in a situation, where you need a special purpose logging.

For example performance logging. If you have performance bottleneck in your application and if you suspect a few classes to be the culprit (or methods for that matter), then you may need a separate logger, that will log the performance of those classes. It will be in addition to the existing logging you have in your application.

Performance logging is just an example, but in these special situations, you feel the need of a custom logger.

Writing a custom logger is very simple, yet very helpful.

I a hereby giving the example of a performance logger. It will note the START time, END time and the time difference in the form of a CSV. As you dont want this to mess with your main application logs, you will need a separate log appender for this(TimingStats in this example).

Though it talks about performance logging, this code snippet can be modified to implement any kind of custom logger.

PerformanceLogger.java

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class PerformanceLogger {
 
 
 private static Logger logger = Logger.getLogger(PerformanceLogger.class);
 String methodName; 
 long startTime;
 long endTime;
 
 public PerformanceLogger() {
  super();
  logger.setLevel(Level.ERROR);
 }
 public PerformanceLogger(Level level) {
  super();
  
  logger.setLevel(level);
 }
public static boolean debug(){
 return logger.getLevel()==Level.DEBUG?true:false;
}

 public void writeTime(String operation){
  logger.debug(operation);
 }
 public void startMethod(String methodName){
  this.methodName = methodName;
  startTime = System.currentTimeMillis();
  writeTime(methodName+":START: ,"+startTime+", milliseconds");
 }
 public void endMethod(String methodName) {
  this.methodName = methodName;
  endTime = System.currentTimeMillis();
  writeTime(methodName+":END: ,"+endTime+", milliseconds");
  writeTime(methodName+":TIME TAKEN: ,"+((endTime-startTime)/1000)+", seconds");
 }
 
}

log4j.xml

<appender name="Your_Default_appender" />
    <!-- this appender will be used by performance logger class -->
 <appender name="TimingStats" class="org.apache.log4j.RollingFileAppender"> 
    <param name="File" value="./logs/TimingStats.csv"/> 
    <param name="Append" value="false" />
    <param name="MaxFileSize" value="10MB"/>
    <param name="MaxBackupIndex" value="1"/>
    <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%d , [%t] , %x , %-5p , (%F) , %m%n"/> 
    </layout> 
   </appender>
 
 
 <!-- All your loggin levels for classes would be here. -->
 
 <logger name="some class" additivity="false">
    <level value="DEBUG" />
    <appender-ref ref="Your_Default_appender" />
  </logger>

<!-- There will be a special declaration of the PerformanceLogger class. Note that it is not using the default appender. -->
  <logger name="PerformanceLogger" additivity="false">
    <level value="DEBUG" />
    <appender-ref ref="TimingStats" />
  </logger>

Put the following lines in the class you want to log the performance.

private static PerformanceLogger log = new PerformanceLogger(Level.DEBUG);

You can use a singleton pattern if you want. But that is another topic.

At the start of any methos put
log.startMethod(methodName);

At the end of any method put
log.endMethod(methodName)


That should serve your purpose. If you see any issue with my code, please comment and help me improve

Monday, October 12, 2009

Setting up a cron job in unix/linux

What is CRON?
Cron is a time-based job scheduler in Unix-like computer operating systems. 'cron' is short for Chronograph. It is a long running process that enables users to schedule jobs (commands or shell scripts) to run automatically at a certain time or date. 

What are the common uses?
It is commonly used to perform system maintenance or administration. Though it can be used for all other practical purposes

What is CRONTAB?
Cron is driven by a crontab, a configuration file that specifies shell commands to run periodically on a given schedule.
crontab -e (Edit your crontab file).
crontab -l Show your crontab file.
crontab -r Remove your crontab file.
MAILTO=user@domain.com Emails the output to the specified address.

Each entry in a crontab file consists of six fields:

minute(s) hour(s) day(s) month(s) weekday(s) command(s)

The fields can be separated by spaces or tabs.

Field  Value  Description 
minute(0-59) - The exact minute that the command sequence executes.
hour(0-23) - The hour of the day that the command sequence executes.
day(1-31) - The day of the month that the command sequence executes.
month(1-12) - The month of the year that the command sequence executes.
weekday(0-6) - The day of the week that the command sequence executes. Sunday=0, Monday = 1 and so on.

Example: Print "Hello" after every hour

Sample cron job command:-  * 1 * * * echo "Hello"
Sample cron job script:-  * 1 * * * whatever_you_want.sh

Steps to setup the above cron job:-
  1. In you unix prompt fire "crontab -e" . It will open the crontab file in the default editor (Most commonly vi editor)
  2. Press "i" to change the mode to INSERT.
  3. At the end of the file, type in the above sample command and/or script.
  4. Wait for the stipulated time mentioned in the cronjob and then check your mail, you should be able to see the output (if any) there.

Happy Scheduling




Friday, October 9, 2009

Date and Big Decimal utilities

Problem Description

We need various small utilities regardign numbers and dates.
This code snippet has included some of the common conversions for convenience.



Solution Description

There are two separate classes "DateUtils" and "NumberUtils". MyMain class shows the usage.



Code Snippet


NumberUtils.java



import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;


public class NumberUtils {

    /**
     * Method takes Object as parameter and returns decimal number.
     * if argument is float or double and contains tailing zeros
     * it removes them. If argument is float or double then no change in return type.
     * Change the Format of the Number by changing the String Pattern
     */
    public static String changeToDecimalFormat(Object number) {

        BigDecimal bdNumber = new BigDecimal(number.toString());
        bdNumber = bdNumber.stripTrailingZeros();           //Returns a BigDecimal with any trailing zero's removed
        String pattern = "###,##0.0###########";        //To apply formatting when the number of digits in input equals the pattern
        DecimalFormat newFormat = new DecimalFormat(pattern, new DecimalFormatSymbols(Locale.US));
        return newFormat.format(bdNumber);

    }

    /* Method takes Object as parameter and removes commas from the parameter */
    public static double removeCommasFromNumber(Object number) {
        try {
            StringBuffer inputNo = new StringBuffer(number.toString());
            if (inputNo.length() > 0) {
                while (inputNo.indexOf(",") != -1) {
                    inputNo.deleteCharAt(inputNo.indexOf(","));
                }
            } else {
                return 0.0;
            }
            return Double.parseDouble(inputNo.toString());

        } catch (NumberFormatException e) {
            return 0.0;
        }
    }

    /* Some times its required to have a fixed set of decimal places for a
     * number. We can set that by changing the precision number for a particular
     * input BigDecimal Input String
     */
    public static String changeToRequiredDecimals(String bigDecimalString,
            int precision) {
        String newFormattedString = null;
        String afterDecimal = null;
        if (bigDecimalString == null || bigDecimalString.length() == 0) {
            return "0.0";
        }
        if (bigDecimalString.contains(".")) {
            afterDecimal = bigDecimalString.substring(bigDecimalString
                    .indexOf(".") + 1);
            int length = Math.abs((afterDecimal.length() - precision));
            if (afterDecimal.length() < precision) {
                newFormattedString = bigDecimalString;
                for (int i = 0; i < length; i++) {
                    newFormattedString = newFormattedString + "0";
                }
            } else if (afterDecimal.length() > precision) {
                newFormattedString = bigDecimalString.substring(0,
                        bigDecimalString.length() - length);
                if (precision == 0) {
                    newFormattedString = newFormattedString.substring(0,
                            newFormattedString.indexOf("."));
                } else {
                    newFormattedString = bigDecimalString;
                }

            } else {
                    if (precision > 0)
                        newFormattedString = bigDecimalString + ".";
                    else
                        newFormattedString = bigDecimalString;
                    for (int i = 0; i < precision; i++) {
                        newFormattedString = newFormattedString + "0";
                    }
            }
        }
        return newFormattedString;
    }

}


DateUtils.java



import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;


public class DateUtils {

    public static Date getNthFromCurrentDate(int field, int nValue) {
        Calendar current = Calendar.getInstance();
        current.setLenient(true);
        current.add(field, nValue);
        return current.getTime();
    }
   
    public static Date convertStringToDate(String dateString, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        try {
            return sdf.parse(dateString);
        } catch (ParseException e) {
            return null;
        }
    }
    public static Date convertStringToTimestamp(String dateString, String pattern) {
        return new Timestamp(convertStringToDate(dateString, pattern).getTime());
    }
}


MyMain.java



import java.math.BigDecimal;


/**
 *
 */
public class MyMain {

    /**
     *Method
     * @param args
     */
    public static void main(String[] args) {

       
        System.out.println(DateUtils.convertStringToDate("11.10.2010", "dd.MM.yyyy"));
        System.out.println(DateUtils.convertStringToTimestamp("11.10.2010", "dd.MM.yyyy"));
        System.out.println(DateUtils.getNthFromCurrentDate(1,2));
       
        int intVar = 10;
        double doubleVar = 10.504000;
        float floatVar = 343534534348.5687654F;
        String commaString = "343,534,535,000.0";
        BigDecimal bdNumber = new BigDecimal("1234.8765");
       
       
        System.out.println(NumberUtils.changeToDecimalFormat(new Integer(intVar)));
        System.out.println(NumberUtils.changeToDecimalFormat(new Double(doubleVar)));
        System.out.println(NumberUtils.changeToDecimalFormat(new Float(floatVar)));
       
        System.out.println(NumberUtils.removeCommasFromNumber(commaString));
       
        System.out.println(NumberUtils.changeToRequiredDecimals(bdNumber.toString(), 8));

    }


}






Thursday, October 8, 2009

Drawing multiple XY graphs using JFreechart

Problem Description
There are sometimes requirement to draw multiple plots against time in any java application. JFreechart provides an excellent API for this purpose. But knowing and remembering all the methods in this API is painfull and time consuming






Solution Description
My code draws multiple X-Y charts using the data provided. The source comes with all the jar files necessary for this purpose. It does two things.
1) Saves the chart in some specified location of local machine as JPG image.
2) Draws the chart on the screen using Swing API.

Dependencies
jfreechart-1.0.4.jar
jcommon-1.0.9.jar








Sample Code


MyMain.java





package graph;


/**
* Helper class. Used to testing purpose
*
*/
public class Mymain {


/**
*
* @param args
*/
public static void main(String[] args) {
System.out.println("MAIN : START");
Graph graph = new Graph();
Value value;
Value localvalues[]= new Value[names.length];
graph.setNames(names);
for (int i=0;i
value = new Value();
value.setI(values[i]);
localvalues[i] = value;
}
graph.setValues(localvalues);
new MyGraphs().createChart(graph,GraphConstants.PERIOD_TYPE_MONTHLY);


System.out.println("MAIN : END");


}

protected final static Integer values[][] = {
{12,1,123,10,200,12,45,15},
{1,12,10,112,0,122,15},
{121,34,21,13,90,6,78},
{5,67,15,104,2,123,4}
};
protected final static String names[] = {
"Report1",
"Report2",
"Report3",
"Report4"
};


}


Graph.java





package graph;


/**
*
*
*/
public class Graph {
String names[];
Value values[];
/**
*
* @return names
*/
public String[] getNames() {
return names;
}
/**
*
* @param names
*/
public void setNames(String[] names) {
this.names = names;
}
/**
*
* @return values
*/
public Value[] getValues() {
return values;
}
/**
*
* @param values
*/
public void setValues(Value[] values) {
this.values = values;
}


}



GraphConstants.java



package graph;


/**


* Constant file


*


*/


public interface GraphConstants {





/**period type if weekly*/


public final int PERIOD_TYPE_WEEKLY = 0;


/**period type if monthly*/


public final int PERIOD_TYPE_MONTHLY = 1;


/**period type if monthly*/


public final int PERIOD_TYPE_QUATERLY = 2;






/** the location of the file to be stored*/


public static final String FILE_PATH = "d:\\chart.jpg";





/**plotting details : width of x-axis*/


public static final int X_AXIS_WIDTH = 500;


/**plotting details : width of y-axis*/


public static final int Y_AXIS_WIDTH = 300;





/**graph name : This part should be moved to property file*/


public static final String GRAPH_NAME = "Graph Name";


/**x-axis label : This part should be moved to property file*/


public static final String X_AXIS = "X Axis";


/**y-axis label : This part should be moved to property file*/


public static final String Y_AXIS = "Y Axis";


/** Sample data error. This part should be moved to property file*/


public static final String ERROR_MESSAGE = "Name and values must be equal in number";





/** Null string*/


public static final String NULL = null;






}


MyGraphs.java




package graph;


import java.awt.BorderLayout;


import java.io.File;


import java.io.IOException;


import javax.swing.JPanel;


import org.jfree.chart.ChartFactory;


import org.jfree.chart.ChartPanel;


import org.jfree.chart.ChartUtilities;


import org.jfree.chart.JFreeChart;


import org.jfree.chart.labels.XYToolTipGenerator;


import org.jfree.chart.plot.XYPlot;


import org.jfree.chart.renderer.xy.XYItemRenderer;


import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;


import org.jfree.data.time.Month;


import org.jfree.data.time.Quarter;


import org.jfree.data.time.RegularTimePeriod;


import org.jfree.data.time.TimeSeries;


import org.jfree.data.time.TimeSeriesCollection;


import org.jfree.data.time.Week;


import org.jfree.data.xy.XYDataset;


import org.jfree.ui.ApplicationFrame;


import org.jfree.ui.RefineryUtilities;










/**


* This class is responsible for creating the graph using the data provided.


*


*/


public class MyGraphs extends ApplicationFrame implements XYToolTipGenerator{








/**


*


*/


private static final long serialVersionUID = -4019769545419857920L;






/** JFreeChart */


private JFreeChart chart;





/** Time series collection */


private TimeSeriesCollection dataset;


/**


* no-arg constructor


*/


public MyGraphs(){


this(GraphConstants.GRAPH_NAME);


}


/**


*


* @param title


*/


public MyGraphs(String title){


super(title);


}


/**


* This method takes care of all the aspects of drawing the graph


* @param graph


* @param periodType


*/


protected void createChart(Graph graph,int periodType) {


dataset = new TimeSeriesCollection();






// Add series data from table model to chart


try{


addSeriesToChart(dataset, graph,periodType);






// Create chart


chart = ChartFactory.createTimeSeriesChart(GraphConstants.GRAPH_NAME,GraphConstants.X_AXIS,GraphConstants.Y_AXIS,


dataset, true, true, false);






XYPlot plot = (XYPlot) chart.getPlot();





//Configured the axis of the graph


configureAxis(plot);






//Configures the rendered


configureRenderer(plot);






//Saves the graph image at the mentioned file path


saveChart();






//Draws the chart on screen using java swing


drawChart();


}catch (IOException ioe){


ioe.printStackTrace();


}catch(Exception e){


e.printStackTrace();


}






}





/**


* saves the chart as a jpg image at specified location.


*/


private void saveChart()throws IOException{


ChartUtilities.saveChartAsJPEG(new File(GraphConstants.FILE_PATH), chart, GraphConstants.X_AXIS_WIDTH, GraphConstants.Y_AXIS_WIDTH);


}





/**


* creates the graph on screen, with the aid of the class XYChartDemo.


*/


private void drawChart(){


this.setSize(new java.awt.Dimension(GraphConstants.X_AXIS_WIDTH,GraphConstants.Y_AXIS_WIDTH));


ChartPanel chartPanel = new ChartPanel(chart);








// size


chartPanel.setPreferredSize(new java.awt.Dimension(GraphConstants.X_AXIS_WIDTH,GraphConstants.Y_AXIS_WIDTH));






final JPanel main = new JPanel(new BorderLayout());


final JPanel optionsPanel = new JPanel();






main.add(optionsPanel, BorderLayout.SOUTH);


main.add(chartPanel);


setContentPane(main);


RefineryUtilities.centerFrameOnScreen(this);


setVisible(true);






}


/**


*


* @param dataset


* @param graph


* @param periodType


* @throws Exception


*/


protected void addSeriesToChart(TimeSeriesCollection dataset,Graph graph,int periodType)throws Exception{





int count_from = 0;


int count_to = graph.getNames().length;


if (graph.getNames().length!= graph.getValues().length){


throw new Exception(GraphConstants.ERROR_MESSAGE);


}


for (int j = count_from;j


TimeSeries g = new TimeSeries(graph.getNames()[j], getTimePeriod(periodType).getClass());


RegularTimePeriod start = getTimePeriod(periodType);


for (int i = 0; i


start = start.previous();


double value = (graph.getValues()[j].getI()[i]).doubleValue();


g.add(start,value);


}


dataset.addSeries(g);


}


}


/**


* @param xyPlot


*/


protected void configureAxis(XYPlot plot){


// Make crosshair visible for Range and Domain axis.


plot.setDomainCrosshairVisible(true);


plot.setRangeCrosshairVisible(true);






// Set upper margin of Domain axis for proper display of Item label.


plot.getDomainAxis().setUpperMargin(.05);






// Set margin of range axis for proper display of Item label.


plot.getRangeAxis().setUpperMargin(0.15);


plot.getRangeAxis().setLowerMargin(0.15);


//plot.getRangeAxis().setAutoRange(true);


}





/**


*


* @param plot


*/


protected void configureRenderer(XYPlot plot){


XYItemRenderer r = plot.getRenderer();






if (r instanceof XYLineAndShapeRenderer) {


XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r;


renderer.setBaseShapesVisible(true);


renderer.setBaseShapesFilled(true);


}


}


/**


*


* @param periodType


* @return


*/


protected RegularTimePeriod getTimePeriod(int periodType){


switch(periodType){


case GraphConstants.PERIOD_TYPE_WEEKLY:


return new Week();


case GraphConstants.PERIOD_TYPE_MONTHLY:


return new Month();


case GraphConstants.PERIOD_TYPE_QUATERLY:


return new Quarter();


default:


return new Month();


}


}





/**


* @param dataset


* @param series


* @param item


* @return tooltip


*/


public String generateToolTip(XYDataset dataset, int series, int item) {


String tooltip;


if(item == 0){


tooltip = GraphConstants.NULL;


}else{


tooltip = " ";


}


return tooltip;


}






}



Wednesday, October 7, 2009

XWindows and Java

Often in our java code, we use AWT or SWING packages. The application runs fine in windows machines(usually development environments are in windows machines). But when we try to run those java applications in Linux/Unix box, we face problem in running. Because It uses the native graphics toolkits for rendering, but Linux/Unix doesn't have graphics toolkits installed.
XWindows is a package, when installed, gives the Linux/Unix the graphics toolkit ability.
But in most practical cases, you are not the ROOT user of the box. So you have to raise a request to infrastructure team for installing the XWindows package. And they will ask you hundreds of questions like:
why you need it?
are you sure you need it?
prove us, that XWindows will solve your problem etc etc...

You want to be very sure that installing XWindows will solve your problem. For this, you may follow these steps:
  1. CYGWIN is an application, using which you can simulate Linux like facilities in your windows machine. Install CYGWIN in your system from here. While installing, it will give you options regarding which packages you want to install. Make sure the X11 packages are all selected.
  2. Put your application jar into the remote machine, where your application is supposed to run.
  3. Open CYGWIN window and run "startxwin.bat". It will start the xserver and open a new window. Or you can directly open XWin Server from the start-menu under Cygwin-x.
  4. In the new window add the remote machine ip in the access control list. Using the command "xhost ". "xhost  /remote machine ip/ "
  5. In the remote machine set the DISPLAY property as: "export DISPLAY=/local machine ip/:0.0" . By doing this, you are directing the remote machine, to use the display of you local machine for rendering.
  6. Now run the application in you remote machine. It should run fine.
Now that you are able to run your application using XWINDOWS, you can confidently go and command Infra team, that this is exactly what you want.
If you face any issues, please post it here, I will try to help you out.
Hope this makes your life easier. Because I had a hard time convincing my Infra team.