Thursday Mar 08, 2012

Using af:serverListener as a JS client-server proxy

Despite of ADF Faces having a client side JavaScript architecture, JavaScript rule #1 in ADF Faces is to use JavaScript as a fallback option only for development use cases in which there is no native solution to a problem. A built-in feature of the ADF Faces JavaScript client architecture is security that disallows certain component properties like disabled and readOnly to be changed from JavaScript.

To quote the JavaScript doc for the AdfRichInputText object:

http://docs.oracle.com/cd/E12839_01/apirefs.1111/e12046/oracle/adf/view/js/component/rich/input/AdfRichInputText.html#getReadOnly__

public Boolean getReadOnly()

Get function for attribute for 'readOnly'. This attribute is secured. You may get it, but you may not set it. Any changes to this attribute will not be transmitted to the server.

Note: The disabled property can be enabled for JavaScript modification by setting the component unsecure property as explained in the component documentation, which however I don't recommend you to do. If you need to open protected features for modification, do so in a way that you control, for example in that you can check a user permission to do so.

There might be use cases in which you need to change a protected property from JavaScript, and here is how this can and should be done:

The ADF Faces af:serverListener component allows developers to invoke server side Java from JavaScript and thus can be used as a proxy to bypass applied client side security.

For example, to be able to change the readOnly property on an af:inputText component, you define the text field as shown below

<af:inputText label="Label 2"
              id="it2" 
              clientComponent="true"                      
              value="#{SetInputTextFieldReadOnly.textValue}">
              <af:serverListener type="serverAction"
                                 method="#{SetInputTextFieldReadOnly.actionEvent}"/>
</af:inputText>

The clientComponent property need to be set to true on the component to ensure a JavaScript object is created on the client architecture. With no clientComponent set to true and no af:clientListener attached, the text field component is not accessible from JavaScript at all.

The af:serverListener needs to be configured on the component that is passed as a component reference to the server. In the sample, the component reference that is sent to the server is the input text field that you want to switch from updateable to read-only. If the integration is from a non ADF Faces component, like an Applet, you would configure the af:serverListener on the af:document component. If this is the case, you may not make use of the component reference on the server and instead pass additional payload arguments.

In the Oracle JDeveloper 11.1.1.6 sample to this article the switch between read-only and updateable is simulated by a command button you can press. The sample can be dowloaded from here.

In a realistic use case, this switch would be triggered from a non ADF Faces component like Applet or another technology you integrate in your ADF Faces page.

Note: The use of a command button in the sample is only for demonstration purpose. If the trigger was a command button then no JavaScript would be needed at all and JavaScript rule #1 would apply

On the server, a managed bean method is invoked by the client JavaScript call shown below:

<af:resource type="javascript">
  function setUpdateable(actionEvent){
     actionEvent.cancel();
     var commandButton = actionEvent.getSource();
     var textFieldId = commandButton.getProperty('componentId');
     invokeServerAction(textFieldId,actionEvent,'true');
  }
       
  function setReadOnly(actionEvent){      
    actionEvent.cancel();
    var commandButton = actionEvent.getSource();
    var textFieldId = commandButton.getProperty('componentId');
    invokeServerAction(textFieldId,actionEvent,'false');
  }   
  function invokeServerAction(compId,evt,isUpdateable){
    var textField = evt.getSource().findComponent(compId);            
    AdfCustomEvent.queue(
         textField,"serverAction",
         {updateable: isUpdateable},false);                              
  }
</af:resource>

Note: payload arguments are surrounded by curly braces. If you want to pass multiple arguments then you use a comma separated list of key1:value1, key2:value2 …pairs.

The JavaScript is taken from the sample provided for this tip and – as mentioned – is invoked from a command button. The command button has a custom property (af:clientAttribute) added that tells the script about the text component Id to modify. The component and the desired switch state "readOnly" or "updateable" is passed to the managed bean method:

 /**
  * Proxy the client request
  * @param clientEvent The client event gives you access to the 
  * component that raises the event as well as to the paraneters 
  * passed from the client to the server 
 */
 public void actionEvent(ClientEvent clientEvent) {
  /*
   * This would be a good place to check an ADF Security resource
   * permission if the user is allowed to perform the change on the 
   * attribute. There is no security in JavaScript, but using server 
   * side JAAS protects you from unauthorized changes
   */
   RichInputText inputText =  (RichInputText) clientEvent.getComponent();
   String updateable = (String) clientEvent.getParameters().get("updateable");
   inputText.setReadOnly(!Boolean.parseBoolean(updateable));
   AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance();
   adfFacesContext.addPartialTarget(inputText);
 }

Sample Download

https://blogs.oracle.com/jdevotnharvest/resource/SetInputTextToReadOnlyJS.zip

About

The Oracle JDeveloper forum ranks in the Top 5 of the most active forums on the Oracle Technology Network (OTN).



The OTN Harvest blog is a summary of selected topics posted on the OTN Oracle JDeveloper forum.



It is an effort to turn knowledge exchange into an interesting read for developers who enjoy little nuggets of wisdom





Frank Nimphius

Search

Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today