So many technologies I want to study further: JSF 2.0, GWT, ADF Faces Rich Client component library, deployment of Java EE apps to phones and pda's, Scala, Wicket, Tapestry, Facelets, et cetera ad nausium.
...so little time. I wish we could learn like they did on the matrix :-)
Wednesday, October 28, 2009
Monday, October 19, 2009
Oracle Open World Aftermath
I definitely owe a blog entry at this point!
Just came back from Open World, and boy: is my brain tired!! (ba-dum-CRASH)
Anyway. I had a request that I make some specific entries on my blog from someone in the audience that came up to visit after my presentation.
He wanted to know how to do two things that I mentioned:
1. how to use the phase listener to get resource files in a custom component, and
2. how to use a renderer to divide up functionality.
These are somewhat meaty topics but I will try to be concise.
I. PhaseListener "magic"
If you have Schalk and Burns's
JavaServer Faces: the complete reference then just (re)read Chapter 11.
If you do not...here comes the paraphrase. The general idea is that you need to add a phase listener to your application in the normal manner: by adding a few lines to your faces-config.xml file. Note that if you have a custom component in JSF, then your jar has in it in its META-INF directory a faces-config.xml file, where you can reference this phase listener. JSF guarentees that this will be read first before the one in your application, I believe, provided this jar is in your WEB-INF/lib directory of your application.
Anyway you take your added phase listener, and make it listen for the RESTORE_VIEW phase by overriding the getPhaseId() method, and returning PhaseId.RESTORE_VIEW constant.
So let us say for example that your component has a need to have javascript code, that you want to keep in a sepparate file...because there is too much code to render on the html page itself (or you are a "tidy" individual). So your component will encode/render a javascript "include" (i.e.,<script src="somename" type="text/JavaScript"></script>
). So you encode this line onto the page. Then when this page is "interpreted", and issued as a request, your phaseListener can be ready. Your phaseListener has knowledge that at some point after the RESTORE_VIEW phase is complete, the FacesContext.getViewRoot().getViewId() will contain "somename". At that point, the phase listener can use getClass().getResource("somename's filename"), to get a url. This url can be connected-to and read from, an inputStream, then an inputStreamReader, then a BufferedReader. Meanwhile you open the outputWriter from the response on the FacesContext's ExternalContext, create an outputStreamWriter, then do a while loop reading lines from the buffered reader and writing lines to the outputStreamWriter, until there are no more lines to write. By the way the FacesContext is available from the PhaseEvent that your receive as a parameter. And with this FacesContext, you finish with a call to its responseComplete() method.
II. Renderer.
This is easier. If you have a custom component that has no renderer you can move your encode*() methods and decode() method to the a custom Renderer class. The main changes you will need to make are because you now no longer say "this" when you need to reference your component. In your new renderer class (which BTW extends "Renderer") the encode*() and decode methods receive your component as a parameter, so you much change your "this" references to use this parameter.
You must also augment the faces-config.xml, to have aelement with a sub-element which shows the family, type, and class of your renderer. Type can be anything, but whatever it is must now also be returned by getRendererType() overridden method in your tag handler class.
Also you will need to guard against receiving a null FacesContext or a null Component value for your parameters. This is in the spec so don't shoot me; I'm just the messenger.
Sir, I hope, whoever you said you were, that this blog entry, approaches meeting your custom-component writing needs or curiosities, or whatever drove your question. I bid you: good day!
I bid the same for the rest of you as well.
Just came back from Open World, and boy: is my brain tired!! (ba-dum-CRASH)
Anyway. I had a request that I make some specific entries on my blog from someone in the audience that came up to visit after my presentation.
He wanted to know how to do two things that I mentioned:
1. how to use the phase listener to get resource files in a custom component, and
2. how to use a renderer to divide up functionality.
These are somewhat meaty topics but I will try to be concise.
I. PhaseListener "magic"
If you have Schalk and Burns's
JavaServer Faces: the complete reference then just (re)read Chapter 11.
If you do not...here comes the paraphrase. The general idea is that you need to add a phase listener to your application in the normal manner: by adding a few lines to your faces-config.xml file. Note that if you have a custom component in JSF, then your jar has in it in its META-INF directory a faces-config.xml file, where you can reference this phase listener. JSF guarentees that this will be read first before the one in your application, I believe, provided this jar is in your WEB-INF/lib directory of your application.
Anyway you take your added phase listener, and make it listen for the RESTORE_VIEW phase by overriding the getPhaseId() method, and returning PhaseId.RESTORE_VIEW constant.
So let us say for example that your component has a need to have javascript code, that you want to keep in a sepparate file...because there is too much code to render on the html page itself (or you are a "tidy" individual). So your component will encode/render a javascript "include" (i.e.,<script src="somename" type="text/JavaScript"></script>
). So you encode this line onto the page. Then when this page is "interpreted", and issued as a request, your phaseListener can be ready. Your phaseListener has knowledge that at some point after the RESTORE_VIEW phase is complete, the FacesContext.getViewRoot().getViewId() will contain "somename". At that point, the phase listener can use getClass().getResource("somename's filename"), to get a url. This url can be connected-to and read from, an inputStream, then an inputStreamReader, then a BufferedReader. Meanwhile you open the outputWriter from the response on the FacesContext's ExternalContext, create an outputStreamWriter, then do a while loop reading lines from the buffered reader and writing lines to the outputStreamWriter, until there are no more lines to write. By the way the FacesContext is available from the PhaseEvent that your receive as a parameter. And with this FacesContext, you finish with a call to its responseComplete() method.
II. Renderer.
This is easier. If you have a custom component that has no renderer you can move your encode*() methods and decode() method to the a custom Renderer class. The main changes you will need to make are because you now no longer say "this" when you need to reference your component. In your new renderer class (which BTW extends "Renderer") the encode*() and decode methods receive your component as a parameter, so you much change your "this" references to use this parameter.
You must also augment the faces-config.xml, to have a
Also you will need to guard against receiving a null FacesContext or a null Component value for your parameters. This is in the spec so don't shoot me; I'm just the messenger.
Sir, I hope, whoever you said you were, that this blog entry, approaches meeting your custom-component writing needs or curiosities, or whatever drove your question. I bid you: good day!
I bid the same for the rest of you as well.
Labels:
JSF Custom Components,
PhaseListeners,
Renderers
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...
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...
JSF Custom Components
View more presentations from Michael Fons.
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...
...instead of using someting like the following...
The use-case for this problem was a bit odd, but nothing too bad...
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/
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.
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_
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.
Labels:
ADF/BC,
JDev 10g,
query bind variables,
ViewLink,
ViewObject
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:
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.
}
Labels:
ADF Faces 10g,
af:treeTable,
tree binding,
TreeModel
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. :-)
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:
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:
- 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.
- 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.
:-)
Subscribe to:
Posts (Atom)