Saturday 19 November 2011

Oracle ADF Tutorial


Hi,
 In this post, I am going to build a simple ADF application to get you started with the basics of Oracle Application Development Framework 11g.Oracle ADF is a very powerful tool using which we can build robust enterprise applications very fast.

Oracle ADF is a meta framework i.e. a framework comprised of frameworks.For the front end (i.e. user interface), the ADF Faces framework is used which is an extension of the very popular Java Server Faces framework.For the back end related stuff, it uses the ADF Business Component(ADF BC) framework.Before getting started, we should have the basic understanding of the different components of the ADF BC.

At the heart of the ADF BC lies the Entity Objects, the View Objects and the Application Module.Let us see what purpose they serve.

The Entity Objects can be thought of as the local copy of the database.For now, you can think in the way that each Entity Object instance represents a row in the underlying database.

The View Objects provide a view of the underlying data through the entity objects.Most of the times, view objects are based on Entity Objects which in turn interact with the database.However, it is possible to create view objects which are not based on Entity Objects.In this case however, you cannot create or update any data through the view object.

The application module is the place where you typically write the part of your business logic code which operates on the underlying data.For each use case in your application, you might have a different application module.


In this example, we are going to build a simple JSF page - a simple log in screen to be precise.The log in screen should roughly look like the following sketch:-

When the user enters the username and the password and hits the 'Login' button, the system is going to go to a database table to authenticate the user.If the authentication is successful, the user will be navigated to the welcome scree.Otherwise, the user is going to end up at the error page.

To control the application flow, we are going to see how to use "ADF Taskflow" which is a very important component of the ADF Faces framework.

Without further ado,  let us get started and see how and where all these things fit in.I am using Oracle JDeveloper 11.1.1.5 for this tutorial.If you have a slightly older version, don't worry as the steps are going to be almost same.

First open JDeveloper if it is not already open.Next click on File->new.



In the "New Gallery" that pops up,in the left pane, select the "Applications" node under the "General".On the right pane, select the "Fusion Web Application(ADF)" option and hit "OK".




In the next screen that pops up, enter a suitable application name.To follow along, enter "SimpleLoginApp".Enter an application prefix of your choice.This application prefix name is going to be the root java package name for all the java classes you write.To follow along, enter 'loginapp'.Hit next once you are done.



In the next screen, leave the defaults and hit next.In this step, you instructed JDeveloper to create an ADF BC project automatically.


In the next screen, leave the defaults and hit next.


In the next screen that appears, leave the defaults and hit next.In this step, you instructed JDeveloper to create an ADF Faces project automatically.


In the next screen, accept the defaults and hit finish.



As you can see now in the application navigator, there are two projects namely "Model" and "ViewController" which have been automatically created inside our application.




We should create and keep all the ADF BC related artifacts like Entity Objects ,View Objects, Application Modules etc. in the "Model" project and all the ADF Faces related objects such as JSF pages and Taskflow etc. in the "ViewController" project.

Now, we are going to create a database table.Following is the SQL script for the table.


create table testusers(username varchar2(20) primary key,password varchar2(20));

Next, insert some date:-


insert into testusers values('admin','password1$');
insert into testusers values('admin2','password2$');
insert into testusers values('admin3','password3$');
commit;


Now, we are going to create our data layer i.e. the ADF BC components.To do this, right click on the model project and select "new" from the context menu.




In the left pane, select the "ADF Business Components" node under "Business Tier" and in the right pane, select the "Business Components from Table" option.Hit OK once you are done.


In the next screen that pops up, click on the green plus sign beside the Connection to create a new database connection(If you already have a database connection configured, then you can select that by clicking on the magnifying glass icon).


The "Create Database Connection" screen will appear.Enter a name for your connection.To follow along, enter "DBConn".Enter the other details as per your environment.Hit  the "Test Connection" button once you are done.If all goes well, a success message is going to be displayed.Hit OK once you are done.


In the first screen that appears, you are asked to select the tables which you want to base your entity objects on.To do this, click on the "Query" button as indicated in the image below:-



Once you hit the "Query" button, the list of tables will appear.Select the "testuser" table and shuttle it to the right by clicking on the single arrow button.Hit next once you are done.



In the next screen, we are going to create our view object.This view object is based on the entity object that we created in the previous step.Shuttle the "Testusers" entity object to the right side.Hit next once you are done.


In the next screen, you are asked to create "Read Only" view objects.We do not require any for this application.Just hit next.


In the next screen, you are asked to create a default application module.Accept the defaults and hit finish.


So, we have created the basic ADF BC components needed for our application.

In the next step, we are going to write a method in our application module which checks whether the user exists in the database or not.To do this, we must generate the java classes for our applicatin module.To do this, right click on the Application Module and select the "Open AppModule" option.Alternatively, you can double click on your application module:-


Next, go to the "Java" tab and click on the pencil icon beside the "Java Classes" as indicated in the image below:-



In the window that pops up, select the "Generate Application Module Class" option and hit OK.We are not going to generate the definition class.Typically, you won't need to work with the definition class.



Now, int application navigator on your left, expand the "Applica tion Module" node and you will the java class has been generated.Double click on it to open it.Alternatively, you can right click on the java file and select the "Open" option.



Add the following method to the class:-


  public boolean isExistingUser(String userName,String password){
      try {
          ViewObjectImpl vo = getTestusersView1();
          RowSetIterator itr = vo.createRowSetIterator(null);
          while (itr.hasNext()) {
              Row row = itr.next();
              if (row.getAttribute("Username").equals(userName) &&
                  row.getAttribute("Password").equals(password)) {
                  return true;
              } //end if


          } //end while
      } catch (Exception e) {
          e.printStackTrace();
      }
      return false;
  }


The code is very simple.We create a RowsSetIterator on the view object in order to loop through all the rows and check for the existing user.Pay attention to how we have create the RowSetIterator:-

      RowSetIterator itr = vo.createRowSetIterator(null);


The "createRowSetIterator" method takes a string parameter which specifies the name of the iterator.Save the changes.

The method that we have written here has to be exposed to the clients.Unless we expose it, outside code can not access this method.To do this, open the "Application Module" and go to the "Java" tab.Next,  click on the pencil shaped button beside the "Client Interface" as indicated in the image below:-



In the "Edit Client Interface" window, shuttle the available method i.e. the "isExistingUser" method to the right side.Hit OK once you are done.


You will be able to see the method under the "Client Interface" section.Save the changes.



So we are done.Next we are going to test our ADF BC layer.To do this, right click on the application module and hit Run:-

 


Sometimes you might see the exception saying that the timezone is not set.In case you get this exception, right click on your "Model" project and select "Project Properties".


In the "Project Properties" window, select the "Run/Debug/Profile" node in the left pane.Under "Run Configurations", select the "Default" node and hit "Edit".


In the next screen, enter the following as java options:-

 -Duser.timezone="+5:30"




Hit OK two times to dismiss all the windows.



Now run the application module.You won't see the exception this time around.


JDeveloper provide you a swing based GUI to test the behaviour of your ADF-BC objects.You should always verify that your ADF BC objects behave in the way expected before using them in your pages.In the
"Oracle Business Component Browser" window which pops up once you run the application module, double click on the "TestusersView1" node in the left pane under the "AppModule" node:-


A new screen will appear.Using the various buttons at the top, you can perform various operations like navigating through the rows, adding new rows, deleting rows,commit etc.Take sometime to make yourself comfortable with the "Business Component Browser".

Next, we are going to test the method we created.To test that, double click on the "AppModule" node in the left pane.A new screen will appear.Provide the parameter values and hit "Execute".


Notice that the Result is success indicating that the method was executed successfully.The return value is "false" as we had entered wrong username and password.Also test the method with a valid username and password.The value returned will be true.



Dismiss the "Business Component Browser" once you are done with the testing.Now, we are all set to build our page.

First, right click on your "ViewController" project and select the "New" option from the context menu.



In the "New Gallery", in the left pane, select the "JSF" node under the "Web Tier".On the right pane, select the "JSF Page" option and hit OK.


Enter "login.jspx" as the File Name.Leave the other defaults and hit OK.


A new blank page will open up.Now, recall the screen sketch:-

To achieve this,we are going to use layouts.ADF layout components are a very powerful and flexible way to layout various components of a JSF page.It takes a little time to get used to using layout components.First, make sure the component palette is visible on the right side.If it is not visible, click on View->Component Paletter to bring it up.At the top of the component palette,make sure that the "ADF Faces" is selected in the dropdown.


Next, expand the "Layout" accordion and locate the component "spacer".


Next drag the "spacer" component from the component palette onto the page.

The structure and the property inspector window plays a very important role.Make sure they are visible.If they are not visible, go to view and click on structure window and properties window respectively to bring them up.By default the property inspector is visible on the right bottom and the structure window is visible in the bottom left.



Select the spacer node on the structure pane as indicated in the image below.


In the properties window,change the height property from 10 to 180 for the "spacer" and hit enter.


Next, we are going to use our first layout component - the panel group layout. The panel group layout is used to group a set of elements vertically or horizontally.(For example, you might want to put three buttons side be side  in a single row.For this, we can use the panel group layout, set the layout property for the panel group layout to horizontal and put the buttons inside the panel group layout and this will do the trick.)

 To insert a panel group layout, we could drag and drop it from the component palette onto the page.But this approach becomes very tedious when you have a significant number of components already laid out and you want to place the new component after a certain component or in between two components.For this, JDeveloper provides us with another option which we are going to see now.

 Go to the structure panel and right click on the spacer component.Next, hover your mouse over the "Insert after af:spacer...." menu item.In the sub-menu, there is a good chance that you will be able to see the "Panel Group Layout" component.If you see it, click on it and the component is going to be inserted just after the "spacer" element.


However, if you do not see the "Panel Group Layout" in the sub-menu, click on the "ADF Faces" menu item.A new window will open.Scroll down and select the "Panel Group Layout" component and hit OK.



.
Next, on the application navigator, expand the "Data Controls" accordion.Under data controls, expand the "AppModuleDataControl" node.Under this, expand the "TestUserView1" node.Under this node, you will see the node "isExistingUser" which represents the method that we wrote and exposed through the application module.Drag and drop the method from the "Data Controls" window onto the page
 inside the "Panel Group Layout".A menu will pop up.Select the "ADF Paramater Form" option.





The data controls server as an extra layer of abstraction between the front end and the back end.It is frequently referred to as the model layer.When you drag and drop components from the data controls, connections are created which binds the front end controls to the relevant attributes.These connections are known as bindings. Through this binding, the front end accesses the data which lies at the back end.Each time you drag and drop a component from the data control


You will see that two input text boxes and a button is created.Bring up the structure window and select the "Panel Group Layout" component.Go to the properties window(If it is not visible, then go to view->Property Inspector to bring it up) and select the layout as horizontal.





Next for the panel group layout set the Halign property to "center".The screen should look like the following image.







So we are done with the design and the page is not that bad! Now we shall create a managed bean for our application.A managed bean is a POJC.Using a managed bean, we can have programmatic control on our page components.Let us see how it is done.

In the structure window, select the first input text box inside the panel box.Next go to the property inspector and locate the "Binding" property.Click on the arrow sign just beside the "Binding" property.





In the window that pops up,select the "Edit" option.




The "Edit Property: Binding" window will pop up.For the first time, we will have to create a managed bean.Click on the "new" button.




In the "Create Managed Bean" window, enter the details.To follow along, enter "TestMBean" as the "Bean Name" and "TestMBean" as the class name.Enter "loginapp.mbeans" as the package name.Leave the other defaults.Make sure the "Generte Class If  It Does Not Exist" check box is checked.Hit OK once you are done.




Once you hit OK, the managed bean class will be created and you'll be brought back to the "Edit Property:Binding" window.Now we shall create a new proprty for our input text.Hit the "New" button beside the "Property" drop down.In the create property window that pops up, enter a name of your choice.To follow along, enter "itUserName".





Hit OK once you are done.Back in the "Edit Property:Binding" window, hit OK.Click on Save all to save the changes.




Let us see what has happened on the back end for all the actions we did in the previous step.First, go to the application navigator and double click on the "adfc-config.xml" file to open it.Once it is open, click on the overview tab at the bottom.In the overview page, click on the "Managed Beans" tab on the left.You will be able to see the managed bean that we created in the previous step is declared here.We can also add managed beans from here by clicking on the green plus icon at the top right corner.However, we shall have generate the managed bean class manually.





Next, let us see the ManagedBean class.Go to the application navigator and double click on the "TestMBean.java" file to open it.



You will see an instance variable "itUserName" and it's getter and setter methods.This instance variable represents the user name input text box.

Let us create a binding for the password this time.To do this, select  the password input text in the structure window and go to properties window.Next click on the arrow sign next to the "Binding" property like before.Click on "Edit" in the window that pops up.In the "Edit Property:Binding" window, select the "TestMBean" from the "Managed Bean" drop down.




Next, we shall create a new property for the password input.So click on the "New" button and enter a name for the new property.To follow along enter, "itPassword".Hit OK twice.Click on "Save all" to save the changes.Verify by opening the managed bean whether the new property has been added or not.


  Our next task will be to create a method which gets invoked whenever the button "isExistingUser" gets clicked. Remember that we created this button by dragging and dropping the method that we created inside our application module.So whenever this button gets clicked, the method that we wrote inside the application module i.e "isExistingUser"  gets invoked automatically.

 To create a method whenever the button "isExistingUser" is clicked upon, double click on the "isExistingUser" button.In the "Bind Action Property" window, select the "TestMBean" from the "Managed Bean" drop down.Next, enter a suitable name for the method.To follow along, enter "cbValidateUser_action".Make sure you check the "Generate ADF Binding Code" option.This will generate the code which calls the application module method.Hit OK once you are done.Click on "Save all" to save the changes.




Next, go to the "TestMBean" class.You will see a method "cbValidateUser_action" has been  created.



Notice how an operation binding is created to the method inside the application module i.e. isExistingUser.If we remember correctly, the method "isExistingUser"  has two string parameters.We shall have to write the code to pass those parameters and process the result.

Replace the code inside the method "cbValidateUser_action" with the following code:-

        String userName=itUserName.getValue().toString();
        String password=itPassword.getValue().toString();
        BindingContainer bindings = getBindings();
        OperationBinding operationBinding = bindings.getOperationBinding("isExistingUser");
        Map parameters=operationBinding.getParamsMap();
        parameters.put("userName",userName);
        parameters.put("password",password);
        Object resultObj = operationBinding.execute();
        boolean result=(Boolean)resultObj;
        if(result==true){
          return "valid";
        }
        return "invlid";



Notice how we are passing the parameters.We have first obtained the parameters map using the "getParamsMap" method of the OperationBinding and then creted the key value pairs.Notice that the keys must match the parameter names of the method "isExistingUser".

Another thing that we have changed is that we are returning a string instead of null.What is the purpose of this? We will see soon.

Next, we are going to take a look at the basics of ADF Task flow.As the name indicates, through ADF task flows we can control the flow of our applications.If you are familiar with JSF, then you can think of ADF task flow as an extended version of JSF page flow.

In the application navigator, double click on the "adfc-config.xml" file to open it(If not already open).Click on the "Diagram" tag at the bottom.(If not already selected)




Next, from the component palette drag and drop a view onto the task flow screen.Once you drag and drop a view onto the taskflow, it will prompt you for a name.Enter a suitable name.To follow along, enter "login" and hit return.





A view in the task flow represents a "JSP" or "JSPX" page.Next click on the view object in the task flow to select it and go to the property inspector.Click on the button just beside the page property as indicated in the following image:-




In the window that pops up, select the "login.jspx" page and hit OK.




Next drag and drop another view object from the component palette onto the pageflow screen.Name it "welcome".Double click on the "welcome" view.The "Create JSF Page" window will pop up.Leave the defaults and hit OK.






In the previous step, we just created a new jspx page.Follow the same. steps and drag and drop another view object onto the page.Name it "error" and generate the page for it like earlier.Click  on save all to save the changes.The taskflow will look like the following image:-




Next we are going to specify control flow cases.To do this,first click on the "Control Flow Case" in the component palette.Next, click on the "login" view and then click on the "welcome" view.You will see an arrow is created.You will be prompted for a name.Enter "valid" and hit enter.




Follow the same set of steps to create another control flow case;this time from "login" to "error" and name it "invalid".The taskflow will look like the following image:-







Next open the "welcome.jspx" by double clicking on the "welcome.jspx" from the application navigator.


 


Next drag and drop an output text from the component palette onto the jspx page.Set the value property to "welcome user".








Similarly for the "error.jspx" page, create an output text and set the value to the "error".

  Now let us see how the task flow works.When you click on a command button, the page navigation happens as per the value of the action property for that button.If the action property is set to null, the
 flow returns to the same page.We can specify a simple string for the action property or a method as we did in this case.If we specify a simple string, then the navigation will happen as per the value.For example, had we specified the string "valid" for the "action" property of the "isExistingUser" button, then the flow will always go to the "welcom.jspx" page (As we named the control flow case from login view to welcome view as "valid" in the "adfc-config.xml").

  In this case though, we have specified a method and the returned value from the method is used to evaluate the page navigation.

Before running the application, we shall have to make a small change.The password field should not show the characters being entered.To achieve this, in the structure window, select the password input text.Next in the property inspector, set the "secret" property to "true".




Next, select the button "isExistingUser" in the structure window and go to the property inspector.In the property inspector, set the "Text" property for the button to "true".






The application is complete.Next, we shall test it.To do this, in the application navigator, right click on the jspx page and select "Run" from the context menu.



Once the page opens, enter a valid username/password pair which is present in the "testusers" table.Once you click the "login" button, the welcome page is going to be displayed.If you  provide an invalid username/password, you are going to be navigated to the error page.

2 comments:

xslt padding with characters call template for left pad and right pad

  Could a call-template be written that took two parameters ?   a string, and a   number) return the string with empty spaces appended t...