Friday, December 10, 2010

ADF 11g : How to control where a new row is inserted

On the JDeveloper forum a question was asked how to insert a new row in an ADF table after the selected row. Default behavior is insertion before the current row. In this short post I describe how to achieve this. In order to do this I create a custom method on the application module that takes the position (BEFORE or AFTER) as an argument. Based on this argument the new row is inserted at the appropriate position.

  public void createRow(String beforeOrAfter){  
Row newRow = getJobsView1().createRow();
newRow.setNewRowState(Row.STATUS_INITIALIZED);
//get instance of the above created view object
ViewObjectImpl vo=getJobsView1();
// to insert row at the end of the table
if (beforeOrAfter.equalsIgnoreCase("AFTER")){
vo.next();
vo.insertRow(newRow);
}
else
{
vo.insertRow(newRow);
}
}


I publish the method, and drop it as a Button on the page. I copied the button so I have one for each option.

  <af:panelCollection id="pc1">  
<f:facet name="menus"/>
<f:facet name="toolbar">
<af:toolbar id="t2">
<af:commandButton actionListener="#{bindings.createRowBefore.execute}"
text="create Before"
disabled="#{!bindings.createRowBefore.enabled}" id="cb1"/>
<af:commandButton actionListener="#{bindings.createRow.execute}"
text="create After"
disabled="#{!bindings.createRow.enabled}" id="cb2"/>
</af:toolbar>
</f:facet>
<f:facet name="statusbar"/>
<af:table value="#{bindings.JobsView1.collectionModel}" var="row"
rows="#{bindings.Jo .......................
........................................

The page definition contains the corresponding MethodAction. I copied the MethodAction, so I have one for each option.
   <methodAction id="createRow" RequiresUpdateModel="true"  
Action="invokeMethod" MethodName="createRow"
IsViewObjectMethod="false" DataControl="AppModuleDataControl"
InstanceName="AppModuleDataControl.dataProvider">
<NamedData NDName="beforeOrAfter" NDValue="AFTER"
NDType="java.lang.String"/>
</methodAction>
<methodAction id="createRowBefore" RequiresUpdateModel="true"
Action="invokeMethod" MethodName="createRow"
IsViewObjectMethod="false" DataControl="AppModuleDataControl"
InstanceName="AppModuleDataControl.dataProvider">
<NamedData NDName="beforeOrAfter" NDValue="BEFORE"
NDType="java.lang.String"/>
</methodAction>

When I run the page, the 'insert before' button inserts the new record before the currently selected one.

So now the 'insert after' button inserts the new record after the currently selected one.

Tuesday, November 30, 2010

ADF 11g : Change a Viewobjects' Query on the Fly

One of the requirements at my current project is to have one ADF table display data from different database tables. That is, depending on criteria entered by the user, the query behind the view object needs to change. All in all 12 different database tables are involved in this story. This requirement is based on functionally in the original (oracle forms) application. This forms application used the set_block_property built-in:
 set_block_property('<blockName>, query_data_source_name, <datasource>);  

I was able to reproduce this behavior in an ADF application. In this post I explain how I did this.

Database and ADF Business Components.
Luckily these tables all have the same attributes so it is relatively easy to achieve this. I created two database views. One based on the employees table, and a second one based on the locations table. Mark that I defined identical column aliases for both views.
 create view EMP_ABSTRACT_VW as  
select
EMPLOYEE_ID IDENTIFIER,
FIRST_NAME DESCRIPTION
from employees

 create view LOC_ABSTRACT_VW as  
select
location_id IDENTIFIER,
city DESCRIPTION
from LOCATIONS

Next I created an ADF Business Components viewObject based on one of the database views. I called this viewObject 'dataprovider'.
 select  
IDENTIFIER objId
,DESCRIPTION objDesc
from emp_abstract_vw


ADF Faces Page.

To display the data on a page I just created a simple page and dropped the collection from the datacontrol pallet onto the page as an ADF Table component. When running the page, you see data from the emp_abstract_vw as expected.

Preparing the Query Change Method.

In order to change the query I have to create a method on the application module. This method gets a handle to the viewObject, sets some properties, changes the query and executes it. Ok, not that fast. In the codefragment below you see one line where I use setFullSqlMode. Lets explain what FULLSQL_MODE_AUGMENTATION does.

First I apply the new programmatic query by calling setQuery() and execute the query. If I need to call setWhereClause or if a user changes criteria the query, the ADF Business Components framework augments the whereClause on the programmatic query. If you don't use FULLSQL_MODE_AUGMENTATION any changes by setWhereClause or change of query criteria are applied to the original query (that is the query that was defined design time).
1:   static String baseQuery = "select IDENTIFIER objId, DESCRIPTION objDesc from ";  
2: public void changeBaseTable(String baseTable){
3: String query = baseQuery + baseTable;
4: ViewObjectImpl voi = getdataProvider();
5: voi.setFullSqlMode(voi.FULLSQL_MODE_AUGMENTATION);
6: voi.setQuery(query);
7: voi.executeQuery();
8: }

Next step is to publish this method so I can use it on my page. I drop the method from the datacontrol, resulting in a methodAction in my bindingcontainer.
1:   <methodAction id="changeBaseTable" RequiresUpdateModel="true"  
2: Action="invokeMethod" MethodName="changeBaseTable"
3: IsViewObjectMethod="false" DataControl="AppModuleDataControl"
4: InstanceName="AppModuleDataControl.dataProvider">
5: <NamedData NDName="baseTable" NDType="java.lang.String"/>
6: </methodAction>

Final step is the implementation of a selectOneChoice with a value change listener to change the basetable for the query. The selected value corresponds to the name of one of the database views, and will be directly applied to the viewObjects' query.
1:  <af:selectOneChoice label="Basetable...&gt;&gt;&gt;  " id="soc1"  
2: value="#{pageFlowScope.SwitchIterator.baseTable}"
3: autoSubmit="true"
4: valueChangeListener="#{pageFlowScope.SwitchIterator.switchBaseTable}">
5: <af:selectItem label="Employees" value="EMP_ABSTRACT_VW"
6: id="si1"/>
7: <af:selectItem label="Locations" value="LOC_ABSTRACT_VW"
8: id="si2"/>
9: </af:selectOneChoice>

The valueChangeListener executes the methodBinding, thus changing the query.
  public void switchBaseTable(ValueChangeEvent valueChangeEvent) {  
setSource(valueChangeEvent.getNewValue().toString());
}
public void setSource(String baseTable) {
// Add event code here...
DCBindingContainer bc = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
OperationBinding oper = bc.getOperationBinding("changeBaseTable");
oper.getParamsMap().put("baseTable", baseTable );
oper.execute();
}

Now when you start the application you will see the table displaying all employees.
This is the default query behind the viewobject.


By changing the value of the listbox, you will also change the viewobjects' query, resulting in locations data being displayed in the table.




This post was originally posted at the AMIS Technology Blog

Thursday, November 11, 2010

ADF 11g : SelectOneRadio in Table Layout

Today at one of my customers I was asked the question if you can use a SelectOneRadio component in table layout. I know that the first thing they should have done is try Google to find a solution. As a matter of fact they did and found this blogpost by Frank Nimphius. This however is based on ADF 10g. The part where Frank converts the InputText to a selectOneRadio isn't available in ADF 11g anymore. It can be achieved in ADF 11g very simple as well.

Based on an example I will explain how to do this in ADF 11g. For this I added an extra column to the EMPLOYEES table. This column called "OutOfOffice" holds the status of the selected employee. I created ADF BC for the Employees table. When dropping this as an ADF table you will see the result as below.


Not user-friendly at all. But how can we change this ?

Actually it's simple. First remove the inputText field from the column.
Next drop the OutOfOffice attribute from the datacontrol on the column as a selectOneRadio.


In the ListBinding editor select Static List and add the static values. In this case just Y and N.


In the pageDef this looks like this:


The choices in the selectOneRadio will be displayed in a vertical layout. For a table I prefer horizontal layout. This will not change the height of the rows.


Now when you run the page it looks a lot better.


And that is all you have to do.

Monday, October 25, 2010

Book Review: Quick Start Guide to Oracle Fusion Development

A couple of weeks ago yet another ADF book was released. This time it was Grant Ronald’s turn. He managed to write a “Quick Start Guide to Oracle Fusion Development”. I was somewhat worried because it is seemingly impossible to write a Quick Start Guide to Fusion Development. However after reading the book I was very surprised of what the book has to offer to people starting with fusion development. In this post I share my findings with you...


A look at the content immediately learns that this book covers the whole development process. The “Quick Start Guide” provides the essential information you need to build applications. Nothing more and, more important, nothing less. The book really is an introduction to the most important building blocks and functionality that you’ll use while starting ADF development.

Part I : Introductions and Overviews.
1. Introduction to Fusion and the Fusion Technologies.
2. Introduction to JDeveloper and Oracle ADF.
3. Finding your Way Around JDeveloper.
Part II : Building Business Services.
4. Building ADF Business Components.
5. The Role of the Entity.
6. View Object: A window to your data.
7. The Application Module.
8. More View Object Features.
9. Implementing Business Service Validation.
Part III : Building the User Interface.
10. Introducing ADF Faces Rich Client.
11. Introducing ADF Model.
12. Building Typical ADF Faces Pages.
13. Building Application Flow.
14. Buttons and Menus.
15. Advanced UI Techniques.
16. Data Visualization Components.
17. Building a Reusable UI.
Part IV : Common Coding Patterns.
18. Common Business Service Coding Examples.
19. Common View Coding Examples.

Part I introduces Oracle Fusion and the techniques and programming languages you need to know to a certain extend when developing Fusion Applications. Not that these are really explained, but just telling you very briefly what they are all about. This is very handy when you start with Fusion development. You know what people around you are talking about when they mention for instance Model-View-Controller. Also the ADF Framework Components and the JDeveloper IDE are explained briefly.

The second Part helps you understanding business services.
What immediately struck me was the fact that here is finally a book that does not use the HR schema. Instead of that, the OE schema is used in all examples in the book. This forced me to read a bit more carefully. 99.8% of all ADF examples are based on the HR schema or the FOD (Fusion Order Demo), and most of these I know by heart. All techniques you need for developing business services are covered. Chapter 5 of the book mentions some re-factor techniques. Re-factoring is a technique to reorganize your ADF project. Experience learns that re-factoring in JDeveloper works very well, but there are some cases where you have to be careful. There is one tip in this part of the book (the tip on page 56) that I don’t agree with. Using system.out.println() is one way to debug your code, but a better way is using log4j. However in the stage of your learning curve, for now system.out.println() is just fine.

The third part is all about User Interface and the components and techniques involved. After introducing ADF visual components and ADF layout components, you learn (at lightning speed) how to build your first page. After that, ADF model is introduced. ADF model is the framework part that enables you to expose your business services (Part II of the book) to the User Interface. The concepts of data control and data binding are explained. Next, you read all about building a typical ADF Faces page and how to use table layout, form layout and master detail layout and how to use ADF Query components. In this context you will learn ‘on the fly’ how to use the JDeveloper IDE for building ADF Pages.

Also one of the core concepts of Fusion Development, the task flow, is mentioned in chapter 13. This is a somewhat advanced concept, so as a beginner you would only have to know the basics of the taskflow. Some taskflow related and navigation concepts will do for now. The author manages to provide you with only the necessary info. In the advanced UI Techniques chapter, you should read the part about PPR with care. This will be one of the things that you are going to use extensively. The concept is easy to understand. The techniques in the rest of this chapter (except popups and validation) are the ones that you will probably use less. However, even these are explained very well. Buidling Reusable UI’s is about page templates and declarative components. You will learn just that tiny bit to get you up to speed.

Finally common coding techniques are described in the fourth part. You will see that it is very easy to override DML operations and how to set view criteria dynamically. Believe me, these are the things that you want to know they exist. You will use them a lot. The same applies to programmatic access to bindings and programmatic PPR which are indeed VERY common UI coding techniques.

Conclusion.

In short, a great book for starting with Fusion Development. The book is written in clear and easy to understand language. It takes you trough all stages and helps you to get a quick start. Throughout the whole book, the author is honest and clear about the knowledge you need at this stage of your learning curve. For instance the use of managed beans is mentioned but just to let the reader know that these exist. You do not yet need to know how to use these. And there are more of these examples. After reading this book, you are up and running. Maybe you need some more reading on specific topics, but core concepts should be familiar after reading. This book could be an addition to training material for students that take the ADF course at AMIS. The training is an in depth ADF course, but the book can really help them to understand core concepts of ADF. It uses the same order of subjects as our training. Even after the training, this book can be used as a Quick Reference Guide, to refresh your knowledge.

Ordering the book.

The book can be ordered here at amazon or at other (online) bookstores. The ISBN for this book is: 9780071744287.

This post was initially published at the AMIS Technology Blog.

Thursday, September 30, 2010

ADF 11g inputNumberSpinbox: Changing Value When Value is Null

This post is a short one, however, it is useful. When you use a Spinbox to change and display values, you might encounter a problem when the Spinbox' value is empty (or Null).

I used the Employees table in the HR Schema for this example.
Created ADF BC for this, and dropped the collection as an ADF Form an a simple page.
I converted the commission inputText component to an inputNumberSpinbox and set stepSize="0.1".

You can click whatever you want but the Spinbox just doesn't work for NULL values.




One of the options you have, is to enter a value in the Spinbox by just typing it.

A somewhat more elegant solution is the use of javascript.
For this I add a client Listener to the Spinbox.



The clientListener invokes a javascript function as soon as the Spinbox gets focus. Whenever the value is NULL, it will set the value to ZERO. The Spinbox now knows what to do.

   <af:document id="d1">  
<af:resource type="javascript">
function initSpinner(evt){
spinbox = evt.getSource();
val = spinbox.getValue();
if (val ==null){
spinbox.setValue(0);
}
}
</af:resource>


When you click the empty Spinbox now, it will work as expected.



Monday, August 16, 2010

ADF 11g: toggle operators in query component

When you use view criteria to be exposed in an <af:query/> component, it is sometimes weird that ADF allows you to change query operators. In this use case I define a view criteria using a BETWEEN clause on two dates.



When you create an <af:query/> component based on this criteria, you will see that it is rendered with operation 'between' as the selected operator. You do however have the possibility to change the operators. This actually makes no sense because you only need between.



You can change this behavior on the UI-hints tab of the view criteria editor.



When you run the application again, no operators are shown, but you can still insert two dates, still making it clear to the user that the search will be from - to.



This is a design-time solution. You can also manipulate this at run-time.

Run-time manipulation

For this you need to create the view object implementation class. In this class you then create a method that will show or hide the operators. By setting the "displayOperators" property of the view criteria, you can toggle between the show "InAdvancedMode" and show "never" mode.
1:   public void toggleShowOperators(){  
2: for (ViewCriteria vc:getAllViewCriterias()){
3: System.out.println(vc.getName());
4: System.out.println("displayOperators before change " + vc.getProperties().get("displayOperators"));
5: if (vc.getProperties().get("displayOperators")=="InAdvancedMode"){
6: vc.setProperty("displayOperators", "never");
7: }else
8: {
9: vc.setProperty("displayOperators", "InAdvancedMode");
10: }
11: System.out.println("displayOperators after change " + vc.getProperties().get("displayOperators"));
12: }
13: }


You publish this method to the client and drop it as an <af:commandToolbarButton/> on your page. Last thing is to set partialSubmit attribute of the button and the partialtriggers attribute of the corresponding <af:query/> component.

1:  <af:toolbar id="t1">  
2: <af:commandToolbarButton text="toggleShowOperators"
3: id="ctb1"
4: actionListener="#{bindings.toggleShowOperators.execute}"
5: disabled="#{!bindings.toggleShowOperators.enabled}"
6: partialSubmit="true"
7: />
8: </af:toolbar>
9: <af:panelHeader text="Employees" id="ph1">
10: <af:query id="qryId1" headerText="Search" disclosed="true"
11: value="#{bindings.EmployeesHireDateCriteriaQuery.queryDescriptor}"
12: model="#{bindings.EmployeesHireDateCriteriaQuery.queryModel}"
13: queryListener="#{bindings.EmployeesHireDateCriteriaQuery.processQuery}"
14: modeChangeVisible="false"
15: queryOperationListener="#{bindings.EmployeesHireDateCriteriaQuery.processQueryOperation}"
16: resultComponentId="::resId1"
17: partialTriggers="::ctb1"/>
18: </af:panelHeader>


Now you can toggle between the show operators by pushing the button.

Thursday, August 12, 2010

ADF 11g: Change attribute order in query component

Ever wondered if you can change the order in which the attributes are displayed in an 'af:query' component? It can be done. Here is how.

After you have created BC you can drop the named criteria "all queriable attributes" as an 'af:query' component with table.



When you run this, you will see the default generated query component. let's assume that the attributes in this component are not in the order that you like. You are in desperate need to show the "job" attribute first.



The solution is at view object level. You can change the order of the attributes by invoking the "Set Source Order" button. This button will show you a popup in which you can reorder the attributes. Use the button(s) so the attributes are in the order you want.



If you run the page again, the query component shows the "job" attribute first.



Too bad that this is a design time solution. There are some pending ER's regarding this subject.

Monday, August 09, 2010

ADF 11g: Using a List in Query component

When you create a default query component you might miss some of the features that ADF offers to you. One of these is the use of lists in the query component. In this post I'll explain to you how to do that.

First image here is the way a query component displays when you use all the defaults, and do no tweaking at all. Forget that I already changed some attributes so they are not displayed in the query component.

It looks ok, but the user of your application might not be so happy. They have to know the id of all departments. This is fine when you only have a few, but what if you have many ?

Let's try to add a list to the query component.

We have to start with the creation of the lookup item for department name. This can also be used in the actual table showing the results. First we add an entity usage for departments to the employees view object

After this we can add the lookup items.

Now create the list of values. The list of values should be based on the departments name attribute.

On the second tab set the UI hints for the list of values. Be aware of the fact that you can only use a couple of list types that can be used in the query component. For now we pick the combo box with list of values.

The last step in the process is to set the queriable property of the departmentId's (both base and lookup) to false.

When you run the page now, you will see that the contains a nice list with all departments.

You can even invoke a complete List Of Values, when you select 'search...' in the combobox (green area in picture above).


Much better than working with department id's (see the difference with the first picture in this post).

Monday, July 26, 2010

ADF 11g Skinning: Three ways to change look and feel

On the JDeveloper ADF forum there are many questions on how to change the look and feel of components. In this post I'll explain three ways to do that.

Setting skin Selector property

For this we need to define a custom skin.
<?xml version="1.0" encoding="ISO-8859-1"?>
<skins xmlns="http://myfaces.apache.org/trinidad/skin">
<skin>
<id>mySkin.desktop</id>
<family>MySkin</family>
<extends>blafplus-rich.desktop</extends>
<render-kit-id>org.apache.myfaces.trinidad.desktop</render-kit-id>
<style-sheet-name>skins/MySkin.css</style-sheet-name>
</skin>
</skins>

In the style sheet we will add an entry that will hide the columnheaders.
af|column::column-header-cell{display: none;}

This entry in the styleSheet will apply to ALL columns in your application.


Using and appending styleClasses

Now we create a StyleClass that is exactly the same as the style in the previous example.
.TableNoHeader af|column::column-header-cell{display: none;}

When we apply this styleClass to only one of the tables in our application, we will see the effect.
<af:table value="#{bindings.Departments1.collectionModel}" 
var="row"
rows="#{bindings.Departments1.rangeSize}"
styleClass="TableNoHeader"
emptyText="#{bindings.Departments1.viewable ? 'No data to display.' : 'Access Denied.'}"
fetchSize="#{bindings.Departments1.rangeSize}"
rowBandingInterval="0"
filterModel="#{bindings.Departments1Query.queryDescriptor}"
queryListener="#{bindings.Departments1Query.processQuery}"
filterVisible="true"
varStatus="vs"
selectedRowKeys="#{bindings.Departments1.collectionModel.selectedRow}"
selectionListener="#{bindings.Departments1.collectionModel.makeCurrent}"
rowSelection="single"
id="t1">

Only one table has no columnheaders now.


Use Skins to change labels.

Using styleClasses you can adjust a lot of the components look and feel. However, you cannot change the labels and hint texts that are shown in the application. To do that you will have to use a skin resource bundle. See in the example below the bundle-name tag.
<?xml version="1.0" encoding="ISO-8859-1"?>
<skins xmlns="http://myfaces.apache.org/trinidad/skin">
<skin>
<id>mySkin.desktop</id>
<family>MySkin</family>
<extends>blafplus-rich.desktop</extends>
<render-kit-id>org.apache.myfaces.trinidad.desktop</render-kit-id>
<style-sheet-name>skins/MySkin.css</style-sheet-name>
<bundle-name>com.blogspot.lucbors.view.bundles.MySkinBundle </bundle-name>
</skin>
</skins>

Create the class that will hold the entries for the bundle.

Lets asume that we want a different text for the pannelsplitter.

Add entries for all labels and hints that you need to change.
package com.blogspot.lucbors.view.bundles;

import java.util.ListResourceBundle;

public class MySkinBundle extends ListResourceBundle {
public MySkinBundle() {
super();
}
@Override
public Object[][] getContents() {
return _CONTENTS;
}

static private final Object[][] _CONTENTS = {
{"af_column.TIP_SORT_ASCENDING","first things first"}
,{"af_panelCollection.LABEL_MENUITEM_QBE","the text that you want"}
,{"af_panelSplitter.TIP_COLLAPSE", "hide all of this this"}
,{"af_panelSplitter.TIP_RESTORE", show all again"}"
};
}

When you run the application now, you will see changed texts.


Online overview with all skin selectors can be found here;
The workspace for this blogpost can be downloaded here.

Wednesday, June 30, 2010

ADF 11g panelgroup: Tournament Layout

This is a short post on layout. With the quarter finals of the world cup 2010 coming up, it is time to show a simple layout example. A layout to show all teams and groups, competing in the world cup.



This layout is achieved by af:panelgrouplayout, af:panelbox, and af:forEach.
I read all the group data from a database table, and use the af:forEach to create a panelbox for each group. After that I use another af:forEach to add a line for every team in a group.

 <af:panelGroupLayout id="pgl1" layout="horizontal"  
inlineStyle="width:654px;">
<af:forEach var="group" items="#{bindings.ExistingGroups.rangeSet}">
<af:panelGroupLayout layout="vertical" id="pgl3">
<af:panelBox id="pb1"
showHeader="always" showDisclosure="false" >
<af:forEach items="#{bindings.GroupDraw.rangeSet}"
var="team" begin="#{group.index*4}"
end="#{(group.index*4)+3}">
<!-- *4 and +3 depends on the groupsize.-->
<af:panelGroupLayout layout="horizontal" halign="start"
id="pgl2">
<af:panelGroupLayout layout="horizontal"
halign="end" id="pgl5">
<af:image source="/flagservlet?detail=#{team.Teamcode}"
id="i5" shortDesc="#{team.Teamname}"/>
</af:panelGroupLayout>
<af:spacer width="25"/>
<af:panelGroupLayout layout="horizontal"
halign="start" id="pgl4">
<af:commandLink text="#{team.Teamcode}"
shortDesc="#{bindings.GroupDraw.hints.Teamcode.tooltip}"
id="cl1"></af:commandLink>
</af:panelGroupLayout>
<af:spacer height="35"/>
</af:panelGroupLayout>
</af:forEach>
<f:facet name="toolbar">
<af:panelGroupLayout layout="horizontal" halign="center">
<af:commandLink text="#{group.Code}"
shortDesc="#{group.Description}"
action="Detail"
id="cl2">
<af:setActionListener from="#{group.Code}" to="#{pageFlowScope.Groupcode}"/>
</af:commandLink>
</af:panelGroupLayout>
</f:facet>
</af:panelBox>
</af:panelGroupLayout>
</af:forEach>
</af:panelGroupLayout>


That is all to create a layout to show group contents, and to link to the groups, or team details.

Thursday, May 20, 2010

ADF Mobile Client: Article on OTN - Developing Applications for the BlackBerry

After a couple of months of hard work, my article on developing ADF applications for blackberry smartphones finally made it to OTN.



If you go to otn.oracle.com you cant' miss it. If it's gone by the time you read this, you can find the article right here.

Friday, April 30, 2010

ADF 11g popup and panelwindow: Open wikipedia in a modal popup.

This post was more or less inspired by the noteWindow example on
Oracles tag demo site. When hovering the highlighted text in this example the user gets extra information about the subject. I wanted to give the end user the opportunity to get even more information, for instance by invoking a wikipedia page about the subject. The catch here is that I wanted this information to be shown in a modal popup, and one that is not prohibited by popup blockers. Luckily ADF 11g provides javascript popups that can also be made modal, so the user has to close the popup before returning to the application.

This post describes how I used an in a to open the correct wikipedia in a modal popup.

Step 1: Create the plain text that invokes the noteWindow.

This is taken directly from the mentioned Oracle example.
 <p style="margin-left:30px;width:500px;margin-right:30px;line-height:16px">
Vultures are scavenging birds, feeding mostly on the carcasses of dead animals.
Vultures are found in every continent except
<af:outputText id="antarctica" value="Antarctica"
inlineStyle="color:red; font-weight:bold">
<af:showPopupBehavior popupId="popupAntartica"
triggerType="mouseHover" alignId="antarctica"/>
</af:outputText>
and in Oceania.
</p>

This code produces the following page.



Step 2: Create the noteWindow that calls wikipedia.
This piece of code shows the noteWindow with the extra information. There is an with an associated . Also note the binding of the goLink. This binding makes sure that I can use the textvalue of the goLink in the backing bean to create the URL with the request parameter for the wikipedia page.
<af:popup id="popupAntartica" contentDelivery="lazyUncached">
<af:noteWindow inlineStyle="width:500px;" id="nw2">
<p>Antarctica is Earth's southernmost continent, overlying the South
Pole. It is situated in the southern hemisphere almost entirely
south of the <af:goLink text="Antarctic Circle "
binding="#{toolTips.goLink}"
id="gl1">
<af:showPopupBehavior popupId="popupExt" triggerType="click"/>
</af:goLink> and is surrounded by the Southern
Ocean. At 14.4 million km² (5.4 million sq mi), it is the
fifth-largest continent in area after Asia, Africa, North
America, and South America. Some 98% of Antarctica is covered by
ice, which averages at least 1.6 kilometres (1.0 mi) in thickness.</p>
</af:noteWindow>
</af:popup>

The link in the text is the one that I'm going to use to invoke Wikipedia.



Step 3: Creating the wikipedia URL.

Wikipedia uses a pretty simple URL with request parameters to navigate to the requested subject.
http://en.wikipedia.org/w/index.php?search=<here goes my value>

With this knowledge it is easy to create a URL yourself to navigate to the requested page.
private static String wikipedia =
"http://en.wikipedia.org/w/index.php?search=";

String url;
String reqParam;
private RichGoLink goLink;

public ToolTips() {
}

public String getUrl() {
return wikipedia + this.getReqParam();
}
public void setReqParam(String reqParam) {
this.reqParam = reqParam;
}
public String getReqParam() {
return this.goLink.getText();
}


The popup containing the inlineframe is also straightforward. The source attribute of the inlineframe is an EL expression pointing to the url property in the above code fragment.
<af:popup id="popupExt" animate="default"  >
<af:panelWindow id="pw1"
modal="true"
title="External Internet Info in a Modal Popup"
contentHeight="625"
contentWidth="700"
resize="on">
<af:inlineFrame id="if1" shortDesc="This is an inline frame"
source="#{toolTips.url}"
styleClass="AFStretchWidth"
inlineStyle="height:600px;">
</af:inlineFrame>
</af:panelWindow>
</af:popup>

When you click the goLink, the requested wikipedia page opens in a modal popup.
The users can 'only' return to the application by closing the popup.



Possible extensions to this example.
It is easy and possible to invoke multiple search engines (google, yahoo ....). This example could also be extended by a text box in which the user types a word or sentence which then is forwarded to a search engine. If you know more, don't hesitate to share.
The application used in this blog is available here.

Wednesday, March 31, 2010

ADF 11g Contextual Event Framework: An Example

Often a page or a region within a page needs information from somewhere else on the page or from a different region. While you can pass parameters to obtain that information, doing so makes sense only when the parameters are well known and the inputs are EL-accessible to the page. Parameters are also useful when a task flow may need to be restarted if the parameter value changes.

However, suppose you have a task flow with multiple page fragments that contain various interesting values that could be used as input on one of the pages in the flow. If you were to use parameters to pass the value, the task flow would need to surface output parameters for the union of each of the interesting values on each and every fragment. Instead, for each fragment that contains the needed information, you can define a contextual event that will be raised when the page is submitted. The page or fragment that requires the information can then subscribe to the various events and receive the information through the event.

Events are configured in the page definition file for the page or region that will raise the event (the producer). In order to associate the producer with the consumer that will do something based on the event, you create an event map also in the page definition (when using events between regions, the page definition file which holds both the regions contains the event map).

The Contextual Event Framework in action.

Let’s start with a simple example. Take a look at the following situation: There is a page (PAGE-1) containing two 2 regions (these regions where created by dropping taskflows on PAGE-1). The first region (“edit employees”) will publish an event, and the second region (“show information”) is a subscriber to this event.
In other words, as soon as an event is published by “edit employees”, “show information” will respond to that event for instance by displaying the action performed in “edit employees”.

When the user clicks NEXT, a contextual event with a payLoad parameter is broadcasted by the edit employee task flow. This event is then consumed by the show information task flow and its handler, the getInformationByEmail() method which is derives the Email address.

The situation is shown in this simple diagram:



This example uses an event published by a command button. So how is this example implemented?

Adding an event to a action component.

To implement the above example the next button has to publish an event when the button is pressed by the user. There are two requirements to achieve this functionality. First of all an event has to be available in the producer page (or page fragment). This event can be created in the “contextual events tab” of the overview editor for the producer page definition.

In the Events section, click the Add icon. Now it is possible to enter the name of the event and define the payload data for the event. For example, if you want to pass an attribute value from the producer page to the consumer page, you can select Page Data and select the attribute from the tree structure. In this case the “input value” of the Email field is used, as displayed in this figure:



After creating this event it is not published automatically. There still need for a actual “publisher” So to be able to actually publish the event, it has to be associated by with the NEXT button.
To associate the NEXT button with the event, select the “NEXT” button, open the Contextual Events pane in the Property Inspector, and click the Add icon. Now it is possible to select an existing event. In this case select the “nextButtonPressed” event that was created previously, from the tree structure, as is shown here:



The event is now ready for publishing. In plain code the result of the above actions for the published event looks like this in the pageDefintion file of the “edit employees” page fragment:

 <action IterBinding="EmployeesView1Iterator" id="Next"  
RequiresUpdateModel="true" Action="next">
<events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
<event name="nextButtonPressed"
customPayLoad="${bindings.Email.inputValue}"
eventType="button pressed event"/>
</events>
</action>
…………
</bindings>
<events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
<event name="nextButtonPressed"
customPayLoad="${bindings.Email.inputValue}"
eventType="button pressed event"/>
</events>


Now that the event is published still nothing will happen at runtime because no component has subscribed to the event. Subscribing to the event is pretty straightforward.

Subscribing to an event.

First of all the “subscriber” needs a handler process. In this case the handler method is a method on the application module that returns a valid Email address; getInformationByEmail().
When this handler method is published to the client, it’s output can be dropped on the page fragment as an output text. By doing this a method action is created in the page definition of the information page. Now the action method can subscribe to the event published in the “edit employee” page.
The actual subscribing needs to be configured in the PAGE-1. This is the page where both fragments (“edit employees” and “show information”) are present. In the “page definition” overview tab of PAGE-1 it is possible to select the event to subscribe to. After selecting that event there is the possibility to add a subscription in the “subscribers” tab.
With the “Subscribe to Contextual Event” dialog open the subscription can be configured. Select the producer from the Publisher dropdown list. To add the handler, click the Search icon next to the Handler field and select the event handler (getInformationByEmail) from the tree. Finally add the parameters for the handler method:



What was just described with a lot of words is actually the creation of a very simple publish/subscribe mechanism: There is a published event (NextButtonPressed) that has a payload (email value) which is used as parameter (mailadress) by the subscriber (getInformationByEmail).

This is just a very simple example of what can be done with the Contextual Event Framework. An action component is not the only component that can publish an event. Also components like input components, table components can publish events. Events can also be published from a managed bean, and indirectly from javascript.

Sunday, February 28, 2010

ADF 11g : Label Modifications and Persisting Resource Bundle Changes

In a comment on one of my posts on the AMIS technology blog I had a question on UIComponents. The question was if it is possible to modify prompts and labels of components programmatically. As a matter of fact this is possible. You can do this for the session only, or you can choose to persist these changes. In this post I first explain how to implement the "session only" functionality, and in the second part I explain how to use a persisted resource bundle with immediate refresh.

Application Setup

The application used in this post is based on the HR schema and the business components are created and not changed.

First of all you create a page that is used to hold components of which you want to change labels and prompts. Create two panelboxes next to each other. In the first one drop the employees collection and in the second one drop the child employees collection. Drop both as read only form. When browsing the first box, the second one will show the subordinate employees (if any).



Making the Prompts Adjustable

In order to have full control on the attributes of the panelboxes, you have to bind the panelboxes to a bean.
1:  <af:panelBox text="PanelBox1" id="pb1"  
2: binding="#{componentEditor.firstPanelBox}">
3: ...........
4: <af:panelBox text="PanelBox2" id="pb2"
5: binding="#{componentEditor.secondPanelBox}">
6: ...........

In the componentEditor bean, you now have full control over the properties of the panelboxes. You need a way to enter the new values for the prompts of the panelboxes. We will use a popup for that. Add a popup behavior to both of the panelboxes.
1:        <af:showPopupBehavior popupId="labelEditor"  
2: triggerType="click"/>

Define the popup in the page. In this popup we will also use a button to submit the changes to the server.
1:      <af:popup id="labelEditor">  
2: <af:dialog okVisible="false" title="change texts">
3: <af:panelGroupLayout layout="vertical">
4: <af:commandButton text="change text"
5: actionListener="#{componentEditor.editLabel}"/>
6: </af:panelGroupLayout>
7: </af:dialog>
8: </af:popup>

The next step is to add input components to the popup that you can use to enter the new values for the components' label. For this example we will add two; one for each panelbox.
1:         <af:inputText label="box 1"   
2: binding="#{componentEditor.boxOneLabelValue}"
3: value="test">
4: </af:inputText>
5: <af:inputText label="box 2"
6: binding="#{componentEditor.boxTwoLabelValue}"
7: value="test">
8: </af:inputText>

Note that these two input components are bound to the same bean as all other components. If you invoke the popup you can now enter alternative values for the panelbox' headers.


The code in the backing bean that is invoked when the button is pressed, is responsible for actually changing of the prompts. This code is not very difficult.
1:   public void editLabel(ActionEvent actionEvent) {  
2: // Add event code here...
3: firstPanelBox.setText((String)getBoxOneLabelValue().getValue());
4: secondPanelBox.setText((String)getBoxTwoLabelValue().getValue());
5: AdfFacesContext.getCurrentInstance().addPartialTarget(this.getFirstPanelBox());
6: AdfFacesContext.getCurrentInstance().addPartialTarget(this.getSecondPanelBox());
7: }

When the button is pressed the changes are visible immediately.



Persisting Changes

So far, the changes are only visible during the session. If you need to persist the changes you would need a table to store the values, some ADF-BC objects to do the ORM for you, and some logic in the bean to invoke the save action. Besides that, we will use a class based resource bundle.

First let's create the table. For now keep it simple, but be aware that in real life you could also add languages, userid, pageid's (ID's are unique per page).
1:   CREATE TABLE CUTSTOM_LABELS  
2: (
3: COMP_ID VARCHAR2(32 BYTE) NOT NULL ENABLE,
4: LABEL VARCHAR2(64 BYTE) NOT NULL ENABLE
5: )


Creating Business Components

Add the business components that will be responsible for persisting the changes, by simply creating them via the wizard. While in the wizard, make sure to add the viewobject to the application module as well, as it will be used in the page.


Now select the "CutstomLabelsView" collection from the datacontrol and drop it as a table on the popup.

Creating the Resource Bundle

Create a new class called demoResources that extends ListResourceBundle class.
In this class create a method getContents() to collect data from the database via the binding framework, and add the fetched data to the resource bundle.
1:   public Object[][] getContents() {  
2: DCIteratorBinding labelIter =
3: getBindings().findIteratorBinding("CutstomLabelsView1Iterator");
4: RowSetIterator labelRSI = labelIter.getRowSetIterator();
5: int count = labelRSI.getRowCount();
6: Object[][] theseContents = new String[count][count];
7: Row labelRow = labelRSI.first();
8: boolean firstRow = true;
9: int i = 0;
10: do {
11: if (!firstRow) {
12: labelRow = labelRSI.next();
13: } else {
14: firstRow = false;
15: }
16: theseContents[i][0] = labelRow.getAttribute("CompId");
17: theseContents[i][1] = labelRow.getAttribute("Label");
18: i++;
19: } while (labelRSI.hasNext());
20: return theseContents;
21: }


Preparing the Page

In the page, we have to make sure that the resource bundle is recognized and used.
This can be achieved by using , as is shown in the code fragment below.
1:    <f:view>  
2: <f:loadBundle basename="lucbors.blogspot.demo.view.bundle.demoResources"
3: var="res"/>
4: .............

For all labels that need to be dynamic, create a reference to the resource bundle. In this example we will just use a few. These, and all others, all look like the following example.
1:       <af:panelBox text="#{res['BOX1']}" id="pb1"  
2: binding="#{componentEditor.firstPanelBox}">

You can pick as many components as you like, just as long as the resource keys that you reference are also available in the database table. You might want to consider adding functionality to the application to add resource keys to the table.

The Magic Part

In order to refresh the bundle every time changes are committed to the database, we just add an extra method to the demoResources class. This method, called refreshBundle gets the bundleName as argument, and when invoked, it will force the bundle to refresh. This can be done by invoking the clearCache method on this bundle.
1:   public static void refreshBundle(String bundleName) {  
2: try {
3: ResourceBundle.getBundle(bundleName).clearCache();
4: } catch (Exception e) {
5: System.out.println("Failed to refresh bundle " + bundleName +
6: " due to " + e.getMessage());
7: }
8: }

Now we only need to make sure that necessary code is executed when committing changes to the database. First add an action attribute to the commit button. This action has to invoke a method ( saveAndRefresh() ) in the componentEditor bean.
1:          <af:commandButton text="Commit"  
2: id="cb5" partialSubmit="true"
3: action="#{componentEditor.saveAndRefresh}"
4: actionListener="#{bindings.Commit.execute}"/>

In the saveAndRefresh method, invoke the refreshBundle() method.
1:    public String saveAndRefresh() {  
2: // Add event code here...
3: AdfFacesContext.getCurrentInstance().addPartialTarget(this.getFirstPanelBox());
4: AdfFacesContext.getCurrentInstance().addPartialTarget(this.getSecondPanelBox());
5: demoResources.refreshBundle("lucbors.blogspot.demo.view.bundle.demoResources");
6: return null;
7: }

And now, when running the application, every time changes are made to the custom Labels table, the bundle is refreshed, and the new labels are displayed immediately.


And see how this results in an immediate and persisted change.



Conclusion

The use case in this post is just an example of how to persist resource bundle changes and immediatley see these changes in the application. However, by extending ListResourceBundle class, as I did, you can also add objects to the resource bundle. This could for instance be used to implement some kind of content management functionality that will reflect changes immediately.

The application used in this blog is available here.