Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g Release 3 (10.1.3.0)
B25947-01
  Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

25.3 Customizing Framework Behavior with Extension Classes

One of the common tasks you'll perform in your framework extension classes is implementing custom application functionality. Since framework extension code is written to be used by all components of a specific type, the code you write in these classes often needs to work with component attributes in a generic way. To address this need, ADF provides API's that allow you to access component metadata at runtime. It also provides the ability to associate custom metadata properties with any component or attribute. You can write your generic framework extension code to leverage runtime metadata and custom properties to build generic functionality, which if necessary, only is used in the presence of certain custom properties.

25.3.1 How to Access Runtime Metadata For View Objects and Entity Objects

Figure 25-7 illustrates the three primary interfaces ADF provides for accessing runtime metadata about view objects and entity objects. The ViewObject interface extends the StructureDef interface. The class representing the entity definition (EntityDefImpl) also implements this interface. As its name implies, the StructureDef defines the structure and the component and provides access to a collection of AttributeDef objects that offer runtime metadata about each attribute in the view object row or entity row. Using an AttributeDef, you can access its companion AttributeHints object to reference hints like the display label, format mask, tooltip, etc.

Figure 25-7 Runtime Metadata Available for View Objects and Entity Objects

Image shows flow of available metadata for objects

25.3.2 Implementing Generic Functionality Using Runtime Metadata

In Section 7.9.3, "What You May Need to Know About Enabling View Object Key Management for Read-Only View Objects" you learned that for read-only view objects the findByKey() method and the setCurrentRowWithKey built-in operation only work if you override the create() method on the view object to call setManageRowsByKey(true). This can be a tedious detail to remember if you create a lot of read-only view objects, so it is a great candidate for automating in a framework extension class for view objects.

The SRDemo application contains an SRViewObjectImpl class in the FrameworkExtensions project that is the base class for all view objects in the application. That framework extension class for view objects extends the base ViewObjectImpl class and overrides the create() method as shown in Example 25-4 to automate this task. After calling the super.create() to perform the default framework functionality when a view object instance is created at runtime, the code tests whether the view object is a read-only view object with at least one attribute marked as a key attribute. If this is the case, it invokes setManageRowsByKey(true).

The isReadOnlyNonEntitySQLViewWithAtLeastOneKeyAttribute() helper method determines whether the view object is read-only by testing the combination of the following conditions:

  • isFullSql() is true

    This method returns true if the view object's SQL query is completely specified by the developer, as opposed to having the select list derived automatically based on the participating entity usages.

  • getEntityDefs() is null

    This method returns an array of EntityDefImpl objects representing the view object's entity usages. If it returns null, then the view object has no entity usages.

It goes on to determine whether the view object has any key attributes by looping over the AttributeDef array returned by the getAttributeDefs() method. If the isPrimaryKey() method returns true for any attribute definition in the list, then you know the view object has a key.

Example 25-4 Automating Setting Manage Rows By Key

public class SRViewObjectImpl extends ViewObjectImpl {
  protected void create() {
    super.create();
    if (isReadOnlyNonEntitySQLViewWithAtLeastOneKeyAttribute()) {
      setManageRowsByKey(true);
    }
  }
  boolean isReadOnlyNonEntitySQLViewWithAtLeastOneKeyAttribute() {
    if (getViewDef().isFullSql() && getEntityDefs() == null) {
      for (AttributeDef attrDef : getAttributeDefs()) {
        if (attrDef.isPrimaryKey()) {
          return true;
        }
      }
    }
    return false;
  }
  // etc.
}

25.3.3 Implementing Generic Functionality Driven by Custom Properties

In JDeveloper, when you create application modules, view objects, and entity objects you can open the Custom Properties tab of the editor to define custom metadata properties for any component. These are name/value pairs that you can use to communicate additional declarative information about the component to the generic code that you write in framework extension classes. You can use the getProperty() method in your code to conditionalize generic functionality based on the presence of, or the specific value of, one of these custom metadata properties.

For example, the SRViewObjectImpl framework extension class in the SRDemo application overrides the view object's insertRow() method to conditionally force a row to be inserted and to appear as the last row in the row set. If any view object extending this framework extension class defines a custom metadata property named InsertNewRowsAtEnd, then this generic code executes to insert new rows at the end. If a view object does not define this property, it will have the default insertRow() behavior. In the SRDemo application, the ServiceHistories view object defines this custom metadata property so any new rows added to it get inserted at the bottom.

Example 25-5 Conditionally Inserting New Rows at the End of a View Object's Default RowSet

public class SRViewObjectImpl extends ViewObjectImpl {
  private static final String INSERT_NEW_ROWS_AT_END = "InsertNewRowsAtEnd";
  public void insertRow(Row row) {
    super.insertRow(row);
    if (getProperty(INSERT_NEW_ROWS_AT_END) != null) {
      row.removeAndRetain();
      last();
      next();
      getDefaultRowSet().insertRow(row);    
    }
  }
  // etc.
}

In addition to defining component-level custom properties, you can also define properties on view object attributes, entity object attributes, and domains. At runtime, you access them using the getProperty() method on the AttributeDef interface for a given attribute.

25.3.4 What You May Need to Know

{para}?>

25.3.4.1 Determining the Attribute Kind at Runtime

In addition to providing information about an attribute's name, Java type, SQL type, and many other useful pieces of information, the AttributeDef interface contains the getAttributeKind() method that you can use to determine the kind of attribute it represents. This method returns a byte value corresponding to one of the public constants in the AttributeDef interface listed in Table 25-1.

Table 25-1 Entity Object and View Object Attribute Kinds

Public AttributeDef Constant Attribute Kind Description

ATTR_PERSISTENT

Persistent attribute

ATTR_TRANSIENT

Transient attribute

ATTR_ENTITY_DERIVED

View object attribute mapped to an entity-level transient attribute

ATTR_SQL_DERIVED

SQL-Calculated attribute

ATTR_DYNAMIC

Dynamic attribute

ATTR_ASSOCIATED_ROWITERATOR

Accessor attribute returning a RowSet of set of zero or more Rows

ATTR_ASSOCIATED_ROW

Accessor attribute returning a single Row


25.3.4.2 Configuring Design Time Custom Property Names

Once you have written framework extension classes that depend on custom properties, you can set a JDeveloper preference so that your custom property names show in the dropdown list on the Custom Properties tab of the appropriate component editor. To set up these pre-defined custom property names, choose Tools | Preferences from the JDeveloper main menu and open the Business Components > Property Names tab in the Preferences dialog.

25.3.4.3 Setting Custom Properties at Runtime

You may find it handy to programmatically set custom property values at runtime. While the setProperty() API to perform this function is by design not available to clients on the ViewObject, ApplicationModule, or AttributeDef interfaces in the oracle.jbo package, code you write inside your ADF components' custom Java classes can use it.


Note:

You can experiment with an example of this technique by using the ProgrammaticallySetProperties project in the AdvancedExamples workspace. See the note at the beginning of this chapter for download instructions.