Thursday, 9 February 2012

ADF Stored Proc Output Cursor View Object Implementation

I had to write an ADF implementation of an Oracle Form which relies a lot on Stored Procedures for the read and display of data from Output Cursors. Hence, I've eventually implemented what I call, a generic stored procedure output cursor view object implementation in order to support the create of a simple VO in ADF for use in the View Layer. Please find the implementation below:

public class StoredProcOutputCursorVOImpl extends ViewObjectImpl {
 
  private String cursorParameterName = null; 
  private String storedProcFullyQualifiedSql = null; 
  // stored proc parameters
: the ProcParam class is simply an encapsulation of a stored proc parameter
  private ProcParam[] procParameters; 
  // cursor cached data : a Map like object representing the output from the cursor (also used for caching)
  private RefCursorData refCursorData = null;
 
    /**
   * This is the default constructor (do not remove).
   */
  public StoredProcOutputCursorVOImpl() {   
  }

  public StoredProcOutputCursorVOImpl(String storedProcFullyQualifiedSql, String cursorParameterName) {
    this.storedProcFullyQualifiedSql = storedProcFullyQualifiedSql;
    this.cursorParameterName = cursorParameterName;
  }
 
  private Collection<Map<String, Object>> executeStoredProcWithRefCursorResult(String storedProcFullyQualifiedSql,
    String refCursorName, ProcParam... parameters) {   
    return DbUtils.callProcReturningRefCursorResult(this.getDBTransaction(), storedProcFullyQualifiedSql,
        refCursorName, parameters);
  } 

  /**
   * executeQueryForCollection - overridden for custom java data source support.
   */
  protected void executeQueryForCollection(Object qc, Object[] params, int noUserParams) {   
    RefCursorData refCursorData = new RefCursorData(this.getOrderByClause());   
    if (this.getProcParameters() == null) {
      throw new JboException("Stored Procedure Parameters need to be set. At least initialize and empty ProcParam Array!");
    }
    Collection<Map<String, Object>> refCursorList =
      this.executeStoredProcWithRefCursorResult(this.getStoredProcFullyQualifiedSql(), this.getCursorParameterName(),
        this.getProcParameters());
    refCursorData.setResultCollection(refCursorList);
    this.setRefCursorDataForCollection(qc, refCursorData);   
    // Prime the pump with the first row.
    this.hasNextForCollection(qc);
    super.executeQueryForCollection(qc, params, noUserParams);
  }

  /**
   * hasNextForCollection - overridden for custom java data source support.
   */
  protected boolean hasNextForCollection(Object qc) {
    boolean hasNext = getRefCursorDataForCollection(qc).getNextRow();
    if(!hasNext) {
      setFetchCompleteForCollection(qc, true);
      return false;
    }
    return true;
  }

  /**
   * createRowFromResultSet - overridden for custom java data source support.
   */
  protected ViewRowImpl createRowFromResultSet(Object qc, ResultSet resultSet) {
    ViewRowImpl row = createNewRowForCollection(qc);   
    // populate row from Map entry in RefCursorDataCollection
    Map<String, Object> cursorRow = ((RefCursorData) getRefCursorDataForCollection(qc)).getNextRow();
    int rowIndex = 0;
    for(Object obj : cursorRow.values()) {
      this.populateAttributeForRow(row, rowIndex, obj);
      rowIndex++;
    }
    return row;
  }

  /**
   * getQueryHitCount - overridden for custom java data source support.
   */
  public long getQueryHitCount(ViewRowSetImpl viewRowSet) {
    QueryCollection qColl = viewRowSet.getQueryCollection();
    RefCursorData refCurrData = (RefCursorData) getRefCursorDataForCollection(qColl);
    if (refCurrData != null) {
      return refCurrData.size(); 
    } else {
      return 0;
    }   
  }

  protected void create() {   
    getViewDef().setQuery(null);
    getViewDef().setSelectClause(null);
    setQuery(null);
  }

  public void setRefCursorDataForCollection(Object queryCollection, RefCursorData refCursorData) {
    this.refCursorData = refCursorData;
  }

  public RefCursorData getRefCursorDataForCollection(Object queryCollection) {
    return refCursorData;
  }

  public void setCursorParameterName(String cursorParameterName) {
    this.cursorParameterName = cursorParameterName;
  }

  public String getCursorParameterName() {
    return cursorParameterName;
  }

  public void setStoredProcFullyQualifiedSql(String storedProcFullyQualifiedSql) {
    this.storedProcFullyQualifiedSql = storedProcFullyQualifiedSql;
  }

  public String getStoredProcFullyQualifiedSql() {
    return storedProcFullyQualifiedSql;
  }

  public void setProcParameters(ProcParam[] procParameters) {
    this.procParameters = procParameters;
  }

  public ProcParam[] getProcParameters() {
    return procParameters;
  }
}
With the above code in place, one simply creates a programmatic View Object with its Java implementation extending the above class...providing the SQL to call the appropriate stored procedure as well as defining the output cursor parameter name.
And there you have a usable View Object calling a stored procedure and populating the attributes dynamically from the stored proc output cursor!

I had to update the code listing above (fixed a bug in the RefCursorData class) and hence I realised I also need to provide the code for the RefCursorData class as part of this post:

public class RefCursorData {
 
  private String orderByClause;
  private Collection<Map<String,Object>> resultCollection;
  private Iterator<Map<String,Object>> statefulPointer = null;
 
  public RefCursorData() {
  }
 
  public RefCursorData(String orderByClause) {
    this.orderByClause = orderByClause;
  } 
 
  public Map<String,Object> getNextRow() {   
    if (this.statefulPointer != null && this.statefulPointer.hasNext()) {
      return this.statefulPointer.next();
    }
    return null;
  }
 
  public boolean hasNextRow() {
    if (this.statefulPointer != null) {
      return this.statefulPointer.hasNext();
    }
    return false;
  }
 
  public int size() {
    if (this.resultCollection != null) {
      return this.resultCollection.size();    
    }
    return 0; 
  }
 
  public String getOrderByClause() {
    return this.orderByClause;
  }
 
  public void setOrderByClause(String orderByClause) {
    this.orderByClause = orderByClause;
  }
 
  public void setResultCollection(Collection<Map<String,Object>> resultList) {
    this.resultCollection = resultList;
    this.statefulPointer = this.resultCollection.iterator();
  }
}


Enjoy!

ADF Stored Proc Output Parameters View Object Implementation

I had to write an ADF implementation of an Oracle Form which relies a lot on Stored Procedures for the read and display of data. Hence, I've eventually implemented what I call, a generic stored procedure output parameter view object implementation in order to support the create of a simple VO in ADF for use in the View Layer. Please find the implementation below:
public class StoredProcOutputParametersVOImpl extends ViewObjectImpl {
 
  private String storedProcFullyQualifiedSql = null; 
  // stored proc parameters : the ProcParam class is simply an encapsulation of a stored proc parameter
  private ProcParam[] procParameters;
 
  // view attribute mapping to stored proc parameters
  // Key   : view attribute name
  // Value : stored procedure parameter name
  private Map<String,String> viewAttributeMapping;
 
  // Collection Map containing output parameter name value pairs as result collection for caching purposes
  private Collection<Map<String,Object>> resultCollection;
 
  public StoredProcOutputParametersVOImpl() {    
  }
 
  public StoredProcOutputParametersVOImpl(String storedProcFullyQualifiedSql) {
    this.storedProcFullyQualifiedSql = storedProcFullyQualifiedSql;   
  }
 
  private Collection<Map<String, Object>> executeStoredProcWithOutputParametersResult(String storedProcFullyQualifiedSql,
    ProcParam... parameters) {    
    return DbUtils.callProcReturningParametersResult(this.getDBTransaction(), storedProcFullyQualifiedSql,
             parameters);
  }
 
  /**
   * executeQueryForCollection - overridden for custom java data source support.
   */
  protected void executeQueryForCollection(Object qc, Object[] params, int noUserParams) {
    
    if (this.getProcParameters() == null) {
      throw new JboException("Stored Procedure Parameters need to be set. At least initialize and empty ProcParam Array!");
    }
    
    Collection<Map<String, Object>> outputParamResult =
      executeStoredProcWithOutputParametersResult(this.getStoredProcFullyQualifiedSql(),
        this.getProcParameters());   
    
    // cache result collection
    this.setResultCollection(outputParamResult);
    
    // Prime the pump with the first row.
    this.hasNextForCollection(qc);
    
    super.executeQueryForCollection(qc, params, noUserParams);
  }
 
  /**
   * hasNextForCollection - overridden for custom java data source support.
   */
  protected boolean hasNextForCollection(Object qc) {
    boolean hasNext = getResultCollection().iterator().hasNext();
    if(!hasNext) {
      setFetchCompleteForCollection(qc, true);
      return false;
    }
    return true;
  }
 
  /**
   * createRowFromResultSet - overridden for custom java data source support.
   */
  protected ViewRowImpl createRowFromResultSet(Object qc, ResultSet resultSet) {
    if (this.viewAttributeMapping == null || this.viewAttributeMapping.size() <= 0) {
      throw new JboException("All Output Parameters have to be mapped to corresponding view attributes on this View Object!");
    }    
    ViewRowImpl row = createNewRowForCollection(qc);
    
    // get output parameters data from result collection to populate row from
    Map<String, Object> outputParametersRow = getResultCollection().iterator().next();   
    
    // get reference to view attribute mapping (maps view attributes to proc params)    
    Set<String> viewAttrNames = this.viewAttributeMapping.keySet();
    int rowIndex = 0;
    for (String viewAttrName: viewAttrNames) {
      // set row/view attributes according to view attribute mapping.
      String procParamName = this.viewAttributeMapping.get(viewAttrName);     
      Object viewAttrValue = outputParametersRow.get(procParamName);
      this.populateAttributeForRow(row, rowIndex, viewAttrValue);
      rowIndex++;
    }
    
    // return populated row
    return row;
  }
 
  /**
   * getQueryHitCount - overridden for custom java data source support.
   */
  public long getQueryHitCount(ViewRowSetImpl viewRowSet) {
    return getResultCollection().size();
  }
 
  protected void create() {    
    getViewDef().setQuery(null);
    getViewDef().setSelectClause(null);
    setQuery(null);
  }
 
  public void setStoredProcFullyQualifiedSql(String storedProcFullyQualifiedSql) {
    this.storedProcFullyQualifiedSql = storedProcFullyQualifiedSql;
  }
 
  public String getStoredProcFullyQualifiedSql() {
    return storedProcFullyQualifiedSql;
  }
 
  public void setProcParameters(ProcParam[] procParameters) {
    this.procParameters = procParameters;
  }
 
  public ProcParam[] getProcParameters() {
    return procParameters;
  }
 
  public void setViewAttributeMapping(Map<String, String> viewAttributeMapping) {
    this.viewAttributeMapping = viewAttributeMapping;
  }
 
  public Map<String, String> getViewAttributeMapping() {
    return viewAttributeMapping;
  }
 
  public void setResultCollection(Collection<Map<String, Object>> resultCollection) {
    this.resultCollection = resultCollection;
  }
 
  public Collection<Map<String, Object>> getResultCollection() {
    return resultCollection;
  }
}
With the above code in place, one simply creates a programmatic View Object with its Java implementation extending the above class...providing the SQL to call the appropriate stored procedure as well as defining the view attribute - stored procedure parameter mapping.

And there you have a usable View Object calling a stored procedure and populating the attributes dynamically from the stored proc output parameters!

Thursday, 26 January 2012

I had to transform an Apache FOP file to PDF and got the following error running on Weblogic:
XML-22900: (Fatal Error) An internal error condition occurred.
<Servlet> <convertFO2PDF>
javax.xml.transform.TransformerException: XML-22900: (Fatal Error) An internal error condition occurred.
    at oracle.xml.jaxp.JXTransformer.reportException(JXTransformer.java:915)
    at oracle.xml.jaxp.JXTransformer.transform(JXTransformer.java:502)


The way to fix it is to explicitly make use of the Xalan XML Transformer Factory. Otherwise, the Oracle implementation gets used and hence the above error. Due to the fact that Apache FOP requires the Xalan Transformer Factory it fixes the problem.

This is how I did it:
TransformerFactory factory = new org.apache.xalan.processor.TransformerFactoryImpl();

All this resulted in :-)

Wednesday, 14 December 2011

ADF Task Flow Input Parameter Definition common pitfall

When you define an input parameter to your ADF Task Flow and you get the following error on calling/loading the Task Flow:
javax.el.PropertyNotWritableException: Illegal Syntax for Set Operation
Then, you've probably forgot to set the value of the Input Parameter to:
#{pageFlowScope.inputParameterName}
I don't know why but I keep on forgetting this, hence I've recorded it here now.