Thursday, April 22, 2010

JSF 2.0 exploration notes

As I embark along the path to learning JSF 2.0 from a having a fairly firm, intermediate grasp of JSF 1.1/1.2; I am following Burns and Schalk’s JSF 2.0: the complete reference. I got my current grasp of JSF in no small part from studying and referring to their book by the same name which pertained to JSF 1.1/1.2. In that former book they started you off doing the assembly of the deployable war by hand from the source code which they walked you through in the book in detail. The newer book starts similarly, except that the new book seems to rely on Maven to construct the war file. While I have maven installed on my machine, my lack of the downloadable pom file from the book’s on-line downloadable source code website, the book’s failure to spell out the pom file (probably due to size??) in the text of the book, the fact that I am on an airplane and unable to download anything, and my undeniable stubbornness – all these things add up me now assembling the exploded war directory by hand – according to the book’s documentation of what this exploded directory structure should look like and what it should contain. When I have this, I will use jar –c to build a war file because I just don’t have the patience to wait until I get off the plane to build my first JSF 2.0 program! I will have to go from memory and jar --help and experimentation to accomplish this. Wish me luck!
Some observations so far: jsf-api.jar and jsf-impl.jar seem to be all you need to compile a JSF 2.0 program (which does not use any external libraries). That is to say…no more standard.jar, or commons*.jar any more…which is not surprising, since JSF 2.0 is based on Facelets, and not JSP/JSTL etc. Also: no more faces-config.xml (if you don’t want to); you can go with all annotations if you want that.

After I installed java 1.6 JDK, set up the exploded directory copying the xhtml to the exploded directory’s root directory, copied the two jsf jars into the WEB-INF/lib and the source packages into the WEB-INF/classes directory of my exploded directory, and the web.xml file into my WEB-INF directory, I executed the following command:
javac -classpath ../../../../lib/jsf-api.jar;../../../../lib/jsf-impl.jar UserBean.java
…where UserBean.java is the book’s first sample class (backing bean/request-scoped-managed bean).
Then I went to the root directory of the exploded directory and executed the jar command to make the war:
C:\sandbox\jsf2-0book\personaltrainer\target\jsfreg>jar cvf jsfreg.war *
added manifest
adding: register.xhtml(in = 2690) (out= 730)(deflated 72%)
adding: WEB-INF/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/com/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/com/jsfcompref/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/com/jsfcompref/model/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/com/jsfcompref/model/UserBean.class(in = 2305) (out= 109
1)(deflated 52%)
adding: WEB-INF/classes/com/jsfcompref/model/UserBean.java(in = 2378) (out= 757)
(deflated 68%)
adding: WEB-INF/classes/com/jsfcompref/model/UserBean.java~(in = 2377) (out= 754
)(deflated 68%)
adding: WEB-INF/lib/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/lib/jsf-api.jar(in = 591845) (out= 530662)(deflated 10%)
adding: WEB-INF/lib/jsf-impl.jar(in = 1816536) (out= 1682891)(deflated 7%)
adding: WEB-INF/web.xml(in = 883) (out= 384)(deflated 56%)

C:\sandbox\jsf2-0book\personaltrainer\target\jsfreg>dir
Volume in drive C is SW_Preload
Volume Serial Number is B2D3-A76F

Directory of C:\sandbox\jsf2-0book\personaltrainer\target\jsfreg

03/05/2010 07:56 PM <dir> .
03/05/2010 07:56 PM <dir> ..
03/05/2010 07:56 PM 2,219,418 jsfreg.war
02/28/2010 07:37 PM 2,690 register.xhtml
03/05/2010 07:10 PM <dir> WEB-INF
2 File(s) 2,222,108 bytes
3 Dir(s) 111,780,872,192 bytes free

I am confident (grin) that this war file will deploy ok on the glass fish web server that I downloaded and have yet to try (at least after I correct all my typos) from copying the book’s code manually.)

Looks like I am already using port 8080, so I will need to ask glassfish nicely to use some other port as its default… (or Oracle XE…that seems to be the other user of this port number…). Oh well: the trip back.

3/14/2010 8:23:25 PM

OK, I finally got my own code going…that is to say…the code I tried to copy manually form chapter 1 I finally got to run on glassfish app server.

Apparently I had made a number of critical typos, which has interesting results. The most interesting of these was the mistakes I made in the web.xml file:
1. In the root element (web-app?) the xsi:schemaLocation attribute’s value has a couple of places in it where it should say “…/xml/…”. For some reason I had mistakenly typed “…/sml/…”. This letter difference was enough to confuse the html server for glass fish in to responding with a 404 code, saying that a “resource” was missing. Obviously that was not a very helpful error. Once I got through that however there was …
2. In the servlet-mapping element I had a sub-element defined called url-mapping. I should have called this sub-element url-pattern instead. This however kept deployment from happening properly.

After solving these errors, I had to correct three minor typos in register.xhtml, then things worked fine. These typos were mine, not the book’s – I am sure.

Anyway, as I was getting things in running condition, I remembered reading that I could deploy on glass fish as an exploded directory. I had done such a thing on weblogic server (when it was still bea weblogic (10.3 I think)). Up until trying to do this on glassfish, I had been using the jar command above to package things up as a jar in between changes. I got pretty quick at it, but not quick enough to compete with the speed of working on an exploded directory and just recompiling when necessary.

So basically I just deployed the root directory I had been jar-ing up, and it worked fine. I made a change or to to the xhtml files, and hit f5; then I saw the changes I had just made. Great!

Back to the book now for more information…

4/16/2010 7:26 PM

So some new things I have learned today about JSF 2.0:
1. On page 96 of [Burns] is a section called invoking arbitrary methods in EL. This means that, for instance, if you have a method that returns a string you can conjure up an expression like the following, and put it right in the middle of your page: #{myManagedBean.myMethod(someOtherManagedBean.property1, anotherManagedBean.property2)} (BTW: the caveat here really got my attention: this kind of invocation in EL is only available if your EE6 container is Java-based. I was not aware there were any other EE6 containers besides Java-based EE6 containers.)
2. …

I next want to talk about Facelets. I have made a stab or two at working with Facelets. Now that I am studying JSF 2.0, Facelets is the standard, not JSP any more

So in my first experiment, I took the files (the little registration program in chapter 3) and tried to use the templating concepts presented in Chapter 4 a reality; so I got the template file and template client file which references the template through the ui:composition tag. But when I start referencing the template instead of the full page I had in the register.xhtml page I get the following errors:

• Warning: This page calls for XML namespace http://www.w3c.org/1999/xhtml declared with prefix body but no taglibrary exists for that namespace.
• Warning: This page calls for XML namespace http://www.w3c.org/1999/xhtml declared with prefix title but no taglibrary exists for that namespace.
• Warning: This page calls for XML namespace http://www.w3c.org/1999/xhtml declared with prefix tr but no taglibrary exists for that namespace.
• Warning: This page calls for XML namespace http://www.w3c.org/1999/xhtml declared with prefix tr but no taglibrary exists for that namespace.
• Warning: This page calls for XML namespace http://www.w3c.org/1999/xhtml declared with prefix html but no taglibrary exists for that namespace.
• Warning: This page calls for XML namespace http://www.w3c.org/1999/xhtml declared with prefix td but no taglibrary exists for that namespace.
• Warning: This page calls for XML namespace http://www.w3c.org/1999/xhtml declared with prefix table but no taglibrary exists for that namespace.
• Warning: This page calls for XML namespace http://www.w3c.org/1999/xhtml declared with prefix h1 but no taglibrary exists for that namespace.
• Warning: This page calls for XML namespace http://www.w3c.org/1999/xhtml declared with prefix head but no taglibrary exists for that namespace.
• Warning: This page calls for XML namespace http://www.w3c.org/1999/xhtml declared with prefix meta but no taglibrary exists for that namespace.
Here is the error I made to cause that:
<html xmlns="http://www.w3c.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets">
Can you see it? I could not, but the error message kept driving me back to this line…here is how it is supposed to be:

<html xmlns=http://www.w3.org/1999/xhtml …

Now can you see it? I had to see a file that was working side by side to get it. I typed “w3c” instead of “w3”. I thought w3c was the name of the domain. Oh, well: live and learn.

Thursday, April 8, 2010

ADF/BC JDBC to retrieve structured data from packaged function

Got a request for code to show how to retrieve a collection of structured data (Oracle Type Objects) using JDBC in an ADF/BC scenario. The first parameter is the name of the Oracle Type that is the collection of your structured data type.

public Object callStoredFunctionReturningArrayOfRecords(String pfunctionReturnType, String stmt,Object[] bindVars) throws SQLException {
oracle.sql.STRUCT [] returnArray = null;
String [] recordArray = null;
Connection conn = getDBTransaction().createStatement(1).getConnection();
//Connection conn = getConnection();
// Now, declare a descriptor to associate the host array type with the
// array type in the database.


ArrayDescriptor arrayDescriptor=ArrayDescriptor.createDescriptor(pfunctionReturnType, conn);
// example:  StructDescriptor structDescriptor = StructDescriptor.createDescriptor("TEST_ARR_OF_REC_TYPE", conn);


// Create the ARRAY objects to associate the host array
// with the database array.


oracle.sql.ARRAY returnARRAY = new oracle.sql.ARRAY(arrayDescriptor,conn,returnArray);

OracleCallableStatement st = null;
try {
// 1. Create a JDBC CallabledStatement
st = (OracleCallableStatement)getDBTransaction().createCallableStatement(
"begin ? := " + stmt + ";end;", 0);


// 2. Register the first bind variable for the return value
st.registerOutParameter(1, OracleTypes.ARRAY, pfunctionReturnType);
if (bindVars != null) {
// 3. Loop over values for the bind variables passed in, if any
for (int z = 0; z < bindVars.length; z++) {
// 4. Set the value of user-supplied bind vars in the stmt
st.setObject(z + 2, bindVars[z]);
}
}
// 5. Set the value of user-supplied bind vars in the stmt
st.executeUpdate();
// Associate the returned arrays with the ARRAY objects.


returnARRAY = (oracle.sql.ARRAY)st.getARRAY(1);
// OracleResultSet mainRS = (OracleResultSet)st.getResultSet();
// ARRAY anotherARRAY = mainRS.getARRAY(1);


// Get the data back into the data arrays.
// NOTE: I got an NPE on the following line at one point...not sure why...
// I saw this error in opmn log; not sure if returnARRAY was null or
// if there are special rules about casting null into an array.
Object[] oarray = (Object[])returnARRAY.getArray();
// Object[] oarray = (Object[])anotherARRAY.getArray();


for (int i = 0; i < oarray.length; i++) {
oracle.sql.STRUCT struct = (oracle.sql.STRUCT)oarray[i];//new STRUCT(structDescriptor, conn, recordArray);
StructDescriptor structDescriptor = struct.getDescriptor();
ResultSetMetaData rsmd = structDescriptor.getMetaData();
Object [] attrs = struct.getAttributes();
if (rsmd != null && attrs != null && attrs[0] != null && attrs[1] != null) {
getLogger().fine("nested row [" + i + "]: " + rsmd.getColumnLabel(1) +
" " + attrs[0].toString() + " " + rsmd.getColumnLabel(2) +
" " + attrs[1].toString());
}
}
// 6. Return the value of the first bind variable
return oarray;
} catch (SQLException e) {
throw new JboException(e);
} finally {
if (st != null) {
try {
// 7. Close the statement
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}