.

Sunday, September 24, 2017

Eclipselink 2.5.2 (JPA 2.1.0): Determining Fetch State

This discussion made use of JPA 2.1.0 and Eclipselink 2.5.2. Specs and implementation and may change in future releases. It might be helpful to test with different versions by (locally) modifying the pom.xml file that appears in the github repository Eclipselink Fetch State Experiment that contains in-depth code and discussion for the concepts relevant to this post.

Also, here is another great reference for when reading through the code: Eclipselink JPA 2.0 Persistence Utils

This "issues" disucussed here do not seem to have been resolved yet as of Eclipselink 2.6.x releases.

Lazy-loading (in various degrees) definitely benefits optimization, and being able to tell whether certain attributes of JPA entities are loaded or not pretty much lies in cusps between such decisions.

At the forefront, JPA actually provides a way to inspect an entity (or its attributes) to determine its fetch state - whether they are loaded or not - through PersistenceUtil.

It can be invoked via the following code:
Looks simple enough. However, is it reliable?

Because it relies on provider implementation, that greatly depends.

To be fair, aside from the method semantics, JPA (as of 2.0, and even in 2.1) provides specification described in the comments in an interface used in the implementation internals of PersistenceUtil, ProviderUtil:
  • isLoadedWithoutReference and isLoadedWithReference, both with arguments (Object entity, String attributeName)

    • "If the provider determines that the entity has been provided by itself and that the state of the specified attribute has been loaded, this method returns LoadState.LOADED."

    • "If the provider determines that the entity has been provided by itself and that either entity attributes with FetchType.EAGER have not been loaded or that the state of the specified attribute has not been loaded, this methods returns LoadState.NOT_LOADED"; and

    • "If a provider cannot determine the load state, this method returns LoadState.UNKNOWN."

    • These two methods are differentiated in that WithReference is permitted to obtain/initialize a reference, whereas the other is not. Note that Eclipselink does not obtain a reference for either one anyway.

  • isLoaded(Object entity)

    • "If the provider determines that the entity has been provided by itself and that the state of all attributes for which FetchType.EAGER has been specified have been loaded, this method returns LoadState.LOADED."

    • "If the provider determines that the entity has been provided by itself and that not all attributes with FetchType.EAGER have been loaded, this method returns LoadState.NOT_LOADED"; and

    • "If the provider cannot determine if the entity has been provided by itself, this method returns LoadState.UNKNOWN."

    • This method is also not permitted to obtain/initialize references.

To put it simply, JPA specifies that an entity is loaded if all the attributes and associations configured to be EAGER by "DEFAULT" have been initialized; if the entity is found to be loaded, then checking for attributes can be done properly and predictably.

The word "default" is stressed here because it actually describes explicit configuration via ORM XML or annotations - pretty much whatever you define at the beginning.

Watch how your provider implements the specification metioned in the comments in ProdivderUtil.

Eclipselink holds true to this (tested in version 2.5.2), and only to this extent. When dynamic configuration is done through runtime application of FetchGroups, PersistenceUtil becomes completely unusable.

Experiment-discussion


The meat of this discussion actually appears in the test class found in this github repository:

Eclipselink Fetch State Experiment

Simply run the "mvn test" Maven command from the directory that contains the pom.xml file to see if all the test pass (they should). After this, read the code found in the only test class under src/test/main/....

With all the technicalities discussed in the github repository linked previously, I'll just leave y'all with a summary of what was in there.

Summary


For Eclipselink, there are actually two main ways to accurately determine entity/attribute/association fetch state. Furthermore, they only work for entities that have been woven. Then again, weaving is what enables lazy loading, and we'd only need to determine fetch state at all if lazy loading was enabled. Anyway, here they are:
  • org.eclipse.persistence.queries.FetchGroupTracker, the simpler (but not the best) way
    • FetchGroupTracker is one of the interfaces that entity weaving adds to your entities. It tracks the FetchGroup used when the specific entity was loaded. A FetchGroup is simply a group of attributes used by Eclipselink to specify which attributes and associations a query or fetch should use.

    • FetchGroupTracker has the _persistence_isAttributeFetched(String attributeName) with which the load state of an attribute can be determined.

      Do this by simply casting the entity to FetchGroupTracker, and use the method accordingly:
    • Now, the problem (or maybe the cool thing) here is that this method is the counterpart of PersistenceUtil; it is unreliable when a FetchGroup is not present for the entity - this means that the entity was fetched using default configuration, where no basic attributes were made LAZY (if a basic attribute was made LAZY, it would have had a default FetchGroup). So if PersistenceUtil works on entities that used defaults while FetchGroupTracker works on entities that used a custom FetchGroup, perhaps they can be made to work together to cover each other's weaknesses (this is only an option; the better ways are described below).
  • org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl, the actual correct way
    • Even though Eclipselink's PersistenceUtil uses the relevant EntityManagerFactoryImpl methods internally, PersistenceUtil fails due to some of the logic written to follow JPA's specification. However, using EntityManagerFactoryImpl's various isLoaded(...) methods actually work properly (isLoaded(entity) follows JPA's definition of a loaded entity; you'll be using the more attribute-specific overloads).

    • The following snippet describes the methods in question:


And that's pretty much it. Hope this helped!

Friday, September 22, 2017

ADF (12.1.3) Table Row Selection: Dangerous Behavior

The ADF Table is one of those prolific components used in ADF web projects.

Over at the ADF project I worked on, there were cases where the selectionListener attribute was used to hook processing to the event. Of course, being a newbie that time, using the feature didn't go very smoothly.

This post will discuss things to watch our for when using the selection listener.



The following is a normal ADF table whose value is bound to some List whose values are irrelevant:


These tables are usually bound to a backing bean via the following code:

The generic type org.apache.myfaces.trinidad.util.ComponentReference is used to store component reference in a serializable and lightweight manner.

Row Selection and Activity

Selection Basics


By default, highlighting rows to mark them for selection is not enabled in a table. To augment this, simply modify the rowSelection property of the table. For example, if the rowSelection is set to "single", clicking on a row will yield the following visual output:


Although it has a little more added pleasant effects on the side, the highlighting is the most notable.

Behind the scenes, a table uses RowKeySets to keep track of the states of each row – like which rows are selected. The structure of a RowKeySet is quite close to a simple array of integers.

This allows the use of the table's getSelectedRowData() method to return the selected row, although a cast is needed as the return is of type java.lang.Object.

A problem with this is that this highlighting can be cached, even if the row is not actually selected! Furthermore, row selection cannot occur when a highlighted row is clicked on. This is very troublesome for pages that initially render with tables that have cached selection, while the tables have important row selection events – especially if there is only a single row, where the user can no longer trigger the event for the row whose selection is cached.

Of course, there are workarounds for this.

For pages with tables that initially render with cached selection, the solution can be quite a burden, but it is a solution nonetheless. It is as follows:
  1. Bind the table's selectedRowKeys property to the bean.
    • The bound bean property should be of type org.apache.myfaces.trinidad.model.RowKeySet; the property variable can be initialized using the concrete class org.apache.myfaces.trinidad.model.RowKeySetImpl. Initializing the variable with the empty constructors is sufficient.
    • Do not include the settermethod for this bean property so the table does not influence the state that the bean – in other words, the developer – should manage.
      • This means that for every process that might modify the table or its contents, the RowKeySet must be adjusted manually and constantly. Idioms exist for such cases:
        • adding an element to the table:
        • removing an item:
        • clearing selection:
  2. In the setter method for the table's binding, use the setRowIndex(int) method of the table during initialization, and pass it -1, as in "table.setRowIndex(-1)".
    • This is to make sure that the table has no initial back-end cached row selections (this does not make it safe from front-end selection caching, however)
    • Doing this disallows proper use of the varStatus property of the table for some reason – row indices are not displayed properly, but it does not negatively affect server-side processing.
  3. If the table resides in a reusable region, make sure the invoking page refreshes the region before it is displayed. The following snippet does just that:

On the other hand, when clearing the selection only has to happens during the lifecycle of the view, then clearing the table selection is sufficient.

 The Selection Event


Another main benefit of allowing selection is the ability to declare a selectionListener on the table. This property a allows a hook on which logic can be serviced upon the selection of a new row in the table. The following empty method snippet describes the signature of the method to bind:

Using this feature imposes new behavior upon its table. Without a selectionListener, row selection will not cause (partial) submission of table data; input components with validation will not trigger by merely selecting rows on the table. On the other hand, declaring a selectionListener the table submits its contents, tripping the validation of any enabled component within the table. Although this might sound very risky and could potentially produce vulnerabilities (this post discusses some of that), this is also a step taken to extend the operability of tables - also, because the events would usually reside on the server, it only makes sense that the table produces a request.

Of course, using more features introduces more considerations and maintenance requirements. It cannot be reiterated enough how invaluable awareness is throughout the construct of a page; couple it with knowledge of the problems discussed here, and, as with many other features, the output can be made robust.

Adding a selection event causes the table, and any partial targets to submit. This means that a selection will not succeed if the components queued for submission are not satisfied. Furthermore, the problem is aggravated by the inconsistency introduced regarding selection: even though the selection event is not fired, the selection changes anyway! This causes selection integrity efforts done during the selection event to go awry.

Here is a quick demonstration:
  1. Initially, the input components are not required so that the first selection can be made, and the selection event fired properly. A row is then selected (the text components below the table are partial targets of the table):

    • The value for "current selection via table" is directly bound in the JSF through the expression #{viewScope.backingBean.table.selectedRowData.name}, with the following properties:
      • backingBean refers to a viewScope bean that holds the table component
      • table is the bean property of the backing bean where the table is bound
      • selectedRowData is the table method that returns what is actually selected
      • name is a property of a row in the table that corresponds to the first column (output components)
    • The value for "current selection via selection listener" is bound to a viewScope bean property whose value is update during the table's selection event with code following from this snippet:
  2. The "make input required" button is clicked so that the input fields on the second column are now required. This is implemented as a simple toggle in the view-scope bean.
  3. The second row is selected, and then the page is manually refreshed (via f5 in most browsers) since partial rendering will not occur if there are unsatisfied fields during submission:

Notice that "current selection" text fields at the bottom are inconsistent. Again, "current selection via table" takes the value straight from the table, with the EL string "#{viewScope.backingBean.table.selectedRowData.name}". On the other hand, "current selection via selection listener" takes its value from a bean property that is managed by the table's selectionListener. It becomes clear that the selection event was not fired.

There is quick remedy for this problem: setting the table's immediate attribute to "true". Doing so will bypass errors from component validation as the table short-circuits its submission, if only to allow unhindered row changes. Take careful consideration of its implications to your desired program flow and guard your code well against problems (increasing such robustness may involve relocatin validation and manually queueing events, among others).

Use the immediate attribute for components responsibly. Normally, it is to be used with action components such as buttons or links, but finer requirements may merit the use of the attribute in input components as well. Be careful as using this attribute introduces delicacy in the lifecycle of a JSF request. This blog post provides a full explanation of what the attribute does.

Table Editing Mode

Table Editing Mode is another neat feature of ADF tables which appears as the editingMode property. It has two values: editAll (the default), which has the table leave the its input components to their own conditions for being disabled; and clickToEdit, which has the table disable the input components of a row that is not selected (hence, "click on the row to edit" its values).

As cool as this feature is, a selection listener combined with rows with components that use validation throws a spanner into its workings.

Let's observe such a case. Here is the previous table (still not made immediate), now modified to have the clickToEdit editingMode (notice the input text box only appears on the selected row):



The input text box components on the second row were left so that input is required. Since a selection listener causes table data submission upon row selection change, the requiredness should trip an error:



A truly frightening sight, even as we have not manually refreshed the page!

Now, let us refresh the page to find out of the selection listener was called:



It is now also clear that even the selection event was not fired, but the actual selection still changed.

Hold on, what about submission?

Let's satisfy the requiredness of the input field, and then click on the submit button:



Though the event is invisible (as the implementation is hollow), the submit actually proceeded. This spells bad news for inactive rows with invalid data – manual validation has to be done upon submit when using this feature.

Summary

Selection is pretty much commonplace when using tables, though the newbie ADF developer may find trouble when having to use the selectionListener.

When selection is enabled in a table, a selectionListener can further be declared to handle selection events as desired. However, doing so now forces the table to submit its contents as it now makes requests whenever row selection (of a different row from the previous) is done.

This can be troublesome when input components in the table have validation issues, as row selection now only "occurs" in the view (via highlight changes), as the selection event does not get called. A quick solution for this is to have the table's immediate attribute set to "true". Of course, be careful of its implications.

Another nice feature of ADF tables is the editingMode. Depending on the value, a table can have input components of non-selected rows disabled (by default, all input components of the table would be enabled).

Of course, this feature is not safe from what selection events and component validation impose. With both in commission, row selections that trip validation errors still have the highlight (only the visual element) move, while the actual selection remains, also without the selection event being called. Furthermore, "inactive" rows with invalid input do not trip their validations, so proper collective validation also has to be done deeper in server-side logic (as better practices also propose).


And that's all. Hope you find this helpful. Cheers!