Hibernate, Spring, Google Web Toolkit – Part Two
Firstly in the previous example I mentioned that you should make it a true web app with WEB-INF folders etc, this has to then be reflected in the Google compile
and launch script examples given below:
MyApplication.launch
<?xml version="1.0" encoding="UTF-8"?> <launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication"> <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.GWTShell"/> <listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> <listEntry value="<?xml version='1.0' encoding='UTF-8'?><runtimeClasspathEntry containerPath='org.eclipse.jdt.launching.JRE_CONTAINER' javaProject='TheProject' path='1' type='4'/>"/> <listEntry value="<?xml version='1.0' encoding='UTF-8'?><runtimeClasspathEntry internalArchive='/TheProject/WEB-INF/src' path='3' type='2'/>"/> <listEntry value="<?xml version='1.0' encoding='UTF-8'?><runtimeClasspathEntry id='org.eclipse.jdt.launching.classpathentry.defaultClasspath'><memento project='TheProject'/></runtimeClasspathEntry>"/> <listEntry value="<?xml version='1.0' encoding='UTF-8'?><runtimeClasspathEntry externalArchive='/Yourpath/gwt-mac-1.4.60/gwt-dev-mac.jar' path='3' type='2'/>"/> </listAttribute> <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XstartOnFirstThread"/> <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out www com.company.MyApplication/MyApplication.html"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="TheProject"/> <booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/> </launchConfiguration>
MyApplication-compile
#!/bin/sh APPDIR=`dirname $0`; java -XstartOnFirstThread -cp "$APPDIR/WEB-INF/src:$APPDIR/WEB-INF/classes:/yourpath/gwt-mac-1.4.60/gwt-user.jar:/yourpath/gwt-mac-1.4.60/gwt-dev-mac.jar" com.google.gwt.dev.GWTCompiler -out "$APPDIR/www" "$@" com.company.MyApplication;
MyApplication-shell
#!/bin/sh APPDIR=`dirname $0`; java -XstartOnFirstThread -cp "$APPDIR/WEB-INF/src:$APPDIR/WEB-INF/classes:/Yourpath/gwt-mac-1.4.60/gwt-user.jar:/Yourpath/gwt-mac-1.4.60/gwt-dev-mac.jar" com.google.gwt.dev.GWTShell -out "$APPDIR/www" "$@" com.company.MyApplication/MyApplication.html;
Right moving on to part two of the tutorial as a couple of people have asked me to follow this so thought I should pull my finger out….
First off all our testdatabase – again this is made using Postgresql and the DB can be made either using a tool such as PgAdmin III and/or running
the following SQL commands. Note : Alter the priviledges etc as needed.
CREATE DATABASE testdatabase WITH ENCODING='SQL_ASCII' TEMPLATE=template1 TABLESPACE=pg_default;
That creates the Database now the tables. It seems like a Teacher to Pupil is a good example to use. One teacher has many pupils and this allows
us to show Hibenrate Collection and Mapping throughly as well.
CREATE SEQUENCE teacher_seq INCREMENT 1 START 1; ALTER TABLE teacher_seq OWNER TO postgres; CREATE SEQUENCE pupil_seq INCREMENT 1 START 1; ALTER TABLE pupil_seq OWNER TO postgres; CREATE TABLE teacher ( teacher_id int4 NOT NULL, name varchar, CONSTRAINT teacher_pkey PRIMARY KEY (teacher_id) USING INDEX TABLESPACE pg_default ) WITHOUT OIDS TABLESPACE pg_default; ALTER TABLE teacher OWNER TO postgres; CREATE TABLE pupil ( pupil_id int4 NOT NULL, name varchar, teacher_id int4 NOT NULL, CONSTRAINT pupil_pkey PRIMARY KEY (pupil_id), CONSTRAINT teacher_pupil_fkey FOREIGN KEY (teacher_id) REFERENCES teacher (teacher_id) ON UPDATE NO ACTION ON DELETE NO ACTION ) WITHOUT OIDS; ALTER TABLE pupil OWNER TO postgres;
Right so thats our tables made without any data and referenced accordingly. Again please change these as necessary.
Now you need to map these using Hibernate Annotations. Make the package com.company.server.persistent.
Add a java classes called Teacher and Pupil for our persistent objects. Code show below
package com.company.server.persistent; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.SequenceGenerator; import javax.persistence.Table; @Entity @SequenceGenerator( name="TEACHER_SEQ", sequenceName="teacher_seq" ) @Table(name="teacher") public class Teacher { private int teacherId = -1; private String name = null; private List<> pupils = null; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TEACHER_SEQ") @Column(name="teacher_id") public int getTeacherId() { return teacherId; } public void setTeacherId(int teacherId) { this.teacherId = teacherId; } public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany(mappedBy="teacher") public List<Pupil> getPupils() { return pupils; } public void setPupils(List<Pupil> pupils) { this.pupils = pupils; } }
Pupil class
package com.company.server.persistent; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.SequenceGenerator; @Entity @SequenceGenerator( name="PUPIL_SEQ", sequenceName="pupil_seq" ) public class Pupil { private int pupilId = -1; private String name = null; private Teacher teacher = null; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PUPIL_SEQ") @Column(name="pupil_id") public int getPupilId() { return pupilId; } public void setPupilId(int pupilId) { this.pupilId = pupilId; } public String getName() { return name; } public void setName(String name) { this.name = name; } @ManyToOne @JoinColumn(name="teacher_id") public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } }
Right thats our two persistent classes mapped. Finally we need to make the Hibernate file that references these. Unser WEB-INF/src make a file name hibernate.cfg.xml and put the following in it…
<?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> <mapping class="com.company.server.persistent.Teacher" /> <mapping class="com.company.server.persistent.Pupil" /> </session-factory> </hibernate-configuration>
Right now lets mirror these objects by making DTO objects of them on the client side!! Make a new package called com.mycompany.client.dto we’ll add two classes of TeacherDTO and PupilDTO code given below:
package com.company.client.dto; import java.io.Serializable; import java.util.List; public class TeacherDTO implements Serializable { private static final long serialVersionUID = 1L; private int teacherId = -1; private String name = null; private List pupilsDTO = null; public TeacherDTO() { } public int getTeacherId() { return teacherId; } public void setTeacherId(int teacherId) { this.teacherId = teacherId; } /** @gwt.typeArgs <java.lang.String> */ public String getName() { return name; } public void setName(String name) { this.name = name; } /** @gwt.typeArgs <com.mycompany.client.dto.PupilDTO> */ public List getPupilsDTO() { return pupilsDTO; } public void setPupilsDTO(List pupilsDTO) { this.pupilsDTO = pupilsDTO; } }
Notice how GWT annotations used to refer to gwt.typeArgs. This is used to cut down on the warnings from the GWT compiler
and also to specify what type we expect when we call such a method.
package com.company.client.dto; import java.io.Serializable; public class PupilDTO implements Serializable { private static final long serialVersionUID = 1L; private int pupilId = -1; private String name = null; private TeacherDTO teacherDTO = null; public PupilDTO() { } public int getPupilId() { return pupilId; } public void setPupilId(int pupilId) { this.pupilId = pupilId; } /** * @gwt.typeArgs <java.lang.String> */ public String getName() { return name; } public void setName(String name) { this.name = name; } /** * @gwt.typeArgs <com.mycompany.client.dto.TeacherDTO> */ public TeacherDTO getTeacherDTO() { return teacherDTO; } public void setTeacherDTO(TeacherDTO teacherDTO) { this.teacherDTO = teacherDTO; } }
So these are our complete serializable objects that GWT can refer to if we ever get round to it!!
Next stage is to make our applicationContext that Spring will use. Those that have worked with Tomcat J2EE applications before will recognise some of the syntax as this is very similar to the Tomcat context files. In the folder WEB-INF/src make a file named ‘applicationContext.xml’. The format of the context is shown below. Again please alter as necessary.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans classpath:spring-beans-2.0.xsd http://www.springframework.org/schema/tx classpath:spring-tx-2.0.xsd http://www.springframework.org/schema/aop classpath:spring-aop-2.0.xsd"> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>org.postgresql.Driver</value> </property> <property name="url"> <value>jdbc:postgresql://localhost/testdatabase</value> </property> <property name="username"> <value>postgres</value> </property> <property name="password"> <value>yourpassword</value> </property> <property name="initialSize"> <value>2</value> </property> <property name="maxActive"> <value>5</value> </property> <property name="maxIdle"> <value>2</value> </property> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource"/> </property> <property name="configLocation"> <value>hibernate.cfg.xml</value> </property> <property name="configurationClass"> <value>org.hibernate.cfg.AnnotationConfiguration</value> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop> <prop key="show_sql">true</prop> </props> </property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- enable the configuration of transactional behavior based on annotations --> <tx:annotation-driven transaction-manager="txManager" proxy-target-class="false" /><p></p> </beans>
You’ll notice that I use the postgres user this isn’t really advised and is only used for this tutorial. In real application you
would probably have a new role here. Also notice the line classpath:spring-beans-2.0.xsd I downloaded the xsd files from Spring and put them in the same place as the applicationContext to save the application going out to the internet to download xsd files but this isn’t required. The above file also sets up for us the ability to use Hibernate Transactions easily. (Refer to later)
At this stage the application should run in GWT hosted mode, so in Eclipse if you click ‘run’ the application should run? From here we’ll begin to code our RPC calls so that we start to display some data at least within hosted mode. Firstly do a few inserts into your DB.
INSERT INTO teacher VALUES (NEXTVAL('teacher_seq'), 'Mr Blogs'); INSERT INTO pupil VALUES (NEXTVAL('pupil_seq'), 'Teachers Pet', 1); INSERT INTO pupil VALUES (NEXTVAL('pupil_seq'), 'Grubby Student', 1);
That gives us some data to work with. Next locate the HTML for the page that displays the website in hosted mode, this will be in com.company.public.MyApplication.html. Make the code the same as shown below.
<html>
<head>
<!-- -->
<!-- Any title is fine -->
<!-- -->
<title>GWT Database Application</title>
<!-- -->
<!-- This script loads your compiled module. -->
<!-- If you add any GWT meta tags, they must -->
<!-- be added before this line. -->
<!-- -->
<script language='javascript' src='com.company.MyApplication.nocache.js'></script>
</head>
<!-- -->
<!-- The body can have arbitrary html, or -->
<!-- you can leave the body empty if you want -->
<!-- to create a completely dynamic ui -->
<!-- -->
<body>
<!-- OPTIONAL: include this if you want history support -->
<iframe src="javascript:''" id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe>
<h1>MyApplication</h1>
<p>Example GWT application calling RPC calls</p>
<div id="database"></div>
</body>
</html>The areas to take note of are:
<script language='javascript' src='com.company.MyApplication.nocache.js'></script>
And
<div id="database"></div>
The script language allows us to import the GWT compiled javascript and the div allows us to find in the HTML where we want our GWT code to be replaced!
Now locate the java code that maps to this HTML within the class com.company.client.MyApplication.java and enter the following code:
package com.company.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.RootPanel; /** * Entry point classes define <code>onModuleLoad()</code>. */ public class MyApplication implements EntryPoint { /** * This is the entry point method. */ public void onModuleLoad() { final Button button = new Button("Our New Database Button"); RootPanel.get("database").add(button); } }
You’ll notice that we call RootPanel.get(“database”).add(button); so this looks through our HTML and replaces what it finds with something
we want in this case a button. (See where I’m going with this…)
The screen should look very similar to this one shown here. In part 3 of the tutorial I’ll introduce RPC calls to get items from the database and display them on the page.