Showing posts with label ADF. Show all posts
Showing posts with label ADF. Show all posts

Wednesday, April 2, 2014

Creating Weblogic Store and Forward (SAF) for EDN

SAF is a very reliable mechanism when you have to move JMS messages between servers. In one of my recent projects, I had to send ADF business events from a weblogic server to my SOA domain on a different box. Because my EDN  subscriptions are on the SOA server, I had to create a pseudo EDNQueue on ADF weblogic server and move it over to the actual EDNQueue on the SOA server.

Moreover, because it is a pseudo queue on sending server, you could even have the JNDI of the queue different than the actual JNDI of the queue on remote server. This means, in my scenario, I could create a pseudo local JNDI for EDNQueue (JNDI: jms/fabric/EDNQueue); but have it forward to a regular JMS queue with a different JNDI (other than jms/fabric/EDNQueue) on the SOA server. This is a consideration if you want to get away from some of the inherent limitations of EDN subscriptions.

Here is how you do it.

Preparing ADF server for EDN:
This step is specific to ADF applications on non-SOA domains that want to use EDN. For steps to create an ordinary SAF, go to next section.

1. Copy the two directories oracle.soa.fabric_11.1.1 and oracle.soa.workflow_11.1.1 to the non-SOA server. We will be deploying these as shared libraries on the non-SOA servers. Make sure these folders are copied to the same location. These servers bring the EDN capabilities to a regular weblogic. These folders can be found under /oracle_soa_home/soa/modules of a SOA domain.

2. From non-SOA server console, go to deployments and deploy these shared libs by browsing and selecting oracle.soa.workflow_11.1.1/oracle.soa.workflow.wc.jar
3. Complete the steps and make sure the jars are showing up on the console.

Receiving SOA server:
Create the queue on the server to which JMS messages need to be forwarded. In my case, queue is TestEDNQ.

Sending ADF server:
This is where we will be creating the SAF mechanism to forward messages to TestEDQ on the receiving server.

1. Create a SAF agent from weblogic console of the server. Services>Messaging>Store-and-Forward Agents. Create new, give a name, and select an appropriate 'Agent Type'. I am leaving this as 'both'. Pick a value based on the purpose of this agent to either send, receive or both SAF messages.

2. Create a jms server and jms module they doen't exist. Services>Messaging>JMS Servers and Services>Messaging>JMS Modules.
3.  Create a sub deployment for the jms module and specify the target to a JMS server.
4. Create a SAF remote context. This is the connection to the remote receiving server. From within jms module, click new> select 'Remote SAF Context'> Specify a name, t3 URL to the remote server, user name and password. In the screenshot below, I am setting up my remote context to weblogic at localhost:7101

5. Create SAF imported destinations. This is a collection of queues and topics that can share the same SAF remote context. From within jms module, new>select 'SAF Imported Destinations', specify a name, select the remote SAF context that got created in previous step. Leave the default targeting and finish.

6. Created SAF remote context and imported destinations should look like this:


7. Create SAF queue. This is where we specify the remote queue and JNDI. In my case, I am trying to forward an EDNQueue to a regular JMS queue on the remote server. Hence, I have different values for local and remote JNDIs. However, if remote queue's JNDI is what you need on local server also, ignore the local JNDI value in this configuration. Click on the created SAF Imported Destinations > go to queues tab> 'New' and enter remote queue name and remote queue JNDI. Click OK.
8. Once created click on the created queue and add additional configuration. There is where I am overdiding remote JNDI with a different JNDI name locally on this server. My local JNDI is that of the EDNQueue and remote JNDI is that of the queue to which I want to forward my events (JMS messages).

9. Send a test JMS message to jms/fabric/EDNQueue and it will get forwarded to JMS/TESTEDNQ on the remote server. Important note here is that there is no local physical queue on the sender. All you do is, with the SAF configuration, you create a reference to a remote queue and SAF will store the message and forward it to the queue based on its availability.
10. Optionally, error handler can also be configured for SAF destinations.

Monday, October 21, 2013

Populating database values in human task payload

I had a recent requirement to populate database table values to BPM payload based on certain selections user makes in a human task UI. To add to the complication, there could be multiple rows that are associated with the user selection on UI and hence my BPM object had to be an array. Creating array objects and automatically populating them turned out quite tricky.

One way to solve this is by generating the payload as DOM and updating the BPM with java API.

A lesser complicated approach is to make use of ADF bindings. This article explains the steps.

1. Create the BPM project
2. Create the ADF Model for database
3. Generate the ADF UI for human task. This can be done using the auto-generate wizard.
4. Find the bindings for 'CreateInsert' button for the array object and the array UI table.
5. Comment out the source code for the button and table mentioned above.
6. From BPM data control, drag and drop the children of array object on to the jspx page.

7. This will create bindings the attributes of array object. We now have bindings for 'CreateInsert' button, the array itself and the array object attributes.
8. Comment out the array object attributes UI elements. We are only interested in the bindings. Not the source. You could always create bindings from the page definition file.
9. Construct the UI for database objects with action components. In my case, it was a select one choice drop down with a selectionListener.
10. From within the action listener in my backing bean (this could be a submit button as well), use an EL helper class to invoke 'CreateInsert' and then set array attributes with the database selected values. In between you could do any kind of operation, like calling another AM method to retrieve additional details.

11. In the back end we are creating the array object and populating it every time user makes a selection. In some scenarios you might want to delay this until user 'submit's the form. But either ways, the process of calling 'CreateInsert' setters will work.

For more complicated scenarios, working with human task API is the only option.


Sunday, September 29, 2013

Get that good looking ADF RichTable


Here are some suggestions to build a good looking ADF table.

1. Use a panelBox for the table. It makes the table stand out from the background.
2. Put a panelCollection inside the panelBox. This will provide some very neat out of the box features- like column selection, detach, column ordering, etc. Detach is very useful when displaying large number of columns under space constraint. It will let the table open up in a popup occupying the entire page width. PanelCollection will also open up a good toolbar area where actions can be added.
3. Use that toolbar facet inside panelCollection and add action components there.
4. Set 'AFStretchWidth' styleClass to panelCollection.
5. Add the table to the panelCollection and pick required columns.
6. Set a column or 'last'  for columnStretching property of the table
7. Set contentDelivery as immediate and autoHeightRows to an appropr1ate value. This setting will display the vertical scrollbar when required based on autoHeightRows value.
8. Set a width for all columns except for the column picked for columnStretching. eg: width="200px"
9. Set column width using the inlineStyle property of column. eg: inlineStyle="height:25px"

This should provide the basic framework for a nicely formatted ADF table. Work with other visual attributes like horizontalGridVisible, inlineStyle, etc. to make the table even better.

Code for the basic layout options mentioned above:


<af:panelbox id="pb1" text="My Company Contacts">
          <f:facet name="toolbar">
          <af:panelcollection id="pc1" styleclass="AFStretchWidth">
            <f:facet name="menus">
            <f:facet name="toolbar">
              <af:toolbar id="t4">
                <af:activecommandtoolbarbutton icon="/resources/edit.png" id="actb4" text="Edit Person">
                <af:activecommandtoolbarbutton icon="/resources/delete.png" id="actb5" text="Remove Person">
                <af:activecommandtoolbarbutton icon="/resources/add.png" id="actb6" text="Add Person">
              </af:activecommandtoolbarbutton></af:activecommandtoolbarbutton></af:activecommandtoolbarbutton></af:toolbar>
            </f:facet>
            <f:facet name="statusbar">
            <af:table autoheightrows="20" columnstretching="last" contentdelivery="immediate" emptytext="#{bindings.XXX.viewable ? 'No data to display.' : 'Access Denied.'}" fetchsize="#{bindings.XXX.rangeSize}" horizontalgridvisible="true" id="t3" partialtriggers=":::soc1" rowbandinginterval="1" rows="#{bindings.XXX.rangeSize}" rowselection="single" selectedrowkeys="#{bindings.XXX.collectionModel.selectedRow}" selectionlistener="#{bindings.XXX.collectionModel.makeCurrent}" value="#{bindings.XXX.collectionModel}" var="row" verticalgridvisible="false">
              <af:column headertext="#{bindings.XXX.hints.FirstName.label}" id="c5" inlinestyle="height:25px" sortable="true" sortproperty="FirstName" width="200px">
                <af:outputtext id="ot4" value="#{row.FirstName}">
              </af:outputtext></af:column>
</af:table></f:facet></f:facet></af:panelcollection></f:facet></af:panelbox>

End product:




Tuesday, December 13, 2011

ADF - Display timeline indicator on DVT graph

Here is how you do it. Use dvt:timeSelector and set explicitStart and explicitEnd to the same value on Y axis.
This is a good technique to display current position on a timeline chart.

In the example below, i am making use of a getNow method in my backing bean to get start and end values as the same date.

Code:


<dvt:lineGraph id="lineGraph1" value="#{bindings.MyDS.graphModel}" subType="LINE_VERT_ABS" emptyText="No data"
seriesRolloverBehavior="RB_HIGHLIGHT">
<dvt:background>
<dvt:specialEffects/>
</dvt:background>
<dvt:graphPlotArea/>
<dvt:seriesSet>
<dvt:series/>
</dvt:seriesSet>
<dvt:o1Axis/>
<dvt:y1Axis/>
<dvt:timeSelector explicitStart="#{myBean.now}" explicitEnd="#{myBean.now}" mode="EXPLICIT"/>
<dvt:legendArea automaticPlacement="AP_NEVER"/>
</dvt:lineGraph>


Result: