14 Replies Latest reply on Jul 18, 2008 11:02 PM by Ken Clark

    How to handle by-browser-page scope

    Ken Clark Newbie

      I am guessing this has been discussed before but I can't figure a way to search for it so my apologies if this has already been covered.


      Basically, what I need is to keep certain variables in a scope that is session-wide, but on a per-browser-window/tab basis.  In other words a setting that will remain with any browser page until reset by the user on that page.  Other views open by the user should not be affected by changes on another window.


      In past projects, we have handled this using Tomahawk's t:saveState (which is embedded in every page in the application), but I am hoping that there is a Seam-specific solution.


      Can anyone suggest a way to do this?


      Is there any consideration of adding such a scope to the Seam core?

      Thanks,
      ken

        • 1. Re: How to handle by-browser-page scope
          Francisco Jose Peredo Noguez Master

          Have you tried with ScopeType.PAGE?

          • 2. Re: How to handle by-browser-page scope
            Ken Clark Newbie
            <blockquote>
            _Francisco Peredo wrote on Jul 15, 2008 22:53:_<br/>

            Have you tried with |ScopeType.PAGE|?

            </blockquote>

            No, that would only get the value through to the next page request (I think).

            What I would like is to be able to say something like:

            @In(scope=ScopeType.SESSION_BY_BROWSER_WINDOW)
            String myConfigVar;

            and know that I would get the same value every time from every request that originated from the same browser window.

            Note: sorry for the poor choice of title originally -- I changed the word "page" to "window".

            Thanks,
            ken
            • 3. Re: How to handle by-browser-page scope
              Francisco Jose Peredo Noguez Master

              Hi!




              What I would like is to be able to say something like:

              @In(scope=ScopeType.SESSION_BY_BROWSER_WINDOW)
              String myConfigVar;



              and know that I would get the same value every time from every request that originated from the same browser window.



              Well then use ScopeType.CONVERSATION. (Of course, you need to use @Begin to enable long running conversations)

              • 4. Re: How to handle by-browser-page scope
                Ken Clark Newbie

                I have not looked much into nested conversations, but my gut feeling is that that is going to add a lot of complexity.  I will have several individual conversations specifically for handling various user transactions, yet there will be a few attributes I want to share basically across the session (yet not across browser windows.)  I can add a conversation to handle this, but then must deal with all my other conversations as nested conversations -- right?


                Thanks,
                ken

                • 5. Re: How to handle by-browser-page scope
                  Francisco Jose Peredo Noguez Master

                  Hi!



                  Ken Clark wrote on Jul 16, 2008 01:26:


                  I have not looked much into nested conversations,



                  I didn't mention nested conversations... I wrote long running conversations




                  but my gut feeling is that that is going to add a lot of complexity.



                  I agree about nested conversations adding complexity, but... I thought you wanted the same value every time from every request that originated from the same browser window and for that you do not need nested conversations, good old long running conversations are good enough.




                  I will have several individual conversations specifically for handling various user transactions, yet there will be a few attributes I want to share basically across the session (yet not across browser windows.)



                  Well you can use ScopeType.SESSION for those few attributes you want to share basically across the session (still no need for nested conversations)


                  Now if you want to share them across the session (yet not across browser windows.)... First thing that comes to my mind is that is a contradiction... scopes go from more general to specific ScopeType.APPLICATION ->  ScopeType.SESSION -> ScopeType.CONVERSATION -> ScopeType.PAGE (there are other scope types but they follow that basic rule) so, either you want somethig to be shared for all the browser windows inside the same session (ScopeType.SESSION) , or you want something fora particular window (ScopeType.CONVERSATION) or for a particular page (ScopeType.PAGE), I just do not see how something could be shared them across the session (yet not across browser windows.)



                  I can add a conversation to handle this, but then must deal with all my other conversations as nested conversations -- right?


                  Perhaps (If what you need is smaller conversations inside a long running conversation across many pages... because if it is going to be in the same page you can use ScopeType.PAGE) , I would have to be more familiarized with the effect you want to achieve... one thing is for sure, I can not think of an easier way to do this without Seam ScopeTypes (with or without nested conversations). Of course you can reinvent ScopeTypes, but I bet using what seam provides for this will a much better idea (and specially easier to implement).


                  Another options is to build your UI like a RIA, with all this nested conversations coming and going as javascript functions, and essentially building a heavy client with javascript (I feel that is where everything will end sooner or later when we realize that all RIAs are doing is bringing back the heavy client) (Welcome back Swing!)


                  Hope that helps.


                  Regards,



                  • 6. Re: How to handle by-browser-page scope
                    Ken Clark Newbie

                    Here is a use case that illustrates what is needed:


                    1) User logs in and enters a part of the application where he needs to select a portfolio -- he has multiple choices, and every screen (or many screens anyway) hereafter will make use of the currently selected portfolio.


                    2) User goes to the projects page, which lists all projects for said portfolio.  He selects one to edit.  (At this point I start a conversation which will be used over a number of pages to manage his edit session). 


                    3) User can either complete the edit session or perhaps may exit using the menu -- in the menu all the links are s:link with propagation none btw.


                    4) User does various other activities, most of which use conversations.


                    5) At some point user opens another browser window, and selects a different portfolio -- because perhaps he wants to retrieve some information from that portfolio while editing the first, and would like to cut and paste or view screens side by side or whatever.


                    6) Back in the original window, the user should still have that original portfolio value as the current portfolio for that window.


                    Now, then, is using nested conversations the only way to handle this use case?


                    Thanks,
                    ken

                    • 7. Re: How to handle by-browser-page scope
                      Francisco Jose Peredo Noguez Master

                      Hi!



                      Ken Clark wrote on Jul 16, 2008 13:59:


                      Here is a use case that illustrates what is needed:

                      1) User logs in and enters a part of the application where he needs to select a portfolio -- he has multiple choices, and every screen (or many screens anyway) hereafter will make use of the currently selected portfolio.


                      If it is true that hereafter will make use of the currently selected portfolio and only the selected portafolio  the SESSION should be enough.




                      2) User goes to the projects page, which lists all projects for said portfolio.  He selects one to edit.  (At this point I start a conversation which will be used over a number of pages to manage his edit session). 



                      Right, conversation is a good idea for this. (IMO)




                      3) User can either complete the edit session or perhaps may exit using the menu -- in the menu all the links are s:link with propagation none btw.



                      I have had some performance problems with s:link in menus when the .page.xml have many of parameter references <param name="" value="#{}", so I prefer to use h:outputlink.




                      4) User does various other activities, most of which use conversations.



                      Well, if those are of a smaller scope, I guess you will have to use nested conversations after all (or you may use parallel conversations)




                      5) At some point user opens another browser window, and selects a different portfolio -- because perhaps he wants to retrieve some information from that portfolio while editing the first, and would like to cut and paste or view screens side by side or whatever.



                      Well that means it is not true that hereafter will make use of the currently selected portfolio and only the selected portafolio and therefore you will have to use CONVERSATION for that (and that means you will need NESTED for subsequent operations (in this case projects) on the selected portfolio)




                      6) Back in the original window, the user should still have that original portfolio value as the current portfolio for that window.



                      But, not only for that window, also for any window called by that window... and any window with that exact same url? don't you agree?


                      I think here you might have a conceptual problem, it is not right (from a server perspective) to say that something happens for that window, but you can say that it happens for that url o for that conversation id... unless, as I said in the previous post, you are building a RIA and then, since all interaction is handled in javascript, you may only need CONVERSATION for the moment when you select the portfolio (or perhaps not even than, nothing prevents you from building portfolio browser -all in javascript- on the same window), and after that, all operations done for a particular conversations are handled in the client




                      Now, then, is using nested conversations the only way to handle this use case?



                      The way I see it you have 2 options, if you want to make the server aware of what is going on, then you have to use conversations, or, you can build this as a RIA using something like... i don't know, ExtJS o Flex and do all this conversational handling on the client.


                      Regards,

                      • 8. Re: How to handle by-browser-page scope
                        Francisco Jose Peredo Noguez Master

                        Hi!


                        Oh, and by the way, I read about Tomahawk uiSaveState,and if what it is stated in that page is correct t:saveState it is the exact same thing as ScopeType.PAGE.


                        Regards,

                        • 9. Re: How to handle by-browser-page scope
                          Ken Clark Newbie
                          Yes, they are functionally equivalent.  However, the way they are used leads to significant differences.  Consider what I did using t:saveState to resolve the above use case:

                          All web pages had to include the following (not a big deal -- we just stuck this in the common jsp that is included in every page):

                          <t:saveState id="savestateUserctx" value="#{userctx}"/>

                          and then this snippet goes into faces-config:

                          <managed-bean>
                              <managed-bean-name>userctx</managed-bean-name>
                              <managed-bean-class>myapp.MyUserContext</managed-bean-class>
                              <managed-bean-scope>request</managed-bean-scope>
                          </managed-bean>

                          and thats *it*.  Now every single piece of code in the application can pull userctx out of FacesContext and use it to store/retrieve configuration information.

                          I have not figured out a way to duplicate this in Seam using PAGE scope.  I can of course create a bean object that Injects and Outjects "userctx", but unless that bean is actually used during a user transaction, the Injection/Outjection will not happen and thus the value will be lost.  (Or is there an easy way you can think of to force the injection/outjection on every single user transaction?)

                          Thanks,
                          ken
                          • 10. Re: How to handle by-browser-page scope
                            Francisco Jose Peredo Noguez Master

                            Well, I haven't used Tomahawk, but I think it migth be lot easier in Seam: all you have to do is go to your MyUserContext.java and write:


                            
                            @Name("userctx")
                            @Scope(ScopeType.PAGE)
                            public class MyUserContext{
                            }
                            
                            



                            And that is it, now, if you want it autocreated:


                            
                            @Name("userctx")
                            Scope(ScopeType.PAGE)
                            @AutoCreate
                            public class MyUserContext{
                            }
                            
                            



                            And if you want to use it in SomeWhere.java:


                            
                            Scope(ScopeType.PAGE)
                            @AutoCreate
                            public class SomeWhere.java{
                            
                               @In
                               MyUserContext userctx;
                            
                            }
                            
                            



                            have you tried this?


                            • 11. Re: How to handle by-browser-page scope
                              Ken Clark Newbie

                              I have not actually tried it, no, but I believe it will not work, because as soon as there is any transaction that does not explicitly use userctx, it will not be created/outjected into the next Page scope, and therefore will never be available again for any subsequent transaction that does need it (except of course it would be auto-created, though that does not help because it will have lost any values previously stored in it.)


                              Do I misunderstand how the Seam life cycle works?


                              Thanks,
                              ken


                              • 12. Re: How to handle by-browser-page scope
                                Francisco Jose Peredo Noguez Master

                                Ken Clark wrote on Jul 17, 2008 20:49:


                                I have not actually tried it, no,


                                Well then... why don't your try?




                                but I believe it will not work, because as soon as there is any transaction that does not explicitly use userctx, it will not be created/outjected into the next Page scope, and therefore will never be available again for any subsequent transaction that does need it (except of course it would be auto-created, though that does not help because it will have lost any values previously stored in it.)



                                I don't quite get what do you mean by transaction... and why would you want to have it outjected into the next Page scope (AFAIK pages scopes are for stuff in the same page, no in the next page, and that (I think) should be true for both Tomahawk and Seam)




                                Do I misunderstand how the Seam life cycle works?

                                Thanks,
                                ken




                                I have to admit I don't like when someone else post this as an answer to one of my questions but in this case I think: you should really try and see.

                                • 13. Re: How to handle by-browser-page scope
                                  Ken Clark Newbie

                                  A user transaction is any single unit of work that a user executes via a single http request.  Every link click or form submission in the application is a user transaction.


                                  Not to be confused in any way with a persistence transaction.


                                  The reason I need this to follow up in the next page scope is that I would be using this page scope trick to pass a variable value from page to page to page forever, thereby placing the users current selection as available to any downstream code, even if it is 100 user transactions down the road.  The nice thing about using said trick is that when the user opens a second browser window and changes his selection, it cannot affect the original browser window.


                                  Or at least that is how I used t:saveState (and it has worked quite well.)  Note one drawback I'd like to fix is that we could never redirect as the variable in the request scope is lost in doing so.


                                  I am not yet ready to try this because I am still relatively sure that even though everything will work great going from A to B (really I do believe this), when the user then goes from B to C and there is no explicit use of userctx, then any values in userctx will be gone.


                                  The difference between savestate and Seam Page scope is that in the former, it goes from embedded in the page to into the request scope and then back out embedded in the next page.  Whereas in Seam, the value will be outjected only if something specifically outjects it -- and I would prefer not to have to go into every single action class and write an Inject/Outject userctx, which it seems to me would be the only way to get this to work.


                                  However, I do have a hope that there is some trick I could use to do this.  I am afraid that the inability to redirect is going to be too restrictive for Seam (plus I just generally would prefer to find a Seam solution.)


                                  Thanks again,
                                  ken

                                  • 14. Re: How to handle by-browser-page scope
                                    Ken Clark Newbie

                                    Quick update -- I did try this since it was easy enough to do, and I can confirm that it worked as I expected.  The userctx value does not survive past a user transaction in which the underlying action class does not inject the userctx bean.


                                    Thanks,
                                    ken