1 2 Previous Next 15 Replies Latest reply on May 14, 2009 3:03 PM by Arshad Mahmood

    Remove and Destroy annotations

    Arbi Sookazian Master

      Ok so I'm confused as to whether or not I need the @Destroy in addition to @Remove annotations as is typically customary in Seam components like SFSB, for example.


      However, looking at HotelBookingAction from 2.1.1 distro, this is what I see:


      @Remove
      public void destroy() {}



      Was the @Destroy omitted on purpose for the above example?  If yes, why?


      Most of the Seam distro example code seem to use something similar to this:


      @Remove @Destroy
      public void destroy() {}



      SiA reference:




      The method on a component annotated with @PostConstuct is called after an
      instance has been created and initialized (meaning after the initial property values
      have been applied). The @PreDestroy method is called before the component
      instance is removed from the context in which it resides. Both of these annotations
      are part of the Java EE 5 API. When working with a non-EJB component, you can use
      either the standard Java EE annotations or their synonyms from the Seam API. The
      @Create annotation stands in for the @PostConstruct annotation and the @Destroy
      annotation stands in for the @PreDestroy annotation in non-Java EE 5 environments.

      Ok, so assuming your app is in a JEE 5 environment, should we use the @Destroy annotation in addition to @Remove or not?


      From JavaDocs:


      org.jboss.seam.annotations.Destroy
      Alternative to javax.annotations.PreDestroy for use in a pre Java EE 5 environment. Designates a destroy method that is called when a context ends and the component is being disposed.
      



      Note pre Java EE 5 environment.  Ok, so does that mean J2EE 1.4 or plain Tomcat or what?


      page 93 of the Yuan et al book uses both annotations as well.


      ????

        • 1. Re: Remove and Destroy annotations
          Arbi Sookazian Master

          More data (I guess I was wrong about ejb container calling @Remove method??)


          from SiA:


          The @Remove method is called when the context containing the session bean reference is destroyed. Seam uses
          this method to instruct the EJB container to destroy the session bean. If the @Remove
          method is invoked directly, it leads to an immediate removal of the session bean reference,
          unless a runtime or remote exception is thrown and the exception class is
          marked with @ApplicationException (it’s not a system exception) or an exception is
          thrown that isn’t a runtime or remote exception and the retainIfException attribute
          on the @Remove annotation is set to true.
          
          NOTE Note that there is a distinct difference between the @Remove and @Pre-
          Destroy annotations. The method marked with the @Remove annotation
          is called when Seam removes the reference to the instance, and the method
          marked with the @PreDestroy annotation is called when the EJB 3 container
          destroys the instance itself.

          • 2. Re: Remove and Destroy annotations
            Nikolay Elenkov Master

            IIRC, you used to need both Destroy and Remove, but that restriction was removed somewhere along the line,
            and now you only need Remove on your SFSB's.


            Books and specs are good, but when in doubt, use the source :) This stuff is handled/checked in org.jboss.seam.Component.


            IIRC, Remove/Destroy methods are called by Seam interceptors (RemoveInterceptor or some such.).


            HTH



            • 3. Re: Remove and Destroy annotations
              Arbi Sookazian Master

              Nikolay, thx for your response.  I took a look at the org.jboss.seam.Component class but it's somewhat long and confusing.  :)


              I used process of elimination (unfortunately no root cause detected yet) and simplified my JSF/SFSB to the following (see below code).


              After searching for a serial number and clicking submit button, then clicking goNext link,
              when I click the back button on my browser from the 2nd page, the destroy() method is executed (I added a debug breakpoint).  In the POC code below, the destroy() method is not being called when I click back button.


              Anybody know why destroy() is called in one use case and not the other when back button is click in browser?


              There is nothing outstanding or interesting in pages.xml that is causing an explicit end to LRC, I checked already.


              TestManageEquipment.xhtml (this one is problematic with back button click from 2nd page - dataTable data is missing probably due to destroy() being fired when I click back button in IE7):


              <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                                    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
              
              <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                   xmlns:ui="http://java.sun.com/jsf/facelets"
                   xmlns:h="http://java.sun.com/jsf/html"
                   xmlns:f="http://java.sun.com/jsf/core"
                   xmlns:a4j="http://richfaces.org/a4j"
                   xmlns:rich="http://richfaces.org/rich"
                   xmlns:s="http://jboss.com/products/seam/taglib"
                   template="/templates/normal.xhtml">
                   
              <ui:define name="body">
                                     
                        
                                             <h:form>
                                               <h:panelGrid columns="3">
                                                    <h:column>
                                                         <b>Serial Number:</b> 
                                                    </h:column>
                                                    
                                                    <h:column>
                                                        <h:inputText id="serialNumberId" 
                                                                    value="#{testManageEquipment.serialNumber}" 
                                                                    size="32" 
                                                                    maxlength="32" 
                                                                    required="true">
                                                         </h:inputText>
                                                    </h:column>     
                                                    <h:column>
                                                         <a4j:commandButton id="searchButton"                                             
                                                                             value="Search" 
                                                                             action="#{testManageEquipment.searchSerialNumber}"   
                                                                             reRender="form1">
                                                         </a4j:commandButton>                            
                                                    </h:column>
                                               </h:panelGrid>     
                                               <BR/>
                                               <BR/>
                                                 <BR/>
                                                                                                                                
                                                <a4j:commandLink id="goNext" value="goNext" action="#{testBackButtonAction.goNext}"/>                  
                                          </h:form>
                                          <BR/>
                                          <BR/>
                                          <BR/>
                                              <h:form id="form1">     
                                                   <h:panelGrid columns="2">
                                                        <h:outputText value="MAC Address:"/>
                                                      <h:outputText value="#{testManageEquipment.equipmentDetailBean.macAddress}"/>
                                                      <h:outputText value="Desc:"/>
                                                      <h:outputText value="#{testManageEquipment.equipmentDetailBean.description}"/>
                                                 </h:panelGrid>                                             
                                            </h:form>
                                       
                                              
                          
                       
              </ui:define>     
              </ui:composition>



              TestManageEquipment SFSB:


              @Stateful
              @Name("testManageEquipment")
              @Scope(ScopeType.CONVERSATION)
              @SuppressWarnings("unchecked")
              public class TestManageEquipmentAction implements TestManageEquipmentLocal 
              {
                   @Logger
                   private Log log;
                        
                   private EquipmentDetailBean equipmentDetailBean;
                   
                   private Boolean showCreateNew = false;
                   
                   private String serialNumber;
                   
                   /************************* BEGIN PUBLIC METHODS *************************/
                   
                   @Begin(join=true)
                   public void searchSerialNumber() 
                   {     
                        equipmentDetailBean = new EquipmentDetailBean();
                        equipmentDetailBean.setDescription("desc");
                        equipmentDetailBean.setEarliestReturnDate(new Date());
                        equipmentDetailBean.setMacAddress("MC90098II8");
                        
                        showCreateNew = true;
                   }
                   
                   
                   /*********************************SETTERS/GETTERS********************************************/
                        
                   public void setSerialNumber(String serialNumber)
                   {
                        this.serialNumber = serialNumber;
                   }
                   
                   public String getSerialNumber() 
                   {
                        return serialNumber;
                   }
                   
                   public Boolean getShowCreateNew()
                   {
                        return showCreateNew;
                   }
                   
                   public EquipmentDetailBean getEquipmentDetailBean() {
                        return equipmentDetailBean;
                   }
              
              
                   public void setEquipmentDetailBean(EquipmentDetailBean equipmentDetailBean) {
                        this.equipmentDetailBean = equipmentDetailBean;
                   }
                   
                   //@Remove @Destroy
                   @Remove
                   public void destroy () {
                        log.info("in destroy()");
                   }
              
              
                   
              
              }
              



              And the POC whose back button functionality works fine:


              TestBackButton1.xhtml:


               <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                                    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
              
              <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                   xmlns:ui="http://java.sun.com/jsf/facelets"
                   xmlns:h="http://java.sun.com/jsf/html"
                   xmlns:f="http://java.sun.com/jsf/core"
                   xmlns:a4j="http://richfaces.org/a4j"
                   xmlns:rich="http://richfaces.org/rich"
                   xmlns:s="http://jboss.com/products/seam/taglib"
                   template="/templates/normal.xhtml">
                   
              <ui:define name="body">
               
                    <h:form>
                         <rich:dataTable id="courseList" 
                                         var="course"
                                       value="#{testBackButtonAction.searchResults}" 
                                       rendered="#{not empty testBackButtonAction.searchResults}"> 
                                <h:column>
                                    <f:facet name="header"><h:outputText value="Course ID"/></f:facet>               
                                    <s:link view="/TestBackButton2.xhtml"  value="#{course}"/>                      
                                </h:column>  
                      </rich:dataTable>  
                      
                      <h:inputText value="#{testBackButtonAction.userInputCourseId}" id="searchBox"/>
                      <h:commandButton  id="searchBtn" value="search" action="#{testBackButtonAction.search}" reRender="courseList"/>
                      <a4j:commandLink id="goNext" value="goNext" action="#{testBackButtonAction.goNext}"/>     
                   </h:form>   
              
              
              </ui:define>     
              </ui:composition>



              TestBackButton2.xhtml:


              <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                                    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
              
              <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                   xmlns:ui="http://java.sun.com/jsf/facelets"
                   xmlns:h="http://java.sun.com/jsf/html"
                   xmlns:f="http://java.sun.com/jsf/core"
                   xmlns:a4j="http://richfaces.org/a4j"
                   xmlns:rich="http://richfaces.org/rich"
                   xmlns:s="http://jboss.com/products/seam/taglib"
                   template="/templates/normal.xhtml">
                   
              <ui:define name="body">
              
                   <h:form>
                         <a4j:commandLink id="btnBack" 
                                                  value="go back" 
                                                  action="#{testBackButtonAction.goBack}"/>
                   </h:form>
                   
                   <s:link view="/TestBackButton1.xhtml" value="go back via s:link"/>
                   
              </ui:define>     
              </ui:composition>
              



              TestBackButtonAction SFSB:


              @Name("testBackButtonAction")
              @Stateful
              public class TestBackButtonAction implements TestBackButtonLocal {
              
                   @Logger
                   private Log log;
                   
                   private List<Integer> searchResults;
                   
                   private Integer userInputCourseId;
                   
                   private Integer courseId;
              
                   public String goNext() {
                        
                        return "/TestBackButton2.xhtml";
                   }
                   
                   public String goBack() {
                        
                        return "/TestBackButton1.xhtml";
                   }
              
                   
                   @Begin(join = true)
                   @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
                   public void search() {
                        log.info("courseList.search() called. input courseId for search is: "+this.userInputCourseId);
                      //put your search logic here and populate the searchResults
                        this.searchByCourseId(this.userInputCourseId);          
                   }
              
              
                   public List<Integer> getSearchResults() {
                        return searchResults;
                   }
                   
                   public void searchByCourseId(Integer userInputCourseId) {
                        searchResults = new ArrayList<Integer>();
                        searchResults.add(userInputCourseId);
                   }
                   
                   public Integer getUserInputCourseId() {
                        return userInputCourseId;
                   }
              
              
                   public void setUserInputCourseId(Integer userInputCourseId) {
                        this.userInputCourseId = userInputCourseId;
                   }
                   
                   @Remove @Destroy
                   public void destroy() {
                        log.info("in destroy");
                   }
              
              }

              • 4. Re: Remove and Destroy annotations
                Arshad Mahmood Newbie

                I am having some problems related to this with Glassfish. It seems like Glassfish doesn't like putting Stateful sessions beans in temporary conversations.


                So what does it mean then to have two or more conversations with the same Stateful session bean (either because they're nested, or because of bad coding with the cid not being passed to a link and therebu creating another conversation).


                I had assumed that Seam would just get another instance of the Stateful session bean. But certainly on Glassfish I have lot problem when I do this (can't inject EntityManager in the new instance for example).


                It's all weird, I wish I had stuck to sessions now and not bothered with conversations.


                Regards.


                • 5. Re: Remove and Destroy annotations
                  Arbi Sookazian Master

                  Robert Burns wrote on May 13, 2009 22:41:


                  I wish I had stuck to sessions now and not bothered with conversations.

                  Regards.




                  In that case you may as well stick with Spring (and I believe Web Flow supports conversations to some extent).  In fact I'm going to a SpringSource Tomcat optimization training tomorrow in LA.  The Advanced Seam training is not even available yet, I've been using Seam at work for 2 yrs now! 


                  The JBoss core devs seem to rarely respond to help threads on this forum (anymore) and are focusing on Seam 3 and Web Beans RI/TCK, etc.


                  Very lame.

                  • 6. Re: Remove and Destroy annotations
                    Arshad Mahmood Newbie
                    >In that case you may as well stick with Spring (and I believe Web Flow supports conversations to some extent)

                    I am 100% committed to getting seam to work, at the moment I won't bother trying to raise a JIRA for the problems I am having because it's not worth fixing them. I would rather developers work on Seam 3 and JSF 2.0 and JEE 6 support, once that stack is ready I can assure them I have a very complex application to build on it and hopefully harden Seam and Glassfish support.

                    To be honest the application was working OK with JBoss, unfortunately the performance of JBoss is very poor so I decided to port it to Glassfish. Now the performance is great but obviously a lot of these niggling problems (all of which I have found a workaround for, but it's pity I have to waste so much time just getting seam and glassfish to work rather than focus on the actual application I am developing).

                    Regards.
                    • 8. Re: Remove and Destroy annotations
                      Nikolay Elenkov Master

                      Robert Burns wrote on May 14, 2009 00:20:



                      I am 100% committed to getting seam to work, at the moment I won't bother trying to raise a JIRA for the problems I am having because it's not worth fixing them.



                      You should definietly raise JIRA issues. Because:



                      1. the problem will never get fixed if no one reports it

                      2. even if doesn't get fixed right away, if you post your workarounds in the JIRA issue, that will save time for everyone else facing the problem




                      I would rather developers work on Seam 3 and JSF 2.0 and JEE 6 support, once that stack is ready I can assure them I have a very complex application to build on it and hopefully harden Seam and Glassfish support.


                      I am looking forward to Seam 3 as well, but that doesn't mean that Seam 2.1/2 should be abandoned (look what happend to Seam 2.0...)
                      Systems developed with Seam 2 will be used and need to be maintained for at least a few years, and upgrading/rewriting is not always
                      easy/possible. So every JIRA helps :)



                      ....
                      (all of which I have found a workaround for, but it's pity I have to waste so much time just getting seam and glassfish to work rather than focus on the actual application I am developing).


                      Time wasted is, of course, unfortunate, but that's precisely why you should post/report your workarounds -- so that other people could benefit from your experience.


                      BTW, is Glassfish really that much faster than JBoss?




                      • 10. Re: Remove and Destroy annotations
                        Stuart Douglas Master

                        At a guess I would say that jboss uses more memory than glassfish, which is putting you close the the memory limit for the JVM and making the GC go into overdrive, killing performance. How much memory are you giving the JVM?

                        • 12. Re: Remove and Destroy annotations
                          Stuart Douglas Master

                          Just out of curiosity is it mainly startup time that you are talking about? Or is it everything?
                          I have always been curious about glassfish, but never curious enough to put in the hours to port my app over.

                          • 13. Re: Remove and Destroy annotations
                            Arshad Mahmood Newbie
                            >Just out of curiosity is it mainly startup time that you are talking about? Or is it
                            >everything? I have always been curious about glassfish, but never curious enough to put in
                            >the hours to port my app over.

                            No, startup is not really an issue. Obviously, I deploy the application development about a dosen times daily so it's nice to have the redeployment a couple of seconds quicker but not that critical.

                            The main problem for me was the fact the webapp was unusable on production. Taking 20-30 seconds to display the first page, and even subsequent pages taking about 5-7 seconds and then the load average rising inexorabley.

                            There was I could go live with that. I even considered dumping J2EE and going back to a PHP based solution at the darkest hour, but I just couldn't believe that things could be that bad. I looked at open source alternatives for J2RR and the only other viable solution was Glassfish so I decided to give it a go, and I am very happy with the outome.

                            Regard.
                            • 14. Re: Remove and Destroy annotations
                              Miroslav Vasko Newbie

                              JBoss 5 is VERY demanding. If performance is a concern, I advise to try staying away from it. In comparison with 4.2.3 it starts more than 100 percent longer and uses at least 100 percent more RAM. I've never used Seam with GlassFish but what I remember from using NetBeans Web Pack app on it, it was also nowhere that demanding.

                              1 2 Previous Next