Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: Struts actions and declarative transactions

  1. #1
    Join Date
    Aug 2004
    Location
    Ankara, Turkey
    Posts
    24

    Default Struts actions and declarative transactions

    Hi,

    The question is: What is the simplest way to define declarative transaction demarcation for all my Struts actions?

    If I try to explain further:
    Our project currently uses Struts and Castor. We want to move to Spring and Hibernate (with Struts still present for the moment).
    The architecture we came up with is like this (giving example class names):

    OfferDAO (interface)
    OfferDAOHibernate (implements OfferDAO)
    OfferManager (interface)
    OfferManagerImpl (implements OfferManager) (calls methods of OfferDAO)

    These are all set up now. Relevant parts in the applicationContext.xml looks like this:
    Code:
        <bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
            <property name="sessionFactory"><ref local="sessionFactory"/></property>
        </bean>
        <bean id="offerDAO" class="dao.hibernate.OfferDAOHibernate">
            <property name="sessionFactory"><ref local="sessionFactory"/></property>
        </bean>    
    	<bean id="offerManager" 
    		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
    		<property name="transactionManager"> 
    			<ref local="transactionManager"/> 
    		</property> 
    		<property name="target"> 
    			<ref local="offerManagerTarget"/> 
    		</property> 
    		<property name="transactionAttributes"> 
    			<props> 
    				<prop key="save*">PROPAGATION_REQUIRED</prop> 
    				<prop key="remove*">PROPAGATION_REQUIRED</prop> 
    				<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> 
    			</props> 
    		</property>
    	</bean>	
    	
    	<bean id="offerManagerTarget" 
    		class="offer.OfferManagerImpl"> 
    		<property name="offerDAO"><ref local="offerDAO"/></property>
    	</bean>
    I have written unit tests and it works beautifully. However, all the methods in the managers are the methods present in the DAOs... Which means that the managers are not real managers at the moment, but a facade to call the DAO methods instead.

    Now I want to adapt my Struts actions to use this setup. Unfortunately, at the moment in our Struts actions, what we do is this:
    1. Get a transaction context, and begin transaction
    2. Get necessary parameters from request object
    3. Do lots of business logic
    4. At the end, commit or rollback the transaction.

    With the new Struts+Hibernate setup, I understand that I have to move lots of the code in my Struts actions to the Managers... As an example, we have a "CreateOfferAction" Struts action. I already refactored it to call the methods from OfferManager, which in turn calls methods of OfferDAO. However, since I defined declarative transactions for the OfferManager, each call from the Struts action takes its own transaction. But of course what I want is, that in a single Struts action, all calls to the OfferManager methods to share a single transaction.

    So, let me repeat the question again: I have lots of Struts actions, which obviously have their own "execute" methods. How can I define in the applicationContext.xml file so that all "execute" methods of all Struts actions to have "PROPAGATION_REQUIRED" declarative transaction?

    To illustrate, I want to have:
    Code:
    <for all classes that extend from a particular class &#40;org.apache.struts.action.Action here&#41;>
        <property name="transactionAttributes"> 
    			<props> 
    				<prop key="execute*">PROPAGATION_REQUIRED</prop> 
    				<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> 
    			</props> 
    		</property>
    </for all>
    Of course, ideally, I'll refactor the actions to call the managers only, sending request parameters, and accepting parameters to be put into the response object. All transactons will take place in the manager methods. But at the moment, I don't have that time, so I'd like to learn if there is any simple way to make all "execute" methods of Struts actions to have their own transactions, using Spring AOP support...

    Thanks in advance,
    Regards,
    Turgay Zengin

  2. #2
    Join Date
    Aug 2004
    Location
    Warsaw, Poland
    Posts
    33

    Default Re: Struts actions and declarative transactions

    Quote Originally Posted by turgayz
    With the new Struts+Hibernate setup, I understand that I have to move lots of the code in my Struts actions to the Managers...
    Yes :).

    [...] have a "CreateOfferAction" Struts action. I already refactored it to call the methods from OfferManager, which in turn calls methods of OfferDAO. However, since I defined declarative transactions for the OfferManager, each call from the Struts action takes its own transaction. But of course what I want is, that in a single Struts action, all calls to the OfferManager methods to share a single transaction.
    Consider rewriting Your Service layer in such a way, so You would be able to declare transaction on one "service level". Just delegate your "buisness logic" from actions into service layer.

    So, let me repeat the question again: I have lots of Struts actions, which obviously have their own "execute" methods. How can I define in the applicationContext.xml file so that all "execute" methods of all Struts actions to have "PROPAGATION_REQUIRED" declarative

    [...]

    Of course, ideally, I'll refactor the actions to call the managers only, sending request parameters, and accepting parameters to be put into the response object. All transactons will take place in the manager methods. But at the moment, I don't have that time, so I'd like to learn if there is any simple way to make all "execute" methods of Struts actions to have their own transactions, using Spring AOP support...
    You have two options:

    * org.springframework.web.struts.DelegatingRequestPr ocessor
    or
    * org.springframework.web.struts.DelegatingActionPro xy

    Remember that struts actions are classes, so You have to use cglib instead of jdk Proxies.

    Artur

  3. #3
    Join Date
    Aug 2004
    Location
    Ankara, Turkey
    Posts
    24

    Default

    Consider rewriting Your Service layer in such a way, so You would be able to declare transaction on one "service level". Just delegate your "buisness logic" from actions into service layer.
    Yes, that's what I'll do in new projects. But with this one, I am trying to adapt to Spring without a major change.
    You have two options:

    * org.springframework.web.struts.DelegatingRequestPr ocessor
    or
    * org.springframework.web.struts.DelegatingActionPro xy
    I'll investigate DelegatingRequestProcessor and DelegatingActionProxy to see if I can manage this.
    Can you please describe a little more what you mean by :
    Remember that struts actions are classes, so You have to use cglib instead of jdk Proxies.
    Thanks a lot,
    Turgay Zengin

  4. #4
    Join Date
    Aug 2004
    Location
    Ankara, Turkey
    Posts
    24

    Default Solution

    Here is the solution I ended up with, sending in hope that this might be useful for others as well:
    A Struts action's execute method was like this before:
    Code:
    public ActionForward execute&#40;ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response&#41; 
    	&#123;
         get request parameters...
         perform business logic, access database, update database, etc...
        	if&#40;forward==null&#41; return null;
        	else return mapping.findForward&#40;forward&#41;;
        &#125;
    Now I created a Facade where all the business logic is centralized. I moved the business logic there, and the execute method of an action now looks like:
    Code:
    public ActionForward execute&#40;ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response&#41; 
    	&#123;
    		String forward=myFacade.aBusinessMethod&#40;request,response&#41;;
        	if&#40;forward==null&#41; return null;
        	else return mapping.findForward&#40;forward&#41;;
        &#125;
    In my applicationContext.xml file, I defined declarative transactions for my facade, such that if a method name begins with "update_", that method is executed in a transaction, for other methods, a transaction is not forced:
    Code:
    		<property name="transactionAttributes"> 
    			<props> 
    				<prop key="update_*">PROPAGATION_REQUIRED</prop> 
    				<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> 
    			</props> 
    		</property>
    Unfortunately, the facade is tied to the servlet API right now, but I know that this should be abstracted as well, to let other kinds of clients (like Swing) use the facade... With HashMaps as inputs and outputts maybe...

    Regards,
    Turgay Zengin

  5. #5
    Join Date
    Aug 2004
    Location
    Columbus, OH, USA
    Posts
    133

    Default Good first step

    Turgay I agree that's a good, pragmatic first step towards creating a business service layer from an existing app that has business logic in the Struts actions.

    And you're right, the next step is to bring the Http stuff back up to the actions and leave just the (one or many) DAO operations and business decision logic in the service classes.

  6. #6
    Join Date
    Sep 2004
    Posts
    346

    Default Transactions / thread do not appear to work

    Set up declarative transactions and in struts action make multiple calls to service layer. It seems that each call to the service layer results in a commit. I thought the transaction was tied to the local thread so it would only commit once per request. What am I missing here?

  7. #7
    Join Date
    Aug 2004
    Location
    Columbus, OH, USA
    Posts
    133

    Default Re: Transactions / thread do not appear to work

    Quote Originally Posted by garpinc2
    Set up declarative transactions and in struts action make multiple calls to service layer. It seems that each call to the service layer results in a commit. I thought the transaction was tied to the local thread so it would only commit once per request. What am I missing here?
    No, the transaction is wrapped around the service method call. For this reason I like to make a single service call per action (which returns a composite view object).

  8. #8
    Join Date
    Sep 2004
    Posts
    346

    Default Please send an example...

    Please send an example...

  9. #9
    Join Date
    Aug 2004
    Location
    Columbus, OH, USA
    Posts
    133

    Default Re: Please send an example...

    Quote Originally Posted by garpinc2
    Please send an example...
    Just have a look at Matt Raible's "Spring Live" e-book, in particular his free Chapter #2 at http://www.sourcebeat.com/docs/Sprin...pleChapter.pdf.

  10. #10
    Join Date
    Sep 2004
    Posts
    346

    Default Recomended best practice

    So how do you handle scenarios where the save logic is tied to the view wrt user action and resulting feedback messages.

    So for instance lets say a screen accomodates 4 use cases i.e If button A pressed do this, button B pressed do this

    and if A pressed and save occurs report message to user one message for Obj1 and another for Obj2 indicating that both Obj1 and Obj2 got saved for the user.

    What's the best practice for 1) passing the operation being performed i.e Button A, B, C was pressed and 2) breturning lists of statuses with varying severity etc

Similar Threads

  1. Declarative transaction management in Spring
    By Jarva in forum Container
    Replies: 4
    Last Post: Nov 12th, 2006, 09:11 AM
  2. Replies: 15
    Last Post: Sep 1st, 2005, 07:41 AM
  3. Declarative Transaction Question
    By xMarcus in forum Data
    Replies: 1
    Last Post: Jan 13th, 2005, 11:59 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •