13 Replies Latest reply on Jun 10, 2008 6:53 PM by nathan dennis

    Seam Remoting and Context

    nathan dennis Expert

      I've been working on a Web 2.0 app that is pretty complex. In the app i perform a lot of partial rerenders based on the users actions.. drag and drop for adding elements to an array... i also use a lot of javascript to calculate various div positions on the screen.... position, dimensions, etc.
      the page also consist of a few mod panels that contain wizard type functionality,, and also contain partial rerenders within them on their own session beans.


      I was originally using session context on this main backing bean. that would allow me to do as many rerenders as i wanted with no problem. But im worried about scalability. This bean could contain massive amounts of data that i really don't want hanging around as long as the user is log in.


      When i tried to switch the main session bean to conversation context... my rerenders no longer work. I'm sure this is a fundamental misunderstanding of when the appserver is cleaning up the conversation context beans...  I was under the impression it was when the conversation id changed. if that was the case i could use something like


      Seam.Remoting.getContext().setConversationId( id );
      Seam.Component.getInstance("modeditAction").getRemoteFile(tmedianame, showCropperBox);



      before i did the ajax call and i would keep the same cid. obviously where

      id = #{conversation.id}



      I would consider doing a complete page refresh,,, which seems to work with conversation context but part of my page contains several large movable image files... png format so i can maintain an alpha channel. i really dont want the user waiting on those to load more than once.



      what am i missing regarding seam.remoting rerenders on callback and the conversation scope? Is this possible using conversation scope without a complete rerender of the page?


      if not,,, is there a way i can clean up a group of session context beans manually before the user's overall session has ended?


        • 1. Re: Seam Remoting and Context
          Shane Bryzak Master

          This should work, could you post your code for your Seam component (modeditAction) plus the relevent bits from your view?

          • 2. Re: Seam Remoting and Context
            nathan dennis Expert

            this is definitely a bit... no need in making everyone's head swim with 25 thousand lines of code... literally.


            from one of the modalPanel.. i oringinaly thought i could use

            @Begin(nested=true)

            on these ,, but had no luck.


            <h:form>
            <a:jsFunction name="rerenderCropperBox" reRender="croppercontainer"/> 
            ...
            <a:outputPanel id="croppercontainer">
            ...
            <rich:menuGroup value="Laplace">
                 <rich:menuItem  submitMode="none" onclick="specialFunction(4)" value="Laplace Light"/>
            
             <s:graphicImage id="cropperphoto"
                       value="#{modeditAction.outpic}"
                             alt="Image" style="z-index:250;"
                       rendered="#{modeditAction.outpic != null}"                         
                             cacheable="false"/>     
            </a:outputPanel>
            <h:form>
            



            from the js Remote Call


            function specialFunction(i){
                 Seam.Remoting.getContext().setConversationId( id ); //passed to javascript when modPanel opened
                 Seam.Component.getInstance("modeditAction").specialFunction(i, editItCallback);
            }
            function editItCallback(result){
                 if(result == "true"){
                        rerenderCropperBox();
                    } else {
                         alert("an error has occurred while loading the selected file");
                    }
            }
            



            from the modalPanel backing bean i make calls too.


            @Stateful
            @Name("modeditAction")
            @Scope(ScopeType.SESSION)
            public class ModularEditAction implements ModularEditLocal, Serializable{
            ...
            
            //imaged editing
                 byte[] outpic =null;
                 
                 
            public String getRemoteFile(String medianame){....sudo get editedImage...}
            ....
                 public String specialFunction(int i) throws IOException{
                  try{
                      PictureUtilLocal sfunction = (PictureUtilLocal) Component.getInstance("pictureUtil");
                      sfunction.loadBuffered(editedImage);
                      sfunction.setQuality(10);
                      sfunction.specialFunction(i);
                      editedImage = sfunction.writeResult("PNG");
                      sfunction.destroy(); //is this a good way to clean up????
                      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                             ImageIO.write(editedImage, filetype, outputStream);
                             outpic = outputStream.toByteArray();
                             outputStream.close();outputStream.flush();
                             rotsw=false;
                      return "true";
                  } catch (Exception e){
                            return "false";
                 }
                 
            


            and the interface


            @Local
            public interface ModularEditLocal {
            ....     
                    public byte[] getOutpic();
                 public void setOutpic(byte[] outpic);
                 
                    @WebRemote
                 public String specialFunction(int i) throws IOException;
                 ....
            

            • 3. Re: Seam Remoting and Context
              nathan dennis Expert

              ignore the try... dont ask me how it got there..

              • 4. Re: Seam Remoting and Context
                Shane Bryzak Master

                I assume that when you tried this you changed it to @Scope(CONVERSATION).  Where/how was your conversation started?

                • 5. Re: Seam Remoting and Context
                  nathan dennis Expert

                  I apologize..


                  actually i used @Scope(Scope.CONVERSATION) which i believe might be the same thing.


                  I tried starting this conversation several ways actually... both with annotation and xml.


                  as i said before the above is an snippet from one of the modalPanels contained on this page.


                  the conversation was originally begin using


                  @Begin(join=true)
                  


                  from the main backing bean of the page.
                  in for the nested modalPanel conversation i created a modpanel.page.xml  and used something like


                  <begin-conversation nested="true"/>



                  when that didnt work, i created a method that pretty much did nothing and added @WebRemote to the interface and start it from the javascript call using


                  @Begin(nested=true)
                   public startAConversation()



                  all this while attempting to use the
                  @Scope(Scope.CONVERSATION)


                  strange this was, if i tried to start a conversation on the modPanels things seemed to break. currently running this modPanel in session context, and only beginning the conversation on the page that it is imported into seems to work fine... as long as i keep track of my conversationId...


                  here is more snippet from the main page that may help you understand how the above example fits into the application..


                  @Stateful
                  @Name("picAction")
                  //@Synchronized
                  //@Scope(ScopeType.CONVERSATION)
                  @Scope(ScopeType.SESSION)
                  public class PicAction implements PicLocal, DropListener, Serializable {
                  ....
                       @Begin(join=true)
                       public void start(){
                            initEdit();
                       }
                  


                  the main xhtml where the modalPanel is included.


                      <h:panelGroup id="photowizard">
                          <a:include  viewId="include/modpanel.xhtml" />
                      </h:panelGroup>
                  



                  then obviously (maybe not so obviously) modpanel.xhtml is directed toward modeditAction.
                  so the conversation is currently only started once on the picAction bean, and both are running in session context. i dont even know why the modPanel is working. my understanding was it shouldnt. after two days of debug with no luck nesting the conversation and getting my partial refresh calls to work in anything other than session context... i start thinking more about how i could keep myself out of memory trouble by cleaning object manually,, instead of building a well designed application. but i know this approach will haunt me... know what i mean?

                  • 6. Re: Seam Remoting and Context
                    Shane Bryzak Master

                    Ok how about you try to start the conversation via a remoting call.  Make sure you set the conversation ID to null before you make the call (Seam.Remoting.getContext().setConversationId(null)), then make sure the conversation ID is set to whatever ID is returned in the context after invoking your @Begin method.  There should be no problem at all having remoting maintain it's own conversation, separate to the rest of the page.

                    • 7. Re: Seam Remoting and Context
                      nathan dennis Expert

                      i tried this. used


                      @Begin(nested=true)
                      public String getRemoteFile(String medianame)



                      in modeditAction.


                      code used in the javascript


                           Seam.Remoting.getContext().setConversationId( null );
                           Seam.Component.getInstance("modeditAction").getRemoteFile(tmedianame, showCropperBox);
                           id=Seam.Remoting.getContext().getConversationId();



                      which didnt quite work as desired. so i used debug to look at the object hanging around out there.


                      i saw a conversation of modeditAction associated with the initial instance of the main page.. like it loaded an instance before i called Begin(). it contained a bunch of null values. then i also saw a conversation with a null view-id that contained all the information that my bean was suppose to to contain.


                      its like the s:graphic is directed at the wrong instance,,


                      thanks for the help. apparently, this is by far my weakest point of understanding the seam framework.

                      • 8. Re: Seam Remoting and Context
                        Shane Bryzak Master

                        Don't use a nested conversation.  Simply let remoting start its own conversation.

                        • 9. Re: Seam Remoting and Context
                          nathan dennis Expert

                          I really feel like i am starting to get close on this. i just did a major amount of reading/rereading of every seams book and documentation i could get my hands on.


                          i got rid of that nest with no luck...
                          correct me if im wrong though...


                          since i have a login. @Begin signifying the beginning of one long running conversation, then i should nest the initial entry point into the this function of my application. And all @Begin(joins) after that would also be nested from the initial entry point until i call @End (only cleaning up the nested conversation).


                          i havent try it yet. and here is why..


                          the app should work theoretically run under one long running conversation starting at the login and using joins.


                          AFTER trying all combinations of the above (Passing cid to Seam Remoting) my ajax refresh is still pointed at the wrong instance. Data is correct on the initial load, but after a action, the refresh displays as if the page wasnt initialized and i see too many conversation in debug.


                          The only place on the page that it preforms the refresh correctly is where i used a4j:support... that one works like a charm...


                          so here is what im thinking.... the problem is here


                          <a:jsFunction name="rerenderCropperBox" reRender="croppercontainer"/> 
                          


                          it is getting a new conversationid on these rerenders...


                          the question is how do i force this component to use the correct conversation id?


                          somehow with

                           
                          <a4j:actionParam>

                          maybe???

                          • 10. Re: Seam Remoting and Context
                            nathan dennis Expert

                            oh man,,, am i confused now... i just build a simplest case to prove my point and i proved myself wrong and this guy
                            My Link
                            wrong in the process.


                            the simplest case works fine if you pass it the id. my app does the exact same thing just with more noise and fluff... and the calls might take longer to process...


                            im at a loss...

                            • 11. Re: Seam Remoting and Context
                              nathan dennis Expert

                              after letting this issue rest a bit,, and reading a bit more.. i figured it out. for any other poor souls through an unfortunate system of events that has lead them to this post... your best friend with ALL richfaces functions is


                              <s:conversationId/>
                              
                              



                              i mean use it everywhere for every call returning an ajax response to the server if the conversation context must land on the same instantiated bean. it may look like the address is staying the same during the call by looking at the address bar. but its not. it is giving you a new conversation id on the update.


                              this includes all drop zones, jsFunctions.
                              as well as setting the conversation id in seams remoting as described above.


                              i would have seen this sooner if the app wasnt already so complex.
                              lesson well learned.

                              • 12. Re: Seam Remoting and Context
                                Sachin Rajshekarappa Newbie

                                I am facing a similar issue with nested conversation on ajax calls.


                                Can anyone direct me to a small example program that illustrates the above discussed topic. i.e using nested conversations with ajax.


                                Thanks

                                • 13. Re: Seam Remoting and Context
                                  nathan dennis Expert

                                  i dont have an example i can post on here... but post some of your code and ill help.