Sunday, November 8, 2009

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:
adf.context.expressionEvaluator.evaluate
('#pageFlowScope.activityFlowId}')

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:
adf.userSession.userData.activityFlowId

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.

Sunday, October 18, 2009

Entity Object based on a PL/SQL Package API

A simple demo application that uses Entity Object based on the Stored Procedure is attached here.
More details can be found in Developer's Guide, section 37.5 Basing an Entity Object on a PL/SQL Package

PS: Unzip the attachment and run the script(StoredProcedureExample/script) to set up the required DB objects for running this demo

Friday, October 16, 2009

Reset the content of a web page

Resetting the page contents or undoing the changes made by a user is a very common use case scenario in Rich Internet Applications. The 'reset action' should skip all validations defined on the current page and page contents needs to restored from the underlying data layer. Some of the web frameworks support this feature out of the box. Let me try explaining possible ways to reset a page when developing applications using ADFFaces.

1. <af:resetButton>

As the name suggests, af:resetButton resets the contents of a form. Please note that developer doesn't have much control here as he/she might not be able to bind any action method with this built in reset button.
<af:resetButton  text="ResetButton" id="rb1"/>
2. <af:resetActionListener>

This tag is usually bound to an action source like command button to reset all submitted values whenever an action is triggered. Obviously this gives more control to the developer as the action sources like command button can be optionally bound to an action method through the Expression Language(EL). Please note that, you may need to keep immediate="true" for the command button ( for the action source ) to skip the validations while implementing the reset/cancel behavior.
  
<af:commandButton text="Cancel with resetAction" id="cb2"  immediate="true"   
     partialSubmit="true"
     actionListener="#{SomeBean.cancelBusinessAction}">
     <af:resetActionListener/>
</af:commandButton>

Why do we need to reset submitted values?

Each component has local cache value. When you submit a form, submitted value gets assigned to this localValue at the end of 'PROCESS VALIDATIONS' pahse, and thereafter submitted value is set as null. During the RENDER RESPONSE, first consult the local value property of this component. If non-null return it. If null, see if we have a ValueExpression for the value property. UIInput::resetValue() reset the submitted value that would force the rendering logic to take the value from the model/binding layer.

3. Custom Reset Implementation

So far so good, but in some scenarios developers may need to dirty their hands a bit to get the job done - where the declarative 'reset' support is missing. I noticed a rare use case scenario recently, that calls for custom reset implementation. There master-detail data is displayed in tabular form and user is allowed to edit one master record (and it's children as well) at a time, then save that record and proceed to next. In case user decided to navigate to next record without saving current record, then current changes needs to be cancelled. Though use case is bit odd one, adding this feature is pretty simple. All we need to is override the default selectionListener and from this custom method, parse the component tree and call reset on each element.
Code Snippet:
   
 public void customSelectionHandler(SelectionEvent selectionEvent) {

     UIComponent source = (UIComponent)selectionEvent.getSource();
     UIComponent uiComp = _getRootToReset(source);
     _resetChildren(uiComp);
     EL.invokeMethod(
     "#{bindings.DepartmentsView11.collectionModel.makeCurrent}",
     SelectionEvent.class, selectionEvent);
}
   

On a related note, I would suggest you to look at the source of org.apache.myfaces.trinidadinternal.taglib.listener.ResetActionListener, that may help you to understand the 'reset' concept much better. (Even the below given sample application just tries to reuse the same reset logic from ResetActionListener class).

You can download the sample workspace from here.

Monday, September 28, 2009

Decorate JSF managed bean with custom Annotations

Java Annotatons  has been widely accepted by enterprise application developers. It really free up developers from writing down tons of boilerplate code which is used for business service invocation or basic infrastructural set up like initializing the service context or getting handle to some core runtime services etc.

This blog post is mainly intended to take you through the possibilities of using annotation while building enterprise solutions. There are definite advantages if you use this tool judiciously. Few highlights are:
  • Reduces the boilerplate code in your business tier.
  • Adds dynamism to your code.
  • Greater control on the implementation part, as the logic is abstracted  from the developers.
  • High Extensibility etc...
JSF managed bean and custom ADF flavored annotations

A closer look at the source code of a typical web application may reveal fair amount of boilerplate code that spread across managed beans on the client tier. This repetitive piece of code mainly does the below tasks.

  • Look up ApplicationModule/DataControl
  • Invoke business service methods
  • Retrieve binding parameter values etc.
Is there any better alternatives available to handle such scenarios?

Answer is 'YES'. One possibility is by using Annotation. If you are building a huge system based on ADF + Java EE technology stack, It's really worth checking possibility of building custom Annotations for your application.

The below diagram clearly depicts how custom Annotation can be leveraged to look up ApplicationModule from a managed bean.





How to build custom Annotations?

I would suggest you to go through this link if you are not familiar with Annotation.

Define custom Annotation

Define custom Annotations based on your system's requirement. The below code snippet shows a custom annotation class (ServiceContext.java) that can be applied to fields of JSF managed bean to inject the reference of underlying ApplictionModule.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)

public @interface ServiceContext {

    /**
     * Purely for extensibility reasons we keep this enum type. As of now
     * we deal with only Application Module
     * */
    public enum Servicable {
        APPLICATION_MODULE;
    }

    public Servicable servicable() default ServiceContext.Servicable.APPLICATION_MODULE;

    public String serviceName(); //DC name if the servicable is of type APPLICATION_MODULE;

}

Processing custom annotation

 Next step is to process the Annotations at runtime. As I stated earlier, the custom Annotation that we are discussing here is purely meant for JSF managed beans. So what we need here is a hook to add the custom AnnotationProcessor so that annotation defined in a managed bean can be processed based on the rule definitions at runtime. Fortunately JSF gives an option to add custom ELResolver where we can listen for bean instantiations and invocations using Expression Language(EL). Please go through this article to learn more about this topic. Annotation processing can be carried out from this custom ELResolver at runtime.

Annotate JSF managed bean

Consider a use case where backing bean of a web application needs to get the reference of underlying ApplicationModule instance. Let us try addressing this use case by introducing the annotation that we generated in the above steps. Now the bean may look like as shown below.

 @ServiceContext(serviceName = "AppModuleDataControl")
 ApplicationModule myAppModule;   
 public String testAMAnnotation() {
        // Add event code here...
        amResult =((AppModuleImpl)myAppModule).getTodaysMessage();
        System.out.println(" Message: " + amResult);
        return null;
    }


That’s it, job is done without writing any sort of boilerplate code. System runtime injects the right ApplicationModule reference to the designated variable at runtime.

More on custom Annotations

Few more ADF Flavored custom annotations are listed below.

Definitions:

 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.FIELD)
 public @interface PageBindingContext {
    public enum BindingType {
        ATTRIBUTE_BINDING,
        ITERATOR_BINDING,
        OPERATION_BINDING,
        VARIABLE_BINDING;
    }
    String name();
    BindingType bindingType();
}

Usage:

    @PageBindingContext(name = "someAttribute",
                        bindingType = BindingType.VARIABLE_BINDING)
    String attribBindingValue;

    @PageBindingContext(name = "someMethod",
                        bindingType = BindingType.OPERATION_BINDING)
    OperationBinding opBinding;

Sample workspace


You can download the sample workspace from here.


Performance Issues

Apparently, Annotation is a very powerful tool. However this needs to be used very judiciously, especially if you are planning to use Annotations at runtime. I would suggest you to go for a strict performance test before releasing the feature to the end users(developers).

Summary

This blog gives you an overview of building custom Annotations for your ADF/Java EE applications. The above example doesn't really replaces the ADF Binding layer, rather tries to make use of the features of binding layer and adds more dynamism to your backing bean.

Annotations can be of great use if it's being used in right way, so be measured and use it judiciously.


Thursday, September 17, 2009

Format date for a Locale

A very common use case related to localization is that, formatting the date specific to a user-selected locale.
Following code snippet will help you to identify the default pattern corresponding to a locale.
String pattern =
((SimpleDateFormat)DateFormat.getDateTimeInstance(SimpleDateFormat.FULL,
SimpleDateFormat.LONG,
locale)).toPattern();


Your jsf page snippet may look like:
  <af:inputDate label="Date:" id="id1" value="#{viewScope.TestBean.date}"
                      binding="#{viewScope.TestBean.inputDate}"
                      partialTriggers="soc1">
          <af:convertDateTime type="both"
                              timeZone="#{viewScope.TestBean.timeZone}"
                              locale="#{viewScope.TestBean.locale}"
                              pattern="#{viewScope.TestBean.pattern}"
                             />
        </af:inputDate>
You can download the sample workspace from here.

Saturday, August 22, 2009

How to Skip Validation?

ADF has a very robust validation framework. Validations can be added at different layers (view, model and business services) based on your application's requirement. To learn more about the ADF validation framework, please go through the Fusion Developer's Guide for Oracle Application Development Framework.
That said, however, in a real business scenario there are cases where the validation needs to be skipped (or by passed) conditionally while submitting the form. This post discusses this topic with some common use cases.

Keep immediate=true

A very common way to skip validation is by keeping the value for immediate attribute as 'true' for the UIComponents. Immediate attribute allow processing of components to move up to the Apply Request Values phase of the lifecycle.

Use case scenario

While canceling a specific action, system should not perform the validation. One possible way to achieve this is by keeping immediate=true associated with UI element. To know more abut this feature, please refer this wiki.
Sometimes you may need to update UI controls with model data as part of the ‘immediate’ action. Make sure that you call resetValue() on the UIInput in this scenario. This causes to reset the submitted value and would ensure that UI gets updated with right value from the model.

SkipValidation

Another approach is to use SkipValidation property associated with the page definition file. SkipValidation by pass the model layer validation based on the specified parameter value.

Please note that:
1. This doesn’t have any impact on JSF/ADF Lifecycle.
2. This property doesn’t have any effect on the client side validation (even if it is generated using the EL bound with model layer)


Where can I locate SkipValidation?

SkipValidation can be located as part of the root node of the page definition file.



Possible values for SkipValidation are given below.



a. SkipValidation=true

Setting ‘SkipValidation’ property to true will bypass the ADF Model validation. In this case validation happens only when you commit the transaction( i.e: when you call transaction.commit()). Please note that SkipValidation skips only the entity level validation. The attribute level validation fire irrespective of the value for the boolean flag

Use case Scenario

This is useful where you need to delay the validation till the point where transaction gets committed to Database. There are cases where business data needs to be captured in bulk. A typical example would be capturing transaction data using a grid form/tabular list. Business user must be able to key in values in any order. i.e. even without completing the data capture for the current record, user must be able to move to next set of records. Here model level validation needs to be delayed till we really save the data. SkipValidation=true is the right option to achieve this sort of use case, which does the validation across records, only while committing the transaction.

b. SkipValidation=custom

In this case, framework validates only the 'CustomValidator' specified in page definition file.
The value of the 'CustomValidator' property would be an EL expression that evaluates to a bean that implements the oracle.binding.BindingContainerValidator interface



Use case Scenario

This gives more control to the developer while validating the data. Only validates(or rather executes) what is given in custom implementation for BindingContainerValidator. It is much useful in complex business scenarios where developer needs finer control on validation.

c. SkipValidation=skipDataControls

skipDataControls means that it will skip the data control level validation (also known as Transaction Level validation) and instead only will validate data in the row or rows which got updated through iterator in the current binding container.

Use case Scenario

The property is very much useful while dealing with below given scenarios.
1. A single entity is mapped to multiple tabs in a page.
2. Same page is making use of multiple Data Controls. Here commit on one Data Control should not trigger validation on other Data Controls defined in the same page.


d. SkipValidation=false

This is the default value for SkipValidation, apparently this setting just ensures the normal flow for validation during form submission.

Monday, August 17, 2009

How to keep track of modified values of controls in a JSF application?

I recently encountered an interesting use case where ADF Faces is used for the view layer and the data(model) is persisted in LDAP Store. Now the requirement is to identify the modified records/attributes and perform the update only on these records. There may be different ways to achieve this, say for example using container like Spring with AOP. But, is there any other smart approach without adding extra layer to my application's technology stack? Answer is 'Yes'. Let us explore one possible approach for this use case scenario.

ELResolver

The solution is based on customized ELResolver. We know that backing beans are bound to the view(jsf pages) using Expression Language(EL). ELResolver actually resolves thesa 'binding expressions' at runtime. So idea is to intercept in the invocation of setters for the backing beans through a customized ELResolver. And add the logic to track the modified attributes at this point. JSF specification enables to add customized javax.el.ELResolver by modifying faces-config.xml.

Example

<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee">
<application>
<default-render-kit-id>
oracle.adf.rich
</default-render-kit-id>
<el-resolver>
view.extension.SmartELResolver
</el-resolver>
</application>
</faces-config>


Now we can hook the custom logic to address the above requirement by overriding the ELResolver::setValue(...). Adding this logic is left to you, needless to say your backing bean may need to follow predefined contract to enable the centralized processing at ELResolver. What I meant is, bean may need to implement a predefined interface and the ELResolver can work on the 'instance of' this specific object type.

You can download the sample workspace from here.