• Post Reply Bookmark Topic Watch Topic
  • New Topic

Using JPA query parameters in JSF to render Javascript (D3) Graph  RSS feed

 
Jay Tai
Ranch Hand
Posts: 222
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm trying to render a Javascript graph in a JSF application where the user chooses from a list of countries and gets a bar graph pertaining to the chosen country. The query result is returned as a ListDataModel which is then converted into a GSON string that is pulled and populated by the graph. The graph uses the D3 JS library.

If I hardcode the query parameter (the country id) into the JPA facade, the graph renders perfectly. If I use a parameter query, however, I get a blank graph. The GSON string is still successfully created using the parameter method. I do not get any stack trace, but I get an index error in the Javascript console (see below).

The start page is an xhtml giving the user a drop down list to choose the country:




The following method is called in the managed bean:


The RigCount xhtml page returned is:




The above method uses the following method in the managed bean to create the GSON string:




The following JPA is used (the commented JPA is just a test method used to hardcode the countryid):




The problem appears to be with the 'rigInstance.CountryInstance.countryid' parameter. This is a query parameter in the JPA. When it is hardcoded the grapth picks it up and renders. When using the above methods, the GSON string which is returned is:



The data is correct but the index:0 suggests that the query parameter from the JPA is not being correctly coded in the bean methods. I've tried several different ways to declare this 'index' but to no avail. Would really appreciate any advise where I"m going wrong. Thanks in advance!






 
Tim Holloway
Bartender
Posts: 18531
61
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Tsk, tsk, tsk. Really. JSF backing beans are not Controllers. They are Models. In JSF, the Controllers are not user-written code - they are part of JSF itself.

Nitpicking aside, there was a little more information there than I could comfortably read this early in the morning. But it sounds like you're attempting to convert your ListDataModel object directly to gson/json and getting more than you bargained for.

If you want the list and only the list, use the "getWrappedData()" method to return the backing data for the ListDataModel without the extra decorations that the ListDataModel itself contains.
 
Jay Tai
Ranch Hand
Posts: 222
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Tim,

Some nits simply must be picked! To be precise, this is a CDI (Controller) bean which was auto generated by the IDE (Netbeans). I added the user areas because I don't really understand how to separate model and controller logic in two beans, as a I need the controller bean methods in the model logic. I'd like to revisit this after solving the immediate problem in this post.


In terms of the current problem, I've never used getWrappedData() before so I tried two ways to use this method, neither successful. The first way was simply to call getWrapped data (countryList.getWrappedData), which had no effect in that I got exactly the same Gson and blank graph. The second (commented) way, was to cast an object to a ListDataModel, but this gives:






Yet another attempt was to create getWrappedData as a stand alone method and pass this to the getGson method:




Can you please explain more about getWrappedData and how to use it? I am not looking at the API


 
Jay Tai
Ranch Hand
Posts: 222
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sorry edit to my above post. I meant I am NOW looking at the API. My use of getWrappedData SEEMS to be correct but it made no difference in the output of the GSON string. The thing that solved my problem was using a plain ole List instead of ListDataModel in the JPA query and result list in the controller class. My problem is solved but I'd like to know why using a List works when using a ListDataModel results in a zero index for the resulting GSON string. I always assumed very close similarities between List and ListDataModel, thinking that List actually results in the creation of an anonymous ListDataModel. If that's the case, then using ListDataModel is just me manually creating the data model that the generic List method would create anyway, so why does List result in the correct GSON output where ListDataModel results in an output that has a zero index? Thanks in advance for the explanation
 
Tim Holloway
Bartender
Posts: 18531
61
Android Eclipse IDE Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If NetBeans is tacking on "Controller" to the classnamef of your JSF backing beans, regardless of whether they're defined via XML, JSF annotations, or CDI annotations, it's doing so in error.

In MVC, a Controller does exactly one thing. It takes a Model and a View, compares them, and, if they compare unequal, it updates the Model or View to match the changes that had been made in the corresponding View or Model. Controllers do not do business functions or access persistent storage.

In JSF, the master (parent) Controller is the FacesServlet. The sub-Controllers are implemented in the rendering and processing logic of the JSF control element processors. Unless you are creating a custom binary control, therefore, you will not write any Controller logic.

A JSF backing bean is always a Model if it contains any referenceable properties ('value=' targets) in it. The non-property methods (listeners and action methods) are not Controller logic. The listeners are support functions and are not allowed to directly update the View the way the Controllers do. The action methods are business logic and not part of MVC - it's just simpler not to have separate action beans to hold them. Unless the business logic is complex, in which case, the backing bean would generally have an action method invoke methods in a pure business-logic bean.

I'm afraid I'm still not reading what you're posting as closely as necessary, but I don't get paid for this, and I'm being lazy. I did notice that you're doing your data fetch in the "get model" property access method. That's bad.

There are 2 reasons why it's bad. First, because the "get" method could get called multiple times for a single page display operation. Since database access is relatively slow, that multiplies the overhead considerably.

The second reason is what's known as "idempotency". An idempotent function will always return the same data, with the same attributes, in the same order, regardless of how many times it is called. If you're lucky, your property-get is doing that, and you've simply got unnecessary database overhead. However, if some other process is modifying the data in between your fetch calls, you'll be getting back data that's inconsistent and the results can be extremely unpredictable. JSF "get" methods are supposed to be idempotent. And, for that matter, "set" methods should not have side-effects that would cause problems if a single page operation caused them to be called repeatedly.

Because of this, what I normally do is use a cached DataModel. On the first "get" call, there's no existing DataModel object (it's null), so I build one, and the build process invokes a load function that does the actual data load from persistent store. I then save the constructed DataModel and return it as needed so I don't have to keep rebuilding it. If the data changes, I can trigger a refresh by simply resetting the DataModel properry to null, which will initiate the build/load process all over again, but with the latest version of the data.

A JSF DataModel is basically a façade for a collection of data. There exist different types of DataModel classes, including Lists, arrays, and JDBC fetch operations. All they really do is provide a container for the wrapped data and a cursor that can be used to help the UI track certain operations such as what row the user clicked on. The DataModel object itself (and therefore the wrapped data) must exist in an enduring scope. In other words, not Request scope, because Request scope would destroy and re-create the datamodel and in the process lose its state data.

The actual wrapped data in the datamodel is whatever data you want it to be. It can be the direct results of a data fetch or synthesis operation or it can in turn be a façade for some other data. For example, since many database ORM systems don't allow boolean primitives, but JSF cannot convert non-booleans to serve as Model values for checkboxes, a facade or decorator might overlay the actual returned object model row to provide the necessary translation. JSF itself does not alter, copy, or replace the underlying wrapped data model collection object itself, although it does connect the row data properties to the corresponding tabular display controls (again, this is JSF's built-in Controllers at work).

If you use an automated service to render JSON, XML or whatever from the wrapped data, therefore, what you should get is the raw data itself. What I think you were doing was rendering from the DataModel object, which would return data with 2 differences. First, the cursor property of the Datamodel might render and secondly, the collection itself would appear as a sub-property of the rendered Datamodel. That's because DataModel doesn't aggregate the raw data, it embeds it. But like I said, I'm being lazy so I haven't verified that. As long as you've got a solution, the rest is academic.

Incidentally, the row index (cursor) value is zero because the model is "at rest" when queried. It's only actively something else inside an action method when the getRowData() or getRowIndex() methods are invoked.
 
Don't get me started about those stupid light bulbs.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!