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.