Tuesday, April 05, 2011

Usecase(ADF)-Controlling UI components Behaviour from Model Layer

Requirement

Say,an ADF UI has 50 UI components and you want to control these UI components behaviour dynamically.For example,

* 15 UI components shouldnt be rendered in a specific condition.
* 10 UI components should be ReadOnly in a specific condition.
* 20 UI components should have a MaxLength 120 in a specific condition.
* 30 UI components should have a different Label in a specific condition.
* and so on.

Simple Solution

Simplest solution is to manipulate the "rendered", "disabled" ,"label", "shortDesc", "maximumLength" etc properties in the JSFF/JSPX using EL expressions which can be calculated using a managed bean method.
Smart Solution

The simple solution makes the JSFF/JSPX messy with complex conditional EL expressions which is hard to maintain and improvise.

A smart solution is to handle this entirely in the Model Layer if your UI is driven by a View Object. View Object attributes have Control Hints which derive their values and represent themselves in the UI layer.

These are the things you need to do to achieve this.

Create a Service/Util class that will handle the logic to derive the values of the properties based on some business requirement.

import java.util.HashMap;
import java.util.Map;

import oracle.jbo.AttributeHints;

public class UIHintsService {

private static UIHintsService uiHintsService;

private UIHintsService() {
super();
}

public static synchronized UIHintsService getInstance() {
if (uiHintsService == null) {
uiHintsService = new UIHintsService();
}
return uiHintsService;
}
//Your Business Logic goes here, which says, for DepartmentName Attribute following UI properties need to be changed at the runtime.
public Map getAttributeHints(String attributeName) {
Map map = new HashMap();
if("DepartmentName".equalsIgnoreCase(attributeName))
{
map.put(AttributeHints.ATTRIBUTE_CTL_DISPLAYWIDTH, 100);
map.put(AttributeHints.ATTRIBUTE_LABEL,
attributeName + "[Overridden1111]");
map.put(AttributeHints.ATTRIBUTE_TOOLTIP,
attributeName + "[Overridden1111]");
map.put(AttributeHints.ATTRIBUTE_DISPLAY_HINT,
AttributeHints.ATTRIBUTE_DISPLAY_HINT_HIDE);
map.put(AttributeHints.HINT_NAME_UPDATEABLE,
"NEVER");
}
return map;
}
}



Create a Custom Class in your Model Layer called LazyViewRowAttrHintsImpl.java that extends oracle.jbo.server.ViewRowAttrHintsImpl.

public class DepartmentsViewRowImpl extends ViewRowImpl {


/**
* This is the default constructor (do not remove).
*/
public DepartmentsViewRowImpl() {
}

/**
* Gets Departments entity object.
* @return the Departments
*/
public EntityImpl getDepartments() {
return (EntityImpl)getEntity(0);
}

@Override
protected ViewRowAttrHintsImpl createViewRowAttrHints(AttributeDefImpl attrDef) {
//See here, we are returning the custom RowAttrHintsImpl class which has our own logic
return new LazyViewRowAttrHintsImpl(attrDef, this);
}

}
import java.util.HashMap;

import java.util.Map;

import oracle.jbo.AttributeHints;
import oracle.jbo.LocaleContext;
import oracle.jbo.server.AttributeDefImpl;
import oracle.jbo.server.ViewAttributeDefImpl;
import oracle.jbo.server.ViewRowAttrHintsImpl;
import oracle.jbo.server.ViewRowImpl;

import model.UIHintsService;

public class LazyViewRowAttrHintsImpl extends ViewRowAttrHintsImpl {

public LazyViewRowAttrHintsImpl(AttributeDefImpl attributeDefImpl,
ViewRowImpl viewRowImpl) {
super(attributeDefImpl, viewRowImpl);
decorateWithLazyHints(attributeDefImpl);

}

public LazyViewRowAttrHintsImpl() {
super();
}

private void decorateWithLazyHints(AttributeDefImpl attributeDefImpl) {
String flag = (String)attributeDefImpl.getProperty("Populated");
if ("true".equals(flag)) {
return;
}
System.out.println("##### Inside decorateWithLazyHints for : " +
attributeDefImpl.getName());
Map propMap =
UIHintsService.getInstance().getAttributeHints(attributeDefImpl.getName());
if (propMap != null && propMap.size() > 0) {
attributeDefImpl.setPropertyMap(propMap);
AttributeDefImpl entAttr =
((ViewAttributeDefImpl)attributeDefImpl).getEntityAttributeDef();
if (entAttr != null) {
entAttr.setPropertyMap(propMap);
}
}
attributeDefImpl.setProperty("Populated", "true");
}
}



In your VORowImpl.java, override the method createViewRowAttrHints(AttributeDefImpl attrDef) to return the custom LazyViewRowAttrHintsImpl like this.

Your UI JSFF/JSPX would look like this as you have already used the VO bound UI and the control hints would automatically be bound to these components.

<af:inputText value="#{bindings.DepartmentId.inputValue}"
label="#{bindings.DepartmentId.hints.label}"
rendered="#{bindings.DepartmentId.hints.displayHint == 'DISPLAY'}"
required="#{bindings.DepartmentId.hints.mandatory}"
columns="#{bindings.DepartmentId.hints.displayWidth}"
maximumLength="#{bindings.DepartmentId.hints.precision}"
shortDesc="#{bindings.DepartmentId.hints.tooltip}"
id="it3">
<f:validator binding="#{bindings.DepartmentId.validator}"/>
<af:convertNumber groupingUsed="false"
pattern="#{bindings.DepartmentId.format}"/>
</af:inputText>
<af:inputText value="#{bindings.DepartmentName.inputValue}"
label="#{bindings.DepartmentName.hints.label}"
rendered="#{bindings.DepartmentName.hints.displayHint == 'DISPLAY'}"
required="#{bindings.DepartmentName.hints.mandatory}"
columns="#{bindings.DepartmentName.hints.displayWidth}"
maximumLength="#{bindings.DepartmentName.hints.precision}"
shortDesc="#{bindings.DepartmentName.hints.tooltip}"
id="it1">
<f:validator binding="#{bindings.DepartmentName.validator}"/>
</af:inputText>
<af:inputText value="#{bindings.ManagerId.inputValue}"
label="#{bindings.ManagerId.hints.label}"
rendered="#{bindings.ManagerId.hints.displayHint == 'DISPLAY'}"
required="#{bindings.ManagerId.hints.mandatory}"
columns="#{bindings.ManagerId.hints.displayWidth}"
maximumLength="#{bindings.ManagerId.hints.precision}"
shortDesc="#{bindings.ManagerId.hints.tooltip}"
id="it4">
<f:validator binding="#{bindings.ManagerId.validator}"/>
<af:convertNumber groupingUsed="false"
pattern="#{bindings.ManagerId.format}"/>
</af:inputText>
<af:inputText value="#{bindings.LocationId.inputValue}"
label="#{bindings.LocationId.hints.label}"
rendered="#{bindings.LocationId.hints.displayHint == 'DISPLAY'}"
required="#{bindings.LocationId.hints.mandatory}"
columns="#{bindings.LocationId.hints.displayWidth}"
maximumLength="#{bindings.LocationId.hints.precision}"
shortDesc="#{bindings.LocationId.hints.tooltip}"
id="it2">
<f:validator binding="#{bindings.LocationId.validator}"/>
<af:convertNumber groupingUsed="false"
pattern="#{bindings.LocationId.format}"/>
</af:inputText>

9 comments:

Les said...

Looks good. I shall implement this and see in my project. Thank you for sharing this Amulya. Highly Appreciated

jmxking said...

Amulya, I tried exactly what you said and the inputtext items created on the jsff page doesnt have rendered="#{bindings.DepartmentId.hints.displayHint == 'DISPLAY'}" this property set.
Can you explain the process please? or do u have an email id where I can get in touch

Anonymous said...

Amulya, I tried exactly what you said and the inputtext items created on the jsff page doesnt have rendered="#{bindings.DepartmentId.hints.displayHint == 'DISPLAY'}" this property set.

Anonymous said...

viagra achat viagra moins cher precio viagra donde comprar viagra viagra acquistare viagra italia

Anonymous said...

http://site.ru - [url=http://site.ru]site[/url] site
site

Anonymous said...

cilias generic cilias generic achat cialis tadalafil generico cialis cialis acquisto cialis comprar cialis andorra

Anonymous said...

generic cialis generic cialis cialis commander cialis medicament cialis acquistare cialis cialis comprar cialis precio farmacia

Anonymous said...

http://cialisnopreascriptionmg.net/ cialis no preascription 20 mg
http://achatcialisgenerique20mg.net/ commander cialis
http://acquistocialisgenerico20mg.net/ cialis roma
http://comprarcialisgenerico20mg.net/ cialis generico

Anonymous said...

http://acheterviagragnerique1.net/ acheter viagra
http://comprarviagragenerico1.net/ viagra generico
http://acquistareviagragenerico1.net/ viagra generico
http://kaufenvaigragenerika1.net/ viagra