Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers 10g (10.1.3.1.0) Part Number B25947-01 |
|
|
View PDF |
Whenever you create a new business component, if necessary, you can extend an existing one to create a customized version of the original. For example, in the SRDemo application, as shown in Figure 25-9, the ServiceRequestsByStatus
view object extends the ServiceRequests
view object to add a named bind variable named TheStatus
and to customize the WHERE
clause to reference that bind variable.
While the figure shows a view object example, this component inheritance facility is available for all component types. When one component extends another, the extended component inherits all of the metadata and behavior from the parent it extends. In the extended component, you can add new features or customize existing features of its parent component both through metadata and Java code.
Note: The examples in this section refer to theBaseProject project in the AdvancedExamples workspace. See the note at the beginning of this chapter for download instructions. |
To create an extended component, use the component wizard in the New Gallery for the type of component you want to create. For example, to create an extended view object, you use the Create View Object wizard. On the Name page of the wizard — in addition to specifying a name and a package for the new component — provide the fully-qualified name of the component that you want to extend in the Extends field. To pick the component name from a list, use the Browse button next to the Extends field. Then, continue to create the extended component in the normal way using the remaining panels of the wizard.
As you've learned, the ADF business components you create are comprised of an XML component definition and an optional Java class. When you create a component that extends another, JDeveloper reflects this component inheritance in both the XML component definition and in any generated Java code for the extended component.
JDeveloper notes the name of the parent component in the new component's XML component definition by adding an Extends
attribute to the root component element. Any new declarative features you add or any aspects of the parent component's definition you've overridden appear in the extended component's XML component definition. In contrast, metadata that is purely inherited from the parent component is not repeated for the extended component.
Example 25-15 shows what the ServiceRequstsByStatus.xml
XML component definition for the ServiceRequstsByStatus
view object looks like. Notice the Extends
attribute on the ViewObject element, Variable element related to the additional bind variable added in the extended view object, and the overridden value of the Where
attribute for the WHERE clause that was modified to reference the StatusCode
bind variable.
Example 25-15 Extended Component Reflects Parent in Its XML Descriptor
<ViewObject Name="ServiceRequestsByStatus" Extends="oracle.srdemo.model.queries.ServiceRequests" Where="((ServiceRequest.CREATED_BY = CreatedByUser.USER_ID) AND (ServiceRequest.ASSIGNED_TO = AssignedToUser.USER_ID(+))) AND (ServiceRequest.PROD_ID = Product.PROD_ID) AND STATUS LIKE NVL(:StatusCode,'%')" OrderBy="REQUEST_DATE DESC" BindingStyle="OracleName" CustomQuery="false" ComponentClass="oracle.srdemo.model.queries.ServiceRequestsByStatusImpl" FetchMode="FETCH_AS_NEEDED" UseGlueCode="false" > <Variable Name="StatusCode" Kind="where" Type="java.lang.String" DefaultValue="%" > </Variable> </ViewObject>
If you enable custom Java code for an extended component, JDeveloper automatically generates the Java classes to extend the respective Java classes of its parent component. In this way, the extended component can override any aspect of the parent component's programmatic behavior as necessary. If the parent component is an XML-only component with no custom Java class of its own, the extended component's Java class extends whatever base Java class the parent would use at runtime. This could be the default ADF Business Components framework class in the oracle.jbo.server
package, or could be your own framework extension class if you have specified that in the Extends dialog of the parent component.
In addition, if the extended component is an application module or view object and you enable client interfaces on it, JDeveloper automatically generates the extended component's client interfaces to extend the respective client interfaces of the parent component. If the respective client interface of the parent component does not exist, then the extended component's client interface directly extends the appropriate base ADF Business Components interface in the oracle.jbo
package.
{para}?>
Since an extended component is a customized version of its parent, code you write that works with the parent component's Java classes or its client interfaces works without incident for either the parent component or any customized version of that parent component.
For example, assume you have a base Products
view object with custom Java classes and client interfaces like:
class ProductsImpl
row class ProductsRowImpl
interface Products
row interface ProductsRow
If you create a ProductsByName
view object that extends Products
, then you can use the base component's classes and interface to work both with Products
and ProductsByName
.
Example 25-16 illustrates a test client program that works with the Products
, ProductsRow
, ProductsByName
, and ProductsByNameRow
client interfaces. A few interesting things to note about the example are the following:
You can use parent Products
interface for working with the ProductsByName
view object that extends it.
Alternatively, you can cast an instance of the ProductsByName
view object to its own more specific ProductsByName
client interface.
You can test if row ProductsRow
is actually an instance of the more specific ProductsByNameRow
before casting it and invoking a method specific to the ProductsByNameRow
interface.
Example 25-16 Working with Parent and Extended Components
package devguide.advanced.extsub; /* imports omitted */ public class TestClient { public static void main(String[] args) { String amDef = "devguide.advanced.extsub.ProductModule"; String config = "ProductModuleLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef,config); Products products = (Products)am.findViewObject("Products"); products.executeQuery(); ProductsRow product = (ProductsRow)products.first(); printAllAttributes(products,product); testSomethingOnProductsRow(product); // 1. You can use parent Products interface for ProductsByName products = (Products)am.findViewObject("ProductsById"); // 2. Or cast it to its more specific ProductsByName interface ProductsByName productsById = (ProductsByName)products; productsById.setProductName("Ice"); productsById.executeQuery(); product = (ProductsRow)productsById.first(); printAllAttributes(productsById,product); testSomethingOnProductsRow(product); am.getTransaction().rollback(); Configuration.releaseRootApplicationModule(am,true); } private static void testSomethingOnProductsRow(ProductsRow product) { try { // 3. Test if row is a ProductsByNameRow before casting if (product instanceof ProductsByNameRow) { ProductsByNameRow productByName = (ProductsByNameRow)product; productByName.someExtraFeature("Test"); } product.setName("Q"); System.out.println("Setting the Name attribute to 'Q' succeeded."); } catch (ValidationException v) { System.out.println(v.getLocalizedMessage()); } } private static void printAllAttributes(ViewObject vo, Row r) { String viewObjName = vo.getName(); System.out.println("Printing attribute for a row in VO '"+ viewObjName+"'"); StructureDef def = r.getStructureDef(); StringBuilder sb = new StringBuilder(); int numAttrs = def.getAttributeCount(); AttributeDef[] attrDefs = def.getAttributeDefs(); for (int z = 0; z < numAttrs; z++) { Object value = r.getAttribute(z); sb.append(z > 0 ? " " : "") .append(attrDefs[z].getName()) .append("=") .append(value == null ? "<null>" : value) .append(z < numAttrs - 1 ? "\n" : ""); } System.out.println(sb.toString()); } }
Running the test client above produces the following results:
Printing attribute for a row in VO 'Products' ProdId=100 Name=Washing Machine W001 Checksum=I am the Product Class Setting the Name attribute to 'Q' succeeded. Printing attribute for a row in VO 'ProductsById' ProdId=119 Name=Ice Maker I012 Checksum=I am the Product Class SomeExtraAttr=SomeExtraAttrValue ## Called someExtraFeature of ProductsByNameRowImpl Setting the Name attribute to 'Q' succeeded.
Note: In this example, Products is an entity-based view object based on theProduct entity object. The Product entity object includes a transient Checksum attribute that returns the string "I am the Product class". You'll learn more about why this was included in the example in Section 25.10, "Substituting Extended Components In a Delivered Application". |
When you create an extended component, the Class Extends button on the Java page of the extended component is disabled. This is due to the fact that JDeveloper automatically extends the appropriate class of its parent component, so it does not make sense to allow you to select a different class.
When you create an extended entity object, you can introduce new attributes, new associations, new validators, and new custom code. You can override certain declarative aspects of existing attributes as well as overriding any method from the parent component's class.
When you create an extended view object, you can introduce new attributes, new view links, new bind variables, and new custom code. You can override certain declarative aspects of existing attributes as well as overriding any method from the parent component's class.
When you create an extended application module, you can introduce new view object instances or new nested application module instance and new custom code. You can also override any method from the parent component's class.
If you add new attributes in an extended entity object or view object, the attribute index numbers are computed relative to the parent component. For example, consider the Products
view object mentioned above. If you enable a custom view row class, it might have attribute index constants defined in the ProductsRowImpl.java class like this:
public class ProductsRowImpl extends ViewRowImpl implements ProductsRow { public static final int PRODID = 0; public static final int NAME = 1; public static final int CHECKSUM = 2; //etc. }
When you create an extended view object like ProductsByName, if that view object adds an addition attribute like SomeExtraAttr
and has a custom view row class enabled, then its attribute constants will be computed relative to the maximum value of the attribute constants in the parent component:
public class ProductsByNameRowImpl extends ProductsRowImpl implements ProductsByNameRow { public static final int MAXATTRCONST = ViewDefImpl.getMaxAttrConst("devguide.advanced.extsub.Products"); public static final int SOMEEXTRAATTR = MAXATTRCONST;
Additional attributes would have index values of MAXATTRCONST+1
, MAXATTRCONST+2
, etc.
After defining an extended component, JDeveloper allows you to change the parent component from which an extended component inherits. You can accomplish by:
Selecting the extended component in the Application Navigator
Using the Property Inspector to change the Extends
property
However, you cannot currently use this technique to change the extended component to not inherit from any parent. The one exception to this limitation is the entity object, whose component editor offers an Extends field on the Name page that you can blank out if necessary. For all other extended components, to make them no longer extend from a parent component you need to delete and recreate them to accomplish this.