Tuesday, September 27, 2011

ADF Faces NamingContainer Components

Here is a list of ADF Faces components that implements the NamingContainer interface.


af:calendar
af:carousel
af:declarativeComponent
af:navigationPane
af:panelCollection
af:query
af:quickQuery
af:region
af:pageTemplate
af:subform
af:table
af:train
af:treeTable
af:tree
dvt:hierarchyViewer
dvt:map
dvt:pivotTable
dvt:projectGantt 



Thursday, June 16, 2011

ADF Managed Bean Memory Scope and its Configuration Files

From time to time, I see lots of people messed up with managed bean memory scopes as the application complexity increases. Those errors you would see are types of Null Pointer Exception or the bean/its attribute/method cannot be found. Most of the time the reason behind it is its managed bean memory scope is not set up properly.

JSF web application itself has 4 types of scopes: application, session, request and none; ADF technology has brought 3 additional types of scopes: page flow, view and backing bean. The most common ones being used across an ADF fusion application are request, page flow, view and backing bean. Though placing a managed bean into a bigger scope than it should be will still work for your application most of the time but will bring cost on the overhead, placing the bean the other around will definitely stop your application from working properly.

If you are working on the ADF fusion application, the developer's guide should the first resource to refer. The following table list 3 locations of registering your managed bean and their rules of thumb:


Table 20-1 Effects of Managed Bean Configuration Placement
Managed Bean PlacementEffect
adfc-config.xml
  • Managed bean can be of any scope. However, any backing beans for page fragments or declarative components should useBackingBean scope. For more information regarding scope, see Section 21.3, "Object Scope Lifecycles."
  • When executing within an unbounded task flow, faces-config.xml will be checked for managed bean definitions before theadfc-config.xml file.
  • Lookup precedence is enforced per scope. Request-scoped managed beans take precedence over session-scoped managed beans. Therefore, a request-scoped managed bean named foo in the adfc-config.xml file will take precedence over a session-scoped managed bean named foo in the current task flow definition file.
  • Already instantiated beans take precedence over new instances being instantiated. Therefore, an existing session-scoped managed bean named foo will always take precedence over a request-scoped bean named foo defined in the current task flow definition file.
Task flow definition file
  • Managed bean can be of any scope. However, managed beans of request scope, of pageFlow scope, of view scope, or with the scope set to none that are to be accessed within the task flow definition must be defined within the task flow definition file. Any backing beans for page fragments in a task flow should use BackingBean scope.
  • Managed bean definitions within task flow definition files will be visible only to activities executing within the same task flow.
  • When executing within a bounded task flow, faces-config.xml will be checked for managed bean definitions before the currently executing task flow definition. If no match is found in either location, adfc-config.xml and other bootstrap configuration files will be consulted. However, this lookup in other adfc-config.xml and bootstrap configuration files will only occur for session- or application-scoped managed beans.
  • Lookup precedence is enforced per scope. Request-scoped managed beans take precedence over session-scoped managed beans. Therefore, a request-scoped managed bean named foo in the adfc-config.xml file will take precedence over a session-scoped managed bean named foo in the current task flow definition file.
  • Already instantiated beans take precedence over new instances being instantiated. Therefore, an existing session-scoped managed bean named foo will always take precedence over a request-scoped bean named foo registered in the current task flow definition file.
  • Customizations are allowed.
faces-config.xml
  • Managed beans can be of any scope other than pageFlow scope or view scope.
  • When searching for any managed bean, the faces-config.xml file is always consulted first. Other configuration files will be searched only if a match is not found. Therefore, beans registered in the faces-config.xml file will always win any naming conflict resolution.
  • No customizations can be made.



Additionally, the guide says:

As a general rule for Fusion web applications, a bean that may be used in more than one page or task flow, or one that is used by pages within the main unbounded task flow (adfc-config), should be registered in the adfc-config.xml configuration file. A managed bean that will be used only by a specific task flow should be registered in that task flow's definition file. There should be no beans registered in the faces-config.xml file.

The most common mistakenly setup of managed bean scopes in an ADF fusion application are:


  • A bean is used in more than one page or task flow and registered in one of the task flow definition files
  • A bean for page fragment in a task flow is not put into the backing bean scope.
  • Put a common accessible bean into faces-config.xml
  • Put a bean in adfc-config.xml and choose the scope as "PageFlowScope"
  • Put a bean in a bigger scope than it should.

Wednesday, June 1, 2011

Invoke actions on non-command component

It's a small demo on how to perform additional actions on click a goLink component which doesn't support any action logics inherently. The solution is to use javascript to invoke a command component programatically. But why do I need to perform some action on a golink click, why don't I use commandLink directly? Well, the reasons can be many, one of the valid reason is if you have such requirement like: on click of a link, open a predefined URL in a new window and also perform some action. I know there must be other similar scenarios which could be categoried into the same group like this one.

The implementation is fairly easy. Here is the code snippet:



The command link is hidden and aligned after goLink in page source. The additional action logics is defined in the action listener of the command link. 

Here is the demo to download. (JDeveloper 11.1.1.5 and need HR schema objects to run)

Friday, March 4, 2011

Using Popup to Confront user to Save/Forget Changes

This is an example topic followed by the previous post. Here I am presenting an example that using a popup to confront the user to save or forget the pending changes when navigate to different frame.

The example can be download from here. The example is based on Andrejus Baranovskis's example on how to detect pending changes using dynamic regions. What Andrejus did for pending changes is to throw an Warning message, but I came up with a scenario that to confront the user with popup and let use to choose either stay on the page or go ahead forget the change for the next frame.

1. How the pending changes are detected through ADF controller layer.











2. How to navigate to a different frame in dynamic region. If there are pending changes, the popup will be thrown to the user.












3. How to handle the logics if the user choose to forget the pending changes and navigate away.

















4. Main.jspx page structure:



Here are the UI of this example:

1. Make some changes on the location flow.
















2. Navigate to a different frame - Department Flow.


3. A warning pop up has been thrown.












4. User choose to forget the changes and successfully navigate to department flow.






















5. Go back to the location flow and pending changes have been wiped out.


Task Flow Pending Changes

Task flow as a functional unit provides great flexibility and offers developers lots of ways to get a hand on its state, transaction and management. Common requirements exist like web application needs to prompt to the user asking for save/cancel pending changes before navigating to a different frame.


In ADF, pending changes can be caught at the modal layer by calling getTransaction().isDirty() in ApplicationModuleImpl. That's common for developer to come up with at the first moment. Here I present how it's easily handled by using task flow in terms of pending changes detection.


ADF task flow, as main player in the ADF controller layer, provides several context interface to manage its state and transaction. In our case today, the context interface class is ControllerContext class.


The ControllerContext class provides per-request information about the controller state for a web application. 


To get hold of the ControllerContext in your managed bean:


ControllerContext cctx = ControllerContext.getInstance();


To detect the pending changes, there is a method "isDirty()" available in ViewPortContext or TaskFlowContext just like the one in DBTransactionImpl class. The difference as well as the advantage is the method exist in the viewController layer and no need to get hold the DataBinding and subsequent Application Module of the modal layer.


cctx.getCurrentViewPort().getTaskFlowContext().isDataDirty();
or
cctx.getCurrentViewPort().isDataDirty();


ViewPortContext.isDataDirty() 
          Returns true if this view port, or any of its children view ports, has a current task flow with uncommitted ADF model data.



TaskFlowContext.isDataDirty()
          Returns true if task flow contains any uncommitted ADF model data.

Thursday, March 3, 2011

Does your task flow need a transaction?

Task flow is a great feature in ADF and serve as a milestone for ADF 11g. The best documentation for ADF matters is to dig into the fusion developer's guide. The particular matter for task flow is here (11.1.1.3).


In ADF task flow, there is a concept - "transaction". It is a persisted collection of work that can be committed or rolled back as a group. Task flow present itself as a perfect group for such transaction. Transaction applies when one task flow is interacting with another. For example, there are two task flows here, one is parent task flow (flow P) and the other is child task flow (flow C). When P calls C, there are several transaction options for C. The options specify whether C will join P's existing transaction, create its own transaction or only create its own transaction if no existing transaction in P. Of course, C could also not have a transaction at all, which is the default option.


Steve Muench stated the following in his article: If your bounded task flow modifies data or wants to control when to commit or roll back data modified by anycalled task flows, it will require a transaction. You indicate this by setting the task flow’s transaction property torequires-transaction . At runtime, when Oracle ADF starts a bounded task flow that requires a transaction, one of two things occurs. If no transaction is currently active, Oracle ADF will begin a new transaction and remember the task flow that was responsible for starting the transaction. In contrast, if a current transaction is already open, the new task flow will participate in that existing transaction. Given this rule of thumb, any task flow you build that requires a transaction will either coordinate one or be coordinated by a calling task flow’s transaction, depending on how the task flow is used. Sometimes a task flow requires a transaction but also requires parameters from a calling task flow in order to work properly. In such a case, set the task flow’stransaction property to requires- existing-transaction instead. This says a task flow can participate in an existing transaction but not start a new transaction itself. To indicate that a task flow should never be used as part of an existing transaction, set its transaction property to new-transaction .


Besides the transaction options, there are two more parameters in the context: whether share the data control with the calling task flow and whether set the save point on the task flow entry. I will talk about the two one by one.


Let's look at the whether set the save point on the task flow entry, which is pretty straightforward. ADF save point is a saved snapshot of the ADF model state. It will automatically created if the task flow is called based on a existing transaction. Upon the return of the called task flow, there is an option "return save point" to set to true to roll back to the implicitly save point created by ADF. The default value is set the save point at the task flow entry. This parameter is not available the transaction option is set to "always start a new transaction" which literally tells since the a new transaction will be created upon task flow entry, there is no effect to the previous transaction at all, so the save point is no need here.


Whether share the data control with the calling task flow is an important parameter to note. I will demonstrate it using an example. Say we have 3 task flows, A calls B, and B calls C. A and B have the same data control frame (save Application Module), and C has a different data control frame. If the share data control parameter is set to true, which is the default. What happens is a data control instance created upon A flow enters. When B called from A, it will detect it's the same data control and will refer to the same instance as A does. When C called from B, even though it's not the same data control, ADF will nest the C's data control instance under A and B's data control instance. It's like the nested application module. The advantage is share the data control across the task flows will use the same DB connection.

Saturday, December 25, 2010

JRockit Mission Control Console Cannot be Started

Today I had an issue that the JRockit mission control cannot be started. The problem is when trying to start mission control from windows programs, the mission control splash flashed and disappeared right away. Something is blocking the process to be started properly.

The key to this issue is to start JRockit mission control using debug command-line. From windows:

%JROCKIT_HOME%\bin\jrmc -consoleLog 2>1& | more

Here was the output I got:

Dec 25, 2010 11:07:57 PM com.jrockit.mc.rjmx.internal.RJMX initializeSettings
INFO: Reading console settings from C:\Documents and Settings\jzheng\.jrmc\4.0.1\rjmx.4.0.1.xml
Dec 25, 2010 11:07:58 PM com.jrockit.mc.rjmx.core.connections.internal.ConnectionDescriptorRepository diffAgainstConsoleModel
WARNING: Found discrepancy in Browser View - could not find 10.0.0.4:4711 in view. Removing it from the model...
!SESSION 2010-12-25 23:07:56.656
eclipse.buildId=unknown
java.version=1.6.0_20
java.vendor=Oracle Corporation
BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en_US
Command-line arguments: -consoleLog

!ENTRY org.eclipse.osgi 4 0 2010-12-25 23:07:58.188
!MESSAGE An error occurred while automatically activating bundle com.jrockit.mc.rjmx.core (79).
!STACK 0
org.osgi.framework.BundleException: Exception in com.jrockit.mc.rjmx.core.RJMXPlugin.start() of bundle com.jrockit.mc.rjmx.core.
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:806)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:755)
-- More --
By checking the debug info, I can see that the console setting config xml file -- "C:\Documents and Settings\jzheng\.jrmc\4.0.1\rjmx.4.0.1.xml" is the trouble spot. After I deleted the file, the console was able to be started properly.

Friday, December 24, 2010

How to Enable JRockit Remote Management

To enable a JRockit JVM for remote management, the external management agent must be started.

There are two ways to start the management agent:

1. Start the JVM with the -Xmanagement command-line.

JROCKIT_HOME/bin/java -Xmanagement:ssl=false,authenticate=false,port=4711

2. use JRCMD when the JVM is already started.

use JRCMD to find the PID of the JVM (4620 for example)

JROCKIT_HOME/bin/jrcmd 4620 start_management_server ssl=false authenticate=false port=4711 autodiscovery=true

The command line will not produce any output if everything goes well.

Friday, December 10, 2010

Page Navigation using JavaScript in ADF Faces

Recently I posted a question on the Oracle ADF forum asking if there is Javascript API for page navigations in ADF faces and the simple answer is NO.

My Original Post:

I have a UI user case that has a af:menu which contains mutiple af:goMenuItem. When user click on the menu, the menu slides down and shows up the af:goMenuItem. As we know, you could define the page destinations in af:goMenuItem to go to another page when user clicked, but af:menu itself cannot be redirected to another page. Well, the user case wants the menu itself could be redirected if user click on it. 

So I am thinking using JavaScript to do this: when the af:menu gets clicked, redirect to another page. BUT, I looked over the ADF Faces Javascript API and was not able to find that piece of code to do this. Any help???


Frank's Response:

1 - you can have a hidden command item to do the navigation based on a control flow case. In this case, you access the command component from JavaScript create a new ActionEvent and queue it
2 - JavaScript can use an af:serverListener to call into a server side managed bean method to perform the navigation

there is no JavaScript API for navigation in ADF Faces because navigation in JavaServer Faces is an event driven framework and we don't support developers fighting the framework.

Steps to solve the problem:

Step 1: Create a CommandMenuItem under the af:menu component. Note goMenuItem is not working in this case because later we will use AdfActionEvent.queue method to simulate CommandMenuItem action while GoMenuItem doenn't have the action property.

Step 2: Drag and Drop af:ClientListener tag to af:menu component. Set the method as "onMenuClick" and the type is "click".

Step 3: Create a new JavaScript file and add the following codes into the file:


function onMenuClick(evt) {
    var source = evt.getSource();
    var component = source.findComponent('::pt_cmi1');
    AdfActionEvent.queue(component, component.getPartialSubmit());
}

pt_cmil1 is id name of the created commandMenuItem.

Step 4: Add af:resouce tag to af:document and set the source to the created javascript file and type is "javascript".

Thursday, November 18, 2010

BI Publisher: Passing Runtime Parameters into RTF Template and If conditions

When creating reports using BI Publisher, we could define parameters to dynamically get the proper data set as business needs.



The parameters we created are like the "binding variables" put into the where condition of the SQL (Data Source). Please note the name of the parameter has to be the same.




















If the parameters are also the columns in our data source, it will be displayed in the template as a data attribute, for example,

But in certain scenario, you want to display the input parameters as independent on the report. The reasons are:

1) If the user input for the parameters doesn't match in our database and there will no rows fetched. In this way, format will give you empty value. But at this moment, you still want to see the user input values from the report even there is no data rows.

2) If the user input parameter is not a binding variable in the where clause. For example, there is a user input parameter called "description" and user could input comments and want to print out their inputs with the report. Since the "description" is not database and   will not work.

So how to pass runtime parameters into template?

Step 1: Assuming the parameter is already created in the BI Publisher Server UI. From the RTF template, declare the parameter as:

where:  
parameter_name is the parameter name
parameter_value is the default value
 
Step 2: Refer to the parameter in the template by prefixing the name with a "$" character

To use if conditions in RTF template:

If we are passing a empty value to the parameters and we need to display some texts if the parameter is empty.

The syntax could be like:
 
For Example:
Please refer the BI Pub document for more details.

Monday, November 8, 2010

Refresh ADF table programmatically

This is the same post to this post.

It achieve the same result of PPR. This is used when somehow PPR in the table isn't working properly. For instance, you have a transaction process on the selected row in a table. You select the row in the table, and click the button which will perform the transaction process, but somehow the table isn't refreshed to the updated state of the row (even though you setup the PPR declaratively).

But you alway could solve this programmatically.

Here I posted the snapshot of the coding snippet.

















You can call setSelectedRow(getSelectedRowStr()) inside the actionListener of the button which will perform the custom transaction.

Another scenario: if you have a called task flow to process some transaction on the table and upon return to the calling task flow, the user wants to see the transaction changes which were performed during the called task flow. The solution is you can add a method action in the calling task flow to refresh the binding iterator of the table before returning to the page having the table.



Please note the refresh method is put in the backing bean and by default has no binding at all. Since we can calling the iteratorBinding, it's required to add the proper iterator in the binding. So Create page definition for the method action and add the proper iterator.



Take a look at the icon of the method action in the calling task flow, if it already has a page definition, it will have a little icon at the right bottom.

Friday, November 5, 2010

Programmatically Call Iterator and Refresh Iterator from UI (Managed Bean)

The code snippet is as follows:

 DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
DCIteratorBinding iter = bindings.findIteratorBinding("ReceiptsIterator");
iter.executeQuery();


Get the iterator through DCIteratorBinding 

Thursday, November 4, 2010

How to access Application Module from UI Layer

Application module is in the business service layer and is separated from user interface layer. The first thing to do is to get the bridge to business service from user interface - BindingContext.

BindingContext bctx = BindingContext.getCurrentInstance();

And then;

BindingContainer bc = bctx.getCurrentBindingEntry();

The method is get ApplicationModule is through "DCDataControl" by method: getApplicationModule (for any non-bc4j application, this method returns null).

To get DCDataControl, you could use DBBindingContainer by "getDataControl". But look at the API instructions, "*** For internal framework use only *** Returns the DCApplciation object to which this form binding belongs." So this method is for Oracle internal developers only.

The workaround on this is to use EL to reference the ApplicationModule bound to the UI page and use EL resolving to cast to application module type.

To find the Data Control Name:


    public static DCDataControl findDataControl(String dataCtlName)
    {
       return BindingContext.getCurrent().findDataControl(dataCtlName);
    }

To get the application Module data control by name:


  public static ApplicationModule getApplicationModuleForDataControl(String name)
  {
    return (ApplicationModule)JSFUtils.resolveExpression("#{data." +
                                                          name +
                                                          ".dataProvider}");
  }

JSFUtils.resolveExpression method can be found from Frank and Steve's ADF JSFUtils class.

Tuesday, November 2, 2010

Programmatically Access Page Bindings

Using EL references bindings declaratively in ADF should always be followed, but there always is room for you to argument your application behavior in your own code.

Here I am summarizing to access page bindings programmatically.

How to access Page Definitions/Binding Context/Binding Container?

BindingContainer bc = BindingContext.getCurrent().getCurrentBindingsEntry();

How to access page bindings in the page definition?

There are different types of bindings: attributeBinding, treeBinding, listBinding, actionBinding, methodBinding, etc
The corresponding types of codings have only two types: controlBinding and operationBinding. It's easy to recognize here. ActionBinding and methodBinding reference some actions and custom methods which are supposed to be executed somehow, therefore goes into the type of OperationBinding because it has execute() function. Other bindings are belonging to the valueBinding type so controlBinding is used.

The codings are:

OperationBinding oper = bc.getOperationBinding("actionMethodName");

We can also use JUCtrlActionBinding for actionBinding

ControlBinding cb = bc.getControlBinding("valueBindingName");

When using getControlBinding() method, we probably already know what type of valueBinding to access. So it usually is cast to the type of binding. For example,

1. attribute binding
AttributeBinding attr = (AttributeBinding)bc.getControlBinding("attrBindingName");

2. tree binding
JUCtrlHierBinding hierBinding = (JUCtrlHierBinding)bc.getControlBinding("treeBindingName");


Check here for the controlBinding implementing class.

Expression Language Conversion in ADF

Expression Language (EL) is widely used in ADF Binding to reference items in the Binding Context. In some scenario, direct use of EL reference isn't enough and manipulation of several EL references needed to accomplish the task. While you can always manipulate the logics in a manged bean, if you want to go with "declarative", here is why I am saying about.

Varchar2 type in SQL format (database) is converted to String automatically, but Number type in SQL is converted to oracle.jbo.domain.Number format. EL inherit generic Java API and can only recognize java.lang.Number type.

Therefore, if you have two EL binding references to two database Number attributes: #{bindings.NumberAtt1.inputValue} and {bindings.NumberAtt2.inputValue}. If you want to evaluate if the first number greater than the second number, you cannot use compareTo() method which is belongs to oracle.jbo.domain.Number and you cannot use #{A > B} because A or B is not java.lang.Number

A simple conversion is to attach ".value" in the end of EL binding reference and it will convert it to a java.lang.Double format type.

Create a SQL query at runtime in Application Module

We should use view object and related view criteria or bind variable to get any values from the database. Even though it is not recommended in many reasons, you still could try this way if the query is simple and trying to get a single value from the query.

In your application module implementation file, you could use getDBTransaction().createStatement() method to execute a sql query at run time.

Note there are three SQL statement types available in the DBTransaction interface: statement, callableStatement and preparedStatement.

Here is the snippet of coding in your application module file:

Friday, October 8, 2010

Create custom validators in ADF application


If somehow you need to create your own validation logic to meet your business needs. You can either create a validation method on the page's backing bean (if you want custom validation for a component on a single page), or create JSF validator classes (if you want to reuse the validation logics by various pages in the application).
In the real world, of course creating the custom JSF validator classes would be adopted for ADF application for better reuse and maintantence.
Here I present an example on creating custom validators in ADF application. In the example, I created two validators, one for email validation and the other for dateMustComeAfter valiation. You can add as many as you need to meet your requirements.
1. Create a new application based on ADF template.
2. In the viewController layer, create two validators classes - one called "EmailValidator" - to validate a valid email address - and the other called "DateMustComeAfterValidator" - to validate one date input has to be come after the other.

Here is the codes snapshots:

EmailValidator:


DateMustComeAfterValidator:





















In the java codes, please note you have to contain a validate method to implement Validator interface. The validate method has three arguments (FacesContext, UIComponent and Object). The UIComponent represent the component to be validated, and the object represent the value of the component to be validated.

3. Register the custom validator in faces-config.xml file. Open faces-config.xml, on the validator tab, click new to add the emailValidator and dateValidator.
























4. Add the validators to the components. Create a TestValidator page to test validations. In the page, drag a inputText and two inputDate component.

Right click on the inputText and choose "insert inside' --> JSF core --> validator. In the validator attribute, choose the validatorId as the name of the validator we registered in faces-config.xml file, it is "custom.EmailValidator". Perform same actions on the inputDate component. The difference in the inputDate component is that you have to add an "attribute" for the validator. The name of the attribute is "StartDateCompoonentId" we have used in the DateMustComeAfterValidator java file and the value is the component id of the first inputDate component.



Here are the user interface snapshots:

Email Validation:















Date Validation: 


















You can download the application if you wish to know more details: CustomValidatorApp.zip

The Web User Interface Developer's Guide demonstrated the usage and customizations of ADF converters and validators.
http://download.oracle.com/docs/cd/E14571_01/web.1111/b31973/af_validate.htm#ADFUI343

Tuesday, September 28, 2010

How to reference the value in a ADF Table column declaratively and in Java

I am correcting myself. I think I could not find a way to reference the value in a ADF table column using EL outside the table component.

As we all know, the value in the column of ADF table is referenced by using EL "#{row.AttributeName}", while "row" is defined in the ADF table component attribute - "Var" by default. If there is a scenario that you have to reference the value outside of the table: for example, you have a button outside of the table and will be dynamically disabled if a value in the table is null and enabled if a value is not null. The question is, how you gonna reference the column value out of the table.

Using the IteratorBinding EL is not accessible, I was trying to use #{Bindings.IteratorName.AttributeName.inputValue} to reference the value but it failed, since it is not the way it should be referenced. It is a attribute of the active Iterator binds to the table so simply it should be using the attribute binding. When drag and drop the view object to be exposed as an ADF table, the pageDef file adds the treeBinding as the Binding type for the table. So if we need to reference the value in the table, we need to create an attributeBinding, and simply reference its value by using EL: "#{Bindings.AttributeName.inputValue}".

Also we can reference it in Java. My previous post did this by utilizing the automatic binding of the UI component in a managed bean, by calling the method getSelectedRowData() or getValue() on the ADF table. Here I demonstrate just by calling the getControlBinding("IteratorName") from the Binding Container. In the method, I pass the name of the view object iterator in the data control that binds with the ADF table. Actually calling getControlBinding() from BindingContainer or getValue() from the binding table component did the exact same thing behind the scene.

Here is the code in Java:

Friday, September 17, 2010

About ClientListener and ServerListener

ClientListener, by its meaning, is fired/triggered by its source component to execute some client side script been defined in java scripts. Oracle defines it as "The clientListener tag is a declarative way to register a client-side listener script to be executed when a specific event type is fired. This tag will be ignored for any server-rendered components, as it is only supported by rich client components."
Before using the clientListener tag, be sure to look for any existing behavior tags which might eliminate the need for scripts. ClientListener is more generic and could be used anywhere there is a need for java scripts insertion. But ADF already provides some specific tag listener for some special occasion,  for example: the af:showPopupBehavior tag simplifies what it takes to display a popup.

This example will invoke the JavaScript method "showPopupFromAction" when the button is clicked and will then manually display a popup.

ServerListener, is fired/triggered by a custom client event to execute some server side actions. Oracles defines as "The serverListener tag is a declarative way to register a server-side listener that should be executed when a custom client event is fired. This tag will be ignored for any server-rendered components, as it is only supported for the rich client. The target method must return void and take one argument, a ClientEvent object."

The server side actions could be defined in a managed beans supporting the source components of the server listener. So the actions could be just a view layer action or it could be a method defined in business components (Application Module or View Objects) and exposed to client data control.

To fire a custom event from the client, use the AdfCustomEvent.queue() Javascript method. The Javascript having AdfCustomEvent.queue() should be called by the ClientListener, and AdfCustomEvent.queue() method is calling the server side action defined in ServerListener.

The AdfCustomEvent.queue() JavaScript method enables you to fire a custom event from any component whose clientComponent attribute is set to true. The custom event object contains information about the client event source and a map of parameters to include on the event. The custom event can be set for immediate delivery (that is, during the Apply Request Values phase), or non-immediate delivery (that is, during the Invoke Application phase).

For example, in the File Explorer application, after entering a file name in the search field on the left, users can press the Enter key to invoke the search. As Example 5-12 shows, this happens because the inputText field contains a clientListener that invokes a JavaScript function when the Enter key is pressed.

The JavaScript contains the AdfCustomEvent.queue method that takes the event source, the string enterPressedOnSearch as the custom event type, a null parameter map, and False for the immediate parameter.
The inputText component on the page also contains the following serverListener tag:
Because the type value enterPressedOnSearch is the same as the value of the parameter in the AdfCustomEvent.queue method in the JavaScript, the method that resolves to the method expression #{explorer.navigatorManager.searchNavigator.searchOnEnter} will be invoked.

Reference:
ClientListener
SeverListener
Sending custom event from client to the server

Wednesday, September 15, 2010

"Undo changes" Java codes

To implement a cancel edit button on an view object iterator which has changed data in cache, simple java codes can be used. The script is extracted from Frank's ADF code corner series 06 - "How to cancel an edit form, undoing changes in Java".

The script is put in the managed bean of the cancel button, either in ActionListener or Action beans. The example is in the ActionListener.


Monday, August 2, 2010

Manually refresh a row in a table after data manipulation

It's very common that the requirement asks to handle data manipulation for a ADF table. The data manipulation could be update, create or delete the table row and change some of the attributes in a table row. User interface experience should be achieve as that once the action button/link for the data manipulation has been pressed, the changed data should be reflected right away. It's not acceptable that the user has to refresh the page or search table to render the updated data.

Solution to this concern is easier to be fulfilled via declarative handling in Jdeveloper 11g. Setup the "refresh", "refresh condition" of the iterator that the table binds should be considered first to utilize the "PPR" feature of the ADF. But sometimes the declarative handling does not behave as expected, and you need to achieve this manually as a workaround.

Here is how I achieve this. Assume we have a manged bean to handle the data manipulation codes. After we selected a row in the table and press the data manipulation button, the codes for the data manipulation is executed, and should be followed by the below steps:

1). Get the row key for the selected Row.
2). Refresh the table manually. If you have a search functionality to refresh the table, we can use executeQuery of the binding View Object in our codes to refresh the table.
3). Set the current row of the refreshed table with the row key in step 1.

Here is the sample codes for this:

=====How to get the row key for the selected row in a table======
_Table is the binding name in managed bean

  private Key getRowKey() {
    Object _selectedRowData = _Table.getSelectedRowData();
    JUCtrlHierNodeBinding _nodeBinding = (JUCtrlHierNodeBinding)_selectedRowData;
    Key _rowKey = _nodeBinding.getRowKey(); 
    return _rowKey;
  }

=====How to set the current row in the a table with a given row key=====

  private void setSelectedRow(Key rowKey) {  
    BindingContainer bc = BindingContext.getCurrent().getCurrentBindingsEntry();
    OperationBinding oper2 = bc.getOperationBinding("executeQuery");
    oper2.execute();
    CollectionModel _tableModle = (CollectionModel)_Table.getValue();
    JUCtrlHierBinding _tableBinding = (JUCtrlHierBinding)_tableModle.getWrappedData();
    DCIteratorBinding _tableIteratorBinding = _tableBinding.getDCIteratorBinding();
    _tableIteratorBinding.setCurrentRowWithKey(rowKey.toStringFormat(true));
  }

Thursday, June 24, 2010

Manually Assign new value to sequence column

Sometime we need to manully assign a new value to a sequence column. For example, we have a department table with primary key column department_id, which is based on a sequence "department_sequence".

When we try to create a new record in the department table, we will do the following in the AMImpl.java:

*************************************************************
DepartmentVOImpl vo = getDepartmentVOImpl();
vo.clearCache();
Row row = vo.createRow();

SequenceImpl sequence = new SequenceImpl("department_sequence, getDBTransaction());
Number dept_id = sequence.getSequenceNumber();

row.setAttribute("DepartmentId", dept_id);

//set other attribute values...

vo.insertRow(row);
getDBTransaction().commit();
*************************************************************

Wednesday, June 23, 2010

Post Ordering Issue

I have a previous post about the post ordering constraints error. The situation in that post might be somewhat special: the association between two entity objects (master and detail) is a DBSequence in the master table.

Here is a working solution to the generic post ordering issue.

Steve Muench has an article "Forcing a New Dept to Post Before a New Emp Without Composition", which presented two ways to solve the post ordering contraints:

1. Override postChanges() method in the detail/child entity object Implementation java file. For example, if Dept and Emp table, then write below codes in EmpImpl.java file:



2. An even simpler way:


Steve also has a very good article on "Most Commonly Used Methods in ADF Business Components" which lists all common used methods in EO, VO, AM, etc.

Monday, June 21, 2010

Setup SSL Certificate for PayFlow Gateway in Weblogic 10.3

PayFlow Pro is a gateway provided by PayPal Inc for payment transactions, like credit card transaction. To use payFlow gateway in ADF application, you have to install the payFlow SDK from Paypal. You can find info in here.

After installation of payFlow processor you can download the payflow Java Library and write codes to process the transaction.

But before that, you have to set up the SSL on your server to make it work. The SSL is installed on your development server to recognize the PayFlow's transaction process server, therefore the SSL has to be installed into the trust keystore on the weblogic server.

For test and development purpose, the SSL certificate can just added to the default existing keystore in Weblogic server. The steps are here:

1. download the SSL certificate that can recognize PayFlow server. It can be downloaded from either A or C link.The download link is here.

2. Use keytool command to import the certificate into the existing trust keystore for development use. The syntax of the command is (assuming the certificate file is put under jdk directory \jre\lib\security in JDeveloper install directory. This directory is arbitrary):

*JDeveloper_Install_Directory*\jdk*version*\jre\bin\keytool -import -alias paypal -keystore *JDeveloper_Install_Directory*\wlserver_10.3\server\lib\DemoTrust.jks -trustcacerts -file *JDeveloper_Install_Directory*\jdk160_14_R27.6.5-32\jre\lib\security\72fa7371.cer

DemoTrust.jks is the default trust keystore. "72fa7371.cer" is the downloaded certificate. You will be prompted to enter the keystore password to import, the password for DemoTrust keystore is "DemoTrustKeyStorePassPhrase"

3. The DemoTrust Keystore is already use in weblogic server by default so nothing needs to be changed in weblogic admin console. But if you want to see the configuration in weblogic console, go to server, under configuration tab, there are Keystore tab and SSL tab, that's where you setup the identity keystore and trust keystore.

4. Restart the weblogic server and you shall be able to use the paypal payFlow process to process any credit card transaction using your weblogic server.

In case of production instance, the custom keystore has to be created and configured in Weblogic console. Here are steps for production instace:

1. Create the private key for standalone weblogic server and send the key to CA (e.g.: Verisign) for certificate.

2. Create an identity keystore for weblogic server using java keytool command.

3. Import key/certificate pair into the identity keystore using weblogic command ImportPrivateKey (keytool command cannot do this step)

4. Import Verisign certificate which could recognize payflow process server to weblogic trust keystore (The current certificate is noted on paypal’s development site, name is “72fa7371.cer”)

5. Change the settings in Weblogic Console to use the custom identy keystore and trust keystore.

Useful links:
A. ***Important Notice Regarding The Payflow Gateway***
https://www.x.com/docs/DOC-1675

B. ***PayFlow gateway documents***
https://www.x.com/docs/DOC-1444

C. ***Certificate download link from Verisign***
https://www.verisign.com/support/roots.html

D. ***Certificate Install Instructions***
https://knowledge.verisign.com/support/ssl-certificates-support/index?page=content&id=AR212&actp=LIST
http://www.geocerts.com/install/weblogic_8

E. ***Configure keystores in Weblogic Admin Console***
http://download.oracle.com/docs/cd/E14571_01/apirefs.1111/e13952/taskhelp/security/ConfigureKeystoresAndSSL.html

F. ***KeyTool Command***
http://www.sslshopper.com/article-most-common-java-keytool-keystore-commands.html
http://www.informit.com/articles/article.aspx?p=407886&seqNum=2
http://publib.boulder.ibm.com/infocenter/wbihelp/v6rxmx/index.jsp?topic=/com.ibm.wbia_adapters.doc/doc/sap_xi/sapximst85.htm

G. ***No identity key/certificate entry was found***
http://objectmix.com/weblogic/564019-ssl-custom-keystores-question.html

H. ***Weblogic ImportPrivateKey Command***
http://download.oracle.com/docs/cd/E14571_01/web.1111/e13749/utils.htm#i1176073

I. ***Setup Weblogic Server Command Enviorment***
http://download.oracle.com/docs/cd/E14571_01/web.1111/e13749/weblogicserver.htm#i1008498

Thursday, June 10, 2010

Implement Cascading lists of values in ADF 11g

In many cases, we will have to use cascading lists of values, also called dependent lists of values in our ADF application. Cascading lists of values, in its name, means one set of list of values are dependent on selected value on another set of list of values.

How does it work is apply view criteria to a model driven list of value.

Here I present one example in HR schema. Let's say we have a list of departments, when one department value is selected, a second list of values - manager will be set to managers within the selected departments, a third list of values - employees will be set to employees under the selected manager.

First, we create our base VO - EmployeesVO (can be created from Entity object also)


Second, we create 3 list of values for 3 attributes we are interested in EmployeesVO: DepartmentId, ManagerId, EmployeeId.

Each list of value needs a view accessor (data source for the LOV). 

DepartmentId attribute needs a view accessor from DeptListVO, which is based on query "select department_id, department_name from departments". 



































ManagerId attribute needs a view accessor from EmployeesVO itself with additional attributes: Firstname and LastName.


ManagerId is based on selected departmentId, so we have to create a view criteria on its view accessor - EmployeesVO.

Then we have to add the view criteria to the view accessor. In the "Bind Parameter Values" section, type in the value "DepartmentId' using Groovy script.


EmployeeId attribute needs a view accesor from EmployeesVO like managerId. Create a LOV based on EmployeesVO view accessor.




































Employee is based on selected managerId. So a view criteria needs to be applied on its view accessor - EmployeesVO.


































Similarly, we will add the view criteria into the view accessor.
Now we create the UI for the list of values.

Please note for the UI to work with dependent lists of values, the properties of the parent LOV has to be set as: "AutoSubmit: true" and the partial trigger property of its child LOV has to be set as its parent LOV id.

Finally it works as this:

1. select a department id.


2. the manager Id then displays only the ones under the selected department.


3. the employees then display only the ones under the selected manager.