Tuesday, March 20, 2012

JSF 2 Navigation Pitfalls and Solutions

In this article I will present some cases where JSF 2 navigation will not work; in order the reader can avoid them.


JSF navigation works by first calling the action method (if defined), and from the outcome of the action, the JSF implementation decides which view to display. If there is no action method, a view id can be used directly (e.g.: "landingPage", the file name without extension).


1. Missing <h:form> tag


symptom: By pressing the button (or clicking the link), nothing happens. If there is a <h:messages> tag in the view, the following "cryptic" message is displayed: 


The form component needs to have a UIForm in its ancestry. Suggestion: enclose the necessary components within <h:form>


solution: Put the <h:commandButton> or <h:commandLink> inside a <h:form>
If the <h:commandButton> or <h:commandLink> component is outside of the <h:form>, or there is no <h:form> in the view, no form submit will be generated, so no navigation will occur (and the action method is also won't be called)


2. Missing EL brackets (#{})


Eclipse with JBoss Tools displays the action value with
underline and warning icon, if the EL brackets are missing




symptom: the page is redisplayed, but the action method is not called. If there is a <h:messages> tag in the view, the following error message appears: 


Unable to find matching navigation case with from-view-id '/navigation/page1.xhtml' for action 'navigation.navigateAction1()' with outcome 'navigation.navigateAction1()'


In this case, the button was defined as: 


<h:commandButton
            action="navigation.navigateAction1()"
            value="Missing EL brackets"
/>

solution: Put the action method reference between EL brackets.


note: In this case, the JSF implementation thinks, that what we defined as an action method, is a view id, but it doesn't find a file called "navigation.navigateAction1().xhtml".




3. "void" action method (navigation rule is defined in faces-config.xml)


symptom: The action method is called; page is redisplayed, but no navigation occur, no error message is displayed.


solution: change the action method to return anything (e.g.: a String)


This method:
// doesn't navigate because of void return value
public void doNotNavigateAction1() {
  logger.info("doNotNavigateAction1");
}
should be rewritten to return anything to enable navigation:

public String navigateAction1() {
  logger.info("navigateAction1");
  return "success";
}






4. action method returns null value

symptom: The action method is called; page is redisplayed, but no navigation occur, no error message is displayed.


solution: change the action method to return anything (e.g.: a String value), but not null.

note: This is by design, if the action method returns null, this means, that the previous page should be redisplayed.


Monday, March 19, 2012

Installing new instance of JBoss 7.1.1 with Oracle 10+ database driver and datasource

Installing new instance of JBoss 7.1.1 with Oracle 10+ database driver and datasource
While installing a new instance of JBoss AS 5.1 GA consisted of unzipping the zip file into a directory and copying the jdbc driver into the server's lib directory, installing JBoss AS 7.1.1 requires more work. The following steps describes how to install a new instace of JBoss AS 7.1.1 (and 7.1.0), configure the Oracle JDBC driver and set a datasource.
  1. Download the JBoss AS 7.1.1 from http://www.jboss.org/jbossas/downloads/
  2. Unzip the archive file to a directory (e.g.: D:\bin\jboss-as-7.1.1.Final)
  3. set JBOSS_HOME environmental variable to the unzipped directory (e.g.: "D:\bin\jboss-as-7.1.1.Final")
  4. Run <JBOSS_HOME>/bin/add-user.bat to create an administrator user to be able to log in into the administration interface
  5. Configure Oracle driver & Datasource:
    1. Create directory: <JBOSS_HOME>\modules\oracle\jdbc\main
    2. Download ojdbc6.jar from Oracle (http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html). Note: ojdbc14.jar was not recognized by JBoss 7.1.0 Final.
    3. Copy ojdbc6.jar into the <JBOSS_HOME>\modules\oracle\jdbc\main
    4. Create the file module.xml with the following content:
    5. <?xml version="1.0" encoding="UTF-8"?>
      <module xmlns="urn:jboss:module:1.0" name="oracle.jdbc"><resources><resource-root path="ojdbc6.jar"/>
          </resources>
          <dependencies>
              <module name="javax.api"/>
              <module name="javax.transaction.api"/>
          </dependencies>
      </module>
      
    6. Edit the <datasource> entry in "\standalone\configuration\standalone.xml", by adding the followings. (Change the _datasource_name_, _jdbc_conncection_url_, _schema_name_, _password_ strings to match to your environment. The datasource name will be referenced by the your application, e.g.: in the persistence.xml)
    7. <subsystem xmlns="urn:jboss:domain:datasources:1.0">
          <datasources>
       ...
       <datasource 
              jndi-name="java:jboss/datasources/_datasource_name_" 
              pool-name="_datasource_name_" 
              enabled="true" 
              use-java-context="true">
                  <connection-url>_jdbc_connection_url_</connection-url>
                  <driver>oracle</driver>
                  <security>
                      <user-name>_schema_name_</user-name>
                      <password>_password_</password>
                  </security>
              </datasource>
              <drivers>
                  <driver name="oracle" module="oracle.jdbc"/>
                            ...
                        </drivers>
          </datasources>
      </subsystem>