JHeadstart

Subscribe to JHeadstart feed
Java EE Consultants - JHeadstart, ADF, JSF
Updated: 6 hours 24 min ago

Oracle JHeadstart 11.1.1.5 Now Available

Mon, 2013-09-30 05:15

Oracle JHeadstart 11.1.1.5 is now available. This is a maintenance release for JDeveloper 11g R1. Oracle JHeadstart 12c, a new release that will be compatible with JDeveloper 12c is currently planned to become general available later this calendar year. 

This 11.1.1.5 release contains the following new features:

  • UI Tree Checked for Pending Changes: Prior to this release, pending changes were only detected in the model, after the JSF lifecycle phase "Update Model" was executed to update the underlying ADF model bindings. This implied that for menu item commands the immediate property had to be set to false to detect the last changes made by the user that were not yet sent to the server, otherwise the "Update Model" phase was skipped. However, with immediate=false, the end user could not abandon pages with invalid or incomplete data as validation errors occurred before the menu navigation could take place. So, the choice was to either limit the navigation freedom of the end user, or accept the fact that the pending changes alert was not always shown. With this new release this problem is solved. All menu items have immediate=false allowing complete freedom to navigate away, while the latest changes are also detected because JHeadstart now inspects the UI Components in the page UI tree for any changes. The UI Components are always updated with the latest value, also when immediate is set to true because the UI components are updated in JSF lifecycle phase "Apply Request Values" which is always executed, regardless of the setting of the immediate property. The inspection of the UI tree is performed in a new managed bean class PendingChangesVisitCallBack. This class is generated as managed bean in JhsCommon-beans.xml. If for some reason you want to keep the old behavior, and not inspect the UI tree for pending changes, you can add the following property to the ApplicationDefinition.xml file:
      checkUITreePendingChanges="false"
    
    Note that you need to set this property directly in the xml file, it is not visible in the JHeadstart Application Definition editor. If this property is set to false, the PendingChangesVisitCallBack bean is not generated and the menu item commands are generated again with immediate=false.
  • Ability to override generated item properties: The item-level property "Additional Properties" has been renamed to "Additional / Overriding Properties" can now be used as well to override standard generated properties. If you specify a property in "Additional / Overriding Properties" then this property always 'wins', it will override a property by the same name that was generated by the same item template. This signifcantly reduces the need for custom item templates.
  • Support for Skyros Skin: If you wan to use the new Skyros skin introduced in JDeveloper 11.1.1.7, you should change the JHS_PAGE_TEMPLATE setting at application level from default/misc/file/jhsPageTemplate.vm to default/misc/file/jhsPageTemplateSkyros.vm. This new template is optmized for the Skyros skin, and also uses the new af:panelGridLayout component.

See the JHeadstart 11.1.1.5 Release Notes for a list of bugs fixed in this release.

See the support matrix for supported JDeveloper releases.
Customers who own a JHeadstart supplement option license can download it from the Consulting Supplement Option portal. 

For a complete list of all JHeadstart features, use this link. For detailed information on all the features, check out the comprehensive JHeadstart Developer's guide. Want to try JHeadstart yourself? Do the tutorial using the JHeadstart evaluation version that you can install using Help -> Check for Updates functionality in JDeveloper.


Categories: Development

JHeadstart 11.1.2 Evaluation Version and Updated Tutorial Now Available!

Mon, 2012-05-14 14:41

Anybody who is interested  in building ADF applications like the experts do, and at the same time wants to increase developer productivity significantly should take a look at the free downloadable JHeadstart 11.1.2 evaluation version. This evaluation version is compatible with JDeveloper 11.1.2.1.x and 11.1.2.2. The best way to evaluate the immense power of this JHeadstart release is to follow the comprehensive tutorial, that is updated for this latest release. The tutorial includes instructions for installing JHeadstart, and has step-by-step instructions so even people with minimal or no ADF/Java experience can follow along. You can also download the completed tutorial application here, in case you don't have the time to go over the tutorial. To run the tutorial application, you do need to install JHeadstart (see the tutorial for instructions) as JHeadstart comes with a powerful Java runtime library (source code is included!). 

For more information on JHeadstart, visit the JHeadstart Product Center.

Enjoy!

Categories: Development

Oracle JHeadstart 11.1.1.4 Now Available

Wed, 2012-02-29 12:03

Oracle JHeadstart 11.1.1.4 is now available for download (build 11.1.1.4.26).
See the support matrix for supported JDeveloper releases.
Customers who own a JHeadstart supplement option license can download it from the Consulting Supplement Option portal.

This release is mainly a bug fix release. In addition, some small small enhancements have been added: 

  • Enhanced Support for Dynamic Tabs: The implementation of dynamic tabs has been changed and enhanced. There is no longer a dependency on the standard oracle uishell dynamic tabs implementation. A new oracle.jheadstart.view.dyntab.DyntabContext class is now used instead of the oracle.ui.pattern.dynamicShell.TabContext class that supports additional features like updating the document title based on the current tab, setting the maximum number of tabs, and displaying initial tabs.
  • Enhanced Support for Function Keys: New function keys have been added for first row, previous row, next row, and last row, and go to details. In addition when changing a page fragment or tab within a page fragment, the cursor focus will be set on the first item.
  • Control over Generated Value Bindings: At the service level, two new properties have been added. The property Always Generate Form Value Bindings controls whether individual attributeValues bindings are generated for a group that does not have form layout. The property Generate Value Bindings for Hidden Items controls whether a value binding is generated whe the item is hidden. To ensure upwards compatibility the default value of both properties is true, however, if you create a new service definition, both properies are set to false. If one or both if these service-level properties are set to false, you can still force generation of an individual value binding using the two new item properties Generate Form Value Binding and Generate Table Value Binding. Both these new service properties, and new item properties are only visible in advanced mode in the Application Definition Editor.
  • Enhanced Implementation of Dependent Items: In previous releases, dependent items were refreshed using the partialTriggers property. This caused the dependent items to be validated as well as part of the optimized lifecycle, forcing usage of showRequired property rather than the required property to prevent premature client-side validations. In this release, the dependent items are refreshed programtically by adding them as partial target inside the DependsOnItem bean. This means all items can have client-side validations as desired.
  • Enhanced Implementation of Display New Row on Entry: The check whether a new row must be displayed is now performed inside the task flow itself, instead of in the calling task flow. This allows for a proper implementation of the "when no rows found" option in this property.
  • Enhanced Implementation of JHeadstart LOV's: The JHeadstart web-tier LOV implementation has been completely rewritten. The new implementation uses one generic LOV popup per page, with one associated generic LOV task flow binding and one genwric LOV Task flow manager bean. LOV for validation has been implemented using a generic dynamic task flow call (in the task flow template). This new implementation is easier, more robust, and generates significantly less managed beans. The pages will also load faster since every page has only one LOV popup included, instead of separate popups for each and every lov item (which were even repeated for each row in a table)
  • Enhanced Implementation of Custom Properties: Custom properties can now also be accessed using the name of the property (previously labeled description). There are three expression you can now use now, for example for group custom properties you can use:
    • ${JHS.current.group.property1}, this is the existing expression that also works when no name is entered for the property.
    • ${JHS.current.group.getCustomProperty("propertyName")}, where propertyName should be substituted with the name you entered for this property.
    • ${JHS.current.group.propertyName}, where propertyName should be substituted with the name you entered for this property. If you use this expression and the group does not have this custom property defined, you will get an error during generation.
We recommend to use the new second or third expression, these expressions dot not care which custom property number you used to enter the name and value. In addition, if you use the second or third expression, you never run out of custom properties, because you can also enter a comma-delimited list of names and values in the name and value property.

For a complete list of all existing features, use this link. For detailed information on all the features, check out the comprehensive JHeadstart Developer's guide. Want to try JHeadstart yourself? Do the tutorial using the JHeadstart evaluation version.

Categories: Development

Model-based Cascading LOV's For JHeadstart

Fri, 2012-02-10 02:32

Written By Peter Koletzke, 8 February, 2012 (posted by Steven)

SCENARIO

While searching for employees, users need to find a department by first finding a location from a City LOV (dropdown list). After selecting a city, the City and Postal Code appear on the screen.  LocationId also returns from the LOV, but is hidden because users should not see the ID.  

Then the user opens a Departments LOV (pop up LOV with query fields), which displays only departments within the selected city. After selecting a department, the Department ID and Department Name are returned to the screen. 

CONCLUSION

Implementing a cascading LOV consists mostly of work in the Model project. It is important that you prove that the cascading LOV works in the Model project before implementing it in the ViewController project. A brief list of the special components and settings needed to implement a cascading LOV follows. 

You can access a detailed recipe for this technique here. A sample application that results from this recipe is here.

MODEL PROJECT

  • Base view object for the Employees entity object: EmployeeMaster
  • Read-only view objects for the Locations LOV and Departments LOV queries
  • View criteria on the Departments LOV to represent a WHERE clause for location_id = :bind_variable
  • Locations and Departments added as reference entity objects to EmployeeMaster
  • Calculated attributes in EmployeesMaster as follows. All have Queryable as “true” and Display Hint as “Display.”
    • LocCity (LOCATIONS.CITY)
    • LocPostalCode (LOCATIONS.POSTAL_CODE)
    • LocLocationId (LOCATIONS.LOCATION_ID)
    • DeptDepartmentName (DEPARTMENTS.DEPARTMENT_ID)
  • Locations LOV on the Employees.LocCity attribute, returns city, location ID (hidden), and postal code
  • Departments LOV on the Employees.DepartmentName, returns DepartmentName and DepartmentId, uses DepartmentsLOV view object accessor with the detail LOV view criteria mentioned above (parameter value = LocLocationId)
  • AutoSubmit UI hint set for the two LOV items: LocCity, DeptDepartmentName
  • Dependencies to LocCity from DeptDepartmentName and DepartmentId (so they clear when the city changes)
  • View criteria on EmployeeMaster for a list of attributes needed in Quick Search area. An additional view criteria is needed for the Advanced Search area. LocLocationId is listed in both view criteria, but its UI Hint for Rendered Mode is “Never.” Deselect Show in List on the UI Hints tab.

VIEWCONTROLLER PROJECT

All actions are in the JHS application definition editor unless noted.

  • Set the LocLocationId item so it does not display in the table or in the form.
  • Set Quick Search View criteria and Advanced Search View criteria properties to the names of the appropriate (but separate) view criteria you created for to list attributes in these search sections
  • Set Depends On Item(s) properties for LocPostalCode as “LocCity,” for DepartmentId as “DeptDepartmentName,LocCity” so the LOV return fields on the edit page are set after an LOV selection.
  • Select the Clear/Refresh Value? property for DepartmentId so it clears when the city or department name changes.
  • For JHS 11.1.1.4: select Clear/Refresh? Value for DeptDepartmentName.
  • For JHS 11.1.1.3: edit adf-config-EmployeeMaster.xml after generation to define a depends-on refresh for DeptDepartmentName.


Categories: Development

Core ADF11: Building Highly Reusable ADF Task Flows

Wed, 2011-12-14 02:52

In this old post in the Core ADF11 series, I explained the various options you have in designing the page and taskflow structure. The preferred approach in my opinion that maximizes flexibility and reusability, is to build the application using bounded taskflows with page fragments. You then have various ways to disclose these task flows to the user. You can use a dynamic region or dynamic tabs, or a human workflow task list, or even have the user add the task flow at runtime using Webcenter Composer. 

To maximize reuse of individual task flows, there are some simple techniques you can apply:

  • Define a set of input parameters that allows you to configure for the various (re)use cases
  • Define a router activity as the default activity to enable reuse-case-based conditional flows
  • Configure use of dynamic iterator binding to use a task flow both as a master region or detail region
  • Configure display properties of UI components based on task flow input parameters so components can be shown/hidden, editable/readOnly, required/optional, etc based on the specific (re)use case

By applying these techniques, you can dramatically reduce the number of task flows you need to build in your project. In this sample application, you can see how you can reuse the same task flow to support the following reuse cases:

  • Show in read-only mode
  • Enable deeplinking from another page to show one specific row 
  • Use as read-only context info in popup
  • Use as master region as well as detail region 
  • Enable deeplinking from external source like e-mail.

Downloads: 

Categories: Development

Core ADF11: UIShell with Dynamic Tabs

Fri, 2011-10-07 06:05

Last update on 28-aug-2013 Sample added for JDeveloper 12.1.2, see bottom of post.

In this old post in the Core ADF11 series, I explained the various options you have in designing the page and taskflow structure. The preferred approach in my opinion that maximizes flexibility and reusability, is to build the application using bounded taskflows with page fragments. You then have various ways to disclose these task flows to the user. You can use a dynamic region that displays the taskflow, as described in this post. You can also go for a more advanced user interface pattern that provides multi-tasking capabilities to the end user by dynamically adding tabs that represent independent tasks for the end user. This patterns is described in more detail here and covers more than only the dynamic tabs. Oracle provides a sample implementation named "Oracle Dynamic Tabs Page Template" of this user interface pattern as an extension to JDeveloper  that can be installed through the JDeveloper Help -> Check for Updates option.  While this implementation might be sufficient in your case, I discovered the need for additional related functionality not provided out-of-the-box by this extension, as well as the need for easier customization options. As I started to implement this pattern at various customers I added more and more functionality to my implementation of this pattern that started off with a more or less one-to-one copy from the Oracle extension implementation. The end result is quite different from the Oracle extension, also because I optimized the implementation for JDeveloper 11.1.2, leveraging the new multiregion binding. For my presentation of this topic at Oracle OpenWorld 2011 I created a showcase application that includes all the code and templates for the dynamic tabs implementation and illustrates all the functionalities my customers asked for, including:

  • Open new tabs in various ways: Using a menu, using a global quick search, from within another tab, and conditionally based on a tab unique identifier that is used to check whether there is already a tab open with the same UID.

  • Close a tab in various ways: using the close icon on the tab, using a close tab button inside the tab region, or auto-closing a tab when the user finished the task.
  • Transaction handling: Each tab should have an independent transaction, a tab needs to be marked dirty with a visual indicator indicating the dirty tab state, and a warning should be shown when the user tries to close a tab with pending changes.
  • Miscelleanous requirements: Update browser window/tab title based on currently selected tab, initially display tabs, prevent tabs from being closed automatically, set maximum number of tabs the user is allowed to open, and update of the tab label based on the current data shown in the region.

If you have similar requirements, then this sample application might be useful to you. You can download the application below, feel free to copy and paste the infrastructure classes, templates and declarative components to your own application. For an explanation of the implementation, see the slides of my OOW presentation.

Downloads: 

Update 13-nov-2012: The implementation in the sample applications has been improved. It is no longer needed to define the managed bean for a tab that is initially displayed in view scope rather than request scope. By improving this implementation of initially displayed tabs, the following issues have been fixed:

  • Closing and re-opening an initially displayed tab caused an NPE (11.1.1.x only)
  • It was not possible to launch another tab from within an initially displayed tab
Update 28-aug-2013: Dynamic Tabs Sample For JDeveloper 12.1.2

Initially, I had problems getting the sample to work in JDev 12.1.2. I logged the following bugs against 12.1.2 that could be reproduced when opening  the 11.1.2 sample in 12.1.2:

  • Bug 17158398 - COMMAND COMPONENTS DO NOT WORK WHEN OPENING REGION IN DYNAMIC TAB
  • Bug 17156672 - UI NOT RENDERED CORRECTLY DUE TO CONTEXT PARAM DEFAULT_DIMENSION
  • Bug 17156560 - JAVA.LANG.ILLEGALSTATEEXCEPTION: COULD NOT FIND COMPONENT TO STREAM
  • Bug 17158597 - UPDATES ARE LOST WHEN DEFINING REGIONCONTROLLER IN PAGEDEF CONTROLLERCLASS PROP

Product development has investigated some of these bugs, and this is the result:

  • The behavior described in bug 17156560 was caused by the fixed value specified for the id property in the af:region tag. Unlike JSP, facelets does not ensure uniqueness when stamping out multiple components, in this case multiple regions inside the af:forEach loop. By removing the id property (facelets will then auto-generate a unique id), or making it unique using an EL expression like id="reg_${vs.index}"  the issue was resolved. See this blog post from Duncan Mills for more info.
  • After applying the fix for bug  17156560 , the behavior reported in bugs 17158398 and 17158597 was no longer seen. These bugs are now closed as "not a bug".
  • The work around for bug 17156672 is simple. The top-level af:decorativeBox in the page template should have the dimensionsFrom property set to "parent" when the DEFAULT_DIMENSIONS context param is set to 'auto' in web.xml. However, since JDeveloper should ensure upwards compatibility, it should never automatically add the DEFAULT_DIMENSIONS web.xml context param to an existing application. So, the bug has been changed to a design-time bug to prevent this from happening. 
With these fixes, the 12.1.2 sample is now working correctly and can be downloaded here.

Categories: Development

How to become an Oracle ADF expert in one week (or in 1 day if you don't have so much time)

Tue, 2011-09-13 22:15

Oracle ADF is an extremely powerful framework for developing SOA-based web applications. Once you have grasped the key concepts of ADF, it is a real pleasure to work with ADF, and to experience how fast you can build really sophisticated stuff. But......as with any advanced framework, there is a learning curve involved, and I have to admit the ADF learning curve might be experienced as rather steep at times. I am often asked, "how long does it take to become a good ADF developer?", and I usually answer "something between 3-6 months".  The problem is that most project managers don't allow you this time, so you simply start your first ADF project, and find out along the way that you should have chosen a fundamentally different approach to make you application components truly flexible, easy to maintain, and reusable.

Well, Oracle has a one-time-only-unique-offer that allows you to become an ADF expert in one week, and get your ADF app right the first time: Attend Oracle Open World 2011, 2-6 october in San Francisco! The 2011 version of OOW has been proclaimed by the ADF EMG as "Year of the ADF developer" and with good reason. There are lots of good ADF sessions at OOW 2011, a complete overview of all ADF sessions can be found here.

If your employer does not allow you a whole week off from your project, you can go for the sunday-shortcut to become an ADF expert in even one day. The ADF EMG has put together an impressive list of speakers and topics, who will all present on sunday october in Moscone room 2000. See you there! (And don't forget to attend my own presentations on sunday 2.00 PM and wednesday 10.15 AM )

Categories: Development

JDev 11.1.2: Differences in Table Behavior

Thu, 2011-07-28 23:03

While building a simple ADF application in JDev 11.1.2 I encountered some strange runtime behavior. I built another application with the same behavior in exactly the same way in JDev 11.1.1.4 and there things worked smoothly. However, in JDev 11.1.2, the addRow and deleteRow functions didn't work as expected. In this post I will share my tough journey in founding out what was happening, and discuss the difference in behavior and the changes required to make it work in JDev 11.1.2.

When using the add row button (the green plus icon in the screen shot below) an error message for the required JobId dropdown list was shown immediately.

Some investigation using the Google Chrome Developer tools revealed that two requests instead of one are sent to the server, with apparently the second request causing the validation error to appear. (Although, the validation error is a client-side error, so still not sure how the second request can trigger the error.)

At first I thought this was caused by the partialSubmitproperty on the addRow button, which was set to true. Setting this property to false (or removing this property) fixed this problem, but caused table rendering to hang. Weird, but I didn't investigate that further. I decided to build the same app in JDev 11.1.1.4 which worked smoothly and then opened this app in JDev 11.1.2. After the auto-migration, I ran the app but much to my surprise the "Selection required" message didn't show up. I compared the page and page definition of both apps over and over again, and couldn't see any difference.  Eventually, I started comparing all the files in both projects. This lead me to the adf-config.xml file, located in the .adf directory under the root directory of the application, also visible under the Resources panel. In this file, one property existed in the JDev 11.1.2 application that was not present in the JDev 11.1.1.4 version: changeEventPolicy="ppr".

By removing this property, things started to work again, and only one request was sent again.

Note that the really tricky thing here is that when you upgrade an application from JDev 11.1.1.4 this property does not get added, but new JDev 11.1.2 apps will have this property setting, causing difference in behavior between a migrated app and a new app. At this point, my recommendation is to remove this property (or set it to none) for new JDev 11.1.2 apps. If memory serves me well, in some JDev 11.1.1.x version, dragging and dropping a data a table on a page, added the changeEventPolicy="ppr" property to the iterator binding in the page def. In a later JDev 11.1.1.x release this property was gone again. Looks like it is back in a different form (this time in adf-config.xml), but still with undesirable implications. 

The next error I hit was in the delete confirmation dialog, when trying to delete a row. Regardless of which button I pressed (Yes or No), I got validation errors on the underlying new row, and the dialog was not closed, nor was the row removed.

Now, I think this error has to do with the ADF Faces optimized JSF lifecycle.  Since the table needs to be refreshed when the row is removed by clicking yes in the dialog, the af:table component  requires a partialTrigger property that refers to the af:dialog element. With this partialTrigger property in place the ADF JSF optimized lifecycle causes the table items to be submitted (and validated) as well when clicking the Yes or No button in the dialog. Now,I am speculating here, but may be this wasn't supposed to work at all in JDev 11.1.1.4, but it did because of a bug in the optimized lifecyle code, that has now been fixed in JDev 11.1.2...?

Anyway, what feels like the most logical and easy way for me to solve this issue, is setting the immediate property on the af:dialog to true, so the dialog listener method would skip the JSF validation phase. However, the af:dialog element does not have such a property (logged enhancement request).  Two other solutions remain:

  • No longer use the dialoglistener property, but instead define custom Yes/No buttons using the toolbar facet on the af:dialog. On these buttons I can set the immediate property to true, bypassing client-side and server-side validation.
  • Do not specify the af:dialog as partial trigger on the af:table component, instead, add the table or a surrounding layout container element as partial target programatically after deleting the row. This is the solution I chose, since it only required one line of code in the managed bean class that deletes the row.

Links and references:

Categories: Development

Core ADF11: UIShell with Menu Driving a Dynamic Region

Thu, 2011-07-07 21:44

In this old post in the Core ADF11 series, I explained the various options you have in designing the page and taskflow structure. The preferred approach in my opinion that maximizes flexibility and reusability, is to build the application using bounded taskflows with page fragments. You then have various ways to disclose these task flows to the user. You can use an dynamic tabs as described in this post. You can also embed the taskflows using a dynamic region in a page. The application menu then drives the content of the dynamic region: clicking a menu option will load another taskflow in the dynamic region.

 The initial drawback of this approach is that it adds some additional complexity:

  • You can no longer use standard JSF navigation with your menu, there are no pages to navigate to, only regions
  • The XMLMenuModel, an easy way to define your menu structure in XML, cannot be used as-is. The selected menu entry when using the XMLMenuModel is based on the current page, and in our design, the whole application consists of only one page, the UIShell page.
  • The dynamic region taskflow binding should contain a list of all parameters of all taskflows that can be displayed in the dynamic region.

    This is a rather ugly design, and the developer of the UIShell page would need to know all the parameters of all taskflows that might be displayed in the dynamic region. A cleaner implementation is to use the parameter map property against the taskflow binding. However, when using the parameter map, you need to do the housekeeping of changed parameter values yourself when you want the taskflow to refresh when parameters change. In other words, just specifying Refresh=ifNeeded on the taskflow binding no longer works because ADF does not detect changes in a parameter map.

Fortunately, you can address this complexity quite easily by creating some simple, yet powerful infrastructure classes that hide most of the complexity from your development team. (The full source of these classes can be found in the sample application, download links are at the bottom of this post)

  • A DynamicRegionManager class that keeps track of the current task flow and current parameter map 
  • A TaskFlowConfigBean for each task flow that contains the actual task flow document path, the task flow parameters and a flag whether the parameter values have been changed.
  • A RegionNavigationHandler that subclasses the standard navigation handler to provide JSF-like navigation to a region taskflow.
  • A RegionXMLMenuModel class that subclasses the standard XMLMenuModel class to ensure the proper menu tab is selected based on the currently displayed taskflow in the dynamic region. 

The following picture illustrates how this UIShell concept works at runtime.

The UIShell page (with extension .jsf in JDeveloper 11.1.2 and with extension .jspx in JDeveloper 11.1.1.x) contains a dynamic region. The taskflow binding in the page definition of UIShell gets the currently displayed taskflow from the DynamicRegionManager class that is registered as a managed bean under the name mainRegionManager. The actual task flow id and task flow parameters are supplied by the TaskFlowConfigBean. The DynamicRegionManager manages the current taskflow based on a logical name, for example Jobs. When method setCurrentTaskFlowName is called on the DynamicRegionManager with value Jobs (and we will later see how we use the RegionNavigationHandler to do this), the DynamicRegionManager looks up the corresponding TaskFlowConfigBean by suffixing the Jobs task flow name with TaskFlowConfig.he methods getCurrentTaskFlowId and getCurrentParamMap and currentParamMapChanged then obtain and return the correct values using the JobsTaskFlowConfig bean.

Using this technique, you can configure your dynamic region completely declarative, there is no need to write any Java code. All you need to do is configure the mainRegionManager and task flow config beans, as shown below. 

In this sample, I configured the required managed beans in adfc-config.xml. When using ADF Libraries that contain task flows you want to show in the UIShell dynamic region, it is more elegant to define the TaskFlowConfigBean inside the ADF library. I usually define this bean in the adfc-config file of the task flow itself, below the  <task-flow-definition/> section.  It needs to be outside this section, otherwise the bean cannot be found by the DynamicRegionManager bean that is defined in the unbounded task together with the UIShell page. The advantage of this approach is that the config bean is placed in the same file as the task flow it refers to, the disadvantage is that beans defined outside the </task-flow-definition> section are not visible in the overview tab of a bounded task flow.

To set the current task flow name on the DynamicRegionManager, we use a custom RegionNavigationHandler class that you register in the faces-config.xml.

This class extends the default navigation handler, and overrides the handleNavigation method. The code is shown below. If the outcome contains a colon, the part after the colon contains the task flow name that should be set in the dynamic region.


With this class in place, we can use the action property on command components again to do region navigation, just like we are used to for normal JSF navigation, or navigation between page fragments inside a bounded task flow. The complete flow is as follows:

  • The menu item has the action property set to uishell:Jobs.
  • The region navigation handler set the current task flow name on the Dynamic region manager to Jobs (and navigates to UIShell page if needed) 
  • The dynamic region manager picks up the current task flow id and current parameters from the JobsTaskFlowConfig bean.

The last part of the puzzle is the RegionXMLMenuModel class that subclasses the standard XMLMenuModel class. This class overrides the getFocusRowKey method to return the focus path based on the current task flow region name.

With this class defined in the menu model managed bean, the menu will correctly display the selected tab.   

In a future post I will discuss how the same concepts can be applied to a UIShell page with dynamic tabs.

Downloads:

Categories: Development

Some More New ADF Features in JDeveloper 11.1.2

Thu, 2011-06-23 22:39

The official list of new features in JDeveloper 11.1.2 is documented here. While playing with JDeveloper 11.1.2 and scanning the web user interface developer's guide for 11.1.2, I noticed some additional new features in ADF Faces, small but might come in handy:

  •  You can use the af:formatString and af:formatNamed constructs in EL expressions to use substituation variables. For example: 
    <af:outputText value="#{af:formatString('The current user is: {0}',someBean.currentUser)}"/>
    See section 3.5.2 in web user interface guide for more info.

  • A new ADF Faces Client Behavior tag: af:checkUncommittedDataBehavior. See section 20.3 in web user interface guide for more info. For this tag to work, you also need to set the  uncommittedDataWarning  property on the af:document tag. And this property has quite some issues as you can read here. I did a quick test, the alert is shown for a button that is on the same page, however, if you have a menu in a shell page with dynamic regions, then clicking on another menu item does not raise the alert if you have pending changes in the currently displayed region. For now, the JHeadstart implementation of pending changes still seems the best choice (will blog about that soon).

  • New properties on the af:document tag: smallIconSource creates a so-called favicon that is displayed in front of the URL in the browser address bar. The largeIconSource property specifies the icon used by a mobile device when bookmarking the page to the home page. See section 9.2.5 in web user interface guide for more info. Also notice the failedConnectionText property which I didn't know but was already available in JDeveloper 11.1.1.4.

  • The af:showDetail tag has a new property handleDisclosure which you can set to client for faster rendering.

  • In JDeveloper 11.1.1.x, an expression like #{bindings.JobId.inputValue} would return the internal list index number when JobId was a list binding. To get the actual JobId attribute value, you needed to use #{bindings.JobId.attributeValue}. In JDeveloper 11.1.2 this is no longer needed, the #{bindings.JobId.inputValue} expression will return the attribute value corresponding with the selected index in the choice list.
Did you discover other "hidden" new features? Please add them as comment to this blog post so everybody can benefit. 

Categories: Development

Oracle JHeadstart 11.1.1.3 Now Available

Wed, 2011-03-16 05:27

Oracle JHeadstart 11.1.1.3 is now available for download (build 11.1.1.3.35).
This release is compatible with JDeveloper 11 releases 11.1.1.4, as well as 11.1.1.3 and 11.1.1.2.
Customers who own a JHeadstart supplement option license can download it from the Consulting Supplement Option portal.

In addition to many small enhancements and bug fixes, the following features have been added to JHeadstart 11.1.1.3:


  • Support for Dynamic Tabs: There is a new page template insipred by the dynamic tabs functional pattern. Note that this template and associated managed beans are all included with JHeadstart and can be easily customized. The implementation does not depend on the "Oracle Extended Page Templates" library. Additional JHeadstart-specific features include: automatically marking the current tab dirty, initially displaying one or more tabs, ability to uniquely identify tabs by a tab unique identifier, close tab icon displayed on tab itself. When using the item Display Type "groupLink" there is a new allowable value "New Dynamic Tab" for property Display Linked Group In that can be used when you use the dynamic tabs template. For example, this allows you to have a first "EmployeeSearch" group that searches employees and shows the result in a table, and then clicking a groupLink edit icon for one employee in the table, which opens a new dynamic tab showing the linked "CustomerEdit" group for this specific employee. See section 9.3 "Using Dynamic Tabs when Opening a Menu Item" in the JHeadstart Developer's Guide for more information.

    Dynamic Tabs



  • Support for Function Keys: There is a new application level property Enable Function Keys. When this property is checked, JHeadstart will generate context-sensitive function keys. The list of function keys can be
    seen by clicking Ctrl-K. The actual function keys shown in the list depend on the location of the cursor in the page. The default mapping of function keys to ADF actions is inspired by Oracle Forms function key mapping, but can very easily be changed. Function keys for custom buttons can easily be added as well. See section 11.7 "Using Function Keys" in the JHeadstart Developer's Guide for more information.

    Context-Sensitive Function Keys

  • Support for Popup Regions: There are two new region container layout styles: Modeless Popup Window and Modal Popup Window. With these layout styles, the content of the region container and its child regions are displayed in a poupup window. If the Depends on Item(s) property is set on the region container, the item context facet of the depends-on-item is used to launch the region container popup. If the depends-on-item is a button item, the popup will be launched when clicking the button. If the Depends on Item(s) property is not set for the popup region conatiner, an additional button with the label set to the region title is generated to launch the popup. See section 5.10.4 "Generating Content in a Popup Window" in the JHeadstart Developer's Guide for more information.

    Popup Region Container with Method Call Button

  • Support for Dynamic Iterator Bindings: There is a new group property Data collection Expression. In this property you can specify an EL expression that determines at runtime which data collection (view object usage) should be used. This can be useful when reusing the same group taskflow multiple times. For example, the Employees group can be used as a top-level taskflow, and as a group region taskflow under the departments group. Rather then setting up bind variables and a query where clause, this use case can be implemented much easier by dynamically switching the view object usage between a top-level employees view object usage and a nested usage under the departments view object usage. The data collection expression can then refer to a taskflow parameter which specifies the actual view object usage name.
  • Support for Custom Toolbar Buttons: There are two new item display types toolbarButton and groupLinkToolbarButton. Items with this display type are generated into the group-level toolbar for form layout, and added to the table toolbar for table layouts

    Custom Iconic Toolbar Button

  • Control over Label Position: There is a new property Label Alignment for groups and item regions that allows you to specify whether labels (prompts) should be positioned at the left of an item, or above the item.
  • Support for Icons: There is a new icon property available at group and item level. At item level, this can be used to generate iconic buttons and group links. At group level, the icon is displayed in the header bar of the group, and in buttons that navigate to the group taskflow
  • Support for Online Help: At the application level, there is a new property Online Help Provider. Two new properties Help Text and Instruction Text have been added to the group, region container, group region, item region and item elements. These two new properties are only used when a help provider is set at application level. If a help text is entered a help icon will be displayed at the right of the element title, or in case of an item, at the left of the item prompt. If an instruction text is entered, it will be displayed below the element title, or in case of an item, in a popup when the user clicks in the input component of the item. See section 11.6 "Using Online Help" in the JHeadstart Developer's Guide for more information.

    Online Help

  • Deeplinking from External Source Like E-Mail: You can now launch the application with a specific page (region) being displayed by adding "jhsTaskFlowName" as parameter to the request URL.
    The value of "jhsTaskFlowName" should be set to a valid group name as defined in the application definition. Any other request parameters will be set as taskflow parameters.
    For example the following URL will start the application with the Employees taskflow, displaying employee with employeeid 110:

    http://127.0.0.1:7101/MyJhsTutorial/UIShell?jhsTaskFlowName=Employees&rowKeyValueEmployees=110
  • Ability to Call Business Method from Button: There is a new item level property Method Call where you can select a method from the list of application module methods that have been added to the client interface.
    Using item parameters, you can specify the method arguments. The return value of a method call can easily be displayed in an unbound item using a simple EL expression. See section 6.10.3 "Executing a Button Action" in the JHeadstart Developer's Guide for more information.
  • Requery when Entering Task Flow: The group-level combobox property Requery Condition has a new allowable value "When Entering the Task Flow" to ensure the latest data are queried when the user enters a task flow. As before, you can still enter a custom boolean EL expression in this property as well.
  • Additional Item Properties: There is a new item property "Additional Properties" where you specify additional properties that are added to the ADF Faces
    Component generated for the item. See section 12.4.4 "Adding Custom Properties to a Generated Item" in the JHeadstart Developer's Guide for more information.
  • New Custom Properties: You can now specify 5 custom properties against region containers, item regions and group regions.
  • Easier Taskflow Customization: Most of the content of the bounded taskflow Velocity template for a top group (groupAdfcConfig.vm) has been refactored into separate templates to make customization of generated bounded taskflows easier and faster. Placeholder (empty) templates to easily add custom managed beans, custom taskflow activities and custom control flow rules have been added as well. See section 12.5 "Customizing Task Flows" in the JHeadstart Developer's Guide for more information.
  • Easier File Generation Customization: The fileGenerator.vm now uses logical template names instead of hardcoded template paths to generate files. You can now use the Application Definition Editor to create a custom template for a specific file, just like all other templates. In addition, to prevent generation of a file, you can set the template to default/common/empty.vm, the file generator will no longer create files with empty content. See section 12.6 "Customizing Output of the File Generator" in the JHeadstart Developer's Guide for more information.
  • Better Support for ADF Libraries: A new paragraph (2.4) in the JHeadstart Developer's Guide describes JHeadstart-specific steps to take when using ADF Libraries. In addition, it is now possible to "import" JHeadstart service definitions from other projects that are packaged as ADF Library so you can reference JHeadstart groups in other projects in the JHeadstart Application Definition editor of the project that contains the ADF libraries with JHeadstart-generated content. See section 2.4 "Packaging JHeadstart-Generated ViewController Project as ADF Library" in the JHeadstart Developer's Guide for more information.
  • Use of ADFLogger: The JHeadstart runtime classes now use the ADFLogger instead of Log4j. The ADFLogger nicely integrates with WebLogic, allowing you to configure log levels dynamically at runtime and monitoring log messages from specific threads. To see all JHeadstart debug messages during development, go to the WebLogic log window in JDeveloper, click on the "Actions" dropdown list and choose "Configure Oracle Diagnostic Logging". Now add a persistent logger with name "oracle.jheadstart" and log level "INFO". You can do this while Weblogic is already running.

For a complete list of all existing features, use this link.

Categories: Development

Hidden gems in JHeadstart runtime

Wed, 2010-11-24 00:15

JHeadstart is well known for its powerful generator and its rich collection of templates. What a lot of people don't know is that JHeadstart also has an extensive runtime library that can be very useful, even if you don't use the generator.

A great example is the DatabaseProcedure class. This class allows you to call a database procedure or function from your ADF application with only one or two lines of code! For the source code and more information on this class read Calling an Oracle database procedure from Java with only ONE line of code and Calling a database procedure with table input and output parameters from Java.

Categories: Development

How to Programmatically Disclose a Row in ADF Faces Table

Tue, 2010-10-12 23:53

If you have defined the detailStamp facet on an ADF Faces Table, you can disclose the content of this facet using the expand/collapse icon rendered at the beginning of the row.
Sometimes, you want to programmatically disclose this content, for example when the user adds a new row, it is convenient that alle inout fields in the detailStamp facet are displayed right away.

In ADF 10.1.3, the following code used to work:

RowKeySet rks = table.getDisclosureState();
rks.getKeySet().add(row.getKey());

In ADF 11, implementation has slightly changed. Since a tree binding is now also used to render plain tables, we need to pass in a list of keys, the key path. Unlike a tree or treeTable, the path is always one level deep, so we can create a list with just the key of the row we want to disclose:

RowKeySet rks = table.getDisclosedRowKeys();
List keyList = Collections.singletonList(row.getKey());
rks.add(keyList);

Note that when you actually use this code when adding a new row, the primary key must be pre-populated by the model. This is required anyway with the current ADF 11.1.3 release, as is documented in the JDeveloper release notes (JDeveloper 6894412).

Categories: Development

ADF Faces: How to Prevent Closing of Dialog When Pressing Enter Key

Tue, 2010-10-05 00:05

The af:dialog element supports a number of built in buttons that can be displayed at the bottom of the dialog. The type property governs which buttons are displayed, like OK/Cancel or Yes/No. If the type property is not set, an OK and Cancel button is displayed by default.
When using the built in buttons, the first button is the default button. If you press the Enter key the dialog will close because the default button action is executed.

If your dialog window contains an af:subform with a default command button, and the cursor is in an input component inside the af:subform, clicking enter closes the dialog, it does not execute the default command associated with the subform.

To solve this, you can set the type property to "none" and use the buttonBar facet to include custom OK and Cancel buttons.
Here is an example:

<af:popup id="p0" contentDelivery="lazyUncached" eventContext="launcher">
  <af:dialog modal="true" title="My Dialog" type="none" id="dialog2"
             resize="on" stretchChildren="first">
    <af:region value="#{bindings.myTaskflowWithSubForm.regionModel}" id="region2"/>
    <f:facet name="buttonBar">
      <af:group id="g1">
        <af:commandButton text="OK" actionListener="#{myDialogBean.handleOK}" id="cb1"/>
        <af:commandButton text="Cancel" actionListener="#{myDialogBean.handleCancel}" id="cb2"/>
      </af:group>
    </f:facet>
  </af:dialog>
</af:popup>

JHeadstart users who use JHeadstart-generated List of Values, will see this enhanced behavior in the upcoming 11.1.1.3 release, which means you can use the Enter key to perform a quick search in the LOV dialog window.

Categories: Development

ADF Faces: Avoid Use of &lt;jsp:include&gt; Tag!

Wed, 2010-09-29 00:50

When reviewing ADF applications, I frequently see ADF Faces pages that use the <jsp:include/> tag to include another ADF Faces page fragment.

This is really old-school JSP programming and should be avoided:

  • Component id's in the included page fragment might conflict with component id's in the base page.
  • You cannot use it as a partial source or partial target in partial page refresh
  • You cannot use JSF expression language in the <jsp:param/&gt since it was designed for JSP, not JSF
  • You cannot customize this tag using MDS

It is much better to use the native ADF Faces <af:declarativeComponent> tag, which is a first-class UI Component:
  • It is a naming container with its own id property, you will never have id conflicts with the page using the component
  • It has a partialTriggers property and can be specified as partial target component by other UI components
  • You can pass parameters using custom properties (see below) or the <f:attribute> tag, and you can use JSF expression language to specify parameter values.
  • You can customize the component using MDS

So, replace code like this:

<jsp:include page="/includes/myIncludeFragment.jsff">
  <jsp:param name="myParam" value="myValue"/>
 </jsp:include>

with this:

<af:declarativeComponent id="dc0" viewId="/includes/myIncludeFragment.jsff" myParam="myValue"/>

Note the use of custom property "myParam" inside the tag, this property should be defined as attribute in the declarative component definition as shown below:

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich" version="2.1">
    <af:componentDef var="attrs">
        <af:xmlContent>
            <component xmlns="http://xmlns.oracle.com/adf/faces/rich/component">
                <description>my fragment</description>
                <attribute>
                    <attribute-name>myParam</attribute-name>
                    <attribute-class>java.lang.String</attribute-class>
                    <required>true</required>
                </attribute>
            </component>
        </af:xmlContent>
        <!-- Actual content goes here-->
        <af:outputText value="#{attrs.myParam}"/>
    </af:componentDef>
</jsp:root>

Categories: Development

UIShell with Dynamic Tabs: Marking the Current Tab Dirty

Mon, 2010-09-27 20:26

THIS POST IS OBSOLETE, THE TECHNIQUE DESCRIBED BELOW HAS SOME ISSUES. A NEW AND BETTER IMPLEMENTATION IS DISCUSSED HERE:  http://blogs.oracle.com/jheadstart/entry/core_adf11_uishell_with_dynamic

The Dynamic Tabs UI Shell Template includes an API to mark the current tab as dirty or clean.
By marking a tab as dirty, the tab label will appear in italics, and when closing the tab, the end user will get an alert that pending changes will be lost. Nice functionality, but it is left to the ADF developer to write custom code to call this API.

In the upcoming 11.1.1.3 release of JHeadstart, we added support to automatically call this API by checking the data control state of the current tab. This is done using a custom phase listener, that contains the following code:

package oracle.jheadstart.controller.jsf.listener;

import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

import oracle.adf.controller.internal.binding.DCTaskFlowBinding;
import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.model.binding.DCDataControl;

import oracle.adf.view.rich.context.AdfFacesContext;

import oracle.binding.BindingContainer;

import oracle.ui.pattern.dynamicShell.Tab;
import oracle.ui.pattern.dynamicShell.TabContext;

import org.apache.log4j.Logger;

/**
* JHeadstart JSF PhaseListener.
* When using Dynamic tabs template, the current tab state is set to dirty or clean,
* depending on the state of the taskflow data control of the current tab
*/
public class JhsPhaseListener
implements PhaseListener
{

private static Logger sLog = Logger.getLogger(JhsPhaseListener.class);

public static final String PAGE_TEMPLATE_BINDING = "pageTemplateBinding";

@Override
/**
* While refreshing the curent tab seems more effective to do only just before render response
* it turns out that when closing a tab, and then returning to a dirty tab, the data control
* of the dirty tab is no longer seen as dirty, so we do it after the three phases that can
* change the state of the current tab: apply request values, update model values and invoke application
*/
public void afterPhase(PhaseEvent event)
{
if (event.getPhaseId() == PhaseId.APPLY_REQUEST_VALUES
|| event.getPhaseId() == PhaseId.UPDATE_MODEL_VALUES
|| event.getPhaseId() == PhaseId.INVOKE_APPLICATION)
{
checkCurrentTabDirtyState();
}
}

@Override
public void beforePhase(PhaseEvent event)
{
}

@Override
public PhaseId getPhaseId()
{
return PhaseId.ANY_PHASE;
}

public void checkCurrentTabDirtyState()
{
TabContext tabContext = TabContext.getCurrentInstance();
if (tabContext == null || tabContext.getSelectedTabIndex() < 0)
{
return;
}
BindingContainer bc =BindingContext.getCurrent().getCurrentBindingsEntry();
if (bc==null)
{
return;
}
DCBindingContainer pageTemplateBc =
(DCBindingContainer) bc.get(PAGE_TEMPLATE_BINDING);
if (pageTemplateBc == null)
{
return;
}
DCTaskFlowBinding tfb =
(DCTaskFlowBinding) pageTemplateBc.get("r" + tabContext.getSelectedTabIndex());
if (tfb == null || tfb.getExecutableBindings() == null ||
tfb.getExecutableBindings().size() == 0)
{
return;
}
DCBindingContainer taskFlowBc =
(DCBindingContainer) tfb.getExecutableBindings().get(0);
DCDataControl dc = taskFlowBc.getDataControl();
if (dc==null)
{
// no data control, we cannot detect pending changes
return;
}
boolean isDirty = dc != null && (dc.isTransactionDirty() || dc.isTransactionModified());
// calling covenience method markCurrentTabDirty adds content area as partial target,
// causing any popups currently displayed to be hidden again.
// Therefore retrieve current tab instance and call setDirty directly
// tabContext.markCurrentTabDirty(isDirty);
Tab tab = tabContext.getTabs().get(tabContext.getSelectedTabIndex());
if (tab.isDirty() != isDirty)
{
sLog.debug("Setting dirty state of dynamic tab with index " +
tab.getIndex() + " to " + isDirty);
tab.setDirty(isDirty);
AdfFacesContext.getCurrentInstance().addPartialTarget(tabContext.getTabsNavigationPane());
}
}
}

Just copy and past this code to create your own phase listener class, and register the phase listener in faces-config.xml like this (substitute with your own class name):


<lifecycle>
<phase-listener>oracle.jheadstart.controller.jsf.listener.JhsPhaseListener</phase-listener>
</lifecycle>

And make sure that the taskflows that are accessed through the dynamic tabs have the data-control-scope element set to shared.
That's all you need to do to enjoy this nice functionality.

Categories: Development

New: Reusable ADF Taskflows Generator!

Sun, 2010-09-26 11:11

Last week I attended Oracle Open World 2010. I was pleased to see how much focus there was on the Oracle Application Development Framework. With about 40 sessions, ADF was a major topic on this conference, as it should be!
Overall, the ADF sessions were of high quality and well attended. The drawback of so many sessions is overlap, sometime there were 2 or even 3 ADF sessions at the same time. For my session on JHeadstart, I had to compete with a presentation on functional patterns in ADF and an ADF hands on session. Thanks to a bit of twitter marketing and retweeting by JDeveloper, I nevertheless had about 35 people, while only 20 people preregistered for my session.
This time, I slightly changed the way I presented and positioned JHeadstart. In previous sessions I usually demoed for about 50 minutes, hurrying through the intro and wrap up slides. With earlier versions of ADF, my motto "seeing is believing" was enough, and the audience left mumbling things like "What you just showed me in 1 hour, has taken me 6 months to build".
Now, ADF11 is so impressive by itself, that I noticed somehow people start to think there is less of a need for JHeadstart. And of course, you can perfectly build ADF 11 applications without JHeadstart. But hey, don't you want to get things right the first time, and as fast as possible? Well, I do, and I am convinced that the above statement about saving 6 months is more true than ever with ADF11. ADF11 is immensely powerful when used in the proper way, following best practices, proven design patterns and advanced techniques. And this is the crux, despite more than 2000 pages of official documentation, and a couple of books on ADF, most of this info to really get it right is scattered around the web, in OTN articles and blogs of various ADF experts, or simply not yet documented.
It takes a couple of months before you figured it all out. Unfortunately, the typical project manager does not give you so much time, so you don't get it right the first time and you'll discover along the way that you should have chosen a different approach, applying other, more advanced techniques. And then you have a nasty choice to make: leave it as it is, a-less-functional-less-flexible-and-costlier-application to maintain, or go for a major refactoring......
Well, with JHeadstart you will get it right the first time! Which brings me to the title of this blog entry, I did a "major announcement" during my session, introducing the "Reusable ADF Taskflows Generator" (RATG). And the good news is, you don't have to wait for the next JHeadstart release to use it, it is already there in the current release! Only the name is slighty different: "JHeadstart Application Generator" (JAG). We have chosen the name JAG 8 years ago, when we launched JHeadstart, and ADF did not even exist. But RATG is probably a better name right now. Sure, JHeadstart still generates a complete and fully functional ADF web application, but the core of the application consists of highly reusable and highly configurable task flows.

The generated taskflows can be (re-)used

  • in a "traditional" tabbed menu (also generated with JHeadstart)
  • in the more modern "UI Shell with dynamic tabs". I demoed the excellent JHeadstart support for this pattern in the upcoming JHeadstart 11.1.1.3 release. (You can use the pattern already with current release, requires a bit of coding)
  • in handbuilt drag-and-drop pages, see the JHeadstart tutorial for an example
  • as a child in another parent region, minimizing duplication of UI logic. Again, see the JHeadstart tutorial for an example.
  • in combination with ADF Human workflow tasklist, deeplinking to the task specific object instance within the taskflow
  • in pop up windows. And again, see the JHeadstart tutorial for an example.
  • as WebCenter portlets
  • in WebCenter Composer allowing the end user to add taskflows at runtime

To enable all these reuse cases, the generated taskflows are highly configurable. They
can be configured
  • to start in create mode (displaying a new row)
  • to show one specific row (deeplinking)
  • initially launch a summary page or specific deeplink detail page
  • to hide action buttons (ike Save, Cancel, Browse)
  • to hide search region
  • to show in read-only mode

I also emphasized the concept of the generator templates, which allows you to customize anything you want. For example, you can easily customize the generator to add additional taskflow configuration options.
And if you don't care for 100% generation, you have the freedom to skip generation at any time, and proceed with the visual design editor in JDeveloper to finish off your pages.

I believe that this message of advanced design patterns, reuse, and superior productivity without compromizing on flexibility, was well understood by the crowd. And the demo although shorter was still impressive enough, showing off many of the built in features that will save you additional months of development time. The crowd was "sold" as a couple op attendees said at the end, and made clear in tweets from respected ADF experts like Chris Muir and Wilfred van der Deijl!

Yes, OOW10 was inspiring and provided me with new energy to blog about JHeadstart.
OOW10 made me realize we should communicate more about many of the smart ADF techniques used in JHeadstart. There are still way too many people not using it, ignorant of all the good stuff. So, keep an eye on this blog in the next weeks!

Slides of my presentation can be viewed and downloaded here.

Categories: Development

JHeadstart custom search with default values

Sun, 2010-05-30 00:15

JHeadstart has a powerful generator for ADF Faces pages. One of the features of the generator is the generation of search functionality into a page. The search functionality offers a Quick Search with a single search item and an Advanced Search for multiple search criteria. When generating search functionality with JHeadstart 11g a design decision has to be made whether to use the ADF Model or JHeadstart custom approach.

With the ADF Model approach the Quick- and/or Advanced Search is defined in the View Object using Query Criteria. The generated page uses a single component (<af:query> or <af:quickQuery>) that renders a complete search area. This approach is recommended if you

The JHeadstart custom approach uses meta-information in JHeadstart to generate the search areas. There is no need to specify something on the View Object. The generated search areas are composed by more page components which can be flexible arranged. This approach is recommended if you

  • have special layout requirements like organizing search items in groups using tabs
  • need to use the JHeadstart custom List Of Values because of your LOVs need multi-selection, detail disclosure or special layout requirements
  • want to keep you metadata in the JHeadstart application definition instead of in the ADF Business Components
  • want to customize your search

Often it would be nice to have initial values for the search items, but this is not supplied by JHeadstart by default. For customization reason I am using JHeadstart Search custom approach to add this functionality.

Based on the idea of the article by Lucas Jellema Using default search values on the JHeadstart advanced search the solution described here shows how to implement the feature of default values for search items. In this solution default values can be specified for both Quick- and Advanced Search. An additional "Default" button is added into the search region to manually apply the default values. In addition the default values are always set when the task flow starts e.g. when be called from the menu. The final pages will look like these:

Quick Search with Default button: JHSSearchDefaultQS.png

Advanced Search with Default button:JHSSearchDefaultAS.png

The demo application is based on the employee data of the HR demo database schema. Here are the steps to implement it.

  1. Create a new Fusion Web Application (ADF) and define an ADF BC Model with only one updateable Viewobject EmployeesView based on the table EMPLOYEES.

  2. Enable JHeadstart on the ViewController project and create a new Service Definition. Choose the following settings:

    • Quick Search Style=JHeadstart - Dropdown List
    • Advanced Search Style=JHeadstart - Same Page
    • Always use JHeadstart LOVs in JHeadstart search area: Checked

    For the other options accept the default values of the wizard.

  3. Define a default value for the item DepartmentId when creating new rows. This is not the definition for the default value of a search item but it will be used later for demo supplying a default value from the generated bean. Open the JHS Application Definition Editor navigate to group Employees and select DepartmentId in Items. Enter 50 to the property "Default Display Value".

  4. Generate the application and run it to see everything is working.

  5. Now it is time to add search with default values functionality. In this solution the default values will be supplied as managed properties of the search bean generated by JHeadstart. A new custom generator template needs to be registered on the Employees group in the application definition:

      SEARCH_BEAN = custom/misc/facesconfig/EmployeesSearchBean.vm
    

    In the custom generator template the new Search bean class and the managed properties are defined:

    <managed-bean>
      <managed-bean-name>${bean.beanName}</managed-bean-name>
      <managed-bean-class>
    com.jhssearchdemo.controller.jsf.bean.SearchBeanWithDefaultValues
    </managed-bean-class>
        ...
        <managed-property>
          <property-name>advancedSearchDefaultValues</property-name>
          <map-entries>
            <key-class>java.lang.String</key-class>
            <map-entry>
              <key>EmployeesDepartmentId</key>
              <value>
           #{pageFlowScope.EmployeesDefaultValues.defaultValues['DepartmentId']}
              </value>
            </map-entry>
            <map-entry>
              <key>EmployeesHireDate</key>
              <value>10-Apr-1997</value>
            </map-entry>
          </map-entries>  
        </managed-property>
        <managed-property>
          <property-name>quickSearchDefaultValues</property-name>
          <map-entries>
            <key-class>java.lang.String</key-class>
            <map-entry>
              <key>EmployeesLastName</key>
              <value>O*</value>
            </map-entry>
          </map-entries>  
      </managed-property>
    </managed-bean>
    

    Defining the managed properties as a Map allows to use the item name as key and the default value as value of the map entry. The item name is the name of the associated control binding generated for the page fragment. The value can be a constant or a reference to another bean. The Advanced Search default value for EmployeesDepartmentId shows an example how to reference a value from the default value bean for new rows.

    The new enhanced search bean has to supply managed properties to hold the default values and a method to apply the default values. The new class will extend the JHeadstart search bean class JhsSearchBean.

    package com.jhssearchdemo.controller.jsf.bean;
    public class SearchBeanWithDefaultValues extends JhsSearchBean {
        // Maps of default values
        private Map quickSearchDefaultValues;
        private Map advancedSearchDefaultValues;
        ...  // getter and setters
    
        /**
         * Appy default values to searchBean
         */
        @PostConstruct
        public void applyDefaultSearchValues() {
            sLog.debug("enter applyDefaultSearchvalues");
    
            Map criteria = super.getCriteria();
            sLog.debug("current criteria:" + criteria);
    
            // clear all search criterias
            super.clearSearchCriteria();
    
            DCBindingContainer container = getBindingsInternal();
    
            if (advancedSearchDefaultValues != null) {
                // Apply default values for advanced search
                sLog.debug("set advanced search items:" + 
                  advancedSearchDefaultValues);
                for (String searchItemName :
                     (Set)advancedSearchDefaultValues.keySet()) {
    
                    // copy default value only to items that exists
                    if (findSearchControlBinding(container, searchItemName) !=
                        null) {
                        Object asItemValue =
                            advancedSearchDefaultValues.get(searchItemName);
                        sLog.debug("set default value " + asItemValue +
                                   " for advsearch item: " + searchItemName);
                        criteria.put(searchItemName, asItemValue);
                    } else {
                        sLog.warn("search item for default value doesn't exist: " +
                                  searchItemName);
                    }
                }
                // super.getCriteria().putAll(advancedSearchDefaultValues);
            }
    
            // Apply default value for simple search
            if (quickSearchDefaultValues != null &&
                !quickSearchDefaultValues.isEmpty()) {
                // get first key from Quicksearch Map
                Set keyset = quickSearchDefaultValues.keySet();
                Iterator keyIter = keyset.iterator();
                String qsItem = (String)keyIter.next();
    
                sLog.debug("previous search item was " + getSearchItem());
                if (findSearchControlBinding(container, qsItem) != null) {
    
                    Object qsItemValue = quickSearchDefaultValues.get(qsItem);
    
                    // set Quicksearch item
                    sLog.debug("set quicksearch item: " + qsItem);
                    setSearchItem(qsItem);
                    if (qsItemValue != null && !"".equals(qsItemValue)) {
                        sLog.debug("set quicksearch item value: " + qsItemValue);
                        setSearchText(qsItemValue);
                    }
                } else {
                    sLog.warn("search item for default value doesn't exist: " +
                              qsItem);
                }
            }
            sLog.debug("exit applyDefaultSearchvalues");
        }
    

    The method applyDefaultSearchValues() clears the existing search criteria, looks up and applies the default search values from the managed properties. Take a note on the annotation @PostConstruct. JSF will fire the method applyDefaultSearchValues() when all managed properties are set. As the Search Bean is pageflow-scoped the method will be automatically applied every time the pageflow is entered like from a menu item. This way the default search values will be already set when entering the page. The method findSearchControlBinding() checks if the specified item name is valid (has a control binding with the same name).

  6. To manually invoke the method applyDefaultSearchValues() add a "Default" Button next to the Search button of the Advanced Search. The button has an actionListener to invoke the new method of the search bean. In the JHeadstart Application Definition Editor customize the template DO_ADVANCED_SEARCHED_BUTTON at group (Employees) level. Add the following at the end of the new template custom/button/doAdvancedSearchDefaultButton.vm:

    ...
    <af:commandButton textAndAccessKey="#{nls['FIND_DEFAULT']}"
        actionListener="#{#SEARCH_BEAN().applyDefaultSearchValues}"
        id="${JHS.current.group.shortName}AdvancedSearchDefaultButton"/>
    

    The same way create a new customized template DO_QUICK_SEARCH_BUTTON (custom/button/doQuickSearchDefaultButton.vm):

    <af:commandButton textAndAccessKey="#{nls['FIND_DEFAULT']}"
        actionListener="#{#SEARCH_BEAN().applyDefaultSearchValues}"
        id="${JHS.current.group.shortName}QuickSearchDefaultButton"/>
    
  7. Add the button label to the application resource file. Locate the resource file ViewController\src\com\jhssearchdemo\view\ApplicationResources_en.properties and add a new entry:

    FIND_DEFAULT=&Default
  8. Add the actionListener applyDefaultSearchValues to the search bean class. Note that there is already a method applyDefaultSearchValues in the search bean class but not with the rigtht signature for an action listener. Adding a small wrapper will help:

        /**
         * Wrapper to set default values with action listener
         * @param evt
         */
        public void applyDefaultSearchValues(ActionEvent evt) {
            applyDefaultSearchValues();
        }
    
  9. Generate the application again, compile and run it. Navigate to the Employees tab to see the new button "Default" in the Quick Search. Also the default search item "Lastname" and value "O*" is shown. Change the search item and/or value and apply the new "Default" button to initialize the search again. Execute the search to verify that it works.

    The same functionality is available in Advanced Search. Once the search is initialized either manually or by the annotation both Quick Search and Advanced search is defaulted. The reason is that the method applyDefaultSearchValues() set the default values for both Quick Search and Advanced Search. If this is not desired the method can be splitted into default values for Quick Search and Advanced Search. Two separate action listeners can invoke these methods.

That's it. You can download a sample workspace that illustrates the solution here.

Categories: Development

JHeadstart 11g Evaluation Version Now Available!

Thu, 2010-04-22 22:22

Oracle JHeadstart 11g went production two months ago. As of today, a fully functional evaluation version is available for everyone. It can be installed through the JDeveloper Check for Updates facility, by choosing the Open Source and Partners Extensions Update Center.
The evaluation version contains the same functionality as the production version, with two limitations: the JHeadstart Forms2ADF Generator is not included, and the workspace cannot contain more than 10 View Objects.

The comprehensive JHeadstart tutorial initially written by Steve Muench has been revised and extended for release 11g. If you quickly want to get insight in the added value of JHeadstart 11g, then the tutorial is the place to start. I believe that even seasoned ADF developers are likely to be impressed by the functionality, productivity gains and best practices JHeadstart 11g brings to the table, and which are highlighted in this tutorial.

The JHeadstart Product Center on OTN includes a lot of new material, including an updated feature list, new overview presentations and online demonstrations of the JHeadstart Forms2ADF generator.

Categories: Development

Oracle JHeadstart 11.1.1 Technical Preview 2 Now Available

Tue, 2009-08-11 23:17

Oracle JHeadstart 11.1.1 Technical Preview 2 is now available for download (build 11.1.1.0.46).
This release is compatible with JDeveloper 11 release 1 (11.1.1.1.0), as well as with the two JDeveloper Boxer releases (11.1.1.0.1 and 11.1.1.0.2).
Customers who own a JHeadstart supplement option license can download it from the Consulting Supplement Option portal.

An evaluation version of JHeadstart 11.1.1 is not yet available. We plan to make an evaluation version available in the fall of calendar year 2009.

In addition to many small enhancements, the following features have been added to the second technical preview:


  • Support for Stretching Layouts: JHeadstart now fully supports stretching options for ADF Faces Rich Client components.
    Through a new group-level property Enable Stretching, you can stretch the generate group content to fill the available space. Whether or not stretching
    will actually occur depends on some additional conditions that must be met. See the help description of this new group property in the application definition editor, and the
    JHeadstart Developer's guide for more info.

  • New Table Overflow Styles: The Table Overflow Style group property has two new allowable values: 'Right with Splitter' and 'Below with Splitter', which are
    useful settings when you want to generate multiple panes with stretching layouts that adjust based on the position of the splitter.

  • New Allowable Values for Same Page Display Position: The Same Page Display Position group property has two new allowable values: 'At the Right of Parent Group with Splitter'
    and 'Below Parent Group with Splitter', which are useful settings when you want to generate multiple panes with stretching group layouts that adjust
    based on the position of the splitter.
  • New Allowable Values for Region Container Layout: The Layout property of a region container has two new allowable values: 'Horizontal with Splitter'
    and 'Vertical with Splitter', which are useful settings when you want to generate multiple panes with stretching region layouts that adjust
    based on the position of the splitter.
  • Ability to Add Bindings to PageDefinition using Velocity Templates: It is now possible to add bindings and iterators to the page definition using
    custom velocity templates. Here are some examples:

    ${JHS.pageDefGenerator.addBinding($JHS.page,"myBinding","#CUSTOM_BINDING()")}
    ${JHS.pageDefGenerator.addExecutable($JHS.page,"myIterator","#CUSTOM_BINDING()")}
    ${JHS.pageDefGenerator.addParameter($JHS.page,"myParam","#CUSTOM_BINDING()")}


    The custom binding macro simply contains the XML you want to add to the page definition. This macro can be defined within the same
    velocity template.
  • Flex items: The 10.1.3 functionality of Flex Items (items added dynamically at runtime) is now re-implemented for release 11. The region that
    contains the flex items is now a reusable task flow, providing you with more flexibility and re-use of code.

  • File up/download: File upload, file download and display of images is now supported in release 11. It supports Intermedia (ORDSYS) column types, as well
    as BLOB column types

  • XML Reformatting: There is a new application-level property Reformat all XML Files which will reformat all generated XML files (except for the page definitions),
    giving you more readable and consistent files accross your application.

  • Upgrading from 10.1.3: When opening a 10.1.3 application definition file, JHeadstart will migrate this to release 11 upon your approval.

Click here for a list of features added in the first technical preview:

For a complete list of all existing features in JHeadstart 10.1.3, use this link.

Categories: Development

Pages