This article is a developer-focused tutorial where operations carried by ADF BC (Application Development Framework Business Components) are exposed as web services, so they can be easily integrated into SOA applications. I will describe the end to end development process, starting with service-enabling ADF BC Application Modules, showing how to secure them and how to package the application using JDeveloper.
So let’s take a look at how service-enabling business logic encapsulated in ADF BC looks like. Roughly put, ADF BC comprise 3 main components: Entity Objects (EOs), View Objects (VOs) and Application Modules (AMs). EOs are the object representations of a business domain, VOs are the queries built on top of those objects, giving shape to data, and AMs are the way in which data and business logic is exposed to the outside world. I strongly recommend reading JDeveloper’s embedded documentation on ADF for the full picture. ADF BC is a very powerful framework and aims for quick and consistent development of java-based enterprise-wide applications. It is worth mentioning that is the natural path for the thousands of Oracle Forms customers to enter an SOA world.
AMs are the entry point for encapsulated business logic. They are the components for which web services interfaces are created. Service-enabled AMs are stateless enterprise session beans that are added a SOAP binding. One can expose any AM public custom method or any VO method as a service operation. And each of these operations can be added distinct security policies.
As an example, I am considering an SOA Loan Application. In order to make a decision whether or not the Loan should be granted to the requester, the application needs to query an AM for the requester payment history. This is precisely the AM that I will make available as a SOAP web service.
Here is the sequence:
This is a read-only VO, meaning it is not based on an EO, so you cannot update data through it. It queries a database for the customer payment history.
Couple of things to notice:
a) customerName bind variable, used in the specified view criteria.
b) CustomerPaymentHistoryVCByName view criteria, allowing any name to be added to the query at runtime.
a) Double-click the AM (CustomerHistoryAM) in the Application Navigator on the left side, click Service Interface (on the right side) and then click the green plus sign on the top right.
Attention to the Target Namespace field value. That’s vital information when it comes to securing the web service. More on this later.
Also see that there’s an option of generating asynchronous web services methods. I will cover it in a future article.
Click Next button.
b) On the left side, click Service View Instances, pick the VO instance, select it and send it to right side using the blue arrow.
c) Select View Criteria Find Operations tab and click on the green plus sign.
d) Pick the View Criteria that was previously created in step 1 and give the operation a more meaningful name. The binding variable defined for the view criteria is automatically exposed as an input parameter.
e) The View Criteria gets exposed as a method that takes the binding variable as an input parameter. Click Next.
f) In the summary screen, do notice the Service Interface name (highlighted). It will be used when securing the service.
g) Upon clicking the Finish button, here’s what we get:
Four classes are defined for the Application Module. For the purposes of security we’re interested in the Remote Server Class, which is the web service implementation.
Securing the web service here means attaching an OWSM authentication and an authorization policy to it. Both are attached at the service level, meaning all operations are now protected. However, different operations can be granted to different subjects.
In this example, the authentication policy is a username-based one, which means this web service expects a username token in the incoming SOAP message header. The authorization policy delegates the authorization decision to the OPSS layer, which expects an authorization policy defined in the OPSS policy store.
a) To attach the policies, place the cursor over the web service implementation class name (CustomerHistoryAMServiceImpl.java). In the property inspector, under Web Services Extension, under OWSM Policies, click the … button next to Security
b) Pick the following policies from the list:
oracle/wss_username_token_service_policy and oracle/binding_permission_authorization_policy.
Notice they are added as a SecurityPolicy class annotation.
These policies can also be added/removed/changed in Enterprise Manager.
At this point, all operations of our web service will require a valid user, but there’s still no authorization rule governing which users can access the findCustomerPaymentHistoryByName method. Let’s take care of it now.
As you might think, these authorization rules are expressed in the OPSS policy store. At design time, this translates to creating the rule in jazn-data.xml. Let’s assume that we only want to allow members of the manager role to invoke the findCustomerPaymentHistoryByName method.
Here’s the jazn-data.xml snippet.
Attention to lines 15-31. They define the authorization rule for our method.
<?xml version = '1.0' encoding = 'UTF-8' standalone = 'yes'?> <jazn-data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/oracleas/schema/jazn-data-11_0.xsd"> <policy-store> <applications> <application> <name>CustomerHistory</name> <app-roles> <app-role> <name>managers</name> <class>oracle.security.jps.service.policystore.ApplicationRole</class> </app-role> </app-roles> <jazn-policy> <grant> <grantee> <principals> <principal> <name>managers</name> <class>oracle.security.jps.service.policystore.ApplicationRole</class> </principal> </principals> </grantee> <permissions> <permission> <class>oracle.wsm.security.WSFunctionPermission</class> <name>/customerhistory/common/CustomerHistoryAMService#findCustomerPaymentHistoryByName</name> <actions>invoke</actions> </permission> </permissions> </grant> </jazn-policy> </application> </applications> </policy-store> </jazn-data>
Line 19 contains the role name granted the permission to invoke the method.
Line 26 defines the permission class that understands the name and actions specified in lines 27 and 28. oracle.wsm.security.WSFunctionPermission is mandatory for authorization rules based on OWSM authorization policies.
Line 27 defines the web service and the operation name being protected. Here is where we need the web service namespace and name, as said in subsection 2f above. You can also find this information in the service wsdl.
The format is <webservice-target-namespace>/<webservice-name>#<method-name>
And yes, you can use * in place of <method-name> and protect all methods in one shot.
Line 28 defines the action. The only available and allowed for webservices at the time of this writing is invoke.
To deploy an application like this, it is necessary to create a Business Components Service Interface Deployment Profile and then deploy it to an EAR file.
a) In JDev’s Application Navigator, right-click your project and select New…
Under General Categories, choose Deployment Profile and pick Business Components Service Interface in the right side.
Upon clicking OK button, give it a meaningful name and click OK
The deployment profile gets created.
b) Now, to actually package the application into an EAR file, click the little screen sign next to the application name in JDev’s application navigator, as shown below.
Then pick the deployment profile you have just created and deploy it to an EAR file.
That’s it. Your secured service-enabled ADF BC is ready to de deployed.
Hope this is useful for you. Good luck!