UIX Developer's Guide
Go to Table of Contents
Contents
Go to previous page
Previous
Go to next page
Next

6. Handling Errors

A robust application always handles error conditions. Web applications present some interesting twists on error handling that you may not have encountered if you've only written more traditional client-server applications. This chapter tells how to handle errors during data binding and event handling, how to display those errors to the client, and how to use client-side validation to improve the user's experience.

This chapter contains the following sections:

Errors in Data Binding

UIX data binding presents an interesting problem for error handling. Data binding happens as the page renders. Values are retrieved only at the moment they are needed, and DataProviders are only asked for their DataObjects the first moment those DataObjects are needed. But once a line of HTML has been sent on its way across the internet, it's too late to get it back. You can no longer cleanly redirect to an error page, or render an elegant error section in place of the failed portion. Instead, you're forced to soldier on and finish the page as best you can. And it looks extremely unprofessional to dump a stack trace in the middle of a page, not to mention how much this may scare users!

This seems to imply a harsh fact about DataProviders, DataObjects, BoundValues, and all the other pieces of data binding code in your application. It would seem that none of these can ever fail - they've always got to return a valid result. Thankfully, this isn't exactly the case. There are plenty of alternatives.

A first choice: Catch, log and drop errors

The simplest option is always to do nothing. Catch the exception, log it to our ErrorLog API, and then drop it! For example:

  public class SimpleDataObject implements DataObject
  {
    public Object selectValue(RenderingContext context,
                              Object key)
    {
      try
      {
        // Try to get the value
        return _aMethodThatMayFail(context, key);
      }
      catch (SQLException sqle)
      {
        // Oh no - an error!  But just log it...
        context.getErrorLog().logError(sqle);
        // and return null.
        return null;
      }
    }
  }

If you're horrified by the thought of code like this, that's partly a good thing. It's always better to display an elegant error message to a user than to fail silently. Displaying blank cells or fields will confuse users or, even worse, lead them to submit the wrong data!

However, keeping all code up to these high standards is sometimes counterproductive. The more error cases you try to handle elegantly, the more error handling code you'll write. And error handling code is usually the least tested code in an application - and therefore it can be the buggiest code in an application!

There are already exceptions you're probably not handling. For example, do you always catch NullPointerExceptions? Such an exception means an unexpected event has happened. It'd be going overboard to design into your application how to present to the user not only expected errors - like a database connection that fails - but also the unexpected errors - like NullPointerExceptions or MissingResourceExceptions. It's difficult to decide where to draw that line, but choosing not to handle RuntimeExceptions is a reasonable choice.

You may wonder how UIX handles NullPointerExceptions and other RuntimeExceptions thrown by databinding code. We automatically catch all exceptions thrown by DataProviders and DataObjects, log the errors, and return null, just like the example above. Once the exception has reached our layer, this is the best and only alternative left.

Finally, remember that this error isn't altogether silently dropped - it is being logged on the servlet engine's error log. (The UIX error log will by default send messages and errors to the servlet engine's error log, but it can be replaced to use a different strategy). Even in a production application, you should be monitoring the log for errors. However, the errors are invisible to the user, which can mean they have no visible indication that anything's gone wrong.

A second choice: Catch, log, and mark errors

The major problem with the first technique is that the user gets no feedback when an error happens. They may see curiously empty tables or fields without any hints that something went wrong. A simple modification of the first technique solves this problem. As soon as an error happens, instead of just logging it, store the error and support returning the error from the data. For example, take the following UIX:

  <dataScope>
    <!-- Get some data -->
    <provider>
      <data name="dataForTable">...</data>
    </provider>
    <contents>
      <!-- Put the data in a table -->
      <table>...</table>
    </contents>
  </dataScope>

Now, let's add an extra piece after the table:

     ...
    <contents>
      <!-- Put the data in a table -->
      <table>...</table>
   
      <!-- And warn the user of an error if one happened, -->
      <header messageType="error" data:rendered="error@dataForTable">
        <contents>
           An error occurred:
          <styledText data:text="exception@dataForTable"/>
      </header>
    </contents>
     ...

This bit of UIX adds an error message. It's rendered only if the magic "error" flag is somehow set. (See Dynamic Structure for UIX Pages for more information on the "rendered" attribute.) Then it shows the exception - you could present friendlier output if you wished. Now, how to update the data source to support this?

  public class SimpleDataObject2 implements DataObject
  {
    public Object selectValue(RenderingContext context,
                              Object key)
    {
      // Have we encountered an error yet?
      if ("error".equals(key))
      {
        return (_exception == null) ? Boolean.FALSE : Boolean.TRUE;
      }
      // What exception have we seen?
      else if ("exception".equals(key))
      {
        if (_exception == null) return null;
        return _exception.toString();
      }

      try
      {
        // Try to get the value
        return _aMethodThatMayFail(context, key);
      }
      catch (SQLException sqle)
      {
        // Oh no - an error!  But log it...
        context.getErrorLog().logError(sqle);

        // ...store it...
        _exception = sqle;

        // and return null.
        return null;
      }
    }

    // Cached exception
    private Exception _exception;
  }

This is a lot like the previous example, but we don't just throw away exceptions after logging them - they're also stored away for later use. We also add two new keys to our DataObject that expose this error state.

This strategy works fairly well. It has extremely low overhead when there aren't errors and lets users know when errors have occurred. On the downside, the user still sees potentially incorrect data and may have to scroll far down the page to notice the error, and you've put error handling code into each DataObject. You can solve this last issue and make the error storing code generic, but the user's problems are inherent to this technique.

A final piece of advice if you're using this strategy: the block of UIX that renders the error is a perfect candidate for wrapping up in a UIX template - see UIX Includes and Templating for more information on templates.

A third choice: Get everything up front

If you want to show a databinding error at the top of a page or the top of a section - that is, before the data is actually used - you've got two choices. First, you can get all the pieces of data in one pass, so that there's no chances of failure in the middle of rendering. We'll consider this first option here, and leave the second option for the next section.

Let's show how this works with a UIX <method> element (or the Java MethodDataProvider class). We'll define a method that tries to get the data, but if it fails, it instead returns a simple DataObject that just contains error codes:

import oracle.cabo.ui.data.DictionaryData;

...

  static public DataObject getResultSet(
    RenderingContext context, String namespace, String name)
  {
    DictionaryData data = new DictionaryData();
    try
    {
      
      ResultSet result = _getJDBCResultSet(...);

      data.put("ename", result.getObject("ENAME"));
      data.put("id", result.getObject("ID");
      data.put("manager", result.getObject("MANAGER");
      // .. etc...
      // And mark that we didn't have any errors
      data.put("errors", "no");
    }
    catch (SQLException sqle)
    {
      // No - an error.  Mark the error case, store 
      // the exception, and return.
      data.put("errors", "yes");
      data.put("exception", sqle.toString());
    }

    return data;
  }

Stepping through this code, we can see that it:

  1. Creates a DictionaryData. This class is a crude but simple way to store a small, fixed set of data - and it never throws an exception.
  2. Tries to get the JDBC ResultSet - if it succeeds, it:
    1. Copies each value out of the result set.
    2. If each value is retrieved successfully, stores "no" at the "errors" key; we'll use this in our UI to render the "there-weren't-any-errors" UI.
  3. But if it fails at any time, it:
    1. Stores "yes" at the "errors" key; we'll use this in our UI to render the "yes-there-were-errors" UI.
    2. Stores the text of the exception - as above, a better UI is possible.

Now, here's the UI that uses this data:

 <dataScope>
   <provider>
     <!-- Get the result set.  Note that this _is not_ enough 
           to trigger actually calling getResultSet();  that won't
           happen until we try to access a piece of the result -->
     <data name="resultSet">
       <method class="...." method="getResultSet"/>
     </data>
   </provider>
   <contents>
     <!-- Now: did we have an error?  Ask for the "errors" key
              first - this will at last trigger the call to
              getResultSet(), which will get all of the data and
              set the "errors" key. -->
     <switcher data:childName="errors@resultSet">
       <case name="no">
         <!-- No errors: show the result set -->
         <labeledFieldLayout>
           <contents>
             <messageStyledText name="id" prompt="Employee ID:"
                                data:text="id@resultSet"/>
             <messageTextInput name="ename" prompt="Employee name:"
                                data:text="ename@resultSet"/>
           </contents>
         </labeledFieldLayout>
       </case>
       <case name="yes">
         <!-- An error.  Show the exception -->
         <header messageType="error">
           <contents>
             <styledText data:text="exception@resultSet"/>
           </contents>
         </header>
       </case>
     </switcher>
   </contents>
 </dataScope>

There's a good bit of UIX here. Let's walk through it.

  1. First, we load up the data provider:
         <data name="resultSet">
           <method class="...." method="getResultSet"/>
         </data>
    The key point to remember here is that merely referencing a data provider does not load the data. That won't happen until a piece of data is requested from that provider.
  2. Now, we start rendering the content with a bean you probably haven't seen yet: <switcher>. (The Java equivalent is the SwitcherBean). Dynamic Structure for UIX Pages describes this in more detail; but for now, just note that it switches between any number of cases based on a childName string attribute:
         <switcher data:childName="errors@resultSet">
           <case name="no">
             ...       
           </case>        
           <case name="yes">
             ...       
           </case>
         </switcher>
    Here, we've used the "errors" key to drive the "childName" attribute. As you may remember, this key is set to "no" when we get all the data successfully, and set to "yes" when there's an error.
  3. The rest of the example, the UIX inside of each <case>, is nothing you haven't seen before. When there's an error, we show an error message. Otherwise, we show the results as expected.

(Though we used a DataProvider to show off this strategy, you can still use it even if you're just writing a DataObject. It's just easier with DataProviders. Also, you don't have to copy each bit of data into a DictionaryData - the only important rule of this strategy is that all requests after the first must succeed completely.)

This choice does give you the best of all worlds for output. When there's an error, the output is cut off immediately, and the user immediately sees an error message. But there's a cost to your development time and to your application performance. Your Java code is forced to get every bit of data up front, even if it only needs one or two small pieces. Even worse, you've forced yourself to write a list of all the pieces of information this code can ever create and to keep that list up to date. That's a maintenance headache, and writing this kind of code is tedious.

A fourth choice: The TryBean and output buffering

All of these choices so far require adding extra intelligence to all of your DataProviders and DataObjects. It'd be much easier if those could be left alone, and instead we could put the responsibility for error handling into the UIX framework itself. We have a bean that makes this much easier: the <try> element, and its Java counterpart, the TryBean.

Instead of forcing your data provider to handle error conditions, you simply add a <try> element around the section. Let's write a DataProvider that always fails:

  static public DataObject throwException(
    RenderingContext context,
    String        namespaceURI,
    String        name) throws Exception
  {
    throw new java.sql.SQLException("Big problem");
  }

And now, some UIX that uses this.

 <try>
   <contents>
     <dataScope>
       <provider>
         <data name="noGood">
           <method class="..." method="throwException"/>
         </data>
       </provider>
       <contents>
         <text text="This won't work: "/>
         <text data:text="notAChance@noGood"/>
       </contents>
     </dataScope>
   </contents>
 </try>

Run this example, and you'll see... nothing. When we enter a <try>, we immediately start buffering the output. Instead of sending bytes directly off to the network, they're stored in a buffer. If the section finishes without errors, the buffer is immediately flushed and sent to the network. (Unless, that is, the<try> is itself inside of another <try> - we support nesting.) But if an error occurs, the entire section is dropped.

If you do want to let the user in on the error (usually a good idea), <try> supports a <catch> section. It also stores the error object as a property on the RenderingContext, so you can use it in your error message. Here's a UIX example complete with the <catch> section:

 <try>
   <contents>
     <dataScope>
       <provider>
         <data name="noGood">
           <method class="..." method="throwException"/>
         </data>
       </provider>
       <contents>
         <text text="This won't work: "/>
         <text data:text="notAChance@noGood"/>
       </contents>
     </dataScope>
   </contents>
   <!-- Catch the error if it happens -->
   <catch>
     <header messageType="error">
       <!-- And for the text of the error message, just show
                the exception that caused it -->
       <boundAttribute name="text">
         <contextProperty select="ui:currentThrowable"/>
       </boundAttribute>
     </header>
   </catch>
 </try>

Note how we got the Throwable at the "ui:currentThrowable" key on the rendering context. This is where the <try> bean stores the error. From Java, you'll be able to access the error with the following code:

  import oracle.cabo.ui.UIConstants;

  ...
  RenderingContext ctxt = ...;
  Throwable error = (Throwable)
    ctxt.getProperty(UIConstants.MARLIN_NAMESPACE,
                     UIConstants.CURRENT_THROWABLE_PROPERTY);

To make it easier to show errors, UIX provides a <displayException> element that can be used inside of <catch>. In addition to showing the type of exception and the exception's message (which is all you get with the previous example), you'll also get a stack trace:

 <try>
   <contents>
     <!-- etc. -->
   </contents>
   <!-- Catch the error if it happens -->
   <catch>
     <displayException/>
   </catch>
 </try>

This buffering is closely akin to what JSPs are already doing today, and why developers used to JSPs may not have been exposed to this problem in web applications. The problem with the built-in JSP solution is that it's all or nothing: either you buffer the entire page, or you buffer none of it. There's no simple way to selectively buffer portions of a page. (The JSP 1.2 specification includes a TryCatchFinally tag interface that would let you address this problem with a custom tag; the UIX solution works with all versions.) And if you're buffering the entire page, the user has to wait until the entire page is generated before a single byte is even sent across the web, much less displayed on their browser. Selective buffering lets you send results as soon as they're completed.

So, why not always use <try>? It's certainly much simpler to add this to a pre-existing page than any of the other approaches - except for, of course, ignoring the errors altogether. The most significant downside of <try> is efficiency. It's faster not to buffer output unnecessarily. So, always buffering the entire contents of all pages is a waste of time. Be selective with <try> - wrap it around a <table> or a group of form elements. But not too selective! Don't use it around each individual form element - there's a cost to turning on and off buffering.

A second disadvantage is that a single error will discard all of the output inside the <try>. Usually, that's a good thing - no output is better than wrong output! But this missing output can make it difficult to identify problems, especially if you don't include a <catch> section or don't have access to the error log. This is more of an issue at development time than for users.

The TryBean: A slight hitch

If you start writing BoundValues, DataObjects, and DataProviders to take advantage of TryBean, you'll likely run right into a roadblock. None of these interfaces actually let you throw any exceptions! Java methods always let you throw subclasses of RuntimeException, but you can't throw IOException, SQLException, SAXException, or any other real exception you're likely to encounter! In retrospect, our design of these APIs may have been a mistake; it would have been much simpler to allow these methods to throw any exception. But, in the meantime, you'll need a way out.

The solution is the UnhandledException class, in the oracle.bali.share.util package. It's a subclass of RuntimeException, so it can be thrown from any piece of code. And it can wrap any Throwable or Exception passed to its constructor. A quick example of a DataObject may help explain:

Example:

  public class SomeDataObject implements DataObject
  {
    public Object selectValue(RenderingContext context, Object key)
    {
      try
      {
        ...
        Try to get the data...
        ...        
      }
      catch (SQLException sqle)
      {
        // We can't throw a SQLException from a DataObject.  But
        // we can throw an UnhandledException!
        throw new UnhandledException(sqle);
      }
    }
  }

You may be curious how a DataProvider example we gave above was able to throw a SQLException. We bend the rules xfor DataProviders accessed via the <method> element. Because such DataProviders don't actually implement the interface, they're free to throw any exception as long as it's in their method's throws declaration.

Summary

You've seen a variety of options for handling databinding problems. Because there's so many options, it's difficult to describe a one-size-fits-all strategy. Some of the decisions may depend on your personal preferences as a developer. But, a sensible and simple strategy might be to use a combination of <try> and "doing nothing":

Of course, relying on <try> is no substitute for writing robust code! No matter what error handling code you have in place, your first priority should always be producing fewer errors to begin with.

Errors in Event Handling

Handling errors in event handling is thankfully a much simpler task. Since you haven't produced any output yet, you're free to respond in any way you see fit. In general, there's two options: go to a generic error page, or display "inline errors". "Inline errors" are used to show user errors in the same page as the content, and we'll talk about how to handle those in the next section.

Many errors in event handling are unpredictable: a database refuses a connection, a query fails, or the server is out of memory. None of these are expected errors, and there's no way a user can fix the problem. It's best to simply show the user a simple error page letting them know what happened, and this is simple with the UIX Controller.

First, remember that your event handlers are free to throw any exception at all. This shouldn't be an excuse to not handle any errors. Some errors should always be caught and handled elegantly, like a NumberFormatException thrown when your users don't enter numbers correctly. But when you do encounter an exception that can't be handled well, simply let it escape out of your EventHandler.

When an exception is thrown, the UIX Controller will call the PageBroker.renderError(BajaContext, Throwable) method. That method will, by default, take the following steps:

  1. Save the Throwable as a ServletRequest attribute at the "oracle.cabo.servlet.eventError" key.
  2. Get the error page, if one is set, and ask it to render.
  3. If no error page is set, log the error and send an HTTP error message.

The error page can be set either by calling setErrorPage() or with the oracle.cabo.servlet.errorPage servlet configuration parameter, so they can be retrieved at any time.

Displaying Errors

When you want to display errors, you have to describe them. UIX has a regular format for these descriptions: the MessageData class. The MessageData API allows your event handlers to describe multiple errors for a single page, and specify how those errors match up to components in a page. Within your user interface, the <messageBox> summarizes the errors, and UIX's inline messaging components let you display those errors inline with your components.

Describing errors: MessageData

The MessageData class is a special version of DataObject that makes it much easier to put server-side error messages into your pages.

A single MessageData object gathers up a list of any number of messages. You'll create a MessageData object and add each message in succession, then use that MessageData for rendering.

Each individual message can either be page-level, if it applies to the total contents of the page ("The username and password combination you entered is incorrect") or component-level, if it applies only to a single component message ("The date must be after today."). Each message contains the following pieces on information:

Example:

The following example builds up a series of page-level error messages in response to a SQLException:

  static public MessageData getMessages(SQLException exception)
  {
    MessageData msgs = new MessageData();
    
    while (exception != null)
    {
      // Create a title and get the message
      String title = "ORA-" + exception.getErrorCode();
      String message = exception.getLocalizedMessage();

      // Add the message
      msgs.addError(null,    // null select - a page-level error
                    message, // the error message
                    null,    // description URL - only for component-level
                    title,   // the error title
                    null);   // message description - let it default to the
                             //   message itself
      // And now go to the next exception in the chain.
      exception = exception.getNextException();
    }

    return msgs;
  }

The MessageData class has many more convenience methods that let you add errors, warnings, and informational messages; this example used only one. See its API documentation for more information.

It's an important point to make here that this class and all the other related classes and elements are just conveniences. This is all standard databinding, and not especially complicated databinding at that! Still, we recommend that you use MessageData and the UIX elements you'll see shortly, since they'll keep you from making accidental errors.

Once you've created the MessageData object, you have to get it into the page. You can do this with ordinary databinding techniques, like the UIX <method> element. But if you are in a UIX Controller event handler, there's a much easier way. Event handlers have a shortcut for passing DataProviders from the event handler into your page, and MessageDatas have a convenience method for turning themselves into DataProviders. Let's see this in action:

  // An EventHandler that may produce an error
  static public EventResult doSomething(
    BajaContext context,
    Page        page,
    PageEvent   event)
  {
    try
    {
      // .... Do the usual stuff ....
      return ...;
    }
    // An error!
    catch (SQLException sqle)
    {
      // Turn the exception into a MessageData object
      MessageData msgs = getMessages(sqle);

      DataProvider provider = msgs.toDataProvider();

      UIEventResult result = new UIEventResult();
      result.setDataProvider(provider);
 
      return result;
    }
  }

Let's quickly walk through this example. We'll skip over the standard code for all event handlers, and focus on the catch section.

Summarizing errors: MessageBoxBean

The <messageBox> XML element and the MessageBoxBean Java class are used to show a summary of all the messages for a page.

In most cases, you'll only need to set a single attribute on this bean: "automatic". When "automatic" is set to "true" (in Java, MessageBoxBean.setAutomatic(true)), the <messageBox> enters automatic mode. It will automatically look for a MessageData instance at the default location. If it doesn't find one, it renders nothing at all (as per our current UI specification). When one is available, it writes out each message inside the correct bit of content.

The only other feature that will be used commonly is the "message" attribute (setMessage() method). This method lets you set the main message for the entire box. MessageData also supports a setMessage() method, and in "automatic" mode, the message box will pull its message from the MessageData.

UIX Example:

<messageBox> is trivial to use from UIX:

 <pageLayout>
   <messages>
     <!-- A message box belongs at the top of the page's content -->
     <messageBox automatic="true"/>
   </messages>
   <contents>
     <!-- and then follows the rest of the page -->
   </contents>
 </pageLayout>

Note that the <messageBox> was added inside the special <messages> element: this will place the messages in the correct location for your look-and-feel. It's entirely legal to place <messageBox> anywhere on your page, but if you're using <pageLayout>, this is the correct location.

<messageBox> has several other attributes that are less frequently used. For example, you can override the namespace and name where it will search for the MessageData, but as we said above, it's much easier to just use the default.

It's possible to use the <messageBox> out of automatic mode for purposes other than showing error or warning messages. You'll need to add messages explicitly, and set the message type, and title. For example, <messageBox> is used on confirmation pages ("Are you sure you want to delete this file?"). The special messageType value of "confirmation" (UIConstants.MESSAGE_TYPE_CONFIRMATION from Java) gives you the correct look for this use.

Displaying inline errors: the message beans

A major feature of the UIX renderers and the user interface specification they implement is inline messaging. Some web pages display all the errors in a big clump at the top and force the user to figure out which field they need to change to fix each error. UIX solves this usability problem by letting you display errors inline with the input controls that caused the problems.

The component central to this interface is the <inlineMessage> XML element (the InlineMessageBean) in Java). Usually, it just displays a prompt in front of some other control:

Picture of a messageTextInput without errors

But when an error is attached, the component automatically expands to show an error message and icons:

Picture of a messageTextInput with errors

Here's the UIX for the <inlineMessage> shown in both of these two pictures:

 <inlineMessage prompt="Old password:">
   <contents>
     <textInput name="pwd" secret="true"/>
   </contents>

   <boundMessage select="pwdError"/>
 </inlineMessage>

There's nothing very tricky here. The "prompt" attribute sets up the "Password:" on the left side, then the <textInput> inside is responsible for that input field. These may be new elements, but there's nothing conceptually new about them. The only element that's really new is the <boundMessage> element.

The <boundMessage> element is what sets up all the databinding magic that supports the user interface side of MessageData. It databinds five of the attributes of an InlineMessageBean to get their values from a single MessageData. If the "select" attribute of <boundMessage>matches the select value on one of the messages added to the MessageData object, the message appears next to the component, an icon appears, and more. If it doesn't match anything in MessageData, the inlineMessage renders directly.

From Java, this functionality is achieved with the MessageData.bindNode() method:

  InlineMessageBean imb = ....;
  // Attach this node to the "pwdError" message
  MessageData.bindNode(imb, "pwdError");

Laying out message beans

The moment you try putting two <inlineMessage> elements one after the other, you'll notice something's not right:

 <inlineMessage prompt="Your username:">
   <contents>
     <textInput name="user"/>
   </contents>
 </inlineMessage>
 <inlineMessage prompt="Password:">
   <contents>
     <textInput name="pwd" secret="true"/>
   </contents>
 </inlineMessage>

The two <textInput> elements didn't line up at all. To make them line up, you have to put the two inside one of a couple layout components, either <tableLayout> or <labeledFieldLayout>. Check out the documentation of these components for information on their usage.

Convenience message beans

It's extremely common to use inline messaging around form elements. Because of this, we've added a number of convenience elements that join the features of <inlineMessage> with the features of another element. For example, the <messageTextInput> element acts as a combination of an <inlineMessage> with a <textInput>. The following two pieces of UIX are functionally identical:

 <inlineMessage prompt="Username:">
   <contents>
     <textInput name="user"/>
   </contents>
   <boundMessage select="userMsg"/>
 </inlineMessage>

...and:

 <messageTextInput name="user" prompt="Username:">
   <boundMessage select="userMsg"/>
 </messageTextInput>

Note in particular that both versions support the <boundMessage> syntax. Other convenience elements include:

These are all handy, but keep in mind that they're simply conveniences. If you need inline messaging around a component not listed here, just wrap it in an <inlineMessage>. These conveniences are also available with our Java API - MessageTextInputBean, MessageCheckBox, etc.

A complete example: entering a new password

With these pieces explained, let's walk through a full example. We'll define a page for changing a password, using three fields:

  1. The current password
  2. A new password
  3. The new password again, for confirmation

We'll check for several error conditions in an event handler, and redisplay the page with inline messages if any fail.

First, the UIX:

<page xmlns="http://xmlns.oracle.com/uix/controller"
      xmlns:ctrl="http://xmlns.oracle.com/uix/controller">
 <content>
   <form xmlns="http://xmlns.oracle.com/uix/ui"
          name="default" method="post">
     <contents>
       <pageLayout>
         <contents>
           <messageBox automatic="true"/>
           <labeledFieldLayout>
             <contents>
               <messageTextInput prompt="Old password:"
                                  name="old" secret="true">
                 <boundMessage select="oldError"/>
               </messageTextInput>

               <messageTextInput prompt="New password:"
                                  name="new" secret="true"
                          tip="Passwords must be between 4 and 12 characters">
                 <boundMessage select="newError"/>
               </messageTextInput>
   
               <messageTextInput prompt="Confirm:"
                                  name="confirm" secret="true"/>
             </contents>
           </labeledFieldLayout>
         </contents>

         <contentFooter>
           <submitButton text="Submit" ctrl:event="newPassword"/>
         </contentFooter>
       </pageLayout>
     </contents>
   </form>
 </content>

 <handlers>
   <event name="newPassword">
     <method class="oracle.cabo.doc.demo.PasswordDemo"
              method="handleNewPassword"/>
   </event>
 </handlers>
</page>

The contents are largely self-explanatory. We've added a <form> and <submitButton> to send the entered results, and two of the three <messageTextInput> elements are bound to messaging. We've also put a <messageBox> at the top of the content. Note that nothing in this page needs to describe the types of errors that may occur, or have any reference to the business logic of the page. This is as it should be!

Now, the source code for handling the event. We've stripped out any real password checking code; the old password is hardcoded, and the new password isn't saved anywhere. But the messaging code is all there:

  static public EventResult handleNewPassword(
    BajaContext   context,
    Page          page,
    PageEvent     event) throws Throwable
  {
    MessageData messages = new MessageData();
    
    // Get all three parameters
    String oldPassword = event.getParameter("old");
    String newPassword = event.getParameter("new");
    // Safeguard against null values.  Always check parameters
    if (newPassword == null)
      newPassword = "";
    String confirm = event.getParameter("confirm");

    if (!"abcd".equals(oldPassword))
      messages.addError("oldError",
                        "The old password was not correct (try abcd)",
                        null,
                        "Old password",
                        null
                        );

    if (!newPassword.equals(confirm))
      messages.addError(null,
                        "The two values for the new password didn't match.",
                        null,
                        "Error",
                        null);

    if ((newPassword.length() < 4) ||
        (newPassword.length() > 12))
      messages.addError("newError",
                        "Passwords must be between 4 and 12 characters long",
                        null,
                        "Password length",
                        null);

    // Are there any error messages yet?  If not, then all is good,
    // and move on to the success page.
    if (messages.getLength() == 0)
    {
      // A real application would store the new password here!
      return new EventResult(new Page(page, "success"));
    }
    else
    {
      UIEventResult result = new UIEventResult();
      result.setDataProvider(messages.toDataProvider());
      return result;
    }
  }

This code is also pretty self-explanatory or just a repetition of pieces you've seen before. We check that the old password is correct, that the new password is between 4 and 12 characters, and that the "new" and "confirm" fields match, to be sure that the user didn't mistype the password. Any problems add a message to the list; if there's any messages, we return to the current page and display some errors. Otherwise, we move on. Pretty simple stuff!

Extra features of the message beans

Before moving on, let's learn about a few of the extra features of message beans.

All message beans support a "tip" attribute. This adds a piece of text that guides users in how to use this field. It'll still be visible when an error is displayed, so use it for helpful information that's always useful. The most common example is text that explains the correct format or values:

   <messageDateField prompt="Date:" name="date"
                      tip="DD/MM/YYYY"/>

The message beans also all support a required attribute. We'll go into more detail about the allowed values of required later in this chapter and what those values mean. From the perspective of the message beans, this simply indicates whether we should show an icon to tell the user he must enter a value:

   <inlineMessage prompt="Username:" required="yes">
     <contents>
       <textInput name="user"/>
     </contents>
   </inlineMessage>

The message beans also all support an <end> child element (and a setEnd() method in Java). This element will be added at the end (generally on the right) of the contents:

   <messageTextInput prompt="Username:" name="user">
     <end>
       <button text="Press Me" onClick="alert('Boo!')"/>
     </end>
   </messageTextInput>

<messagePrompt> and <messageText>

One last item before moving on! In some circumstances, the layout of the message beans may be too confining, and may prevent you from lining up items as you would want. For these cases, you can arrange just the slices of the message beans you need with two special components: <messagePrompt> and <messageText>, or in Java the MessagePromptBean and MessageTextBean.

The <messagePrompt> displays just the prompt, the required icon, and any error icons. The <messageText> displays the error message and any tip. Both support the <boundMessage> element (and MessageData.bindNode()), and you'll generally bind the two to the same error message. In the following example, we've broken apart the normal inline message bean to lay it out vertically. Note especially the <boundMessage> elements.

   <stackLayout>
     <contents>
       <messagePrompt prompt="Username:" required="yes">
         <boundMessage select="userError"/>
       </messagePrompt>
       <textInput name="user"/>
       <messageText tip="Your username">
         <boundMessage select="userError"/>
       </messageText>
     </contents>
   </stackLayout>

Client-side validation

Ideally, user errors are caught before the results are sent to the server. This is faster for the user; they don't have to wait for the error page to get loaded. It also saves load on the server, which doesn't have to parse these incorrect results. UIX offers support for this feature, called "client-side validation".

As you start using client-side validation, it's critical that you not come to rely on it. Here's a golden rule of multiple tier applications: "Validate on all tiers". Your middle-tier code - the code running in the servlet engine, for instance - must always check all values, even those that should have been verified by the client. And your database should verify values sent to it to by the middle-tier. This may seem like unnecessary work that'll just slow down your application, but it's essential that you follow this rule. Malicious users can change URLs or dummy up HTTP posts; databases used today with JavaScript-enabled browsers may be used tomorrow with simple handheld browsers. Failure to follow this rule will, at best, leave you with a flaky application. At worst, you'll open up security holes!

Required fields

Our first type of client-side validation is the "required" attribute. This attribute defines whether the user must enter some data, or whether they can leave a value blank. Try hitting "Submit" on the following page, first without entering any text; you'll see an error alert that stops you from submitting the page:

<form name="defaultForm" xmlns="http://xmlns.oracle.com/uix/ui">
 <contents>
   <messageTextInput prompt="Username:" name="user" required="yes"/>
   <submitButton text="Submit"/>
 </contents>
</form>

The "required" attribute is also supported on <choice> and <messageChoice> elements; if used here, you'll want to add an empty option, and usually mark it as selected:

<form name="defaultForm" xmlns="http://xmlns.oracle.com/uix/ui">
 <contents>
   <messageChoice prompt="Withholding:" name="withhold" required="yes">
     <contents>
       <option selected="true"/>
       <option text="10%" value="10"/>
       <option text="20%" value="20"/>
       <option text="30%" value="30"/>
     </contents>
   </messageChoice>
   <submitButton text="Submit"/>
 </contents>
</form>

There are four legal values for the "required" attribute:

  1. "yes": in Java, UIConstants.REQUIRED_YES: only non-blank values are allowed.
  2. "no": in Java, UIConstants.REQUIRED_NO: blank values are always allowed.
  3. "validaterOnly": in Java, UIConstants.REQUIRED_VALIDATER_ONLY: blank values are legal if and only if the attached client-side validaters allow blank values. (See below for information on attaching validaters.)
  4. "uiOnly": in Java, UIConstants.REQUIRED_UI_ONLY: it appears to the user as if the value is required, but others it behaves as REQUIRED_VALIDATER_ONLY. The case where this behavior is useful is fairly obscure, but it occasionally is useful.

Decimal validation

A very common type of input data is a numeric field. The UIX DecimalValidater class and <decimal> element support this behavior. It's a simple element; try entering random text in the following example, then hitting "Submit".

   <messageTextInput prompt="Any number:" name="number">
     <onSubmitValidater>
       <decimal/>
     </onSubmitValidater>
   </messageTextInput>

The <decimal> element is simple enough - it doesn't support any attributes. What's of much more interest here is the <onSubmitValidater> element that wraps it. This element defines what type of validater is used. There's only two types: <onSubmitValidate> and <onBlurValidater>. From Java, these are set with the setOnSubmitValidater() and setOnBlurValidater() methods. An "on-submit" validater executes when the user has completed the form and hits a "submit" button, while an "on-blur" validater executes as soon as the user leaves the field. To see the difference, try the following example. Type random text in the field, then hit the "tab" button:

   <messageTextInput prompt="Any number:" name="number">
     <onBlurValidater>
       <decimal/>
     </onBlurValidater>
   </messageTextInput>

In general, stick to on-submit validation unless you have a very specific reason. Forcing users to enter a correct value before they can enter any other can be extremely irritating.

Date validation and the DateFieldBean

A second common type of input data is a date field. UIX provides this functionality with its <dateField> element and DateFieldBean, as well as their messaging counterparts, <messageDateField> element and MessageDateFieldBean. (Again, a reminder - a <messageDateField> is equivalent to a <dateField> inside an <inlineMessage>.) Here's an example of <dateField> in action; click the calendar icon on the right side of the field:

   <messageDateField prompt="Date:" name="date"/>

Pretty simple. But you might want to change the format of the result if the default isn't what you want, or if you also want to edit the time as well as the date. It's a bit tricky how this is achieved - instead of directly setting an attribute on the <dateField>, you add an <onSubmitValidater> with the special <date> element (or DateValidater object). For all the details, check out the documentation of the <date> element, but trying out this example should give you a feel for what you can accomplish:

   <tableLayout>
     <contents>
       <messageDateField prompt="Date:" name="date" columns="20">
         <onSubmitValidater>
           <date dateStyle="long"/>
         </onSubmitValidater>
       </messageDateField>

       <messageDateField prompt="Date and Time:" name="dateandtime"
                          columns="20">
         <onSubmitValidater>
           <date dateStyle="short" timeStyle="short"/>
         </onSubmitValidater>
       </messageDateField>

       <messageDateField prompt="Patterned:" name="pattern">
         <onSubmitValidater>
           <date pattern="yyyy/MM/dd"/>
         </onSubmitValidater>
       </messageDateField>
     </contents>
   </tableLayout>

Regular expressions

Finally, UIX also supports use of regular expressions for validation with the <regExp> element or RegExpValidater class. We support the syntax used by Javascript. Describing this full syntax is outside of the scope of this document - pick up a Javascript reference - but here's an example of entering a social security number (please, don't enter your real number!):

   <messageTextInput prompt="SSN:" name="ssn" text="123-45-6789">
     <onSubmitValidater>
       <regExp pattern="[0-9]{3}-[0-9]{2}-[0-9]{4}"/>
     </onSubmitValidater>
   </messageTextInput>

Turning off validation

In many cases, you may want only some buttons on your page to validate the user's data but want to skip validation on other buttons. For example, a "Back" button should never force the user to enter correct results, since those results may never get used. To turn off validation on a component-by-component basis, use the "unvalidated" attribute (setUnvalidated() method). Here's the regular expression example again, but now with two buttons, one of which does not perform validation. Try entering an invalid social security number; the "Submit" button will validate, but the "Back" button will not.

   <messageTextInput prompt="SSN:" name="ssn" text="123-45-6789">
     <onSubmitValidater>
       <regExp pattern="[0-9]{3}-[0-9]{2}-[0-9]{4}"/>
     </onSubmitValidater>
   </messageTextInput>
   <submitButton text="Submit"/>
   <submitButton text="Back" unvalidated="true"/>

Manual form submission

Even though the UIX framework provides a powerful system for handling errors, there may be times when developers need to override that system to perform additional actions. For instance, a developer might want to take special Javascript actions when links are clicked, in addition to or instead of the work that the UIX validation system would normally perform.

For this reason, UIX makes available a few client-side Javascript functions which can be called by developers. The functions are implemented in libraries supplied with UIX. Many functions in these files are used internally by UIX and should not be called directly by developers; these function names are prefixed by an underscore "_". Behavior and arguments of these functions are subject to change between releases and should be considered off limits.

However, on function in particular could be used for developers who need to implement special form submission behaviors: the submitForm() function. This function is the same one used by the UIX Components renderers, and it allows developers to hook into the client-side validation framework that UIX has implemented.

Developers who need to submit forms manually in UIX pages must call this method rather than submit the form DOM element directly. The following parameters should be provided:

The function will return "true" if the form was actually submitted, or "false" if the form was not submitted for any reason, such as an error or a failed validation.

In deployment versions of UIX, the Javascript file containing these functions will be reduced for higher performance. Therefore, to see a copy containing comments and documentation, consult the source release for your UIX version and look in the oracle.cabo.ui.jsLibs directory.