Wednesday, September 16, 2009

New slideshow uploaded to slideshare

Check out my new slide share presentation on JSF Custom Components that I will be presenting for Oracle Open World 2009...if you go to the slideshare site you can download the ppt and get the notes that go with the presentation.

http://www.slideshare.net/mfons/jsf-custom-components-972003

You can also download the powerpoint by pressing the Menu icon on the bottom left of the embedded slideshare image below, and selecting Download in the context menu.

Or view the presentation below without the notes...



Thursday, August 27, 2009

ADF Faces (Trinity): af:forEach and af:table...think twice

Rule of thumb: be careful of using af:forEach in af:table rows to generate the options of a select list. Much safer to use getter to get a list and plug into value of f:selectItems (plural), than to use f:selectItem (singular) and use af:forEach to iterate over. af:iterator might work instead of af:forEach, too, but I am not sure.

Also mixed in with this was using forEach's varStatus property...something I have had bad luck with in the past.

Basically what was happening, was this forEach was not even on a part of the screen that was getting rendered, but it was causing components to render multiple times and get all mixed up. Pretty hard to track down.

So in this particular case I would get this doubling when I used the following inside of an af:selectOneChoice...

<af:forEach begin="1"
end="#{bindings.SomeIterator.estimatedRowCount}"
var="priorityRow"
varStatus="priorityLoop">
<f:selectItem itemLabel="#{priorityLoop.index}"
itemValue="#{priorityLoop.index}"/>
</af:forEach>

...instead of using someting like the following...
<f:selectItems
value="#{SomeBackingBean.someHashMapProperty[bindings.SomeIterator.estimatedRowCount]}"/>

The use-case for this problem was a bit odd, but nothing too bad...

Sunday, August 23, 2009

af:menuBar selected style

If you want to use af:commandMenuItem inside an af:menuBar, with the af:commandMenuItem's selected property set to a particular value (true, false, EL), that is great. Just remember you cannot embed your af:commandMenuItem inside some other component and have this selected work...even if that other component is embedded inside an af:menuBar component. The CSS that is generated by the skin selector for the af:menuBar for this purpose is picky about how it wants to see things: td. a

Wednesday, August 19, 2009

speaking at NoVAJUG

If you live/work in Virginia, I will be be giving a preliminary viewing of my Oracle Open World presentation on JSF Custom Component basics.

Here is more info on the matter: http://novajug.wordpress.com/2009/08/19/sept-9-lets-make-some-jsf-custom-components-by-michael-a-fons/

Also here is the NoVAJUG website: http://novajug.org/

Tuesday, August 18, 2009

view links internal to sql statement

There is an esoteric aspect of links that I had not really experimented with until yesterday.

First know that it is possible to write a query/view object, that contains a bind variable in the query which is not defined in the list of bind variables in the view object itself.

Why would you want to do this?

What if you wanted (for speed reasons) to put a bind variable referencing a parent query column in a subquery of a query in the child view object?

Well, if you create a view link between the parent and child queries, ADF will automatically create a bind variable on behalf of the view-link with the name "Bind_. So if the parent was DeptView, and the child EmpView, and their connecting view link was DeptView.DeptNo = EmpView.DeptNo, then at run time this view link would create :Bind_DeptNo referenceable in the child query. So you could put this in a sub-query.

At the moment this still leaves the sometimes problem that you may have to have a connecting DeptNo in the child query select clause, but that is only a problem in some cases. This bit of flexibility can be good enough in many cases.

Also this may be a case where the problem is that I am not sure just how much more flexibility ADF/BC will allow. It is quite possible that you could connect these two queries based on bogus columns like select 1 bogus_columnn, ... from ... in both the parent and child, and then change the where clause in the view link to join on :Bind_DeptNo. Maybe it is even more flexible than that; I just am not sure at this time.

Tuesday, August 11, 2009

af:treeTable: getting at a clicked node

Hi.

I was working with an af:treeTable and its accompanying tree binding. I wanted to click a node to open it (if that node had sub nodes) and then automatically do something with the data in that node. I did not want to have to click on a link in the tree to identify the node.

Here is what I came up with:

public void onDisclosure(DisclosureEvent disclosureEvent) {
CoreTreeTable cmt = (CoreTreeTable)disclosureEvent.getSource();
PathSet ps = cmt.getTreeState();
Set ks = ps.getKeySet();
//ks.clear();
// The key-set is the set of addresses of keys that are open.
// Clearing it closes all that are open.

List rwKey = (List)cmt.getRowKey();
// The row-key is the address of the row that was just disclosed/clicked.
// It is a list of Strings, which contain 0-based numbers.
int depth = 0;
for (Object o1 : rwKey) {
ArrayList pathToAdd = new ArrayList();
for (int i = 0; i < depth + 1; i++) {
pathToAdd.add(rwKey.get(i));
}
//ks.add((Object)pathToAdd);
depth++;
}
// This for loop just added the address of the node clicked,
// to the set of "open" nodes. Along the way it also enters
// all the parent node addresses as well, creating a new
// array list to store the address for each ancestor as well as
// the node clicked.

// I want to get the node that was clicked. I should be able to
// use the row-key to traverse the tree model to get the node I want.
TreeModel lTreeModel = (TreeModel)cmt.getValue();
Object lRowData = null;
for (Object lRowKeyIndexObject : rwKey) {
// Can I assume I start out with the tree model looking at root
// node?
String lRowKeyIndexString = (String)lRowKeyIndexObject;
int lIndex = Integer.parseInt(lRowKeyIndexString);
if (lTreeModel.isRowAvailable(lIndex)) {
lRowData = lTreeModel.getRowData(lIndex);// JUCtrlHierNodeBinding
lTreeModel.setRowIndex(lIndex);
}
if (lTreeModel.isContainer()) {
lTreeModel.enterContainer();
}
}
// When the loop is over the tree model should be
// set to the level and row that was clicked.
// Also lRowData should be the row we care about...the
// clicked row.

// We do not have to reset. I think each request the tree model
// resets. Traversing the tree model does not affect the way
// the tree table renders or looks.

JUCtrlHierNodeBinding lNodeBinding = (JUCtrlHierNodeBinding)lRowData;
String lNodeContents = (String)lNodeBinding.getAttribute(1);
// Display the found node.
this.setLSelectedNodeString(lNodeContents);

// Next experiment. Create binding in query
// and a field that allows you to set this binding.
// See if when you open a node if it affects any others nodes
// or not.
}

Wednesday, July 22, 2009

tomahawk t:popup component

If you have to remember something about the t:popup component: remember this: if you use it on a af:commandLink (or some command component...something that submits) and you click on that component, you will get an error when your page reloads (due to postback), if you are running on IE 6 or 7. "...Operation aborted"

The cause of this error seems to be that you are trying to run javascript before the DOM is all the way loaded.

It also seems to mess up the wysiwyg editor in JDeveloper 10g, but I can kinda get used to that...for what this popup component brings to the tables. It allows you to hover over an element and get a popup which will stay open until you leave it. Or you can make the popup go away when when you leave the driving element.

Anyway...everything is peachy in IE 8 and in the latest version of Firefox. :-)

Tuesday, July 21, 2009

web.xml minutiae: SecurityContext.isUserInRole()

So...

If you are using Oracle SSO, iAS 10.1.4 infra, iAS 10.1.3.4 mid-tier, and running ADF on it, and Oracle Portal on another mid-tier...here is some information that may come in handy for you:

  1. In ADF if you use isUserInRole() method in the SecurityContext, you will need to bounce your 10.1.3 instance every time you make a change (or a set of changes) to the OID users and groups/roles. I imagine there is a way to get my 10.1.3 to refresh from the oid explicitly, but I have not figured it out yet.
  2. isUserInRole also expects that particular roles that you are testing to be listed in web.xml. So just because the user has the role in OID does not mean you can test for it successfully...you must first add it to web.xml.

:-)

Tuesday, July 14, 2009

Custom Components in JSF and af:iterator

I have something to report that I did not realize about custom UI components in JSF (lots of things probably...)

Consider the following scenario: you put a custom component in a af:iterator component. Can you answer the following questions?
  1. How many instances of your custom component that you included in that af:iterator loop will be created?
  2. If your component's function is to print a different kind of input field or widget depending on the parametric input given to the component tag, what might you need to do with any attributes in your component?

The answer to 1 is: one. One for each af:iterator. So if your iterator loop brings back 1000 records from the database, it loops 1000 times and "prints" your component 1000 times, but there is ever only one instance of the component.

For question 2...let us say that your component offers the printing of 4 different kinds of components depending on the value of its "type" tag attribute. So in that page you will have 1000 fields printed one for each af:iterator loop. If your component only rendered UIOutput components then it would suffice to have one property in your component class for each type of component.

But we are doing input components, so decode will be involved. That complicates things. JSF will generate a client id for each field that you generate with your component. If it is in the af:iterator loop it will look something like: formname:iteratorname:n:yourcomponentid -- where n is the zero-based loop index of your af:iterator.

On a JSF postback/decode, each field first runs the decode method. Then each field runs the encode methods for the component. In between the decode runs and the encode runs you need to store the submitted value of each component. I used a HashMap with client id as the key, and the component as the value. If you store everything away in decode you will have whatever you need to do the encode when it occurs for the postback.

Hope this helps someone.

Wednesday, July 8, 2009

af:iterator

I was trying to use af:forEach with a custom component I made. This custom component is a bit like the declarative components in ADF Faces Rich Client components, in that it renders different components depending on what type you send it. I was trying to pass a value binding through an attributes and then trying to evaluate the value of this in the component at encode time, but the af:forEach request scope "var" variable could not be evaluated by the property resolver. af:iterator, I am happy to say, for some reason did something different however so the "var" was more accessable to the child custom component.

There was another project also where af:forEach really was acting up, where I wish I had known about af:iterator.

The inspiration to try this component came from Duncan Mills blog entry http://groundside.com/blog/DuncanMills.php?blog=6&c=1&page=1&more=1&title=jsf_and_the_foreach_loop&tb=1&pb=1&disp=single