Thursday, April 17, 2008

Update /etc/hosts with IP address assigned through DHCP

My /etc/hosts file looks something like:

127.0.0.1       localhost
127.0.1.1 shihabpc
The host name shihabpc should be mapped to my network's IP address; not to a loop back IP address like 127.0.1.1. This is some how mandatory for RMI to work properly.
But the problem is that I have used DHCP to assign IP address and that is changed from one boot to another. So I have to change the /etc/hosts file every time my IP address changes.
So, I have written a script to update /etc/hosts:
#!/bin/sh
# /home/shihab/fixhosts.sh

file=/etc/hosts
interface=eth0

ip=`ip addr show $interface`
ip=`echo "$ip" | grep "inet "`
ip=`echo "$ip" | cut -d "i" -f 2`
ip=`echo "$ip" | cut -d " " -f 2`
ip=`echo "$ip" | cut -d / -f 1`

hostname=`hostname`

found=0
while read line
do
if [ "`echo "$line" | grep $hostname`" != "" ]; then
line="$ip $hostname"
found=1
fi
if [ -z "$text" ]; then
text="$line"
else
text="$text\n$line"
fi
done < $file

if [ found = 0 ]; then
text="$text\n$ip $hostname"
fi

echo -e "$text" > $file
And added it as an init.d script:
#!/bin/sh
# /etc/init.d/fixhosts

case "$1" in
start)
/home/shihab/fixhosts.sh
;;
stop)
# do nothing ;)
;;
restart)
$0 stop
$0 start
;;
*)
echo "usage: $0 (start|stop|restart|help)"
esac
$sudo update-rc.d fixhosts defaults 99
That's it! :-)

Sunday, August 12, 2007

Close resource inside and only inside finally block

Always close any resource (network connection, database connection, file stream) inside and only inside finally block. Don't close it inside try block. What is the problem of closing it inside try block? consider the following example:

try {
String fileName = ...;
InputStream input = new FileInputStream(fileName);
// read theContentOfTheFile
input.close();
retrun theContentOfTheFile;
} catch (IOException e) {
// log the exception
return null;
}

If an exception is thrown while reading theContentOfTheFile, the FileInputStream will never be closed.

A better solution but not totally perfect:
InputStream input = null;
try {
String fileName = ...;
input = new FileInputStream(fileName);
// read theContentOfTheFile
input.close();
retrun theContentOfTheFile;
} catch (IOException e) {
// log the exception
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
// do nothing
}
}
}

If no exception is thrown inside the try block, then before returning from the method the finally block will also be executed. That means we are trying to close the same stream twice. So, an exception will always be thrown form the input.close() inside the finally block.

The best solution:
InputStream input = null;
try {
String fileName = ...;
input = new FileInputStream(fileName);
// read theContentOfTheFile
retrun theContentOfTheFile;
} catch (IOException e) {
// log the exception
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
// do nothing
}
}
}

In this example the input.close() is granted to be executed once and only once.

Tuesday, July 24, 2007

Use System.currentTimeMillis() instead of Date or Calendar

Always try to use System.currentTimeMillis() instead of java.util.Date or java.util.Calendar.

Why?

Because of performance. Date and Calendar internally calls System.currentTimeMillis(). So, why not use it directly?

A BAD example:

long currentTime = Calendar.getInstance().getTimeInMillis();
So, what does Calendar.getInstance() actually do? Following lines are just copied from the source code of jdk1.5:
public static Calendar getInstance()
{
Calendar cal = createCalendar(TimeZone.getDefaultRef(),
Locale.getDefault());
cal.sharedZone = true;
return cal;
}

private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
if ("th".equals(aLocale.getLanguage()) &&
("TH".equals(aLocale.getCountry()))) {
return new sun.util.BuddhistCalendar(zone, aLocale);
}
return new GregorianCalendar(zone, aLocale);
}

public GregorianCalendar(TimeZone zone, Locale aLocale) {
super(zone, aLocale);
gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
setTimeInMillis(System.currentTimeMillis());
}
Have you got it? Calendar.getInstance() checks TimeZone, Locale and of course System.currentTimeMillis(). So, it's an expensive operation.

Another bad example:
Date date = new Date(System.currentTimeMillis());
Why is it bad? Because, it should be as simple as:
Date date = new Date();
And, here is the apidoc of default constructor of Date:
Allocates a Date object and initializes it so that
it represents the time at which it was allocated,
measured to the nearest millisecond.
Yet, another bad example:
Date date = Calendar.getInstance().getTime();
Now, when should we use System.currentTimeMillis():
When we need only the millisecond representation of the current time.

When should we use Date: When we need a date object representing the current time.

When should we use Calendar.getInstance(): When we need TimeZone or Locale specific information. Another use of Calender can be for creating constant Date object:
public static final Date INDEPENDENCE_DAY;

static {
Calendar calendar = Calendar.getInstance();
calendar.set(1971, Calendar.MARCH, 26);
INDEPENDENCE_DAY = calendar.getTime();
}