How to use web services, TopLink, POJO's and other data providers as a business component (ADF BC)
By marcel.marsman on Apr 09, 2007
Or a cunning plan to disguise Java code as view objects and entity objects.
IntroductionFirst of all why do we need to be able to do this anyway? The answer is that we might have some functionality that needs to use data as �business component� (BC or strictly speaking ADF BC). In our case, this is not a surprise, JHeadstart comes to mind. The application definition editor has many conveniences that are �BC aware�. Other usages of being able to represent data as an BC is when we do want to use a table as the source of data. Maybe we need a quick proof-of-concept and we want to use a POJO as a quick way to specify data without going into the trouble of creating a table. Or start building your (JHeadstart generated) ADF application and postpone creating and filling in data in your table and put that in later. Many scenarios come to mind, you might be able to come up with usages yourself.
If you are familiar with JHeadstart and BC you might want to go to the example case.
Table of contents
A crash course in BC
The 'Lookup' Recipe
The 'persistent' VO/EO Recipe
A crash course in BCThere are many better and more elaborate guides on BC. I can recommend for instance Oracle ADF Developer's Guide for Forms/4GL Developers. In this section I will list the basics.The experts might notice some of the confusing details are left out. The following contains �just enough� to support the rest of the story.
First of all the concept of �entity objects� (EO). An EO basically represents a database table. In its minimal shape it is an XML file describing the table, for instance the table columns, the column types and constraints. You can create a Java representation of a row of the table in Java class EORowImpl. The Java class has accessors for the columns of the database and allows implementation of business rules. A good example is the Java method called doDML that is called when a row is inserted, deleted or updated in the database table.
The second concept is �view objects� (VO) which are similar to queries. The major difference is that dataset can be maintained using insert, delete or update. Such a VO can be defined in two ways. First by providing a POSS (plain old SQL statement) in which case the VO can only be used to query data (read-only). Second way is by refering to one or more entity objects. In this case the POSS is generated from the definition of the EO(s) and can be updatable. In both cases you can provide bind-variables, specify order-by, where-clauses and more. Similar to entity objects a VO is defined with an XML file and your are able to create a Java representation for the whole data-set and for the rows in the dataset.
The attributes in the VO are derived from the attributes in the query. Additionaly you are able to code attributes by impementing Java accessors, so called transient attributes, or by using fragments of SQL that are appended to the select, so called calculated attributes.
Another important concept in BC is the �application module�, basically a collection of VO's. At runtime it takes care of the instances of these VO and transactions (commit/rollback). Also BC offers relations: �associations� between EO and �viewlinks� between VO similar to �foreign� keys.
The picture shows the BC elements with VO and viewlinks, EO and associations.
Basic ideaSo the data retrieved in the VO is either read-only and based on a POSS provided by the developer, most often used as a �lookup�. Alternatively when the data needs to be updatable; the VO is based from the entity objects.
The data is retrieved from tables although you can use �transient� attributes to code attributes in the VO class. This leads to the following idea for �programmatic view objects� and �programmatic entity objects�:
1. For �lookup� VO just use transient attributes and do not use a POSS. If you do this there are no dependencies on database tables. As long as you implement a number of mandatory methods in the VO Java class and provide data in a certain format you are set. In the exampke below I provide an abstract baseclass for you to extend. This baseclass implements most of these methods and requires only the implementation of the retrieval of data. This is called a programmatic view object.
2. In the second case: Retrieval of data is left to the VO as a �programmatic view object� however the attributes are �set and get� on the EO. The persistence of the data in the VO is handled by the related EO(s). So we make sure that the instances of EORowImpl Java classes do not commit to the database but instead call custom Java code to �fake� persistence. This is done by overriding the �doDML� method in EORowImpl. This is called a �programmatic entity object� and a baseclass is in the example below.
So now we are left to the problem of retrieving your custom data and provide persistence in the latter cases. Your custom data is retrieved using Java code and hence can be based on web service calls, POJO or using the my.fortuneteller.CrystalBall class.
The remainder of this article will provide details on utility classes you can use to create your �programmatic VO/EO�. No worry, since there is not much effort to make one and a working example is included.
Programmatic classesIn order to make life easier I created a number of Java classes to help you code your own programmatic VO's and EO's. The biggest challenge is to write code to retrieve your data and provide it to the programmatic VO. Since I do not like writing similar code for using these various sources of data, I think we need a generic representation of data. Enter: the JhsProgrammaticResultSet class.
JhsProgrammaticResultSet: A Java interface class that is a generic representation of tabular data (List of Maps). An implementation of the interfaces is given in JhsProgrammaticResultSetImpl. Each entry of the List (which maintains order) is a Map and represents a row. So list entry three represents the fourth row in a table. The key value pairs of the map represent the columns and the values of the rows. This datatype is used as a parameter and return value for the hooks that were implemented in the following baseclasses.
JhsProgrammaticViewObject extends jbo.server.ViewObject: this Java class is an abstract base class which is extended in order to implement a programmatic VO. The class is abstract and implements the required minimal set of method for a VO. You only need to supply the data by implementing a method.>
JhsProgrammaticEntityImpl extends jbo.server.EntityImpl:this class is an abstract base class to implement programmatic EO's. It is an abstract class that has implemented the required minimal set of methods for an EO. You need to implement methods for inserting, deleting and updating data.
JhsProgrammaticHelper: utility class that helps tou to convert instances of Entity or ViewObject into JhsProgrammaticResultSet and vice versa. It also helps you to convert a Java bean from and to a JhsProgrammaticResultset. The latter is interesting since a web service is represented by Java beans (access attributes via getter and setter methods). I use 'Java Web Service from WSDL' tool in JDeveloper.
These classes can be obtained here.
The �lookup� VO recipeHow to implement a programmatic view object for lookup
To implement a �programmatic VO� follow the following recipe:
1. Create a VO with only �transient� String attributes;
2. Optionally introduce named bind-parameters that can be used in your implementation for data-retrieval;
3. Create VOImpl class without accessors and extend JhsProgrammaticViewObject;
4. This requires you to implement method �getJhsProgrammaticResultSet�. Make sure that the keys match your attribute names;
5. Include in application module usage.
The �persistent� VO/EO recipeHow to implement a programmatic view object based on a programmatic entity object
To implement this recipe:
1. Create an EO with all attributes persistent and of type VARCHAR2;
2. Create EORowImpl class and extend JhsProgrammaticEntityObject;
3. This requires you to implement getCurrentRow, insertRow, deleteRow and updateRow.
4. Create VO with attributes from the EO. Use the editor to make sure the attribute names match the attribute names in the EO;
5. Optionally introduce named bind-parameters that can be used in your implementation for data-retrieval;
6. Create VOImpl class and extend JhsProgrammaticViewObject. This acquires you to implement method �getJhsProgrammaticResultSet�. Make sure that the keys match your attribute names;
7. Include VO in application module usage.
An example application (Entity and View Object Based on Web Service) by Steve Muench inspired me to come up with this general recipe. Thanks Steve!
This example illustrates the implementation. In the example case I have defined a small data model representing email messages and folders. From the data model I generated a user interface (ADF JSPX pages) using JHeadstart. So this datamodel is implemented by 'real' BC.
However �they� have decided to make my life harder by requiring that I use a web service built by 'Person POJO Inc.'. This hightech web service offers storage and maintenance of person data (first name, last name and email address).
First 'their' requirement was easy: use a list of values dialog to access the web service and find a person by last name. Select the person and store the email address in the 'From' or 'To' address. I applied the 'lookup' VO recipe that resulted in TransientPersonWebServiceVO. This VO is not based on an entity object and is readonly. It does not even need a database connection, although JDeveloper might try to open a connection anyway.
After this 'they' got enthusiastic and 'they' wanted maintenance of the Persons. 'Please make a screen to allow inserting, deleting and updating on the persons available via the web service!' Luckily these operations are supported by the web service, so I was able to comply.
So I applied the �persistent� VO/EO recipe that gave me PersonWebServiceEO and PersonWebServiceVO. I added the VO as a group to my JHeadstart application definition file and was able to maintain the persons.
The code of the little application is included a zip-file here: Project Download. Just unzip to your favorite place and open JhsWorkshop.jws workspace. This allows you to browse the code. JHeadstart was used to generate the example so JHeadstart runtime is included. The application definition file is included as well, so owners of a JHeadstart distribution can even start changing the example.The example can be run as follows:
Prepare by installing Oracle JDeveloper 10.1.3.2 and install Oracle XE database.
- Create database schema 'jhsmail' to persist the 'real' BC components or use your own schema. Setup datamodel and some example data by executing createSchemaAndData.sql (see database project in workspace);
- Create connection called XE_JHSMAIL used by BC (or change BC setup yourself to match your installation)
- To save space I left out large libraries. So go to the Project Properties of ViewController, then to JSP Tag Libraries. Add the tag libraries JSF Core, JSF HTML, ADF Faces Components and ADF Faces HTML.
- Rebuild the complete workspace;
- Run web service PersonsWebService;
- Since the user-interface is in the same workspace, the user interface is available when running the web-service. The URL depends on your embedded OC4J configuration, in my case I use: http:\\\\\\localhost:8988/JhsWorkshop-ViewController-context-root/faces/pages/MaintainPersons.jspx
ConclusionThe provided example shows how a web service could have been based something else than a POJO. Also the data-provider could have been something else then a web service for instance a remote call to another system, TopLink or a Java implementation reading data from file. The concept of programmatic view objects and entity objects can be used in many ways.
Hopefully this little article was useful to you. I have made use of this concept several times .
Of course this example might not be a perfect match to your particular challenge, but this is the wonderful world of Java, so �Use the source Luke, use the source!�
Suggestions and improvements are welcome!