Simple Tapestry Hibernate app (old)

Update: this document is deprecated

Created: 20 Nov 2003

Document
purpose
: to create a simple application in order to evaluate how easy
is to use the two “things” together.

Application: no purpose application containing just one table (contact)

Download: download
the code
(the libraries are missing to have a smaller archive,
you need the ones for hibernate and tapestry (including contrib))

Results:

  • this is
    a promissing approach which I will use for a larger application
    soon
  • the validField components and the input fields in general helped me a
    lot, I think that starting with the mapping file a generator could be written
    to write the html and page parts
  • there was not much error checking but this can be improved
  • tapestry looks nice, the only thing missing seems to be that I am very
    much used to all those redirects in JSP’s also the documentation is not
    that clear about all the page states and calls. I used the listener interface
    but I am not sure it is the best approach.
  • it took me arround 2-3 hours to have this running (20% to have something
    running, 30% for the add, 20% for the validation, 20% for the table, 10%
    for the icons (I am really bad with gimp)

Versions: Hibernate 1.2.3, Tapestry 2.3

1. Start
with the hibernate mapping file (mapping.hdb.xml) for
the database structure and the hibernate.properties
(I am using a postgresql database).

<class name="ro.nit.contacts.Contact" table="contact"><br></br>
<id name="id" column="uid" type="long"><br></br><generator class="sequence"/><br></br></id> <br></br><br></br><property name="title" type="string" not-null="true"/><br></br><property name="company" type="string"/><br></br><property name="status" type="string" not-null="true"/><br></br><property name="person" type="string" not-null="true"/><br></br><property name="notes" type="string"/><br></br><property name="type" type="string" not-null="true"/><br></br><property name="data" type="string"/> <br></br></class>

2. Tapestry
application

<application name="contacts" engine-class="ro.nit.contacts.AppEngine" ><br></br><property<br></br>                name="net.sf.tapestry.visit-class">ro.nit.contacts.Visit</property> (will<br></br>                contain hibernate part)<br></br>
<page name="Home" specification-path="/ro/nit/contacts/Home.page"/> (nothing)<br></br>
<page name="Add" specification-path="/ro/nit/contacts/Add.page"/> (add
page, add a contact with error check)<br></br>
<page name="View" specification-path="/ro/nit/contacts/View.page"/> (view
page, view contacts in a sortable table)<br></br><component-alias<br></br>                type="ShowError" specification-path="/ro/nit/components/ShowError.jwc" /> (this<br></br>                will show the error for data input)<br></br>
<component-alias type="Menu" specification-path="/ro/nit/components/Menu.jwc" /> (menu
contained in all pages)<br></br><library<br></br>                id="contrib" specification-path="/net/sf/tapestry/contrib/Contrib.library" /> (I<br></br>                will use the table from this)<br></br></application>

3. The Visit class is going to contain hibernate initialization

public class Visit implements Serializable {<br></br>private String appName = "Contacts";<br></br>
private SessionFactory sessionFactory;<br></br>public String getAppName() {<br></br>
return appName;<br></br>
}<br></br>public void setAppName(String appName) {<br></br>
this.appName = appName;<br></br>
}<br></br><br></br>public Visit() {<br></br>
try {<br></br>
Datastore datastore=Hibernate.createDatastore().storeInputStream(getClass().getResourceAsStream("mapping.hbm.xml"));<br></br>
Properties properties=new Properties();<br></br>
properties.load(getClass().getResourceAsStream("hibernate.properties"));<br></br>
sessionFactory = datastore.buildSessionFactory(properties);<br></br>
} catch (Exception e) {<br></br>
e.printStackTrace();<br></br>
}<br></br>
}<br></br>public<br></br>                Session getSession() throws SQLException{ (the visit.session<br></br>                expression will return a new session)<br></br>
return sessionFactory.openSession();<br></br>
}<br></br>
}

4. The Home page does not contains nothing

home.png
Graphic 1:Home page

5. The Add page
contains logic for adding a contact with validation. I use some ValidField
components for checking the input entered by the
user. This validation is one of the most ugly things I can thing about
when creating some dynamic pages. This is mainly due to the repetitive,
error generating code.

<span jwcid="shell"><br></br>
<body jwcid="body"><br></br><span jwcid="menu"/><br></br>
<br><br></br><form jwcid="form"><br></br>
<span jwcid="showError"/><br></br>
<table cellpadding="4"><br></br>
<tr><td>Title:</td><td><input jwcid="titleField" size="20"/></td></tr><br></br>
<tr><td>Company:</td><td><input jwcid="companyField" size="20"/></td></tr><br></br>
<tr><td>Status:</td><td><span jwcid="statusSelect"/></td></tr><br></br>
<tr><td>Person:</td><td><input jwcid="personField" size="20"/></td></tr><br></br>
<tr><td>Notes:</td><td><textarea jwcid="notesText" cols="20" rows="5"/></td></tr><br></br>
<tr><td>Type:</td><td><span jwcid="typeSelect"/></td></tr><br></br>
<tr><td>Data:</td><td><textarea jwcid="dataText" cols="20" rows="5"/></td></tr><br></br>
<tr align="right"><br></br>
<td colspan="2"><input type="submit" value="Add"/></td><br></br>
</tr><br></br>
</table><br></br>
</form><br></br>
</body><br></br>
</span>
<page-specification class="ro.nit.contacts.AddContact"> <bean name="delegate" class="ro.nit.components.SimpleValidationDelegate"/> <bean name="basicValidator" class="net.sf.tapestry.valid.StringValidator"><br></br>
<!--<set-property name="clientScriptingEnabled" expression="true"/>--><br></br>
<set-property name="required" expression="true"/><br></br>
<set-property name="minimumLength" expression="5"/><br></br>
</bean> <component id="form" type="Form"><br></br>
<binding name="delegate" expression="beans.delegate"/><br></br>
<binding name="listener" expression="listeners.formSubmit"/><br></br>
</component> <component id="shell" type="Shell"><br></br>
<binding name="title" expression="visit.appName"/><br></br>
<binding name="stylesheet" expression="assets.stylesheet"/><br></br>
</component> <component id="showError" type="ShowError"><br></br>
<binding name="delegate" expression="beans.delegate"/><br></br>
</component> <component id="menu" type="Menu"/> <component id="titleField" type="ValidField"><br></br>
<binding name="value" expression="contact.title"/><br></br>
<binding name="validator" expression="beans.basicValidator"/><br></br>
<static-binding name="displayName">"Title"</static-binding><br></br>
</component> <component id="companyField" type="ValidField"><br></br>
<binding name="value" expression="contact.company"/><br></br>
<binding name="validator" expression="beans.basicValidator"/><br></br>
<static-binding name="displayName">Company</static-binding><br></br>
</component> <component id="statusSelect" type="PropertySelection"><br></br>
<binding name="model" expression="@ro.nit.contacts.AddContact@STATUS"/><br></br>
<binding name="value" expression="contact.status"/><br></br>
</component> <component id="personField" type="ValidField"><br></br>
<binding name="value" expression="contact.person"/><br></br>
<binding name="validator" expression="beans.basicValidator"/><br></br>
<static-binding name="displayName">Person</static-binding><br></br>
</component> <component id="notesText" type="TextArea"><br></br>
<binding name="value" expression="contact.notes"/><br></br>
</component> <component id="typeSelect" type="PropertySelection"><br></br>
<binding name="model" expression="@ro.nit.contacts.AddContact@TYPE"/><br></br>
<binding name="value" expression="contact.type"/><br></br>
</component> <component id="dataText" type="TextArea"><br></br>
<binding name="value" expression="contact.data"/><br></br>
</component><br></br><component id="body" type="Body"/><br></br><private-asset name="stylesheet" resource-path="/ro/nit/style.css"/><br></br></page-specification>

AddContact class:

public class AddContact extends BasePage{ public static final IPropertySelectionModel TYPE =<br></br>
new StringPropertySelectionModel(new String[] { "Unspecified", "Job", "Bussiness", "Individual" });<br></br>
public static final IPropertySelectionModel STATUS =<br></br>
new StringPropertySelectionModel(new String[] { "Unspecified", "Closed", "Open", "Hope" }); private Contact contact=new Contact(); public Contact getContact() {<br></br>
return contact;<br></br>
} public void setContact(Contact contact) {<br></br>
this.contact = contact;<br></br>
} public void formSubmit(IRequestCycle cycle) { ValidationDelegate delegate = (ValidationDelegate)<br></br>
getBeans().getBean("delegate"); // If no errors process the bid, otherwise stay on this page
and<br></br>
// let the fields show their errors.<br></br>
if (!delegate.getHasErrors()){<br></br>
Visit visit = (Visit)getVisit();<br></br>
Session sess = null;<br></br>
try {<br></br>
sess = visit.getSession();<br></br>
Transaction tx=sess.beginTransaction();<br></br>
sess.save(contact);<br></br>
tx.commit();<br></br>
cycle.setPage("View");<br></br>
} catch (Exception e) {<br></br>
e.printStackTrace();<br></br>
//conceal this for now<br></br>
} finally {<br></br>
if(sess!=null){<br></br>
try {<br></br>
sess.flush();<br></br>
sess.close();<br></br>
} catch (Exception e) {<br></br>
e.printStackTrace();<br></br>
//conceal this also<br></br>
}<br></br>
}<br></br>
}<br></br>
contact = new Contact();<br></br>
}<br></br>
}}

Observation: maybe a generator could be written. This will take a mapping
file and output a component for entering data.


6. The View page contains just a table with data

![view.png](view.png) Graphic 4:View page (the table)
``` public class

ViewContacts extends BasePage implements PageRenderListener{

ITableModel tableModel;

ITableColumnModel objColumnModel =

new ExpressionTableColumnModel(new String[] {

"Title", "title",

"Company", "company",

"Status", "status",

"Contact person", "person",

"Contact data", "data",

"Notes", "notes"

}, true);

OTableDataModel tableDataModel = new OTableDataModel(new Vector()); boolean cssClass=true; public String getCssClass() {

cssClass=!cssClass;

if(cssClass)

return "row1";

else

return "row2";

} public List getContacts(){

Visit visit = (Visit)getVisit();

Session sess = null;

try {

sess = visit.getSession();

List results = sess.find("from c in class ro.nit.contacts.Contact");

return results;

} catch (Exception e) {

e.printStackTrace();

}finally{

if(sess!=null)

try {

sess.close();

} catch (Exception e) {

e.printStackTrace();

//conceal this for now

}

}

return null;

} public ViewContacts() {

} public ITableModel getTableModel(){

if(tableModel==null)

tableModel = new SimpleTableModel(tableDataModel,objColumnModel);

return tableModel;

} protected void finishLoad() {

getPage().addPageRenderListener(this);

} public void pageBeginRender(PageEvent event) { tableDataModel.replaceAllRows(getContacts()); } ```