30 Sept 2016

Time Picker Declarative Component

Recently I came across the following requirement: there is a Timestamp attribute in an entity and users should be able to modify only time part (hours and minutes) of the attribute value.

Apparently,  this requirement could be implemented with a kind of a time-picker component allowing  to input hours and minutes but hiding the date part. There is date-time-picker (af:inputDate) component in ADF Faces, but there is no just time-picker. The solution is to make a declarative component out of two input-number-spinboxes (one for hours, one for minutes):

<af:xmlContent>
    <afc:component>
        <afc:description/>
        <afc:display-name>TimePicker</afc:display-name>
        <afc:attribute>
            <afc:attribute-name>valueBinding</afc:attribute-name>
            <afc:attribute-class>
              oracle.jbo.uicli.binding.JUCtrlAttrsBinding
            </afc:attribute-class>
        </afc:attribute>
        <afc:attribute>
            <afc:attribute-name>label</afc:attribute-name>
            <afc:attribute-class>java.lang.String</afc:attribute-class>
        </afc:attribute>
    </afc:component>
</af:xmlContent>
<af:panelLabelAndMessage label="#{attrs.label}" id="pll1">
    <af:panelGroupLayout id="dc_pgl1" layout="horizontal">
        <af:inputNumberSpinbox simple="true" id="dc_ins1"
                               value="#{backingBeanScope.timePicker.hours}"
                               minimum="0" maximum="23"/>
        <af:spacer width="10" height="10" id="dc_s1"/>
        <af:inputNumberSpinbox simple="true" id="dc_ins2"
                               value="#{backingBeanScope.timePicker.minutes}"
                               minimum="0" maximum="59">
        </af:inputNumberSpinbox>
    </af:panelGroupLayout>
</af:panelLabelAndMessage>


Note, that values for the input-number-spinboxes are provided by backing bean properties. The timePicker backing bean is responsible for extracting hours and minutes from the timestamp value of the attribute value binding which is passed to the component as valueBinding attribute. This is not a big deal with Java 8 Date/Time API:
    private JUCtrlAttrsBinding getValueBinding() {
       return (JUCtrlAttrsBinding) getAttributes().get("valueBinding");
    }


    private LocalDateTime getTime() {
        Timestamp timeStampTime =
            (Timestamp) getValueBinding().getInputValue();
        return timeStampTime.toLocalDateTime();
    }


    public Integer getHours() {
        return getTime().getHour();
    }


    public Integer getMinutes() {
        return getTime().getMinute();
    }


On the other hand, the setters of hours and minutes of the backing bean properties create a new Timestamp instance out of hours and minutes and set it as an input value of the valueBinding attribute:
    public void setHours(Integer value) {
        setTime(value, getMinutes());
    }


    public void setMinutes(Integer value) {
        setTime(getHours(), value);
    }

    private void setTime(int hours, int minutes) {
      LocalDateTime time =
        LocalDateTime.of(getTime().toLocalDate(), LocalTime.of(hours, minutes));

      getValueBinding().setInputValue(Timestamp.valueOf(time));
    }

The sample application for this post, containing the TimePicker declarative component, is available here. It requires JDeveloper 12.2.1.1.

That's it!




17 Sept 2016

Customizing View Link Where Clause

Master-detail behavior is one of the most common use cases. Whenever we need to implement master-detail relationship between  two view objects we use view links for that. Usually, we do that declaratively with JDeveloper's wizard. The corresponding where clauses will be generated by the framework at runtime. For most cases it's enough, it works fine and we don't need to worry about anything else.

However, sometimes the definition of master-detail relationship is not that trivial.  For example, there is a page containing employee's details and a list of employee's colleagues. Like this:


We're building Employee-Colleagues master-detail relationships with the following view link:



Basically, we are selecting all employees of the same department. But! In this case the colleagues detail list will contain the master employee as well. The employee will be shown twice: on the form and in the colleagues list. We don't want that and we'd like to exclude the employees from their colleagues list.

We are adding one more pair of attributes to the view link definition:


















The framework at runtime will generate the following where clause for selecting colleagues:






Obviously, this is not what we actually want. So, we're going to manually specify the where clause to be used for this view link in the property inspector:









And now it will work as it is supposed to, selecting all employees of the my department except myself.


The sample application for this post is available here. It requires JDeveloper 12.2.1.1.

That's it!


10 Aug 2016

New ADF BC Base Classes

In this short post I just want to draw everyone's attention to the fact that in the latest JDeveloper version 12.2.1.1 the set of ADF BC base classes contains more classes then there used to be. They have added base classes for programatic Entity objects (ProgrammaticEntityImpl) and View objects (ProgrammaticViewObjectImpl, ProgrammaticViewRowImpl).





So, if you're planning to migrate to 12.2.1.1, don't forget to extend those classes as well in order to be consistent.

That's it!

21 Jul 2016

ADF BC View Object level Triggers

The latest JDeveloper release 12.2.1.1 came up with a new feature. Now we can define View Object level triggers just like we used to do with entities.  These triggers can be used as extension points provided by the framework to interfere in the VO lifecycle with Groovy script.

There are five available trigger points at this moment:



BeforeExecute
BeforeExecute trigger fires at the very beginning of VO execute lifecycle. Basically, it is invoked by prepareRowSetForQuery method which is a good place to assign bind variable values or modify the where clause for a specific row set. The source of this trigger is VO, so we can refer to VO's methods and properties using source keyword.

Criteria
Criteria trigger fires each time whenever the framework constructs a where clause for a view critera.
The source of this trigger is VO, so the VO instance can be referred with source keyword.

CriteriaItem
CriteriaItem trigger fires each time whenever the framework constructs a where clause for a specific view critera item.  So, we can specify for which VC item the trigger event should occur.

BeforeCreate
If we need to add some logic just before a new view object row is created we can use BeforeCreate trigger for that. The source of this trigger is VO row, so an instance of the VO row which is being created can be accessed with source keyword.

Modify
Whenever a VO attribute is being modified, the framework invokes Modify trigger. We can specify for which attribute the trigger should work. The source of this trigger is the VO row which is accessible with source keyword.


That's it!




8 Jul 2016

Deep Dive into Oracle ADF Transactions : Advanced Techniques

In this post I would like to thank everyone, who managed to attend my session "Deep Dive into Oracle ADF Transactions : Advanced Techniques" at ODTUG Kscope16 conference in Chicago, IL. Thank you guys for coming to listen to me, to learn something new and to support me. 

I promised at the session that the presentation would be available for download. 
The presentation is available here:

That's it!


30 Apr 2016

Application Modules and Entity Cache

Any ADF developer with some basic knowledge of ADF Business Components would be familiar with the following diagram:


It represents the core building blocks of ADF Business Components at run-time. There is an instance of a root application module containing view object instances. View object instances might be backed up by entity objects that are stored in entity collection or in other words entity cache. A root application module may also contain nested application modules which in their turn my contain their own view object instances. This is very important that all view object instances and nested application modules within a single root AM share the same entity cache. The question is How? 

The diagram above represents a very simple case. There is only one user session and it is assumed that there is only one root application module in the application. However, ADF BC suppose that each user session has its own entity cache. So, what links my application module to my and only my entity cache?
And here is where DB Transaction object comes to the scene:


It is an internal framework object that actually contains entity cache and provides it to all application modules registered with this DB Transaction object. Furthermore DB Transaction object contains a DB connection and it provides all jdbc-related services such as creating and executing callable statements. Many developers think that actually application module is responsible for containing entity cache, holding DB connection and interacting with database. That's not actually true. An application module is just attached to DB Transaction object consuming entity cache and DB connection from it. The word "attached" means that there could be many root application modules referring to the same DB Transaction object.


In that case the transaction is called "shared". Each application module attached to it consumes the same DB Connection and the same entity cache. There is a common myth that any instance of a root application module always requires a dedicated DB connection. Obviously, that's not always the case.

This feature is based on jbo.shared.txn AM property. It means that all root application modules with the same value of this property will share the same DB Transaction object and therefore the same DB connection and entity cache. The "shared transaction" feature is commonly used for shared application modules so that by setting the same string value for their jbo.shared.txn property we can force them to share the same DB connection.

That's it!


9 Apr 2016

ADF Separator Skinning

In this very short post I am going to show how we can easily change look&feel of af:separator component.  Let's say we need to make the separator blue and a little thicker. It can be done with the following CSS style:

.MySeparator {
    border: 3px solid #0572ce;   
}

and af:separator component should reference this style:

<af:separator id="s1" styleClass="MySeparator"/> 

The result of this skinning work looks like this:

That's it!

21 Feb 2016

Custom View Criteria Item Operators

There is a nice feature in JDeveloper 12c which allows to define custom where clauses for View Criteria Items declaratively.

Let's say there is a view object CountryVO. I need to define a view criteria PopularCountriesCriteria for this VO. So, basically, I need a where clause like this:  "Code IN (select code from VPopularCountryCodes)".

In order to do that before 12c we had to ether update View Object source XML code or override ViewObjectImpl methods such as getCriteriaItemClause or getViewCriteriaClause. Now we can do that in a bit more civilized way.

There is Custom Operators tab on the Edit View Criteria screen where we can define our custom POPULAR operator:









Having done that, we can use POPULAR operator while defining a view criteria item:


That's it!

29 Jan 2016

Dynamic Iterator Binding Definition

In one of my previous posts I showed how we can use multiple iterator binding definitions to represent data on a page provided by different row sets of a single VO instance. A blog reader asked me a reasonable question about this technique. Suppose that at design time we don't know what row sets and what view objects are going to be shown on a page. So, we're not able to define all necessary iterator bindings in the page def file at design time. Is it possible to dynamically create those iterator binding definitions at run time? Yes, it is!

This job can be done using the following managed bean method:

private DCIteratorBinding createIterator(String iteratorName, String voName,
                                         String dataControlName, String rsiName)
{
  DefinitionFactory defFactory =
    JUMetaObjectManager.getJUMom().getControlDefFactory();
 
  //Create and init an iterator binding definition
  JUIteratorDef iterDef = (JUIteratorDef)
    defFactory.createControlDef(DCDefBase.PNAME_Iterator);

  HashMap initValues = new HashMap();
  initValues.put(JUTags.ID, iteratorName);
  initValues.put(JUTags.DataControl, dataControlName);
  initValues.put(JUTags.PNAME_VOName, voName);
  initValues.put(JUTags.PNAME_RSIName, rsiName);

  iterDef.init(initValues);

  //Create an iterator binding instance
  DCIteratorBinding iter =
    iterDef.createIterBinding(BindingContext.getCurrent(), getBindings());

  //Add the instance to the current binding container
  getBindings().addIteratorBinding(iteratorName, iter);

  return iter;
}

At the very beginning the method gets an instance of the control definition factory. This factory is used to produce an iterator binding definition object. This definition is going to be initialized with a map containing iterator name, data control name, view object name and row set name. So, basically, all those attributes that we set up for an iterator binding definition in a page def file at design time. Finally, the method creates an iterator binding instance and adds it to the current binding container.

This managed bean method can be consumed while creating dynamic value bindings such as an attribute value binding, a button value binding, a lov binding, a tree binding etc. Examples of these techniques are described and implemented in a sample application here.

That's it!

24 Jan 2016

Handling the Close Icon for Dialogs with Running Task Flows

We can run an ADF bounded task flow in a modal dialog using out-of-the-box ADF controller functionality. This feature is fully described in the documentation. So, let's say there is task-flow-definition which we want to run in a dialog from Main page:

In order to get it working we have to set up task flow call activity property Run As Dialog to true and the Display Type property to inline-popup. Besides that the caller command button should have the useWindow property set to true:

  <af:button text="Dialog" id="b1" useWindow="true"
             action="dlg"
             returnListener="#{pageFlowScope.TheBean.returnDialogListener}"/>

Whenever the task flow reaches its Return activity, the framework closes the dialog and invokes a return listener specified for the caller command button. In this way a caller is notified that the dialog is closed and it is able to handle the task flow return values. 

However, if the user closes the dialog using a standard close icon, the task flow is considered abandoned and the framework won't fire any event. So, the caller will never know about that. Obviously, there are some use-cases when the caller needs to get notified about such case. This requirement can be implemented using Chaperone technique. 

Let's define the following interface:

public interface DialogCancelListener {
  void dialogCanceled();
}

and implement it with our caller managed bean (TheBean):

  @Override
  public void dialogCanceled(){
     //Handle dialog cancel event
  }


There is an input parameter of the task flow:

<input-parameter-definition id="__6">
 <name>cancelListener</name>
 <value>#{pageFlowScope.FlowBean.cancelListener}</value>
 <class>com.adfpractice.taskflowdialogapp.view.DialogCancelListener</class>
</input-parameter-definition>

The value of this parameter is going to be an instance of our caller managed bean:


The task-flow-definition looks like this:

So, whenever the task flow is about to be finished in a normal way it is going to set up return values that will be handled by the caller in the return listener. If the user finishes the task flow by clicking on the close icon, the task flow is abandoned and setupReturnValues method will never be invoked. The task flow has a finalizer checking if the return values have been set up. If they have not been set up it invokes dialogCanceled method of the cancelListener.

  public void taskFlowFinalizer() {
    if (!returnValuesSetUp) {
      cancelListener.dialogCanceled(); 
    }
  }
In his way the caller managed bean (TheBean) is going to be notified about abandoning of the target task flow.

That's it!