Ora che ero in possesso di una struttura per il mio progetto avevo bisogno di identificare gli "attori" che avrebbero popolato il mio database. Ho deciso, quindi, di creare una piccola applicazione java per costruire il database facendo uso di Hibernate e dei suoi file di mappatura.
Le tabelle di cui avrei avuto bisogno sarebbero state: User, Order, Product.
Ecco la classe che ho utilizzato per caricare i file .hbm.xml e generare così la struttura per il mio database.
public class SchemaGenerator
{
// System constants for the current platform directory token
static String fileSep = System.getProperty("file.separator");
// We use this session factory to create our sessions
public static SessionFactory sessionFactory;
static String[] db_dialects = {"Mysql", "org.hibernate.dialect.MySQL5InnoDBDialect",};
public static void main(String[] args)
{
initialization();
}
/**
* Loads the Hibernate configuration information, sets up the
* database and the Hibernate session factory.
*/
public static void initialization()
{
System.out.println("initialization");
try
{
Configuration myConfiguration = new Configuration();
/**
* Insert here your beans classes for which you want to generate the SQL script
* one for each bean for each table
**/
myConfiguration.addClass(main.Product.class);
myConfiguration.addClass(main.User.class);
myConfiguration.addClass(main.Order.class);
Properties myProperties = new Properties();
for (int i = 0; i < db_dialects.length; i = i + 2)
{
String dialect_name = db_dialects[i];
String dialect_class = db_dialects[i + 1];
String dialect_file = dialect_name.toLowerCase();
dialect_file = dialect_file.replace(' ', '_');
dialect_file += (".sql");
System.out.println("Generating " + dialect_name);
// Note that this is the only Hibernate property
// set. In particular, there is no JDBC
// connectivity data, nor are we specifying a
// driver!
myProperties.put("hibernate.dialect", dialect_class);
try
{
// Load the *.hbm.xml files as set in the
// config, and set the dialect.
SchemaExport mySchemaExport = new SchemaExport(myConfiguration, myProperties);
mySchemaExport.setDelimiter(";");
// Despite the name, the generated create
// scripts WILL include drop statements at
// the top of the script!
mySchemaExport.setOutputFile("/...your path.../create_"+ dialect_file);
mySchemaExport.create(false, false) ;
// Generates DROP statements only
mySchemaExport.setOutputFile("/...your path.../drop_"+ dialect_file);
mySchemaExport.drop(false, false);
System.out.println(dialect_name + " OK.");
} catch (Exception e)
{
e.printStackTrace();
System.out.println(e.getMessage());
}
}
} catch (Exception e)
{
e.printStackTrace();
}
}
}
Di seguito un esempio di file .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">
<!-- Generated 17-nov-2010 15.44.15 by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="main.Order" table="orders">
<id name="orderId" type="java.lang.Long">
<column name="order_id" />
<generator class="increment" />
</id>
<many-to-one name="userId" class="main.User" cascade="all" lazy="false">
<column name="user" />
</many-to-one>
<property name="totalCost" type="int">
<column name="total_cost" />
</property>
<property name="date" type="java.lang.String">
<column name="order_date" />
</property>
<set name="products" table="order_product" cascade="all" lazy="false">
<key column="order_id"/>
<many-to-many column="product_code" class="main.Product" />
</set>
<property name="deleted" type="boolean">
<column name="deleted" length="0" />
</property>
</class>
</hibernate-mapping>
La classe Product altro non è che un semplice bean.
Una volta creato il database MySql ho importato il file generato dall'applicazione.
Attenzione a quando utilizzate parole come "Order" o "date" all'interno dei vostri file di mappatura poichè sono parole riservate per MySql e quando tenterete di importare gli schema generati vi verranno restituiti messaggi d'errore.
Nel mio database ora avevo le tabella Orders, Products, Users e una tabella di join tra Orders e Products. Quindi ho creato una nuova connessione con il database da NetBeans (Servizi --> Database --> New Connection). Finalmente potevo iniziare ad inserire i primi file di configurazione all'interno di NetBeans.
Pulsante destro sul modulo ejb: Nuovo --> Altro --> Persistenza --> Schema Database (ho inserito la connessione al db appena creata). Quindi ho creato anche un'unità di persistenza (stesso percorso di prima). Di seguito come si presenta il mio file di configurazione con una piccola aggiunta per poter utilizzare Hibernate:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="WiiShop-ejbPU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/wiishopDS</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="hibernate.connection.isolation" value="RepeatableRead"/>
</properties>
</persistence-unit>
</persistence>
Nella stessa posizione ho dovuto copiare a mano il file jboss-ds.xml che riporto di seguito.
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>wiishopDS</jndi-name>
<connection-url>jdbc:mysql://localhost/WiiShop</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password/>
<min-pool-size>5</min-pool-size>
<max-pool-size>20</max-pool-size>
<idle-timeout-minutes>5</idle-timeout-minutes>
<transaction-isolation>TRANSACTION_REPEATABLE_READ</transaction-isolation>
</local-tx-datasource>
</datasources>
Purtroppo esso viene generato dentro setup, ma una volta che farete deploy il server non troverà questo file e restituirà eccezione. Ho perso molto tempo per capire il motivo di questo problema che potrebbe essere dovuto al fatto che NetBeans si aspetta di lavorare con JBoss 4 e non 5. Spostandolo dalla cartella setup a src/conf non ho più avuto problemi.
A questo punto ero già in grado di generare le mie entità dal database. Ho creato un package e cliccando con il destro su di esso ho scelto Nuovo --> Classi Entità dal Database. Niente di più semplice per ottenere le entità corrette con tutte le opportune annotazioni.
Un consiglio: fate partire JBoss 5 da shell separatamente da NetBeans. Per fare deploy non dovrete far altro che pulire e costruire l'applicazione JEE. Copiare il file .ear (generato dentro dist) all'interno di JBoss5/server/default/deploy. In un attimo JBoss si accorgerà del file e lo caricherà. Ogni tanto ricordate anche di cancellare un po' di file da JBoss5/server/default/tmp.