Tech Tidbits - Ruby, Ruby On Rails, Merb, .Net, Javascript, jQuery, Ajax, CSS...and other random bits and pieces.

Sunday, April 29, 2007

Hibernate 3 Tutorial

Here's a simple Hibernate tutorial which will guide you through installation, configuration, and use of Hibernate 3.2, HSQLDB, Ant, and Java on Linux...

This is a rather contrived example and nothing you would see in the real world, but I'll probably expand on this example in later posts.

You'll need the following to run this Hibernate example:

Apache Ant
Hibernate
Hibernate Tools
Hsqldb

As of April 23, 2007, these were the latest downloads:

apache-ant-1.7.0-bin.tar.gz
hibernate-3.2.2.ga.tar.gz
HibernateTools-3.2.0.beta9a.zip
hsqldb_1_8_0_7.zip

I installed these under /usr/local on my laptop (Fedora), but you can install them anywhere that works for you.

So I ended up with this directory structure:

/usr/local/apache-ant-1.7.0
/usr/local/hibernate-3.2
/usr/local/HibernateTools
/usr/local/hsqldb

Note: Manually create the HibernateTools directory and unzip the HibernateTools zip file there.

Create a project directory where you'll place your project files. I created a project directory called "Book" in my home directory (/home/doug/Book).

Here's the project file layout:


Book -
build.properties
build.xml
classes -
data -
src -
hibernate.cfg.xml
log4j.properties
com -
dougsparling -
AddBook.java
Book.hbm.xml
Book.java
ListBooks.java


Database files will build under the data directory. The classes directory will be created during the Ant build process, so you don't need to create that directory manually.

1) Ant build script


Includes targets to create schema/database tables, prepare project files and directories, and compile java source code, as well as a target to add books to the database and another target to read books from databasae.

Book/build.xml
-------------------

<?xml version="1.0"?>
<project name="book">

<!-- properties -->
<property file="build.properties"/>

<property name="src" value="src"/>
<property name="class" value="classes"/>
<property name="data" value="data"/>
<property name="hibernate.tools"
value="${hibernate.tools.home}${hibernate.tools.path}"/>

<!-- project classpath -->
<path id="project.classpath">
<pathelement location="${src}"/>
<pathelement location="${class}"/>
<pathelement location="${hibernate.home}/hibernate3.jar"/>
<fileset dir="${hibernate.home}/lib" includes="**/*.jar"/>
<pathelement location="${hsql.home}/lib/hsqldb.jar"/>
</path>

<!-- Hibernate tools classpath -->
<path id="tools.classpath">
<path refid="project.classpath"/>
<pathelement location="${hibernate.tools}/hibernate-tools.jar"/>
</path>

<!-- task def for Hibernate Tools -->
<taskdef name="htools"
classname="org.hibernate.tool.ant.HibernateToolTask"
classpathref="tools.classpath"/>

<!-- Create runtime subdirectories -->
<target name="prepare">
<mkdir dir="${class}"/>

<!-- Copy property files and O/R mappings needed at runtime -->
<copy todir="${class}">
<fileset dir="${src}">
<include name="**/*.properties"/>
<include name="**/*.cfg.xml"/>
</fileset>
</copy>
</target>

<!-- Generate schemas for all mapping files -->
<target name="schema" depends="prepare">
<htools destdir="${data}">
<classpath refid="tools.classpath"/>
<configuration
configurationfile="${src}/hibernate.cfg.xml"/>
<hbm2ddl drop="true" outputfilename="book.sql"/>
</htools>
</target>

<!-- Compile java source code -->
<target name="compile" depends="prepare">
<javac srcdir="${src}"
destdir="${class}"
debug="on"
optimize="off"
deprecation="on"
classpathref="project.classpath"/>
</target>

<!-- Add a book (create and persist) -->
<target name="addBooks" depends="compile">
<java classname="com.dougsparling.AddBook"
classpathref="project.classpath"/>
</target>

<!-- Display persisted data -->
<target name="listBooks" depends="compile">
<java classname="com.dougsparling.ListBooks"
classpathref="project.classpath"/>
</target>

</project>


2) build.properties


This file is included in the build.xml file. build.properties contains paths to the installed libraries.

Book/build.properties
-----------------------------------------

# Path to the hibernate install directory
hibernate.home=/usr/local/hibernate-3.2

# Path to the hibernate-tools install directory
hibernate.tools.home=/usr/local/HibernateTools

# Path to hibernate-tools.jar relative to hibernate.tools.home
hibernate.tools.path=
/plugins/org.hibernate.eclipse_3.2.0.beta9a/lib/tools

# Path to the HSQL DB install directory
hsql.home=/usr/local/hsqldb


3) Hibernate configuration file


Database connection information mappings.

Book/src/hibernate.cfg.xml
--------------------------------

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.url">
jdbc:hsqldb:file:data/book;shutdown=true
</property>
<property name="hibernate.connection.driver_class">
org.hsqldb.jdbcDriver
</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.connection.pool_size">0</property>
<property name="hibernate.dialect">
org.hibernate.dialect.HSQLDialect
</property>
<property name="hibernate.show_sql">false</property>

<!-- mapping resources -->
<mapping resource="com/dougsparling/Book.hbm.xml"/>

</session-factory>
</hibernate-configuration>


4) Logging


Set up logging. You can use the file that comes in the etc directory of the HibernateTools in the unpacked archive file.

Book/src/log4j.properties

5) Book class


POJO class to represent a book

Book/src/com/dougsparling/Book.java
-----------------------------------------

package com.dougsparling;

public class Book {
private int id;
private String title;

public Book(String title) {
this.title = title;
}

Book() {
}

public int getId() {
return this.id;
}

public void setId(int id) {
this.id = id;
}

public String getTitle() {
return this.title;
}

public void setTitle(String title) {
this.title = title;
}
}


6) Object mapping for Book class



Book/src/com/dougsparling/Book.hbm.xml
-------------------------------------------

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="com.dougsparling.Book" table="book">

<id name="id" type="int" column="id">
<generator class="native"/>
</id>

<property name="title" type="string"/>

</class>
</hibernate-mapping>


7) AddBook class


Code to add a book to database

Book/src/com/dougsparling/AddBook.java
--------------------------------------------

package com.dougsparling;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.dougsparling.Book;

public class AddBook {
public static void main(String[] args) {

String title = "A Book";

SessionFactory factory =
new Configuration().configure().buildSessionFactory();
Session session = factory.openSession();
session.beginTransaction();

Book book = new Book(title);

session.save(book);
session.getTransaction().commit();
session.close();
}
}


8) ListBooks class


Code to read books from database

Book/src/com/dougsparling/ListBooks.java
----------------------------------------------

package com.dougsparling;

import java.util.Iterator;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.dougsparling.Book;

public class ListBooks {
public static void main(String[] args)
{
SessionFactory factory =
new Configuration().configure().buildSessionFactory();
Session session = factory.openSession();

List books = session.createQuery("from Book").list();
System.out.println("Found " + books.size() + " books(s):");

Iterator i = books.iterator();
while(i.hasNext()) {
Book book = (Book)i.next();
System.out.println(book.getTitle());
}

session.close();
}
}


9) Ant build


At this point it's time to run Ant against the build.xml file.


kl93@oiche:/home/kl93/Book$ ant schema
kl93@oiche:/home/kl93/Book$ ant addBooks
kl93@oiche:/home/kl93/Book$ ant listBooks

Saturday, April 28, 2007

Perl - DateTime

Our servers were recently switched from using local time to UTC. This had an affect on our content, causing it to show several hours early since content availability is based on local time. In the past we had relied on Date::Calc on other various date manipulations using epoch seconds. Having recently worked on two projects with Catalyst, I had become familiar with the Perl module DateTime. Not only was converting UTC to local time a breeze, DateTime required far fewer lines of code, not to mention the ease and readability of date manipulations.

The standard Unix date command shows the server is on UTC:

kl93@oiche/home/kl93:$ date
Sat Apr 28 13:10:15 UTC 2007


or in Perl:

my $date = localtime(time);
print "$date\n";


returns

2007-04-28T13:16:29


Now, using DateTime module:

#!/usr/bin/perl
use strict;
use DateTime;
my $dt = DateTime->now();
print $dt->datetime(), "\n";


Output:

kl93@oiche:/home/kl93$ perl datetime1.pl
2007-04-28T13:23:15


To get local time, you can either set the desired time zone when you create the DateTime object:

#!/usr/bin/perl
use strict;
use DateTime;
my $dt = DateTime->now(time_zone => 'America/Chicago');
print $dt->datetime(), "\n";


or set it after you've created the object:

#!/usr/bin/perl
use strict;
use DateTime;
my $dt = DateTime->now();
$dt->set_time_zone('America/Chicago');
print $dt->datetime(), "\n";


Now we have local time for US Central:

kl93@oiche:/home/kl93$ perl datetime2.pl
2007-04-28T08:29:56


Using a named time zone like 'America/Chicago' is nice, as it will calculate DST changes. However, it's not recommended for dates far in the future (read the Pod).

You can also use "today" in place of "now," which will only initialize the date, not the time:


#/usr/bin/perl
use strict;
use DateTime;
my $dt1 = DateTime->today();
print "dt1: ", $dt1->datetime(), "\n";
my $dt2 = DateTime->now();
print "dt2: ", $dt2->datetime(), "\n";



kl93@oiche:/home/kl93$ perl datetime3.pl
dt1: 2007-04-28T00:00:00
dt2: 2007-04-28T17:53:32


You can also initialize the DateTime object to any valid date by passing passing parameters to the constructor:

#!/usr/bin/perl
use strict;
use DateTime;
my $dt = DateTime->new( year => 2001,
month => 4,
day => 23,
hour => 10,
minute => 45,
second => 30,
time_zone => 'America/Chicago',
);
print $dt->datetime(), "\n";


We can see that the date has been initialized to April 23, 2005 at 10:45:30 (am):

kl93@oiche:/home/kl93$ perl datetime4.pl
2001-04-23T10:45:30


There are several accessors - a quick perusal of the Pod shows:

$dt->year;
$dt->month; # 1-12 - also mon
$dt->day; # 1-31 - also day_of_month, mday
$dt->day_of_week; # 1-7 (Monday is 1) - also dow, wday
$dt->hour; # 0-23
$dt->minute; # 0-59 - also min
$dt->second; # 0-61 (leap seconds!) - also sec
$dt->day_of_year; # 1-366 (leap years) - also doy
$dt->day_of_quarter; # 1.. - also doq
$dt->quarter; # 1-4


I won't cover everything, that's what the Pod is for, but a few handy features include easy date formating and date calculations.

A few formatting built-ins:

$dt->ymd; # 2007-04-28
$dt->ymd('/'); # 2007/04/28
$dt->ymd('') # 20070428

$dt->mdy; # 04-28-2007
$dt->mdy('/'); # 04/28/2007
$dt->mdy(''); # 04282007

$dt->dmy; # 28-04-200
$dt->dmy('/'); # 28/04/2007
$dt->dmy(''); # 28042007

$dt->hms; # 12:33:45


And if you need it, you can use 'strftime' for further formatting:

$dt->strftime("%A, %B %d, %Y"); # Saturday, April 28, 2007


A few date manipulations:

You can update an existing DateTime object to another date:

#!/usr/bin/perl
use strict;
use DateTime;
my $dt = DateTime->new( year => 2001,
month => 4,
day => 23,
hour => 10,
time_zone => 'America/Chicago',
);
print $dt->ymd, "\n";

$dt->set( year => 2007 );
$dt->set( month => 11 );
$dt->set( day => 30 );
print $dt->ymd, "\n";


We can see that the date was changed from 2001-04-23 to 2007-11-30:

kl93@oiche:/home/kl93$ perl datetime5.pl
2001-04-23
2007-11-30


You can find x number of years, months, days from a date by using "add" and "subtract" on your DateTime object.

To find one month from today:

#!/usr/bin/perl
use strict;
use DateTime;
my $dt = DateTime->now();
print $dt->datetime(), "\n";
print $dt->add(months => 1), "\n";


Output:

kl93@oiche:/home/kl93$ perl datetime6.pl
2007-04-28T14:05:35
2007-05-28T14:05:35


Or one month previous:

#!/usr/bin/perl
use strict;
use DateTime;
my $dt = DateTime->now();
print $dt->datetime(), "\n";
print $dt->subtract(months => 1), "\n";


Output:

kl93@oiche:/home/kl93$ perl datetime7.pl
2007-04-28T14:07:42
2007-03-28T14:07:42


One note - DateTime objects are hash references, so if you want to keep your original DateTime object unchanged, you need to clone your object and then use "add" or "subtract" to get the calculated date.

Here we simply copy $dt1 and update $dt2.

#/usr/bin/perl
use strict;
use DateTime;
my $dt1 = DateTime->now();
print "dt1: ", $dt1->datetime(), "\n";
my $dt2 = $dt1;
$dt2->add(months => 1), "\n";
print "dt2: ", $dt2->datetime(), "\n";
print "dt1: ", $dt1->datetime(), "\n";


Note that once $dt2 is modified, $dt1 is modified as well (they both "point" to the same DateTime object:

kl93@oiche:/home/kl93$ perl datetime8.pl
dt1: 2007-04-28T17:19:46
dt2: 2007-05-28T17:19:46
dt1: 2007-05-28T17:19:46


To prevent this, use the clone method to create a totally new DateTime object:

#/usr/bin/perl
use strict;
use DateTime;
my $dt1 = DateTime->now();
print "dt1: $dt1->datetime(), "\n";
my $dt2 = $dt1->clone;
$dt2->add(months => 1), "\n";
print "dt2: ", $dt2->datetime(), "\n";
print "dt1: ", $dt1->datetime(), "\n";


Now $dt1 remains unchanged:

kl93@oiche:/home/kl93$ perl datetime9.pl
dt1: 2007-04-28T17:23:39
dt2: 2007-05-28T17:23:39
dt1: 2007-04-28T17:23:39


Find out more about the DateTime module at the Perl DateTime Wiki or at CPAN (written by Dave Rolsky)

Saturday, April 21, 2007

Java/Perl - Command-line arguments

Command-line arguments are passed to a Perl program in the array @ARGV.

Perl

#!/usr/bin/perl
use strict;
use warnings;

my $num_args = @ARGV;
print "Length of \@ARGV array: $num_args\n";
for(my $i = 0; $i %lt; $num_args; $i++) {
print "Argument $i = |$ARGV[$i]|\n";
}

# another way to loop through arguments
my $count = 0;
for my $arg(@ARGV) {
print "Argument $count = |$arg|\n";
$count++;
}


Output:


[kl93@localhost ]$ perl args.pl Eeyore Piglet "Pooh Bear"
Argument 0 = |Eeyore|
Argument 1 = |Piglet|
Argument 2 = |Pooh Bear|
Length of @ARGV array: 3
Argument 0 = |Eeyore|
Argument 1 = |Piglet|
Argument 2 = |Pooh Bear|


Command-line arguments are passed to main method in a Java program. The arguments are passed as a String array called args (or whatever you may choose to call it).

Java

public class Args
{
public static void main(String[] args)
{
System.out.println("Length of args array: "
+ args.length);

for(int i = 0; i < args.length; i++)
{
System.out.println("Argument " + i + " = |" + args[i] + "|");
}
}
}


Output:


[kl93@localhost ]$ java Args Eeyore Piglet "Pooh Bear"
Length of args array: 3
Argument 0 = |Eeyore|
Argument 1 = |Piglet|
Argument 2 = |Pooh Bear|

Java/Perl - String comparison (eq)

In Perl, comparison operators are used when comparing either numbers or strings. For comparing strings, the comparison operator for equality is 'eq.' Unlike Java, Perl doesn't have a String class as Perl is a "typeless" language. However, Perl scalar variables can contain numbers or strings, so there isn't much difference between 999 (number) or '999' (string). So comparing strings in Perl for equality is fairly straight forward.

Perl

#!/usr/bin/perl
use strict;
use warnings;

my $string1 = 'Eeyore';
my $string2 = 'Eeyore';

if($string1 eq $string2) {
print "True\n";
} else {
print "False\n";
}


The output is:

True


In Java, strings are objects. In most cases when an equality comparison is made between two strings, it is the value of the two strings that we want to compare. To check if two strings have the same value, the 'equals' method is used.

Java

public class Equals
{
public static void main(String[] args)
{
String string1 = "Eeyore";
String string2 = "Eeyore";
if(string1.equals(string2))
System.out.println("True");
else
System.out.println("False");
}
}


The output is:

True


Note that with Java, there are two ways to create a new string.

  1. String string1 = "Eeyore";
  2. // informal method
  3. String string2 = new String("Eeyore");
  4. // formal method


There is a subtle difference. With the the informal method, String objects are created and the JVM places them in the "literal pool," an area in JVM memory that allows shared access to String objects. In this case, before a new String object is created, the literal pool is checked to see if an identical string already exists, and if so it is reused. If not, a new String is created and added to the literal pool. That way, if several strings are created with the same value, they all point to the same String object.

With the formal method, a new String object is created even if the same string already exists. In this case the String object is placed in the JVM general memory.

To check if two Strings point to the same object, the '==' operator is used.


public class Equals2
{
public static void main(String[] args)
{
String string1 = "Eeyore";
String string2 = "Eeyore";
String string3 = new String("Eeyore");

if(string1.equals(string2))
System.out.println("True");
else
System.out.println("False");

if(string1.equals(string3))
System.out.println("True");
else
System.out.println("False");

if(string1 == string2)
System.out.println("True");
else
System.out.println("False");

if(string1 == string3)
System.out.println("True");
else
System.out.println("False");
}
}


The output is:

True
True
True
False


This shows that string1 and string2 have the same value and point to the same String object. This also shows that while string1 and string3 have the same value, they point to different String objects.

Java/Perl - split

split breaks up (or splits) a string into "tokens" or substrings according to a separator. split uses a regular expression as the separator.

Perl


#!/usr/bin/perl
use strict;
use warnings;

my @fields = split /:/, "jim:bob:frank:steve";
foreach my $field (@fields) {
print "$field\n";
}

my $string = "one two three four\tfive";
my @array = split /\s+/, $string;
foreach my $el(@array) {
print "$el\n";
}


Output:

jim
bob
frank
steve
one
two
three
four
five


Java 1.4 added the split() method to the String class.

Java


public class Split
{
public static void main(String[] args)
{
String string1 = "jim:bob:frank:steve";
String[] names = string1.split(":");
for(int i=0; i<names.length; i++)
System.out.println(names[i]);

String string2 = "one two three four\tfive";
String[] words = string2.split("\\s+");
for(int i=0; i<words.length; i++)
System.out.println(words[i]);
}
}


It is also possible to use the java.util.StringTokenizer to break a string into tokens.


import java.util.StringTokenizer;

public class StringToke
{
public static void main(String[] args)
{
String string1 = "jim:bob:frank:steve";
StringTokenizer st1 = new StringTokenizer(string1,":");
while(st1.hasMoreTokens())
System.out.println(st1.nextToken());

String string2 = "one two three four\tfive";
StringTokenizer st2 = new StringTokenizer(string2);
while(st2.hasMoreTokens())
System.out.println(st2.nextToken());
}
}


Output:

jim
bob
frank
steve
one
two
three
four
five


If no regular expression pattern is used, split defaults to using white space as the separator. (both in Perl and Java)

Java/Perl - Directory handles

With Perl, one way to get a list of names in a given directory is to use a directory handle. On my Fedora box, Perl displays "." and ".." while Java does not.

Perl

#!/usr/bin/perl
use strict;
use warnings;

my $dir = '/home/kl93';
opendir DH, $dir or die "Cannot open $dir: $!";
foreach my $file (readdir DH) {
next if $file =~ /^\.\.?$/; # skip . and ..
print "$file\n";
}
close DH;


Java

import java.io.*;

public class ReadDir
{
public static void main(String[] args) throws Exception
{

File file = new File("/home/kl93");

if( !file.exists() || !file.canRead() )
{
System.out.println("Can't read " + file);
return;
}

if( file.isDirectory() ) {
String[] files = file.list();
for(int i=0; i<files.length; i++)
System.out.println(files[i]);
}
else {
System.out.println(file + " is not a directory");
}
}
}


If you want to display filenames based on some sort of criteria - like all files with the .java extension for example - then it's often easiest to use a regular expression.

Perl

#!/usr/bin/perl
use strict;
use warnings;

my $dir = '/home/kl93';
opendir DH, $dir or die "Cannot open $dir: $!";
foreach my $file (readdir DH) {
next unless $file =~ /\.java$/;
print "$file\n";
}
close DH;


Java

import java.io.*;
import java.util.regex.*;

public class ReadDir2
{
public static void main(String[] args) throws Exception
{

File file = new File("/home/kl93");

if( !file.exists() || !file.canRead() )
{
System.out.println("Can't read " + file);
return;
}

if( file.isDirectory() ) {
String[] files = file.list();
for(int i=0; i<files.length; i++)
{
if(files[i].matches("^.*\\.java$"))
System.out.println(files[i]);
}
}
else {
System.out.println(file + " is not a directory");
}
}
}


Or


import java.io.*;
import java.util.regex.*;

public class ReadDir3
{
public static void main(String[] args) throws Exception
{

File file = new File("/home/kl93");

if( !file.exists() || !file.canRead() )
{
System.out.println("Can't read " + file);
return;
}

if( file.isDirectory() ) {
String[] files = file.list();
Pattern pattern = Pattern.compile("\\.java$");
Matcher matcher;
for(int i=0; i<files.length; i++)
{
matcher = pattern.matcher(files[i]);
if(matcher.find())
System.out.println(files[i]);
}
}
else {
System.out.println(file + " is not a directory");
}
}
}


Sort (ascending)

Perl

#!/usr/bin/perl
use strict;
use warnings;

my $dir = '/home/kl93';
opendir DH, $dir or die "Cannot open $dir: $!";
foreach my $file (sort readdir(DH)) {
print "$file\n";
}
close DH;


Sort desending


#!/usr/bin/perl
use strict;
use warnings;

my $dir = '/home/kl93';
opendir DH, $dir or die "Cannot open $dir: $!";
foreach my $file (reverse(sort readdir(DH))) {
print "$file\n";
}
close DH;

About Me

My photo
Developer (Ruby on Rails, iOS), musician/composer, Buddhist, HSP, Vegan, Aspie.

Labels