Saturday 9 June 2012

View Object Bind Parameter pitfall

Well one get to a point in ADF development when it has been a long time since you've referenced the ADF Documentation and so I got to this pitfall with regards to Bind Parameters on View Objects. In my specific scenario I wanted to use Bind Parameters with wildcard values such as nulls amongst others. Hence, I discovered out of my ignorance that Bind Parameters get excluded when they have null values, unless they are marked as required parameters. After hours of debugging and struggle to get things working, everything started working suddenly after making all bind parameters required.

One of my colleagues also discovered another rule (as documented) with regards to view objects and bind parameters, but I'll provide those hints at another time...

Here it is:
Bind parameters marked as required can only be used in your main VO query. Those not marked as required can only be used in your View Criteria.
Thanks to Anilin Reddy!!

Monday 16 April 2012

Oracle ADF : How to change an attribute value of the read-only iterator's current row

// change attribute value of current row in iterator
DCIteratorBinding iterBind = ADFUtils.findIterator("MyVOIterator");
Row currRow = iterBind.getCurrentRow();
BackingBeanUtils.setRowEditable(currRow);
currRow.setAttribute("MyAttribute", "MY_VALUE");

// commit transaction
iterBind.getDataControl().commitTransaction();


...and for reference purposes, the setRowEditable(Row) utility method:
public static void setRowEditable(Row row) {
    int attribCount = row.getAttributeCount();
    for(int i = 0; i < attribCount; i++) {
      ViewAttributeDefImpl attrDef = (ViewAttributeDefImpl)
              row.getStructureDef().getAttributeDef(i);
      attrDef.setEditable(true);
      attrDef.setSDOHidden(false);
      attrDef.setUpdateableFlag(ViewAttributeDefImpl.UPDATEABLE);
    } 
}

Tuesday 27 March 2012

Oracle Forms / OraFormsFaces and Automated Testing

Automated testing tools rely on some key software attributes to enable the automatic testing of functionality in software. One of these attributes I recently had to deal with was field or object names for elements which reside in a web page / html page. Well, to be more specific, by default Oracle Forms return numbered record identifiers to the Forms Applet rendering the forms. By setting the record property to the value of "names" it will behave differently by returning the names by which the records are identified.
So, it is as simple as adding a request parameter to the Forms Servlet URL like below:
http://host:9001/forms/frmservlet?config=MyConfig&record=names
Then I would like to conclude in saying I was happy to discover that the OraFormsFaces framework does in fact pass on all request parameters to the Forms Server. Hence, if you append the same record parameter to the OraFormsFaces Forms URL (the one returning the JavaScript Functions) then it eventually sets the record parameter on the Forms Request and subsequently the record names are evident in the final response!!

Wednesday 14 March 2012

Oracle ADF Query Component : Executing custom code before or after process query

This is more a kind of note to myself. I had to execute custom code specifically after the query component finished querying and returning its results; i.o.w. after the search button was clicked on the ADF query component and subsequently after the processQuery-method was execute. I did it as follow:

  • I added the following method to my backing bean
   public void processQuery(QueryEvent queryEvent) {   
      
// over here you can put your PRE-processQuery custom code.      

       // call the usual method as part of default query processing.
       JSFUtils.resolveMethodExpression("#     {bindings.DefaultMyVOCriteriaQuery.processQuery}",
      null, new Class[]{QueryEvent.class}, new Object[] {queryEvent});   
      

       // over here you can put your POST-processQuery custom code.      
    }

  • I changed the queryListener attribute's value, of my query component to have the value of (referencing backing bean):
 queryListener="#{viewScope.myBackingBean.processQuery}

Wednesday 15 February 2012

Native OS ping implemented in Java

I've recently had to implement this very handy code to do an operating system dependent native ping. You'll notice I've created an OSType Enumerator type to represent the OS in question. Also, I've implemented two classes to represent the host to be "ping-ed" as well as the ping result. See below...


   private Process constructWindowsOSProcess(Runtime rt, PingHost host)
                throws IOException {
        return rt.exec("ping -n 1 -w "+ host.getTimeout() +" "+host.getNameOrIP());
    }
   
    private Process constructLinuxOSProcess(Runtime rt, PingHost host)

                throws IOException {
        return rt.exec("ping -c 1 -W "+ (host.getTimeout()/1000) +" "+host.getNameOrIP());
    }
   
    private Process constructOSSpecificProcess(Runtime rt, OSType osType,

             PingHost host) throws IOException {
        if (OSType.WINDOWS == osType) {
            return constructWindowsOSProcess(rt, host);
        } else if (OSType.LINUX == osType) {
            return constructLinuxOSProcess(rt, host);
        }
        return constructWindowsOSProcess(rt, host);
    }


    private boolean isReachable(OSType osType, String pingResult) {
        if ((OSType.WINDOWS == osType) && (-1 < pingResult.indexOf(":Reply"))) {
            return true;
        } else if ((OSType.LINUX == osType) && (-1 < pingResult.indexOf("64 bytes from"))) {
            return true;
        }
        return false;
    } 


   /**
     * Pings a host natively with the specified milliseconds(contained in PingHost)

     * as time-out for the ping.
     * @param rt Java Runtime to use in this method
     * @param osType the OS type this code is executing on or should be based on

                              (enum class type)
     * @param host encapsulation of a pingable host and all its attributes.
     * @return PingResult indicating whether the host is reachable or not.
     */
    private PingResult doNativeOSPing(Runtime rt, OSType osType, PingHost host) {
        StringBuffer pingResult = new StringBuffer("");
        try {                       
            Process p = this.constructOSSpecificProcess(rt, osType, host);           
            BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                pingResult.append(inputLine);
            }
            in.close();
           
        } catch (IOException e) {           
            e.printStackTrace();
        }
        return new PingResult(host, this.isReachable(osType, pingResult.toString()));
    }

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 :-)