Setting Custom Properties and UI Hints on Dynamically Created View Objects

Send me a mail
 Dive into Oracle ADF   Click to see the XML version of this web page.   (Updated: 2/3/2008; 9:24:23 PM.)
Tips and tricks from Steve Muench on Oracle ADF Framework and JDeveloper IDE

Setting Custom Properties and UI Hints on Dynamically Created View Objects

Creating view objects dynamically is not the most efficient way to use a View Object, but the createViewObjectFromQueryStmt() API on oracle.jbo.ApplicationModule provides the method that can get the job done when you truly don't know the SQL statement you need to execute until runtime. If what's changing at runtime is the where clause, bind variable values, or order by clause, then you can still create the view object in the JDeveloper IDE at design time, and then use runtime API's like setWhereClause(), setWhereClauseParam(), and setOrderByClause(), without having to incur the runtime overhead of describing the SQL query which the createViewObjectFromQueryStmt() method is forced to do. However, when you truly need a dynamic SQL statement, it's the way to go.

One feature of design-time-created view objects is the ability to pre-set custom properties at the view object and view object attribute levels, as well as setting UI Control Hints at the view object attribute level. If you need to dynamically create the view object, these custom properties and UI control hints are not present. The oracle.jbo.* interfaces consciously do not expose the ability for clients to set the custom properties, however this functionality is available in the middle-tier oracle.jbo.server.* framework base classes for you to take advantage of if you want to expose this functionality on demand for a particular application.

Here's an example of a custom method that you can add to any application module's custom Java implementation class to expose a new custom service API like createViewObjectWithHintsFromQueryStmt() to your client applications. Let's say you have an application module named test.TestModule. The following method would go into your TestModuleImpl.java file:

  /**
   * Custom application module method to supplement the base feature of
   * dynamic view object creation with the ability to dynamically set
   * view object-level custom properties or view object attribute-level
   * custom properties at the time of creation.
   *
   * The "properties" array is expected to look like this:
   *
   * {
   *    {           null, "HintName", "HintValue"},
   *    :
   *    etc
   *    :
   *    {"AttributeName", "HintName", "HintValue"}
   *  }
   *
   * Where the first slot in the contained 3-tuples is the name of
   * the attribute on which to set the hint, or else null to set the
   * property at view object level (i.e. not on any specific attribute)
   */
  public ViewObject createViewObjectWithHintsFromQueryStmt(String voInstanceName,
                                                           String sqlStatement,
                                                           String[][] properties) {
    /*
     * First We call the base framework method to create the dynamic view object
     */
    ViewObject vo = createViewObjectFromQueryStmt(voInstanceName,sqlStatement);
    /*
     * Loop over the hints that have been supplied
     */
    for (int z = 0, numHints = properties.length; z < numHints; z++) {
      String attributeName = properties[z][0];
      String propertyName  = properties[z][1];
      String propertyValue = properties[z][2];
      /*
       * If the attribute name is null, set a view object level custom property
       */
      if (attributeName == null) {
        if (propertyName != null) {
          /*
           * Since this code lives in an *Impl.java class (TestModuleImpl.java)
           * it is fine to cast the oracle.jbo.ViewObject interface to the
           * concrete implementation class oracle.jbo.server.ViewObjectImpl
           * If this code were on the client, it is *NOT* ok to do this since
           * it will break the client code's ability to run in a physical 3-tier
           * deployment. We need to cast since the setProperty() method is
           * not available on the client via the oracle.jbo.ViewObject interface
           */
           ((ViewObjectImpl)vo).setProperty(propertyName,propertyValue);
        }
      }
      /*
       * Otherwise, set the custom property on the indicated attribute
       */
      else {
        AttributeDefImpl attrDef = (AttributeDefImpl)vo.findAttributeDef(attributeName);
        attrDef.setProperty(propertyName,propertyValue);
      }
    }
    return vo;
  }

Then, in the application module editor, if you visit the "Client Methods" tab, you can select the createViewObjectWithHintsFromQueryStmt method as one of your exposed client methods. When you (Apply) or (Finish) the wizard, BC4J will create you the test.common.TestModule interface that extends the oracle.jbo.ApplicationModule interface, and adds your custom client-exposed service methods. We place the interface in the ".common" subpackage of your test package to emphasize the fact that this interface is common to both the server tier and the client tier.

Here's an example of a test client program that acquires an instance of the TestModule application module, casts it to our test.common.TestModule interface, and creates a dynamic view object with some dynamically-provided view object and view object attribute-level hints. Then, it illustrates how these dynamic hints are usable by the client API's to retrieve the custom property values, or in the instance of UI Control Hints, retrieve the hints through the UIHelper object associated to each attribute's definition object.

package test;
import oracle.jbo.AttributeDef;
import oracle.jbo.LocaleContext;
import oracle.jbo.Row;
import oracle.jbo.ViewObject;
import oracle.jbo.client.Configuration;
import test.common.TestModule;
/**
 * Example test client class illustrating how to use our custom method
 * for dynamically creating a view object and setting properties on it.
 */
public class Test  {
  public static void main(String[] args) {
    String _am = "test.TestModule", _cf = "TestModuleLocal";
    /*
     * Cast the oracle.jbo.ApplicationModule interface to the custom
     * interface BC4J design time creates for us when we mark the
     * createViewObjectWithHintsFromQueryStmt() method as a "client method".
     */
    TestModule am = (TestModule)Configuration.createRootApplicationModule(_am,_cf);
    /*
     * Call our custom AM method to create the dynamic VO and set the
     * custom properties that we want. Not that the attribute-level properties
     * named "LABEL" and "TOOLTIP" (case-sensitive!) are specific names that
     * BC4J uses to find attribute-level label and tooltip UI hints, but we
     * can set those as well as any other properties via this technique.
     */
    ViewObject vo = am.createViewObjectWithHintsFromQueryStmt(
                   "MyDynamicVOInstance",
                   "select empno, sal, hiredate from emp where rownum < 3 order by sal desc",
                    new String[][]{
                      {null, "SomeViewObjectLevelProperty","SomeValue"},
                      {null, "AnotherViewObjectLevelProperty","AnotherValue"},
                      {"EMPNO","LABEL","Employee ID"},
                      {"EMPNO","TOOLTIP","The identification number of the employee"},
                      {"SAL","LABEL","Monthly Salary"},
                      {"SAL","TOOLTIP","The monthly salary of the employee"},
                      {"HIREDATE","LABEL","Date of Hire"},
                      {"HIREDATE","TOOLTIP","The date on which this employee was hired"}
                    });
    /*
     * Test the VO-level properties on the client level
     */
    System.out.println("SomeViewObjectLevelProperty="+
                       vo.getProperty("SomeViewObjectLevelProperty"));
    System.out.println("AnotherViewObjectLevelProperty="+
                       vo.getProperty("AnotherViewObjectLevelProperty"));
    /*
     * Get the array of attribute definitions for the view object
     */
    AttributeDef[] attrDefs = vo.getAttributeDefs();
    int numAttrs = vo.getAttributeCount();
    LocaleContext loc = am.getSession().getLocaleContext();
    /*
     * Loop over the data in the view object's default rowset.
     * NOTE: Our query has a "rownum < 3" clause so we'll just get 2 records
     */
    while (vo.hasNext()) {
      Row currentRow = vo.next();
      /*
       * Loop over the attributes generically and print out their
       * Label: Value (tip: Tooltip)
       */
      for (int z = 0; z < numAttrs; z++) {
        System.out.println(
          attrDefs[z].getUIHelper().getLabel(loc)+": "+
          currentRow.getAttribute(z)+
          " (Tip: "+
          attrDefs[z].getUIHelper().getTooltip(loc)+
          ")"
        );       
      }
    }
    Configuration.releaseRootApplicationModule(am,true);
  }
}

sdfsdf

SomeViewObjectLevelProperty=SomeValue
AnotherViewObjectLevelProperty=AnotherValue
Employee ID: 7499 (Tip: The identification number of the employee)
Monthly Salary: 1600 (Tip: The monthly salary of the employee)
Date of Hire: 1981-02-20 (Tip: The date on which this employee was hired)
Employee ID: 7369 (Tip: The identification number of the employee)
Monthly Salary: 800 (Tip: The monthly salary of the employee)
Date of Hire: 1980-12-17 (Tip: The date on which this employee was hired)



© Copyright 2008 Steve Muench. Click here to send an email to the editor of this weblog.
Last update: 2/3/2008; 9:24:23 PM.