Implementing Conditional Insert, Update, and Delete Allows for View Objects
User's of Oracle Forms are familiar with the declarative "data block" settings for:
- Insert Allowed? [Y|N]
- Update Allowed? [Y|N]
- Delete Allowed? [Y|N]
The BC4J framework does not (yet) have declarative view object settings for these, however we provide the framework methods that you can override to conditionally decide whether you want to allow insert, update, or delete on a view object. In a nutshell...
- To disallow insert, throw a JboException (or any subclass of it) from an overridden create() method in the ViewRowImpl class
- To disallow update, throw a JboException from an overridden setAttributeInternal() method in the ViewRowImpl class
- To disallow delete, throw a JboException from an overridden remove() method in the ViewRowImpl class
- To give clients (like JClient, JSP, UIX, etc.) feedback on the updateability of individual attributes in a conditional/custom way, override the isAttributeUpdateable() method and return true/false as appropriate.
Since BC4J is a framework, one of the most powerful things you can do is extend the framework to do that it doesn't already. BC4J gives you powerful building-blocks to do this. One of the key ones is the framework support for custom name/value-pair metadata properties that can be associated with Entity Objects, EO Attributes, View Objects, VO Attributes, or Application Modules.
The class below illustrates a custom subclass of oracle.jbo.server.ViewObjectImpl that checks whether the user has set custom metadata properties on their view objects named InsertAllowed, UpdateAllowed, and DeleteAllowed, and then exposes getter/setter methods to allow the programmer to get the status of these settings.
package otn.howto.fwkext;
import oracle.jbo.server.ViewObjectImpl;
import oracle.jbo.Row;
import oracle.jbo.*;
public class CustomViewObjectImpl extends ViewObjectImpl {
private static final String YES = "y";
boolean insertAllowed;
boolean updateAllowed;
boolean deleteAllowed;
public boolean isInsertAllowed() { return insertAllowed; }
public boolean isUpdateAllowed() { return updateAllowed; }
public boolean isDeleteAllowed() { return deleteAllowed; }
public void setInsertAllowed( boolean value ) { insertAllowed = value; }
public void setUpdateAllowed( boolean value ) { updateAllowed = value; }
public void setDeleteAllowed( boolean value ) { deleteAllowed = value; }
protected void create() {
super.create();
String insProp = (String)getProperty("InsertAllowed");
String updProp = (String)getProperty("UpdateAllowed");
String delProp = (String)getProperty("DeleteAllowed");
// If property not specified, default allowability to true.
setInsertAllowed(insProp == null || insProp.equalsIgnoreCase(YES));
setUpdateAllowed(updProp == null || updProp.equalsIgnoreCase(YES));
setDeleteAllowed(delProp == null || delProp.equalsIgnoreCase(YES));
}
}
The following custom subclass of the base oracle.jbo.server.ViewRowImpl class overrides the methods mentioned above, and generically enforces the insert-allowed, update-allowed, and delete-allowed behaviors for any view object that subclasses from this custom framework subclass, instead of extending from the default oracle.jbo.server.ViewRowImpl:
package otn.howto.fwkext;
import oracle.jbo.server.*;
import oracle.jbo.AttributeList;
import oracle.jbo.*;
/*
* Requires use of CustomViewObjectImpl
*/
public class CustomViewRowImpl extends ViewRowImpl {
protected boolean hasEntities() {
return getEntity(0) != null;
}
/*
* By convention, we'll say that the state of this VO row
* is the state of its first entity object.
*
* Only makes sense to call this if VO row has entities
*/
protected byte getViewRowStatus() {
return getEntity(0).getPostState();
}
public boolean isAttributeUpdateable(int index) {
if (hasEntities()) {
byte status = getViewRowStatus();
switch (status) {
case Entity.STATUS_NEW:
case Entity.STATUS_INITIALIZED: {
if (!getVO().isInsertAllowed()) return false;
else break;
}
case Entity.STATUS_UNMODIFIED:
case Entity.STATUS_MODIFIED: {
if (!getVO().isUpdateAllowed()) return false;
else break;
}
}
}
return super.isAttributeUpdateable(index);
}
protected void setAttributeInternal(int index, Object val) {
if (hasEntities()) {
byte status = getViewRowStatus();
switch (status) {
case Entity.STATUS_NEW:
case Entity.STATUS_INITIALIZED: {
if (!getVO().isInsertAllowed())
throw new JboException("no inserts");
else break;
}
case Entity.STATUS_UNMODIFIED:
case Entity.STATUS_MODIFIED: {
if (!getVO().isUpdateAllowed())
throw new JboException("no updates");
else break;
}
}
}
super.setAttributeInternal(index, val);
}
public void remove() {
if (!hasEntities() || getVO().isDeleteAllowed()) {
super.remove();
}
else {
byte status = getViewRowStatus();
if (status == Entity.STATUS_NEW || status == Entity.STATUS_INITIALIZED) {
super.remove();
}
else {
throw new JboException("Delete not allowed in this view");
}
}
}
protected void create(AttributeList nvp) {
if (getVO().isInsertAllowed()) {
super.create(nvp);
}
else {
throw new JboException("Insert not allowed in this view");
}
}
private CustomViewObjectImpl getVO() {
return (CustomViewObjectImpl)getViewObject();
}
}
With these two classes in place, these are the steps to take advantage of them:
- On the "Java" tab of your view object, click the (Extends) button and set the View Object Class to otn.howto.fwkext.CustomViewObjectImpl and the View Row Class to otn.howto.fwkext.CustomViewRowImpl
- On the "Properties" tab, add custom properties like InsertAllowed with a value of N, for example, to disallow inserts for this view object
To make these custom framework subclasses your global defaults, you can visit the Tools | Preferences... dialog and visit the "Business Components" / "Base Classes" category to set the IDE-wide defaults. In the JDeveloper 9.0.4 release, these defaults can also now be set at the project level by clicking "Edit..." from the right-mouse menu on your *.jpx file in the project.