0 Replies Latest reply on Aug 25, 2007 9:23 AM by krica

    Problem with no handledException with StaleObjectStateExcept

    krica

      Hi,

      I've been trying to figure this out for 5 straight days and cannot understand why org.jboss.seam.handledException is not being set in certain cases. Actually, it is set, but I cannot retrieve it in my handler class.

      First the setup:
      -Seam 1.2.1
      -Tomcat
      -Richfaces 3.0.1
      -Myfaces 1.1.5

      Ok, so I have a "my account" page, where a user can update his details. I also have an admin function, where an admin can update any user's details. The StaleObjectStateException occurs if both the user and the admin update the details at the same time. Nothing strange about this. What is strange is that if the admin is the "winner" (i.e. his update was commited) then the exception handler for the user's exception gets hold of org.jboss.seam.handledException value and proceeeds. However, if the user is the winner, then the admin's handler (same class) does NOT get the org.jboss.seam.handledException value. Why? Obviously something is happening in one case but not the other, but I can't figure out what.

      Here are some details:

      The "handler" is defined as follows:

      
      pages.xml
      
       <page view-id="/errorConcurrentModif.xhtml" action="#{concurrentModifHandler.handle}">
       <end-conversation before-redirect="true"/>
       </page>
      
      
       <exception class="org.hibernate.StaleObjectStateException">
       <end-conversation/>
       <redirect view-id="/errorConcurrentModif.xhtml"/>
       </exception>
      
      


      So, when a StaleObjectStateException occurs, the user is redirected to /errorConcurrentModif.xhtml, which has a page action handle().

      @Stateless
      @Name("concurrentModifHandler")
      public class ConcurrentModifHandler implements ConcurrentModifHandlerLocal {
      
       public void handle() {
       ...
       StaleObjectStateException sose = null;
       if (Contexts.isConversationContextActive()) {
       Object o = Contexts.getConversationContext().get("org.jboss.seam.handledException");
       if (o != null && o instanceof StaleObjectStateException) {
       sose = (StaleObjectStateException) o;
       }
       }
      
       ...
       }
      


      Here, sose is null in one case but not the other. In both cases, prior to reaching my code, org.jboss.seam.core.Exceptions successfully sets "org.jboss.seam.handledException" into an instance of ServerConversationContext's "additions" map.

      Another funny thing I noticed was that in the case where it works (as I expected), the ServerConversationContext's flush() method is called before my handler, but in the case where sose is null, the flush() method is called afterwards. flush() is where the values in the additions map are moved to the Session's attributes.

      Here's how the pages are set up. First the admin's (role is named BR). The admin (BR) searches for users and gets presented with a data table in a page called manageBidders. The actualt DataModel is created in a Session scoped component.

      @Stateful
      @Name("bidderSearch")
      @Scope(ScopeType.SESSION)
      @Restrict("#{s:hasRole('BR')}")
      public class BidderSearchingAction implements BidderSearchingLocal {
       ...
       @DataModel
       private List<Bidder> bidders;
       ...
       @Factory
       public List<Bidder> getBidders() {
       ...
       return bidders;
       }
      }
      


      The admin then clicks on the edit link in the data table
      <rich:dataTable var="bidder" value="#{bidders}">
      ...
      <s:link action="#{bidderManager.showEdit(bidder)}" value="#{messages.label_Edit}"/>
      ...
      </rich:dataTable>
      


      BidderManager:
      @Stateful
      @Scope(ScopeType.CONVERSATION)
      @Name("bidderManager")
      public class BidderManager implements BidderManagerLocal {
       ...
       @Begin(join = true)
       public void showEdit(Bidder selectedBidder) {
       selBidder = database.merge(selectedBidder);
       userName = selBidder.getUserName();
       emailRepeat = selBidder.getEmailAddress();
       action = Constants.EDIT;
       }
       ...
      }
      


      And the corresponding entry in pages.xml

       <page view-id="/restricted/manageBidders.xhtml">
       <restrict>#{s:hasRole('BR')}</restrict>
       <navigation from-action="#{bidderManager.showEdit(bidder)}">
       <redirect view-id="/restricted/editBidder.xhtml"/>
       </navigation>
       </page>
      


      When the admin submits the changes, an action bidderManager.save() is called.

       <h:commandButton id="save" action="#{bidderManager.save}" value="#{messages.button_Save}"/>
      
      
       In BidderManager:
      
       @End
       @Restrict("#{s:hasRole('Bidder') or s:hasRole('BR')}")
       public void save() {
       ...
       }
      
      


      Navigation after save is handled by pages.xml:
       <page view-id="/restricted/editBidder.xhtml" no-conversation-view-id="/restricted/manageBidders.xhtml">
       <restrict>#{s:hasRole('Bidder') or s:hasRole('BR')}</restrict>
       <navigation from-action="#{bidderManager.save}">
       <rule if="#{bidderManager.action == constants.EDIT_MYACCOUNT}">
       <redirect view-id="/home.xhtml"/>
       </rule>
       <redirect view-id="/restricted/manageBidders.xhtml"/>
       </navigation>
       </page>
      
      


      Now, for the user (the Bidder) the process is as follows:

      His menubar has a link to "my account":

       <s:link id="accountBidder" rendered="#{s:hasRole('Bidder')}" view="/home.xhtml" action="#{bidderManager.showEditMyAccount}" value="#{messages.label_MyAccount}" propagation="none"/>
      


      As you see, it is the same action class BidderManager, but in this case the showEditMyAccount method

       @Begin(join = true)
       @Restrict("#{s:hasRole('Bidder')}")
       public void showEditMyAccount() {
       selBidder = loggedInUser.getBidder();
       userName = selBidder.getUserName();
       action = Constants.EDIT_MYACCOUNT;
       }
      


      This presents the user with the same page as the admin, but with some fields disabled. The same bidderManager.save() as for the admin is called on submit. The loggedInUser object is a Session scoped object created during login.

      The only significant difference I can see is that the edited user object comes from a Session scoped search component in one case, and a directly from the Session scoped loggedInUser object in the other.

      Any ideas on how I can get org.jboss.seam.handledException would be very helpfull