Announcement Announcement Module
Collapse
No announcement yet.
Struts actions and declarative transactions Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    Re: Struts actions and declarative transactions

    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

    Comment


    • #3
      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

      Comment


      • #4
        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

        Comment


        • #5
          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.

          Comment


          • #6
            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?

            Comment


            • #7
              Re: Transactions / thread do not appear to work

              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).

              Comment


              • #8
                Please send an example...

                Please send an example...

                Comment


                • #9
                  Re: Please send an example...

                  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.

                  Comment


                  • #10
                    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

                    Comment


                    • #11
                      Put your view (parameter and result) processing in the action, your business logic in the service classes and data access in your DAO classes. Spend some time with the Spring examples...

                      Comment

                      Working...
                      X