Monday, July 30, 2012

SOA 11g XML Literal Uninitialized Variable XPath Error

Often while using the XML literal option within a XPath expression builder the following XPath error is encountered at runtime;

<dataObject name="FaultMessage" detailId="55029" isBusinessIndicator="false">
<value> oracle.bpm.bpmn.engine.model.runtime.microinstructions.TrappableException: faultName: {{http://schemas.xmlsoap.org/ws/2003/03/business-process/}uninitializedVariable} messageType: {{http://schemas.oracle.com/bpel/extension}RuntimeFaultMessage} cause: {XPath expression failed to execute. An error occurs while processing the XPath expression; the expression is oraext:parseXML('<Employees><Employee><Name>John Doe</Name><Dept>AE</Dept></Employee><Employee><Name>Cathy Poe</Name><Dept>BES</Dept></Employee></Employees>'). The XPath expression failed to execute; the reason was: internal xpath error. Check the detailed root cause described in the exception message text and verify that the XPath query is correct. }

From the error message although it is clear that the XML literal that is assigned to the XML element is not initialized, the question is how to initialize the XML literal variable?

The following is how the expression builder XML literal assignment looks;



To overcome the initialization issue, we should ensure that the XML fragment/literal that is assigned conforms to the schema along with valid namespace. Namespace declaration is the key here. The XML literal is treated as a variable by the SOA processor and hence would expect the proper namespace for initialization.


Review the XSD (schema) of the target to which you are trying to assign this XML literal. The sample schema used in this example is shown below;


All elements in this 'employees' schema are referenced with the targetNamespace 'http://www.example.com/ns/Employees'. We have to qualify the XML literal elements with this namespace as shown in screenshot below;


This will ensure that the XML literal is successfully initialized and there should be no more 'Uninitialized Variable' errors at runtime.

One other thing which might be of interest with XML literal assignments is that the XML literal should always have a wrapper root element. For example if you have to assign values to the unbounded 'Employee' element as in our example, the XML literal should wrap/enclose all the 'Employee' elements with the 'Employees' root element. Otherwise there will be an error during parsing.

Tuesday, July 17, 2012

Refresh ADF table after a popup message/confirmation

In this blog post, I am demonstrating a way to refresh the contents of an ADF table after a certain action (any CRUD operation) especially when a confirmation popup or message has to be displayed.

Just creating an invokeAction on the binding to refresh the table works if there are no popups or message dialogs on button action. However, if you have a situation to refresh the table AND display the popup, you will just have to do an additional config. There could be other ways to solve this, but I found the following approach easy to work with.

The solution is to disable the 'cacheResults' property of the iterator to which the ADF table is bounded to and ensure that an "invokeAction" executable is created on the binding to refresh it (say prepareModel stage or renderModel stage for example). To do this,
  • Go to the page definition file and edit the source view
  • Find the iterator to which the ADF table is bounded with
  • Add the additional property cacheResults and set its value to false
<iterator Binds="AdminVO1" RangeSize="25" DataControl="AppModuleDataControl"
              id="AdminVO1Iterator" CacheResults="false"/>

Let us find out why this additional config is required? Why does the invokeAction which is set to re-execute on page render does not work when a popup/message is displayed?

By default, whenever an ADF table is created on a datacontrol it cache the results in memory in order to save on performance. Let us see what ADF documentation has to offer in this regard; (Highlighted portions that is of importance to this case)

When a data control modifies a collection, the data control must instantiate a new instance of the collection in order for the ADF Model layer to understand that it has been modified. In other words, although some action in the client may change the collection, that change will not be reflected in the UI unless a new instance of the collection is created. However, for performance reasons, accessor and method iterators cache their results set (by default, the cacheResults attribute on the iterator is set to true). This setting means that the iterator is refreshed and a new instance of the collection is created only when the page is first rendered. The iterator is not refreshed when the page is revisited, for example, if the page is refreshed using partial page rendering, or if the user navigates back to the page.

Since the popup/message dialog is displayed on action and the page refresh is interrupted midway, the refresh is not actually happening on just invokeAction and the table displays the cached results. However, if the iterator is set to not cache results, in a way we are forcing it to execute again for fetching the results when the page is rendered after the popup/message dialog display.

Thursday, July 12, 2012

ADF 11g WebService Data Control JBO-25080 and JBO-25058

I recently encountered a strange error while using a WebService Data Control on ADF. Since, I could not find any documentation or reference on this issue easily available on the web I thought of posting it here.

At runtime, the following error was logged in my console;

oracle.jbo.NoDefException: JBO-25080: Definition name: CancelRequest does not match the file in which it is loaded from: com.oracle.Requests.CancelRequest
at oracle.jbo.mom.DefinitionManager.loadLazyDefinitionObject(DefinitionManager.java:999)
at oracle.jbo.mom.DefinitionManager.loadParent(DefinitionManager.java:1228)
at oracle.jbo.mom.DefinitionManager.loadLazyDefinitionObject(DefinitionManager.java:933)
at oracle.jbo.mom.DefinitionManager.findDefinitionObject(DefinitionManager.java:482)
at oracle.jbo.mom.DefinitionManager.findDefinitionObjectDontCheckName(DefinitionManager.java:433)
at oracle.adf.model.bean.DCBeanDataControl.findStructureDef(DCBeanDataControl.java:1884)
at oracle.adf.model.bean.DCBeanDataControl.getAttributeDefs(DCBeanDataControl.java:1936)
...........................................................
...........................................................

Supplementing to the above error the following error was also logged;

oracle.security.jazn.JAZNRuntimeException: JBO-25058: Definition RequestId of type Attribute not found in RequestId

Even on repeated analysis (including the case sensitivity), everything seemed fine and the error message did not make sense.

After lots of googling around, I stumbled upon an Oracle forum where it noted a critical ADF bug.

"The package name CANNOT be the same as the class name". This will sound like a very ridiculous bug but that's the way it is at least for now (I am seeing this error in JDev 11.1.1.6). Since my class name and the package name were both 'CancelRequest', ADF data control went weird and complained with the JBO errors JBO-25080 & JBO-25058.

This can happen with EJB data controls as well!

I had to resolve the error the hard way. Had to go back and change my Web Service to reflect a different name (different name for the root node and operation). Operation name will be the package name and the parameter root element name will be thei class name when the WebService data control is generated.

Although you can do very little in a production scenario to handle this bug, you can probably take a different approach beforehand like using a WS Proxy or a POJO data control instead of a WebService data control if you see that the package name and class names are identical.

Tuesday, July 10, 2012

BAM-01273: Active Data Cache unique constraint violation

There can be multiple reasons for this error. I had a situation in my BPM process where the workflow can take two possible flows. One for the valid payload where the process is fully automated (no human intervention) and another for the incorrect data which goes through a manual user review.

BAM was enabled on this BPM process. The BAM DO got created 'as expected' and the incorrect flow involving the user intervention worked like a charm and was pushing the process data into the BAM DO. Surprise sprung up when 'happy path' was execute. I could see no data in the BAM DO.

On analyzing, the BAM diagnostic logs reported the following error;


Exception: oracle.bam.adc.common.exceptions.UniqueConstraintViolationException: BAM-01273: Active Data Cache unique constraint violation at oracle.bam.adc.dse.oracle.OracleExceptionHelpers.getStorageException(OracleExceptionHelpers.java:135)
  at oracle.bam.adc.dse.oracle.OracleStorageEngine.insertDataSetRow(OracleStorageEngine.java:1216)
……………………………………………
……………………………………………
Caused by: java.sql.SQLIntegrityConstraintViolationException: SQLError(1) SQLState(23000) ORA-00001: unique constraint (PS4_ORABAM.SYS_C0015167) violated
……………………………………………
at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)

This error is very deceptive. Because, we have different workflow paths behaving differently apparently under the same BPM process.

Then I found the solution trying to assess the process flows and dehydration points. Since the 'happy path' flow was completely automated, I think the BPM process never dehydrated and hence didn't pass on the DO updates into BAM (for whatever reasons). There is a simple solution to this; Open the activities where the BAM DO values are set/updated in the BPM process and force the 'Sampling'. This way we are forcing the BPM process to update the BAM DO with the sampled values. There can be other reasons why you may get the same error on which I have blogged about here


Oracle Open World 2012


 Oracle Open World fever is here!!
2012 Oracle Open World is going to be held in San Francisco this year from September 30 to October 4. As usual, there is going to be lots of excitement and fun. One of those would be the following BPM session which I will be co-presenting with Harish Gaur (Director, Product Management) and there is going to be a Hands-on lab as well on this.

If you would like to touch & feel Oracle BPM, please join us for the presentation. Session details below;


Session ID: CON9184
Session Title: Business-Driven Development with BPM: Lessons from the Real World

Looking forward to meeting you there!


Update 2:

Workshop information below;
 
Session ID: HOL10804
Session Title: Business-Driven Development: Oracle Business Process Management Workshop

Update 3: 12/Aug/2012

The session schedule is published and is as follows;



Session ID: CON9184
Session Title: Business-Driven Development with BPM: Lessons from the Real World
Venue / Room: Moscone South - 310
Date and Time: 01-Oct-2012, 13:45 - 14:45


Session ID: HOL10804
Session Title: Business-Driven Development: Oracle Business Process Management Workshop
Venue / Room: Marriott Marquis - Salon 1/2
Date and Time:  01-Oct-2012 , 10:45 - 11:45

Session ID: HOL10804
Session Title: Business-Driven Development: Oracle Business Process Management Workshop
Venue / Room: Marriott Marquis - Salon 1/2
Date and Time:  04-Oct-2012 , 14:15 - 15:15


Follow this page & look out for further updates.....

Final Update:

It was amazing to see the overwhelming response for the sessions. Thanks to all who could make it to the sessions that we delivered during the Open World and I sincerely hope that you had some key takeaways from them that you will capitalize on. Feel free to write back to me and I would be more than glad to assist you in every way possible. 

Saturday, July 7, 2012

ADF 11g "Cannot convert -2 of type class java.lang.String to class oracle.jbo.domain.DBSequence"

Have you ever encountered the above error? The reason for this could be manifold. Go through the following list and hopefully should resolve it if everything is 'as expected'.

1. Check whether you have any validators on the ADF component

2. Check for any 'Converters' that might run

3. Remove the mandatory, maximumLenght properties of the ADF component and check if this resolves the issue

4. Finally, go to the source view of the Entity Object attribute which is modified to DBSequence and check if the columnType, Type, SQLType properties are fine which could cause the casting error. A valid attribute can be as shown below;

<Attribute
    Name="RequestId"
    ColumnName="EQUEST_ID"
    SQLType="NUMERIC"
    Type="oracle.jbo.domain.DBSequence"
    ColumnType="NUMBER"
    TableName="REQUESTS"
    PrimaryKey="true"
    IsUpdateable="false"
    Domain="oracle.jbo.domain.DBSequence"
    RetrievedOnInsert="true">
    <DesignTime>
        <Attr Name="_DisplaySize" Value="39"/>
    </DesignTime>
</Attribute>
 
On a side note, more often than not, if the primary key is generated by a DBSequence using the trigger approach, it often shows a negative integer value in the element on the UI. Oncommit, the value gets replaced with the DB sequence. In many cases this might look ugly to show a negative number to the user. To overcome this, check for the "Default Value" property for the attribute in the entity object and remove it.
 
Usually, the DefaultValue property will have a value as "@0" which causes the VO to render a temporary negative integer value on the UI.

ADF DB Sequence - Using DB Trigger approach

In this post I am going to show another more sophisticated way to generate a unique number (generated by a database sequence) and display it on the ADF UI if needed. The advantage of this approach over the previous technique (using the View Object create() method) is that the DB sequence is not wasted - The sequence number gets generated only on commit.

Let us take an use-case and see how this can be achieved through a step-by-step illustration;

1. For this use-case assume the following database table; where REQUEST_ID is the primary key column for which we would insert value dynamically from a DB sequence through ADF
2. Now, create a Fusion Web Application (ADF) in JDeveloper - Provide a name for the ADF app and accept the defaults in the create wizard

3. Now, right click on the model project and choose 'New'. Choose the 'ADF Business Components' under the 'Business Tier' and select 'Business Components from Tables' option
 4. Choose the 'Requests' table as the entity object on the first screen and select the RequestsView entity as the 'Updatable View Object'. Accept defaults in the following screens to complete creation of the model layer business components

5. This will automatically create the data control for the Requests view object.

6. Let us now create a DB sequence which will provide values to be inserted into the REQUEST_ID column and a DB trigger on the REQUEST_ID column under the REQUESTS table. The idea of db trigger is to ensure that the sequence id gets generated whenever there is an insert request on the table. This way the sequence numbers are not lost even if the transaction is rolled back before commit.

If you are not familiar with DB sequence or DB trigger creation, don't worry. JDeveloper can help you to create these declaratively in no-time.

7. Go to the Database Navigator view -> Right click on the Sequences and create a sequence as shown below

8. Similarly, right click on the REQUESTS table and create a DB trigger as shown below. Enter the trigger name and choose the sequence name (created in step 7) and the column name (REQUEST_ID)
 
9. Now, go to the ADF model project -&gt; open the Requests entity object. Under the 'Attributes' section, edit the 'RequestId' attribute as shown below;

  • Change the type to DBSequence (oracle.jbo.domain.DBSequence) - If this is not showing up by default, you can browse & select this class
  • Updatable property - Never
  • Refrest After - Insert

10. Time to create the UI. Right click on the ViewController project and create a JSF page.

11. Let us now drag and drop the RequestsView1 data control from the 'Data Controls' panel on to the JSF page that we created as an ADF table component

12. Now, drag and drop the 'CreateInsert' operation on to the page as an ADF button

13. Similarly drag and drop the 'Commit' and 'Rollback' operations as ADF buttons as shown below



PS: Note that 'CreateInsert' operation is available under the 'RequestsView1' data control where as 'Commit' and 'Rollback' operations which are common across all VOs are available at the root level (AppModuleDataControl)

14. Now, let us run this page and observe the results. Click on the 'CreateInsert' button to create a new row. Enter values for RequestType and Description columns. Notice that the RequestId column is read only as modelled. This column will get a value once the commit button is hit. Behind the scenes, when commit button is pressed, a record is inserted into the REQUESTS table which will invoke the trigger to get a unique number from the DB sequence. After insert the ADF UI is refreshed partially to reflect the primary key value.

Hope this helps.

There are some tips & solutions here. Take a look.

Friday, July 6, 2012

Blogger not supporting Mozilla Firefox

Hi friends,

This morning when I logged in to my blogger account, I was shown the following message.

Your browser is no longer supported by Blogger. Some parts of Blogger will not work and you may experience problems.
If you are having problems, try Google Chrome. | Dismiss

This comes to me as a real surprise!

I am not trying to sell or evangelize Mozilla Firefox here. But fact remains that Firefox is the second most used/sought-after browser (if not first - considering the IT crowd) in the market. I would like to point out here that Firefox 3.0 had a record download on its first day of release - 8 Million downloads in 24 hours - also in Guinness book of world records and Firefox 4.0 hit a 7 Million mark in 24 hours.

If Google's sole intention is to market 'Chrome' by stopping support for other browsers then they are ridiculously wrong. Remember, there are many blogger solutions on the market - and one can always resort switching blogger account rather than install Google chrome to continue with 'Blogger'.

Feel free to post your comments on this post if you feel that Google should start supporting other browsers.
It is a Win-Win situation!