« September 2006 | Main | November 2006 »

October 2006 Archives

October 9, 2006

Business Rules in Java or Database?

Gustavo writes in to ask how to migrate Oracle Forms business rules, for example when using JHeadstart Designer Generator. In case all business rules are
inside the Forms application, do you translate every business rule to the appropriate "spot" in
the ADF BC Framework or do you use CDM RuleFrame?

The answer is: it depends! Each solution has its pros and cons, and it depends on the circumstances which choice is best. I'll describe some characteristics, you can decide for yourself which are advantages and which are disadvantages, and how big a (dis)advantage it is. The characteristics not only apply when migrating Forms to Java, they apply in general when deciding where to put business rules when building a Java application using ADF Business Components on top of an Oracle database.

Characteristics of using ADF Business Components for business rules

  • Needs Java skills
  • Needs Oracle JDeveloper and ADF Business Components
  • The rules are enforced for each application that is based on these ADF Business Components (including JHeadstart-generated applications)
  • Usually faster user-feedback than business rules in the database
Characteristics of using CDM RuleFrame for business rules
  • Needs PL/SQL skills
  • Needs Oracle Designer and iDevelopment Accelerators
  • The rules are enforced for each application that is based on these database tables and that opens/closes CDM RuleFrame transactions and knows how to display CDM RuleFrame error messages (this is no problem for JHeadstart-generated applications: just turn on a built-in feature)
  • Usually slower user-feedback than business rules in the application server

October 10, 2006

JHeadstart 10.1.3 Evaluation Version Available!

Many customers asked for it over the past months, and as of today it is available: the free-downloadable evaluation version of JHeadstart 10.1.3 for ADF. The evaluation version is fully-functional: it contains the same set of features and functionality as the production version (including Service Update 1). The only limitation in this evaluation version is the number of ADF Business Components you can have in your workspace which is limited to 10 View Objects.

With this evaluation version, you will be able to generate sophisticated JSF applications that fully leverage ADF Faces, Oracle's comprehensive library of JSF UI Components, which is also available in the open source space under the name Trinidad.

Features that can be generated include wizards, shuttles, trees, list of values, multi-row insert/update/delete, advanced and quick search capabilities, deep-linking, multi-level tabs and stacked regions, table overflow regions, conditionally dependent items, file upload and file download, dynamic breadcrumbs, role-based security and more. And last but not least, all of the generator outputs are fully customizable by using powerful Velocity Generator Templates.

This evaluation version is certified against JDeveloper 10.1.3.0 as well as 10.1.3.1 which is expected to be released soon.

We believe that the combination of ADF and JHeadstart 10.1.3 provides you with a productivity and flexibility that is second to none as it comes to developing standards-based J2EE web applications. Do you think this is a bold statement? Well, then we invite you to try out this evaluation version. The easiest way to get started is by going to the excellent JHeadstart 10.1.3 Tutorial written by Steve Muench. This tutorial provides you with detailed step-by-step instructions on how to generate the aforementioned features, starting with the (simple) steps required to install the JHeadstart 10.1.3 Evaluation Version.

Additional material about this release, including viewlets, a FAQ, the Developers Guide, can be found at the JHeadstart Product Center.

Have fun!

October 13, 2006

Generating Select-Form Layout in Same Page

Ting Rung writes in to ask how he can generate a select-form layout with the select list displayed in the same page as the form items.
Using a custom velocity template, this is easy to generate. Here are the steps:

  • Create a custom template "selectFormGroup.vm" that merges the content of the selectGroup.vm which is used for the select page, and formGroup.vm used for the form page. Click here to download a sample of such a template that uses partial page rendering to refresh the form items when the user selects another entry in the select list.
  • Change the layout style of the group from "select=form" to "form".
  • While selecting the correct group in the navigator, select the templates tab and set the FORM_GROUP template to  your newly created template, for example "default/pageComponent/selectFormGroup.vm".
  • Run the JHeadstart Application Generator.
  • Run your application.
That's all. When you apply these steps to the Jobs group in the HR demo, it will look like this:

Inserting New Row in Table with Overflow Right

When generating a table with overflow right or below, it is not possible to generate the table with one or more empty rows that can be used to insert new rows. The reason for this limitation is that displaying the correct information in the overflow area, requires the notion of a current row in the underlying iterator binding, which is not available for new table rows.

To still allow users to insert a new row in such a table, we can generate a new button that creates a new row in the underlying iterator binding, and make this new row the current row, as shown in the screen shot below:
overflowRightNewRowImage:

To generate this, follow these steps:

  • Create a subclass of JhsCollectionModel, and add the following method to this subclass:
public String createNewRowAtBottomOfCurrentRange()
{
   DCIteratorBinding ib = getRangeBinding().getIteratorBinding();
   int rangeSize = ib.getRangeSize();
   int rowsInRange = ib.getAllRowsInRange().length;
   int insertPos = rowsInRange < rangeSize? rowsInRange: rangeSize - 1;
   Row row = ib.getRowSetIterator().createRow();
   applyModifiedAttrs(row, getDefaultValues());
   ib.getRowSetIterator().insertRowAtRangeIndex(insertPos,row);
   ib.setCurrentRowIndexInRange(insertPos);
   return null;
  }
  • Next, we create a custom template "myCollectionModelbean.vm" based on the standard default/misc/facesConfig/collectionModelBean.vm template. The only change you need to make in this custom template is the class name: set it to the name of your custom class instead of oracle.jheadstart.controller.jsf.bean.JhsCollectionModel.
  • Create a new template "newRowButton.vm" with the following content:
<af:commandButton
action="#{#COLLECTION_MODEL_BEAN().createNewRowAtBottomOfCurrentRange}"
textAndAccessKey="${JHS.nls(${JHS.current.group.displayTitleSingular},
  "NEW_BUTTON_LABEL_${JHS.current.group.name}", "NEW_BUTTON_LABEL" )}"
immediate="true"
onclick="return alertForChanges();"
id="${JHS.current.group.name}NewRowButton">
<f:actionListener
type="oracle.jheadstart.controller.jsf.listener.DoRollbackActionListener"
/>
<af:resetActionListener/>
</af:commandButton>
  • Now, we must configure the generator to use these two custom templates: select the correct group in the navigator and click the Templates tab.
  • In the templates tab, set NEW_BUTTON_NOT_IN_FORM_LAYOUT to the name of your custom button template, for example myapp/button/newRowButton.vm.
  • Set template COLLECTION_MODEL_BEAN to the name of your custom collectionModel template, for example myapp/misc/facesConfig/myCollectionModelBean.vm.
  • Run the JHeadstart Application Generator
  • Run your application.
Note that the New button now appears as a page level button. When you have detail groups displayed on the same page, the new button will appear as a group-level button, just below the table.
We could also have chosen to add the button to the table selection facet, just like the "Details" button generated for a "table-form" layout. However, the selection facet is only rendered when the table contains at least one existing row, which would make it impossible to create a new row in an empty table.

Finally, this example illustrates that custom templates are not just for layout customizations. They can also be used to specify the usage of custom subclasses of the JHeadstart Runtime classes, allowing you to change or extend the default JHeadstart runtime behaviors.
 

October 17, 2006

Announcing ADF JHeadstart 10.1.3 Workshops

The JHeadstart Team proudly announces two new runs of the successful ADF JHeadstart 10.1.3 Workshop, at the following dates:



  • 13 - 17 Nov 2006
  • 18 - 22 Dec 2006

These workshops will be held in De Meern (Netherlands). For more information and for registrations, please contact the Education Service desk, tel. +31 30 66 99 244, or via e-mail esd_nl@oracle.com.


Unable to attend at these dates? Check out the Specials page of Oracle University NL on a regular basis to see when this workshop will be held again in the Netherlands. Want to attend the workshop at a different time and/or location? Read the "Custom Delivery" section below!


Course Description

The JHeadstart Team has developed the ADF JHeadstart Workshop to provide you with the necessary training to use ADF and JHeadstart successfully on your projects. Rather than just explaining the use of the JHeadstart tool, much focus is placed on understanding and working with the ADF technologies that form the foundation of a JHeadstart application: ADF Business Components, Java Server Faces and ADF Faces. In fact, we do not start using JHeadstart until the 4th day of the course. Also, we incorporated many tips and best practises regarding common, real-life issues that will surely be helpful when you start building your own applications.


For a full description of the workshop contents, see the Oracle University page for the ADF JHeadstart workshop.


User Feedback

The feedback on earlier runs of this workshop has been very positive. Here are some reactions from customers and partners, as posted on the JHeadstart OTN Forum:




Steve Muench attended an internal 4-day version of the 10.1.2 version of this workshop. He wrote day-by-day reports of his impressions: first day, second day, third day, last day.


Preparation

If you have decided to attend the workshop, and want to get the most out of it, we recommend that you check the Preparation document for the ADF JHeadstart Workshop. This document provides links to a number of excellent OTN tutorials. For the best possible preparation, follow these tutorials before you attend our workshop.



Custom Delivery

The ADF JHeadstart 10.1.3 Workshop can also be delivered on demand and even on-site, anywhere on the globe. As such, it could be an excellent kick-off for a project that involves the use of JHeadstart. Apart from receiving thorough training on JHeadstart and its underlying ADF/JSF technologies, you would have an experienced instructor/consultant at your disposal that can advise you on how to tackle issues specific for your project. If you are interested in such a "custom" workshop, please contact us at idevcoe_nl@oracle.com.


 

October 20, 2006

Showing Parent Lookup Details with Edit Link

David posts on the JHeadstart Discussion Forum: on a page for editing an person, he wants to have a very condensed report of who the boss (manager) is together with a link,
on the same page as the base person (employee), so that he can use the link if
needed to edit the "boss". Other requirements are: 1) to display some differentiated columns (for example name, lastname, town,
country, ...) with their header for the boss and 2) more generally, having a similar look-and-feel of the page as other pages, and keeping
things clearly separated.

Here is my suggested solution, based on the HR schema that is also used in the JHeadstart Tutorial:
Manager Details with Edit Link Image: The lookup attributes of the manager are shown in a separate Item Region, together with a hyperlink that deeplinks to the page to edit the manager.<br>

The example has a link to the same group, but the solution described here works just as well if you link to another group. If you apply it, you will be using partial page rendering, deeplinking custom templates en custom properties, while only making some easy changes in JDeveloper.

How to show parent lookup details with an edit link

First change the relevant View Object in the Model project:

  1. Edit the ADF BC View Object for Employees and add the Entity for the Manager (check that the correct Entity Association is used in the bottom right corner of the panel).
  2. Add the desired lookup attributes you want to show of the Manager, and optionally rename them to make them easily recognizable.
  3. Ensure that the lookup attribute for the id of the Manager is not marked as Primary Key.
  4. Ensure that the SQL Query where clause performs an outer join if the manager relation is optional.
  5. Test the View Object with the ADF BC Tester
Now add a Generator Template and change the Application Definition in the ViewController project:
  1. Save the custom Velocity template {manilaSuite.gems.includeGem (26)} in a templates/custom folder of your ViewController project.
  2. Open the Application Definition, go to the Employees Group, and click the button to synchronize the items. This will add the new Manager Lookup attributes as items.
  3. Create a new Item Region for the Employees Group, and drag and drop the Manager Lookup items and the Employee item for changing the Manager to the new Item Region.
  4. Put in an appropriate Title for the region, set Columns to 1 and Width to 10%.
  5. Set the Depends On Item property (only visible in Expert Mode) for the Manager Lookup items to the Employee item that changes when you update the Manager (the ManagerId item in this case). This ensures that when you change the Manager, the lookup attributes are refreshed.
We will turn the Manager Lookup item that contains the id of the manager (not the ManagerId, but the EmployeeId of the manager entity) into an edit deep link. I will call this item the ManagerEmployeeId.
  1. In the Application Definition Editor, go to the ManagerEmployeeId item, and go to the Templates tab. Set the FORM_TEXT_INPUT template to the new template formDeepLink.vm you downloaded.
  2. Go back to the Properties tab, and set Custom Property 1 (only visible in Expert Mode) to the name of the group you want to link to (in this case Employees). You can put an explanation in Custom Property Description 1.
  3. Go to the Employees group, and set Type of Deep Linking (only visible in Expert Mode) to Query By Key Value.
  4. Set the Deep Linking Key Expression to the JSF EL expression #{param.EmployeesId}.
If you want to add a similar deeplink in a table layout, download {manilaSuite.gems.includeGem (27)} and use it as the TABLE_TEXT_INPUT template.

For more information about dependent fields, deep linking and custom templates, see sections 8, 9 and 10 of the JHeadstart Tutorial. See also the JHeadstart Developer's Guide chapter 3, section Customizing Page Layout Generation.

Note: in this case the deep link goes to the same group, but the technique also applies when linking to any other group.
In case you want to link to the same group, there is an alternative solution possible: instead of a deeplink, put an actionListener on the commandLink, to set the current row using setCurrentRowWithKey, setCurrentRowWithKeyValue or queryByKeyValue. Let the actionListener reference a suitable action binding, that you manually add to the page definition. If you uncheck the group property Clear Page Definition Before Generation?, your change will be preserved.

October 23, 2006

ADF Faces: Setting Locale through Application Logic (rather than Browser language)

ADF Faces allows you to create multi-lingual applications without much effort at all. Translations are present for all the standard texts and messages that ADF Faces uses, and all you need to do is provide resource bundles containing translations for all the application-specific texts, labels, prompts etc. in your application.


By default, ADF Faces determines the locale of the end user by inspecting the browser language settings. Recently, a partner asked me how this default behaviour could be changed to an implementation where the application itself can determine the locale to be used for a specific end user. A common scenario is to provide the end user with links or "flag" images in the page on which he can click to determine his language preference. Another common scenario is to use some kind of "user preference" functionality where preferred locales are persisted and automatically restored when the user logs in.


At first, I thought it would take a few minutes in the JDeveloper Online Help to find an example on how to do this, but that did not appear to be the case. I did learn some interesting facts, though, that I'll list here in case you're interested:



  • You can get to the current Locale with the following EL expression: #{view.locale.language}.
  • The scope of the "view" bean is "request", and it is an instance of javax.faces.component.UIViewRoot.
  • In Java code, you can get a hold of this object using the following code: FacesContext.getCurrentInstance().getViewRoot()
  • The "locale" property of this UIViewRoot bean is "writable", and is indeed the "single point of truth" for all locale-dependent code in the ADF Faces framework.

Wild goose chase

Lacking an example, my first incling was to look for this type of functionality in the adf-faces-config.xml file. As the ADF Faces Developers Guide points out, you can use EL expressions in that file (very cool!), so I hoped to be able to set the default locale there using an expression like #{userPrefs.locale}. Unfortunately,  this did not appear to be the case.


Next, I turned my attention to the following section in the Faces Config file:

&lt;application>
  ...
  &lt;locale-config>
    &lt;default-locale>en&lt;/default-locale>
  &lt;/locale-config>

   ...
&lt;/application>

In the &lt;locale-config> section you can specify the default locale and the supported locales for your application. Unfortunately, it is not allowed to put an EL expression in here as follows:

&lt;default-locale>#{userPrefs.locale}&lt;/default-locale>

With that, I had exhausted the possibilities I could come up with to solve this problem in a declarative manner.


Google came to the resque, however, and pointed me to the "locale" property of the &lt;f:view> component. Suddenly it all made sense to me: both the Java statement: FacesContext.getCurrentInstance().getViewRoot() and the EL expression  #{view.locale.language} are just different ways to access the &lt;f:view> component, and you can set the "locale" property declaratively in the JSF page!


The Solution

As an example, I implemented a small "LocaleManager" Java class, and used in a managed bean. Let's start with the managed bean definition in the Faces Config file:

&lt;managed-bean>
  &lt;managed-bean-name>localeManager&lt;/managed-bean-name>
  &lt;managed-bean-class>demoapp.LocaleManager&lt;/managed-bean-class>
  &lt;managed-bean-scope>session&lt;/managed-bean-scope>
&lt;/managed-bean>

I'll provide the code of the LocaleManager class here:

public class LocaleManager
{
  String userLocale;
  public void setUserLocale(String userLocale)
  {
    this.userLocale = userLocale;
  }
  public String getUserLocale()
  {
    return userLocale;
  }
  public void changeLocale(ActionEvent actionEvent)
  {
    String id = actionEvent.getComponent().getId();
    setUserLocale(id.substring(id.lastIndexOf("_")+1));
  }
}

The LocaleManager has a writable "userLocale" property that could be used in JSF pages both to show and change the "userLocale" user preference. But also added is a "changeLocale" action listener method that can be used, for instance, if you want clickable links, images or buttons in your application that the end user can use to set the locale to his preference. In this example, I (ab)use the "Id" property for parameter-passing; when this method is invoked from a UI component with id="xxxxx_en", "en" will be the new locale.


Next step is to tie the View component in the JSP pages to the LocaleManager, which is straightforward:


&lt;f:view locale="#{localeManager.userLocale}"/>


Finally, lets put buttons in the page with which we can invoke the "changeLocale' method, for example:

&lt;af:commandButton
    text="French"
    actionListener="#{localeManager.changeLocale}"
    id="changeLocale_fr"/>

Conclusion

Although this approach is pretty straighforward and requires little coding, I still feel that the more "logical" place for configuring the locale behaviour would be in the &lt;locale-config> section (what's in a name) in the Faces config file, rather than in a UI component in each and every JSF page of my application. I am actually hoping that someone reading this will point out that this is indeed possible. But at least, this is a workable solution, especially for JHeadstart users who only need to customize the dataPage.vm template to get this set up in all the generated pages.


 

October 30, 2006

Back Button Protection by Prevention instead of an Error

ADF web applications that do data inserts/updates/deletes are vulnerable to browser Back and Refresh functions. The risk is that you are seeing data on the page that is not consistent with the state of the application server that handles the transaction. The user might think he is performing one type of transaction, while the middle tier actually performs another one.

That's why ADF has a feature called row currency validation for data bound input forms. If the iterator's current row no longer matches what the user has edited, a validation error will appear at the top of the web page. The validation error provides feedback to the user that the page is no longer valid for editing, and prevents the user from unintentionally modifying the wrong object.

JHeadstart 10.1.2 has a different type of back/refresh protection, involving a hidden page timestamp on every page. When the page is submitted, JHeadstart checks if the timestamp is the same as the last one issued, otherwise an error is shown.

In our project we noticed that end users ran into this back/refresh error a lot, without them realizing why. So we figured that it would be better to prevent them from (accidentally) invoking the browser back/refresh function, by disabling certain browser functionality. We did this in two ways:

  1. Open the application in a popup window that does not have the browser toolbars (so the users cannot click the back or refresh button)
  2. Use Javascript to trap function keys that invoke the browser back and refresh functions
Here is how to disable the browser back and refresh button (tested with Internet Explorer 6) in a JHeadstart 10.1.3 application.
  • Download the zip file with sources for disabling browser back/refresh.
  • Extract the javascript library disable_back_button.js into your
    ViewController project's public_html/common subfolder.
  • Make sure this javascript library is loaded on every page by extracting pageConfig.jspx from the zip and letting
    it overwrite the existing public_html/common/regions/pageConfig.jspx.
    Note 1: if you did not put disable_back_button.js into the "common" subfolder, you need to edit the contents of pageConfig.jspx.
    Note 2: to prevent future upgrades of JHeadstart from overwriting this
    file, you should actually copy/rename it and use the Generator Templates to
    ensure that your customized region is used.
  • Extract the index.html into your ViewController project's web root (public_html).
  • Edit index.html so that it shows your application name in the title and visible body text, and change "faces/pages/EmployeesTable.jspx" to the first page of your own application.
  • Use index.html to start up the application (is used by default if you don't specify anything after the application's context root in the url, for example: http://host:port/myapplication).
When running index.html, you will see a page telling you that the application is started in another window. If you allow popups for the appserver site, the application itself will open in a new browser window without toolbars. If you press F5 (refresh) or Backspace (back), there is no effect.

If you want to build this functionality into a JHeadstart 10.1.2 UIX application, the steps are similar except for the pageConfig part. Instead, put the following line into your standardPageLayout.uit file, just above or below other <script> entries:
<script source="${requestContextPath}/common/disable_back_button.js"/>

About October 2006

This page contains all entries posted to JHeadstart Blog in October 2006. They are listed from oldest to newest.

September 2006 is the previous archive.

November 2006 is the next archive.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type and Oracle