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"/>