30 Apr 2014

Enabling and Disabling AM Pooling Programmatically

In this post I am going to show some useful technique that ADF developers and QAs may use in their daily work. I mean the ability to enable and disable application module pooling on-the-fly without redeploying and restarting the application. This can be useful for testing purposes when you are able to quickly enable or disable AM pooling and check how the application works in both cases. There are some issues that you can run into only when the pooling is enabled. So, developing and testing an application with constantly disabled AM pooling doesn't cover all cases.
I believe that not many developers and testers use in their daily life such monster instruments like EM Fusion Middleware Control. Therefore I would propose to include that functionality in the application, certainly for the development and testing purposes only.

In order to implement that nice feature, we have to create our custom implementation of the ApplicationPool interface and register it in the application module configuration. So, our custom ApplicationPool looks like this:
public class CustomApplicationPoolImpl extends ApplicationPoolImpl {
    private boolean amPoolingEnabled = true;
    

    public CustomApplicationPoolImpl() {
        super();
    }

    @Override
    public boolean isAMPoolingEnabled() {
       return amPoolingEnabled;
    }
    

    public void setAmPoolingEnabled(boolean amPoolingEnabled) {
        this.amPoolingEnabled = amPoolingEnabled;
    }
}

It has an overridden method isAmPoolingEnabled which returns a private valriable member amPoolingEnabled.  In order to register this class and make it used by the framework we should go to the application module configuration and specify the class name in the PoolClassName property at the bottom of the properties list:



And when we need to get an instance of our CustomApplicationPoolImpl and setup the value of the amPoolingEnabled variable, we can make use of the oracle.jbo.common.ampool.PoolMgr internal class and do the following:
    public void setAmPooling(boolean value){
       CustomApplicationPoolImpl pool =
          (CustomApplicationPoolImpl)PoolMgr.getInstance().
           getResourcePool("com.cs.blog.ampoolappl.model.AppModuleLocal");

        pool.setAmPoolingEnabled(value);
    }

The sample application for this post requires JDeveloper R2 11.1.2.3.0.

That's it!

26 Apr 2014

Working with the Array Data Type in a Table

In this post I would like to follow up on my previous article about Oracle collection data types and I am going to focus on working with oracle.jbo.domain.Array attributes in af:table component.

So, in my database I have the following SQL type:

create or replace type varchar2_array_type as table of varchar2(200)  

And I've got the following table:

create table testarray (
 SomeField Number,
 ArrValue VARCHAR2_ARRAY_TYPE)

nested table ArrValue store as arrvalue_tab return as value;  

There is an entity in ADF BC model which is based on the testarray table:


The data type of the attribute Arrvalue is oracle.jbo.domain.Array. 

There is a corresponding attribute binding in the binding container:

    <attributeValues IterBinding="VTestarrayIterator" id="Arrvalue">
      <AttrNames>
        <Item Value="Arrvalue"/>
      </AttrNames>
    </attributeValues>
The easiest way to display the value of this attribute could be like this:
<af:table value="#{bindings.Arrvalue.inputValue.array}" var="row" 
          id="t1">
   <af:column sortable="false" headerText="Array Values" id="c1">
      <af:inputText value="#{row}" id="ot3"/>             
   </af:column>
</af:table>
And the result looks pretty nice:

The only problem with this approach is that the table is not updatable. It is read only one.  

The EL expression "#{bindings.Arrvalue.inputValue.array}" is going to invoke the method oracle.jbo.domain.Array.getArray() which returns an immutable Object[] array and all modifications to this array will be lost.

If we need to be able to update the data in the table, we've got to do the following:
  1. Make a copy of the bindings.Arrvalue.inputValue.array
  2. Set this copy as table's value
  3. At the Update Model Values phase wrap the copy back into oracle.jbo.domain.Array and put it to the Arrvalue.inputValue. 

So, we are going to make a copy and keep it in a request scope managed bean:

private Object[] array = null;

private Object[] createArray() {
  JUCtrlValueBinding dcb = getArrayCtrlBinding();
  if (dcb!=null){
      Array arr = (Array) dcb.getInputValue();
      if (arr!=null) {
          array = arr.getArray();
      }          
  }
  return array;
}


public void setArray(Object[] array) {
    this.array = array;
}

public Object[] getArray() {
    return (array == null ? createArray() : array);
}

    
private JUCtrlValueBinding getArrayCtrlBinding() {
  BindingContext bc = BindingContext.getCurrent();
  DCBindingContainer binding = (DCBindingContainer) bc.getCurrentBindingsEntry();
  return (JUCtrlValueBinding ) binding.findCtrlBinding("Arrvalue");
}
 
   
When it comes to using this copy as table's value, we can do the following:
  <af:table value="#{TheBean.array}" var="row" 
            id="t1"
            varStatus="status">
    <af:column sortable="false" headerText="Array Values" id="c1">
       <af:inputText value="#{TheBean.array[status.index]}" id="ot3"/>             
    </af:column>
  </af:table>
 
Note, that we didn't use just #{row} as inputText's value. It wouldn't work, since #{row} would just return an immutable String. Instead of that we used the varStatus table attribute. The EL expression #{TheBean.array[status.index]} makes the framework able to call a corresponding setter method at the Update Model Values phase, so all modifications made in the table will be saved to the TheBean.array.  
 
The last step is to put TheBean.array back into the attribute value at the Update Model Values phase. We can use a fake invisible inputText for that purpose:
<af:inputText value="#{TheBean.dummy}" 
              visible="false" 
              converter="EmptyConverter"
              id="it2"/>

  
This input text should be placed below the table on a page. The beauty of this approach is that the framework will try to update the inputText value on each request. So, the setter method TheBean.setDummy(String dummy) will be invoked on each request at the Update Model Values phase right after the table values have been saved to the TheBean.array. And at this moment we're going to wrap the array into oracle.jbo.domain.Array and put it back to the Arrvalue.inputValue:

public void setDummy(String dummy) {
  getArrayCtrlBinding().setInputValue(new Array(array));   
  array = null;
}
 
The secret of this dummy inputText is hidden in the EmptyConverter:
public class EmptyConverter implements Converter {
 public Object getAsObject(FacesContext facesContext,
                           UIComponent uIComponent, String string) {
     return null;
 }

 public String getAsString(FacesContext facesContext,
                           UIComponent uIComponent, Object object) {
     return null;
 }
}
It emulates that null value has been submitted for this component with the request. On the other hand, the dummy getter always returns a not null value:
 public String getDummy() {
    return DUMMY;
 }   

So, the framework has no option, but to invoke the setDummy method at the Update Model Values phase.

The sample application for this post requires JDeveloper 11.1.1.7.

That's it!