1 2 Previous Next 17 Replies Latest reply on Jul 2, 2010 7:48 AM by Andrzej Mazur

    Conversation scope in separate requests

    Daniel Posch Newbie

      Hi everyone,


      I have an issue with conversation scoped-data that I want to access from two different Seam components. The use-case is quite simple: In one class a list of data is outjected to the conversation context. In the other class this list should be injected. However, the injected data always happens to be null.


      The thing is, the other class which fails to inject the data is a painter class that is called by a RichFaces <rich:paint2D/> tag. Well, RichFaces requests resource contents in a separate request.


      In my understanding that should not be a problem, i.e. the two classes both access the same (conversation) context. However, it looks like they don't. Have I missunderstood the concept?


      Regards, Daniel


      Here's the relevant code:


      Class trying to inject the data:


      @Name("facelayout")
      @Scope(ScopeType.CONVERSATION)
      public class FacelayoutManager implements Serializable {
              @In(required = false)
              private List<Hardware> hardwareList; // <-- is always null
      
              public void paint(Graphics2D g2d, Object obj) { //...
              }
      }



      Class outjecting the data:


      @Name("hardwareManager")
      @Scope(ScopeType.CONVERSATION)
      public class HardwareByNetelementAndDate implements Serializable {
              @Out(scope=ScopeType.CONVERSATION)
              private List<Hardware> hardwareList;
      
              @Create
              public void findHardware() { //...
              }
      
               */
              @End
              public String showDetails(Hardware hw) { //...
              }
      }



      pages.xml:


      <page action="#{conversation.begin}">
              <!-- ... -->
      </page>
      
      





        • 1. Re: Conversation scope in separate requests
          Bernard Labno Master

          Yes, you do not understand. If you declare 2 components to reside within the same scope type it does not mean that they will reside in the same scope instance. I.e. if 2 components are EVENT scoped then two requests will have two different instances of EVENT scope.


          Now merge that information with this : CONVERSATION scope is (almost) equal to EVENT scope if it is not long-running. So it seems you do not start conversation and thus two requests operate in 2 different contexts.

          • 2. Re: Conversation scope in separate requests
            Daniel Posch Newbie

            Okay, I understand the concept, but after some debugging I came to the conclusion that you are right and the two components are not stored in the same context. But shouldn't the action method in my pages.xml begin a new long-running conversation?

            • 3. Re: Conversation scope in separate requests
              Ilya Dyoshin Novice

              I guess better would be to use in your page.xml


              <begin-conversation join="true" />


              regards,


              Ilya Dyoshin

              • 4. Re: Conversation scope in separate requests
                Ilya Dyoshin Novice

                As I understand page-scope actions i.e. <action /> defined in page.xml would be called every time the request comes. Even with ajax. Thus join="true" would be a great solution for simple actions. I'm using that with my ajaxified forms and it works just fine.


                Regards,


                Ilya Dyoshin

                • 5. Re: Conversation scope in separate requests
                  Daniel Posch Newbie

                  Hi and thank you for your answers,


                  your suggestion to chang from the action-method to <begin-conversation join="true" /> is indeed a better solution for me. However, that doesn't do the trick. My second component (facelayout) still does not appear in the conversation context. The Seam debug page says there is one conversation that has my hardwareManager and hardwareList in it, but not the facelayout component.


                  I also tried to make my facelayout component @Conversational, but as expected (in a bad way) this causes an exception, because there is no long-running conversation. I just don't get why...


                  Regards, Daniel

                  • 6. Re: Conversation scope in separate requests
                    Ilya Dyoshin Novice

                    Hi Daniel.


                    I've looked at your code and find this problem:


                            @In(required = false)
                            private List<Hardware> hardwareList;



                    you're injecting a hardwareList but not require it - that leads to the following error:  Seam scan's for the component hardwareList - and if it found it should be placed, but as far as your hardwareManager haven't done any work so no hardwareList currently outjected. So there is no data to inject. You need to redefine your application logic. I guess the best approach for you would be to use the DataModel - Factory approach for producing your hardwareList - in that case SEAM would create the component hardwareManager and invoke the factory method for hardwareList.


                    if the component is marked as belonging to the CONVERSATION scope  - that doesn't means that SEAM would create it every time the following scope is activated. (that would made a huge amount of OutOfMemory errors :) SEAM creates instance if and only if it's invoked in the application lifecycle and prolongates its existence in the CONVERSATION scope.


                    Kind regards,
                    Ilya Dyoshin

                    • 7. Re: Conversation scope in separate requests
                      Bernard Labno Master

                      Do you touch facelayout in that conversation at all? I mean, that bijection happens only if any method is invoked on a bean or it is referred by JSF via EL. Post your XHTML.

                      • 8. Re: Conversation scope in separate requests
                        Ilya Dyoshin Novice

                        sorry in previous post there is an error: I've wrote:



                        you're injecting a hardwareList but not require it

                        that doesn't corresponds to error - that is your solution for removing Could not instantiate component facelayout Exception


                        if you define your hardwareList in the Create method of the HardwareManager - you need to create the instance of the HardwareManager. So just inject the HardwareManager to the facelayout component.


                        But nevertheless - DataModel - Factory - far more better approach, IMHO.


                        Regards,


                        Ilya Dyoshin

                        • 9. Re: Conversation scope in separate requests
                          Daniel Posch Newbie

                          Yes, I do use facelayout, but only once:


                          <!-- Facelayout -->
                          <rich:paint2D id="facelayoutImg" alt="Facelayout" format="png"
                               paint="#{facelayout.paint}" width="1082" height="616" border="0" />



                          As already mentioned in my original post, RichFaces' <rich:paint2D/> has the unpleasent behaviour to request those resource contents in a separate request. But is that really a problem?

                          • 10. Re: Conversation scope in separate requests
                            Ilya Dyoshin Novice

                            but you don't use hardwareManager which produces the data for you ;)  that's the point.



                            Regards,
                            Ilya Dyoshin

                            • 11. Re: Conversation scope in separate requests
                              Daniel Posch Newbie

                              Ilya, injecting hardwareManager in facelayout works fine, but doesn't solve the actual problem. There is a hardwareManager, just not in the right context (for facelayout). So, injecting hardwareManager causes another hardwareManager to be instantiated and thus, another database request, which is a a SELECT-statement returning hundreds of rows - and that's definitely not what I would want.


                              DataModel and Factory is a good combination, but doesn't help me out with this issue. In this case, I need the data right after instantiation, that's why I fetch my everything @Create.

                              • 12. Re: Conversation scope in separate requests
                                Ilya Dyoshin Novice

                                that means that your hardwareManager is prolongated to this conversation - and it was created somewhere else.


                                Why don't you create another class of the hardwareManagerForFacelayout  - it would be extending from AbstractHardwareManager  -the superclass with some specific methods, 'common for both classes.  Or simply fetch your data in the facelayout component?

                                • 13. Re: Conversation scope in separate requests
                                  Daniel Posch Newbie

                                  Ilya Dyoshin wrote on Mar 30, 2010 16:03:


                                  but you don't use hardwareManager which produces the data for you ;)  that's the point.


                                  Regards,
                                  Ilya Dyoshin

                                  I do use hardwareManager elsewhere on the page. Actually I don't have the problem that hardwareManager is not in the conversation context. Quite the contrary applies: hardwareManager is in the conversation context, but facelayout isn't. I suppose that has to do with <rich:paint2D/>'s separate request, but I'm not sure.


                                  To avoid confusion: hardwareManager is actually very heavily used to provide all kind of operations. All my 'facelayout' component does is painting an image to present my data in a non-textual way. Of course one could argue that an additional component was not necessary, but I want to strictly separate business logic and presentation tier. I'm quite aware that putting the paint()-method in hardwareManager would do the trick, but I don't see reasonable arguments - I can solve my problem, but the price is a dirty solution. The same goes for saving my data in the session context. I tried all these things and they work perfectly. But I very much prefer the most elegant solution.

                                  • 14. Re: Conversation scope in separate requests
                                    Daniel Posch Newbie

                                    Bernard Labno wrote on Mar 30, 2010 14:40:


                                    Do you touch facelayout in that conversation at all? I mean, that bijection happens only if any method is invoked on a bean or it is referred by JSF via EL. Post your XHTML.


                                    Using the facelayout component elsewhere on the page, i.e. not in <rich:paint2D/>'s paint-attribute causes facelayout to be instantiated twice (!). The component used outside <rich:paint2D/>'s paint-attribute has the data (hardwareList) properly injected while the component used inside the attribute seems to be completely isolated. From this component's view there is no conversation and thus injection doesn't work.


                                    So, <rich:paint2D/> causes this behiavor (actually I've been struggling with this for quite a while...), but in my understanding a separate request shouldn't bother Seam's conversation, should it?


                                    I would be very pleased if anyone could explain to me why this happens as it's not the behavior I would expect. Any suggestions?


                                    Also, any suggestions regarding workarounds would be appreciated. :-)


                                    Regards, Daniel

                                    1 2 Previous Next