Monday, August 29, 2011

ADF : lazy checking if a row in a table is new programmatically/el


Lazy arb piece of code but hey well maybe it will help someone:

Put this in the component in your table you want to make non readonly when it is a new row:

readOnly="#{not yourBean.newRow}"


public boolean isNewRow() {
  ViewRowImpl row = (ViewRowImpl) JSFUtils.resolveExpression("#{row.row}");
  return row.getNewRowState() == Row.STATUS_INITIALIZED || row.getNewRowState() == Row.STATUS_NEW;
}

could also just use el : readOnly="#{not (row.row.newRowState < 1}"

Friday, August 26, 2011

ADF Taskflows with jspx : is referenced in a context where a page fragement is expected

If your page definition is underlined in red in your taskflow and you are using jspx files
Click the Use Page Fragments tick box on the Overview General tab of your task flow or remove this xml

Random blog stat : Top 10 countries

Maybe this says something about who uses adf and in which countries - and maybe not.

United States - by FAR 3 * the number of post hits than India
India
Germany
United Kingdom
Canada
Spain
Netherlands
Brazil
South Africa
Poland

Welcome Poland to my top 10.

 Top 20 Countries by GDP:

United States
People's Republic of China
Japan
Germany
France
United Kingdom
Brazil
Italy
Canada
India
Russia
Spain
Australia
Mexico
South Korea
Netherlands
Turkey
Indonesia
Switzerland
Poland


I think I may need to brush up on my japanese/ chinese and russian to get some more hits from the top 20 countries.

Hits per browser:
Firefox 43%
Internet Explorer 28%
Chrome 23%

Hits per os: (Linux version of jdev buggy perhaps?)
Windows 88%
Linux 4%
Macintosh 3%
Other Unix 2%

ADF : Ridiculous java.lang.ClassNotFoundException oracle.jbo.server.nullImpl

I added a EO that had a fk assoc to another entity I wasnt working with and suddenly (after a bit of refactoring) when I ran my app I kept getting: java.lang.ClassNotFoundException: oracle.jbo.server.nullImpl.


So I searched through my entities for nullImpl and found

<AccessorAttribute
    Name="AccountToDivisionFkAssoc"
    Association="AccountToDivisionFkAssoc"
    AssociationEnd="AccountToDivisionFkAssoc.sourceEnd"
    AssociationOtherEnd="AccountToDivisionFkAssoc.destEnd"
    Type="nullImpl"
    IsUpdateable="true"/>


I changed this back to oracle.jbo.server.EntityImpl and all was well
<AccessorAttribute
    Name="AccountToDivisionFkAssoc"
    Association="AccountToDivisionFkAssoc"
    AssociationEnd="AccountToDivisionFkAssoc.sourceEnd"
    AssociationOtherEnd="AccountToDivisionFkAssoc.destEnd"
    Type="oracle.jbo.server.EntityImpl"
    IsUpdateable="true"/>

Thursday, August 25, 2011

Savepoint

SAVEPOINT MySavePoint;
 //do some sql stuff
ROLLBACK TO MySavePoint;

Monday, August 22, 2011

ADF service based lov and query

I want to have a LOV/ query backed by a webservice in adf.

Looks like I am going to have to implement some code for this ()

XCode - Bound to a returned service value for now.


<af:inputListOfValues id="XCode"
  popupTitle="Search and Select: #{bindings.XCode.hints.label}"
  value="#{bindings.XCode.inputValue}" label="#{bindings.XCode.hints.label}"
  model="#{viewScope.backingBean.listOfValuesDataModel}"
  required="#{bindings.XCode.hints.mandatory}"
  shortDesc="#{bindings.XCode.hints.tooltip}" styleClass="colspec_fshort"/>


Map your service and execute. In the listOfValuesDataModel method.
      Object ob = ADFUtils.executeOperationBinding("findCodeTypesVO", new HashMap());

Map that to a custom implementation of oracle.adf.view.rich.model.ListOfValuesModel and return it.
There is a nice example of how to do this in the ADF demo application code. oracle.adfdemo.view.lov.DemoLOVBean


http://download.oracle.com/otn/java/jdeveloper/111/extensions/adf-richclient-demo.war

Will post more once I have implemented some more.


Wednesday, August 17, 2011

ADF Error handling new lessons

1) When using a custom error handler (in DataBindings.cpx ErrorHandlerClass="blah") in a main project that contains in a shared libs the main projects error handler will be used not the shared libs. So it is best not to override the error handler in the main project.

2) ErrorHandler for unexpected errors:
http://blogs.oracle.com/jdevotnharvest/entry/extending_the_adf_controller_exception_handler

3) action-listener in faces-config.xml can be overriden.
http://www.techbrainwave.com/?p=3

4) JSF 2 error handler:
http://jugojava.blogspot.com/2010/09/jsf-2-exception-handling.html

Monday, August 15, 2011

ADF Custom declarative component error 11.1.2

OK so I though the components where broken in 11.1.2 but it turns out it was just me who was broken.

Here a a couple of things I struggled with:

Naming yes I got the name of my custom component in declarativecomp-metadata.xml component file I had an extra l in my taglib-name. (if you get a blank page like me check the spelling then check it again)

I also put the folloing in my consuming project - dont know if it is necessary but it made me feel good:


<context-param>
  <param-name>javax.faces.FACELETS_VIEW_MAPPINGS
  <param-value>*.jsf;*.xhtml
<context-param>
<context-param>
  <param-name>javax.faces.FACELETS_SKIP_XML_INSTRUCTIONS
  <param-value>true
<context-param>
<context-param>
  <param-name>javax.faces.FACELETS_SKIP_COMMENTS
  <param-value>true
<context-param>
<context-param>
  <param-name>javax.faces.FACELETS_DECORATORS
  <param-value>oracle.adfinternal.view.faces.facelets.rich.AdfTagDecorator
<context-param>
<context-param>
  <param-name>javax.faces.FACELETS_RESOURCE_RESOLVER
  <param-value>oracle.adfinternal.view.faces.facelets.rich.AdfFaceletsResourceResolver
<context-param>


Also small tip for those who live in history the tab lib is Faclets Tag Libraries not JSP Tag Libraries this may save you a few seconds.


This article helped me a LOT:
http://download.oracle.com/docs/cd/E18941_01/tutorials/jdtut_11r2_40/jdtut_11r2_40.html

Friday, August 12, 2011

ADF Mapping a service based Select One choice

1) Select the field you would like and drag it onto the jspx.

2) Select Single Selection then ADF select one choice
3) Click the add button next to List Data Source
4) Find you web service data control and expand it.
5) Find your "find" service method ie. findGenderLOV --> Return --> result (the one with the white icon not the red)
6) Press ok , Press ok

Follow these simple steps and everything should work in a serviceable manner.



Thursday, August 11, 2011

ADF Making the results of a service backed find editable

Get the current row or the row you want editable and run it through this method:


import oracle.jbo.server.ViewAttributeDefImpl;   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.setUpdateableFlag(ViewAttributeDefImpl.UPDATEABLE);     }   }

Monday, August 8, 2011

ADF Webservice data control HACK: DONT TRY THIS AT HOME

I really wanted to be able to do things with my ADF service implementation based web service data control:

1) Change configuration of the wsdl location dynamically for each environment.
2) Make sure that I could add to the results of the web service with ADF. (createNewRow)

The first point: This is hard to do because the url is looked up from the bindings and wsdl. You could do this at build time and build an artifact for each environment but I didnt want to.

The second point: The result created by the ws data control was an XMLHandler$DataCollection wich did not implement the add method - I got a Not supported exception.

So here is the solution very ugly but hey well (this is a work in progress so shout if you want more code/ explanation):

1) Override the SOAPProvider in the DataControls.dcx

<DataControlConfigs xmlns="http://xmlns.oracle.com/adfm/configuration"
  version="11.1.2.60.17" id="DataControls"
  Package="za.co.transcode.adf.prj.model">
  <AdapterDataControl id="YourModelService" 
    FactoryClass="oracle.adf.model.adapter.DataControlFactoryImpl"
    ImplDef="oracle.adfinternal.model.adapter.webservice.WSDefinition"
    SupportsTransactions="false"
    SupportsSortCollection="true" SupportsResetState="true"
    SupportsRangesize="true"
    SupportsFindMode="true" SupportsUpdates="true"
    Definition="za.co.transcode.adf.prj.model.YourModelService"
    BeanClass="za.co.transcode.adf.prj.model.YourModelService"
    xmlns="http://xmlns.oracle.com/adfm/datacontrol">
    <Source>
      <definition xmlns="http://xmlns.oracle.com/adfm/adapter/webservice" 
      name="YourModelService" version="1.0"
      provider="za.co.transcode.adf.prj.model.YourSOAPProvider"
      wsdl="http://127.0.0.1:7101/Your-Model-context-root/YourAppModuleService?WSDL"
      UsePersistedStructure="false"> 



2) Implement your own SOAP Provider link this one.


package za.co.transcode.adf.prj.model;

import java.net.URL;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import oracle.adf.model.adapter.AdapterException;
import oracle.adf.model.connection.webservice.api.WebServiceConnection;
import oracle.adf.model.connection.webservice.impl.WebServiceConnectionImpl;

import oracle.adfinternal.model.adapter.webservice.WSOperation;
import oracle.adfinternal.model.adapter.webservice.provider.WSProvider;
import oracle.adfinternal.model.adapter.webservice.provider.soap.SOAPProvider;
import oracle.adfinternal.model.adapter.webservice.resource.WSDCResource;
import oracle.adfinternal.model.adapter.webservice.resource.WSDCResourceBundle;

import oracle.j2ee.ws.model.soap.SoapPortImpl;

import oracle.webservices.model.Operation;
import oracle.webservices.model.Port;
import oracle.webservices.model.soap.SoapPort;


public class YourSOAPProvider extends SOAPProvider {
  Map mOperations;

  public YourSOAPProvider() {

    super();
  }

  public void init(Map map) {

    super.init(map);
    mOperations = (Map) map.get(WSProvider.PROVIDER_OPERATIONS);
    WebServiceConnection conn = (WebServiceConnection) map.get(WSProvider.PROVIDER_CONNECTION);
    try {
//@TODO look this up from an external propeties file
      ((WebServiceConnectionImpl) conn).setWsdlUrl(
new URL(
"http://10.10.10.10:7001/Your-Model-context-root/YourAppModuleService?WSDL"));
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
  private WSOperation findServiceOperation(String operationName) throws AdapterException {
    Iterator portIterator = mOperations.keySet().iterator();
    while(portIterator.hasNext()) {
      String portName = (String) portIterator.next();
      List operations = (List) mOperations.get(portName);
      Iterator operationIter = operations.iterator();
      while(operationIter.hasNext()) {
        WSOperation operation = (WSOperation) operationIter.next();
        if(operation.getName().equalsIgnoreCase(operationName))
          return operation;
      }
    }

    // Fatal Error if the operation to invoke could not be found
    throw new AdapterException(WSDCResourceBundle.class, WSDCResource.ERR_NOSUCH_OPERATION,
        new Object[] { operationName });
  }

  public void setUrl(Port port, String url) {
    SoapPort soap = getSoapExt(port);
    if(soap == null) {
      soap = new SoapPortImpl();
      port.addExtension(SoapPort.EXTENSION_TYPE, soap);
    }
    soap.setAddressUrl(url);
  }

  protected static SoapPort getSoapExt(Port port) {
    return (SoapPort) port.getExtension(SoapPort.EXTENSION_TYPE);
  }

  public Object execute(String string, Map map) throws AdapterException {
    Operation oper = findServiceOperation(string).getOperation();
//@TODO look this up from an external propeties file
    setUrl(oper.getPort(), "http://10.10.10.10:7001/Your-Model-context-root/YourAppModuleService");
    Object resp = super.execute(string, map);
    if(resp != null && resp instanceof Collection && ((Collection) resp).size() > 0) {
      Object resp1 = (Object) ((Collection) resp).iterator().next();
      if(resp1 != null && resp1 instanceof Map && ((Map) resp1).size() > 0) {
        Object key = ((Map) resp1).keySet().iterator().next();
        Object resp2 = ((Map) resp1).get(key);
        if(resp2 != null && resp2 instanceof Collection && ((Collection) resp2).size() > 0) {
          Collection replacedCollection = replaceCollection((Collection) resp2);
          ((Map) resp1).put(key, replacedCollection);
          Object resp3 = ((Collection) resp2).iterator().next();
        }
      }
    }
    return resp;
  }

  private Collection replaceCollection(Collection objects) {
    return new ArrayList(objects);
  }
}



NB: remember we may have to do this all again when a new release happens so it is better to follow the tried and tested solutions to these problems.

1) http://forums.oracle.com/forums/thread.jspa?messageID=9393754&tstart=0
2) Use two iterators (based on create for the form and the findresults for the other) instead of writing to the results. Or create two screens a search and a create screen.

Friday, August 5, 2011

ADF converter add : page hanging

If your page is hanging or not displayed after you have added a custom converter check if you have defined the class name correctly in your faces-config file.

An incorrect classname is one cause of this behaviour.

Tuesday, August 2, 2011

ADF : Refreshing a service backed table and keeping the correct item highlighted

Make sure your table has  displayRow="selected" set.

<af:table value="#{bindings.CustomerVO.collectionModel}" var="row"
  rows="#{bindings.CustomerVO.rangeSize}"
  emptyText="#{bindings.CustomerVO.viewable ? 'No data to display.' : 'Access Denied.'}"
  fetchSize="#{bindings.CustomerVO.rangeSize}" rowBandingInterval="0"
  selectedRowKeys="#{bindings.CustomerVO.collectionModel.selectedRow}"
  rowSelection="single" id="table" columnStretching="last" immediate="true"
  displayRow="selected" binding="#{viewScope.customerTypesBean.table}"
  selectionListener="#{viewScope.customerBean.handleTableRowSelection}">

Invoke the following code when your table needs a refresh

//use the name of your tables result iterator here
    DCIteratorBinding iterator = BackingBeanUtils.getIteratorBinding(getResultsIteratorName());
    int rangeIdx = iterator.getCurrentRowIndexInRange();
    int rangePos = iterator.getRangeStart();
    int actualPos = rangeIdx + rangePos;
    String action = "findCustomerVO";
//execute the service here
    ADFUtils.executeOperationBinding(action, new HashMap());
    int rem = actualPos % iterator.getViewObject().getRangeSize();
    int page =
      (int) Math.floor(actualPos / iterator.getViewObject().getRangeSize());
    iterator.getViewObject().setRangeStart(page * iterator.getViewObject().getRangeSize());
    iterator.getViewObject().setCurrentRowAtRangeIndex(rem);

Faith based development

We cam up with yet another development term while converting our existing adf page to work off web services.

So if you use any of the following statements you know you are engaged in "faith" based development,
  • Have faith in the framework it will work.
  • It all happens automagically.
  • Trust the tool.
  • Just click a button and it works.
  • They will fix it in the next release.
  • I have no control over how that works.
  • The MDS will take care of that.
  • I have seen a blog post about that.
 
Very uncomfortable but apt.