Showing posts with label Declarative component. Show all posts
Showing posts with label Declarative component. Show all posts

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!




31 Jan 2014

Binding Container for Declarative Component

Usually a binding container for a declarative component is provided by a page or a page fragment this component is placed on. A declarative component doesn't have its own binding container. For example, there is Main.jspx page with the following code:
    <af:form id="f1">
        <af:declarativeComponent viewId="/component.jsff" id="dc1"/> 
    </af:form>


This page has a page definition file (representing its binding container) MainPageDef.xml:
  <executables>
    <iterator Binds="ViewObj" RangeSize="25" DataControl="AppModuleDataControl"
              id="ViewObjIterator"/>
  </executables>
  <bindings>
     <attributeValues IterBinding="ViewObjIterator" id="EmployeeId">
      <AttrNames>
        <Item Value="EmployeeId"/>
      </AttrNames>
    </attributeValues>
   ...


The component.jsff page fragment looks like this:
   <af:componentDef var="attrs" componentVar="comp">
     <af:panelFormLayout id="pfl1">
        <af:inputText label="#{bindings.EmployeeId.hints.label}"
                      value="#{bindings.EmployeeId.inputValue}"
                      id="ot1"/>
        <af:inputText  label="#{bindings.FirstName.hints.label}"
                       value="#{bindings.FirstName.inputValue}"
                       id="ot2"/>
        <af:inputText  label="#{bindings.LastName.hints.label}"
                       value="#{bindings.LastName.inputValue}"
                       id="ot3"/>
     </af:panelFormLayout>              
   </af:componentDef>

So, the #{bindings} expression will return parent page's binding container and it will work if this container has EmployeeId, FirstName, LastName attribute bindings. We can decouple the declarative component from the exact Ids and pass the bindings to the component as its attributes: 

   <af:componentDef var="attrs" componentVar="comp">
    <af:xmlContent>
        <component xmlns="http://xmlns.oracle.com/adf/faces/rich/component">
          
           <attribute>
              <attribute-name>empId</attribute-name>
           </attribute>
           <attribute>
              <attribute-name>fName</attribute-name>
           </attribute>
           <attribute>
              <attribute-name>lName</attribute-name>
           </attribute>
           
        </component>
     </af:xmlContent>
     <af:panelFormLayout id="pfl1">
        <af:inputText label="#{attrs.empId.hints.label}"
                      value="#{attrs.empId.inputValue}"
                      id="ot1"/>
        <af:inputText  label="#{attrs.fName.hints.label}"
                       value="#{attrs.fName.inputValue}"
                       id="ot2"/>
        <af:inputText  label="#{attrs.lName.hints.label}"
                       value="#{attrs.lName.inputValue}"
                       id="ot3"/>
     </af:panelFormLayout>              
   </af:componentDef>

On the Main,jspx page:
<af:declarativeComponent viewId="/component.jsff" id="dc1">
 <f:attribute name="empId" value="#{bindings.EmployeeId}"/>                       
 <f:attribute name="fName" value="#{bindings.FirstName}"/>                       
 <f:attribute name="lName" value="#{bindings.LastName}"/>                       
</af:declarativeComponent>
 
Let's add to the declarative component a commandButton invoking a method from an application module. For sure, it would be nice to invoke an AM's method through the binding layer. And this method is always the same. It doesn't depend on where the the component is placed on. So, it'd be cool if the component had its own binding container. All we need to do is to comment the af:componentDef tag and leave only af:panelFormLayout, and afterwards we can create a pageDef file as we usually do for any page fragment or a page. If we drag-n-drop an AM's method customMethod from the Data Controls palette onto the declarative component as a commandButton, the framework will create a pageDef file componentPageDef.xml, make the changes in the DataBinding.cpx and the button will look this:
   <af:commandButton text="Button" id="dc_cb1"
                     actionListener="#{bindings.customMethod.execute}"
                     disabled="#{!bindings.customMethod.enabled}"/>


Once the pageDef file is created we have to uncomment back the af:componentDef tag.

But the commandButton is not going to work, since #{bindings} expression will return parent page's binding container but not the component's one.  We can fix that using a backing bean. The ContactInfoBean class has the following methods:
//Get the component's binding container
public BindingContainer getBindings() {
    BindingContext bc = BindingContext.getCurrent();
    return bc.findBindingContainerByPath(getMyself().getViewId());        
}


//Get the reference to the declarative component  
public RichDynamicDeclarativeComponent getMyself() {           
    RichDynamicDeclarativeComponent  _this = 
        (RichDynamicDeclarativeComponent) getValueObject("#{comp}", RichDynamicDeclarativeComponent.class);
    return _this;
}

//Just a helper method for EL evaluation 
public static Object getValueObject(String expr, Class returnType){
  FacesContext fc = FacesContext.getCurrentInstance();
  ELContext elctx  = fc.getELContext();
  ExpressionFactory elFactory = fc.getApplication().getExpressionFactory();
  ValueExpression valueExpr = elFactory.createValueExpression(elctx,expr,returnType);
  return valueExpr.getValue(elctx);
}
 
The command button's declaration should be modified a little bit. We're going to add backingBeanScope.ContactInfoBean before bindings in the EL expressions:
<af:commandButton text="Button" id="dc_cb1"
  actionListener=
  "#{backingBeanScope.ContactInfoBean.bindings.customMethod.execute}"
  disabled="#{!backingBeanScope.ContactInfoBean.bindings.customMethod.enabled}"/>
 
And it works fine now.

The sample application for this post requires JDeveloper 11gR2.

That's it!

17 Apr 2011

Working with Oracle SQL object types

Introduction
Sometimes, it could be convenient to represent real business entities using Oracle object types. For example, address, contact information or some payment instructions - all theses entities have standard set of attributes and, may be, have some internal business logic. It would be handy to define an object type, encapsulating all necessary attributes, and work with it in the same way if it were usual scalar type. In this post I'll show how to work with a simple Oracle object type at the business model level and how to create a declarative component working with this model at the view level.

Use Case
I need to store in my database information about payments. It should contain payment's date, currency, amount and contact information of the person connected with the payment. I'm going to use object type for contact info with the following structure:

create or replace type Tcontact_info as object
(Name Varchar2(100),
 PhoneNumber Varchar2(100),
 CellPhoneNumber Varchar2(100),
 email Varchar2(100)
 )

And the table for payments looks like this:

create table Payment
(ID Number,
 PaymentDate date,
 Currency Varchar2(3),
 Amount Number,
 Contact Tcontact_info
 )


Let's do it

In JDeveloper in the model project I created entity for Payment table using "Create Business Components from Tables" wizard.


The wizard has created entity object with the following structure:


Have a look at the Contact's type. And the wizard has created business domain object TcontactInfo representing Tcontact_info SQL object type:


After that I created entity based view object VPayment and Application Module containing an instance of this view object. If we now explore the Data Controls panel, we will see very interesting picture:



Contact attribute is defined like a child iterator with its own set of attributes and operations. And if we drag-n-drop VPayment from the Data Controls panel to the page, we will see interesting structure in the generated PageDef file:

  <executables>
    <variableIterator id="variables"/>
    <iterator Binds="VPayment" RangeSize="25" DataControl="AppModuleDataControl"
              id="VPaymentIterator"/>
    <accessorIterator MasterBinding="VPaymentIterator" Binds="Contact"
                      RangeSize="25" DataControl="AppModuleDataControl"
                      BeanClass="com.cs.blog.sqlobjectexample.model.common.TcontactInfo"
                      ObjectType="true" id="ContactIterator"/>
  </executables>
  <bindings>
    <!--General payment's attributes: -->   
    <attributeValues IterBinding="VPaymentIterator" id="Amount">
      <AttrNames>
        <Item Value="Amount"/>
      </AttrNames>
    </attributeValues>
    ... 

    <!--Contact's attributes: -->    
    <attributeValues IterBinding="ContactIterator" id="Name">
      <AttrNames>
        <Item Value="Name"/>
      </AttrNames>
    </attributeValues>
    ... 
  </bindings>
  

Access to Contact's attributes is provided via special "accessIterator"! And it works fine as we can see here:

At this point we could say "We are done!", but we are not looking for easy ways! I'm going to create declarative component for contact info in order to  use it widely in my applications.

In my previous post you can see how to create, deploy and use declarative components in details. In "Create JSF Declarative Component Wizard" we need to add attribute "value" with type of business domain TcontactInfo:

          

In jspx file for our declarative component ContactInfo I have added the following content:

<af:panelBox text="Contact Info" id="dc_pb1" showDisclosure="false"
              inlineStyle="width:350.0px;">
  <af:panelFormLayout id="dc_pfl1">
    <af:inputText value="#{attrs.value.name}" label="Person's name"
                  id="dc_it1"></af:inputText>
    <af:inputText value="#{attrs.value.phonenumber}" label="Phone number"
                  id="it6"></af:inputText>
    <af:inputText value="#{attrs.value.cellphonenumber}"
                  label="Cell phone number" id="it5"></af:inputText>
    <af:inputText value="#{attrs.value.email}" label="Email" id="dc_it2"></af:inputText>
    <f:facet name="footer"/>
  </af:panelFormLayout>
 </af:panelBox>

Note, that access to the Contact's attributes is provided using keyword "attrs.value", which is referring to an object of TcontactInfo class.

In my target jspx page I can use new declarative component like this:

<compLib:ContactInfo id="ci1" value="#{bindings.Contact.inputValue}"/> 

And my PageDef looks like this:

  <executables>
    <variableIterator id="variables"/>
    <iterator Binds="VPayment" RangeSize="25" DataControl="AppModuleDataControl"
              id="VPaymentIterator"/>
  </executables>
  <bindings>
    <!--General payment's attributes: --> 
    <attributeValues IterBinding="VPaymentIterator" id="Amount">
      <AttrNames>
        <Item Value="Amount"/>
      </AttrNames>
    </attributeValues>
    ...
    <attributeValues IterBinding="VPaymentIterator" id="Contact">
      <AttrNames>
        <Item Value="Contact"/>
      </AttrNames>
    </attributeValues>
 </bindings>


So, I don't need any "accessorIterator" and define "Contact" as usual scalar attribute. The following screen is presenting the result of our work. Sorry for design:

Are we done? Almost. We can get and show information from the database SQL object type. And we need to be able to put this information back, to save it to the database. Next time.


2 Apr 2011

ADF Declarative Component example

In my previous post I promised to show  how to create ADF Declarative Component for Smart List Of Values. So, I'm going to create a component consisting of three elements: a label, an input text and a combobox list of values. That's very easy. I created a separate ADF ViewController project in my work space:




In this project open the Create JSF Declarative Component wizard:



The new declarative component smartLovDef should have at least three attributes: some string for label, attribute binding for input text and LOV binding for combobox list of values:


The wizard creates metadata file declarativecomp-metadata.xml and smartLovDef.jspx file where we can put the content of our component:


The source code of smartLovDef.jspx looks like this:
<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <af:componentDef var="attrs" componentVar="component">
        
 <af:panelLabelAndMessage label="#{attrs.label}" id="plam1">
  <af:panelGroupLayout id="pgl1" layout="horizontal">
    <af:inputText value="#{attrs.attrBinding.inputValue}"
                  required="#{attrs.attrBinding.hints.mandatory}"
                  columns="#{attrs.attrBinding.hints.displayWidth}"
                  id="deptid" partialTriggers="departmentNameId"
                 autoSubmit="true" simple="true"/>
    <af:inputComboboxListOfValues id="departmentNameId"
                popupTitle="Search and Select: #{attrs.lovBinding.hints.label}"
                value="#{attrs.lovBinding.inputValue}"
                model="#{attrs.lovBinding.listOfValuesModel}"
                columns="#{attrs.lovBinding.hints.displayWidth}"
                shortDesc="#{attrs.lovBinding.hints.tooltip}"
                partialTriggers="deptid"
               simple="true">
    </af:inputComboboxListOfValues>
  </af:panelGroupLayout>
 </af:panelLabelAndMessage>

    <af:xmlContent>
      <component xmlns="http://xmlns.oracle.com/adf/faces/rich/component">
        <display-name>smartLovDef</display-name>
        <attribute>
          <attribute-name>label</attribute-name>
          <attribute-class>java.lang.String</attribute-class>
          <required>true</required>
        </attribute>
        <attribute>
          <attribute-name>attrBinding</attribute-name>
          <attribute-class>java.lang.Object</attribute-class>
          <required>true</required>
        </attribute>
        <attribute>
          <attribute-name>lovBinding</attribute-name>
          <attribute-class>java.lang.Object</attribute-class>
          <required>true</required>
        </attribute>
        <component-extension>
          <component-tag-namespace>cscomponent</component-tag-namespace>
          <component-taglib-uri>/componentLib</component-taglib-uri>
        </component-extension>
      </component>
    </af:xmlContent>
  </af:componentDef>
</jsp:root>

The next step is to deploy the component into ADF Library. We have to add new deployment profile for the CSComponents project:




And let's deploy the project into library:



The following step is to define File System connection in the resource palette to the deployment path of CSComponents project:



After that we have to choose the project where we're going to use the new component (in my case ViewConroller) and add CSComponents.jar library to it:



Now we can use smartLovDef  component in our page and drag it from the component palette:



In our jspx page the source code is going to look like this:

    <cscompLib:smartLovDef label="#{bindings.DepartmentId.label}"
                        attrBinding="#{bindings.DepartmentId}" 
                        lovBinding="#{bindings.DepartmentName}"
                        id="sld1"/>