Hibernate 3.x - simple example



Hibernate 3.x example - persisting an object in a command-line application

This is a small hibernate example, which may be run from command-line. You'll need: When run, the program example will create the table used by hibernate through standard JDBC (I know, mixing system-dependant JDBC and Hibernate is not appropriate - but it simplefies setup, not requirering SQL to be run from the database adm. command console). In any case, I personally always keep a piece of propritary JDBC code somewhere, to setup the database - and learned that a lot of other people do this also.

Hibernate has the advantage of supporting a large number of different databases through 'dialects' - and the choice of 'pointbase' for this example should have no practical importance for the example usability.

The setup consist of:


Let's check out the specifics:

Client runtime
PersistanceClient.java

/**
 *
 * Client - setting up the table required by Hibernate through JDBC
 * - then creating a couple of Hibernate objects - doing manipulation
 * - finally shuts down by cleaning database (removing table).
 *
 */
package dk.topsecurity.hibernate;

import javax.naming.*;
import java.util.*;
import java.sql.*;
import org.apache.log4j.Logger;
import org.hibernate.*;

public class PersistanceClient {

          //JDBC properties for database-specific setup
        static final String DB_DRIVER = "com.pointbase.jdbc.jdbcUniversalDriver";
        static final String DB_URL  = "jdbc:pointbase:server://localhost:9092/topsecdb";
        static final String DB_USER = "testuser";
        static final String DB_PASS = "testpassword";
        static final String DB_MAKE_TABLE = "CREATE TABLE persistancetest (    id INTEGER NOT NULL,  name VARCHAR(250) default NULL,  value VARCHAR(250) default NULL,  PRIMARY KEY  (id))";
        static final String DB_DEL_TABLE = "drop table persistancetest";
        static Connection connection = null;
        static Statement stmt = null;


        private static Logger log = Logger.getLogger(PersistanceClient.class);

        public static void main(String[] args) {
                System.out.println("PersistanceClient starting!");

                doTable(DB_MAKE_TABLE);
                doHibernate();
                doTable(DB_DEL_TABLE);
        }

        private static void doTable(String stm) {

                System.out.println("Attempting command: "+stm);

                try {
                    System.out.println("Database="+DB_URL);
                    Class.forName(DB_DRIVER).newInstance();
                    connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
                    System.out.println("user="+DB_USER);
                    System.out.println("password="+DB_PASS);

                    connection.setAutoCommit(false);
                    stmt = connection.createStatement();

                    try {
                        PreparedStatement ps = connection.prepareStatement(stm);
                        ps.execute();
                        ps.close();
                    } catch (SQLException e) {
                        throw e;
                    }
                    stmt.close();
                    connection.commit();
                    connection.setAutoCommit(true);
                    connection.close();
                    System.out.println("Successfully completed SQL");
                } catch (Exception e) {
                        System.out.println("ExecuteSQLScript.runScript()"
                                        + ":Unable to execute script"
                                        + e.getMessage());
                        if (e instanceof SQLException) {
                                System.out.println("SQLException : "
                                                + ((SQLException) e).getSQLState());
                        }
                }
        }


        private static void doHibernate() {
                  //create two objects
                PersistanceObject testObj1 = new PersistanceObject("testname1","testvalue1");
                PersistanceObject testObj2 = new PersistanceObject("testname2","testvalue2");
                createPersistanceObject(testObj1);
                createPersistanceObject(testObj2);
                  //show how id's have been assigned...
                log.debug(">>>Having assigned testObj1.Id="+testObj1.getId()+", testObj2.Id="+testObj2.getId());
                listPersistanceObject();
                  //manipulation
                deletePersistanceObject(testObj1);
                  //show manipulation effects
                listPersistanceObject();
        }


        private static void listPersistanceObject() {
                Transaction tx = null;
                Session session = ThreadsafeSessionFactory.getInstance().getCurrentSession();
                try {
                        tx = session.beginTransaction();
                        List objs = session.createQuery("select o from PersistanceObject as o").list();
                        for (Iterator iter = objs.iterator(); iter.hasNext();) {
                                PersistanceObject element = (PersistanceObject) iter.next();
                                log.debug(">>>Id="+element.getId()+", name="+element.getName()+", value="+element.getValue());
                        }
                        tx.commit();
                } catch (HibernateException ex) {
                        ex.printStackTrace();
                        if (tx != null && tx.isActive())
                                tx.rollback();

                }
        }


        private static void deletePersistanceObject(PersistanceObject obj) {
                Transaction tx = null;
                Session session = ThreadsafeSessionFactory.getInstance().getCurrentSession();
                try {
                        tx = session.beginTransaction();
                        session.delete(obj);
                        tx.commit();
                } catch (HibernateException ex) {
                        ex.printStackTrace();
                        if (tx != null && tx.isActive())
                                tx.rollback();
                }
        }

        private static void createPersistanceObject(PersistanceObject obj) {
                Transaction tx = null;
                Session session = ThreadsafeSessionFactory.getInstance().getCurrentSession();
                try {
                        tx = session.beginTransaction();
                        session.save(obj);
                        tx.commit();
                } catch (HibernateException ex) {
                        ex.printStackTrace();
                        if (tx != null && tx.isActive())
                                tx.rollback();
                }
        }


}

This runtime client does the practical work while demonstrating Hibernate. The rest of the files are mostly support setup related.


Client persisted class
PersistanceObject.java

/**
 * Object being persisted by Hibernate in the database according to the
 * standard mapping file.
 */

package dk.topsecurity.hibernate;

public class PersistanceObject {
  private Integer id;
  private String name;
  private String value;

  public PersistanceObject() {}

  public PersistanceObject(String n, String v) { name=n; value=v; }

  public Integer getId() { return id; }

  public void setId(Integer i) { id = i; }

  public String getName() { return name; }

  public void setName(String n) { name = n; }

  public String getValue() { return value; }

  public void setValue(String val) { value = val; }
}

I know, it's rather short on comments. But it's usage is rather simple. Just need to contain a field for a primary key (id) used for 1-to-1 mapping with regard to the database - and a couple of other fields name, value carrying realistic payload to manipulate.


Client factory - threadsafe accessing Hibernate org.hibernate.SessionFactory
ThreadsafeSessionFactory.java

/**
 * Threadsafe factory - a little overkill for a single-thread
 * command-line example - but required in a web container, where we don't
 * want parallel processes persisting different values in the same
 * physical table.
 */
package dk.topsecurity.hibernate;

import javax.naming.InitialContext;

import org.apache.log4j.Logger;
import org.hibernate.*;
import org.hibernate.cfg.*;

public class ThreadsafeSessionFactory {

        private static Logger log = Logger.getLogger(ThreadsafeSessionFactory.class);
        private static String CONFIG_FILE = "hibernate.cfg.xml";
        private static final Configuration cfg = new Configuration();
        private static org.hibernate.SessionFactory sessionFactory;

        public static synchronized SessionFactory getInstance() {
                if (sessionFactory == null)
                        initFactory();
                return sessionFactory;
        }

        public Session openSession() {
                return sessionFactory.getCurrentSession();
        }

        public Session getCurrentSession() {
                return sessionFactory.getCurrentSession();
        }

        private static void initFactory() {
                if (sessionFactory == null) {
                         try {
                                cfg.configure(CONFIG_FILE);
                                String factoryJndiName = cfg.getProperty(Environment.SESSION_FACTORY_NAME);
                                if (factoryJndiName != null) {
                                        log.debug("using jndi factory");
                                        cfg.buildSessionFactory();
                                        sessionFactory = (SessionFactory) (new InitialContext()).lookup(factoryJndiName);
                                } else{
                                        log.debug("using default factory");
                                        sessionFactory = cfg.buildSessionFactory();
                                }

                        } catch (Exception ex) {
                                ex.printStackTrace();
                                System.err.println("failed creating session factory");
                                throw new HibernateException("failed initializing configuration");
                        }
                }
        }
 
        public static void close(){
                if (sessionFactory != null)
                        sessionFactory.close();
                sessionFactory = null;
 
        }
}

As mentioned in the past, the example could do without any threadsafe handling of org.hibernate.SessionFactory in a single-thread command-line situation. But in most practical cases it is required to apply the factory pattern to make sure that parallel thread (fx. in a web container doesn't mess up persistance to the database). Hibernate itself is threadsafe, so it would be a shame not to carry through this ability at the application layer.

This completed the client code. Remaining is the Hibernate setup files.

Hibernate setup file - defining which database - how to access - etc.
hibernate.cfg.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="connection.url">jdbc:pointbase:server://localhost:9092/topsecdb</property>
    <property name="connection.username">testuser</property>
    <property name="connection.driver_class">com.pointbase.jdbc.jdbcUniversalDriver</property>
    <property name="dialect">org.hibernate.dialect.PointbaseDialect</property>
    <property name="connection.password">testpassword</property>
    <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>

<!-- thread is alias for org.hibernate.context.ThreadLocalSessionContext
     and will let Hibernate bind the session automatically to the thread
  -->

    <property name="current_session_context_class">thread</property>

    <!-- show all sql statements -->
    <property name="hibernate.show_sql">true</property>
    <!-- name of mapping file, somewhere in classpath -->
    <mapping resource="PersistanceObject.hbm.xml" />
  </session-factory>
</hibernate-configuration>

This file need to be in classpath when running the application using Hibernate. In this example, it is copied by the build.xml to approprirate location. Don't worry, you will figure out very quickly if it don't end up in the appropriate place. It is perfectly possible to configure Hibernate from a properties file "hibernate.properties" instead. Hibernate will scan classpath for both kinds of files. That was normally used for Hibernate 2.x and beyond.

The hibernate.cfg.xml makes a reference to another file PersistanceObject.hbm.xmlwith the database mapping, which should also be contained in classpath. It is perfectly possible to change the name of this file as long as the reference in hibernate.cfg.xml and the actual filename is kept synchronized.


Hibernate setup file - defining database mapping from Java object to database table entries
hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
  <class name="dk.topsecurity.hibernate.PersistanceObject" table="persistancetest">
    <id name="id" column="id" type="java.lang.Integer">
      <generator class="increment"/>
    </id>
    <property name="name" column="name" type="java.lang.String" />
    <property name="value" column="value" type="java.lang.String" />
  </class>
</hibernate-mapping>

In the case above, we let Hibernate set the primary key using seting <generator class="increment"/>. It is possible to let the database automaticly generate unique primary keys instead <generator class="native"/>. But this requires that the database (driver) support this (which appeared not to be the case for Pointbase here). You could also specify a specific sequence to use for the primary key (which I primarily used with Oracle with: <generator class="sequence"><param name="sequence">sequence_name_id_seq</param></generator> . For simple examples such as this, I found <generator class="increment"/> should work more uncomplicated with most types of databases.


log4j setup
log4j.properties

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=debug, stdout
log4j.logger.org.hibernate=info

### log just the SQL
log4j.logger.org.hibernate.SQL=debug

### log JDBC bind parameters ###
log4j.logger.org.hibernate.type=info

### log schema export/update ###
log4j.logger.org.hibernate.tool.hbm2ddl=info

### log cache activity ###
log4j.logger.org.hibernate.cache=info

log4j need no further introduction. I'm sure you're all familier with it. Otherwise troubleshooting Hibernate applications might turn out as... quite a challenge :)

Finally we need just the buildfile to compile and run the example. A small detail is how the buildfile demonstrates building classpath by adding all .jar files in certain directories. This avoids tediously listing all sort of relevant .jar files.


ant build file
build.xml


<project name="TopsecurityHibernate" default="all" basedir=".">

  <target name="init">
	<echo>+ ===================================================== +</echo>
	<echo>+                                                       +</echo>
	<echo>+  Init                                                 +</echo>
	<echo>+                                                       +</echo>
	<echo>+ ===================================================== +</echo>

        <property name="compiler.debug" value="off"/>
        <property name="compiler.type" value="modern"/>

        <!-- set global properties for this build -->
        <property name="build.java.dir" value="./src"/>
        <property name="build.class.dir" value="./classes"/>
        <property name="libhibdir" value="./libhib"/>
        <property name="libdbdir" value="./libdb"/>
        <property name="libmiscdir" value="./libmisc"/>

        <path id="project.class.path">
    		<fileset dir="${libhibdir}"             includes="**/*.jar" />
    		<fileset dir="${libdbdir}"              includes="**/*.jar" />
    		<fileset dir="${libmiscdir}"            includes="**/*.jar" />
        </path>


  </target>

  <target name="clean" depends="init">
    <delete dir="${compiledir}" />
  </target>

  <target name="build" depends="clean">
  
	<echo>+ ===================================================== +</echo>
	<echo>+                                                       +</echo>
	<echo>+  Compiling                                            +</echo>
	<echo>+                                                       +</echo>
	<echo>+ ===================================================== +</echo>
		
       	<mkdir dir="${build.class.dir}" />

      	<javac
            destdir="${build.class.dir}"
            debug="${compiler.debug}" 
            deprecation="${compiler.deprecation}"
            compiler="${compiler.type}"
            classpathref="project.class.path"
        >
          <src path="${build.java.dir}" />
        </javac>
        <copy todir="${build.class.dir}">
        	<fileset dir="${build.java.dir}" includes="**/*.properties" />
        	<fileset dir="${build.java.dir}" includes="**/*.xml" />
        </copy>
    
  </target>


  <target name="runtest" depends="init">
  
	<echo>+ ===================================================== +</echo>
	<echo>+                                                       +</echo>
	<echo>+  Running                                              +</echo>
	<echo>+                                                       +</echo>
	<echo>+  project.class.path=${project.class.path}                                                     +</echo>
	<echo>+ ===================================================== +</echo>

         <java classname="dk.topsecurity.hibernate.PersistanceClient"
             classpathref="project.class.path">
           <classpath>
             <pathelement path="${build.class.dir}"/>
           </classpath>

         </java>
  </target>
  <target name="all" depends="clean,build" />
</project>

It should be noted that the buildfile has two targets - default is compilation - and 'runtest' is running the application (actually depending on previous successfull compilation).

1) To get started, we need to compile using "ant" from the commandline:



It actually copies 3 files to the build drectory .\classes - but that's really another story...

2) Next, you better get Pointbase started. Different ways to do this. I normally locate my BEA Weblogic <BEA_HOME>\weblogic<version>\common\bin\startPointbase.cmd and possibly use -port=9092 if the port comes out wrong the first time (and perhaps you get a [java] java.sql.SQLException: SQL-server rejected establishment of SQL-connection. Pointbase Server may not be running on localhost at port 9092 later on:



3) Then start the database administration console using <BEA_HOME>\weblogic<version>\common\bin\startPointBaseConsole.cmd and define a new database according to properties previously provided in hibernate.cfg.xml (I could give them here again - but I think it is better for you to doublecheck yourself):



4) After a little while, you should get a confimation that the database has been created - which is pritty essential for further progress in this example.



5) Run the example using "ant runtest" from commandline:

stdout from running example
"ant runtest"

Buildfile: build.xml

init:
     [echo] + ===================================================== +
     [echo] +                                                       +
     [echo] +  Init                                                 +
     [echo] +                                                       +
     [echo] + ===================================================== +

runtest:
     [echo] + ===================================================== +
     [echo] +                                                       +
     [echo] +  Running                                              +
     [echo] +                                                       +
     [echo] +  project.class.path=${project.class.path}                                                     +
     [echo] + ===================================================== +
     [java] PersistanceClient starting!
     [java] Attempting command: CREATE TABLE persistancetest (    id INTEGER NOT NULL,  name VARCHAR(250) default NULL,  value VARCHAR(250) default NULL,  PRIMARY KEY  (id))
     [java] Database=jdbc:pointbase:server://localhost:9092/topsecdb
     [java] user=testuser
     [java] password=testpassword
     [java] Successfully completed SQL
     [java] 23:59:21,656  INFO Environment:479 - Hibernate 3.1.3
     [java] 23:59:21,718  INFO Environment:509 - hibernate.properties not found
     [java] 23:59:21,718  INFO Environment:525 - using CGLIB reflection optimizer
     [java] 23:59:21,718  INFO Environment:555 - using JDK 1.4 java.sql.Timestamp handling
     [java] 23:59:21,890  INFO Configuration:1308 - configuring from resource: hibernate.cfg.xml
     [java] 23:59:21,906  INFO Configuration:1285 - Configuration resource: hibernate.cfg.xml
     [java] 23:59:23,875  INFO Configuration:469 - Reading mappings from resource: PersistanceObject.hbm.xml
     [java] 23:59:24,140  INFO HbmBinder:309 - Mapping class: dk.topsecurity.hibernate.PersistanceObject -> persistancetest
     [java] 23:59:24,171  INFO Configuration:1419 - Configured SessionFactory: null
     [java] 23:59:24,187 DEBUG ThreadsafeSessionFactory:? - using default factory
     [java] 23:59:24,343  INFO DriverManagerConnectionProvider:41 - Using Hibernate built-in connection pool (not for production use!)
     [java] 23:59:24,343  INFO DriverManagerConnectionProvider:42 - Hibernate connection pool size: 20
     [java] 23:59:24,343  INFO DriverManagerConnectionProvider:45 - autocommit mode: false
     [java] 23:59:24,359  INFO DriverManagerConnectionProvider:80 - using driver: com.pointbase.jdbc.jdbcUniversalDriver at URL: jdbc:pointbase:server://localhost:9092/topsecdb
     [java] 23:59:24,359  INFO DriverManagerConnectionProvider:86 - connection properties: {user=testuser, password=****}
     [java] 23:59:24,437  INFO SettingsFactory:77 - RDBMS: PointBase, version: 4.4 ECF build 274
     [java] 23:59:24,437  INFO SettingsFactory:78 - JDBC driver: PointBase JDBC Driver, version: 4.4 ECF build 274
     [java] 23:59:24,484  INFO Dialect:103 - Using dialect: org.hibernate.dialect.PointbaseDialect
     [java] 23:59:24,500  INFO TransactionFactoryFactory:34 - Transaction strategy: org.hibernate.transaction.JDBCTransactionFactory
     [java] 23:59:24,515  INFO TransactionManagerLookupFactory:33 - No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
     [java] 23:59:24,515  INFO SettingsFactory:125 - Automatic flush during beforeCompletion(): disabled
     [java] 23:59:24,515  INFO SettingsFactory:129 - Automatic session close at end of transaction: disabled
     [java] 23:59:24,515  INFO SettingsFactory:144 - Scrollable result sets: enabled
     [java] 23:59:24,515  INFO SettingsFactory:152 - JDBC3 getGeneratedKeys(): enabled
     [java] 23:59:24,531  INFO SettingsFactory:160 - Connection release mode: auto
     [java] 23:59:24,531  INFO SettingsFactory:187 - Default batch fetch size: 1
     [java] 23:59:24,531  INFO SettingsFactory:191 - Generate SQL with comments: disabled
     [java] 23:59:24,531  INFO SettingsFactory:195 - Order SQL updates by primary key: disabled
     [java] 23:59:24,531  INFO SettingsFactory:338 - Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
     [java] 23:59:24,546  INFO ASTQueryTranslatorFactory:24 - Using ASTQueryTranslatorFactory
     [java] 23:59:24,546  INFO SettingsFactory:203 - Query language substitutions: {}
     [java] 23:59:24,546  INFO SettingsFactory:209 - Second-level cache: enabled
     [java] 23:59:24,546  INFO SettingsFactory:213 - Query cache: disabled
     [java] 23:59:24,546  INFO SettingsFactory:325 - Cache provider: org.hibernate.cache.EhCacheProvider
     [java] 23:59:24,562  INFO SettingsFactory:228 - Optimize cache for minimal puts: disabled
     [java] 23:59:24,562  INFO SettingsFactory:237 - Structured second-level cache entries: disabled
     [java] 23:59:24,578  INFO SettingsFactory:257 - Echoing all SQL to stdout
     [java] 23:59:24,593  INFO SettingsFactory:264 - Statistics: disabled
     [java] 23:59:24,593  INFO SettingsFactory:268 - Deleted entity synthetic identifier rollback: disabled
     [java] 23:59:24,609  INFO SettingsFactory:283 - Default entity-mode: pojo
     [java] 23:59:24,718  INFO SessionFactoryImpl:154 - building session factory
     [java] 23:59:24,734 DEBUG CacheManager:191 - Creating new CacheManager with default config
     [java] 23:59:24,750 DEBUG CacheManager:164 - Configuring ehcache from classpath.
     [java] 23:59:24,796  WARN Configurator:126 - No configuration found. Configuring ehcache from ehcache-failsafe.xml found in the classpath: jar:file:/C:/hibernate/examples/commandline/libmisc/ehcache-1.1.jar!/ehcache-failsafe.xml
     [java] 23:59:24,828 DEBUG Configuration$DiskStore:185 - Disk Store Path: C:\DOCUME~1\Ejer\LOCALS~1\Temp\
     [java] 23:59:26,062  INFO SessionFactoryObjectFactory:82 - Not binding factory to JNDI, no JNDI name configured
     [java] 23:59:26,312 DEBUG SQL:346 - select max(id) from persistancetest
     [java] Hibernate: select max(id) from persistancetest
     [java] 23:59:26,406 DEBUG SQL:346 - insert into persistancetest (name, value, id) values (?, ?, ?)
     [java] Hibernate: insert into persistancetest (name, value, id) values (?, ?, ?)
     [java] 23:59:26,437 DEBUG SQL:346 - insert into persistancetest (name, value, id) values (?, ?, ?)
     [java] Hibernate: insert into persistancetest (name, value, id) values (?, ?, ?)
     [java] 23:59:26,437 DEBUG PersistanceClient:? - >>>Having assigned testObj1.Id=1, testObj2.Id=2
     [java] 23:59:26,890 DEBUG SQL:346 - select persistanc0_.id as id0_, persistanc0_.name as name0_, persistanc0_.value as value0_ from persistancetest persistanc0_
     [java] Hibernate: select persistanc0_.id as id0_, persistanc0_.name as name0_, persistanc0_.value as value0_ from persistancetest persistanc0_
     [java] 23:59:26,921 DEBUG PersistanceClient:? - >>>Id=1, name=testname1, value=testvalue1
     [java] 23:59:26,921 DEBUG PersistanceClient:? - >>>Id=2, name=testname2, value=testvalue2
     [java] 23:59:26,937 DEBUG SQL:346 - delete from persistancetest where id=?
     [java] Hibernate: delete from persistancetest where id=?
     [java] 23:59:26,968 DEBUG SQL:346 - select persistanc0_.id as id0_, persistanc0_.name as name0_, persistanc0_.value as value0_ from persistancetest persistanc0_
     [java] Hibernate: select persistanc0_.id as id0_, persistanc0_.name as name0_, persistanc0_.value as value0_ from persistancetest persistanc0_
     [java] 23:59:26,968 DEBUG PersistanceClient:? - >>>Id=2, name=testname2, value=testvalue2
     [java] Attempting command: drop table persistancetest
     [java] Database=jdbc:pointbase:server://localhost:9092/topsecdb
     [java] user=testuser
     [java] password=testpassword
     [java] Successfully completed SQL

BUILD SUCCESSFUL
Total time: 9 seconds

Looking closely you first see the >>>Having assigned testObj1.Id=1, testObj2.Id=2 indicating that Hibernate correctly took care of primary key for the two persisted objects. Subsequently with >>>Id=1, name=testname1, value=testvalue1 (and for Id=2) it is visible how both objects are first accessible from the database - and after the first objects is deleted in the code, only the latter remain.

This pritty much concludes this primitive Hibernate example. It has been demonstrated, how to persiste an object to a database using Hibernate - retrieving and manipulating the object - using Hibernate xml setup files

/topsecurity.dk 2006-10-17

Ressources: