1 2 Previous Next 18 Replies Latest reply on Jul 4, 2008 10:25 PM by nathandennis

    Ending a Conversation

    nathandennis

      I'm having considerable trouble ending a conversation since i upgraded to seam 2.0.1.ga.


      It seems that a seam gen crud app works without problem but on my own beans there is some problem.


      i have tried


      @End
      
         <navigation from-action="#{#{epbackgroundSelect.saveBackgroundLayer}">
             <end-conversation/>
             <redirect view-id="/epigraph/epigraph.xhtml">
                  </redirect>
         </navigation>
       
      as well as 
      
      s:link propagation="end"
      
      


      what should i look for in my configuration that would cause all my conversation magic to go away?

        • 1. Re: Ending a Conversation
          nathandennis

          i should probably also mention that


          conversationPropagation=end
          


          is appearing in my address bar on the redirect.

          • 2. Re: Ending a Conversation
            pmuir

            You need to provide way more information to get any help.

            • 3. Re: Ending a Conversation
              nathandennis

              for example..


              <s:link action="#{epfileuploadAction.end}" 
                      view="/epigraph/epigraph.xhtml"
                      propagation="end"
                      value="Return to Epigraph"/>  
              



              @Stateful
              @Name("epfileuploadAction")
              @Scope(ScopeType.CONVERSATION)
              public class EpFileuploadAction implements EpFileuploadLocal{
              
              @End
              public void end(){
              //do some stuff
              }
              
              


              xxx.page.xml


              <?xml version="1.0" encoding="UTF-8"?>
              <page xmlns="http://jboss.com/products/seam/pages"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.0.xsd"
                    login-required="true">
                 
                 <begin-conversation join="true"/>
                 
                 <navigation from-action="#{epfileuploadAction.end}">
                     <end-conversation/>
                     <redirect view-id="/epigraph/epigraph.xhtml">
                          </redirect>
                 </navigation>
               
              </page>
              
              


              i realize that i am trying to end the conversation three different ways.. but to save space.. if you remove any two of the ways and execute... it is the same result


              conversationPropagation=end
              


              moved into the address bar and the cid never changes. look at it with debug and the conversation remains.

              • 4. Re: Ending a Conversation
                nathandennis

                some of the debug log.


                2008-04-14 13:21:53,328 DEBUG [org.jboss.seam.core.Manager] Discarding conversation state: 27
                2008-04-14 13:21:53,328 DEBUG [org.jboss.seam.contexts.ServletLifecycle] After request, destroying contexts
                2008-04-14 13:21:53,328 DEBUG [org.jboss.seam.Component] instantiating Seam component: org.jboss.seam.transaction.tran
                saction
                
                
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.contexts.Contexts] destroying conversation context
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] instantiating Seam component: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] initializing new instance of: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] done initializing: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] instantiating Seam component: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] initializing new instance of: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] done initializing: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.core.Events] Processing event:org.jboss.seam.preDestroyContext.CONVERSAT
                ION
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] instantiating Seam component: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] initializing new instance of: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] done initializing: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] instantiating Seam component: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] initializing new instance of: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] done initializing: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.core.Events] Processing event:org.jboss.seam.postDestroyContext.CONVERSA
                TION
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.contexts.Contexts] flushing server-side conversation context
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.contexts.Contexts] flushing session context
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.contexts.Contexts] destroying event context
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] instantiating Seam component: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] initializing new instance of: org.jboss.seam.core.events
                2008-04-14 13:21:53,329 DEBUG [org.jboss.seam.Component] done initializing: org.jboss.seam.core.events
                
                



                it looks like the session is actually being destroyed but the address bar isnt getting updated with the correct info. is what im seeing in debug is a new conversation instantiated with the same cid after the original has been deleted?

                • 5. Re: Ending a Conversation
                  andygibson.contact.andygibson.net

                  I sometimes use the following code as a listener to listen for conversations starting and ending. You are probably correct though, when seam ends a conversation the next page takes place in the same conversation with the same Id. The difference is whether the isLongRunning flag has been set. When you end a conversation, it is not destroyed, I believe it is simple made into a temporary (i.e non-long running) conversation.
                  This can trip people up since if you have a dirty entity in the conversation, and you cancel changes and go back to a view page, the view page will display the dirty entity from the conversation as it is left over.
                  (Obviously, if I'm wrong, someone please correct me)


                  Here's the code to implement the listener :


                  package org.seamtest;
                  
                  public interface ConversationListener {
                  
                       void observeConversationStart();
                       void observeConversationEnd();
                  }
                  


                  and


                  package org.seamtest;
                  
                  import javax.ejb.Stateless;
                  
                  import org.jboss.seam.annotations.Logger;
                  import org.jboss.seam.annotations.Name;
                  import org.jboss.seam.annotations.Observer;
                  import org.jboss.seam.log.Log;
                  
                  @Stateless
                  @Name("conversationListener")
                  public class ConversationListenerBean implements ConversationListener {
                  
                       @Logger
                       private Log log;
                       
                       @Observer(value="org.jboss.seam.endConversation")
                       public void observeConversationEnd() {
                            log.debug("CONVERSATION Ended");
                            
                       }
                  
                       @Observer(value="org.jboss.seam.beginConversation")
                       public void observeConversationStart() {
                            log.debug("CONVERSATION Started");          
                       }
                  
                       
                  }
                  



                  Cheers,


                  Andy

                  • 6. Re: Ending a Conversation
                    nathandennis

                    that was a good idea.
                    it turns out that the conversations are ending and starting exactly where it is suppose too. however, when it restarts it is dirty. (data from the previous instance)


                    how do i force it to clean up?

                    • 7. Re: Ending a Conversation
                      andygibson.contact.andygibson.net

                      Clean up can be done a few ways but I think the main idea is to set the context variables to null and outject them or load refreshed data into the variables and the persistence context (PC) as necessary.  However, there are a few caveats in terms of entities.


                      The PC may contain dirty copies of entities and the same PC may end up being reused as it is contained in the conversation that is reused. That can be another source of dirty data turning up since any entity request on the PC may return the dirty version. There is a clear() method on the PC that can help avoid that issue.


                      Generally speaking, when I display a list of items I always do it stateless so there is nothing to clean up. When I go and edit an  item, I have a cancel changes method on my entity home so I can load a fresh version. I could set the variable to null and outject it which would trigger a re-load by seam next time that variable is needed. Outjecting a null for an entity variable isn't enough since the PC can hold the dirty version, so you might want to do a refresh on the entity to put the clean version in the PC.


                      I think some people have registered event listeners to entity types so if you save changes to an entity, any lists which might contain a different instance of the entity are invalidated and re-loaded. I don't quite like this as it is a little too tightly coupled for my taste. However, it may be a necessary evil if you really want a stateful list and you want it to be aware of changes to the entities in other browser windows.


                      If you post what kind of data you need to clean up, I, or someone else might be able to give you a more specific answer.


                      At one time, there was talk of a kill conversation propagation value which would end the conversation and then scatter it to the four winds so it would not be re-used.


                      Cheers,


                      Andy

                      • 8. Re: Ending a Conversation
                        nathandennis

                        Thanks for the response. im not sure if it is the entitys that are causing the problem. here is an example... user arrives at this page and a conversation is started with the backing bean in conversation scope. when the conversation is ended when user leaves the page (and we know it is by using your above code)... and user returns to that page... the original instantiated bean remains,, with the old data array still visible.


                        should i be injecting the PC and clearing it in this bean somehow?


                        
                        
                        @Stateful
                        @Name("epfileuploadAction")
                        @Scope(ScopeType.CONVERSATION)
                        public class EpFileuploadAction implements EpFileuploadLocal{
                             
                             @In
                             Identity identity;
                             
                             @PersistenceContext
                             private EntityManager entityManager;
                             
                             @Logger
                             private Log log;
                             
                              @In
                              private FacesMessages facesMessages;
                             
                              
                              
                                  private ArrayList<FileData> files = new ArrayList<FileData>();
                                  private int uploadsAvailable = 5;
                                  private boolean autoUpload = false;
                                  
                                  public int getSize() {
                                       if (getFiles().size()>0){
                                            return getFiles().size();
                                       }else 
                                       {
                                            return 0;
                                       }
                                  }
                        
                                  
                                  public void listener(UploadEvent event) throws IOException{
                                     UploadItem item = event.getUploadItem();
                                       if (item.isFile()) {
                                            byte[] data = FileUtils.readFileToByteArray( item.getFile() );
                                       
                                            if(data == null){
                                                 log.info("data is null");
                                            }
                                            if(FilenameUtils.getName(item.getFileName()).equals("")){
                                                 log.info("filename is null");
                                            }
                                            if(data.length==0){
                                                 log.info("length == 0");
                                            
                                            }
                                          String name = FilenameUtils.getName(item.getFileName());
                                          String[] format = name.toString().split("\\.");
                                         String filetype ="*";
                                         if ("png".equals(format[1].toLowerCase())){
                                                  filetype = "image/png";
                                            } else if ("jpg".equals(format[1].toLowerCase())) {
                                                  filetype = "image/jpeg";
                                             } else if ("bmp".equals(format[1].toLowerCase())){
                                                  filetype = "image/bmp"; // filetype not supported by s:graphicimage
                                             } else if ("image/gif".equals(format[1].toLowerCase())){
                                                  filetype ="image/gif";
                        //                          disabled until java 6 installed. will not write gif in java 5
                                             }
                                        FileData file = new FileData(FilenameUtils.getName(item.getFileName()), data.length, data, filetype );
                                     files.add(file);
                        
                                         try{
                                       if(!filetype.equals("*")){       
                                                     
                                         FileUploadLocal fileupload = (FileUploadLocal) Component.getInstance("uploadAction");
                                         
                                         fileupload.nonComponent(data, filetype, name.toString(), 102);
                                       }
                                      } catch (Exception e){
                                               log.error(e.getStackTrace());
                                          }
                                     
                                     }
                                     
                                      uploadsAvailable--;
                                  
                                  }
                                  
                                  public String clearUploadData() {
                                       files.clear();
                                       setUploadsAvailable(5);
                                       return null;
                                  }
                                  
                                  public ArrayList<FileData> getFiles() {
                                       return files;
                                  }
                        
                                  public void setFiles(ArrayList<FileData> files) { 
                                       this.files = files;
                                  }
                        
                                  public int getUploadsAvailable() {
                                       return uploadsAvailable;
                                  }
                        
                                  public void setUploadsAvailable(int uploadsAvailable) {
                                       this.uploadsAvailable = uploadsAvailable;
                                  }
                        
                                  public boolean isAutoUpload() {
                                       return autoUpload;
                                  }
                        
                                  public void setAutoUpload(boolean autoUpload) {
                                       this.autoUpload = autoUpload;
                                  }
                              
                              
                                  @End
                                  public void end(){}
                             
                             @Destroy @Remove
                             public void destroy() {}
                        
                        
                        }
                        
                             



                        pages.xml


                        <?xml version="1.0" encoding="UTF-8"?>
                        <page xmlns="http://jboss.com/products/seam/pages"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                              xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.0.xsd"
                              login-required="true">
                           
                           <begin-conversation join="true"/>
                           
                           <navigation from-action="#{epfileuploadAction.end}">
                               <end-conversation/>
                               <redirect view-id="/epigraph/epigraph.xhtml">
                                    </redirect>
                           </navigation>
                         
                        </page>
                        
                        

                        • 9. Re: Ending a Conversation
                          andygibson.contact.andygibson.net

                          Try :


                          @End
                          public void end(){
                            files.clear();
                          }
                          



                          That should clear out the data when you end the conversation.


                          If you want to be proper you could have a clear/reset method on the bean that will reset the values at the end of the conversation.



                          • 10. Re: Ending a Conversation
                            nathandennis

                            you know,,, i was doing this in some other places and stop because i wasnt sure if deleting an array of pointers was such a solid choice. i was afraid it might cause memory leaks. but now that you mention it... i dont think i am have this trouble any where the entities arent in an arraylist.


                            is it possibly part of the seam framework seeing this arraylist outjected and stopping the clean up of the object?


                            since im not the only person cleaning up with this i will re implement it.


                            one final question though...


                            should i be worried that the conversation id is not updating in the address bar and is reverting to the same number instead of advancing?

                            • 11. Re: Ending a Conversation
                              andygibson.contact.andygibson.net

                              I don't think there would be a problem with the conversation Id not advancing. After all, it is because of this Id that you are re-using the same conversation.


                              What you could also do is set the conversation propagation to 'none' instead of just ending it. This would cause the next request to start a brand new conversation instead of just ending the old one and re-using the conversation.


                              Here you wouldn't have to worry about any clean up since you will never re-use that conversation. No conversation is propagated over to the next page and the next page takes place in a new temporary conversation.


                              I don't think Seam treats arraylists any different in terms of clean up. Looking at your code you aren't outjecting the array list, but you might have been talking about some other code.


                              I like to start with a new conversation, use the conversation, end it, and never re-use it, so I don't usually perform any conversation propagation.


                              This is one of those 'best practices' things which for me personally, it is a best practice, but I'm not sure what the seam best practices are.


                              • 12. Re: Ending a Conversation
                                nathandennis

                                I'll give propagation 'none' a shot and see if i can force it to advance.


                                apparently i didnt post that part of the code, but i had outjected using @Out and @Factory. i did stumble on a pretty good trick.


                                 @Factory(value="somefactory", scope=ScopeType.EVENT)
                                



                                that seemed to keep some of those pesky outject from hanging around unwanted like. previously, i didnt not realize you could do this.


                                thanks for all the help

                                • 13. Re: Ending a Conversation
                                  nathandennis

                                  for anyone following in my foot steps trying to fight this same battle...


                                  the gist is in order to both end the conversation and cause the conversation id to advance without manually altering it... you have to redirect to a page that does not immediately begin or join a new conversation. prime example is the seam gen app..


                                  select a record from the table. conversation id advances. move to edit it. conversation id advances. end the conversation by clicking done.  conversation id does not advance but the conversation has ended. conversation will advance on the next redirect.


                                  andy or pete correct me if im wrong.. but this appears to be what is happening. work great with a simple redirect, although i lose my cid in the address bar. it is correct throughout the xhtml.

                                  • 14. Re: Ending a Conversation
                                    andygibson.contact.andygibson.net

                                    Hey Nathan,


                                    It's all really a question of whether the conversation is propagated or not, and this can be done both explicitly and implicitly.


                                    s:link and s:button both have a propagation attribute that let you propagation the conversation (the default) or not. h:commandLink and h:commandButton do not propagate conversations unless you use the special s:conversationId  or s:conversationPropagation tags.


                                    Remember that all pages use a conversation even if none was started implicitly, a temporary conversation is used for that request. If you do not propagation the conversation, the next page (which still needs a conversation) will grab a new conversation instance which will advance the conversation Id.


                                    Cheers,


                                    Andy


                                    1 2 Previous Next