JDev 12.1.3: Use Default Activity Instead of the Deprecated Invoke Action

Since JDeveloper 12.1.3 the invoke action used in earlier version has been deprecated. Users still using the old invoke action to load data on page load should migrate their code to using the default activity in a bounded task flow instead. This article describes how to use the executeWithParams method as a default activity in a bounded task flow (btf) to load data to be shown in a region. For this we implement a common

Use Case:
in a text field the user enters a string which should be used to look-up data in the DB and show the data as a table in a region.
For this we use the HR schema and build a look-up for locations after the name of the city of the location. In a page the user can insert the name or part of a cities name into a text field. This input is send as parameter to a bounded task flow. The default activity of the btf calls a method in the view object which uses a view criteria to search for cities starting with the given input data. In a second implementation the same technique is used but a where clause is used in the VO and the VO is called with executeWithParams. The result of the search is displayed as a table in a region.

Implementation

Model Project:
We start by creating a new ‘Fusion Web Application’ and creating a model project of the HR DB schema. Here we only use the location table for which we create entity object and view object.
Now we create the view criteria which we use to find locations by part of the city name.

Next step is to create the java class for the view object including the method to safely access the created bind variable. In the class we add a method to apply the created view criteria which we expose in the client interface well as the methods to access bind variables.


Finally we have to make sure that the locations view object is part of the data model of the application module.
Resulting Application Module Data Model

Resulting Application Module Data Model


Next we add another view object to the data model which we use to implement the use case a second time. This time we use the view criteria we defined in the view object LocationsView and select it as the default where clause.

ViewController Project:
We start implementing the view controller project by first adding a start page, ‘Start’, to the unbounded task flow in adfc-config.xml. For this page we use a quick layout (One Column, Header stretched).

After opening the page (which creates it) we add a third grid row to the panelGridLayout we got from the quick layout which later holds the result table. In the first grid row we add a captain for the page, ‘Execute with param sample’, the second grid row we add an af:inputText which holds the users input for the city name to search for.
The page looks like

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html>
<f:view xmlns:f="http://java.sun.com/jsf/core" xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
    <af:document title="Start.jsf" id="d1">
        <af:form id="f1">
            <af:panelGridLayout id="pgl1">
                <af:gridRow height="50px" id="gr1">
                    <af:gridCell width="100%" halign="stretch" valign="stretch" id="gc1">
                        <!-- Header -->
                        <af:outputText value="ExecuteWithParams Test" id="ot1" inlineStyle="font-size:x-large;"/>
                    </af:gridCell>
                </af:gridRow>
                <af:gridRow height="50px" id="gr2">
                    <af:gridCell width="100%" halign="stretch" valign="stretch" id="gc2">
                        <!-- Content -->
                        <af:inputText label="City" id="it1" value="" autoSubmit="true"/>
                    </af:gridCell>
                </af:gridRow>
                <af:gridRow id="gr3">
                    <af:gridCell id="gc3">
                        <!-- REGION HERE -->
                    </af:gridCell>
                </af:gridRow>
            </af:panelGridLayout>
        </af:form>
    </af:document>
</f:view>

Now we create a pageDefinition for the page, where we define a variable and an attribute binding which holds the users input into the inputText we added to a grid row below the header.


The final inputText look like

<af:inputText label="City" id="it1" value="#{bindings.searchCityName1.inputValue}" autoSubmit="true"/>

As you see we set the autoSubmit property to true as we don’t have (and need) a button to submit the data to the binding layer.

The next task is to create a new bounded task flow which has one input parameter, which is used to search for locations with cities starting with the given parameter from the inputText component.

Once the bounded task flow is created we can drag this btf onto the start page and drop it in the girdCell in the third gridRow and wire the parameter for the task flow to the value we have stored in the in the variable iterator via the inputText.

Finally we make the region refresh whenever the inputParamter of the task flow changes by setting the regions refresh property to ‘ifNeeded’.
The final ‘Start’ page layout looks like

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html>
<f:view xmlns:f="http://java.sun.com/jsf/core" xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
    <af:document title="Start.jsf" id="d1">
        <af:form id="f1">
            <af:panelGridLayout id="pgl1">
                <af:gridRow height="50px" id="gr1">
                    <af:gridCell width="100%" halign="stretch" valign="stretch" id="gc1">
                        <!-- Header -->
                        <af:outputText value="ExecuteWithParams Test" id="ot1" inlineStyle="font-size:x-large;"/>
                    </af:gridCell>
                </af:gridRow>
                <af:gridRow height="50px" id="gr2">
                    <af:gridCell width="100%" halign="stretch" valign="stretch" id="gc2">
                        <!-- Content -->
                        <af:inputText label="City" id="it1" value="#{bindings.searchCityName1.inputValue}" autoSubmit="true"/>
                    </af:gridCell>
                </af:gridRow>
                <af:gridRow id="gr3">
                    <af:gridCell id="gc3">
                        <af:region value="#{bindings.showlocatiobycitybtf1.regionModel}" id="r1"/>
                    </af:gridCell>
                </af:gridRow>
            </af:panelGridLayout>
        </af:form>
    </af:document>
</f:view>

This concludes the first implementation and we can run the application

The sample application can be downloaded form ADFEMG Sample Project. It contains a second page (Start2) which uses the other view object (LocationsWithParamsView) inside the region. It’s build like the first version. The difference is that the default activity nor is the executeWithParams from the VOs operations instead the self implemented method from the VO. You spare writing the method and exposing the method in the client interface this way.
Be aware that the sample uses the HR DB schema and you have to change the connection information to point to your DB.

JDeveloper 12.1.3: Using File Templates

Since JDeveloper 12.1.2 Oracle added a feature called ‘File Templates’. Only there was absolutely no documentation for this. We only had the ‘File Templates’ node in the preferences. I filed a bug (ADFEMG-150) for this.
In the current JDeveloper 12.1.3 release the ‘inital’ documentation for the ‘File Templated’ has been added.
To get to the ‘File Templates’ via the Tools->Preferences->’File Tempalates’ and see the below image.

File Templates in Preferences

File Templates in Preferences


Loading the extension you get
FileT emplates Inital Dialog

File Templates Inital Dialog


The only help I found can be reached by clicking the Help button in the dialog which will get you
File Templates Help

File Templates Help


This is not much to work with. I you find more help on using this feature, drop me a note, please. All I present in this blog was found out using try and error. There seams to be a difference if you use a Windows or Unix based machine. Later in the blog I’ll give more info on this.

Let’s start with my findings. Clicking through the tree shown in the image above you quickly get the intention of the file templates. This feature allows us to define template for files (e.g. java classes) which can be used to define repeating code and generate the files from it. The sample which is provided by Oracle builds a template for a java class containing copyright and licence information.


However, there is no button or menu to create your own template from scratch. The pencil icon in the top right corner is disabled for each of the files. The only way to create a new template file is to copy an existing one by using the ‘Copy’ button. The first time you click the copy button for one of the files in the you get a note that you can’t change the files in place:
Confirm Modify Template

Confirm Modify Template


confirming the dialog with yes, a copy the content of the sample template from the jar will be created into a file you can edit. All custom template files are written to system12.1.3.0.41.140521.1008\o.jdeveloper.filetemplate\ folder by default. While copying the files you can change the ID, description, the Name and the file name of the template.

Please not the properties in the dialog which allows to define where you later find the template in the gallery.
Once we have copied all files from the tree we can start to modify them. The file suffix of the templates is ‘ftl’. The copied files are automatically opened in the JDev editor. Here comes the first glitch in the extension. If you change *.ftl files in the JDev editor and hit the ‘Save All’ button, the files are not saved. The caption of the tabs remains italic, meaning that the content of the tab has changed and is not saved. You need to hit the ‘Save’ button to save each file by itself.
Once the templates are copied into an accessible path, you can use the ‘Pencil’ button to open them again in the JDev editor, or you can make small changes directly in the editor window in the dialog.
Looking at the content of the files you see that ‘copyright-hahn-java.ftl’ inludes ‘license-hahn-txt.ftl’ which then includes ‘copyright-hahn-content.ftl’. This is the first file we change to change the copyright notice
Changed Copyright Text

Changed Copyright Text


To make the licence ‘license-hahn-txt.ftl’ pick up the changes copyright text we have to change the include statement in the licence template
Change Include  of Copyright in Licence Template

Change Include of Copyright in Licence Template


and finally we have to change the ‘copyright-hahn-java.ftl’ to pickup the changes licence template
Change Include of Licence in Template

Change Include of Licence in Template


After saving all changes (remember to save each file separately) we can test the template. For this we select a package in a project, right click the package we want the file created in and select ‘New’->’From Gallery…’
Select 'New'->'From Gallery...'

Select ‘New’->’From Gallery…’


When we save the java call template we saved the information where the template shows up via the ‘Category’, ‘Folder’ and ‘Feature’ properties of the template dialog (these properties define where the template shown up in the gallery). Select ‘Java’ and you should see
Select the Template from the Gallery

Select the Template from the Gallery


Please notice the name which is the ID we chose for the template and the description which comes from the save dialog too. Select the template and you get the file save dialog
File Save Dialog

File Save Dialog


In the JDev editor you get the generated java class
Generated Class from Template

Generated Class from Template


Please note the error in line 26 of the generated java class

package de/hahn/blog/test1213/.model/adfbc/;

should be

package de.hahn.blog.test1213.model.adfbc;

This only happens on Windows machines, Unix machines generate the right package statement. You have to correct this yourself. I’ll file an bug this.

Now that we have seen this sample, let’s ask what’s missing.

    1) Documentation: if you look at the templates you seethe usage of variables in the templates like ‘${name}’ or ‘${package}’, however, I could not find if there any other valuables as the once you see in the sample. Same is true for the language behind the template mechanism. The sample show some kind of ternary operator, question is what other options do we have. The file suffix ‘.ftl’ and some other information I gathered for this blog post, suggests that the templates are using a tool named ‘FreeMarker’.
    2) Use cases: I would like to use templates at other points like java classes generated for ViewObjectImpl, EntityObjecImpl or ApplicationModuleImpl. This is not possible right now. It would be handy e.g. to generate files with ADFLogger directly implemented. You can insert the ADFLogger into the class using the template, but as this is only done for classes you create via the template most of the other generated classed need to be changed by hand.
    3) applying the template to an existing class is not possible. If you like a copyright statement in each class you can’t attach it from a template.

Problem Installing MAF on WIN 7 64bit System

Aside

The documentation states that installing JDeveloper 12.1.3 on a Windows 7 system (32 or 64) requires administrators rights (Select an Installation User). This is a known fact.
A side effect on my Windows box was, that installing ‘Mobile Application Framework’ (MAF) failed. When I tried installing MAF on my Win 7 laptop via ‘Check for updates’ and confirming the dialog which ask for a restart of JDeveloper, it never came back on. Using the task manager, it turned out that JDeveloper started but that there are other processes waiting for something.
Using some System Internal’s tools I found out that Jdev started opatch to install a needed patch before applying the MAF extension. As the processes are started from Jdev internally, it’s kind of hard to find out the real problem. Readings the doc and searching the file system found a log file, opatch writes into the opatch log folder. The information from this log is that opatch can’t lock or create a folder needed for internal use.

[04.07.2014 19:49:58]        OUI-67064:OPatchSession kann den Bestand für das angegebene Oracle-Standardverzeichnis nicht laden R:\JAVA\12130~1.0\ORACLE\MIDDLE~1. Mögliche Ursachen sind:
                                Keine Lese- oder Schreibberechtigung für ORACLE_HOME/.patch_storage
                                Zentrales Bestandsverzeichnis ist von einer anderen OUI Instance gesperrt
                                Keine Leseberechtigung für zentrales Bestandsverzeichnis
                                Die Lock-Datei ist in ORACLE_HOME/.patch_storage vorhanden
                                Das Oracle-Standardverzeichnis ist in dem zentralen Bestandsverzeichnis nicht vorhanden
[04.07.2014 19:49:58]        OPatch will clean up 'scratch,backup' directories.

Here is the english message

[04.07.2014 19:57:34]       OUI-67064:OPatchSession cannot load inventory for the given Oracle Home R:\JAVA\12130~1.0\ORACLE\MIDDLE~1. Possible causes are:
                                No read or write permission to ORACLE_HOME/.patch_storage
                                Central Inventory is locked by another OUI instance
                                No read permission to Central Inventory
                                The lock file exists in ORACLE_HOME/.patch_storage
                                The Oracle Home does not exist in Central Inventory

The problem is that installing Jdev as administrator put rights onto the file system (Understanding User Permissions) which prevents creating and locking the folder for the normal use running Jdev. This fact can be found in the doc too

When managing a product installation (for example, applying patches, or starting Managed Servers), you must use the same user ID as was used to perform the initial product installation.

To fix the problem start Jdev as administrator and the installation of the MAF extension should work.

JDev 12.1.3 Reorder Fields in Query Panel Clarification

Aside

Reading the ‘What’s new in this release’ document, I found

Reorder Fields in Query. Added ability to reorder fields in Query search panel.

I thought that we now can change the order of the fields in the af:query component at design time, like in an af:gridLayout, and started searching the documentation.
Sadly it turned out that this is not a design time option, as I thought, but a run time option!
This is documented at ‘33.2 Creating Query Search Forms’. Below you see the images from a query in advanced mode with the reorder button (down right) and the reorder dialog.


To reorder the fields at design time you can only use the technique blogged by Luc Bors ADF 11g: Change attribute order in query component

My Personal Bug Parade of JDev 12.1.2 fixed in JDev 12.1.3

Last week (June, 26th 2014) JDev 12.1.3 arrived, today (June, 30th 2014) the ADF Mobile Extension for 12.1.3 was published. You can get it via the menu Help->”Check for Updates…”
However, the first thing I did over the weekend was to check my personal bug parade.
In the list below you see the bugs and there status
UPDATE (July, 18th 2014): Added ADFEMG-118

Bug Status Info
ADFEMG-118
af:poll with interval set to 5000 and timeout set to 5001 doesn’t stop polling after on roundtrip
OPEN The behavior has changed but still not as expected. You still get refresh events after the timeout.
ADFEMG-120
JDeveloper 11.1.1.7.0: can’t create af:tree or af:treetable on a jspx page
OK
ADFEMG-149
JDeveloper 12.1.2.0.0: Completion Insight doesn’t show javadoc for ADF classes
OK without the ADF source code, which you can get filing a SR with support.oracle.com (payed support contract needed), you only see a notice that ‘No ducumentation is available’ instead the api java doc.
ADFEMG-150
JDeveloper 12.1.2.0.0: Missing documentation for usage of ‘File Templates’
OK
ADFEMG-154
JDeveloper 12.1.2.0.0: Completion Insight ‘ctrl-space’ doesn’t do a ‘Declaration Insert’
OK
ADFEMG-156
AttributeValues assigned to variables iterator loose their assigned iterator after clicking on other attribute values in the same pageDef
OK There are some hints that this bug is somehow not fixed for all circumstances. However, my test case works out OK. Whenever someone has a reproducible test case I reopen the bug. Please drop a note then.
ADFEMG-157
JDeveloper 12.1.2.0.0: Filter on af:table doesn’t show up if VO is only based on a SQL query
OK
ADFEMG-159
JDeveloper 12.1.2.0.0: ViewCriteria editor behavior differs from 11g and generated SQL from VC is suboptimal
OK
ADFEMG-160
JDeveloper 12.1.2.0.0: Property Inspector changes properties of not selected component
OK
ADFEMG-179
JDeveloper 12.1.2.0.0: ViewObject with hidden bind variable in where clause crashes application module tester
OK
ADFEMG-189
JDeveloper 12.1.2.0.0: af:inputFile with multiple files to upload duplicates files
OPEN

Good work! Only one bug didn’t make it into the first 12.1.3 release!

Working through all the test cases was kind of fun. My impression of the product is that it’s stable and easy to use. OK, I had no time playing around with the new features. This will be my task in the next weeks. Stay tuned for more on JDeveloper 12.1.3.

JDeveloper 12.1.3 is out!

Oracle JDeveloper 12cR1 aka JDeveloper 12.1.3 finally arrived. We had to wait almost a year for this version.
From my first day working with it I can say that it was time well spent. Some nasty bugs from version 12.1.2 are fixed, others still need checking. This will take me a couple of days.
I spare you listing all new features which you can find at ‘What’s new’.

You can download the version from the JDev home page.

Interestingly there are only three install packages, one for Windows, one for Linux and the generic installer. The platform specific install packages are only for 64 bit systems. A look into the certification matrix shows that 32 bit systems are only listed under ‘Other Operating Systems’. I’m not sure if this means that you can’t run this version on 32 bit Windows, or if 32 bit Windows is just ‘others’. I don’t have a 32 bit OS available, do I can’t test this. However, to install on a 32 bit system you have to download the generic installer (size 1.8GB).

The installation went smooth, under 1 minute on my 64GB i7 server with a big SSD running Ubuntu 14.04!
Be advised that some things in the configuration have changed. Stuff you are used to change in Jdev.conf (like jdk) has been moved to a new file product.conf which is stored at your home/.JDeveloper folder. This makes it easier to change the configuration like setting the ide.user.dir and some memory options. More information on this can be found in the ‘Installation Guide’.

It’s going to be a busy weekend checking out all the new stuff. Have fun using Jdev 12.1.3!

Book Review: Oracle ADF Faces Cookbook by Amr Gawish

During my short vacation I spend some time reading books. One of them was ‘Oracle ADF Faces Cookbook’ by Amr Gawish (http://bit.ly/PhWTlR).

Oracle ADF Faces Cookbook

Oracle ADF Faces Cookbook


The book is written as a cookbook, as the name says, for ADF Faces in the version 12c (12.1.2.0.0 to be accurate). The book offers 10 chapters:

  1. Building Your ADF Faces Environment From the Ground Up
  2. Here you get information about how to install JDK 1.7, Oracle XE Database, JDeveloper and how to tune the environment to work best together. Finally you can download the code used throughout the book from a GIT repository.Make sure to download the code and have it ready while reading the book!

  3. Getting Started with ADF Faces and JDeveloper
  4. In this chapter you get the very basics about development of Fusion Web Applications, building an workspace, connection to the DB, creating a business service, defining page flows and pages and how to run an ADF Faces application from within JDev.

  5. Presenting Data Using ADF Faces
  6. Here we start with use cases used for presenting data. You get info on how to present single records and different master – detail use cases, using different techniques. Finally a first glance on internationalization.

  7. Using Common ADF Faces Components
  8. Here you get a walk through to the normal adf faces components for input, output, selection, loading of data as well as pop-up, code editor, menu model, links, trains and dynamic components.

  9. Beautifying the Application Layout for Great User Experience
  10. Is about page templates, skins, responsive design and flat design techniques.

  11. Enriching User Experience with Visualization Components
  12. This chapter handles maps, graphs, gauges, Gantt charts, hierarchy, sunburst and timeline components.

  13. Handling Events and Partial Page Rendering
  14. Here events (client and server), partial triggers and behavior components are introduced. Polling, Drag & Drop, Active Data Service and WebSocket are described too in this chapter.

  15. Validating and Converting Inputs
  16. Is about conversation of data, custom converters, validation (client and server) and faces messaging.

  17. Building Your Application for Reuse
  18. Picking up from chapter 2 we learn about page templates, exception handling task flow parameters, contextual events, ADFLibraries and finally Meta Data Service (MDS).

  19. Scaling your ADF Faces Application
  20. The final chapter is about performance and recommendations as well as some advances options like Content Delivery Network (CDN) and ADF caching of resources.

The cookbook uses its own db schema which looks kind of familiar, as it’s build from the well known HR schema.

While reading the book I found some recipes hard to understand for novice developers, without reading the provided code in parallel. This is because the book is all about ADF Faces but spares most about the ADF Business Components Model layer. Here the reader has to know how things are working and how to set things up.
For experienced developers some of the covered topics are nothing new, we work with them every day. The uses cases covered are mostly basic in nature and you often see links to the original documentation. Here you find the missing information which is not covered in the cookbook itself. I would have liked some more deep going information on how properties work together for some often used components like af:table or af:panelGridLayout.

I personally found it hard to understand why the author used task flows build from pages for some of the use cases just because ‘it’s easier’. One of the main advantages are task flows build of fragments. They allow reuse and help divide a task into smaller pieces. Tools like the ADF-EMG Task Flow Tester are not even mentioned. Using this tool makes it easy to run task-flows build on fragments without the need to build a JSF Page to host the region.
There are no use cases which handle region specific questions like when regions are refreshed or how regions are restarted. Transaction management and data control sharing are not covers too.

The real interesting part of the book starts with chapter 5, where page templates, skins and at least some layout techniques are introduced. Very interesting is the use case about using SAAS (Syntactically Awesome Style Sheets) and Compass to build more dynamic css files which can be used in ADF. The chapter covers Responsive Web Design and Flat Design Techniques (which are trying to minimize the design) too.

Also interesting are the samples which are build in chapter 6 for graphs, gauges, maps, pivot table, Gantt charts (calendar is missing), timeline and sunburst. However I personally find them hard to digest as they have many ingredients (steps in this case) which you have to follow. Again the model layer is pre-build for you, which means you have to find out yourself how and if there are something special in the model to cook the dish. Nevertheless, samples in this area are hard to find, and these samples do work!

The chapter about event handling and ppr is a very nice summary of how things work in ADF. Easy to understand samples are making it easy to follow the concepts. Here you find samples for ADS (Active Data Service) and WebSocket too. Nice!
Contextual events are handled in a later chapter (‘Building Your Application for Reuse’) but they are not described in great detail. It’s enough to get a first impression.

The final chapter is a nice summary of performance increasing methods and techniques which is worth reading. After reading the techniques it make sense to test them on your system!

Summary:
Novice developers learn basic ADF Faces techniques and components by building samples. Some recipes are too complicated to understand by just reading them. As the book uses its own DB schema you should have this ready, as well as the code, to work through them.

JDeveloper 11g R1: Advanced Multi Column Table Sort

A question on the JDeveloper and ADF Community Space found my attention. A user asked how to sort an af:table after more then one column.
Well, there is the official way, which Frank Nimphius’s bloged about in ‘Declarative multi-column sort for ADF bound tables’.
However this declarative approach needs the user to select the columns and their sort order. In most cases the sort after a second column is driven by the use case specification. A sample would be that the departments tables should normally be sorted after the column selected by the user, but then the data should always be sorted by the department name inside the first sort.
The image below shows the Departments table sorted first after the LocationId and inside the LocationId sorted by the DepartmentName.

Departments sorted after LocationID and DepartmentName

Departments sorted after LocationID and DepartmentName

Now lets see how to implement this. There are some possible solutions:

  1. add a sort criterion in a managed bean
  2. add a sort Criterion in the ViewObject
  3. a combination of 1) and 2)

All solutions have their advantages and disadvantages. Let’s start with the managed bean approach. This is pretty simple as we only need to add sortListener to the af:table which is pointing a bean method. In the sample below we are using the departments table where we wire up the secondary sort to the DepartmentName column.

<af:table value="#{bindings.DepartmentsView.collectionModel}" var="row" rows="#{bindings.DepartmentsView.rangeSize}"
...
    sortListener="#{DepartmentSearchBean.sortTableListener}">
...

And the sortTableListener in the bean

    public void sortTableListener(SortEvent sortEvent) {
        //log the selected column (just for information)
        List<SortCriterion> criteria = sortEvent.getSortCriteria();
        for (SortCriterion sc : criteria) {
            logger.info("Sort after: " + sc.getProperty());
        }
        // Create new SortCriterion for DepartmentName in ascending order
        SortCriterion scNew = new SortCriterion("DepartmentName", true);
        // Add it to the list
        criteria.add(scNew);
        // and apply it back to the table
        Object object = sortEvent.getSource();
        RichTable table = (RichTable) object;
        table.setSortCriteria(criteria);
        logger.info("----------------------END----------------------");
    }

That’s all we need to do to get the output from the first image. You’ll notice, that both columns are showing the sort icon. Only the one for the DepartmentName can’t change to descending order as we wired things up to always sort in ascending order. From the users point of view this can be disturbing as it’s not obvious why this happens.

For the second solution we use the model layer instead of the view layer. Here we implement the ViewObjectImpl class of the EmployeesView and overwrite the setOrderByOrSortBy(…) method. This is the method the framework calls when you click on a header on the table to sort it.
Now we can hard wire the secondary sort column, as we did in the managed bean. However, let’s think about how to make this more flexible. A nice add on is that we can use the custom properties of each table attribute to define the secondary sort column. This way we can decide which columns to sort after for each of the attributes available. We can even decide to add more then one column for secondary and third sort.

The overwritten setOrderByOrSortBy method looks for the custom property named ‘SECONDARY_SORT’ and if found, creates a new SortCriterion with the column name give in the custom property. This new sort criterion is then added to the list of SortCriteria.

    @Override
    public String setOrderByOrSortBy(SortCriteria[] sortCriteria) {
        SortCriteriaImpl scNew = null;
        // iterate current sort criteria
        for (int i = 0; i < sortCriteria.length; i++) {
            logger.info("Sort: " + sortCriteria[i].getAttributeName());
            // check for SECONDARY_SORT propertie on each attribute
            int attributeIndexOf = this.getAttributeIndexOf(sortCriteria[i].getAttributeName());
            AttributeDef attributeDef = this.getAttributeDef(attributeIndexOf);
            Object object = attributeDef.getProperty("SECONDARY_SORT");
            if (object != null) {
                logger.info("Secondary sort:" + object.toString());
                scNew = new SortCriteriaImpl(object.toString(), false);
            }
        }

        if (scNew != null) {
            // Create a new array for the added criteria
            SortCriteria scNewArray[] = new SortCriteria[sortCriteria.length + 1];
            for (int j = 0; j < sortCriteria.length; j++) {
                scNewArray[j] = sortCriteria[j];
            }

            // add the new criteria
            scNewArray[sortCriteria.length] = scNew;
            //and exceute the search
            return super.setOrderByOrSortBy(scNewArray);
        }
        
        return super.setOrderByOrSortBy(sortCriteria);
    }

The image blow shows the result for the employees table which is first sorted after the ManagerId and then after the FirstName of the employee.

Sort after ManagerId and LastName

Sort after ManagerId and LastName

As you see, only the ManagerId column shows the sort icon. The secondary sort column, FirstName, doesn’t show the sort icon.

You can download the sample application, which uses the HR DB schema from the ADF-EMG ADF Samples Repository: BlogAdvancedTableSort.zip

Free Event on ADF Mobile in Germany: ‘Going Mobile – auf Geschäftsanwendungen zugreifen – mit Oracle ADF Mobile’

Aside

English message follows!

Oracle hält einen kostenlosen 1 Tages Hands on Workshop zum Thema “Going Mobile – auf Geschäftsanwendungen zugreifen – mit Oracle ADF Mobile” in Frankfurt-Dreieich ab. Dies ist sicher interessant für alle ADF Mobile Entwickler, die auf dem neusten Stand der Technik bleiben Wollen. Meldet Euch an, die Teilnehmerzahl ist begrenzt.
Weitere Informationen findet man unter den im Quote angegebenen Links.

START English Message
Oracle holds a free ADF Mobile 1 day Hands-On workshop in Frankfurt, Germany on 2nd, June 2014. If you like to learn about ‘Going Mobile – auf Geschäftsanwendungen zugreifen – mit Oracle ADF Mobile‘ the event is for you. Please register as soon as possible as the number of attendees is restricted.

The event is held in German language!
END English Message

Going Mobile – auf Geschäftsanwendungen zugreifen – mit Oracle ADF Mobile – 1 Tages Hands on Workshop
Immer häufiger gibt es die Anforderungen aus den Fachabteilungen wie Vertrieb oder Logistik, auch vom Tablet oder Smartphone auf existierende Anwendungen wie CRM oder ERP zugreifen zu wollen.
Mittels Oracle ADF Mobile können Sie dies schnell umsetzen. Entwickler mit Java oder ADF Kentnissen können ihr Wissen sofort einbringen.
Aber auch Entwickler ohne Programmierkenntnisse können Oracle Mobile sofort produktiv nutzen.
In diesem Hands-On Workshop erlernen Sie das Basiswissen zum Umgang mit den Oracle Technologien Oracle ADF Mobile sowie dem JDeveloper und Weblogic Server. Sie werden im Workshop eine mobile Anwendung entwickeln und auf Ihrem Smartphone oder Tablet (Android, iOS) ablauffähig installieren.
Mehr zu Oracle Mobile auf dieser Seite.

Zeit: 2. Juli 2014 – Beginn 10:00h – Ende: 17:00h
Ort der Veranstaltung:
Frankfurt-Dreiech
Oracle Deutschland B.V. & Co KG
Robert-Bosch-Straße 5
63303 Dreieich
Anmeldelink hier. Die Teilnahme ist kostenlos. Die Teilnehmerzahl ist begrenzt.
Systemvoraussetzungen für den Workshop finden Sie hier.

Using one ViewObject for Global Lookup Data (Part 3): Multi Language Support

In an earlier post I blogged about a how to use a DB table to hold look up data like gender, weekdays or title which can used in different locations as ‘List Of Value’ data (Using one ViewObject for Global Lookup Data (Part 2)).
This third part adds a use case where we add multi language support when we read data from the DB table. This is an enhancement of the use case implemented in part 2. The old use case could load data in one language only. Now we add the the language to the data in the db table to allow retrieval of language specific data.

To make the use case work, we add two columns to the existing table GENERALLOOKUP. The first one holds the language code and the second one an id which is unique in the type and language. We use this new id named ‘GROUPID’ in the LOV to show the data of the selected type.
The ‘GROUPID’ remains identical for each type and language so that we can enter data in different languages. For the language code we use the codes we get from a Locale class. A sample for the data of WEEKDAY Monday:

Sample for Multilanguage Entry

Sample for Multilanguage Entry

We start by changing the DB table GENERALLOOKUP we used in the sample introduced in part 2. The sql script setup_db_multilangual.sql which is part of the project workspace, adds the two mentioned columns. You find the link to download the workspace at the end of this post. The script holds the needed data for the multi language look up too.
The final DDL for the GENERALLOOKUP table is

  CREATE TABLE "GENERALLOOKUP" 
   (	
    "ID" NUMBER, 
	"TYPE" VARCHAR2(20 CHAR), 
	"DATA" VARCHAR2(255 CHAR), 
	"LANGUAGE" VARCHAR2(5 CHAR), 
	"GROUPID" NUMBER
   ) ;

Next we synchronize the existing EO with the new GENERALLOOKUP table to get the new attributes into the EO

Synchronize with DB

Synchronize with DB


Here are some of the dialogs which you see when synchronizing the DB to the business objects

Now we have to add the new columns to the VO as well

These changes now allow to use the VO GeneralLookup to select language dependent look up data from the db. We now a new view criteria, named TypeLookupByLanguageViewCriteria, to use the language information to only select data for one language and one type from the table.

This new view Criteria uses two bind variables to select only data of one type and one language. How to set these variables we see later in this post.
As we don’t want to break the old application we create a new VO based again on the existing Lookuptest entity object and name it ‘LookupMultiLanguageView’

Next step is to set up the LOVs accessors for the attributes WeekdayId, GenderIs, PositionId and TitleID. Here we only show how to do this for the WeekdayId attribute. The images below showing that we not only set the bindType to ‘WEEKDAY’, but the bindLanguage variable too. Here we use a groovy expression to get the current language from the current locale

The real work is done in pictures 3, 4, 5 and 6 where we use the view criteria we’ve build earlier (TypeLookupByLanguageViewCriteria) to select the type and language from the GeneralLookupView.
In Image 3 we use the GenerallookupView as view accessor for the weekdayId. We rename the accessor to WeekdayMultiLanguageLOV for better understanding what the view accessor does. As the WeekdayMultiLanguageLOV can select any type in any language, we have to use the view criteria and set its bind variables to only get the data we want. In this case we set the bindType variable to ‘WEEKDAY’ and the bindLanguage variable to the current language used in the browser. As this language can change, we can’t use a static string like we used for the bindType. The language has to be calculated. For this we use a groovy expression:

oracle.adf.share.logging.ADFLogger LOGGER = oracle.adf.share.logging.ADFLogger.createADFLogger(source.getClass()); 
loc = adf.context.locale; 
if (loc == null) {
  LOGGER.info("Language not set -> en");
  return 'en';
} else {
  lang = loc.language;
  shortLang = lang.substring(0,2);
  if (!"#de#it#fr#en#".contains(shortLang)) {
    LOGGER.info("Language not recognized -> en");
    shortLang="en";
  } else {
    LOGGER.info("Language set to -> "+lang.substring(0,2));
    shortLang = lang.substring(0,2);
  } 
}

Yes, you can do more with groovy then just simple calculations like “sal *12″!
We use groovy expression like a java function to get the locale from the AdfContext (groovy: loc = adf.context.locale;) and from the locale we get the language (groovy: lang = loc.language;). Now, there are some checks to make, like is the locale is set and if the language found is one of the languages we support. In this sample we only support ‘en’, ‘de’, ‘it’ and ‘fr’ but you can add other languages too. As the language we get from the locale can look like ‘en_US’ or ‘de_CH’ we only use the first two characters (groovy: shortLang = lang.substring(0,2);). You can even use a logger to print out information into the log.

We can now test the switching of languages in the application module tester. Before we start the tester we make sure we can change the locale in the tester. Open the menu ‘Tools’->’Preferences’ and select the node ‘Business Components’, then select the ‘Tester’ node where you can add different languages for the tester.

Supply Languages to Tester

Supply Languages to Tester


Running the tester

Please notice the log output which is visible below the tester which shows the groovy log messages.

Finally we adjust the UI by adding a new page MultiLanguageLookup and hook it up with the existing LookupTest page.

Setup New Test Page

Setup New Test Page


Then we need to setup the faces-config.xml to support multiple languages
Setup New Test Page

Setup New Test Page


Now, if we run the application and change the browser language, reload the page we see the language change

The sample used in this blog can be downloaded from the ADF-EMG Sample repository. The sample uses JDeveloper 11.1.1.7.0 and the HR DB schema.