Skip to main content

Accessing web tier variable values from the business components in a groovy way

Groovy is an amazing dynamic language with lots of unnoticed features. One feature that I like most is the dynamism that can be introduced to an enterprise application at runtime. To know more about the groovy support in ADF, please go through this white paper : Introduction to Groovy

This 'dynamism' fits pretty well for an ADF based application in many scenarios. However, there are few cases where this feature is being used in a non groovy way :)

Accessing web layer data from business components

Rule of thumb for designing a system is that client layer can  depend upon your business service layer, not the other way around. This provides more flexibility and extensibility to the system. Your build tool (say for e.g.: maven) may also expect a unidirectional dependency, to resolve dependencies without getting into infinite loops.

However, there are some use cases where EntityObjects or ViewObjects needs to be initialized with values from the client side(web tier).
Consider a typical example where web tier keeps an 'activity id' in a PageFlowScoped memory variable - 'activityFlowId'. The same value may needs to be accessed from the Service Layer of the application. Let us explore few possible approaches for this specific case, and pros and cons with each one as well.

In this specific use case, the requirement is to access this PageFlowScoped variable from a ViewObject, in order to initialize a specific transient attribute. A very common approach being followed by is to make use of the oracle.adf.share.ADFContext class that has set of APIs exposed for accessing the 'scoped variables' of the web layer. Even groovy expression can be used to achieve the above said functionality in a declarative way. Below image shows the groovy expression that being used for the same.

Groovy expression:

Drawback of accessing PageFlowScoped variable direcly from business service layer

1. Your business service layer starts losing the core principles like extensibility and reusability. In the above case, business service depends on the client layer which is not considered as a good design as we are losing the clear separation between view and business service layers.
2. If you follow Test Driven Development methodology, the above implementation may fail when you try to test business service layer independently (web container is missing here)

A better (recommended) approach for the above use case, which is free from the above mentioned drawbacks is detailed below

Step1: Expose a custom method on the business service layer (Application Module) that accepts the required parameter
Step 2: View layer is supposed to pass the desired information by invoking the above method. The information can be saved in a hash table obtained from session.getUserData(). ADF has groovy support to access the value from this data structure.

The 'custom method' exposed in the Application Module may look like as below
public void setAtivityFlowIdId(String activityFlowId) {
   this.getSession().getUserData().put("activityFlowId", activityFlowId);

The value stored in the 'session user data' can be referenced from EntityObjects and ViewObjects using groovy expression, declaratively. Below image shows how the groovy expression can be used for accessing the userSession value.
(Steps: Select Attribute of ViewObject -> Click Edit -> Select Expression -> key in value)

Groovy expression:

Apparently, the second approach let you to unit test your service layer independently and avoids the dependency to the view layer.

[ Many thanks to Steve Muench who pointed out some flaws in the initial version of the same blog post! ]
You can download the sample workspace from here.

Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post-


Popular posts from this blog

How to set Bind Variable Values at runtime ?

In this post I'm sharing a couple of approaches for programmatically setting bind variables values at run time. This post is an attempt to explain 'When to use what ?'[ In case if you are familiar with 'Bind Variables' in ADF BC, please refer Section 5.10, Working with Bind Variables in Fusion Developer's Guide ]

1. Set the Bind Variable value using RowSet::setNamedWhereClauseParam(...)

You can use use the setNamedWhereClauseParam(...) method on the ViewObject interface (which extends oracle.jbo.RowSet) to set the value for bind variables. Please note this sets the value on default RowSet. In other words, this doesn't have any effect on the secondary RowSets that you/system generates.
ViewObject vo = am.findViewObject("EmployeesView1"); vo.setNamedWhereClauseParam("bindVarDeptId", new Number(10)); vo.executeQuery();
2. Set the Bind Variable value using ViewObject's VariableValueManager::setVariableValue(...)

VariableValueManager Ma…