|
References to Bindings in Non-Current BindingContainer Require Changes After Migration
Note: This is a preview of an important note in the JDeveloper 10.1.3 Release Notes
It is a best practice for each page or panel's binding container to define the bindings for all data it needs to reference. This is the situation that you get by default when building pages by dropping controls from the ADF Data Control palette, for example. If you have developed your pages using this best practice then no application changes are required upon migrating to 10.1.3. However, if your application contains pages that refer to bindings from binding containers other than the current page's binding container, please read on for important information you need to be aware of when migrating existing applications to 10.1.3.
For web applications, the ADF Model runtime framework automatically "prepares" the correct binding container for the current page request during the "prepareModel" phase of the lifecycle, and releases any state held by the bindings in that current binding container at the end of the request. This improves scalability by avoiding unnecessary session-level state. In 10.1.2, if the current page attempted to access a binding from another binding container using an EL expression like ${data.SomeNonCurrentBindingContainer.SomeBindingName} -- then we previously attempted an on-demand prepareModel() for the single iterator related to that binding in the context of the current request. In some situations, this worked ok. Unfortunately, the behavior was inconsistent and could produce unexpected side-effects that surprised many developers depending on the kind of iterator the non-current binding was related to. To address this inconsistency, and to promote the best practice described above, we now avoid this on-demand, per-iterator preparation altogether. The net effect is that by default, the current page can only reference bindings from its own binding container.
You can search your application pages for occurrences of "${data." to check whether your application contains any such references. If it does, you can replace them systematically by:
- Using the Structure Pane to create a new binding in the current page's Page Definition which references the same iterator and attribute that the binding in the other binding container was referencing.
- Changing your current reference of
${data.SomeNonCurrentBindingContainer.SomeBindingName} to ${bindings.NewBindingName}
NOTE: Adding a new binding in a new binding container to an iterator whose query has already been executed by a previous page does not implicitly cause the query to be re-executed. The "prepare" phase only implicitly executes the query for iterators that have not previously ever been executed during the current session. If you wanted the query to be re-executed, you would need to explicitly use the execute built-in action of the iterator to force the query to re-execute (or programmatically invoke its executeQuery() method).
If you reference bindings like ${data.SomeBindingContainer.SomeBindingName} in "shared" JSP page fragments that you include into multiple pages, then you can programmatically prepare the SomeBindingContainer during the current page request by overriding the prepareModel() method of your existing DataAction class and calling a helper method like prepareBindingContainer() below after super.prepareModel() to refresh the necessary binding container containing the binding you need to reference in the page:
public void prepareBindingContainer(DataActionContext ctx, String bcName) { ctx.getBindingContext().findBindingContainer(bcName) .refresh(DCBindingContainer.PREPARE_MODEL); }
Your overridden prepareModel() method would therefore look like this:
/* Programmatically prepare NameOfOtherPageUIModel binding container in this request, too */ public void prepareModel(DataActionContext context) { super.prepareModel(context); prepareBindingContainer(context,"NameOfOtherPageUIModel"); }
If you are adding this code to the DataPage for the first time in 10.1.3, the class will be a subclass of the new PageController class which has the same prepareModel() lifecycle method to override, and the helper method would look like this:
public void refreshBindingContainer(LifecycleContext ctx, String bcName) { ctx.getBindingContext().findBindingContainer(bcName) .refresh(DCBindingContainer.PREPARE_MODEL); }
Currently the ADF Business Components data control is the only data control to agressively enforce this new behavior, but other data control implementations will follow this policy in a future maintenance release so it's best to follow the best practice advice effective immediately regardless of what kind of data control you are using in your applications.
|