JSF and "THE TRAP!" - CommandLinks and DataTables

Discussions

News: JSF and "THE TRAP!" - CommandLinks and DataTables

  1. Dominik Wei-Feig has posted "JSF: DataTable and CommandLink," in which he says that Like a lot of other programmers who are forced to work with JSF, I fell into THE TRAP!" The 'trap' here is that datatables rendered in multiple requests don't necessarily map the element ids consistently. He's incorrect, but it's an interesting point to consider.
    If you are using ManagedBeans in request scope, you get problems with CommandLinks inside DataTables. DataTables are one thing I really like about JSF, and CommandLinks often come in handy as well. But when you put a CommandLink inside a DataTable, e. g., to select the entry of the row in which the CommandLink is, you get bitten. That is, if you want ManagedBeans with request scope. The action which should be triggered by the CommandLink is never triggered, the page is simply rendered again. The reason for this behaviour is that the DataTable modifies the id of the CommandLink during renderering, but the CommandLink does not know that it was rendered with a different id. During the decoding of the request which was triggered by clicking the CommandLink, the ComandLinkRenderer looks at a hidden form parameter. If the value of that form parameter equals the id of the CommandLink, an action is queued. If not, nothing is done. Since the DataTable changes the ids, the value of the hidden form parameter does not match the id of the CommandLink.
    To solve this, he wrote a custom renderer that decodes the buttons properly. However,the problem seems to be in his first sentence, which states that he's using a bean in request scope to manage the datatable. Since the bean is rebuilt every request, elements in it have inconsistent IDs, which yields what he's solved. So it's arguable that there's no actual trap (well, no trap here, at least) but just improper usage - but if the renderer works for him, perhaps it's worth considering long-term. It certainly highlights a lack of clear best practices for JSF. That said, however, there's an enhancement request filed on java.net with a poignant summary related to the "trap" spoken of by Mr. Wei-Feig: "UIData is Fundamentally Broken and Needs to Go Away." The solution proposed, using Facelets, is certainly potentially nicer - but even it would probably benefit through the use of session scope instead of request scope. What do you think?

    Threaded Messages (33)

  2. This post makes no sense[ Go to top ]

    During the decoding of the request which was triggered by clicking the CommandLink, the ComandLinkRenderer looks at a hidden form parameter. If the value of that form parameter equals the id of the CommandLink, an action is queued.
    This statement cannot be true. Without knowing what environment and version of JSF they were using its hard to analyze this. You have two scenerios. If an action is being used, the component does not even have to be identified and all you get is an action method called. In these scenerios, the trick (not trap) is to get access to the datamodel and find the selected row. If an ActionListener is being used, the component does have to be identified because it is passed in with the event parameter. I have never seen an issue with this but then like the action scenerio, component identification does little to identify the row selected.
    Since the DataTable changes the ids, the value of the hidden form parameter does not match the id of the CommandLink.
    The whole notion that the DataTable changes the ids is false. There is a difference between the "id" of a component in the JSP page and the "clientId" that the component is rendered with. The statement makes it sound like this is bad, when in fact, it is good. It occurs due to either "containment" or in this case the "looping nature" of the data table. The command link ids are being pre-pending with essentially a row id.
    I cannot believe this even has to do with Request scope (although Request Scope can present other issues, these are not flaws). While I might accept there is a flaw in the version of JSF they were using (Maybe IBM's RAD), until the environment is identified and the source provided (action or actionListener) it is not worth futher comment. I have never seen this issue and I have used commandLinks in Data Tables.
  3. Re: This post makes no sense[ Go to top ]


    ... get access to the datamodel and find the selected row ...

    For an actionListener, which would replace detailAction below, just get formHandler first before getSelectedRow().getRowData(); JSP === h:dataTable binding="#{formHandler.selectedRow}" ... . . . h:commandLink immediate="true" action="detailAction" ... formHandler.java ================ /** * Holds value of selectedRow datatable row. */ private UIData selectedRow; /** * Getter for selectedRow. * @return Value of selectedRow. */ public UIData getSelectedRow() { return this.selectedRow; } /** * Setter for selectedRow. */ public void setSelectedRow(UIData selectedRow) { this.selectedCase = selectedRow; } public String detailAction() { /* pull out the currently selected row*/ currCase = (MyRow)getSelectedRow().getRowData(); return "success"; }
  4. Re: This post makes no sense[ Go to top ]

    For an actionListener, which would replace detailAction below, just get formHandler first before getSelectedRow().getRowData()
    Ok but you still need a session scoped bean...and remember that binding the table over a session scoped bean is a risk! (sometimes you get duplicated id and other strange stuff, so I avoid this scenario)
  5. Post does make sense[ Go to top ]

    I think the original post does make sense. The situation described is definitely a problem. I don't agree with the other post that states we need to know the JFS implementation before making a judegement. Part of the problem is that the spec doesn't recognize this problem at all. Its up to the vendor to either deal with this problem (in a vendor specific way), or ignore it and hope the user is experienced enough to find her own workaround. As a vendor specific solution, the Tomahawk (ext) datatable provides a solution in the form of the "forceIdIndexFormula". In a nutshell with this attribute an elaborate EL expression can be provided which uses row data to create an unique key. After a click, this key is send along with the request and the backing data model is iterated, calculating the key again for each row and causing a hit when the calculated and provided keys match. Of course, this still doesn't solve the problem where it's not feasible to recreate the data model at each request. Seam may be an option, but caching (e.g. with JBoss TreeCache) may be an other option. With this last option you can keep the model in memory, but limit this to some X entries based on LRU behaviour. If the model does get evicted and the user clicks a page that needs this model, you can always recreate the data afterall and utilize the forceIdIndexFormula to check if the row the user clicked still exists.
  6. Re: Post does make sense[ Go to top ]

    I have begun to believe that we are all talking about differnt JSF behaviors. I wrote a small program using JSF 1.1 RI because I did not believe the assertions to be true. I cannot reproduce the behavior placing my controller in request scope, the simple code follows. <%@ page contentType="text/html;charset=windows-1252"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> datamodule package test; import java.util.ArrayList; import java.util.List; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; public class DataModelController { private List _data = new ArrayList(); public DataModelController() { for (int i=0; i<20; i++) { _data.add(Integer.toString(i)); } } public List getData() { return _data; } public String action() { return null; } public void actionListener(ActionEvent ae) { System.out.println(ae.getComponent().getClientId(FacesContext.getCurrentInstance())); } } This example works just fine and the events are generated for both action and actionListener cases. Thus the premise of this post is false.
    Most of the issues I have seen with the data model is that its scope must survive the transaction in order for row selection to work. Thus the problem is not in the JSF implementation but rather the way the model is being persisted. As other posts in this thread point out, this can be solved by placing the backing bean (and implied model) in session scope, use seam, cache or similar methods to manage the data model (note I do not say backing bean but they could be one and the same) associated with the table.
  7. Re: Post does make sense[ Go to top ]

    Exactly, I tried also with JSF 1.2_04, and the id are cleary the same thru different requests. Maybe also the flash scope provided from Edburns in jsf-extensions project would be usefull here... but also Seam conversational scope, tomahawk saveState component (maybe also the a4j keepAlive component...?), tomahawk dataTable component, session scope...
  8. Re: Post does make sense[ Go to top ]

    Exactly, I tried also with JSF 1.2_04, and the id are cleary the same thru different requests.
    It seems like you don't really understand the problem, the problem manifests itself as folllows: When rendering a datatable, IDs are generated per row as a numbered sequence. E.g. row 1 may correspond to ID foo1, row 2 to ID foo2 etc. When a click is made on a commandlink for e.g. row 5, the ID "foo5" is send with the request. At the serverside the datamodel is recreated and itterated over in the same way as when generation IDs for rendering. So, for row 1 the datatable will assign it ID foo1, etc. Specifically when row 5 is encountered the datatable will generate ID foo5. This matches with the ID send along with the request, and iteration stops. The datamodel's cursor now stays pointing at row 5, and the action method (which has access to the datamodel) assumes this current row corresponds with the row on which the user made her click. All seems right, doesn't it? Wrong! The assumption that row *numbers* correspond to identical rows is most often not true. For example, suppose that we recreate the data model from a DB and between requests someone else deletes row 3, causing the other rows to shift one position. Using datatable's standard method of matching clicks to a datamodel row, the cursor will be pointing to row 4! This can have disastrous results!
    public DataModelController() { for (int i=0; i<20; i++) { _data.add(Integer.toString(i)); } } </blockquote> This is not a valid example. In this case the model is always identical, and of course the problem doesn't manifests itself here. In the bulk of practical situations datamodel's are not guaranteed to be stable between requests.
  9. Re: Post does make sense[ Go to top ]




    public DataModelController() {
    for (int i=0; i _data.add(Integer.toString(i));
    }
    }


    This is not a valid example. In this case the model is always identical, and of course the problem doesn't manifests itself here. In the bulk of practical situations datamodel's are not guaranteed to be stable between requests.
    I am not sure if the assumption is really correct here, the case you describe is an inherent problem of every webapp, no matter which framework accessing a database. The assumption that data stays consistent over request boundaries, especially if it is refetched over and over again, in the view layer simply is wrong. Referencing the data from its data model positional index simply is a user error, data always should be accessed by its key or something mapped to its key values not by some autogenerated internal positional value, which was only set that way to have a visual row index value on the ui, if needed. This is not jsf inherent, this is a general problem every webapp faces to a certain degree, and everyone doing database access and displaying the results in a webpage and having maybe to do it again after the next request has to be aware of that. You have to address this issue, if you do not have a special implementation of a data model and table which deal with this in a different way, just like you do it with every other webapp, simply do not use an internal counter for database row -> memory object mapping!
  10. Re: Understanding the problem[ Go to top ]

    It seems like you don't really understand the problem ...
    No I understand the issue and the scenerio you describe is real. However this has NOTHING to do with UIData model and has everything to do with peoples mis-conception of backing beans, dependency injection, and REST.
    The assumption that row *numbers* correspond to identical rows is most often not true. For example, suppose that we recreate the data model from a DB and between requests someone else deletes row 3, causing the other rows to shift one position.
    This is the heart of your problem, if this is your requirement space then you will need a slightly more complex solution to solve it as I have described above.
    Using datatable's standard method of matching clicks to a datamodel row, the cursor will be pointing to row 4!
    I absolutely agree that the scenerio you present is accurate. My point is that you should not design a JSF web application like this. Now if you don't like this as an answer then you either need an alternative or another framework.

    The problem presented is that you are using the wrong data model, you need a virtual representation of the business model to be used as your table's datamodel. In this scenerio they need to be different and that was the point of my post. You are trying to use a business model, who's representation can vary, as the datamodel, that cannot vary becuase it participates in the virtual representation rendered for the end user. The design, as described, will NOT work.

    The whole concept of JSF is that you build a virtual representation of the end users presentation (Response) and that representation is again materialized during the Request. Since all of the datamodels participate in that virtual representation, their "state" must be preserved as well. If you want to call that a TRAP then fine, there are plenty of ways (easy) to solve it.

    For those who give out JSF advise, the way we describe datamodels and backing beans always seems to lead new developers into this ultimate TRAP. When I get a new developer, this is one of the first things we discuss, it prevents many JSF programming errors.
  11. Re: Understanding the problem[ Go to top ]

    I absolutely agree that the scenerio you present is accurate. My point is that you should not design a JSF web application like this. Now if you don't like this as an answer then you either need an alternative or another framework.
    No UI layer framework in a request based szenario covers this, this so called trap can happen in Struts, in JSF even in pure JSP. In pure JSP you can run into it by assigning a running loop counter to datasets to identify them, same goes for struts or any other framework. The entire discussion revolves around the fact that the original author was not aware that data from a database is not static over time unless you apply some mechanisms (working on views on db level, or covering that in the orm/middleware layer) onto it. Also the author probably was not aware that the id used by the datatable is not the primary key of the datasets! This is not a trap of JSF this is a trap of feeding data from a multiuser database into an application and refeeding it from the same source over time.
  12. There are 2 models[ Go to top ]

    I agree this is not an issue of JSF but general. Talking about MVC, the "model" concept is misleading. There's a model of the view (view-state), is it a web view or a swing app, and a business model. Often a short circuit happens and the view state is directly linked to the (business)model state. What makes things worse for webapps is that (unless you use Seam) your state is request or session scoped, and because request scope is too short and session scope too wide, you extend request scope by reloading state from db directly from business model or some cache. Good complex webapps are difficult to write, but JSF should help and guide more to accomplish the task. It's not only an API problem, it's a best practice and culture problem. I remember struts 1.0 choice about ActionForm beans being bound to a base class to discourage use in the business model (not a good solution, but the sign of an actual problem). We developers are often lazy (or we have too many things to do) that if the language or framework allow us something, we abuse.
  13. Re: There are 2 models[ Go to top ]

    There's a model of the view (view-state), is it a web view or a swing app, and a business model. Often a short circuit happens and the view state is directly linked to the (business)model state. What makes things worse for webapps is that (unless you use Seam) your state is request or session scoped, and because request scope is too short and session scope too wide, you extend request scope by reloading state from db directly from business model or some cache.
    Glad to see someone see's the real issue. Repeated for emphasis.
    Good complex webapps are difficult to write, but JSF should help and guide more to accomplish the task.
    JSF needs a new version quickly. 1.2 took too long and I suspect this was due to the EL unfication process. We now need JSF spec to widen its breath and take on the issues of managed bean persistence (i.e scope), view tree state management, AJAX and component inter-operability, and provide better patterns for real world applicatons.
  14. Re: Understanding the problem[ Go to top ]

    Wow, I remembered my login, finally. I would have signed up again, but the sign-up form wants too much information for just posting a comment. So, just a short comment from the so-called "original author": The data table is bound to the bean on which the method is called. The method is needed as a trigger. I do not rely on some matching of row number to object, but take the object from the data table via getRowData(). As I said in the original post, it works for me. Even if I maliciously shuffle the data which is used to populate the table every time it is requested anew, I get the right object back. So am I just lucky? Well the data table gets set on the managed bean in the restore view phase. Inspecting the data table shows that it is in exactly the same state in which is was when it was constructed in the last invoke application phase, i.e. the ListDataModel (in my case) contains the right object instances at the right indices. Sure, if the user waited long enough between displaying the table and selecting the link, the instance selected might have already been removed from the db. OK, that is detected and can be handled. PS: I am aware that the (row) id used by the data table is not the primary key of the domain object it displays, these tables do paging, how could that be. (And would I really be expecting an empty row when I delete the object with primary key '1' from the database?) Assuming that anybody who has done some programming thinks that view and model are identical seems a bit exaggerated doesn't it?
  15. Re: Understanding the problem[ Go to top ]

    I absolutely agree that the scenerio you present is accurate. My point is that you should not design a JSF web application like this. Now if you don't like this as an answer then you either need an alternative or another framework.
    I wonder what the difference is between an alternative and another framework? Don't they both refer to "something else than JSF" ? ;) Anyway, I'm not really sure I understand why I would need another framework. The way I see it, the core problem is that the datatable component renders markup that sends back sequential numbers. Apart from scoping issues (for which Seam seems to be an incredibly solution), the simple answer is to just use keys. The tomahawk datatable does exactly that. It's a very effective yet surprisingly simple method that solves the majority of the problems. Even if I would go ahead and implement your idea of the "virtual representation", then I would still get back sequential numbers, which means I still have to make some mapping from row number to a logical unique row. Even with multiple layers of virtualisation and abstraction in place, I still don't think using row numbers at any place is a good idea.
  16. The way I see it, the core problem is that the datatable component renders markup that sends back sequential numbers.
    These sequential numbers we keep refering to are XML id's. They are not intended to be used as dataset keys. First, XML id's are limited by the specification as to how they can be formed. Second XML id's need to be unique within a document. Finally, these id's, when used in HTML, are there to identify the component tree not the dataset. Don't try to force something to be what it was not inteded to be used for.
    the simple answer is to just use keys. The tomahawk datatable does exactly that. It's a very effective yet surprisingly simple method that solves the majority of the problems.
    Yes Tomahawk does support a force id capability that you could use to solve your problem, I suppose it is one solution assuming the dataset key can be represented using simple integers. Regardless, you are fussing with something you should not. Wait until you try including two data tables or nested tables, use regions, are other types of complex page designs and you will fine the simple forceId concept does not look all that good anymore.
  17. These sequential numbers we keep refering to are XML id's. They are not intended to be used as dataset keys.
    I wholeheartedly agree with you on this. When I first saw how tomahawk was implemented I frowned at their method too. But that doesn't mean the concept is broken. This concept is simply about using keys to identify data. How tomahawk solves this internally is their problem. I would rather have seen they stored it somewhere else though. Since its an implementation detail and no user code directly depends on keys being stored as XML IDs, it's of course possible to change this in a later version of tomahawk.
    Finally, these id's, when used in HTML, are there to identify the component tree not the dataset.
    True, but in the end you do need something to more specifically identify the dataset that was used for rendering. Currently, the pointers you get after a user clicks a row are "view id", "component id", "row id" (where "row id" is actually just a component sub-ID). How am I going to match just that back to a specific key, given the fact that a user may issue multiple requests simultaneously? Even if we do stick to sequential IDs for the rows, then we do need some key somewhere to identify the specific snapshot (model, virtual set, abstract business component, logical view data, etc) that was used to render the specific view on which the user reacted. What would you propose then?
  18. True, but in the end you do need something to more specifically identify the dataset that was used for rendering. Currently, the pointers you get after a user clicks a row are "view id", "component id", "row id" (where "row id" is actually just a component sub-ID).
    I would look towards using Hibernate, TopLink, or some ORM or EJB3 Persistence solution. On the request: You execute you're query, bring back the dataset, and cache it so that it has a scope that matches the conversation (web page) being used by the user.
    Ladies and gentlemen, I give you ... transactions. Shouldn't it be simply assumed as a matter of common sense that when working with a resultset stored in a datamodel that you would always have actions on that datamodel work within an isolated transaction? In fact, it shouldn't even need a transaction per se -- recreating the data model with every action sounds barkingly insane to me. Is this really how JSF works?
    Transactions are tricky because no one is going to hold open a database transaction for the duration of a web page request/response cycle. We certainly don't want to re-create the datamodel and thus we have the concept of detached POJO's. The larger problem is will you let two peple modify the same data without some sort of locking mechanism? Locks represent a difficult issue.
    How am I going to match just that back to a specific key, given the fact that a user may issue multiple requests simultaneously?
    These POJO's have all of the information you need and JSF will provide you the POJO that represents the selected row during the response. Response: Now you have decisions to make. You can just update/persist the row (POJO) again. Typically if you have two users then last update wins. If the row was deleted elsewhere, you need to handle the update exception and decide if saveOrUpdate is appropriate or error message needs to be generated.
    Even if we do stick to sequential IDs for the rows, then we do need some key somewhere to identify the specific snapshot (model, virtual set, abstract business component, logical view data, etc) that was used to render the specific view on which the user reacted.
    The detached POJO provides you the virtualization the logical view of the database. Because it has the dataset key it also knows how to re-attach and persist itself. The bookworking is done for free!
  19. These POJO's have all of the information you need and JSF will provide you the POJO that represents the selected row during the response. [...] The detached POJO provides you the virtualization the logical view of the database. Because it has the dataset key it also knows how to re-attach and persist itself. The bookworking is done for free!
    By itself this doesn't seem to solve the problem. It merely moves it to another abstraction layer. Your explanation is sound, but it tells us what to do *after* we have identified the exact thing the user clicks on. This is indeed an important thing to get right, but it's not the problem mentioned in the opening post. How would you in the first place (re)create the POJO you mention based on a row click, where only a view ID and a component ID is send along? There's no conceptual difference between restoring a specific (view on a) dataset and restoring a specific POJO that is an abstraction or mapping of a row in this dataset. The only way you could do something like that is by providing more data with the request. Such data could be a logical key (which was already mentioned), it could entail serializing the dataset or individual rows (e.g. as POJOs) to the view state or it could be something else entirely (perhaps a conversation ID or something like that). Neither of those options is offered by the standard datatable. Tomahawk for instance offers two options: providing a key and serializing the associated data. Serializing in tomahawk can either be done directly in the datatable or you can optionally do something yourself using the savestate tag. I'm sure Seam also has some interesting options to solve this problem. Things like Tomahawk and Seam are no alternatives for JSF, but extensions of the kind which have been planned for in the base JSF design. Nevertheless, this doesn't mean using the plain JSF datatable isn't a TRAP. So, I think the proposition of the author is right; using the plain JSF datatable is in fact a trap and first time users should be warned about this.
  20. By itself this doesn't seem to solve the problem. It merely moves it to another abstraction layer.
    Exactly. JSF is NOT an end-to-end solution. It is purely a view layer / abstraction solution. Moving the 'problem' to another abstraction layer is the correct thing to do. Let the ORM layer / abstraction worry about db refreshes, data caching, locks, transactions, etc. This is its job - Not the job of JSF. I see this problem all the time with people creating convoluted ways to use JSF to perform business validations, which should be handled in the middle tier not the presentation tier. JSF is good at presenting data to the user and receiving user input which it passes on to the lower layers. Do not try to force the presentation layer to do what a non-presentation (e.g. ORM) layer should do. Regards, Fintan
  21. Re: Post does make sense[ Go to top ]

    For example, suppose that we recreate the data model from a DB and between requests someone else deletes row 3, causing the other rows to shift one position. Using datatable's standard method of matching clicks to a datamodel row, the cursor will be pointing to row 4! This can have disastrous results!

    Ladies and gentlemen, I give you ... transactions. Shouldn't it be simply assumed as a matter of common sense that when working with a resultset stored in a datamodel that you would always have actions on that datamodel work within an isolated transaction? In fact, it shouldn't even need a transaction per se -- recreating the data model with every action sounds barkingly insane to me. Is this really how JSF works?
  22. Re: Post does make sense[ Go to top ]

    pardons ... I must someday learn to use the CLOSE tag for blockquotes sometime. Wouldn't it be neat if posts were validated for proper HTML?
  23. Well it does imply a problem[ Go to top ]

    Problem is that if data model changes between requests you may be doing an action against the wrong data - not necessarily invalid (say in case you want to delete something and end up with a wrong ID, wooopsy! :) - but this boils down to how the implementation vendor solved the mapping "request param -> value". Oh and BTW is your DataModelController session scoped? And of course we have a problem that if the data is retrieved in some elaborate way, so that it in apply request values -> update model data phases you do not have data in place(happens with request scope beans), your action call may be lost - and that's a fact. Just like a selectOneMenu will validate the incoming against the model, before setting it, that is you cannot set any value into the select box, because only values that are already in select items may be set there.
  24. Re: Well it does imply a problem[ Go to top ]

    Oh and BTW is your DataModelController session scoped?
    I did not include faces-config but it was scoped as request, even none will work.
    Problem is that if data model changes between requests you may be doing an action against the wrong data
    Now you are getting to the heart of the issue. I just want to point out that the premise or under-current of the post is that there is some gaping flaw in JSF RI. If you want to say this is the TRAP then that should be the premise and I would agree that I have seen it as the trap, that is persistence is a HUGH issue.
  25. I firmly believe that the TRAP in JSF is the way it is "taught" in terms of the "Backing Bean". I have seen far too many people bind a selection list whose setValue goes right back to a row in a data base.

    The JSF view needs to be decoupled from the business (data) model with what I like to call a use case or screen controller. When I see people binding the components in a JSF view directly to the business-model (such that update model causes a transaction in the business model) I know their design is headed for trouble.

    This is not the place to get into JSF design patterns but you can see even in the way I wrote my example that the Controller is responsible for managing the interaction between the View and the Model, it is responsible for implementing a portion of a use-case.

    The emerging POJO and EJB3 persistence model fits extremely well with JSF. In these cases, the controller needs to get the business object, cache it (Seam conversation works well here or you can save it in the controller assuming it has session scope or any of other methods above) as POJO, and then the JSF view can safely bind to it.

    The controller is responsible for persisting/commiting the updated POJO into the business model during the invoke phase. Note:During the model update phase all that happens is the light-weight POJO is manipulated, not the underlying "business model". This is an extremely important point when developing in JSF and one that gets confused in all the talk about backing beans.

    Following this design pattern eliminates almost every JSF issue I have seen people disscuss.

    Finally when people talk about a business model that "changes" across a web transaction I would submit that this presents all sorts of design issues that go far beyond JSF. In the simplest cases, where you are just selecting a row in a model, there are typically no issues when using a POJO model. When external changes can occur to data, typically what you need to do is determine if the data (e.g.row in a table) selected has changed in the underlying business model (easy to do with Hibernate) and take the appropriate action. Using a POJO persistence pattern, a change in the business model will not effect the POJO being used in the JSF data model. Note my distinction between the business model and JSF data model, it is an import aspect of JSF implementation technique, or at least I think it is.
  26. the controller needs to get the business object, cache it (Seam conversation works well here or you can save it in the controller assuming it has session scope or any of other methods above) as POJO, and then the JSF view can safely bind to it.
    Simply storing the object in session scope is not a solution at all. On the contrary, in this context it may even make the problem worse. Suppose a user has two views (i.e. a tab or window) on the same page and makes a click on a row in both of them. We now run the risk that two instances of the event handling code run at the same time, causing such mayhem as two different clicks being processed for the same row even if the user clicked on different rows or processing clicks for a row the user didn't clicked at all (e.g. the first handler registers a match for row 3 and calls the action method, but before it gets a chance to actually run the second event handler runs and advances the cursor in the (shared!) datamodel. When the first handler finally runs it tries to process a row the user never clicked)
  27. Suppose a user has two views (i.e. a tab or window) on the same page and makes a click on a row in both of them.
    This is _precisely_ what conversations in Seam solve. You simply begin a long-running conversation when you land on the view or instantiate the bean that has your datamodel in it (your choice), and have an entity manager per conversation scope. The mechanism is so natural that I can't imagine why it hasn't always been done that way ... perhaps because we've been saddled with coarse-grained Sessions for all of JEE's life instead of having arbitrary contexts of user-defineable extent and scope. Perhaps the WebBeans JSR should form the basis of EJB4, but I'm not holding my breath.
  28. Re: Well it does imply a problem[ Go to top ]

    Oh and BTW is your DataModelController session scoped?
    I did not include faces-config but it was scoped as request, even none will work.
    Problem is that if data model changes between requests you may be doing an action against the wrong data
    Now you are getting to the heart of the issue. I just want to point out that the premise or under-current of the post is that there is some gaping flaw in JSF RI. If you want to say this is the TRAP then that should be the premise and I would agree that I have seen it as the trap, that is persistence is a HUGH issue.
    This is not directly a flaw in jsf, data models are generic models delivering data, how the data is provided does not say anything. It does not matter if jsf or not, in a webapp you cannot rely on having constant positional index values on data provided by data layer accessed by many users, unless you work on a snapshot of that data. If you work with data in a webapp, never ever rely on an index position to identify your dataset , unless you know for sure your data is consistent over the request boundaries (which in most cases it is not) you work with, there are other ways to identify a dataset, depending on the type of database or storage, and for updates you also have to check against updates from outside. But those things are matters of the business layer and basically are matters of good db access code. JSF and other webframeworks are view layer related only and hence only have to transfer the data which allows a controller to identify the dataset physically, afterwards so that the request values can be applied in a proper way. To make it short, do not use some kind of memory related index positions in a webapp to identify datasets in a database!!!!
  29. It does not matter if jsf or not, in a webapp you cannot rely on having constant positional index values on data provided by data layer accessed by many users, unless you work on a snapshot of that data. If you work with data in a webapp, never ever rely on an index position to identify your dataset , unless you know for sure your data is consistent over the request boundaries ...
    I will conceed that the simple JSF UIData model relies on having both a snapshot of data in memory and there is a tight coupling between the UI and that data model. I will also conceed that the storage of both the JSF View model and all of these snapshot data models can present performance issues for those not keenly aware of the issues.

    While I don't take issue with the need to have multiple users work on the same data simultaneously, it should be avoided when at all possible, and I don't think this complexity can be solved by JSF RI.

    I could provide you several solutons to this problem but I do not think that the "id" is the best place to store the dataset "key" and this is why I do not think there is any problem here at all. For the majority of cases, the JSF model works well, for more complex cases you need more complex solutons..

    For example, you can store tokens that allow you to map back to the data set and these tokens can even be stored client side (see solutions in ADF/Trinidad). This simultaneously solves both your dataset issue and the server side storage problem. Every framework like JSF comes with a set of patterns that work best for it. JSF RI is just that an RI; any one trying to solve a complex problem with the JSF RI is in a world of hurt. We need better solutions than the RI from vendors and this is happening ... slowly.
  30. Seam will help[ Go to top ]

    With JBoss Seam it is so easy that I have forgotten that that 'problem' ever existed. And it is possible to use conversation which lives longer than request and shorter (not necessarily though) than session.
  31. Re: Seam will help[ Go to top ]

    Yes, I recall Seam addressing this issue explicitly in their managed beans.
  32. I have seen this problem myself. My solution was to use the Tomahawk saveState component to persist the state of the list backing the data table between requests.
  33. Seam conversational model[ Go to top ]

    I have seen this problem myself. My solution was to use the Tomahawk saveState component to persist the state of the list backing the data table between requests.
    Have you checked out Seam's conversational model?
  34. Btw., I do feel honored that my post led to this discussion. Seems like the only news item with more responses these last few days was Marc Fleurys resignment from red hat. Concerning Seam, since it seems like we will be able to use Java 5 on the project, I might use it. I have taken a look at it several months ago and liked what I saw.