Sometimes I try to do things but it just doesn't work out the way I want it to, and I get real frustrated and then like I try hard to do it, and I like, take my time but it just doesn't work out the way I want it to. Its like, I concentrate on it real hard, but it just doesn't work out. And everything I do and everything I try, it never turns out. Its like, I need time to figure these things out.
--Institutionalized by Suicidal Tendencies
This blog is for people who feel this way about JSF. Or who just want a Pepsi.

Wednesday, March 31, 2010

Changes Part 2--The MDS ChangeManager

As discussed in Part 1, Oracle ADF Faces ships with an Apache Trinidad ChangeManager implementation that stores the changes persistently across user sessions using the Oracle Metadata Services (MDS).
Actually configuring this is easy using JDeveloper. Open up your project's properties. Select the "ADF View" category. Select "Enable User Customizations" and "Across Sessions using MDS".

However the actual result seems to make no sense:
To web.xml this added:
And to adf-config.xml, it added:

The issue is that the MDSDocumentChangeManager persists everything to MDS. But we don't want that for a number of reasons.
  1. The current implementation of reading changes applied through MDS rereads and re-reads the entire document. This isn't fast (it would be even slower in the case of JSPs if Oracle didn't use a special JSP engine that interprets the document instead of recompiling it), so we only want to use MDS for the specific changes that users want persisted across sessions (say that layout of their configurable home page).
  2. MDS works by applying deltas to the page's XML document. If there is no way to encode the current value into the document, MDS can't record a change. An example of this are attributes, like the set of expanded nodes in a tree that are only accessed through the Expression Language
  3. MDS security may prevent customizations form being saved for some parts of the document
  4. MDS can't record changes for components that don't have their id attribute set
So, instead of registering the MDSChangeManager with Trinidad directly, we register the FilteredPersistenceChangeManager instead. This ChangeManager implementation handles routing the changes to either the SessionChangeManager or MDSDocumentChangeManager as appropriate. The FilteredPersistenceChangeManager uses the following ordered rules to determine which ChangeManager to persist to:
RulePersist To
Is the change unrepresentable as a change to the page's document?Session
Did attempting to write the change to MDS fail?Session
Is this an attribute change and is the name of the attribute listed in the component's persist attribute?MDS
Is this an attribute change and is the name of the attribute lsited in the componen'ts dontPersist attributeSession
Does this change match an application-wide rule specified in adf-config.xmlMDS
All other casesSession

OK, actually I've oversimplified things. The FilteredPersistenceChangeManager actually writes all of the persistent changes to whatever ChangeManager is returned by AdfFacesContext.getPersistentChangeManager(), which we configured to point to the MDSDocumentChangeManager in our changes to adf-config.xml. (You are probably thinking 'What the hell! Why didn't they just make the MDSDocumentChangeManager work like this all of the time instead of making me perform this extra whacked configuration. Well, at one point internally, it did. But then we had customers, like Oracle Web Center that needed access to an unfiltered version of the persistent ChangeManager. Since I love composition, we went with this approach)
So, even after you have configured ADF Faces to use MDS to store changes, you still need to actually perform some addition configuration to actually get changes stored in MDS rather than in the Session. While you could use the rules in adf-config.xml, for performance reasons, I prefer setting the persist attribute. To remember in MDS whether a showDetailItem is disclosed for a particular instance , you would use:
<af:showDetailItem id="showOff" text="Show Me" persist="disclosed">
... content ...
I'll cover random weirdness and gotchas using the various ChangeManagers in part 3.

1 comment:

  1. Hi Blake ,
    I want to make a dynamic region programatically.For that i have added a RichRegion programatically and added the code already in pagedef.At last my region is not rendering and i am getting this message again and again
    Unserializable value:oracle.adf.controller.internal.binding.DCTaskFlowBinding$InnerTaskFlowRegionModel@6cf2b7 for key:UINodePropertyKey[value,14]

    pasting the code of bean:
    RichRegion rr = new RichRegion();
    FacesContext facesContext = FacesContext.getCurrentInstance();
    Application app = facesContext.getApplication();
    ExpressionFactory elFactory = app.getExpressionFactory();
    ELContext elContext = facesContext.getELContext();
    ValueExpression valueExp =
    elFactory.createValueExpression(elContext, "#{bindings.dynamicRegion.regionModel}",
    RegionModel model = (RegionModel)valueExp.getValue(elContext);

    In pagedef :

    Help if you can suggest some thing or if you can provide some links.