Dear Wiki user, You have subscribed to a wiki page or wiki category on "Tapestry Wiki" for change notification.
The following page has been changed by michaelcourcy: http://wiki.apache.org/tapestry/Tapstry5First_project_with_Tapestry5,_Spring_and_Hibernate ------------------------------------------------------------------------------ === Software architecture === - The main insterest of setting your software architecture this way is having a rigourous management of your ptoject, it garantees the maintainability, the evolutivity and the exploitation. The image below shows the architecture that we're going to set up in this tutorial. This type of architecture is widely regarded as efficient and could be applyed to any web project. + The main insterest of setting your software architecture this way is having a rigourous management of your project, it garantees the maintainability, the evolutivity and the exploitation of the application. The image below shows the architecture that we're going to set up in this tutorial. This type of architecture is widely regarded as efficient and could be applied to any web project. [http://baptiste-meurant.developpez.com/tutoriaux/tapestry5-spring-hibernate/images/fig7.jpg] The main goal of this kind of architecture is to separate the concerns (buisness vs web) using a strict separation of layers. Indeed one can see on the previous image the 3 layers of this application : * DAO Layer : this layer manages the access to the database through the Hibernate framework. - * Service Layer : The layer represents all the buisness code, it organises the access to the DAO layer and manages all the transactionnal aspects. All of them are organized and manages by the Spring framework. + * Service Layer : The layer represents all the buisness code, it organises the access to the DAO layer and manages all the transactionnal aspects. All of them are organized and managed by the Spring framework. - * MVC Layer : This layer is the IHM, it's the client part of the application. It interacts with the Service layer depending of the client action and retreive the data to show them in a well formed way. This layer is undertaken by the Tapestry5 framework. + * MVC Layer : This layer is the IHM, it's the client part of the application. It interacts with the Service layer depending of the client action and retrieve the data to show them in a well formed way. This layer is undertaken by the Tapestry5 framework. Those layers must be decoupled, which means that there should be no dependencies between each other. Pratically this is possible by having each layer collborating to the other layer through interface. For instance the Service layer only know the interfaces of the DAO layer and the MVC layer only know the interfaces of the Service Layer. This way, each layer publish, through its interfaces, all the treatement that it can offer to the upper layer. And the link between the interface and the implementation, which introduces a technologic dependency (for instance the implementation of the DAO layer uses hibernate) is managed by Spring. @@ -94, +94 @@ Let's focus for a little while on the manipulation of the DB. The previous explainations show two aspects : - * The DAO layer publishstransactionnal contexte its access methods to the DB, theses methods can search, create or delete records. Actually they can retreive objects from DB record, create new objects by creating new records in the DB, or delete object by deleting record in the DB. + * The DAO layer publishs its access methods to the DB, theses methods can search, create or delete records. Actually they can retreive objects from DB record, create new objects by creating new records in the DB, or delete object by deleting record in the DB. * The object relational mapping and the persistance of datas in a transactionnal context allow any change in the state of an object to be propagated in the DB through UPDATE actions. Thus the DAO layer won't features any methods to update the objects. Thoses aspects will be covered in greater details later on. @@ -257, +257 @@ * @Entity : declares to hibernate that this class is persistant. * @Table : to which table in the DB this entity must be mapped - * @Id : declare the property of the entity that is used as a primary key + * @Id : declares the property of the entity that is used as a primary key * @Column : map a a property in the entity to a column of the table. This annotation brings extra constraint informations like for instance non nullity or non mutabillity. These hints on the column let hibernate validate the constraints before acting in the DB. @@ -293, +293 @@ [http://baptiste-meurant.developpez.com/tutoriaux/tapestry5-spring-hibernate/images/fig20.jpg] - The Spring framework is on top of a invervion of control and injections dependencies engine. To have layers of the application properly decoupled, each class of a layer collabore with the interface of the other layer. Then the Spring framework inject at runtime the implementation code of the interface in the different classes. The developper make this possible by creating the getters and the setters of this interfaces, then Spring through xml configurations files use this setters to inject implementations of the interfaces. + The Spring framework is on top of an inversion of control and injections dependencies engine. To have layers of the application properly decoupled, each class of a layer collabore with the interface of the other layer. Then the Spring framework inject at runtime the implementation code of the interface in the different classes. The developper make this possible by creating the getters and the setters of this interfaces, then Spring through xml configurations files use this setters to inject implementations of the interfaces. Using this mechanism we're going to create two distincts layers: The DAO layer (Data Access Object) and the service layer (buisness layer), the two layers are going to collabore with each other through interfaces. @@ -442, +442 @@ * The use of the Hibernate Criteria API that let you make request based on Object. We could do the same thing with HQL but it's not as elegant as the Criteria API is. * The use of differents Spring interfaces for accessing the Hibernate (for instance getHibernateTemplate(), etc.). - Create the xml file ApplicationContextDao.xml in WEB-INF and declare the couple interface/implementation using Spring's bean. By Default a Spring's bean is a singleton and thus are ThreadSafe. Thi means that this code could be concurently called by two different processes safly. This mechanism in internally managed by Spring. + Create the xml file ApplicationContextDao.xml in WEB-INF and declare the couple interface/implementation using Spring's bean. By Default a Spring's bean is a singleton and thus are ThreadSafe. This means that this code could be concurently called by two different processes safly. This mechanism in internally managed by Spring. - This file define a bean userDao corresponding to the previous interface and we choose the implementation we want to use. This bean contains a property (in the JavaBeans sens) sessionFactory. The sessionFactory bean represents actually the Hibernate SessionFactory and has to be configured as well. The two mains configuration aspects of this beans is where to find the hibernate.cfg.xml and which strategy must be used for mapping entity to the DB tables, here it's the annotation strategy. + This file defines a bean userDao corresponding to the previous interface and we choose the implementation we want to use. This bean contains a property (in the JavaBeans sens) sessionFactory. The sessionFactory bean represents actually the Hibernate SessionFactory and has to be configured as well. The two mains configuration aspects of this beans is where to find the hibernate.cfg.xml and which strategy must be used for mapping entity to the DB tables, here it's the annotation strategy. {{{ @@ -581, +581 @@ }}} - The services layer need to collaborate with the dao layer. But following the principle of loose coupling, the service layer is going to collaborate with the interface of the dao not with its implementation. Spring has the duty to inject the implememtation in place of the interface at runtime. Two things need to be done to make this possible : provide in the service class a setter method for the dao and write the needed configuration in xml files. + The services layer need to collaborate with the dao layer. But following the principle of loose coupling, the service layer is going to collaborate with the interface of the dao not with its implementation. Spring has the duty to inject the implementation in place of the interface at runtime. Two things need to be done to make this possible : provide in the service class a setter method for the dao and write the needed configuration in xml files. * Edit UserManagerImpl to create the dao injector (actually its a setter). We also add two extras methods that we be needed for the next steps. @@ -648, +648 @@ }}} - Notice that there's no reference to the implementation : only the interface is known and used via the locale variable userDao. At startup, Spring use the setter to inject the implementation you defined in ApplicationContextDao.xml. Thanks to the configuration of ApplicationContextDao.xml, all the method of UserDao become available (Caution : actually only the method defined in the interface are available, anyway trying to invoke a non interface method would end up in compilation error). + Notice that there's no reference to the implementation : only the interface is known and used via the locale variable userDao. At startup, Spring uses the setter to inject the implementation you defined in ApplicationContextDao.xml. Thanks to the configuration of ApplicationContextDao.xml, all the method of UserDao become available (Caution : actually only the method defined in the interface are available, anyway trying to invoke a non interface method would end up in compilation error). To make this injection effective, userManager need to be declared to Spring and must add the internal property userDao. @@ -672, +672 @@ }}} - Once again we deal with the paradigm interface/implémentation with this time the use of injection through the definition of userDao which reference the bean defined before. : the name of the bean must be exactly the name of the property defined in userManager. Spring will use camelise mechanism to invoke the setter : ie set + "U"serDao(userDAO); + Once again we deal with the paradigm interface/implementation with this time the use of injection through the definition of userDao which reference the bean defined before. : the name of the bean must be exactly the name of the property defined in userManager. Spring will use camelise mechanism to invoke the setter : ie set + "U"serDao(userDAO); ==== Transaction management ==== - Beside inversion of control, dependencies injection and layering structuration of your code, Spring features powerful mechanism to manage the transactions. Transaction rely on proxy and PAO (Programmation Aspect Oriented), which is the core of the Spring Framework. You configure transaction in three steps : + Beside inversion of control, dependencies injection and layering structuration of your code, Spring features powerful mechanism to manage the transactions. Transaction rely on proxy and AOP (Aspect Oriented Programmation), which is the core of the Spring Framework. You configure transaction in three steps : - First define a general abstract proxy that will be used by all the manager that need to be transactional : Add this code to applicationConextDao.xml + First define a general abstract proxy that will be used by all the manager that need to be transactional : Add this code to applicationContextDao.xml applicationContextDao.xml {{{ @@ -715, +715 @@ <ref bean="userDao" /> </property> </bean> - <bean id="userManager" parent="transactionProxy"> + <bean id="userManager" parent="transactionProxy"> - <property name="transactionManager"> - <ref bean="transactionManager"/> - </property> <property name="target"> <ref bean="userManagerTarget"/> </property> @@ -731, +728 @@ }}} - Todo : check if the property transactionManager is not redundant. We put a transactionnal proxy in front of the buisness bean. The transactionManager is passed to the transactionnal proxy and we declare to Spring that the transaction configuration is done with annotation thanks to the property transactionAttributeSource. @@ -897, +893 @@ }}} - Notice the attributes t:value that binds a the textefield value to a java variable. The atrribute for binds the html input to the label. + Notice the attributes t:value that binds the textefield value to a page property. The atrribute for binds the html input to the label. Create a package pages and a class Login.java which mirrors the html form : @@ -968, +964 @@ }}} - ${login} uses the login variable in the session if defined. Tapestry can retreive this value if the context ApplicationState has been defined for both classes : Login.java and Home.java must bear the login property with the ApplicationState context. + ${login} uses the login variable in the session if defined. Tapestry can retrieve this value if the context ApplicationState has been defined for both classes : Login.java and Home.java must bear the login property with the ApplicationState context. The element t:actionLink define another link to a tapestry page. @@ -1018, +1014 @@ }}} - * Once again, the annotation @ApplicationState will retreive the variable login from the session. + * Once again, the annotation @ApplicationState will retrieve the variable login from the session. * The annotation @Inject let tapestry inject dependencies from third parties source (here J2EE core). - * The method onLogout which thanks to the annotation @onEvent(component="logout") will be invoked every time the component bubble an event. Here, the component is a simple link, so every time one click on it the session is invalidated and the user comeback to the login page. + * The method onLogout which thanks to the annotation @onEvent(component="logout") will be invoked every time the component bubble an event. Here, the component is a simple link, so every time the link is clicked the session is invalidated and the user comebacks to the login page. Edit web.xml to configure the Tapestry filter and the base package from which tapestry knows where to find the pages package that contains page beans. {{{ @@ -1174, +1170 @@ We notice : - * the annotations @Inject and @Service inject the bean (Manager) from Spring into Tapestry. We can now use all of the methods defined in the interface here we modify the methode onSucces, when the for is submitted the application called the Spring userManager service to execute the checkLogin method and check that login and password really exist in DB. If yes the user is redirected to the Home page. In the opposite, we initialise an error message variable to be diplayed to the user. + * the annotations @Inject and @Service inject the bean (Manager) from Spring into Tapestry. We can now use all of the methods defined in the interface here we modify the methode onSucces, when the form is submitted the application called the Spring userManager service to execute the checkLogin method and check that login and password really exist in DB. If yes the user is redirected to the Home page. In the opposite, we initialize an error message variable to be diplayed to the user. * The annotation @Persist on error persist the value of error only for this page : instead of the annotation @ApplicationState, @Persist define persistence only for the page not for the whole application. * The getErrorMessage make the property errorMessage available in the Login page. change Login.html : @@ -1224, +1220 @@ As we explained it at the beginning of this tutorial dealing with hibernate, every model object is related to a table in the DB. We therefore get a complete object graph : an entity having a 1,n relation with entity E2 in object realm is going to be object O1 of type T1 hold an object O2 of type collection of T2 ⦠And so on. - We quickly realised that the object graph could be extremely heavy if all collections and children of children collections must be loaded. It's why by default, Hibernate uses "Lazy loading". Lazy loading means that when the object is loaded in memory, only the object is loaded not all its collections; collections will be loaded when they will first be used. The opposite of lazy loading is eager loading : when the object is loaded all the graph is loaded. You must explicitly annotate your classes to have eager loading (1,n ; n,1 ou n,n) : @OneToMany, @ManyToMany ou @ManyToOne(cascade = {}, fetch = FetchType.EAGER). + We quickly realized that the object graph could be extremely heavy if all collections and children of children collections must be loaded. It's why by default, Hibernate uses "Lazy loading". Lazy loading means that when the object is loaded in memory, only the object is loaded not all its collections; collections will be loaded when they will first be used. The opposite of lazy loading is eager loading : when the object is loaded all the graph is loaded. You must explicitly annotate your classes to have eager loading (1,n ; n,1 ou n,n) : @OneToMany, @ManyToMany ou @ManyToOne(cascade = {}, fetch = FetchType.EAGER). One very important thing to understand about lazy loading is that you can access to the lazy collections only if the transaction in wich you got this object is not commited yet. Indeed, the lazy loading is possible because the session Hibernate is still active and opened to be able to complete the graph from the DB when needed. And with the transaction manager we used in this tutorial, the session is closed at the end of the execution of the service method. Thus if we try to access a collection in the view we're going to have a LazyInitializationException. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
