InputNumberSpinbox without Spin

ADF offers a wide range of components which allow user to input data. There is a build in intelligence which chooses the ‚right‘ component for the given data type when you create the UI from a data control. This allows e.g. to create a form to input data which e.g. covers the basic formatting and error handling of the data types for the given fields.

From my point of view, one wrong decision is to use the af:inputNumberSpinbox for Integer and BigInteger data types. Setting a bigger number using the spin boxes isn’t working for most people, at least not for me.

The spin buttons are of no real use in most cases. In some versions of JDev the buttons are skinned too small so that it’s hard to use them at all. There are some cases, when the range of numbers is minimal, where using the spin buttons is OK.

What I like about the component is the build in error handling if I try to input anything but a number

without doing anything to the component. This is the code used for the above image

<af:inputNumberSpinbox label="Spinnumber" id="ins2"
    value="#{bindings.myNumber21.inputValue}"/&gt;

As you see there in nothing but the component, still we get the right error message.

You can get the same result by using a normal af:inputText with an included af:numberConverter, but you need to know how to do this:

<af:inputText label="Number in af:inputText" id="it1"
    <af:convertNumber type="number" id="nc1" pattern="0"/&gt;
</af:inputText&gt;

This doesn’t look identical but close enough. One difference to note is that the af:inputText starts the input on the left whereas the af:inputNumberSpinbox aligns the numbers to the right. You can change this too with setting more properties on the component.

For this I like to use the af:inputNumberSpinbox without the spin buttons.

To make the af:inputNumberSpinbox usable I get rid of the spin buttons:

The component works like hte one with the spin buttons but look like a normal inputText

This can be done by changing the skin. If you like it can be done globally or you define a custom skin class and add this class where you don’t want to see the spin butons:

.nospin af|inputNumberSpinbox::incrementor-icon-style {
    display: none;
}

.nospin af|inputNumberSpinbox::decrementor-icon-style {
    display: none;
}

The ‘.nospin‘ is the name of the custom style class you can use on the af:inputNumberSpinbox to turn the spin buttons off.

Here is the part of the page

<af:panelGroupLayout id="pgl2" layout="vertical" inlineStyle="padding-left:20px;"&gt;
    <af:inputNumberSpinbox label="Number" id="ins1" value="#{bindings.myNumber1.inputValue}" styleClass="nospin"/&gt;
    <af:spacer width="10" height="30" id="s1"/&gt;
    <af:inputNumberSpinbox label="Spinnumber" id="ins2"
        value="#{bindings.myNumber21.inputValue}"/&gt;
    <af:spacer width="10" height="30" id="s2"/&gt;
    <af:inputText label="Number in af:inputText" id="it1"&gt;
       <af:convertNumber type="number" id="nc1" pattern="0"/&gt;
    </af:inputText&gt;
    <af:spacer width="10" height="30" id="s3"/&gt;
    <af:button text="Submit" id="b1"/&gt;
</af:panelGroupLayout&gt;

You can download the sample from GitHub BlogInputSpinBoxWithoutSpin. The sample was built with JDeveloper 12.2.1.1.0 but should work with other versions too. There is no DB used or needed to run the sample.

Advertisements

Jdev 12c: Implementing SQL IN Clause in an ADF ViewObject Query or ViewCriteria (Part 2)

In part one, showed how to implement a SQL IN clause in ADF. Now I show how to use this technique in a ViewCriteria or directly in a query of a view object.

We have to solve a couple of problems before we can really use the technique from part one in a ViewCriteria. As you know, when using a ViewCriteria, you select an operator which in turn is translated into SQL code. So, we have to find a way to create a new operator which will then be used to create the needed SQL code.

The technique to do this comes from an older post. Please look at Extending ViewCriteria to use SQL CONTAINS where I showed the basics on how to do this. The older post was designed for JDeveloper 11.1.2.1.0. Using the current JDeveloper version 12.2.1.3 give some ways for improvement of the earlier code.

The first improvement is that JDeveloper 12.2.1.3 allows us to introduce custom operators to view criteria. In the older sample, I had to use the description field of the ViewCriteria to pass information which SQL to generate. Now we can define an operator named ‘IN’ and use it in the ViewCriteria like any other default operator.

The next problem is how to generate the SQL shown in part one when the new custom operator ‘IN’ should be used. One of the big advantages of ADF is reusability. We use a base class which extends from ViewObjectImpl and use this new base class in the project.

The base class is named BaseViewObjectForSqlInClause were we implement the needed method

public String getCriteriaItemClause(ViewCriteriaItem aVCI)

which gets called for each part or item of a ViewCriteria. See the code of hte base class below.

Base Class

public class BaseViewObjectForSqlInClause extends ViewObjectImpl {
    private static ADFLogger _logger = ADFLogger.createADFLogger(BaseViewObjectForSqlInClause.class);

    // comma-separated list of custom operators. Each custom operator muast have a ',' at the end as delimeter!
    private static final String CUSTOM_OPERATORS = "IN,";

    public BaseViewObjectForSqlInClause(String string, ViewDefImpl viewDefImpl) {
        super(string, viewDefImpl);
    }

    public BaseViewObjectForSqlInClause() {
        super();
    }

    /**
     * Check if a given criteria item tries to use an 'IN' operator using a bind parameter (comma seperated list of strings).
     * Create special SQL clause for 'IN' operator
     * @param aVCI Criteria item
     * @return where clause part for the criteria item
     */
    @Override
    public String getCriteriaItemClause(ViewCriteriaItem aVCI) {
        // we only handle the SQL 'IN' operator
        String sqloperator = aVCI.getOperator();
        // add comma to operator as delimiter
        boolean customOp = CUSTOM_OPERATORS.indexOf(sqloperator.concat(",")) &gt;= 0;
        customOp |= sqloperator.indexOf("NVL") &gt;= 0;
        if (customOp) {
            ArrayList<ViewCriteriaItemValue&gt; lArrayList = aVCI.getValues();
            if (lArrayList != null &amp;&amp; !lArrayList.isEmpty()) {
                // check if the criteria item has bind parameters (only the first if of interest here as the IN clause onlyallows one parameter)
                ViewCriteriaItemValue itemValue = (ViewCriteriaItemValue) lArrayList.get(0);
                if (itemValue.getIsBindVar()) {
                    // get variable and check if null values should be ignored for bind parameters
                    Variable lBindVariable = itemValue.getBindVariable();
                    Object obj = ensureVariableManager().getVariableValue(lBindVariable.getName());
                    boolean b = aVCI.isGenerateIsNullClauseForBindVariables();
                    if (b &amp;&amp; obj == null) {
                        // if null values for bind variables should be ignored, use the default getCriteriaItemClause
                        return super.getCriteriaItemClause(aVCI);
                    }

                    try {
                        // we only handle strings data types for bind variables
                        String val = (String) obj;
                    } catch (Exception e) {
                        // the bind variabel has the wrong type! Only Strings are allowed
                        _logger.warning("Bind variabel for SQL " + sqloperator +
                                        " clause is not of type String! -&gt; No custom SQL clause created! (Class: " +
                                        obj.getClass() + ", Content: " + obj + ", Variable: " +
                                        lBindVariable.getName() + ", View: " + this.getName() + ")");
                        String s = ":" + lBindVariable.getName() + " = :" + lBindVariable.getName();
                        return s;
                    }

                    // only handle queries send to the db
                    if (aVCI.getViewCriteria()
                            .getRootViewCriteria()
                            .isCriteriaForQuery()) {
                        String sql_clause = null;
                        switch (sqloperator) {
                        case "IN":
                            sql_clause = createINClause(aVCI, lBindVariable);
                            break;
                        default:
                            _logger.severe("Unknown custom operator '" + sqloperator + "' found! -&gt; do nothing!");
                            break;
                        }

                        return sql_clause;
                    } else {
                        // bind variable not set or
                        // for in memory we don't need to anything so just return '1=1'
                        return "1=1";
                    }
                }
            }
        }

        return super.getCriteriaItemClause(aVCI);
    }

    private String createINClause(ViewCriteriaItem aVCI, Variable lBindVariable) {
        // start build the sql 'IN' where clause (COLUMN is the name of the column, bindParam the name of the bind variable):
        // COLUMN IN (SELECT regexp_substr(:bindParam,'[^,]+',1,level) FROM dual CONNECT BY regexp_substr(:bindParam,'[^,]+',1,level) IS NOT NULL
        // get flagg to create an sql where clause which ignores the case of the bind parameter
        boolean upper = aVCI.isUpperColumns();
        String sql_in_clause = null;
        StringBuilder sql = new StringBuilder();
        if (upper) {
            sql.append("UPPER(");
        }
        sql.append(aVCI.getColumnNameForQuery());
        if (upper) {
            sql.append(")");
        }
        sql.append(" ").append(aVCI.getOperator());
        sql.append(" (select regexp_substr(");
        if (upper) {
            sql.append("UPPER(");
        }
        sql.append(":");
        sql.append(lBindVariable.getName());
        if (upper) {
            sql.append(")");
        }
        sql.append(",'[^,]+', 1, level) from dual connect by regexp_substr(");
        if (upper) {
            sql.append("UPPER(");
        }
        sql.append(":").append(lBindVariable.getName());
        if (upper) {
            sql.append(")");
        }
        sql.append(", '[^,]+', 1, level) is not null)");
        sql_in_clause = sql.toString();

        _logger.finest("generated SQL-IN clause: " + sql_in_clause);

        return sql_in_clause;
    }
}

Using Base Class in Project

To use the base class in all new created ViewObjects of the project, we change the models project properties

Now, whenever you create a new ViewObject, the new base class is used and the SQL IN operator can be used in the VOs view criteria.

You can change any existing ViewObject to use the BaseViewObjectForSqlInClause by changing the extends clause in the class definition by hand.

Creating a ViewCriteria Using the Custom IN Operator

All pieces are in place and using the IN operator is pretty easy. We start by creating a new ViewObject named EmployeesOfDepartmentsViewCriteria

Now we have a ViewObject based on an EntityObject for the Employees. We need to make one change. The DepartmentId is an Integer type attribute, the comma-separated list is of type String (containing numbers). This doesn’t match. We add another attribute to the ViewObject of type String which we calculate from the DepartmentId Integer attribute. We change the SQL query for this by selecting the ‘Query’ node first unselecting the checkbox ‘Calculate Department Query at Runtime (recommended)’, second select the checkbox ‘Write Custom SQL’ and third add the line ‘to_char(Employees.DEPARTMENT_ID) DEPARTMENT_ID_STR,’ to the query.

Once this new ViewObject has been created, we add a ViewCriteria to it

If you like, you can turn off the checkbox ‘Ignore Case’ as it is not needed. The numbers are always lower case.

Running the ApplicationModule in the Tester

At this stage, we can test run the application module in the Application Module Tester (see JDeveloper & ADF: Use the Application Module Tester (BC4J Tester) to Test all your BusinessLogic).

Click the binocular button to select the ViewCriteria we created and click ‘Find’

Which will open a dialog asking for the value of the bind variable

Clicking ‘OK’ will show the result as

Running the ViewCriteria on a Page

Finally, we can add the ViewCriteria to a page as af:query and test it there. I’ll spare the exact howto here and just show hte running application.

Or with different parameters and spaces

You can download the sample application from GitHub BlogSqlInClause.

The Sample was built using JDeveloper 12.2.1.3 (but it should work in all 12c versions) and uses the HR DB schema.

JDeveloper 12c: using Expression Language in pageDef to switch ControllerClass

An interesting question came up late 2018 in the JDeveloper & ADF forum. A user asked how to use Expression Language (EL) in a pageDef file to switch the ControllerClass at runtime depending on some condition of a page.

The ControllerClass can be used to add custom code into the lifecycle of a page or fragment (see the full details at 27.4 Customizing the ADF Page Lifecycle). A tip

Tip:
You can specify the value of the page definition’s ControllerClass attribute as a fully qualified class name or you can enter an EL expression that resolves to a class directly in the ControllerClass field.
When using an EL expression for the value of the ControllerClass attribute, the Structure window may show a warning indicating that e “#{YourExpression}” is not a valid class. You can safely ignore this warning.

given in the documentation mentioned that you can use EL to specify the ControllerClass. The missing information is exactly how to do it.

Use Case

For a JSF page, a ControllerClass should be defined at runtime. The selected ControllerClass should depend on a condition.

Solution

There are a couple of blogs available which use a custom ControllerClass in a pageDef, but they use the direct specification of the custom class in the pageDef. Only one sample (https://github.com/oracle/adf-samples/releases/download/v1.0.0/OnPageLoad.zip) from Duncan Mills uses EL to set the ControllerClass. However, this sample was built for JDev 10.3.1! None of the samples I found use EL to switch the ControllerClass at runtime.

In summary, it’s time for a fresh sample using JDev 12.2.1.3

Building the UI

We start by creating a new Fusion Web Application from the gallery. The steps to follow can be looked up at Why and how to write reproducible test cases, so I skip them here.

Once the basic Fusion Web Application is built we open the adfc-config.xml (the unbounded ADF task flow) and add a page onto it.

We name the page index and create it using a Quick Layout. I normally use

but you can use whatever layout like. We add a Text to the header section and an af:inputText and an af:button to the content section. The page markup will look 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="index.jsf" id="d1">
        <af:form id="f1">
            <af:panelGridLayout id="pgl1">
                <af:gridRow height="50px" id="gr2">
                    <af:gridCell width="100%" halign="stretch" valign="stretch" id="gc1">
                        <!-- Header -->
                        <af:outputText value="Using EL to switch ControllerClass" id="ot1"
                                       inlineStyle="font-size:x-large;"/>
                    </af:gridCell>
                </af:gridRow>
                <af:gridRow height="100%" id="gr1">
                    <af:gridCell width="100%" halign="stretch" valign="stretch" id="gc2">
                        <!-- Content -->
                        <af:panelGroupLayout id="pgl2" layout="horizontal">
                            <af:inputText label="Use Listener" id="it1"/>
                            <af:button text="Update" id="b1"/>
                        </af:panelGroupLayout>
                    </af:gridCell>
                </af:gridRow>
            </af:panelGridLayout>
        </af:form>
    </af:document>
</f:view>

Next, we open the properties of the af:button and edit the actionListener property. Here we create a new bean, name it ‘IndexBean’, create a new method ‘updatePage’. The bean we create in sessionScope. Once the bean has been created, we delete the actionListener from the af:button we just created. The ‘updatePage’ method in the IndexBean we delete too. We don’t need the listener and I only used it to create the bean in the right scope for other things.

I created the bean in session scope as I will use it to store the data from the inputText we added to the page. This is just a convenience, we could have used a pageDef variable for this.

We add a String property ‘usePPListener’ to the IndexBean add the needed getter and setter methods.

public class IndexBean {
    String usePPListener = "1";

    public IndexBean() {
    }

    public void setUsePPListener(String usePPListener) {
        this.usePPListener = usePPListener;
    }

    public String getUsePPListener() {
        return usePPListener;
    }
}

We set the default value of the ‘usePPListener’ to “1”. We set the ‘usePPListener’ to the value property of the af:inputText field of the page. And set the autoSubmit property of the af:inputText to true. The page markup for the content:

<af:gridCell width="100%" halign="stretch" valign="stretch" id="gc2">
    <!-- Content -->
    <af:panelGroupLayout id="pgl2" layout="horizontal">
        <af:inputText label="Use Listener" id="it1" value="#{IndexBean.usePPListener}"
                      autoSubmit="true"/>
        <af:button text="Update" id="b1"/>
    </af:panelGroupLayout>
</af:gridCell>

Running the application at this stage shows

Creating the PagePhaseListener Class

Now we can go on and create the custom PagePhaseListener classes which we then use to switch using an EL. To create such a custom class, the documentation tells us that all we have to do is to create a class which implements the ‘PagePhaseListener’ interface.

This will create the first PagePhaseListener named ‘MyPagePhaseListenerA’. The resulting class looks like

package de.hahn.blog.elpagedef.view.beans;

import oracle.adf.controller.v2.lifecycle.PagePhaseEvent;
import oracle.adf.controller.v2.lifecycle.PagePhaseListener;

public class MyPagePhaseListenerA implements PagePhaseListener {
    public MyPagePhaseListenerA() {
        super();
        System.out.println("MyPagePhaseListenerA created");
    }

    @Override
    public void afterPhase(PagePhaseEvent pagePhaseEvent) {
        // TODO Implement this method
        System.out.println("MyPagePhaseListenerA afterPhase called");
    }

    @Override
    public void beforePhase(PagePhaseEvent pagePhaseEvent) {
        // TODO Implement this method
        System.out.println("MyPagePhaseListenerA beforePhase called");
    }
}

We do it again but name the class ‘MyPagePhaseListenerB’. As you see I added some System.out.println(“…”) statements so that we can see which PagePhaseListener is used later.

Using EL in pageDef.xml

Finally, we start with the interesting part, the EL to use in the pageDef ControllerClass property to switch the listener. The use case demands that we switch the PagePhaseListener depending on a condition. The condition we use is pretty simple:

  • Use MyPagePhaseListenerA if the inputText value stored in usePPListener is equal to “1”
  • Use MyPagePhaseListenerB if the inputText value stored in usePPListener is equal to “2”

We have two options to make the decision,

  1. directly in EL in the pageDef
  2. use a method in a bean where we check the condition

The essential part to know is the type of result both options need to return to work. The ControllerClass expects an object of type PagePhaseListener, or a class which implements this interface.

Solution 1

The classes we created before are implementing this interface, so they should work. To implement option 1 we need to need to instantiate an object of one of the classes and return it on the EL like in the pageDef.xml:

ControllerClass=”#{IndexBean.usePPListener eq ‘1’ ? MyPagePhaseListenerA : MyPagePhaseListenerB}”

And we need to register the bean named ‘MyPagePhaseListenerA’ and ‘MyPagePhaseListenerA’ in the task flow. This will instantiate the object when the task flows starts.

Running this application this way we get

Entering ‘2’ into the af:inputText and clicking ‘Update’ we get

Heureka! The PagePhaseListener have switched as expected.

Solution 2

We implement a method in a bean which returns the right PagePhaseListener class. The EL in the pageDef.xml looks like

ControllerClass="#{IndexBean.pagePhaseListener2Use}"

The method getPagePhaseListener2Use() we implement in the IndexBean as

public PagePhaseListener getPagePhaseListener2Use() {
    if (getUsePPListener() != null && getUsePPListener().equals("2")) {
        return new MyPagePhaseListenerB();
    } else {
        return new MyPagePhaseListenerA();
    }
}

The method returns the PagePhaseListener interface instead of the real class object. This is necessary as a method can only return one object type.

Running the application in this configuration results in exactly the same output we saw before.

Using EL in PageDef for Fragments used in Regions

If you plan to use this technique for fragments which run in regions you would need to return a RegionController instead of a PagePHaseListener. However, as it turned out, you can’t use EL at all in a pageDef of a fragment!

The problem is, that the framework simply doesn’t evaluate the EL you specify for the ControllerClass of a fragment, but uses the EL as the class name. This results in a ‘ClassNotFoundException’ as there is no class named ‘#{your_EL}’.

I’m not sure if this is a bug or a feature. I could not think of a valid use case to use EL for a fragment pageDef.

If you do have one, share it in the comments to this post, please.

If you really think you need to switch the behavior for a RegionController at runtime, you can create one Class which implements the different in the overwritten methods and decide which part to execute inside the method.

Sample

You can download the sample application, which was built using JDev 12.2.1.3 and no DB connection, from GitHub BlogELPageDef

JDeveloper: Creating a FULL OUTER JOIN View Object

On my todo list, I found a topic which I wanted to blog about for a long time. The problem is how to create a ViewObject, based on EntityObjects, which builds a full outer join between two tables.

For those of you who don’t know about full outer joins in SQL here is a short description from https://www.w3schools.com/sql/sql_join_full.asp:

The FULL OUTER JOIN keyword return all records when there is a match in either left (table1) or right (table2) table records.

Note: FULL OUTER JOIN can potentially return very large result-sets!

FULL OUTER JOIN Syntax:

SELECT column_name(s)
FROM table1
FULL OUTER JOIN table2 ON table1.column_name = table2.column_name;
Image to visualize a full outer join

There are not too many use cases where you need to use a full outer join, but they exist (e.g. https://searchoracle.techtarget.com/answer/Another-good-FULL-OUTER-JOIN-example or to compare two or more tables).

Problem: How can a full outer join be created in ADFbc?

I show how to create a VO based on Employees and Department EO using a full outer join on the department_id. This VO will return all departments with all their employees, departments which don’t have any employee and all employees who don’t have a department.

Following the syntax from above, we use an SQL statement like

SELECT Departments.DEPARTMENT_ID,
  Departments.DEPARTMENT_NAME,
  Employees.DEPARTMENT_ID AS DEPARTMENT_ID1,
  Employees.LAST_NAME,
  Employees.FIRST_NAME,
  Employees.EMPLOYEE_ID
  FROM DEPARTMENTS Departments
FULL OUTER JOIN EMPLOYEES Employees
ON Departments.department_id = Employees.department_id
ORDER BY Departments.department_id, Employees.last_name;

There are other SQL statements which produce the same result like

SELECT DISTINCT * FROM
  (SELECT d.department_id AS d_dept_id,
     d.DEPARTMENT_NAME,
     e.department_id AS e_dept_id,
     e.last_name last_name,
     e.FIRST_NAME
   FROM departments d
   LEFT OUTER JOIN employees e
   ON d.department_id = e.department_id
   UNION ALL
   SELECT d.department_id AS d_dept_id,
     d.DEPARTMENT_NAME,
     e.department_id AS e_dept_id,
     e.last_name,
     e.FIRST_NAME
   FROM departments d
   RIGHT OUTER JOIN employees e
   ON d.department_id = e.department_id
  )
ORDER BY d_dept_id, last_name;

The statement combines a left outer join with a right outer join. The ‘Select distinct….’ is used to eliminate duplicate rows which are returned for both joins. Anyway, the results are equal.

Solution

Now we can build the view object based on the two entity objects (Departments and Employees). We start by creating a new view object

and fill in the name as ‘DepEmpViewObj’. Make sure you select ‘Entity’ as ‘Data Source’

On the next wizard page shuttle the Departments and the Employees entities to the right

Now select the Departments entity and you get

Selecting the Employees entity you get

This we have to change as the join type is ‘inner join’ and not what we like to do. If you select the drop down menu you see

Hm, there is no ‘full outer join’ as joint type. We can’t create this type of join declaratively, we have to do this directly with a SQL statement. So, drop down the ‘Association’ field and select ‘none’

The final definition is

On the next page select the attributes

We don’t change anything in step 4 so we go to step 5. Here uncheck the ‘Calculate…’ checkbox and select the ‘Write Custom SQL’

Now we copy the SQL statement from above and copy it into the text area after deleting the current statement. Don’t forget to delete the ‘order by…’ part from the ‘Select:’ text area and add them into the ‘Order By:’ text field

We skip the steps 6,7 and 8 and add the view object to the application module in step 9

Finally, we finish the wizard and are ready to test the view object.

Running solution

Running the application module in the tester show the resulting table (only the last ~40 rows are shown)

We see departments without employees and we have one employee (see the last row) without an assigned department. All as expected.

To complete the application we add the new DepEmpViewObj onto a page as a table. Running it we get the same result as in the tester.

You can download the sample from GitHub BlogFullOuterJoin. The sample was built using JDeveloper 12.2.1.3 and uses the HR DB. The same technique can be used with other JDeveloper versions too.

JDeveloper 12.2.1.3: REST POST Sample

Lately, I got a request to build a REST POST sample using an ADF REST DataControl. Well, here we go.

First of all, we need a REST API which allows us to create data as this will be translated to REST POST call. I deliberately don’t want to use an ADF based REST service as there are samples available for this.

Looking for free REST API services which allow creating data I found “reqres’ (http://reqres.in), a free ‘hosted REST-API ready to respond to your AJAX requests’. This service can be used to test REST calls using any verb you like. It promises to be online 24/7.

Let’s start by creating a new ADF Web Application. If we would only test the REST service we could have created a custom application, but I want to show the viewController part too, so the ADF Web Application is just fine.

I don’t show how to do this here as you can see it done here ‘Why and how to write reproducible test cases’

As we don’t use the ADFModel project you can delete this empty project if you like. After creating the initial workspace, we create a new project from the gallery as a ‘Custom Project’

I named the new project ‘BRPWebService’, but you can name the project anything you like. Inside the new project we new create a ‘Web Service Data Control (SOAP/REST)’:

After selecting this, a wizard will ask which kind of ‘Web Service Data Control’ we like to create. We choose REST and now have to specify the base URL to the REST service API.

We skip the next page as there is no OWSM Policy needed to access the REST API

In step 3 we define the path we want to use after the base URL. From the web page of the service, we see a bunch of possible API endpoints.

For this test, we use the ‘api/users’ path. The whole URL now is ‘http://reqres.in/api/users’. To test the creation of data we use the POST verb, so we select the POST. To make sure the service is functional, we add the GET verb too.

After naming the methods getUsers for the GET and createUser for the POST, we need to give the wizard info about the parameters the API expects and the response we get when the call is successful. When we click on the GET verb on the web page, we get all the info we need.

All JSON code samples are available from the web page or from this blog in the appendix

We copy the response from the web page and pate it o the ‘Response Sample’ field and create a parameter ‘page’ in the parameter section of the next wizard step.

The same we do for the createUser method. Here we have to copy the request parameter JSON and the response JSON from the web page.

On the next page, we test the Web Service Data Control

This completes the creation process. We can now run the Datacontrol from inside JDeveloper by right-clicking the data control and choosing ‘Run’

Testing the getUsers method with the parameter set to 2 we receive the right answer

Now, let’s try the POST verb by trying out the createUser method. As a parameter, we pass some JSON and after executing the method we get a JSON part back telling us the new Id of the user.

Everything works. Please remember that we only use a ‘fake’ service which accepts our JSON, but will not add any data!

Sample Application

For the fun of it, I developed a ViewControler which uses the REST Data Control. It allows to ask for users by providing a page to load, or you can test the POST verb to create a ‘fake’ new user.

The final application can be downloaded from GitHub BlogRestPost. It was built using JDeveloper 12.2.1.3 without a DB connection.

After starting the app we see this UI

The service allows getting users in page mode, three users per page. So, enter 3 into the ‘Page’ filed and we get

Now, filling ‘name’ and ‘job’ field and clicking the createUser button we get

The service returns a new user with a new ID and the timestamp when the user was created.

Appendix

JSON reponse for GET api/users?page=2

{
    "page": 2,
    "per_page": 3,
    "total": 12,
    "total_pages": 4,
    "data": [
        {
            "id": 4,
            "first_name": "Eve",
            "last_name": "Holt",
            "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/marcoramires/128.jpg"
        },
        {
            "id": 5,
            "first_name": "Charles",
            "last_name": "Morris",
            "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/stephenmoon/128.jpg"
        },
        {
            "id": 6,
            "first_name": "Tracey",
            "last_name": "Ramos",
            "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/bigmancho/128.jpg"
        }
    ]
}

JSON payload and response for POST api/create

Payload
{
    "name": "morpheus",
    "job": "leader"
}

Reponse
{
    "name": "morpheus",
    "job": "leader",
    "id": "783",
    "createdAt": "2018-11-19T21:42:47.556Z"
}

JDev 12c: Badge Button reloaded

In my article JDev: Badge Button I showed how to build a special button with a notification ‘badge’:

The declarative component of this sample was build using JDev 11g (11.1.1.9.0 to be exact).

I received a couple of question on how to work with this declarative component in JDev 12c projects. In general, you can use the same source and build the declarative component in JDev 12c. However, as JDev 12c is using a different document type, Facelets instead of JSP XML, you can use the badge button only on JSPX type pages.

So, in this blog, I show how to create a declarative component which is usable in Facelets type pages. I don’t change the behavior of the badge button but reuse the code. This blog is more about how to create a declarative component in 12c and show the differences to 11g.

JSPX vs. Facelets

With the introduction of JSF 2.0 (JavaServer Faces 2.0 Overview and Adoption Roadmap in Oracle ADF Faces and Oracle JDeveloper 11g) a new document type Facelets was introduced. The difference and the motivation behind this is outlined in the document.

We are only interested in the fact that you can’t mix components designed for JSPX XML pages or fragments with Facelets type pages or fragments. This means that you can’t add the badge button created for 11g to a jsf page of jsff fragment of type ‘Facelet’.

Building a Declarative Component for 12c

We start from the old application workspace I created for the 11g implementation. Opening this workspace will migrate it to the 12c. At the end of the blog, you’ll find a link to download the final workspace for 12c.

After the migration we add a new project ‘BBB12cDeclarativeComponent’ of type ‘ADF ViewController Project’ to the workspace:

After creating a new project for the 12c badge button, we create a new ‘Declarative Component’ in the ‘Web Content’ folder

In the wizard, we now select ‘Facelets’ as the document type. Selecting ‘Facelets’ will create the 12c kind of declarative component.

Once we finished the wizard, we get the skeleton declarative component in the ‘BadgeButton12c.jsf’ file. If you got a file name ‘BadgeButton.jspx’ you did not set the document type to ‘Facelets’.

Now we can copy the code from the original sample written for 11g and copy it after the componentDef tag. Once you copied the code from the original sample you have to change the EL used to address the action and the actionListener to match the componentVar property in the componentDef tag. To make this distinguishable from the 11g sample, I changed the componentVar to ‘compButton’. The other change is to use an af:button tag instead of the af:commandButton tag. While the af:commandButton tag can still be used, 12c application should use the af:button tag.

 

The final code looks like

Adding the declarative component to the faces palette

You already know, that to use the declarative component in a project, you first have to add it to the component palette. The difference to the 11g sample is that we have to choose a different node in the project definition to add the library.

First, we need to deploy the declarative component project to an ADF Library. For this, all we need to do is to execute the deployment profile created with the project

Next, we add a ‘File System’ resource which points to the folder the jar is created in

And the jar should show up

To make it usable in the view controller project, we have to add the jar to the project

Now, when we look into the view controller projects properties, we find the new declarative component in the ‘Facelets Tags Libraries’ node. In JDev 11g the tab libraries can be found in the node ‘JSP Tag Libraries’. Again, the difference is where the tags or declarative component are usable. You use JSP tags in JSP XML files and you use Facelets tags in JSF files.

Next step is to create a new JSF Page in the adfc-config.xml, the unbounded task flow.

Again, we make sure to select ‘Facelets’ as document type as we otherwise will not be able to use the declarative component created for ‘Facelets’.

The layout of the page is similar to the one for 11g. 12c uses a panelGridLayout instead of the panelStretchLayout, but that’s all.

As we are now using a JSF page and added the 12c component library and find the BadgeButton in the component palette

and use this on the page. The final layout looks like

Or when running the JSF page

Clicking the button we get the log messages

Sample Application

You can download the sample application from GitHub BlogBadgeButton12.2.1.2

JDeveloper: Info about the clicked cell in an af:table

JDeveloper allows to easily create tables with the af:table component. The table allows easy access to the selected row or rows. However, if you are interested in which cell of a table has been clicked, ADF needs some tweaking. This blog is about how to tweak an af:table to get exactly this info.

Use Case

You like to know which cell in an af:table a user has clicked, e.g. to get some detailed information about the clicked item or cell in the selected row. The sample I show get the information about the current row, and column of the cell and the value of the cell clicked. The final sample will show the info like

How to do it?

The normal af:table component doesn’t give information about the cell a user has clicked on. The ADF pivot table offers this but is complex to use.

We use JavaScript in form of a clientListener to intercept the click on a cell and a serverListener to call a bean method to get more data on the cell. This article 011. ADF Faces RC – How-to use the Client and Server Listener Component shows how to use clientListener and serverListener in detail.

As we are interested in the selected cell, we add a clientListerer to each af:outputText which shows the column value in the af:table which fires on the click event. The clientListener calls a JavaScript method. In the JavaScript method, we build a payload of the UIComponent which is used to show the column value and the column name of the cell. To get this information we have several possible ways:

  1. We can use our knowledge of the DOM tree and get the column via the parent of the component which fired the event. The parent component should be the af:column.
  2. We add a client attribute to the component which shows the cell value adding the column name from the af:column as EL

In this sample, we choose the second solution. With this information, we call the serverListener from the JavaScript method. The serverListener method is implemented in a request scope bean and uses the information passed to get the details about the clicked cell we show in the UI.

Implementation

The sample uses the HR DB schema and only needs one table, Employees in this case. We create a simple page with the table in read-only mode, sortable and filterable. As you see in the image above the table is just build be dragging the Employees VO onto the page and drop it as a read-only table.

Now we add a clientListener and a serverListener to each outputText component which is used to show the cell value

In the image above we see the listener for two columns. In addition, we add an af:clientAttribute with the name ‘columnName’ which we pass the EL of the af:column headerText property.

Next, we add an af:resource component to the af:document where we specify the JavaScript for the clientListener method ‘clientCellSelectionCall’. We use a JavaScript file to code the method. We could have added the method to the page directly, but if we want to reuse the pattern, it’s better to use a JavaScript file

The file is located in the public_html folder (Web Content) in a subdirectory ‘javascript’

The method code is

The click event on the af:outputText component triggers a call to the javascript method ‘clientCellSelectionCall’ (via the clientListener) with the source of the event, the af:outputText component. The method reads the clientAttribute added (line 3) and calls the serverListener of type ‘cellSelection’. This event is defined by the af:serverListener on the af:outputText. The component which triggered the event and the column name added as client attribute are passed to the serverListener.

The serverListener is a bean method defined in a request scope bean on the af:outputText component as

method="#{TableCellSelectionBean.handleTableCellSelection}"

In the bean, the method looks like

public void handleTableCellSelection(ClientEvent event) {
  // get payload which is the ui component which fired the event
  UIComponent ui = (UIComponent)event.getParameters().get("payload");
  // get the column from the event which is sent too
  String column = (String)event.getParameters().get("column");
  RichOutputText rt = (RichOutputText)ui;
  // get current row key
  DCBindingContainer bindingContainer = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
  DCIteratorBinding binding = bindingContainer.findIteratorBinding("EmployeesViewIterator");
  Row currentRow = binding.getCurrentRow();
  Key key = currentRow.getKey();
  // compile info about clicked cell
  String out = "Payload:" + ui + "
  column: "+ column + "
  val: " + rt.getValue() + "
  key: "+key.toString();
  logger.info(out);
  setCellInfo(out);
}

Here we get the component which triggered the event (as payload) and the name of the column. Using this information we can get e.g. to the value of the column (via the UI component). The row of the cell we get via the current row of the iterator. With this information, we get the key of the row. We can get much more information here, like historical data about the current employee’s salary, if the salary cell was clicked.

We just create a string from the information which we show in the UI to the user

Here are some images of different cells clicked in the UI:

Download

You can download the sample, which was built using JDeveloper 11.1.1.9, from GitHub BlogTableCellSelection. The sample uses the HR DB schema.

JDeveloper: Skin Radio Buttons

In this blog article, I like to share how to use a skin to alter the look of radio buttons in ADF. The use case was a question on the ODC space JDeveloper & ADF which asked about how to provide more space for the radio buttons.

Here is an image of the default and the resulting radio buttons:

As you see, in the first radio group the space between the selectItems is narrower than in the second group.

In my older post about JDeveloper: Advanced Skin Technique I showed how to find out which style to change, so I spare this here.

The image above shows the standard “radiogroup” in Chrome Developer Tools. As you can see the radiogroup consists of “div” elements, each specifying one of the selectItem.

To change the spacing, we add a style class to the skin file like

.mysor af|selectOneRadio::content div {
  padding: 0px 0px 10px 0px;
}

The “.mysor” is the name of the style class which we later use on the page. The magic is done by specifying the base style as af|selectOneRadio::content and from there style each “div” element having the base style as a parent. This way we style the blue marked div in the image above.

One question remains. Why do we use a skin and don’t add the code right into the page?

Well, using a skin is the preferred method. The skin is created once and can be used everywhere in the application. If you need to make changes, you don’t have to search for the pages where the style has been added, but you just change the skin file and you are done.

Download Sample

You can download the sample which is build using JDev 12.2.1.2.0 and uses the HR DB schema from GitHub BlogAdvancedSkin

 

 

JDev: Badge Button

In this article, I describe how to build what I call a ‘Badge Button’. This is a button we know from many mobile applications which shows, e.g., how many new messages have arrived since the last visit.

The image above shows what I have in mind. We see a standard button with a badge indicating the number of new items. The badge can be used to display text as well

The idea behind this came from a question on the ODC JDev & ADF space. When I first read the question I wanted to answer “No, there isn’t such a component in ADF”, but after thinking about it, I decided to build one myself.

The Problem has two parts:

  1. How to build the badge
  2. How to create the component looking like a button with a badge

Solution Part 1

Making the badge turned out to be very easy. Searching the web, you find plenty of solutions for such components using CSS. As you might know, it’s not very straightforward to add a CSS solution to ADF. However, there are ways to do this. In the end, I used the following CSS to generate the badge:

.badge {
 background: radial-gradient( 5px -9px, circle, white 8%, red 26px );
 background: -moz-radial-gradient( 5px -9px, circle, white 8%, red 26px );
 background: -ms-radial-gradient( 5px -9px, circle, white 8%, red 26px );
 background: -o-radial-gradient( 5px -9px, circle, white 8%, red 26px );
 background: -webkit-radial-gradient( 5px -9px, circle, white 8%, red 26px );
 background-color: red;
 border: 2px solid white;
 border-radius: 12px; /* one half of ( (border * 2) + height + padding ) */
 box-shadow: 1px 1px 1px black;
 color: white;
 font: bold 15px/13px Helvetica, Verdana, Tahoma;
 height: 16px;
 padding: 4px 3px 0 3px;
 text-align: center;
 min-width: 14px;
 margin: 0px 0px 20px -10px;
 position: relative;
}

Solution Part 2

ADF uses CSS which is built from skin files. It’s not straightforward to add any other CSS to a component as you don’t see the generated HTML where you need to add the CSS. So adding the CSS class just as style to the button doesn’t work, as you can’t add new properties to ADF components. You will get an error like

To create a badge, you need to create a span or div with the CSS class and some data which is put into the badge like
Selection_474

This can’t be added to an existing component easily. However, ADF has a component which renders as a div tag, the af:outputText. If you add an af:outputText to a page and look at the resulting HTML you get
Selection_475
So, the value of the outputText is just surrounded by a div tag. The problem still is that you can’t add your own property to the ADF component, but we can add the div with the needed style and the data as the value you the af:outputText component. All we have to do, other than to add the div is to set the escape property of the outputText to false. This setting avoids that ADF encodes the value which would transform the ‘<’ into ‘<’, essentially making a string out of the value. The reason for that is to prevent security issues (injection), so be aware of this!

Putting this on a page would look like

And generates

The solution works somehow, if we put an af:button on the page instead of the af:spacer. However, it looks ugly or ‘uncool’ to see the ‘div’ in the af:outputText.

Final Solution

The final solution is to hide the ‘how to build it’ in a declarative component. The use case is a perfect fit for an ADF declarative component. We move the CSS, the button and the outputText in such a component and can use the component in the page to get

The new solution looks clean, as the CSS and odd looking outputText isn’t visible. Here are some images of the running test application.

The input field is used to set the data to be shown on the badge. It can be numbers, text or both. Clicking on the button calls the action listener and the action.

And this is the log output.

Building the Declarative Component

There are many other blogs about how to create a declarative component so I will not do this in detail. However, I like to point out some things you should keep in mind when you create such a declarative component.

To make the component work, it’s not enough to just add a button and the outputText holding the CSS. We have to make properties available for the action and the actionListener of the button. If we don’t do this, all we get is a button, which is looking good but which can’t be used to start a navigation or to call an actionListener. The same is true for other properties of the button inside the declarative component. We have to add a property for the button text at least. If you like to enable/disable the badge button, you have to expose an attribute in the declarative component interface to get the value from the outside, your page See later).

When we build the declarative component, we start by adding another ‘ADF View Controller Project’ to the workspace. Declarative components should be developed in a separate project. They are deployed as adfLibrary jar files. We add a new JSF Declarative Component to the project.

And fill out a dialog with necessary data. This data can be changed later if needed. Here is a sample

Once we click OK, a jspx page with the selected name will be created alongside a meta-data file holding the information about the tag library.

In the JSPX page, we create the layout of the component. We already know how to add the badge, all we need to do is to put an af:button onto the page and add the code to the badge to it. The resulting declarative component looks like

Select the af:componentDef tag and open the property editor. There you can define metadata like attributes and methods you want to pass to the component from the outside.

And the methods to activate the button.

The data you specified in the property editor is added to the af:componentDef tag.

A special case is the partialTrigger property. You can’t set a partialTrigger from the outside to a component used in the declarative component. However, you can surround the declarative component with another component which has a partialTrigger property and use this outer component to send a ppr. In the code above I surrounded the declarative component with an af:panelGroupLayout which listens for ppr send from the af:inputText with the id “it1”. This partial refresh is needed in the sample to refresh the button with a new value entered in the field.

If you need more attribute to control the behavior of the component, you can add them via the property editor. For this simple test case, the attributes and methods are enough.

The sample application and declarative component is build using JDev 11.1.1.9.0 and can be downloaded from GitHub BlogBadgeButton. The sample doesn’t need a DB.

Train Stop Status Handling

A question on the Oracle Developers Community was about how to handle a train stops visited status.

Use Case

The use case behind this was that a train can be used as a workflow visualization. A normal user starts the train, but at one point a manager has to approve something. This approval is one or more stops on the same train. If the manager picks up the workflow he should automatically start with the approval stop. There is no need for him to see the data accumulated in the stops before.

The use case has multiple challenges:

  1. Securing train stops for different user roles
  2. Allow starting the train from any stop
  3. Handling the state of the train stops

The first two challenges are handler by All Aboard, 97. How-to defer train-stop navigation for custom form validation or other developer interaction, and 82. How to programmatically navigate ADF trains.

The missing part is how to handle the train stops ‘visited’ state (see image above). If you start the train directly with ‘Stop 3’ you get this state

UI

To implement this use case, we use a simple UI. It contains an input field, a button and the train which is added to the page as a region.

In the input field names label 1 you can enter the stop where the train should start. If no number is given, the train starts with the first stop. We use this input field to mimic the different starting stop for different users. This is the page when we start the application:

This is the page when we start the final application:

You can navigate between the train stops by using the ‘Back’ and ‘Next’ button, or by clicking the next stop in the train bar. As the stops are set to sequential, you can’t directly click on the 4th stop. You have to go through the stops 1 to 3 first.

Enter a number between 1 and 5 into the input field and tab out of the field will set the parameter for the train task flow and restart the task flow. The navigation is done via a router in the task flow. In the image below the stop number 3 is set as the starting stop for the train

And as you see the stops 1 and 2 are looking like they have visited before.

Implementation

To show how to implement this we start with a simple bounded task flow which builds the train

The start builds a router which we use to navigate to the stop where we want to start the train. The starting stop is passed as parameter to the task flow

In the router, which is marked as default activity, the parameter is used to execute the navigation

The Magic

If you look at the train stop properties in the properties inspector you’ll notice, that there is no property for the visited state

This option is not available in the UI. Oracle has missed or deliberately missed to make this property accessible via the properties. If you dig into the implementation of the train task flow (see the articles provided at the begin of the blog), you’ll see how to access the train and its stops by code:

ViewPortContext currentViewPortCtx = controllerContext.getCurrentViewPort();
TaskFlowContext taskFlowCtx = currentViewPortCtx.getTaskFlowContext();
TaskFlowTrainModel taskFlowTrainModel = taskFlowCtx.getTaskFlowTrainModel();
// get the stop from the map
TaskFlowTrainStopModel currentStop = taskFlowTrainModel.getCurrentStop();

The TaskFlowTrainStopModel doesn’t provide any access to the visited state. If you look at the class definition you’ll notice, that it’s only an interface

which doesn’t provide access to the visited property. Setting a breakpoint in the debugger we can inspect an instance of this interface

and we get the class implementing the interface as:

 oracle.adfinternal.controller.train.TrainStopModel

This class has the visited property we are looking for.

Solution

Now we can implement a method which we call before a train stop gets rendered and which sets the visited property of all previous stops to true.

CAUTION

THIS IN AN INTERNAL CLASS WHICH YOU SHOULD NOT USE!

However, it’s the class we need to get to the property. You have to understand, that the usage of the class has its risks, but that it’s not forbidden. The risk is that Oracle can change or delete the class without notifying you beforehand. So, in later versions, your code might break.

The method checks the task flow parameter if it’s null to set to a number less or equal to 0. In this case, the method returns an empty string. We do this check to avoid that the method does it’s work every time we navigate the train. It should be done only once when the train starts.

If the check finds a positive number, it sets the task flow parameter to zero (line 37).

It then gets the task flow information from the Context (lines 39-43). In line 50 we acquire the current stop before we loop over all previous stops and set their visited property to true (lines 53-59).

The missing part is how to call this method when a train stop is rendered. For this, we use a technique called Lazy Initalizing Beans. The trick is to use a hidden af:outputText and set e.g. the value property of the component to a bean property.

When the page or fragment is rendered, the method getInitStatus() in the bean is called. This is exactly the method shown above. We add this hidden af:outputText to each train stop before the af:train component.

Sample

You can download the sample from GitHub BlogTrainStopStatus. The sample is build using JDev 12.2.1.3 and doesn’t need a DB connection. You can use the same technique in other JDeveloper versions.