1 2 Previous Next 18 Replies Latest reply on Feb 16, 2006 2:01 AM by armita

    Ending a conversation and begining another at the same time

    armita

      I want my user to search for an entity in a list wich needs a conversation in EntityList SFSB , after selecting one entity I want to end the conversation in EntityList and begin another Conversation in the EntityLogic SFSB for entity logic manipulations. Is it feasable?

        • 1. Re: Ending a conversation and begining another at the same t
          gavin.king

          I'm not convinced that you really want this :-)

          Possible alternatives:

          (1) do it all in one conversation (if you are worried about memory consumption, simply @Remove the EntityList when you are finished with it)

          (2) Put the EntityList in PAGE scope and don't use a conversation at all for the list screen

          (3) use a nested conversation (specialized cases, this is probably not what you need)

          • 2. Re: Ending a conversation and begining another at the same t
            armita

             


            (1) do it all in one conversation (if you are worried about memory consumption, simply @Remove the EntityList when you are finished with it)

            There is a lot of activities for each entity. Actually each entity has relation ship with a lot of other entities like activities, notes, and each of them has thier own methods like CRUD methods. And I think it is unsafe to define all of the methods in one class which supposed to have several conversations


            (2) Put the EntityList in PAGE scope and don't use a conversation at all for the list screen

            OK. then how can I use the DataModel?

            • 3. Re: Ending a conversation and begining another at the same t
              gavin.king

               

              "armita" wrote:

              (1) do it all in one conversation (if you are worried about memory consumption, simply @Remove the EntityList when you are finished with it)

              There is a lot of activities for each entity. Actually each entity has relation ship with a lot of other entities like activities, notes, and each of them has thier own methods like CRUD methods. And I think it is unsafe to define all of the methods in one class which supposed to have several conversations


              Why would you need to do it all in one class? A conversation can propagate across many classes.

              "armita" wrote:

              (2) Put the EntityList in PAGE scope and don't use a conversation at all for the list screen

              OK. then how can I use the DataModel?


              Pretty much the same as before. It's just a different scope...

              • 4. Re: Ending a conversation and begining another at the same t
                liebner

                Hi Gavin,
                I think what armita means is, that you can't go for the PAGE scope if you want to use the @DataModel with the paging features of your CRUD example. PAGE Scope does not deploy with Statefull Session Beans.

                And in your doc files you say:


                6.8. Annotations for use with JSF dataTable
                The following annotations make it easy to implement clickable lists backed by a stateful session bean. They appear on attributes.


                So, if I understand all this here correctly, it would make sense to have the EntityList (which resembles your CRUD find beans) to be stateless with page scope and then add your variables pageNumber and pageSize as request parameters.

                Correct?

                • 5. Re: Ending a conversation and begining another at the same t
                  gavin.king

                  Um. I don't quite understand.


                  PAGE Scope does not deploy with Statefull Session Beans.


                  Why not?

                  Sure you can use request parameters if you *like*, and sometimes that is the best way (more RESTful) but you should not need to.



                  • 6. Re: Ending a conversation and begining another at the same t
                    liebner

                    If you have a bean annoted like this

                    @Stateful
                    @Scope(ScopeType.PAGE)
                    


                    you get an exception like this one

                    11:19:42,234 ERROR [[/seamapp]] Exception sending context initialized event to listener instance of class org.jboss.seam.servlet.SeamListener
                    java.lang.IllegalArgumentException: Stateful session beans may not be bound to the PAGE context: applicationFinder
                     at org.jboss.seam.Component.checkScopeForComponentType(Component.java:198)
                    


                    Or did you mean, that you simply annote the DataModel with the page scope? But than the data is still attached to the SFSB and no memory would be cleaned.

                    • 7. Re: Ending a conversation and begining another at the same t
                      gavin.king

                      Use @DataModel(scope=PAGE).

                      • 8. Re: Ending a conversation and begining another at the same t
                        liebner

                        Hmm,

                        I'm working with a dataTable and @DataModelSelection. If I use the annotation like you said the next request, in which I want to use the selected item, does not work.

                        I'll settle for the all in session scope variation for now and see what is causing the trouble later.

                        Got to proof that seam is cool :-)

                        Greetings,
                        Stefan

                        • 9. Re: Ending a conversation and begining another at the same t
                          gavin.king

                           

                          "liebner" wrote:
                          I'm working with a dataTable and @DataModelSelection. If I use the annotation like you said the next request, in which I want to use the selected item, does not work.


                          It should work:


                          @Stateful
                          @Scope(EVENT)
                          @Name("search")
                          public class SearchBean implements Search
                          {
                           @DataModel(scope=PAGE)
                           List searchResults;
                          
                           @DataModelSelection
                           Foo selection;
                          
                           ...
                          
                          }


                          • 10. Re: Ending a conversation and begining another at the same t
                            robjellinghaus

                            I'm in exactly the same situation -- I want a search list that's conversationless-ly populated the first time the user hits the main list page, and that then lets you start edit/etc. conversations via action links. It's as if the noejb example always gave you a list of hotels the minute you pull up main.jsf, and then conversations started from the View links.

                            So, if I'm starting from (you guessed it) the noejb example, this means that I want to basically split HotelBookingAction into two beans:
                            - HotelSearchAction (@Stateful @Scope(EVENT), containing @DataModel(scope=PAGE) List hotels and @Out Hotel hotel)
                            - HotelBookingAction (@Stateful @Scope(CONVERSATION)), which gets @In Hotel hotel

                            Is that right? Will "hotel" be properly propagated from the HotelSearchAction to the HotelBookingAction? I'll proceed along this path and find out :-)
                            Cheers!
                            Rob

                            • 11. Re: Ending a conversation and begining another at the same t
                              gavin.king

                              Take a look at the issue tracker example, which is not *exactly* what you are describing (the search results are held in session scope), but is similar.

                              To propagate the selected hotel, I would rather use a request parameter, since that will make the page bookmarkable (RESTful).

                              I need to finish off my blog example app so you can work from that.

                              • 12. Re: Ending a conversation and begining another at the same t
                                robjellinghaus

                                Jeez, and here I am converting the noejb/booking sample INTO a blog sample! :-\

                                Are there any current samples that show how to use RESTful request parameters?

                                • 13. Re: Ending a conversation and begining another at the same t
                                  gavin.king

                                  No there are not, but it is simple:

                                  <h:outputLink value="item.jsf">
                                   <f:param name="itemId" value="#{item.id}"/>
                                   #{item.name}
                                  </h:outputLink>


                                  And, then:

                                  @Stateless
                                  @Name("itemFactory")
                                  public class ItemFactory {
                                  
                                   @Out Item item;
                                   @RequestParameter itemId;
                                  
                                   @Factory("item")
                                   public void getItem() {
                                   item = getItem(itemId);
                                   }
                                  
                                  }


                                  Or whatever.

                                  • 14. Re: Ending a conversation and begining another at the same t
                                    robjellinghaus

                                    OK, I tried the above. Specifically, I wanted to make it so the hotel/booking noejb example brings up the hotel list the first time you land on main.xhtml, without starting a conversation. The hotel list is in session scope, in other words, just like the booking list. Then the "View Hotel" links become plain links with "hotelId" request parameters, for bookmarkability.

                                    So I split HotelBookingAction into HotelListAction (SESSION scope, responsible for the "hotels" datamodel) and HotelBookingAction (the editing methods, still conversational). HotelListAction's find() method becomes a @Factory("hotels") method. There is a new HotelFactory class, which creates the "hotel" component from the "View Hotels" link. So the "View Hotel" links actually read http://localhost:8080/tomcat-seam-noejb/hotel.jsf?hotelId=9 which is fine. (HotelFactory was originally @Stateless but it started complaining about no @JndiName, which I didn't want to have to mess with, so I just made it @Scope(STATELESS).)

                                    All of this works... EXCEPT for the interaction between the HotelFactory and the HotelListAction. Basically, I want the "Next Hotel" and "Previous Hotel" buttons in hotel.xhtml to work, regardless of whether I arrived at hotel.xhtml from main.xhtml or from a bookmarked link. Somehow I need the HotelFactory (the only bean that gets invoked when a bookmarked hotel.jsf link is loaded) to be aware of "hotels" and "hotelIndex", so it can set "hotelIndex" appropriately. Otherwise HotelListAction.nextHotel and HotelListAction.previousHotel don't work properly.

                                    Here's my stab at HotelFactory.

                                    /**
                                     * Factory class to create a single hotel based on request parameter.
                                     */
                                    @Name("hotelFactory")
                                    @Scope(ScopeType.STATELESS)
                                    public class HotelFactory {
                                     private static final Logger log = Logger.getLogger(HotelFactory.class);
                                    
                                     @Out Hotel hotel;
                                     @RequestParameter String hotelId;
                                    
                                     @In(create=true)
                                     private Session bookingDatabase;
                                    
                                     @In
                                     private List<Hotel> hotels; // big trouble with the type of this field
                                     @Out
                                     private int hotelIndex;
                                    
                                     @Factory("hotel")
                                     public void getHotel() {
                                     long hotelId = Long.parseLong(this.hotelId);
                                    
                                     hotel = (Hotel)bookingDatabase.createQuery("from Hotel where id = ?")
                                     .setParameter(0, hotelId)
                                     .uniqueResult();
                                    
                                     if (hotels != null) {
                                     for (int i = 0; i < hotels.size(); i++) {
                                     Hotel listHotel = (Hotel) hotels.get(i);
                                     // have to compare id's because "hotel" and "hotels" were loaded in different
                                     // persistence sessions (since there's no common context for them both).
                                     if (hotel.getId().equals(listHotel.getId())) {
                                     hotelIndex = i;
                                     break;
                                     }
                                     }
                                     }
                                    
                                     log.info("got hotel for id " + hotelId + ": " + hotel);
                                     }
                                    }


                                    As you can see from the comments, this doesn't work. It actually fails to biject "hotels".

                                    - If I declare "hotels" as "@In private List hotels", it fails, because it tries to inject a ListDataModel value into HotelFactory.hotels, which (sensibly enough) gives an IllegalArgumentException at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63).

                                    - If I declare "hotels" as "@In @DataModel private List hotels", it fails for the same reason -- still trying to inject a ListDataModel into a List.

                                    - If I start flailing wildly and declare "hotels" as "@In @DataModel private ListDataModel hotels", munging the code around to call .getWrappedData() etc., etc., then it actually injects successfully and updates hotelIndex properly. THEN it dies with:
                                    java.lang.ClassCastException: org.jboss.seam.jsf.ListDataModel
                                     at org.jboss.seam.Component.outjectDataModel(Component.java:773)
                                     at org.jboss.seam.Component.outject(Component.java:695)

                                    Line 773 is:
                                    list = (List) getFieldValue( bean, dataModelGetter, name );

                                    Seems like Seam's got me coming and going on this one! :-) Either it won't inject a List, or it won't outject a ListDataModel!

                                    What gives? The above seems crufty even to me (even if it worked it would be crufty), so I'm wondering whether there's just a better way to do all this. Is there an existing sample showing how to use a session-scoped list, RESTful item links, and next/previous item navigation all together? How's that blog sample coming? ;-)

                                    Also, as you can see, I have to compare IDs rather than just using "hotels.indexOf(hotel)" since there doesn't seem to be a shared persistence context. (In other words, Hibernate session caching not working in this case.) Is that expected?

                                    I'm also using a CVS snapshot from late January, not Beta2. Would any of this be different in Beta2?

                                    Thanks again. Worst comes to worst, I'll bail on trying to keep the session-scoped list in sync.
                                    Cheers,
                                    Rob


                                    1 2 Previous Next