Tag Archives: ADF BC

How to use discriminator columns

Environment (JDeveloper 11.1.1.5.0, ADF BC, hr schema)

Sometimes you may have a table with more than one type of rows. For example, a company may have a distinction between  salaried employees, and commissioned employees, but we store all our employees in the employees table rather than create new table for each type of employees. In this post I will explain how to use discriminator columns and extended-entities (sub-entities) to represent a table with two different kinds of rows, each with its own business logic.

This example based on EMPLOYEES table in hr schema with a small modification, one extra column (em_type) is added to the EMPLOYEES table to distinguish between different kinds of employees. You can use this SQL statement to add the column.

ALTER TABLE EMPLOYEES ADD emp_type varchar2(1);

A discriminator column is used to indicate which attribute’s value distinguishes the type of row, You can create different entity objects for each of these types, each one implements its own business logic.  To represents a table with a discriminator column, use the following steps:

  1. Create an entity object based on EMPLOYEES table in hr schema.
  2. Double click on youe entity object to open it in the main window, click on the Attributes node, select the EmpType attribute and click edit.
  3. Check the discriminator check box as shown below, then click OK.

    Discriminator Attribute

  4. In your Application Navigator area, right click on Employees entity, and select New Extended Object from the menu as shown below.

    Create sub-entity

  5. Select your package and enter SalariedEmployee in the Name field, and click OK button.The new Entity Object will be open in the main window.
  6. Select the Attributes node, then select the EmpType attribute and any other attribute you want to override it and click the Override button as shown below.

    Override EmpType attribute

  7. After you click on the button, the Edit (pencil symbol) becomes enabled for the overridden attribute. keep EmpType attribute selected and click the edit symbol.
  8. In the Default value field, enter the value of the discriminator column corresponding to this sub-entity. For a sub-entity handling the salaried employees enter “S” as shown below.

    Add the value of the discriminator column

  9. Click Ok, and repeat steps 4-8 for Commissioned employee entity.
  10. For each sub-entity, you can add the business logic you want.
  11. For common business logic, you can add it in the main entity object.
Advertisements

2 Comments

Filed under ADF

What is Change Indicator property

Recently I was wondering, what is the Change Indicator property that we see in each entity’s attribute?

Change Indicator

In this post I will answer myself. ADF framework provides automatic “lost update” detection for entity objects to ensure that a user cannot unknowingly modify data that another user has updated and committed in the meantime. Typically, this check is performed by comparing the original values of each persistent entity attribute against the corresponding current column values in the database at the time the underlying row is locked. ADF framework checks for row changes as follow:

  1. When the entity cache is first populated, or whenever commit() is called, the framework saves a copy of the data as it is exist in the database. This copy is maintained even if the value in the cache is later changed.
  2. When the transaction attempts to acquire a lock, every attribute in the copy is compared with the corresponding table column. If any of these comparison fail, the frame work throws oracle.jbo.RowInconsistentException.

If you are attempting to acquire locks for many rows, and each row has a large number of column, this can be expensive operation. You can make the lost update detection more efficient by identifying any attributes of your entity whose values you know will be updated whenever the entity is modified. Typical candidates include a version number column or a set of attributes that you know will change every time any value in the row is changed. The change-indicator attribute’s value might be assigned by a database trigger you’ve written and refreshed in the entity object using the Refresh After Insert and Refresh After Update options (in the Edit Attribute dialog).When you use a change indicator, the framework only performs the comparison for attribute in the change indicator instead of for every entity attribute.

3 Comments

Filed under ADF

Differences between Pessimistic and Optimistic Locking

Locking is an RDBMS feature that prevents users from different transactions from causing data conflicts. When locking is acquired on a row, it prevents other transactions from changing that row until the transaction ends. In this post I will explain the differences between pessimistic and optimistic locking in the context of ADF framework.

pessimistic locking:

Most Oracle developers are already familiar with pessimistic locking, which was the default locking in BC4J (now optimistic is the  default in 11.1.2.x)). This means that the row is locked in advance once one of  its attribute is changed through a call to setAttribute() method. If anyone else attempts to acquire a lock of the same row during this process, he will be forced to wait until the first transaction has completed. This is achieved by using the familiar SELECT…FOR UPDATE syntax. This is the safest locking mode because two transactions will never make inconsistent change to the same row. However, this locking mode has disadvantages such that:

  1. If a user selects a record for update, and then leaves for lunch without
    finishing or aborting the transaction. All other users that need to update that record are forced to wait until the user returns and completes the transaction, or until the DBA kills the offending transaction and releases the lock.
  2. The Deadlock – Users A and B are both updating the database at the same time. User A locks a record and then attempt to acquire a lock held by user B – who is waiting to obtain a lock held by user A.

Pessimistic locking, which is the default, should not be used for web applications as it creates pending transactional state in the database in the form of row-level locks. If pessimistic locking is set, state management will work, but the locking mode will not perform as expected. Behind the scenes, every time an application module is recycled, a rollback is issued in the JDBC connection. This releases all the locks that pessimistic locking had created.

An example about pessimistic locking based on well known hr schema, suppose user1 and user2 are two different users (two distinct transactions) using pessimistic locking, both of them try to change the same row of data as follows:

  1. User1 calls EmployeesImpl.setSalary(1000) on a particular row, so user1 immediately acquire a lock on that row.
  2. Now user2 calls EmployeesImpl.setSalary(2000) on the same row, user2 tries to acquire a lock on the row and receives oracle.jbo.AlreadyLockedException.

Optimistic Locking:

Optimistic locking assumes that multiple transactions can complete without affecting each other. Oracle recommends using optimistic locking for web applications. instead of locking a row as soon as it is changed, under optimistic locking, BC4J waits until changed row is posted before attempting to acquire a lock. An exception is not thrown until the conflicting transactions attempt to post their changes to the database.

An example about optimistic locking, suppose user1 and user2 are two different users (two distinct transactions) using optimistic locking, both of them try to change the same row of data as follows:

  1. User1 calls EmployeesImpl.setSalary(1000) on a particular row, user1 does not immediately acquire a lock on that row.
  2. User2 calls EmployeesImpl.setSalary(2000) on  the same row. User1 and User2 now have different entity cache for the same row.
  3. User2 calls commit() action, as part of the commit cycle the changed row is posted to the database. before the update can be executed, user2 acquires a lock on that row. The lock expires immediately, when the commit command is sent to the database.
  4. User1 now calls commit() action, BC4J tries to post the changed row to the database, right before posting it, it attempts to acquire a lock on that row. BC4J recognizes that the row has been changed by another user and that updating the row would overwrite another transaction’s changes, so it throws an oracle.jbo.RowInconsistentException.

Finally, Whatever you use, you can lock a row at any time by calling EntityImpl.lock() on the corresponding entity object instance, even if the locking mode is optimistic.

References:

[1] Oracle 9i Jdeveloper handbook, Peter Koletzeke, Dr. Paul Dorsey, Dr. Avrom Faderman.

[2] Fusion Developer’s Guide for Oracle Application Development Framework
11g Release 1 (11.1.1).

[3] http://www.orafaq.com/papers/locking.pdf

6 Comments

Filed under ADF

How to Create a Custom JSF Validator

Environment (JDeveloper 11.1.1.5.0, ADF BC, ADF Faces, hr schema)

ADF Faces provides several validation types; UI component attributes validation, default ADF Faces validators, and custom ADF Faces validators. The last type (custom ADF Faces validators) enables you to create your own validation logic in a Java class then you can use it as a validator to your UI component. The custom validator can be created for a specific component in a single page, or can be created to be used in all pages in your application. In this example, I will explain how to build your own custom validator that can be used in all pages. This example based on hr schema, mainly on Employees table, and assumed that you already have built your BC. Our business rule is that the PHONE_NUMBER attribute should be at least 9 digits. The steps to build your own validator are:

  1. Create a Java class that implements the javax.faces.validator.Validator
    interface in your viewController project as shown below. In the name field enter “PhoneValidator”, enter your desired package, and in the Optional Attributes section click the green plus symbol to add the interface that this class should implement.

    PhoneValidator class

  2. After you have created the class, you will see the validate method to implement the interface. override this method as shown below.
    public void validate(FacesContext facesContext,
    UIComponent uIComponent,
    Object object)
    throws ValidatorException {
    //add your validation logic here
    String phone = object.toString();
    if (phone.length() < 9) {
    FacesMessage fm =
    new FacesMessage(“Phone number should be at least 9 digits”);
    throw new ValidatorException(fm);
    }
    }
  3. Now you need to register your validator in faces-config.xmlfile, locate this file in your viewController project then double click on it, after the file was opened in your main window click the overview tab, then select the validator link from the left hand side. Click on the green plus symbol to add your validator as shown below.

    register the Phonevalidator

  4. Now our validator is ready to use, create a page, drag and drop the EmployeeView1 from the data control, and select ADF form from the menu.
  5. Right click on the PhoneNumbe filed, and select insert inside Input Text → JSF Core → Validator. Once you add the validator, go to the property inspector palette, select the ValidatorId property then select our PhoneValidator from the list. your page source should look like this source snapshot.
    <af:inputText value=”#{bindings.PhoneNumber.inputValue}”
    label=”#{bindings.PhoneNumber.hints.label}”
    required=”#{bindings.PhoneNumber.hints.mandatory}”
    columns=”#{bindings.PhoneNumber.hints.displayWidth}”
    shortDesc=”#{bindings.PhoneNumber.hints.tooltip}”
    id=”it4″>
    <f:validator binding=”#{bindings.PhoneNumber.validator}”/>
    <f:validator validatorId=”phonevalidator”/>
    </af:inputText>
  6. Run your page and enter a phone number less than 9 digits, submit the form, the error message will be shown as below.

    error message shown after violate PhoneValidator

see also: Add business rule in the setter method of an entity attribute

9 Comments

Filed under ADF

Add business rule in the setter method of an entity attribute

Environment (JDeveloper 11.1.1.5.0, ADF BC, hr schema)

Most of us know how we can add a validation rule using methodValidator on an attribute. However, this is not the only way that we can add a business rule for an attribute, we can add our business rule in the setter method for that attribute.

In this post I will explain how to add business rule in the setter method of an attribute and describe the difference if we add a business rule using methodValidator. This example based on hr schema, mainly on Employees table, and supposed that you already have built your BC. Our business rule is that the PHONE_NUMBER column should be at least 9 digits.

First Part.

The first part of this example is to add a business rule using  validatePhoneNumber method as shown below.

/**
     * Validation method for PhoneNumber.
     */
public boolean validatePhoneNumber(String phonenumber) {
        if (phonenumber.length() < 9)
            return false;
        else
            return true;
    }

What happen when we run our application?

when we run the application and set the phone number field, the following steps take place:

  1. the view object layer calls setAttribute(“PhoneNumber”,”123456789″) method.
  2. setAttribute(“PhoneNumber”,”123456789″) method calls setPhoneNumber(String value) method in our EmployeesEntityImpl class.
  3. setPhoneNumber(String value) calls setAttributeInternal(PHONENUMBER, value) where PHONENUMBER is an integer to identify PhoneNumber attribute.
  4. setAttributeInternal(PHONENUMBER, value) method calls validatePhoneNumber(String phonenumber) method.
  5. if validatePhoneNumber(String phonenumber) method returns true, then PhoneNumber attribute is set with the passed value.

As we can see that at some point during the execution setPhoneNumber(String value) method calls setAttributeInternal(PHONENUMBER, value) which in turns calls the validatePhoneNumber(String phonenumber) method. The difference between setAttributeInternal(PHONENUMBER, value) and setAttribute(“PhoneNumber”,”123456789″) methods is that setAttribute(“PhoneNumber”,”123456789″) invokes the set method for this attribute in a subclass of this Entity Object (if a subclass is generated). The set method name is derived from the attribute name: for example, the method setPhoneNumber pertains to an attribute named “PhoneNumber”.But setAttributeInternal(PHONENUMBER, value) validates and sets the value of an attribute by index, it sets an attribute value after validating the value against declarative-validators set for that attribute.

Second Part.

In this part we will add our business rule to the attribute’s setter method as shown below:

/**
     * If you write validation code in a setter method,
     * you have to throw an exception yourself
     */  

public void setPhoneNumber(String value) throws oracle.jbo.JboException {
        if (value.length() >= 9)
            setAttributeInternal(PHONENUMBER, value);
        else
            throw new oracle.jbo.JboException(“Phone number should be at least 9 digits”);
    }

What happen when we run our application?

The setter method just described implements exactly the same business rule as the validatePhoneNumber method. When we run the application and set the phone number field, the following steps take place:

  1. the view object layer calls setAttribute(“PhoneNumber”,”123456789″) method.
  2. setAttribute(“PhoneNumber”,”123456789″) method calls setPhoneNumber(String value) method in our EmployeesEntityImpl class.
  3. now the business rule is checked in the setter method, if passed then it calls setAttributeInternal(PHONENUMBER, value) method, otherwise it throws the exception and notifies the user with business rule violation.

So, what are the differences between methodValidator business rule and business rule validation inside the setter method.

  1. methodValidator are called during the validation rule stage (i.e. at some point during the execution of setAttributeInternal method). On the other hand, business rule inside the setter may or may not call setAttributeInternal method.
  2. use setter validation If you want your business rule validation comes before other validations. But if you want it to come after some validations rules use a methodValidator.
  3. methodValidator can be used for several attributes, as an example the previously mentioned validatePhoneNumber method can be used for WorkPhone and HomePhone attributes.

see also: How to Create a Custom JSF Validator


3 Comments

Filed under ADF

How to Implement many to many association

Environment (JDeveloper 11.1.1.5.0, ADF BC, hr schema)

Many to many relationship can’t be represented in the physical database (i.e. in the actual database table) because you can’t just associate one key from one table with another key from the other table.  However, many to many relationship can be broken down into a series of two or more of one to many relationships through a table called intersection table. Intersection table is simply a table that contains the primary key of each of the table being connected. Consider the followoing cases as examples about many to many relationships:

  1. A student can take many different courses, and each course can be taken from many different students.
  2. An employee can change his job several times during his career life, and each job can be held by several employees.

In this example I will explain how to implement a many to many association based on hr schema. As mentioned above, each employee can have different jobs at different time interval and each job can be held by several employees . To implement this, I will assume that you have already built your BC, we need (Entity objects, View objects) for these database tables:EMPLOYEES, JOBS, JOBS_HISTORY. The steps to implement many to many association are:

  1. from the right click menu of your entities package node, select New Association.
  2. for the association name, enter EmployeePastJobsAssoc and click next.
  3. in the Entity object window, select * to * as the cardinality of the association. And from the Select Source Attribute area, expand the Employees entity and select EmployeeId attribute. From the Select Intersection Attribute area, expand the JobHistory entity and select the EmployeeId attribute then press the Add button as shown below.

    create EmployeePastJobsAssoc association

  4. from the Select Destination Attribute area, expand the Jobs entity object, then select the JobId attribute. From the Select Intersection Attribute, expand JobHistory entity and select the JobId attribute then press the add button as shown below, then click the Next button.create EmployeePastJobsAssoc association
  5. click Next for other windows, you can accept the default configuration. Then click Finish button.
  6. repeat the steps from 1-5 to create JobHoldersAssoc, but make sure to select the JobId from the Jobs entity from the Select Source Attribute area with the JobId from the JobHistory entity in the Select Intersection Attribute area. And select the EmployeeId from the Employees entity in the Select Destination Attribute with the EmployeeId from JobHistory entity in the Select Intersection Attribute area as shown below.

    create JobHoldersAssoc association

  7. right click on your view package node and select New View Link from the menu. you must see the Create View Link window.
  8. on the name window enter EmployeePastJobsLink in the name field and click next.
  9. in the View Object window, select * to * as the cardinality of the view link. In Select Source Attribute area, expand the EmployeesView node and select the EmployeePastJobsAssoc node. In Select destination Attribute area, expand the JobsView node and select EmployeePastJobsAssoc node then press the Add button as shown below. Click the Next button.

    create EmployeePastJobsLink view link

  10. in View Link Property window accept the default and click the Finish button.
  11. repeat the steps 7-10 to create JobHoldersLink association. Make sure to select the JobHoldersAssoc  from JobsView in the Select Source Attribute area. And select JobHoldersAssoc  from EmployeesView in the Select Destination Attribute area as shown below.

    create JobHoldersLink view link

  12. now open your Application Module, then open the Data Model section. shuttle EmployeesView and JobsView via EmployeePastJobLink to the Data Model area. And shuttle the JobsView and EmployeesView via JobHoldersLink to the data Model area as shown below.

    Add the views to Data Model

  13. select Run from the right click menu on your Application Module.
  14. double click on EmployeePastJobsLink1 to see the employee and his/her past jobs as shown below.

    Employees and his/her past jobs

  15. double click on JobHoldersLink1 to see the Job and its employees’ holders as shown below.

    Jobs and holders


Leave a comment

Filed under ADF

Recover deleted rows without using rollback

Environment (JDeveloper 11.1.1.5.0, ADF BC and ADF Faces)

In many cases developers want to cancel an edit form without using rollback action. Frank Nimphius has implemented this functionality using Java  in this example   006.  How to cancel an edit form, undoing changes in Java. However, this method falls a bit short when a record was deleted and now needs to be recovered. In this example I will explain how to  recover  the deleted rows without using rollback.

In my case I have a table called TEST in my database schema, and I have already created BC (Entity object, View object, Application module). The steps to implement this use case are:

  1. generate the TestImpl class for our TEST entity.
  2. override the remove method in  TestImpl class as shown below:    
    public void remove() {

            refresh(REFRESH_WITH_DB_FORGET_CHANGES);
            super.remove();
        }
  3. generate TestViewImpl  class.
  4. add this method to TestViewImpl class.    
    public void undoDelete(){
    Iterator iterator =
    getEntityDef(0).getAllEntityInstancesIterator(getDBTransaction());
    while (iterator.hasNext()) {
    TestImpl test = (TestImpl)iterator.next();
    if (test.getEntityState() == test.STATUS_DELETED) {
    test.revert();
    }
    }
    executeQuery();
    }
  5. add undoDelete() method to view object client interface, as shown in figure below. The client interface contains the methods from view object class that are available for clients using this object.

    Add client interface

  6. create a page and drag and drop the TestView1 from the data control as ADF table in the page.
  7. add an extra column to the table, then go to the data control, expand TestView1, expand the operation folder, drag and drop removeRowWithKey operation into the newly created column, set the parameter for removeRowWithKey operation to this expression value #{row.rowKeyStr} as shown below.

    removeRowWithKey action

  8. again from the data control, expand TestView1, you should see undoDelete() method as shown below, drag and drop it in the page as a button or a link.

    undoDelete() method

  9. run the page and enjoy with testing.


8 Comments

Filed under ADF