GeeCON Prague 2014*
The moose likes Struts and the fly likes Is it a good design model (struts + hibernate)? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


JavaRanch » Java Forums » Frameworks » Struts
Bookmark "Is it a good design model (struts + hibernate)?" Watch "Is it a good design model (struts + hibernate)?" New topic
Author

Is it a good design model (struts + hibernate)?

Marco Vanoli
Ranch Hand

Joined: Jan 12, 2005
Posts: 99
After reading some books i developed my web application (tomcat) using the following design:

I have mapped my table with hibernate then create DAO classes for accessing to them. When i run an action it calls DAO class that use Hibernate.
Do not look at Exception Handling that is a question i find very hard and i' have not understood well..
That i need to understand is my application is on the right way or if i made big mistake in design.

Tnk you very much for assistance
Marco

This is a bare-bone classes of my project (only model & action class):

ACTION CLASS
public class AddAttributeAction extends Action {


public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {

AddAttributeForm addAttributeForm = (AddAttributeForm) form;
AttributeDAO attributeDAO = new AttributeDAO();
if(attributeDAO.addAttribute(addAttributeForm))
return (mapping.findForward("success"));
else
return (mapping.findForward("failure"));
}

}

DAO CLASS
public class AttributeDAO {

public AttributeDAO() {

}

public Session getSession( ) throws PersistenceException {
Session session = null;
try {
session = Persistence.getSession( );
} catch (HibernateException e) {
//log.error("Exception accessing persistence session");
throw new PersistenceException(
"Exception accessing persistence session", e);
}
return session;
}
public boolean addAttribute(AddAttributeForm addAttributeForm) {

boolean save = false;

//setto l' oggetto attributo
Attribute theAttribute = new Attribute();
theAttribute.setName(addAttributeForm.getName());
theAttribute.setType(Short.valueOf(addAttributeForm.getType()));
theAttribute.setColumn(addAttributeForm.getColumn());
theAttribute.setObjectName(addAttributeForm.getMetaobject());

Transaction tx = null;

try {

tx =getSession().beginTransaction();
Query q = getSession().createQuery("from MetaObject m where m.name = :name");
q.setString("name", addAttributeForm.getMetaobject());
List result = q.list();
MetaObject theMetaObject = null;
for (int i = 0; i < result.size(); i++) {
theMetaObject = (MetaObject) result.get(i);
}

//se esiste metaobject aggiungo l' attributo al suo set.
if (theMetaObject != null){
theAttribute.setMetaObject(theMetaObject);
theMetaObject.getAttributes().add(theAttribute);
getSession().save(theMetaObject);
save = true;
}
tx.commit();

}
catch (HibernateException e) {
save = false;
System.out.println("Errore di database: forse hai inserito un nome gia' esistente");
//e.printStackTrace();
if (tx != null) Persistence.rollback(tx);
}
return save;

}
public List getAttributes() {
List result = null;
Transaction tx = null;

try {

tx =getSession().beginTransaction();
Query q = getSession().createQuery("from Attribute");
result = q.list();
tx.commit();
}
catch (HibernateException e) {
System.out.println("Error!!!");
e.printStackTrace();
if (tx != null) Persistence.rollback(tx);
}
return result;
}
}

POJO CLASSES

public class Attribute implements Serializable {

/** identifier field */
private Long id;

/** persistent field */
private String name;

/** persistent field */
private String objectName;

/** persistent field */
private short type;

/** persistent field */
private String column;

/** persistent field */
private MetaObject metaObject;

private Fuzzyattribute fuzzyattribute;

+ getter setter methods

public class MetaObject implements Serializable {

private Long id;

/** identifier field */
private String name;

/** persistent field */
private String from;

/** nullable persistent field */
private String where;

/** persistent field */
private Set attributes = new HashSet();

+ getter setter methods

HIBERNATE MAPPINGS

<hibernate-mapping>

<class name="com.full.hibernate.model.Attribute"
table="ATTRIBUTES">

<!-- Common id property. -->
<id name="id"
type="long"
column="ATTRIBUTE_ID"
unsaved-value="null">
<generator class="native" />
</id>

<property
name="name"
type="java.lang.String"
length="50"
not-null="true" >
<column name="NAME" unique-key="uk_object_name"/>
</property>

<property
name="objectName"
type="java.lang.String"
length="50"
not-null="true" >
<column name="OBJECT" unique-key="uk_object_name"/>
</property>

<property
name="type"
type="short"
column="TYPE"
not-null="true"
length="6" />

<property
name="column"
type="java.lang.String"
column="COLUMN_"
not-null="true"
length="50" />

<!-- Associations -->
<!-- derived association(s) for compound key -->
<!-- bi-directional many-to-one association to Object -->

<many-to-one name="metaObject"
class="com.full.hibernate.model.MetaObject">
<!--update="false"-->
<!--insert="false">-->
<column name="OBJECT_REF" />
</many-to-one>

<!--associazione uno a uno presa da manuale Hibernate in Action, con creazione di colonna apposita-->
<many-to-one name="fuzzyattribute"
class="com.full.hibernate.model.Fuzzyattribute"
column="FUZZYATTRIBUTE_REF"
cascade="all"
unique ="true"/>
</class>

<class
name="com.full.hibernate.model.MetaObject"
table="OBJECTS"
>

<!-- Common id property. -->
<id name="id"
type="long"
column="METAOBJECT_ID"
unsaved-value="null"
>
<generator class="native"/>
</id>

<property
name="name"
type="java.lang.String"
column="NAME"
not-null="true"
unique="true"
/>

<property
name="from"
type="java.lang.String"
column="FROMCLAUSOLE"
not-null="true"
length="50"

/>

<property
name="where"
type="java.lang.String"
column="WHERECLAUSOLE"
length="50"

/>

<!-- Associations -->

<!-- bi-directional one-to-many association to Attribute -->
<set
name="attributes"
lazy="true"
inverse="true"
cascade="all"
>
<key>
<column name="OBJECT_REF" />
</key>
<one-to-many
class="com.full.hibernate.model.Attribute"
/>
</set>

</class>


bye, <br />Marco
Kerry Wilson
Ranch Hand

Joined: Oct 29, 2003
Posts: 254
You shouldn't pass the ActionForm to the Model, you should only pass primitives, 'Standard' classes or a Value Object which contains all data accessed via getters and setters. Personally I add another layer of abstraction and create service classes which usually contain static methods that access the DAO.

So in summary

Struts Action -> passes VO -> Service -> passes VO -> DAO

I use the service in case I need to map across tables. I don't like DAO classes talking to other DAO so I use a service which talks to whatever DAO it wants to.

Hope that helps.


http://www.goodercode.com
SCJP 1.4
Jason Menard
Sheriff

Joined: Nov 09, 2000
Posts: 6450
Piggybacking on what Kerry said, which is very good advice... In general you will not want your Actions to interact directly with the DAOs. This is a pretty good sign that you are coding business logic into your Actions, which you certainly want to avoid. As Kerry mentioned, you should be using Service classes. As a rule of thumb, you can plan on one service method for each use case, with those methods divided amongst a set of service classes that makes sense for your application.

So if you have use cases for "add an attribute", "remove an attribute", "sort attributes", "register a new user", "logoff user", and "edit user information" then you might break things up as follows:

AttributeServices
-----------------
+addAttribute
+removeAttribute
+sortAttributes

AttributeDAO
------------
+createAttribute
+deleteAttribute

UserServices
------------
+editUserInfo
+logoffUser
+registerNewUser

UserDAO
-------
+createUser
+updateUser

The DAOs in this case are strictly handling CRUD and find functions for persistent business objects and not business logic themselves, some of which is required at least to some extent with any use case (for example, "you can't add an attribute if the same one already exists" requires business logic). You'll also notice that not all service methods deal with persisten business objects, such as "sort attributes" which only sorts a collection for display.

When you're doing your design, if you start thinking about each use case as a service method and DAOs as relatively dumb objects use only for handling persistence functions on specific objects, things should fall into place pretty easy.
Marco Vanoli
Ranch Hand

Joined: Jan 12, 2005
Posts: 99
Yes it helps, thanks,
but why necerrary value objects, the form bean isn' t similar to it? (Phereps the problem is that all its properties are Strings?)
--
However instead on create a value object or another class (too much layer for me, i try keep simple thing ) Cannot i istantiate the POJO class (hibernate mapped to a table DB) in the action and pass it to DAO?
Or if this anti-pattern maybe the best chooice is to pass only parameters needed for my operations, isn't it ?

thnks again,
bye
Kerry Wilson
Ranch Hand

Joined: Oct 29, 2003
Posts: 254
If a Value Object contains several field 5+ I will usually assign it to the form. Then, I access in the JSP with ${vo.id} that way I can retrieve in Action with form.getValueObject().
Marco Vanoli
Ranch Hand

Joined: Jan 12, 2005
Posts: 99
Originally posted by Kerry Wilson:
Personally I add another layer of abstraction and create service classes which usually contain static methods that access the DAO.


About this topic where can i fond more info about creating this services classes? Can sombody explain to me why use static method to access dao and not normal ones?
tnk
alan do
Ranch Hand

Joined: Apr 14, 2005
Posts: 354
hibernate is not an apache project and it has no support for stored procedure. i highly recommend using iBatis (http://ibatis.apache.org/) instead.


-/a<br />certified slacker...yes, my last name is 'do' - <a href="http://www.luckycouple.com" target="_blank" rel="nofollow">luckycouple.com</a>
Marco Vanoli
Ranch Hand

Joined: Jan 12, 2005
Posts: 99
My project is in deep develop so i cannot change hibernate.
I' d like to know only the Kelly Wilson phrase that say to use static service for accessing to dao.
I understand this:
I will have an action class that call class (static or normal?) wich implements methods (static or normal) that are the service that i need.
At the end service classe use fine grain DAO to simple acces to database.

Is it al right? .. An my bigges dubt is about servlet' s threads.
I have to synchronize service methods or not?

tnk
alan do
Ranch Hand

Joined: Apr 14, 2005
Posts: 354
for the struts part, there's no need to synchronize the ActionServlet.service(). eventhough the Action classes are static, the objects passed into the .excute() methods are not. the key then is to NOT place any values that can be changed (localized variables/objects) OUTSIDE of the .execute() method.

for the rest of the app, if you are using static methods, the same rules follow. don't use static methods to modify global values. your users will end up overwrite and grabbing each other's values.
 
GeeCON Prague 2014
 
subject: Is it a good design model (struts + hibernate)?