Thursday, November 19, 2009

Fixing a little trouble with ADF dynamic menu model

I had to try to troubleshoot something I previously had working in another ADF application without a problem: declaratively-defined dynamic menus. I followed the example given in the 11.2 Using Dynamic Menus for Navigation section of the Oracle® Application Development Framework Developer's Guide
10g (10.1.3.1.0). When I launched my application to check the menus, I was greeted with the infamous 500 Internal Server Error. The exception was:

javax.faces.el.EvaluationException: javax.faces.FacesException: javax.faces.FacesException: Error performing conversion of value 'oracle.adf.view.faces.model.ChildPropertyTreeModel@e38fae' of type 'class oracle.adf.view.faces.model.ChildPropertyTreeModel' to type 'class my.MenuTreeModelAdapter' for managed bean 'menuModel'.

I looked through the whole stack trace for clues, but only the exception message had any glimmer of meaning. I looked at my Java classes and everything looked fine there, too. I poked through all the managed beans holding the pieces of the menu, but nothing jumped out at me.

So I went step by step through the article, comparing its XML and Java code to mine. I had everything in my components the article said to include. After about the fifth iteration of this, I finally started looking at things from a different viewpoint: what was in my code that wasn't in theirs?

Aha! I added a little too much information to one my menuModelAdapter beans. I specified the Java class for the instance property. The bean was supposed to return a ChildPropertyMenuModel object (injected as #{menuTreeModel.model}) and store it in the instance property of the menuModelAdapter object. I mistakenly entered the class as my menuTreeModelAdapter, telling the Faces servlet to convert it, instead of leaving it empty.



I removed the erroneously entered class, leaving the class unspecified, and it resolved my problem. Sometimes it pays to take a moment and look at things from another perspective.

Thursday, October 15, 2009

Upgrade JDeveloper 10.1.3.3 to work with Subversion 1.6

I wanted to upgrade my Subversion server and client to version 1.6, but what was holding me back was the fear that JDeveloper 10.1.3.3 would no longer be able to access my repository. When I finally got a block of time to play around with it, the mechanics of it turned out to be relatively easy.

The first step was to update my Subversion server and client. The client, unfortunately, is necessary because the JDeveloper interface is limited to basic version control operations. Even then, it doesn't support some necessary corrective actions as files are modified and moved around. I use HTTP as my transport protocol of choice, so see my previous post for how I made an easy task difficult by disengaging my brain :-P.

The next step was about as painless as it gets in the Oracle world - updating JDeveloper's Subversion extension. Thanks to Aino Andriessen's blog, Upgrade JDeveloper 10g Subversion client, on the AMIS Technology web site, I already had a blueprint of how to make JDev work with Subversion 1.5. The same works for 1.6. Since recent incarnations of JDeveloper rely on the SVNKit for its Subversion extension, I simply had to replace a few libraries.
  1. Make sure JDeveloper is shut down.
  2. Download the Standalone Version of SVNKit from the SVNKit web site. The latest version available when I got mine was 1.3.1.
  3. Extract the svnkit-javahl.jar and svnkit.jar files from the archive.
  4. Rename svnkit-javahl.jar to svnjavahl.jar.
  5. Copy the two JAR files to your JDeveloper extensions directory, [JDevRoot]/jdev/extensions/oracle.jdeveloper.subversion.10.1.3, replacing the existing files.
  6. Restart JDeveloper. If it starts without error, that's a good sign (see below).
  7. Open Tools->Preferences... then expand the Versioning->Subversion category to verify JDev recognized the new client libraries. Mine showed:


  8.   Subversion client:

        SVN/1.6.5 SVNKit/1.3.1 (http://svnkit.com.) r6109
That's all there is. Now you can access your updated repositories from within JDeveloper.

For what it's worth, I did run into a minor problem the first time. I forgot to copy the updated svnkit.jar. When I tried to start JDeveloper, it failed with an exception because a JavaHL function was trying to use one of the new classes in it that it obviously couldn't find. Copying both library files solved the problem. Here is the exception I got, with a bit of the stack trace:


java.lang.NoClassDefFoundError: org/tmatesoft/svn/core/internal/util/SVNHashMap

at org.tigris.subversion.javahl.JavaHLObjectFactory.<clinit>(JavaHLObjectFactory.java:69)

at org.tmatesoft.svn.core.javahl.SVNClientImpl$1.handleStatus(SVNClientImpl.java:170)

at org.tmatesoft.svn.core.internal.wc.SVNStatusEditor.sendUnversionedStatus(SVNStatusEditor.java:315)

at org.tmatesoft.svn.core.internal.wc.SVNStatusEditor.getDirStatus(SVNStatusEditor.java:189)

at org.tmatesoft.svn.core.internal.wc.SVNStatusEditor.closeEdit(SVNStatusEditor.java:114)

...

Wednesday, October 14, 2009

Updating to Subversion 1.6.5

I recently attempted to install version 1.6.5 of Subversion on my Solaris 10 server. Everything would have gone very smoothly, but one of my synapses misfired and took me on an unwelcome detour for a couple hours. When it was over, I was embarrassed, but instead of hiding my head in the screen, I put my (brief) story out here so you can learn from my mistake. The other reason is because the particular error I had to diagnose was almost non-existent in Internet searches.

Here was my situation: I had been using Subversion 1.4.5 for about a year or so, but it was growing long in the tooth and some of my development tool updates were looking for a more current version to work with. After doing a little research, I decided to plunge into the latest release of Subversion and get all my Subversion-aware tools updated.

My server ran Solaris 10, so I searched a favorite site, sunfreeware.com, to see if I could get a binary Subversion package and avoid the tedium of compiling it myself. I found it there and proceeded to check its dependencies on other packages. It required the latest, greatest Apache server 2.2.14. No big deal, I thought. OK, in addition to an Apache update, there were about ten other packages I had to replace first. I did that. So far, so good. Now grab Apache.

I was already running version 2.2.6, so I didn't need to change anything...well maybe a few things. I needed to make a backup of my customized files so I didn't overwrite anything. I tarred up my conf, htdocs, icons, lib, modules, and smf (Solaris service management facility files) directories and saved them to a place that wouldn't get lost. Now I downloaded the Apache 2.2.14 package and installed it. Everything was going smooth as silk. Now restore my customized files and install Subversion 1.6.5. Great. Fire it up.

Oops. Mistake! The new Apache came with a whole lot of new libraries and modules recompiled for the update. When I restored my customizations, I clobbered most of the new libraries and modules. When I attempted to start Apache, I was getting what I thought was a Subversion error. I had to dig into the startup log, in my case /var/svc/log/network-http:apache2.log. I found this message:


[ Oct 14 20:06:24 Executing start method ("/lib/svc/method/http-apache2 start") ]

httpd: Syntax error on line 526 of /usr/local/apache2/conf/httpd.conf: Syntax error on line 6 of /usr/local/www/conf/extra/httpd-subversion.conf: Cannot load /usr/local/www/modules/mod_dav_svn.so into server: ld.so.1: httpd: fatal: relocation error: file /usr/local/lib/libsvn_subr-1.so.0: symbol apr_memcache_getp: referenced symbol not found

[ Oct 14 20:06:24 Method "start" exited with status 1 ]



Really confusing, because the dynamic libraries it was complaining about were already installed. So why couldn't it find the missing symbol. I hunted through the Apache and Subversion web sites and found out the latest Apache also used the latest (within days) Apache Portable Runtime libraries. But they were supposed to be bundled with Apache. What was wrong?

"PEBCAK!" was my answer. When I restored my customizations I overwrote the new libraries with the ones I had from Apache 2.2.6, obliterating the functions required by the new Subversion (and eventually, Apache). Reinstalling the Apache 2.2.14 package and selectively restoring only my conf and htdocs directories fixed the error.

Just shows how casual thinking - Oh, look! A simple update! - can get you into trouble. If you found this post useful and it saved you some time, drop me a comment. I'd like to know my self-inflicted aggravation spared someone else's.

Some days it is best just to sit back, take a deep breath, and just laugh at yourself!

Thursday, August 13, 2009

How to Center an ADF Faces Table

I wanted to edit a web application page to center an ADF Table (<af:table> component). The table was very small, with only two columns, and I didn't need to modify any of the others in my application. The Table component has no attribute controlling how to align it when it is narrower than the displayed page. I could accomplish my goal by creating a custom skin, but that would just be overkill. The solution was so simple I almost didn't think of it.

Here are the steps:
  • Create your Table as you normally would.
  • Move the Table inside a PanelHorizontal (<af:panelhorizontal>) component.
  • Set the Halign attribute of the PanelHorizontal component to center.
Done! I wish everything were that easy.

Thursday, March 19, 2009

Using Apache Tomahawk with ADF Faces in JDeveloper 10.1.3

I was faced with a situation where it was necessary for me to allow a user to select multiple options from a rather large list of about 300 items. For an advanced user, a SelectManyListbox would have been an acceptable way to go. My target audience was unsophisticated, so the easiest input method for them was to use a SelectManyCheckbox input component. Sounds easy but, no, ADF Faces doesn't make things that easy.

The ADF Faces SelectManyCheckbox has the limitation of rendering its children either in one huge long vertical list or one huge long horizontal list. Either one is unattractive when you're dealing with more than just a few choices. What about a grid option? Well, the stock ADF Faces library doesn't give you that ability. Apache MyFaces Trinidad, the freely available JSF framework and successor to ADF, has some flexible components, but I wasn't ready to replace a working framework with something completely unknown to me. Fortunately there was another option: Apache MyFaces Tomahawk, an add-on components library compatible with MyFaces and, luckily for me, ADF Faces.

Tomahawk contains a SelectManyCheckbox component that extends the original. Several new attributes control the number of rows or columns to use when rendering the HTML controls, exactly what I needed for the new page of my project. Lucas Jellema, in his AMIS Technology Blog, has a similar article, Integrating ADF Faces and MyFaces Tomahawk - Creating a Popup with ADF Faces Shuttle Component, but using a different component and JSPX pages.

I followed very nearly the same integration steps, but mine differ slightly because of the JDeveloper and library versions I am using. For JDeveloper 10.1.3.3 and Tomahawk 1.1.8, here are the steps to installing and using the Tomahawk library:

1. Download the Tomahawk library. Use the Download Tomahawk link at the top of the page for the list of available packages. Select the regular Tomahawk (for JSF 1.1); it's really for JSF 1.2. Don't use link for JSF 1.2, as is actually for JSF 2.1 and won't work with JDeveloper.
2. Download the Apache Commons FileUpload library. Confusingly, the dependency information says Tomahawk is not dependent on any other project, but this refers to building, not using. The FileUpload library is required.
3. Extract the archived library files to your development libaries area. I used an Apache folder.
4. In JDeveloper, add the libraries and tag libraries.
    a. From the JDeveloper menu, select Tools > Manage Libraries... option.
    b. From the Libraries tab, press the New... button and add the main Tomahawk JAR file to the Class Path entry and JavaDoc and TLD Doc JAR files to the Doc Path entry. Put it into the User location.
    c. From the Libraries tab, press the New... button and add the main Commons FileUpload JAR file to the Class Path entry, the Sources JAR file to the Source Path entry, and the JavaDoc file to the Doc Path entry.
    d. From the JSP Tag Libraries tab, press the New button and select the main Tomahawk JAR file. The TLD file inside it will be automatically selected. The conventional prefix for use in your JSP source files is t (but you can name it what you want). Select the Execute Tags in JSP Visual Editor to integrate the library into JDeveloper's visual JSP editor. It doesn't render tags in the editor correctly, but will mess up viewing all your other pages if you don't select this option.
5. Optionally, configure the required MyFaces Extensions filter in your ViewController project WEB-INF/web.xml file. I added the following sections to mine, but eventually removed them so JDeveloper would render design views correctly. For some unexplained reason, adding this configuration will cause JDeveloper's design-time renderer to hemorrhage a pile of exceptions and prevent the design views from being displayed properly. You can get a little more detail in Oracle's JDeveloper forum.



  <filter>

    <filter-name>MyFacesExtensionsFilter</filter-name>

    <display-name>Apache Tomahawk Filter</display-name>

    <description>Set the size limit for uploaded files.

Format: 10 - 10 bytes

        10k - 10 KB

        10m - 10 MB

        1g - 1 GB

</description>

    <filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>

  </filter>



and


  <filter-mapping>

    <filter-name>MyFacesExtensionsFilter</filter-name>

    <servlet-name>Faces Servlet</servlet-name>

  </filter-mapping>

  <filter-mapping>

    <filter-name>MyFacesExtensionsFilter</filter-name>

    <url-pattern>/faces/myFacesExtensionsResource/*</url-pattern>

  </filter-mapping>




6. Add the taglib directive for the Tomahawk Tag Library to the top of your JSP page. You can do this manually by dropping the taglib component from the JSP component palette or JDeveloper will add it for you when you drop the first Tomahawk component on the page.
7. In your ViewController project Project Properties page, add the new libraries. Add the Tomahawk and Commons FileUpload libraries to the Libraries list and the Tomahawk tag library to the JSP Tag Libraries list.
8. Check your ViewController project WAR deployment profile. Make sure the necessary libraries are included in the WEB-INF/lib directory.

Now you should be able to use the Tomahawk components on your JSP pages. They may not render correctly in the visual JSP editor, but when running your web application, they should be fine.

Friday, March 13, 2009

Order of Security Constraints in web.xml for OC4J

In the course of testing and debugging one of my ADF applications, deployed to an OC4J instance of Oracle's Application Server 10g, the security settings I configured were not behaving as I expected. User accounts were authenticating properly, but failing authorization in some circumstances, making it appear as though the login failed. Finding the real cause was very frustrating because I never found a way to log what was actually happening.

I originally set up declarative J2EE security constraints to control access to certain pages, expecting the rules to be applied as specified in the Java Servlet 2.3 specification that requires URL-matching rules to be applied in a given order. It turns out that in OAS 10g, the container-based security provider is still based on an earlier version. Prior to the 2.3 specification, following the rules for authorization was only a suggestion rather than a requirement, and implementers were free to apply the rules as they saw fit. Unfortunately for me, Oracle has not updated this facet of their OC4J container to comply with the specification. Reordering my constraints solved my problem.

What happened? My application's welcome page is home.jsp. My original constraints had some overlapping URLs, specifically a couple pages that should have been accessible by everyone within a directory that was inaccessible to lower-level users. An example from my web.xml file showing pages secured by two roles, REPORTS (reports only) and USERS (everything else). The /faces/pages/home.jsp and /faces/pages/userprofile.jsp pages should be available, but resulted in a login error. Why? According to the way OC4J security implementation, /faces/pages/* is restricted to the USERS role only.



<security-constraint>
  <web-resource-collection>
    <web-resource-name>Users</web-resource-name>
    <url-pattern>/pages/*</url-pattern>
    <url-pattern>/faces/pages/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>USERS</role-name>
  </auth-constraint>
  <user-data-constraint>
    <transport-guarantee>NONE</transport-guarantee>
  </user-data-constraint>
</security-constraint>


<security-constraint>
  <web-resource-collection>
    <web-resource-name>Common</web-resource-name>
    <url-pattern>/common/*</url-pattern>
    <url-pattern>/faces/common/*</url-pattern>
    <url-pattern>/pages/home.jsp</url-pattern>
    <url-pattern>/faces/pages/home.jsp</url-pattern>
    <url-pattern>/menus/*</url-pattern>
    <url-pattern>/faces/menus/*</url-pattern>
    <url-pattern>/pages/userprofile.jsp</url-pattern>
    <url-pattern>/faces/pages/userprofile.jsp</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>USERS</role-name>
    <role-name>REPORTS</role-name>
  </auth-constraint>
</security-constraint>


When a REPORTS user tried to access /faces/pages/home.jsp, the user would actually be logged in, but because authorization to the page failed, the user was presented with the login form again and could never get to the page. To compound the problem, there were no errors in the application server's log file.

According to the specification, the /faces/pages/home.jsp should have been given precedence because it was an exact URL match. Since OC4J security isn't compliant with the specification, it relies on ordering instead.

My solution: by placing the REPORTS constraint first - and thus the exact URL - the security-constraint elements matched the /faces/pages/home.jsp URL first, allowing the REPORTS user to navigate to that page successfully.



<security-constraint>
  <web-resource-collection>
    <web-resource-name>Common</web-resource-name>
    <url-pattern>/common/*</url-pattern>
    <url-pattern>/faces/common/*</url-pattern>
    <url-pattern>/pages/home.jsp</url-pattern>
    <url-pattern>/faces/pages/home.jsp</url-pattern>
    <url-pattern>/menus/*</url-pattern>
    <url-pattern>/faces/menus/*</url-pattern>
    <url-pattern>/pages/userprofile.jsp</url-pattern>
    <url-pattern>/faces/pages/userprofile.jsp</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>USERS</role-name>
    <role-name>REPORTS</role-name>
  </auth-constraint>
</security-constraint>


<security-constraint>
  <web-resource-collection>
    <web-resource-name>Users</web-resource-name>
    <url-pattern>/pages/*</url-pattern>
    <url-pattern>/faces/pages/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>USERS</role-name>
  </auth-constraint>
  <user-data-constraint>
    <transport-guarantee>NONE</transport-guarantee>
  </user-data-constraint>
</security-constraint>


Simple fix, but hard to find. This was yet another example of extremely poor documentation for what is probably a very well-used operation. I hope this solves a mystery for someone else.

Introduction

Hello and welcome. After hundreds of days spent scouring books and the web for information that should have been easy to find, I decided to create this blog to share some of the things I've found out about how Oracle's Application Development Framework, Sun's Java Server Faces, and related technologies really work. I am continually appalled at the lack of accurate documentation regarding ADF, and its parents, JSF and JSP, in general. This is my way of helping to fix that problem.

I have spent innumerable hours hunting down some of these details. In a few cases, I have had to figure them out by trial and error, involving much cursing and gnashing of teeth. In an effort to spare others a little of the same agony I had to endure, and in no particular order, I offer to share my knowledge.

My search was certainly not an individual effort. If not for the likes of Chris Muir, Steve Muench, Duncan Mills, Avrom Roy-Faderman, John Stegeman, Lucas Jellema, and others, I might have given up on this technology as being too cumbersome, overly complicated, and impractical. A big round of "Thank You'ns" goes out to them and all who have shared their knowledge publically. In the Related Links list to the right are their blogs. I found them very valuable.