If you do not already have a base class defined for your application modules, this is done by editing the Model.jpr project properties. Under Business Components/Base Classes you define a base class for your View Objects and Application Modules. If you do this after your application modules have been defined and your app module has a java implementation, you will need to edit those java implementations and verify that they extend your new base app module. Newly created app modules will automatically extend your base app module.
Below is sample code showing the implementation. The were 2 or 3 app modules used for storing user preferences, saved searches and login history that we still wanted to be allowed so I excluded those. I also added a method allowOneTimeCommitForReadOnlyUser that can be called in the code immediately before calling commit() to allow for other exceptions to the rule.
/* overriden in order to prevent commiting data when user has read only user role
* beforeCommit is called for both the root app module and the app module
* containing the view object being commited.
*/
@Override
public void beforeCommit(TransactionEvent e) {
boolean isReadOnlyAccess = getDBTransaction().getSession().isUserInRole("readOnlyAccessAllowed");
String appModuleName = this.getRootApplicationModule().getName();
// allow commits for login history, performance monitorng and user preferences
boolean allowCommit=(!isReadOnlyAccess ||
"AppCtrlAM".equals(appModuleName) ||
"SearchAM".equals(appModuleName) ); // allow readOnlyAccess users to save searches criteria
// this is used to allow writing the account audit info for USER_ACTIVITY table
if (allowOneTimeCommitForReadOnlyUser){
allowCommit=true;
allowOneTimeCommitForReadOnlyUser=false;
}
if(!allowCommit){
displayReadOnlyMessage();
throw new ReadOnlyAttrException(0,"","",this.getName(),"");
}
super.beforeCommit(e);
}
public static void displayReadOnlyMessage(){
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR,"Read Only","You are allowed read only access. Data cannot be added or changed.");
context.addMessage(null, fm);
}
public void allowOneTimeCommitForReadOnlyUser() {
ApplicationModule am = this.getRootApplicationModule();
if (am instanceof CAAppModuleImpl){
((CAAppModuleImpl)am).allowOneTimeCommitForReadOnlyUser = true;
}
this.allowOneTimeCommitForReadOnlyUser = true;
}
Here's a link to another solution. That solution makes input fields display as read-only output fields.
We didn't do that because we didn't want to change the Application look in any way because we use Selenium non-invasive tests to regression test our pages in production so we want the page to look the same as it does for a normal user but still prevent the test or user from committing data.