Oracle® Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework 11g Release 1 (11.1.1) B31974-06 |
|
![]() Previous |
![]() Next |
This chapter explains the key entity object events and features for implementing the most common kinds of business rules.
This chapter includes the following sections:
Section 8.3, "Assigning Programmatically Derived Attribute Values"
Section 8.4, "Undoing Pending Changes to an Entity Using the Refresh Method"
Section 8.6, "Accessing Related Entity Rows Using Association Accessors"
Section 8.7, "Referencing Information About the Authenticated User"
Section 8.9, "Storing Information About the Current User Session"
Section 8.11, "Sending Notifications Upon a Successful Commit"
Section 8.12, "Conditionally Preventing an Entity Row from Being Removed"
Section 8.13, "Determining Conditional Updatability for Attributes"
Complementing the built-in declarative validation features, entity objects and view objects have method validators and several events you can handle to programmatically implement encapsulated business logic using Java code. These concepts are illustrated in Figure 8-1.
Attribute-level method validators trigger validation code when an attribute value changes.
Entity-level method validators trigger validation code when an entity row is validated.
You can override the following key methods in a custom Java class for an entity:
create()
, to assign default values when a row is created
initDefaultExpressionAttributes()
, to assign defaults either when a row is created or when a new row is refreshed
remove()
, to conditionally disallow deleting
isAttributeUpdateable()
, to make attributes conditionally updatable
setAttribute()
, to trigger attribute-level method validators
validateEntity()
, to trigger entity-level method validators
prepareForDML()
, to assign attribute values before an entity row is saved
beforeCommit()
, to enforce rules that must consider all entity rows of a given type
afterCommit()
, to send notifications about a change to an entity object's state
Note: When coding programmatic business rules, it's important to have a firm grasp of the validation cycle. For more information, see Section 7.2, "Understanding the Validation Cycle." |
Method validators are the primary way of supplementing declarative validation rules and Groovy-scripted expressions using your own Java code. Method validators trigger Java code that you write in your own validation methods at the appropriate time during the entity object validation cycle. There are many types of validation you can code with a method validator, either on an attribute or on an entity as a whole.
You can add any number of attribute-level or entity-level method validators, provided they each trigger a distinct method name in your code. All validation method names must begin with the word validate
; however, following that rule you are free to name them in any way that most clearly identifies the functionality. For an attribute-level validator, the method must take a single argument of the same type as the entity attribute. For an entity-level validator, the method takes no arguments. The method must also be public, and must return a boolean value. Validation will fail if the method returns false
.
Note: Although it is important to be aware of these rules, when you use JDeveloper to create method validators, JDeveloper creates the correct interface for the class. |
At runtime, the Method validator passes an entity attribute to a method implemented in your entity object class.
In Example 8-1, the method accepts strings that start with a capital letter and throws an exception on null values, empty strings, and strings that do not start with a capital letter.
Example 8-1 Method That Validates If the First Letter Is a Capital
public boolean validateIsCapped(String text) { if (text != null && text.length() != 0 && text[0] >= 'A' && text[0] <= 'Z') { return true; } }
To create an attribute-level Method validator:
In the Application Navigator, double-click the desired entity object.
In the overview editor, click the Java navigation tab.
The Java page shows the Java generation options that are currently enabled for the entity object. If your entity object does not yet have a custom entity object class, then you must generate one before you can add a Method validator. To generate the custom Java class, click the Edit icon, then select Generate Entity Object Class, and click OK to generate the *.java
file.
Click the Business Rules navigation tab, and then expand the Attributes node, and select the attribute that you want to validate.
Click the New icon to add a validation rule.
Select Method from the Rule Type dropdown list.
The Add Validation Rule dialog displays the expected method signature for an attribute-level validation method. You have two choices:
If you already have a method in your entity object's custom Java class of the appropriate signature, it will appear in the list and you can select it after deselecting the Create and Select Method checkbox.
If you leave the Create and Select Method checkbox selected (see Figure 8-2), you can enter any method name in the Method Name box that begins with the word validate
. When you click OK, JDeveloper adds the method to your entity object's custom Java class with the appropriate signature.
Finally, supply the text of the error message for the default locale that the end user should see if this validation rule fails.
When you add a new method validator, JDeveloper updates the XML component definition to reflect the new validation rule. If you asked to have the method created, the method is added to the entity object's custom Java class. Example 8-2 illustrates a simple attribute-level validation rule that ensures that the OrderShippedDate
of an order is a date in the current month. Notice that the method accepts an argument of the same type as the corresponding attribute, and that its conditional logic is based on the value of this incoming parameter. When the attribute validator fires, the attribute value has not yet been set to the new value in question, so calling the getOrderShippedDate()
method inside the attribute validator for the OrderShippedDate
attribute would return the attribute's current value, rather than the candidate value that the client is attempting to set.
Example 8-2 Simple Attribute-Level Method Validator
public boolean validateOrderShippedDate(Date data) { if (data != null && data.compareTo(getFirstDayOfCurrentMonth()) <= 0) { return false; } return true; }
Note: The return value of thecompareTo() method is zero (0 ) if the two dates are equal, negative one (-1 ) if the first date is less than the second, or positive one (1 ) if the first date is greater than the second. |
To create an entity-level method validator:
In the Application Navigator, double-click the desired entity object.
In the overview editor, click the Java navigation tab.
The Java page shows the Java generation options that are currently enabled for the entity object. If your entity object does not yet have a custom entity object class, then you must generate one before you can add a Method validator. To generate the custom Java class, click the Edit icon, then select Generate Entity Object Class, and click OK to generate the *.java
file.
Click the Business Rules navigation tab, and then select the Entity node.
Click the New icon to add a validation rule.
Select Method from the Rule Type dropdown list.
The Add Validation Rule dialog displays the expected method signature for an entity-level validation method. You have two choices:
If you already have a method in your entity object's custom Java class of the appropriate signature, it will appear in the list and you can select it after deselecting the Create and Select Method checkbox.
If you leave the Create and Select Method checkbox selected (see Figure 8-3), you can enter any method name in the Method Name box that begins with the word validate
. When you click OK, JDeveloper adds the method to your entity object's custom Java class with the appropriate signature.
Finally, supply the text of the error message for the default locale that the end user should see if this validation rule fails.
When you add a new method validator, JDeveloper updates the XML component definition to reflect the new validation rule. If you asked to have the method created, the method is added to the entity object's custom Java class. Example 8-3 illustrates a simple entity-level validation rule that ensures that the OrderShippedDate
of an order comes after the OrderDate
.
Like the locale-specific UI control hints for entity object attributes, the validation rule error messages are added to the entity object's component message bundle file. These entries in the message bundle represent the strings for the default locale for your application. To provide translated versions of the validation error messages, follow the same steps as for translating the UI control hints, as described in Section 4.7, "Working with Resource Bundles."
When declarative defaulting falls short of your needs, you can perform programmatic defaulting in your entity object:
When an entity row is first created
When the entity row is first created or when refreshed to null values
When the entity row is saved to the database
When an entity attribute value is set
The create()
method provides the entity object event you can handle to initialize default values the first time an entity row is created. Example 8-4 shows the overridden create method of the OrderEO
entity object in the StoreFront module of the Fusion Order Demo. It calls an attribute setter methods to populate the OrderDate
attribute in a new order entity row.
You can also define default values using a Groovy expression. For more information, see Section 4.10.6, "How to Define a Static Default Value."
Example 8-4 Programmatically Defaulting Attribute Values for New Rows
// In OrderEOImpl.java in Fusion Order Demo protected void create(AttributeList nameValuePair) { super.create(nameValuePair); this.setOrderDate(new Date()); }
Note: Calling thesetAttribute() method inside the overridden create() method does not mark the new row as being changed by the user. These programmatically assigned defaults behave like declaratively assigned defaults. |
You should override the initDefaultExpressionAttributes()
method for programmatic defaulting logic that you want to fire both when the row is first created, and when it might be refreshed back to initialized status.
If an entity row has New
status and you call the refresh()
method on it, then the entity row is returned to an Initialized
status if you do not supply either the REFRESH_REMOVE_NEW_ROWS
or REFRESH_FORGET_NEW_ROWS
flag. As part of this process, the entity object's initDefaultExpressionAttributes()
method is invoked, but not its create()
method again.
Section 4.10.9, "How to Synchronize with Trigger-Assigned Values," explains how to use the DBSequence
type for primary key attributes whose values need to be populated by a database sequence at commit time. Sometimes you may want to eagerly allocate a sequence number at entity row creation time so that the user can see its value and so that this value does not change when the data is saved. To accomplish this, use the SequenceImpl
helper class in the oracle.jbo.server
package in an overridden create()
method as shown in Example 8-5. It shows code from the custom Java class of the WarehouseEO
entity object in the StoreFront module of the Fusion Order Demo. After calling super.create()
, it creates a new instance of the SequenceImpl
object, passing the sequence name and the current transaction object. Then it calls the setWarehouseId()
attribute setter method with the return value from SequenceImpl
's getSequenceNumber()
method.
Note: For a metadata-driven alternative to this approach, see Section 4.12.5, "Assigning the Primary Key Value Using an Oracle Sequence." |
Example 8-5 Eagerly Defaulting an Attribute's Value from a Sequence at Create Time
// In WarehouseEOImpl.java import oracle.jbo.server.SequenceImpl; // Default WarehouseId value from WAREHOUSE_SEQ sequence at entity row create time protected void create(AttributeList attributeList) { super.create(attributeList); SequenceImpl sequence = new SequenceImpl("WAREHOUSE_SEQ",getDBTransaction()); setWarehouseId(sequence.getSequenceNumber()); }
If you want to assign programmatic defaults for entity object attribute values before a row is saved, override the prepareForDML()
method and call the appropriate attribute setter methods to populate the derived attribute values. To perform the assignment only during INSERT
, UPDATE
, or DELETE
, you can compare the value of the operation
parameter passed to this method against the integer constants DML_INSERT
, DML_UPDATE
, DML_DELETE
respectively.
Example 8-6 shows an overridden prepareForDML()
method that assigns derived values.
Example 8-6 Assigning Derived Values Before Saving Using PrepareForDML
protected void prepareForDML(int operation, TransactionEvent e) { super.prepareForDML(operation, e); //Populate GL Date if (operation == DML_INSERT) { if (this.getGlDate() == null) { String glDateDefaultOption = (String)this.getInvoiceOption().getAttribute("DefaultGlDateBasis"); if ("I".equals(glDateDefaultOption)) { setAttribute(GLDATE, this.getInvoiceDate()); } else { setAttribute(GLDATE, this.getCurrentDBDate()); } } } //Populate Exchange Rate and Base Amount if null if ((operation == DML_INSERT) || (operation == DML_UPDATE)) { BigDecimal defaultExchangeRate = new BigDecimal(1.5); if ("Y".equals(this.getInvoiceOption().getAttribute("UseForeignCurTrx"))) { if (!(this.getInvoiceCurrencyCode().equals( this.getLedger().getAttribute("CurrencyCode")))) { if (this.getExchangeDate() == null) { setAttribute(EXCHANGEDATE, this.getInvoiceDate()); } if (this.getExchangeRateType() == null) { String defaultConvRateType = (String)this.getInvoiceOption().getAttribute("DefaultConvRateType"); if (defaultConvRateType != null) { setAttribute(EXCHANGERATETYPE, defaultConvRateType); } else { setAttribute(EXCHANGERATETYPE, "User"); } } if (this.getExchangeRate() == null) { setAttribute(EXCHANGERATE, defaultExchangeRate); } if ((this.getExchangeRate() != null) && (this.getInvoiceAmount() != null)) { setAttribute(INVAMOUNTFUNCCURR, (this.getExchangeRate().multiply(this.getInvoiceAmount()))); } } else { setAttribute(EXCHANGEDATE, null); setAttribute(EXCHANGERATETYPE, null); setAttribute(EXCHANGERATE, null); setAttribute(INVAMOUNTFUNCCURR, null); } } } }
To assign derived attribute values whenever another attribute's value is set, add code to the latter attribute's setter method. Example 8-7 shows the setter method for an AssignedTo
attribute in an entity object.
Example 8-7 Setting the Assigned Date Whenever the AssignedTo Attribute Changes
public void setAssignedTo(Number value) { setAttributeInternal(ASSIGNEDTO, value); setAssignedDate(getCurrentDateWithTime()); }
After the call to setAttributeInternal()
to set the value of the AssignedTo
attribute, it uses the setter method for the AssignedDate
attribute to set its value to the current date and time.
Note: It is safe to add custom code to the generated attribute getter and setter methods as shown here. When JDeveloper modifies code in your class, it intelligently leaves your custom code in place. |
You can use the refresh(int flag)
method on a row to refresh any pending changes it might have. The behavior of the refresh()
method depends on the flag that you pass as a parameter. The three key flag values that control its behavior are the following constants in the Row
interface:
REFRESH_WITH_DB_FORGET_CHANGES
forgets modifications made to the row in the current transaction, and the row's data is refreshed from the database. The latest data from the database replaces data in the row regardless of whether the row was modified or not.
REFRESH_WITH_DB_ONLY_IF_UNCHANGED
works just like REFRESH_WITH_DB_FORGET_CHANGES
, but for unmodified rows. If a row was already modified by this transaction, the row is not refreshed.
REFRESH_UNDO_CHANGES
works the same as REFRESH_WITH_DB_FORGET_CHANGES
for unmodified rows. For a modified row, this mode refreshes the row with attribute values at the beginning of this transaction. The row remains in a modified state if it had been previously posted but not committed in the current transaction prior to performing the refresh operation.
By default, any entity rows with New
status that you refresh()
are reverted back to blank rows in the Initialized
state. Declarative defaults are reset, as well as programmatic defaults coded in the initDefaultExpressionAttributes()
method, but the entity object's create()
method is not invoked during this blanking-out process.
You can change this default behavior by combining one of the flags in Section 8.4 with one of the following two flags (using the bitwise-OR
operator):
REFRESH_REMOVE_NEW_ROWS
, new rows are removed during refresh.
REFRESH_FORGET_NEW_ROWS
, new rows are marked Dead
.
You can cause a refresh()
operation to cascade to composed child entity rows by combining the REFRESH_CONTAINEES
flag (using the bitwise-OR
operator) with any of the valid flag combinations described in Section 8.4 and Section 8.4.1. This causes the entity to invoke refresh()
using the same mode on any composed child entities it contains.
When your business logic requires performing SQL queries, the natural choice is to use a view object to perform that task. Keep in mind that the SQL statements you execute for validation will "see" pending changes in the entity cache only if they are entity-based view objects. Read-only view objects will only retrieve data that has been posted to the database.
Since entity objects are designed to be reused in any application scenario, they should not depend directly on a view object instance in any specific application module's data model. Doing so would prevent them from being reused in other application modules, which is highly undesirable.
Instead, you should use a view accessor to validate against a view object. For more information, see Section 10.4.1, "How to Create a View Accessor for an Entity Object or View Object."
Using a view accessor, your validation code can access the view object and set bind variables, as shown in Example 8-8.
Example 8-8 Using a Validation View Object in a Method Validator
// Sample entity-level validation method public boolean validateSomethingUsingViewAccessor() { RowSet rs = getMyValidationVO(); rs.setNamedBindParameter("Name1", value1); rs.setNamedBindParameter("Name2", value2); rs.executeQuery(); if ( /* some condition */) { /* * code here returns true if the validation succeeds */ } return false; }
As the sample code suggests, view objects used for validation typically have one or more named bind variables in them. In this example, the bind variables are set using the setNamedBindParameter()
method. However, you can also set these variables declaratively in JDeveloper using Groovy expressions in the view accessor definition page.
Depending on the kind of data your view object retrieves, the "/* some condition */
" expression in the example will look different. For example, if your view object's SQL query is selecting a COUNT()
or some other aggregate, the condition will typically use the rs.first()
method to access the first row, then use the getAttribute()
method to access the attribute value to see what the database returned for the count.
If the validation succeeds or fails based on whether the query has returned zero or one row, the condition might simply test whether rs.first()
returns null
or not. If rs.first()
returns null
, there is no "first" row. In other words, the query retrieved no rows. In other cases, you may be iterating over one or more query results retrieved by the view object to determine whether the validation succeeds or fails.
The beforeCommit()
method is invoked on each entity row in the pending changes list after the changes have been posted to the database, but before they are committed. This can be a useful method in which to execute view object based validations that must assert some rule over all entity rows of a given type.
Note: You can also do this declaratively using a transaction-level validator (see Section 7.6.4, "How to Set Transaction-Level Validation"). |
If your beforeCommit()
logic can throw a ValidationException
, you must set the jbo.txn.handleafterpostexc
property to true
in your configuration to have the framework automatically handle rolling back the in-memory state of the other entity objects that may have already successfully posted to the database (but not yet been committed) during the current commit cycle.
If your entity object or view object business logic iterates over its own view accessor row set, and that view accessor is not also used by a model-defined List of Values, then there is no need to use a secondary row set iterator. For example, if an entity object has a view accessor named AirportValidationVA
for a view object that takes one named bind parameter, it can iterate its own view accessor row set using either Groovy script or Java. Example 8-9 show a Groovy script that iterates over a view accessor row set.
Example 8-9 Using a View Accessor in Groovy Script
AirportValidationVA.setNamedWhereClauseParam("VarTla",newValue) AirportValidationVA.executeQuery(); return AirportValidationVA.first() != null;
Example 8-10 shows a Java method validator that iterates over a view accessor row set.
To access information from related entity objects, you use an association accessor method in your entity object's custom Java class. By calling the accessor method, you can easily access any related entity row — or set of entity rows — depending on the cardinality of the association.
You can use an association accessor to access related entity rows. Example 8-11 shows code from the ControllingPostingOrder
project in the AdvancedEntityExamples
module of the Fusion Order Demo that shows the overridden postChanges()
method in the ProductsBase
entity object's custom Java class. It uses the getSupplier()
association accessor to retrieve the related supplier for the product.
Example 8-11 Accessing a Parent Entity Row In a Create Method
// In ProducstBaseImpl.java in the ControllingPostingOrder project
// of the Fusion Order Demo Advanced Entity Examples
@Override
public void postChanges(TransactionEvent transactionEvent) {
/* If current entity is new or modified */
if (getPostState() == STATUS_NEW || getPostState() == STATUS_MODIFIED) {
/* Get the associated supplier for the product */
SuppliersImpl supplier = getSupplier()
;
/* If there is an associated product */
if (supplier != null) {
/* And if it's post-status is NEW */
if (supplier.getPostState() == STATUS_NEW) {
/* Post the supplier first, before posting this entity */
supplier.postChanges(transactionEvent);
}
}
}
super.postChanges(transactionEvent);
}
If the cardinality of the association is such that multiple rows are returned, you can use the association accessor to return sets of entity rows.
Example 8-12 illustrates the code for the overridden postChanges()
method in the Suppliers
entity object's custom Java class. It shows the use of the getProductsBase()
association accessor to retrieve the RowSet
object of ProductsBase
rows in order to update the SupplierId
attribute in each row using the setSupplierId()
association accessor.
Example 8-12 Accessing a Related Entity Row Set Using an Association Accessor
// In SuppliersImpl.java in the ControllingPostingOrder project // of the Fusion Order Demo Advanced Entity Examples RowSet newProductsBeforePost = null; @Override public void postChanges(TransactionEvent transactionEvent) { /* Only update references if Supplier is new */ if (getPostState() == STATUS_NEW) { /* * Get a rowset of products related to this new supplier before calling super */ newProductsBeforePost = (RowSet)getProductsBase()
; } super.postChanges(transactionEvent); } ... protected void refreshFKInNewContainees() { if (newProductsBeforePost != null) { Number newSupplierId = getSupplierId().getSequenceNumber(); /* * Process the rowset of suppliers that referenced the new product prior * to posting, and update their ProdId attribute to reflect the refreshed * ProdId value that was assigned by a database sequence during posting. */ while (newProductsBeforePost.hasNext()){ ProductsBaseImpl product = (ProductsBaseImpl)newProductsBeforePost.next(); product.setSupplierId(newSupplierId)
; } closeNewProductRowSet(); } }
If you have run the Configure ADF Security wizard on your application to enable the ADF authentication servlet to support user login and logout, the oracle.jbo.server.SessionImpl
object provides methods you can use to get information about the name of the authenticated user and about the roles of which they are a member. This is the implementation class for the oracle.jbo.Session
interface that clients can access.
For information about how to access information about the authenticated user, see Section 30.11.3.3, "How to Determine the Current User Name" and Section 30.11.3.4, "How to Determine Membership of a Java EE Security Role".
For more information about security features in Oracle Fusion Web Applications, read Chapter 30, "Enabling ADF Security in a Fusion Web Application."
If an entity attribute's value has been changed in the current transaction, when you call the attribute getter method for it you will get the pending changed value. Sometimes you want to get the original value before it was changed. Using the getPostedAttribute()
method, your entity object business logic can consult the original value for any attribute as it was read from the database before the entity row was modified. This method takes the attribute index as an argument, so pass the appropriate generated attribute index enums that JDeveloper maintains for you.
If you need to store information related to the current user session in a way that entity object business logic can reference, you can use the user data hash table provided by the Session
object.
When a new user accesses an application module for the first time, the prepareSession()
method is called. As shown in Example 8-13, the application module overrides prepareSession()
to retrieve information about the authenticated user by calling a retrieveUserInfoForAuthenticatedUser()
method on the view object instance. Then, it calls the setUserIdIntoUserDataHashtable()
helper method to save the user's numerical ID into the user data hash table.
Example 8-13 Overriding prepareSession() to Query User Information
// In the application module protected void prepareSession(Session session) { super.prepareSession(session); /* * Query the correct row in the VO based on the currently logged-in * user, using a custom method on the view object component */ getLoggedInUser().retrieveUserInfoForAuthenticatedUser(); setUserIdIntoUserDataHashtable(); }
Example 8-14 shows the code for the view object's retrieveUserInfoForAuthenticatedUser()
method. It sets its own EmailAddress
bind variable to the name of the authenticated user from the session and then calls executeQuery()
to retrieve the additional user information from the USERS
table.
Example 8-14 Accessing Authenticated User Name to Retrieve Additional User Details
// In the view object's custom Java class public void retrieveUserInfoForAuthenticatedUser() { SessionImpl session = (SessionImpl)getDBTransaction().getSession(); setEmailAddress(session.getUserPrincipalName()); executeQuery(); first(); }
One of the pieces of information about the authenticated user that the view object retrieves is the user's numerical ID number, which that method returns as its result. For example, the user sking
has the numeric UserId
of 300
.
Example 8-15 shows the setUserIdIntoUserDataHashtable()
helper method — used by the prepareSession()
code in Example 8-13 — that stores this numerical user ID in the user data hash table, using the key provided by the string constant CURRENT_USER_ID
.
Example 8-15 Setting Information into the UserData Hashtable for Access By Entity Objects
// In the application module private void setUserIdIntoUserDataHashtable() { Integer userid = getUserIdForLoggedInUser(); Hashtable userdata = getDBTransaction().getSession().getUserData(); userdata.put(CURRENT_USER_ID, userid); }
The corresponding entity objects in this example can have an overridden create()
method that references this numerical user ID using a helper method like the one in Example 8-16 to set the CreatedBy
attribute programmatically to the value of the currently authenticated user's numerical user ID.
The top-level adf
object allows you access to objects that the framework makes available to Groovy script. The adf.userSession
object returns a reference to the ADF Business Components user session, which you can use to reference values in the userData
hashmap that is part of the session.
Example 8-17 shows the Groovy script you would use to reference a userData
hashmap key named MyKey
.
You might find it useful to reference the current date and time in your entity object business logic. You can reference the current date or current date and time using the following Groovy script expressions:
adf.currentDate
— returns the current date (time truncated)
adf.currentDateTime
— returns the current date and time
For more information about using Groovy script in your entity object business logic, see Section 3.6, "Overview of Groovy Support."
The afterCommit()
method is invoked on each entity row that was in the pending changes list and got successfully saved to the database. You can use this method to send a notification on a commit.
A better way to send notifications upon a successful commit is by declaring a business event. For more information on how to create a business event, see Section 4.11, "Creating Business Events."
Before an entity row is removed, the remove()
method is invoked on an entity row. You can throw a JboException
in the remove()
method to prevent a row from being removed if the appropriate conditions are not met.
For example, you can add a test in the remove()
method that determines the state of the entity object and allows the removal only if it is a new record. Example 8-18 demonstrates this technique.
Note: This example is in theAddressesImpl.java file in the ConditionalDelete project of the DevGuideExamples workspace in the StandaloneExamples module of the Fusion Order Demo application. |
Example 8-18 Overriding the remove() Method to Verify Entity Status Before Removal
// In the Addresses entity object custom Java class private boolean isDeleteAllowed() { byte s = this.getEntityState(); return s==STATUS_NEW; } /** * Add entity remove logic in this method. */ public void remove() { if (isDeleteAllowed()) super.remove(); else throw new JboException("Delete not allowed in this view"); }
Note: The entity object offers declarative prevention of deleting a master entity row that has existing, composed children rows. You configure this option on the Relationship page of the overview editor for the association. |
You can override the isAttributeUpdateable()
method in your entity object class to programmatically determine whether a given attribute is updatable or not at runtime based on appropriate conditions.
Example 8-19 shows how an entity object can override the isAttributeUpdateable()
method to enforce that its PersonTypeCode
attribute is updatable only if the current authenticated user is a staff member. Notice that when the entity object fires this method, it passes in the integer attribute index whose updatability is being considered.
You can implement conditional updatability logic for a particular attribute inside an if
or switch
statement based on the attribute index. Here PERSONTYPECODE
is referencing the integer attribute index enums that JDeveloper maintains in your entity object custom Java class.
Example 8-19 Conditionally Determining an Attribute's Updatability at Runtime
// In the entity object custom Java class public boolean isAttributeUpdateable(int index) { if (index == PERSONTYPECODE) { if (!currentUserIsStaffMember()) { return super.isAttributeUpdateable(index); } return CUSTOMER_TYPE.equals(getPersonTypeCode()) ? false : true; } return super.isAttributeUpdateable(index); }
Note: Entity-based view objects inherit this conditional updatability as they do everything else encapsulated in your entity objects. Should you need to implement this type of conditional updatability logic in a way that is specific to a transient view object attribute, or to enforce some condition that involves data from multiple entity objects participating in the view object, you can override this same method in a view object's view row class to achieve the desired result. |