ADF Samples - ADF Business Components
|| Signal RowInconsistentException Correctly Across Activation/Passivation [22.214.171.124] 02-NOV-2011
| This example illustrates an approach to ensure that the RowInconsisentException is correctly signalled even if the AM used by the second user has undergone passivation and activation since the first user changed the row. First, it's important to understand the potential problem. Assume that two users U1 and U2 query up the DEPT row with DEPTNO=10. User U1 modifies the Dname in that row and commits. At this point user U2 is looking at a "stale" value in the page in her browser. User U2 proceeds to make her edit and clicks (Commit). In an ADF page implemented in the typical way, the user will correctly get a warning that "Another user has changed the row" as long as U2's application module has not undergone passivation and activation. If instead application load forces ADF to activate the AM's passivated state to service user U2's (Commit)-button click request, then the change made by user U2 is silently committed, potentially overwriting the changes that user U1. This occurs because the act of activating the AM state reads in current DB values of the queried rows, which now reflect the changes made by user U1 instead of the values that are in user U2's current browser page. The solution involves using a change indicator attribute and including that change indicator attribute in the web page as a hidden field. In the example, the Dept entity object is based on the DEPT_WITH_OBJ_VERSION table. This is the standard DEPT table to which has been added a single, additional NUMBER column named OBJECT_VERSION. The ObjectVersion attribute in the Dept entity is marked as a 'Change Indicator' attribute, and it's also marked as a 'History Column' of type 'version number'. The history column setting tells ADF to automatically set the value of this column to 1 in a newly created row, and to increment the version number each time the row is modified and saved. The change indicator setting tells ADF to compare only the value of this attribute in order to determine whether the row has been changed by another user or not. In the absence of a change indicator attribute, ADF must compare the values of all persistent attributes which can take longer. The view1.jspx page uses the h:inputHidden component to include the ObjectVersion attribute value in the page. By doing this, the object version of the row being edited by user U2 will be submitted to the server along with the other attribute values, and it will be used to compare against the ObjectVersion attribute value of the row being edited. Since these values differ, the RowInconsistentException is thrown as desired. Try re-enabling the AM Pooling to convince yourself that the technique will work under normal circumstances as well. To run the example, start by running the CreateTables.sql script to create the DEPT_WITH_OBJ_VERSION table. Then run the view1.jspx page. Once the page appears in your default browser, copy the URL http://localhost:7101/SignalRowInconsistent/faces/view1 and paste it into a different browser. For example, if Google Chrome is your default browser, paste it into Firefox or Internet Explorer. This will allow you to test having two distinct browser users using your application. Both browsers should be looking at the row for DEPTNO=10. In the first browser window, update the value of Dname and click (Commit). Now the second browser is looking at a "stale" value for the Dname. In this second browser, update the value of Loc and click (Commit). The user gets the expected error "Another user has changed the row with primary key oracle.jbo.Key". The AppModule application module in the example has its 'Enable Application Module Pooling' configuration setting (jbo.ampool.doampooling) set to false for testing purposes. Your application module will never have this pooling setting disabled in production, but it is useful for testing the activation-safety of your application module by stress-testing the passivation/activation on each HTTP request.
See also Steve Muench' undocumented 10.1.3.x samples nr. 115
|| Two Approaches to Referencing Controller-layer Session State in VO Bind Variables [126.96.36.199] 16-DEC-2009]
| This example illustrates two different approaches to referencing controller layer state inside the default value expression of a view object's bind variable. One typical example is to reference the name of the logged-in user (which in the past web applications would store in a Web session attribute), however since you can use the adf.context.securityContext.userName groovy expression to reference the username of the logged-in user when using ADF Security, I choose a slightly-different example of storing a code representing the user's favorite color. The ViewController project contains a UserInfo bean with a single favoriteColor property. This bean is registered in the adfc-config.xml file as a session-scoped managed bean, and using the JSF managed property feature, the default value of emgreen is injected into the bean at creation time. The Model project contains two view objects that each contain a bind variable named VarFavoriteColor whose default value we'd like to come from the current value of the aforementioned UserInfo managed bean's favoriteColor property. There are two basic approaches: one will appeal more to those who cherish the cleanest logical separation of view/controller and model layers. The other appeals more to developers who like to use the "simplest thing that works" (as long as it's not bad practice). The ExampleVO2 VO instance in the AM data model is of type ExampleVOUsingADFContextSessionInfoInBindVariable. This view object's VarFavoriteColor bind variable references the groovy expression adf.context.sessionScope.UserInfo.favoriteColor and represents the "simplest thing that works" approach. This takes advantage of the fact that ADFContext object abstracts access to the four interesting scopes that might be relevant during runtime of an ADF application: applicationScope, sessionScope, viewScope, and requestScope. When running in the web container, these scopes map onto the obvious matching scopes that you are familiar with from the view/controller layer. When running outside the web container, the ADFContext provides a default implementation of these scopes as a set of static maps that are useful for regression testing purposes. The Test class in the Testing project illustrates making use of the ADFContext.getSessionScope() to setup the session-level information the view object is expecting to find at runtime. The ExampleVO in the AM's data model is of type ExampleVOUsingControllerSuppliedUserDataHashtableInfoInBindVariable. This view object's bind variable of the same name references the groovy expression adf.userSession.userData.FavoriteColor. In this implementation that defines the more clear separation of view/controller layer and business tier - which is the one I personally prefer and recommend - the ADFBC session's userData map is used to store information that the view object's bind variable will reference. In a customized data control implementation class (CustomDCJboDataControl), the beginRequest method is overridden to invoke a setSessionFavoriteColor() method on the ExampleModule client interface to pass in the value of the UserInfo.favoriteColor into the business tier. The application module stores this information in the user data map, and makes that information activation/passivation-safe by overriding the passivateState() and activateState() methods. The custom data control is configured by setting the fully-qualified name of the CustomDCJboDataControlFactory class in the ExampleModuleDataControl entry's FactoryClass property in the DataBindings.cpx file (in the dataControlUsages section). On each request, the view/controller layer passes this information into the business layer, and the ExampleVOUsingControllerSuppliedUserDataHashtableInfoInBindVariable view object references its value from the userData map. Notice the setDefaultValuesForSessionLevelFavoriteColor() method in the ExampleModuleImpl class. This is invoked in an overridden prepareSession() method to assign a reasonable default value to both of the favoriteColor elements if their value is currently null. This would ensure that both approaches would work if the respective view object were called from a service or a test client that didn't provide any specific value at runtime. In the Testing project, the Test class illustrates how you can write a standalone regression test (just a simple Java class in this example, not a JUnit test) which mimics the view/controller layer calling of the setSessionFavoriteColor() API in the one case, and which populates a "mock" sessionScope UserInfo bean with a favoriteColor property to make the other view object find its expected information. As mentioned above I prefer the approach that uses the userData hash table set explicitly via an application module method, however at least now you have a good example of both techniques in action so you can decide for yourself which you prefer.
See also Steve Muench' undocumented 10.1.3.x samples nr. 118 and 126
Calling PL/SQL in Database
See also Steve Muench' undocumented 10.1.3.x samples nr. 100
|| Implementing Custom View Row Hint Behavior [188.8.131.52.0] 9-DEC-2008
| This example illustrates how to provide a custom view row attribute hints implementation. The EmpViewRow class overrides the createViewRowAttrHints method to return a new instance of the EmpViewRowAttributeHintsImpl class (which extends the framework base class ViewRowAttrHints. In the EmpViewRowAttributeHintsImpl class, notice that we've overridden the getHint() API to conditionally return a value for user-defined attribute hints named "mindate" and "maxdate". These hints are coded to look at the value of the Hiredate in the current row, and return a date String that represents three days before that date for "mindate" and three days after that date for "maxdate". The class also overrides the getLabel API to customize the value of the "label" UI hint for the Job attribute. Run the TestPage.jspx and try to edit a "Hiredate" value. You'll see that the date picker only allows you to change the date to a date that is within a span of three days before to three days after the current value. This occurs due to the UI component's referencing the custom "mindate" and "maxdate" hints appropriately. Also, you'll notice that the label for the "Job" field is the default label with the value of the Sal attribute appended to it.
Dynamic JDBC Credentials
|| 11g Dynamic JDBC Credentials for Model 1, Struts, Trinidad, and ADF Faces Rich Client [184.108.40.206.0] 06-AUG-2008
| This is an 11g production update of one of my most frequently downloaded examples (Dynamic JDBC Credentials, #14). There are four separate workspaces, one for each of the supported ways you might build a web application using ADF: DynamicCredentialsNoController.jws is a "Model 1" style application with no controller layer; DynamicCredentialsStruts.jws is Struts-based; DynamicCredentialsTrinidad.jws is a 10.1.3 ADF Faces application that's been migrated to use the Apache Trinidad components; and DynamicCredentialsRichFaces.jws uses the new ADF Faces Rich Client components that are new in 11g. Each project references the same Model project and FwkExtensions project. The generic framework extension classes involved in implementing the solution live in the FwkExtensions project. The Model project contains the simple ADFBC components used in the example: a TestModule application module with a single DeptView VO instance of a DeptView view object based on the DEPT table in the SCOTT schema. While updating the example for 11g, I took the liberty of using two new features that allowed me to simplify and streamline the implementation. The first of these was using the new ErrorHandlerClass attribute on the root <Application> element of the DataBindings.cpx file in each of the client web projects in order to register a custom ADFM error handler implementation (test.DynamicJDBCErrorHandlerImpl). This error handler is designed to notice the DMLException thrown by a failed database connection attempt (due to incorrect username/password combination), and it throws that particular exception rather than simply caching it on the binding container. The second new feature employed is the ability to register a global customization to the ADF Page lifecycle by using a META-INF/adf-settings.xml file in each client web project. Each project registers the test.DynamicJDBCPagePhaseListener in order to conditonally execute some custom logic before the ADF "prepare model" phase of the lifecycle. This custom logic references the data controls in the current page definition, causing them to be checked out of the AM pool (if they were not already checked out during the current lifecycle) before the JSF page rendering begins. This allows the error handling code to catch the failed connection attempt in time to redirect the user to the login page before the rendering phase begins. The web.xml file for each ViewController project contains a context parameter (RedirectToLogin) that defines the login page to redirect to for that particular web application. The JSF project contains a second context parameter FacesURLPattern as well. Due to Bug# 5080057, setting the jbo.ampool.sessioncookiefactoryclass property in the configuration is not correctly saved to the bc4j.xcfg file. So, in order to configure a custom session cookie factory class as required to repurpose the code in this example in your own projects, you'll need to hand-edit the bc4j.xcfg file to insert the child element <jbo.ampool.sessioncookiefactoryclass>test.DynamicJDBCSessionCookieFactory</jbo.ampool.sessioncookiefactoryclass> inside the appropriate <AppModuleConfig> element for the configuration in question.
|| Reference View Object and View Row Methods from Groovy [220.127.116.11, SCOTT schema] 03-SEP-2009
| The EmpView view object in this example features two transient, Groovy calculated attributes. The attribute named ValueUsingVOFunction references a custom myFunctionAtVOLevel() method on the EmpViewImpl class, while the attribute named ValueUsingVORowFunction references a custom myFunctionAtVORowLevel() method on the EmpViewRowImpl class, in both cases passing in the value of the Sal attribute. The methods simply return the value passed in surrounded by either parenthesis or square brackets.
|| Referencing UserData Map Values from View Object Bind Variables in Groovy [18.104.22.168, SCOTT schema] 27-JAN-2009
| This example includes a SessionHelper class to simplify referencing entries in the ADFBC session's userData map from the Groovy expressions providing the default values for bind variables. The user data map is referenced via EL expressions in the two JSPX pages, and it is referenced in Groovy bind variable expressions in two places: (1) at the AM data model level for the VO instance named AnotherInstanceOfQueryWithBindVarValue (which you can see by selecting the VO instance in the Data Model list and clicking the (Edit) button, and (2) on the view accessor named QueryWithBindVarValue1 of the EmpView view object. This latter view accessor is used by the LOV definition on the EmpView view object's Mgr attribute. To try the application, run the SetUserMapValue.jspx page, type NameFilter into the setUserMapValue_key field, and (for example) the letter S into the setUserMapValue_value field, and click (setUserMapValue). The table in the page updates to show an example of a data model view object instance using the bind variable value from the userData Map. Clicking on the (GoTo Page Referencing Session Value in LOV Bind Var) button takes you to a page where the search form shows that the view accessor's rowset (based on the same QueryWithBindVarValue view object) is using the bind variable value from the userData map as well. The Groovy expressions that access the userData map use the helper class via the expression test.model.SessionHelper.userData(adf.object).NameFilter. A future release of ADF will make it simpler to reference the ADFBC session object without the need for a helper class.
Programmatic Business Components
|| ADFBC Application With No Database Connection [22.214.171.124, SCOTT schema] 01-SEP-2009
| This example illustrates a technique for creating an application module that does not use a database connection. The only reason you might want to do this is that you are exclusively using programmatic view objects and entity objects, which might be an infrequent scenario, but does come up from time to time. The example illustrates a number of lesser-used framework extension classes. The NoDatabaseApplicationPoolImpl is a custom application module pool implementation class. The NonDatabaseConnectionStrategy is a custom connection strategy class . The CustomSessionImpl is a custom session class, which returns a custom transaction handler factory. The CustomTxnHandlerFactoryImpl is a custom transaction handler factory used to return an instance of the custom CustomTxnHandlerImpl class, which is a custom transaction handler implementation. The SessionClass configuration property is set to the name of the custom session implementation class, which in turn bootstraps the custom transaction handler factory and custom transaction handler. The PoolClassName configuration property is set to the name of the custom application module pool implementation class. This class overrides the isSupportsPassivation() method to return false, indicating to the runtime that this particular application module pool does not support passivation. The jbo.ampool.connectionstrategyclass configuration property is set to the name of the custom connection strategy class which overrides the createApplicationModule() method to set some key properties in the environment hashmap before calling super. The StaticVO is a static view object that returns rows whose data is in the ModelBundle.properties file.
|| Programmatic View Objects Showing Master/Detail Data [126.96.36.199.0] 09-OCT-2008
| This example illustrates some generic framework extension classes in action for programmatic view objects whose data is related master/detail. The generic infrastructure code lives in the StaticDataViewObjectSupport project. All of the view objects in the Model project specify the oracle.adfbc.staticdata.CSVFileViewObjectImpl class as their framework base class to inherit the generic functionality of reading their data from a CSV (comma-separated values) file. The ListOfMapsDataProviderViewObjectImpl framework extension class implements a programmatic view object whose data is populated from a java.util.List of java.util.Map objects. The CSVFileViewObjectImpl extends ListOfMapsDataProviderViewObjectImpl to supply a "data provider" that reads data from CSV files. By convention, it reads data from the *.csv file in the same directory in the classpath as the view object's component definition file. So, for example, the model.States view object reads its data from the model/States.csv file. The compiler options of the project have been modified to add the *.csv extension to the list of files that should be copied to the outpath during compilation time. Four different JSPX pages in the ViewController project allow you to try out master/detail display of the programmatically retrieved data.
|| Weird ADF 11g requirement addressed with left outer join and modern SQL join syntax [188.8.131.52] 13-DEC-11 |
|| Synchronize ViewObject Queryies by dynamically linking bind parameters [184.108.40.206] 28-NOV-11 |
|| Using SQL UNPIVOT to prepare data for dynamic ADF Faces User Interfaces [11.1.2] 03-JUL-11 |
|| Automatic Runtime Query/Join Pruning with Declarative View Objects [220.127.116.11, HR schema] 20-DEC-2008
| This example contains a single EmployeeAllInfo view whose SQL mode is set to use the new-in-11g setting of 'Declarative'. It contains one editable Employees entity usage, and six additional reference entity usages showing related information about the employee's department, the department's manager, the department's location, the department's region, the employee's job, and the department's country. When a view object is in declarative mode, its SQL statement is determined at runtime instead of at design time. Attributes in the view object can have their Selected in Query property set to false, and these attributes will only be selected if they are referenced by the page definition for the current page, otherwise they will be left out of the query. When multiple entity usages are involved, if all the attributes from a given entity usage are left out of the query, then the ADFBC runtime "prunes" that table related to that entity usage out of the query and does not perform that join. The application module in the Model project includes three different instances of the same EmployeeAllInfo view object. You can observe the different runtime queries performed by the three different JSPX pages by looking in the log while performing a search in each page. The file Queries.txt included in the ViewController project contains a formatted version of the different queries. You can see in the query for the MinimalEmployeeInfo.jspx page, that only the EMPLOYEES table is included. In the query for MediumEmployeeInfo.jspx you see EMPLOYEES, DEPARTMENTS, EMPLOYEES (a second time for the manager), and JOBS. The query for the final page joins all of the tables.
|| Joining Static Array of Database Type Data into View Object Query [18.104.22.168.0] 03-OCT-2008
| This example illustrates an approach to take an array of structured information and bind it into a view object query as one of the tables in order to produce a database join between the static information and the database data. The context in which this example arose was that a service call was returning a list of ranked/scored primary keys, that then needed to be joined with the database table to which the primary keys referred in order to produce a friendly display for end-users that includes more descriptive information about the ranked rows. You'll need to run the CreateTypes.sql script before using the demo to create the SCORED_KEY and SCORED_KEYS types in the database. The ViewObjectImplWithScoredKeyBindVariable framework extension class centralizes the code required to work with the bind variable of type oracle.jbo.domain.Array. In this case, its code is binding the SCORED_KEYS type (which is a TABLE OF SCORED_KEY) as an Array of SCORED_KEY types. Both the ReadOnlyScoredEmployees and EntityBasedScoredEmployees view objects inherit this helper code from this class. The setScoredKeysArray() method in the custom view object class of both view objects calls the helper method newScoredKeysArray() in the superclass to create the Array of STRUCT and set the value of the view object's bind variable. It expects to receive a List of Map objects, expecting each Map in the List to contain Map keys "Score" and "Key". The view objects both use the JDBC positional binding style, indicating the (zero-based) integer position of the bind variables as additional metadata in order to still work with the bind variable as a named bind variable in the view object API's. Run the TestClient class to see the results of joining in the static data with the EMP table.
See also Steve Muench' undocumented 10.1.3.x samples nr. 111