25 Dec 2011

Task Flow Exception Handler. You must have it.

Introduction

Defining Exception handlers in your task flows is not only a good practice of ADF development.
Ignoring this practice can get you in some big problems, you will get unpredictable and difficult for understanding behavior of the system like Null Pointer Exceptions in trusted places or system's hanging.
Some time ago I faced a "performance" problem of ADF application. About a hundred of users (it's not too much load for that environment) were working with the system and it "hanged" every 20 minutes. A lot of performance tunings didn't help. There was a bug. One important Task Flow didn't have an exception handler.

Experiments
Let's say we have very simple bounded train task flow:
The task flow is executed as a region within some jspx page and it doesn't have an exception handler. NextView page fragment has the following source:

 <af:panelFormLayout>
  <af:group id="g1">
   <af:train id="pt_t2"
    value="#{controllerContext.currentViewPort.taskFlowContext.trainModel}"/>
   <af:commandButton text="Commit" id="cb1" action="*Commit"/>
   <af:commandToolbarButton text="Back" id="pt_cb1"
    action="#{controllerContext.currentViewPort.taskFlowContext.trainModel.getPrevious}"
    disabled="#{empty controllerContext.currentViewPort.taskFlowContext.trainModel.previous}"
    rendered="#{! empty controllerContext.currentViewPort.taskFlowContext.trainModel.previous}"
    immediate="true"/>

   <af:commandToolbarButton text="Forward" id="pt_cb2"
    action="#{pageFlowScope.WizzardFlowBean.nextButtonAction}"
    disabled="#{empty controllerContext.currentViewPort.taskFlowContext.trainModel.next}"/>
  </af:group>
 </af:panelFormLayout>

And it looks like this:

 
Managed bean method for BadCall activity has the following code:

    public void badCall() {
        int i = 1/0;
    }

In this example the situation is not very dangerous. We will just get the unsupported exception window like this:



But the system is still stable and is working correctly. We can click Back button, we can navigate using af:train at the top of the page. Andrejus Baranovskis explained in his blog how to define exception handler for the task flow to make the exception be caught and rendered correctly.

In the next experiment let's call our task flow from another one. So, let's make it inner.


In this scenario the same Arithmetic exception will crash the system. If we try to click Back button after the exception window, we will get Null Pointer Exception. Why???

The reason is in the controller's exception handling mechanism. In case of an exception during navigation within task flow it tries to find and execute an Exception Handler of the current task flow. If the current task flow does not specify an exception handling activity then the task flow will be popped from the task flow stack and control passed to the calling task flow's exception handler.  This process is continued until an exception handler is located or until all task flow's have been checked. So, in our example, when we don't have any exception handlers at all, our task flow (emp-flow-definition) is just popped out from the calling stack, control is passed to the calling flow, and the exception is thrown. That's why EL expression for Back button's action #{controllerContext.currentViewPort.taskFlowContext.trainModel.getPrevious}" will throw NPE. Current task flow at that moment is calling task flow, but we see the inner task flow on the screen. And off course calling task flow doesn't have any train model.

The situation is even worse. If we try to navigate using af:train, the system will hang!!! We will get a stuck thread!!! EL evaluator doesn't like when complex EL expression containing null values and it sometimes hangs instead of throwing exceptions like NPE. If we define any exception handler in our task flow  the problem is gone. It even doesn't matter what it does. It is just needed  by controller's exception handling mechanism.

Instead of adding exception handler to the inner task flow we can try to add it the calling task flow. And if this handler is just some method call activity without navigating to any View activity, we will face the same problem, because we will still see on the screen "dead" task flow.

So the solution is either to add any exception handler to the inner task flow or to add some handler with a navigation to a view activity to the calling task flow. But! The simplest and the most correct rule - don't have any task flows without exception handlers!


That's it.



11 Dec 2011

Dynamic ADF Train. Showing train stops programmatically.

In one of my previous posts I showed how to create train stops programmatically. And I got a comment with a question on the post - "Is it possible to show different pages on each of the dynamic train stop?". The answer is - Yes, off course!
In this post I'm going to give an example of showing train stops programmatically. So, I need to show or hide some stops dynamically at runtime. Everybody knows that TrainStop has Ignore attribute

 
And if we could dynamically change it's value or put there some EL expression that could be evaluated during the taskflow's life cycle, It would be the best approach of showing/hiding train stops at runtime. But Ignore attribute is evaluated only once, at the task flow initialization phase and cannot be modified further.  But! As it was shown in this post we can programmatically add (or remove) train stops to the train model of the task flow. So, we can do it!

Let's say I've got the following train TaskFlow:


PassenerView activity, LuggageView and MealView  by default have <ignore>true</ignore> attribute and at the very beginning, after task flow initialization, are hidden. The train model doesn't have stops for these activities. On the first stop of the task flow I'm going to decide which activity should be included in the train and which one is hidden. On the task flow initialization I call the following managed bean method:

    private static String START_VIEW = "StartView";
    //Fill map with all activities of the TaskFlow
    //except StartView
    private void InitIgnoredStops() {
        for (Iterator it= getTaskFlowDefinition().getActivities().values().iterator(); it.hasNext();) {
          Activity act = (Activity) it.next();
          if (!START_VIEW.equals(act.getIdAttribute())) {
                ignoredStops.put(act.getId(), "false");
            }

        }
        
    }

The ignoredStops map is shown on the StartView page using techniques explained in this post. So, I have the following page:



The following method is called on Submit button's action:

public String buttonPress() {

    TrainModel trainModel = TrainUtils.findCurrentTrainModel();

    //Loop over the map
    for (Object actid : ignoredStops.keySet().toArray()) {
        //If activity is not chosen 
        if (!Boolean.parseBoolean(ignoredStops.get(actid).toString())) {
            // if activity is included in the train then remove it
            if (trainModel.getTrainStops().get(actid) != null)
                 trainModel.getTrainStops().remove(actid);
        } else {
            //If activity is chosen and it is not included in the train 
            // then we need to include it
            if (trainModel.getTrainStops().get(actid) == null) {
                MetadataService metadataService =
                    MetadataService.getInstance();
                
                //Get activity and its train stop definition
                Activity activity =
                    metadataService.getActivity((ActivityId)actid);                
                TrainStopContainer stopContainer =
                        (TrainStopContainer)activity.getMetadataObject();
                TrainStop ts = stopContainer.getTrainStop();
                
                
                //Create new train stop model and add it to the train
                trainModel.getTrainStops().put((ActivityId)actid,
                                                   new TrainStopModel(ts,
                                                                      (ActivityId)actid));
                }
            }


        }
    
}

If needed activities are chosen we can press Submit  button and get the following picture:




That's it!

13 Nov 2011

Working with af:iterator and HashMap values

In this post I'm going to show a couple of examples of using af:iterator component to render HashMap values. Let's say in my managed bean I have the following HashMap:
private Map m = new HashMap(); {
m.put("One",true);
m.put("Two",false);
m.put("Three",true);            
} 

The issue is to render selectBooleanCheckbox for each entry of the map.

In the same manged bean I've got the following getter method:
    public Object[] getMapEntries() {
       return m.entrySet().toArray();
   }

The method returns map's entries as an array. In the jspx code we are going to iterate over this array using af:iterator:
 <af:iterator value="#{ManagedBean.mapEntries}"
              var="row">

        <af:selectBooleanCheckbox text="#{row.key}"
                                 id="sbc2" value="#{row.value}"/>          
 </af:iterator>

And ... probably... that's all. But that would be Ok if we just wanted to render HasMap values in read only mode.

In order to be able to modify HashMap values we can use a little bit different approach. So, in the managed bean we have the following method:
    public Object[] getMapKeys() {
       return m.keySet().toArray();
   }

The method returns an array of the map's keys. And in jspx code we access to the map entries directly using key values:
 <af:iterator value="#{ManagedBean.mapKeys}"
              var="row">

        <af:selectBooleanCheckbox text="#{row}"
                                 id="sbc2" 
                    value="#{ManagedBean.map[row]}"/>          
 </af:iterator>

For sure, the managed bean should have getter method for the map like this:
    public Map getMap() {
       return m;
    }

That's all!

11 Sep 2011

WebLogic. Wrapping data types.

Some time ago I faced the problem with WebLogic feature of wrapping complex Oracle data types. Let's say I have a stored procedure in the database:

create or replace procedure testArrayProc
(aID Number,
 aArray out TNumberTable
 )
and TNumberTable is a collection type with the following definition:

create or replace type TNUMBERTABLE as table of Number;

Please note, aArray is an out parameter. In my model I  have the following code to call the procedure:
        DBTransactionImpl dbti = (DBTransactionImpl)getDBTransaction();
        CallableStatement statement =
            dbti.createCallableStatement(("BEGIN " + "testArrayProc(?,?);" +
                                          "END;"), 0);
        try {
            statement.setLong(1, new Long(1));
            statement.registerOutParameter(2, Types.ARRAY, "TNUMBERTABLE");
            statement.execute();
            ARRAY ar = (ARRAY)statement.getArray(2);
            for (long i : ar.getLongArray()) {
                //do some work
            }

        } catch (SQLException sqlerr) {
            throw new JboException(sqlerr);
        } finally {
            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException closeerr) {
                throw new JboException(closeerr);
            }
        }

The code used to work fine since I used JDBC URL connection type for my Application module. In such case I worked directly with Oracle JDBC drivers and everything was perfect. But when I created JDBC datasource on the WebLogic server and changed the connection type, I got the following exception in the same piece of code:
  weblogic.jdbc.wrapper.Array_oracle_sql_ARRAY cannot be cast to oracle.sql.ARRAY

Investigating the problem, I found out that WebLogic wraps complex data type parameters Arrays, Blobs, Clobs, NClobs, etc. with its own classes like weblogic.jdbc.wrapper.Array and for sure it can not be converted to oracle.sql.ARRAY. But my application as well as the code above are supposed to work not only on WebLogic. Other application servers (I've worked with) don't have any wrappers and allow the applications to work directly with drivers.
In WebLogic 10.3.4.0 (it comes as integrated server for JDeveloper 11.1.1.4.0) I found very useful checkbox Wrap Data Types. It is located at the Connection Pool tab of the datasources' settings in Advanced section. And it's possible to turn it off! According to the documentation this option allows features like debugging and connection usage to be done by the server, but turning it off can improve performance and in some cases significantly. Great! After turning the option off, my code started to work again.
Earlier versions of WebLogic don't have this wonderful checkbox, so you cannot switch the wrapping off (or may be you can, but I don't know how). But never mind, you always can modify the code to look like this:

        DBTransactionImpl dbti = (DBTransactionImpl)getDBTransaction();
        CallableStatement statement =
            dbti.createCallableStatement(("BEGIN " + "testArrayProc(?,?);" +
                                          "END;"), 0);
        try {
            statement.setLong(1, new Long(1));
            statement.registerOutParameter(2, Types.ARRAY, "TNUMBERTABLE");
            statement.execute();
            ARRAY ar = null;
            Object someArray = statement.getArray(2);
            if (someArray instanceof weblogic.jdbc.wrapper.Array)
                ar =
 (oracle.sql.ARRAY)(((weblogic.jdbc.wrapper.Array)someArray).unwrap(Class.forName("oracle.sql.ARRAY")));
            else
                ar = (oracle.sql.ARRAY)someArray;

            for (long i : ar.getLongArray()) {
                //do some work
            }

        } catch (SQLException sqlerr) {
            throw new JboException(sqlerr);
        } catch (ClassNotFoundException e) {
            throw new JboException(e);
        } finally {
            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException closeerr) {
                throw new JboException(closeerr);
            }
        }

That's all. Thanks.

21 Aug 2011

How to apply View Criteria programmatically

Sometimes it could be handy to apply view criteria dynamically at run time.  Let's say I have a simple VO EmployeesView representing data from Emloyees table in HR schema. The VO has view criteria SalaryCriteria:


The criteria filters records with some salary value using bind variable "salary".  On my jspx page I have a table , inputText for salary value and a button:



By default the VO doesn't have any view criteria applied, but when the button is pressed, SallaryCriteria is to be applied with submitted value for salary bind variable. The button's action listener actually calls very simple method in EmployeesViewImpl class:

    public void applySalaryCriteria(Number salary) {
      setsalary(salary);
      setApplyViewCriteriaName("SalaryCriteria");
      executeQuery();
    }


In this use-case I don't have any af:query component on my jspx page and all the job of applying view criteria is going to be done in the model layer.
But there is another use-case when I have af:query on a page and I need to change selected criteria in af:query's component programmatically at run time. In my managed bean I have the following piece of code:

    private RichQuery queryPnl; //Bounded af:query

    //Looking for query descriptor in a list with specified query name
    private QueryDescriptor getQueryDescriptor(List<QueryDescriptor> list, String queryname) {
        QueryDescriptor result = null;
        for (Object qd: list.toArray()) 
            if (((QueryDescriptor) qd).getName().equals(queryname)) result = (QueryDescriptor) qd;
        return result;           
    }
    
    //Selecting criteria with specified name
    private void  selectCriteria(String criteria) {
        QueryModel model = queryPnl.getModel();

        //Looking for needed query decriptor  
        QueryDescriptor qd = getQueryDescriptor(model.getSystemQueries(),criteria);

        //Setting needed query descriptor as current one
        queryPnl.setValue(qd);        
        model.setCurrentDescriptor(qd);
    }


So, when I need to change selected criteria I call selectCriteria method  with specified criteria name. And if I need to apply the criteria and execute the query I call applyCriteria method:

    private void applyCriteria(QueryDescriptor qd) {       
        //Creating new QueryEvent
        QueryEvent queryevent = new QueryEvent(queryPnl, qd);
        
        //And processing this event
        //EmpCriteriaQuery is ID attribute of the searchRegion tag in the pageDef
        invokeMethodExpression("#{bindings.EmpCriteriaQuery.processQuery}",
            Object.class, new Class[]{QueryEvent.class}, new Object[]{queryevent});
    }
    
    //Just utility method to invoke EL expressions 
    public Object invokeMethodExpression(String expr, Class returnType, Class[]  argClasses, Object[] arguments){   
      FacesContext fc = FacesContext.getCurrentInstance(); 
      ELContext elc = fc.getELContext();
      ExpressionFactory exprFactory = fc.getApplication().getExpressionFactory(); 
      MethodExpression methodExpr = exprFactory.createMethodExpression(elc,expr,returnType,argClasses);    
      return methodExpr.invoke(elc,arguments); 
     }

That's all!

7 Aug 2011

Panel Form Layout and Labels with Icons

We often use panelFormLayout component as a standard approach to align our input controls and their labels on our pages. According to the documentation the component usually contains ADF Faces input components whose names start with 'input' (like inputText and inputDate) and components that start with 'select' (like selectOneChoice, selectBooleanRadio, and selectManyChoice).  When more complex field content is needed, we should use a panelLabelAndMessage around the content. In such case panelFormLayout draws the label on the left side and all the content of the panelLabelAndMessage on the right side. Sometimes we need to have an icon rendered before the label. There are two predefined icons we can get rendered before the label using  panelLabelAndMessage  and its attributes showRequired and changed.
So, in case of showRequired=true  it looks like this:


And in case of changed="true" it looks like this:

 
But when we need our custom icon to be rendered, we use  panelLabelAndMessage's attribute labelStyle. The attribute is used to provide a custom CSS style for the "label" part of the panelLabelAndMessage component. So, in order to get our custom icon rendered we will use the following piece of code:

<af:panelLabelAndMessage label="Label With Icon" id="plam1"
   labelStyle="background: transparent url(UA.png) no-repeat center left;
               padding: 3px 0 1px 18px;">
   <af:inputText id="it2" simple="true"/>
 </af:panelLabelAndMessage>

And it looks like this:


16 Jul 2011

Using attribute's custom properties in model layer

Sometimes we need to change properties of the VO's attributes dynamically at run time, depending on some business logic. Sometimes we need  to pass some extra information from the model layer to the view layer. We can use attributes' custom properties.

For example, I need to change attribute's label and make it readonly on the fly. In my ViewObjectImpl class I have the following method:

 public void setCustomHints() {      
     AttributeDefImpl attr = ((AttributeDefImpl) findAttributeDef("DepartmentName"));
     attr.setProperty("customLabel", "The custom label");
     attr.setProperty("readonly", Boolean.TRUE);
 }

The setCustomHints method is going to be executed on a commandButton's action. And the  jspx page contains the following piece of code:

          <af:inputText value="#{bindings.DepartmentName.inputValue}"
                       
                        label="#{bindings.DepartmentName.hints.customLabel}"
                        readonly="#{bindings.DepartmentName.hints.readonly}"
                       
                        columns="#{bindings.DepartmentName.hints.displayWidth}"
                        maximumLength="#{bindings.DepartmentName.hints.precision}"
                        shortDesc="#{bindings.DepartmentName.hints.tooltip}"
                        id="it4" partialTriggers="cb1">
            <f:validator binding="#{bindings.DepartmentName.validator}"/>
          </af:inputText>
          <af:commandButton actionListener="#{bindings.setCustomHints.execute}"
                            text="setCustomHints"
                            disabled="#{!bindings.setCustomHints.enabled}"
                            id="cb1"/>

Additionally, I set up default values for customLabel and readonly custom properties at the VO's definition page:


And finally, we've got the following result:













The sample application for this post is available.

2 Jul 2011

How to use preRenderComponent event in JDev11g R2

There is very common use case when we need to do some preparation work on initial page rendering. For example, we need to do some initialization stuffs like displaying error messages or disabling/enabling tool buttons depending on the model's state and so on. As usual we create some phase listener or implement BeforePhase  event of the f:view tag. The issue is getting more complicated for task flows with page fragments. Page fragments don't have the f:view tag.
JDeveloper 11g R2 allow us to resolve the issue in elegant and easy way. JSF 2.0 specification supports new f:event tag. It has two simple attributes: type and listener. We can attach f:event tag to any of the page's components meaning the component listens to the event of the specified type and in case of event firing calls correspondent listener provided by some EL expression in the listener attribute.There are some predefined event types: postAddToView, postValidate, preRenderComponent, preValidate. Let's focus on  preRenderComponent event. It fires exactly before rendering the component. In the following example we have commandButton with preRenderComponent event listener. The listener enables or disables the button depending on some conditions:

    <af:commandButton text="commandButton 1" id="cb1">
      <f:event listener="#{managedBean.listenForEvent}" 
               type="preRenderComponent"/>
    </af:commandButton>

And implementation of the listener looks like this:

    public void listenForEvent(ComponentSystemEvent componentSystemEvent) {
        UIComponent cb = componentSystemEvent.getComponent();
        if (cb instanceof RichCommandButton)
            ((RichCommandButton) cb).setDisabled(getSomeCondition());
    }

19 Jun 2011

Using UI Categories with Dynamic form

JDev 11g R2 has new interesting feature "UI Categories". It allows us to group VO's attributes declaratively at the view object definition level. For example, "UI Categories" tab for my  VEmployees view object looks like this:

 
By default every view object has one predefined category "Default". I created three new categories "Name", Contact, Other and assigned attributes to them. At this tab we can also define Label and Tooltip for our categories. In the Application Module Tester window it looks like this:


According to the documentation UI Categories should be utilized by Dynamic forms and Search forms. ADF Faces Dynamic Form component really has new attribute Category. The form filters VO's attributes and shows only attributes of the specified category. For example, if I wanted to show attributes of the Name category, I would use the following construction:

          <dynamic:form value="#{bindings.VEmployeesIterator}" id="f3" 
                        category="Name"/>
So, if we want to show different categories separately, we have to use <dynamic:form tag for each category. But the documentation provide very interesting sentence "In the case of dynamic forms, the attributes from each category will appear in a separate tab". I guess that we are expected to implement this feature by ourselves :). In this post I'm going to show how we can do it.


In the implementation class of my view object I defined some API method to get all UI Categoties of the view object except default one:

    public List<Category> getAttrCategries() {
        return getOrderedCategories(false, //except Default
                                    CategoryType.ATTRIBUTE, null); 
    }


In order to draw tabs on the page for each UI Categogry I used the following jspx code:

       
             
                
            
       
    

So, in this simple construction I use forEach tag within navgationPane to draw commandNavigationItem for each category. The Java code of the MainDynamicBean managed bean looks like this:

    //Currently selected tab
    private String selectedItem;

    //Getting categories list
    public List<Category> getCategoryList() {
        return (List<Category>) resolveExpression("#{bindings.VEmployeesIterator.viewObject.attrCategries}");
    }
    
    //Just a setter
    public void setSelectedItem(String selectedItem) {
        this.selectedItem = selectedItem;
    }

    //Getting selected item
    public String getSelectedItem() {
        //If nothing is selected, then select the first one
        if (selectedItem == null) {
            List<Category> l = getCategoryList();
            if (l.size()>0) selectedItem =  l.get(0).getName();                
        }        
        
        return selectedItem;
    }

    //Resolving EL expressions
    public static Object resolveExpression(String expression) {
           FacesContext facesContext =  FacesContext.getCurrentInstance();
           Application app = facesContext.getApplication();
           ExpressionFactory elFactory = app.getExpressionFactory();
           ELContext elContext = facesContext.getELContext();
           ValueExpression valueExp = 
               elFactory.createValueExpression(elContext, expression, 
                                               Object.class);
           return valueExp.getValue(elContext);
       }

And finally, I use the following construction to draw Dynamic form with attributes of the selected category:
   <dynamic:form value="#{bindings.VEmployeesIterator}" id="f2"
                  binding="#{MainDynamicBean.dynform}"
    forceRefresh="#{MainDynamicBean.needRefresh}"/>

And appropriate piece of Java code:
    private DynamicForm dynform;
    
    //Setter
    public void setDynform(DynamicForm dynform) {
        this.dynform = dynform;
    }

    //Getter
    public DynamicForm getDynform() {
        return dynform;
    }
        
    public Boolean getNeedRefresh() {
        //If selected category is not equal to dynform's category
        //then set needed category and refresh the dynamic form
        if (dynform.getCategory()!=getSelectedItem()) {
           this.dynform.setCategory(getSelectedItem()); 
           return true;
        }
        else return false;              
    }

As the result of our work we get the following screens:


That's all!
You can download sample application for this post. 

3 Jun 2011

Using Pipelined functions in View Objects

In this post I'm going to show how we can use Oracle pipelined functions feature to retrieve data from database in the model layer of our ADF application.
Let's assume I have the following function in database:

create or replace function getEmployees
(aDepartmentID Number)
return empTable
PIPELINED
as
begin
  for rec in (select Employee_ID, First_Name, Last_name
              from employees
              where Department_ID = aDepartmentID) loop
    pipe row(new empRow(rec.Employee_ID, rec.First_Name, rec.Last_name));
  end loop;
  return;
end;

The function returns a collection of employees for some department. The return type empTable is declared as table of some object type empRow:

create or replace type empTable as table of empRow;

create or replace type empRow as object (
 Employee_ID Number,
 First_Name Varchar2(20),
 Last_name Varchar2(25)
)

In the Model project of the application I created VO wtith the following definintion:


The VO's query casts the result of getEmployees to table and it has a required parameter deptid - the department's id. JDeveloper works with such structures correctly and the following VO's attributes have been added automatically:



In the Data Controls palette my VO Vpipelined has operation ExecuteWithParams:






I dropped this operation on the jspx page as ADF Parameter Form and got an inputText for department id value and a button:


After that I dropped Vpipelined as a table to the jspx page and set the table as a partial target for the ExecuteWithParams button. Finally I got the following working page:




22 May 2011

Dynamic ADF Train. Adding train stops programmatically.

In this post I'm going to show how to add train stops to ADF train programmatically "on-the-fly". In my use-case I have some ticket-booking application. It has a bounded task flow with train model. At the first stop of the train users input number of passengers and at the following stops they input some passengers' info. The number of stops with passengers' info has to be changed dynamically depending on the value submitted at the first train stop. So, the result of described behaviour should look like this:


The bounded task flow has the following structure:
StartView activity is a page fragment where we input number of passengers and DynamicView activity provides a page fragment to input passenger's info. At the moment we have only one activity for passenger's info and I will add extra activities if the number of passengers is greater than one.
The inputNumberSpinbox in StartView page fragment submits its value to passengersNumber property of some PageFlowScope backing bean and action for the Submit button is a method of the same bean:

public class MainTrain {
    //Extra added train stops
    private List<ActivityId> dynamicStops = new ArrayList<ActivityId>();
    
    //Value of inputNumberSpinbox
    private int passengersNumber = 1;
    
    public String buttonPress(){
        //The number of extra added train stops is greater than needed
        if (passengersNumber <= dynamicStops.size())
            clearExtraStops();
        else //The number of extra added train stops is less than needed        
          if (passengersNumber-1 > dynamicStops.size()) 
              addDynamicStops(); 
        return null;
    }

So, by pressing on Submit button we either add some train stops or clear extra stops depending on the value of  inputNumberSpinbox. We save all added dynamic stops in dynamicStops list. Let's have a look at the clearExtraStops() method:
    private void clearExtraStops() {
        for (int i = dynamicStops.size(); i >= passengersNumber; i--) {
            //Get ActivityId to be removed
            ActivityId removeActivityId =  dynamicStops.get(i-1);

            //Get current train model and remove train stop
            TrainModel trainModel = TrainUtils.findCurrentTrainModel();
            trainModel.getTrainStops().remove(removeActivityId);
            
            //Remove activity from task flow definition
            getTaskFlowDefinition().getActivities().remove(removeActivityId);
            dynamicStops.remove(i-1);
        }                            
    }

The method removes two things: the train stop from the train model and the activity from the task flow definition. The addDynamicStops() method is going to be much more interesting:
private void addDynamicStops() {    
    for (int i = dynamicStops.size(); i < passengersNumber - 1; i++) {
       //Creating new ActivityId
       ActivityId activityId = 
           new ActivityId(getTaskFlowId(), new StringBuilder("DynamicView").append(i).toString()); 

       //The main trick of the post.
       //We consider DynamicView activity as a base for new train stop and new activity
           
       //Get base activity (DynamicView) and its train stop
       Activity baseActivity = getBaseDynamicActivity();
       TrainStopContainer stopContainer = (TrainStopContainer)baseActivity.getMetadataObject();
       TrainStop baseTrainStop = stopContainer.getTrainStop();

       //Create new Activity based on DynamicView but with new ActivityId            
       ActivityImpl activityImpl = new ActivityImpl(baseActivity, activityId);  
       //Add created activity to the task flow definition
       getTaskFlowDefinition().getActivities().put(activityId, activityImpl);

       //Create new train stop based on the DynamicView's train stop
       TrainStopModel trainStopModel = new TrainStopModel(
                          new TrainStopImpl(baseTrainStop, i+2), activityId);
       //Add created train stop to the train stop model
       TrainModel trainModel = TrainUtils.findCurrentTrainModel();
       trainModel.getTrainStops().put(activityId, trainStopModel);             
       //Add created activity to our list
       dynamicStops.add(activityId); 
    }
}
    
private Activity getBaseDynamicActivity() {
   ActivityId baseActivityId = new ActivityId(getTaskFlowId(), "DynamicView");   
   MetadataService metadataService = MetadataService.getInstance();
   return metadataService.getActivity(baseActivityId); 
}

private TaskFlowDefinition getTaskFlowDefinition() {
    MetadataService metadataService = MetadataService.getInstance();
    return metadataService.getTaskFlowDefinition(getTaskFlowId());        
}


private TaskFlowId getTaskFlowId() {
    ControllerContext controllerContext = ControllerContext.getInstance(); 
    ViewPortContext currentViewPortCtx = controllerContext.getCurrentViewPort(); 
    TaskFlowContext taskFlowCtx = currentViewPortCtx.getTaskFlowContext(); 
    return taskFlowCtx.getTaskFlowId();
}

So, the principal trick of this post is to create new activity and train stops basing on existing ones for DynamicView. In order to implement the idea I created two classes: ActivityImpl and TrainStopImpl. The classes are nothing else than just proxy classes implementing Activity and TrainStop interfaces correspondently. They delegates interface implementation to the base instances except some specific methods like getters for Id and DisplayName:

public class TrainStopImpl implements TrainStop {    
    //Base instance 
    private TrainStop baseTrainStop;
    
    private int mpassNo;
    private static final String PASSANGER_FORM = "Passenger's data: ";
    
    public TrainStopImpl(TrainStop trainStop, int passNo) {
       baseTrainStop = trainStop; 
       mpassNo = passNo;
    }

    //Specific implementation
    public String getDisplayName() {
        return new StringBuilder(PASSANGER_FORM).append(mpassNo).toString();
    }

    public String getOutcome() {
        return baseTrainStop.getOutcome();
    }

    public String getSequential() {
        return baseTrainStop.getSequential();
    }

...

public class ActivityImpl implements Activity {
    private Activity baseActivity;
    private ActivityId mid;
    
    public ActivityImpl(Activity activity, ActivityId id) {
        baseActivity = activity;
        mid = id;
    }

    //Specific implementation
    public ActivityId getId() {
        return mid;
    }

    public String getType() {
        return baseActivity.getType();
    }

    public Object getMetadataObject() {
        return baseActivity.getMetadataObject();
    }
...
 

And one more picture for this post, just to show it's working:

That's all! You can download sample application for JDeveloper 11.1.1.2.0.

8 May 2011

InputText with suggestion on demand

Introduction 
ADF Faces provide us by quite handy tag af:autoSuggestBehavior. It could be used together with some input control in order to implement very common use-case when  a user typing some text is suggested by a drop-down list with some values to be selected and displayed in the input field. The following screenshot shows an example of such behavior:

The jspx code for this example is very simple:

        <af:inputText label="Currency" id="i21">
          <af:autoSuggestBehavior 
              suggestedItems="#{InputSuggestBean.onCurrencySuggest}"/>
        </af:inputText>

The af:autoSuggestBehavior tag needs to be bounded to a backing bean method returning a list of items to be suggested. The method has only one String argument containing submitted user's value. Depending on this value you can implement your own logic for the returning list like filtering, sorting, etc. For example, the following backing bean method returns currency codes that match user's input string:

    private final static String[] ccys = {"USD", "EUR", "UAH", "CAD"};

    public List onCurrencySuggest(String inputValue) {
        ArrayList<SelectItem> suggestItems = new ArrayList<SelectItem>();
        for (String s: ccys) {
            if (s.startsWith(inputValue)) 
                suggestItems.add(new SelectItem(s));
        }
        return suggestItems;
    }

Of course, you can implement your backing bean method getting suggested items from ADF BC layer in order to retrieve them from database or from other data sources. You can find detailed example of this feature in the ADF Code Corner Article posted by Frank Nimphius.

Suggestion on demand
But there is another common use-case when users don't need any auto-suggestion for their input, and they want to be suggested on demand only. For example, by pressing "Ctrl-H", a user is provided by previously submitted values for this input field. Something like a history of values.
In this post I'm going to show two different implementations of this use-case. The first one is based on modified af:autoSuggestBehavior tag and the second implementation is built using usual af:popup tag.

Modified af:autoSuggestBehavior
  The jspx definition of inputText looks as usual:

        <af:inputText label="Modified input" id="it1">        
          <af:autoSuggestBehavior 
            suggestedItems="#{InputSuggestBean.onSuggest}"/>
        </af:inputText>

And the backing bean method looks like this:

    public List onSuggest(String string) {
        ArrayList<SelectItem> selectItems = new ArrayList<SelectItem>();
      
        //Let's assume these are history values:
        selectItems.add(new SelectItem("One"));
        selectItems.add(new SelectItem("Two"));        

        return selectItems;
    }

af:autoSuggestBehavior tag  renders some JavaScript object AdfAutoSuggestBehavior responsible for auto-suggestion functionality. It adds a number of event listeners to the inputText for different event types like 
onKeyUp, onBlur, onFocus, etc.

In order to prevent default behavior of af:autoSuggestBehavior tag I have to override its onKeyUp listener and do some JavaScript coding:

<af:document id="d1">      
 <af:resource type="javascript">
  var initialized = false; //Initialization flag
  
  initMySuggestBehavior = function () {
      if (!initialized) { 
          
         //Saving default _fireKeyUp function
         AdfAutoSuggestBehavior.prototype._fireKeyUpEx = 
            AdfAutoSuggestBehavior.prototype._fireKeyUp;

         //Writing proxy for _fireKeyUp function
         AdfAutoSuggestBehavior.prototype._fireKeyUp = function (e) {
           //Getting the event's source and its content                
           var input = e.getSource();
           if (input instanceof AdfUIEditableValue) 
             var inputContent = AdfDhtmlEditableValuePeer.GetContentNode(input);
             //If user has pressed ctrl H then fire suggestion
           if ("ctrl H" == e.getKeyStroke().toMarshalledString()) {
              AdfAutoSuggestBehavior.prototype._autoSuggest(input);
              //Just for better visualization
              if (inputContent.value.length == 0) inputContent.value = "...";
              }

           //This will prevent default suggestion firing for every input character
           if (inputContent) this._nodeLength = inputContent.value.length;
          
           //Calling default event listener we saved before
           AdfAutoSuggestBehavior.prototype._fireKeyUpEx(e);
        };
             
        //Looking for our inputText
        var inp = AdfPage.PAGE.findComponentByAbsoluteId("it1");
         
        /* At this moment AdfAutoSuggestBehavior has already initialized
         * and added his default listeners to the inputText.
         * We need to clear them and reinitialize with our overridden 
         * _fireKeyUp function.
         */  
        inp.setProperty("clientListeners", null);
        AdfAutoSuggestBehavior.prototype.initialize(inp);
         
        /* Adding a simple listener for onKeyDown event in order to 
         * prevent default browser behavior for Ctrl-H            
         */
        inp.addEventListener(AdfUIInputEvent.KEY_DOWN_EVENT_TYPE, myKeyDown, this);
                
        //We've done it.
        initialized = true;
     }
  }
//Preventing default browser behavior for Ctrl-H
 myKeyDown = function (event) {
    if ("ctrl H" == event.getKeyStroke().toMarshalledString())
       event.cancel();
  }
</af:resource>
...      

I'm going to call initMySuggestBehavior JavaScript  function in a phase listener written for the f:view tag:
<f:view beforePhase="#{InputSuggestBean.viewPhaseListener}">
    public void viewPhaseListener(PhaseEvent phaseEvent) {
        if (phaseEvent.getPhaseId() == PhaseId.RENDER_RESPONSE) {
          FacesContext fctx = FacesContext.getCurrentInstance();
          ExtendedRenderKitService ks = 
              Service.getRenderKitService(fctx, ExtendedRenderKitService.class);
          StringBuffer script = new StringBuffer();
          script.append("window.initMySuggestBehavior()");
          ks.addScript(fctx, script.toString());            
        }

    }

The result of our modifications looks like this:


Using af:popup

The jspx page for this implementation looks like this:

    <af:popup id="ctrlHPopup" contentDelivery="lazyUncached"
              animate="false">
      <af:selectOneListbox 
               id="sol4"
               simple="true"
               autoSubmit="false"
               >
        <f:selectItems value="#{InputSuggestBean.popupSuggestion}" id="si7"/>
        <af:clientListener type="keyDown" method="enterSelection"/>
        <af:clientListener type="click" method="clickSelection"/>
      </af:selectOneListbox>
    </af:popup>

    <af:panelLabelAndMessage label="Input with popup" id="plam1">
      <af:inputText id="it2" simple="true">
       <af:clientListener method="ctrlHKeyDown" type="keyDown"/>
      </af:inputText>
    </af:panelLabelAndMessage>

I have a popup and selectOneListbox component inside it. The listbox get suggested items from the backing bean property popupSuggestion and it has client listeners to submit selected values when Enter is pressed or mouse is clicked. The inputText has a listener to fire popup with suggested items when Ctrl-H is pressed.
The backing bean has the following method:

    public List getPopupSuggestion() {
        ArrayList<SelectItem> selectItems = new ArrayList<SelectItem>();
      
        //Let's assume these are history values
        selectItems.add(new SelectItem("The first value"));
        selectItems.add(new SelectItem("The second value"));        

        return selectItems;
    }

And for sure we have some JavaScript implementation of our listeners:
        //Firing popup and preventing default browser behavior for Ctrl-H
        ctrlHKeyDown = function (event) {
            if ("ctrl H" == event.getKeyStroke().toMarshalledString()) {
              showPopup();     
              event.cancel();              
            }   
        }
        
        //Firing popup
        showPopup = function(){
         //Looking for popup component
         var popup = AdfPage.PAGE.findComponentByAbsoluteId("ctrlHPopup");
         //Define popup alignment 
         var hints = {}; 
         hints[AdfRichPopup.HINT_ALIGN_ID] = 
           AdfPage.PAGE.findComponentByAbsoluteId("it2").getClientId();
         hints[AdfRichPopup.HINT_ALIGN] = AdfRichPopup.ALIGN_AFTER_START;
         //Showing
         popup.show(hints);
        }

        //Hiding popup
        hidePopup = function(){
         var popup = AdfPage.PAGE.findComponentByAbsoluteId("ctrlHPopup");
         popup.hide();
        }    
        
        //If Enter is pressed 
        enterSelection = function(event){         
         if (AdfKeyStroke.ENTER_KEY == event.getKeyStroke().getKeyCode()) {
           setSelectedValue(event);  
         }
        }
        
        //If mouse is clicked
        clickSelection = function(event){         
           setSelectedValue(event);  
        }

        //Submit selected value and hide the popup
        setSelectedValue = function(event) {
            var items = event.getSource();
            var selectedItem = items.getSelectItems()[items.getValue()];
            var inputText = AdfPage.PAGE.findComponentByAbsoluteId("it2");
            var inputContent = AdfDhtmlEditableValuePeer.GetContentNode(inputText);
            inputContent.value = selectedItem.getLabel(); 
            hidePopup();    
        }

And the result of our work looks like this:


That's all. You can download sample application for this post.

2 May 2011

Adding Groovy validation expression programmatically

In this post I'm going to show how you can add Groovy validation rule for an entity's attribute programmatically "on-the-fly". When you build Groovy expression to validate the value of an attribute, you can use predefined keywords "newValue" and "oldValue" referring to the old and new values of the attribute correspondingly.
In the following piece of code we can see how to add Groovy validation expression for some attribute checking that new value of the attribute is not greater than 20:

    //Groovy validation expression
    private static final String VALIDATION_EXPR="newValue <= 20";
    
    //Keyword in the message bundles resource file
    //exprvalue_err=Value must not be greater than {0}   
    private static final String EXPR_VALUE_ERROR="exprvalue_err";    
    private static final int EXPR_MAX_VALUE=20;    
    
    private void addExpressionValidator(AttributeDef at) {
        //creating new validator
        JboExpressionValidator jcv = new JboExpressionValidator(false, VALIDATION_EXPR);
        
        //setting error message
        jcv.setErrorMsgId(EXPR_VALUE_ERROR);
        
        //setting value for the message's token {0}
        HashMap errvaluesMap = new HashMap();
        errvaluesMap.put("0", EXPR_MAX_VALUE);         
        jcv.setErrorMsgExpressions(errvaluesMap);                
        
        //adding validator to the attribute's validators list
        ((AttributeDefImpl) at).addValidator(jcv);
    }


That was really easy!

Working with Oracle SQL object types. Part II

In my previous post I demonstrated how to retrieve and show information from a database table containing an attribute with SQL object type. In this post I'm going to show how to save this information back into the database.
So, I have a table with the following structure:

create table Payment
(ID Number,
 PaymentDate date,
 Currency Varchar2(3),
 Amount Number,
 Contact Tcontact_info
 )

And Tcontact_info SQL object type has the following definition:

create or replace type Tcontact_info as object
(Name Varchar2(100),
 PhoneNumber Varchar2(100),
 CellPhoneNumber Varchar2(100),
 email Varchar2(100)
 )

In order to update data in  Payment table I'm going to use PL/SQL procedure Payment_update:

create or replace procedure Payment_update
(aId Payment.Id%type,
 aPaymentdate Payment.Paymentdate%type,
 aCurrency Payment.Currency%type,
 aAmount Payment.Amount%type,
 aContact Payment.Contact%type
 )
is
begin
  update Payment
    set Paymentdate = aPaymentdate,
        Currency = aCurrency,
        Amount = aAmount,
        Contact = aContact
  where id = aID;      
end;   
 
In my entity object implementation class PaymentImpl I have overridden doDML method:

    protected void doDML(int operation, TransactionEvent e) {
        switch (operation) {
        case DML_UPDATE:
            {
                updateProcedure();
                break;
            }
        case DML_INSERT:
            {
                insertProcedure();
                break;
            }
        case DML_DELETE:
            {
                deleteProcedure();
                break;
            }
        }
    }

Methods insertProcedure(), updateProcedure() and deleteProcedure() are used to call appropriate PL/SQL procedures for corresponding DML modes.
For example, updateProcedure() looks like this:

    private void updateProcedure() {
        DBTransactionImpl dbti = (DBTransactionImpl) getDBTransaction();
        CallableStatement statement =
          dbti.createCallableStatement(("BEGIN " + 
            "Payment_update(:aId, :aPaymentdate, :aCurrency, :aAmount, :aContact);" + 
                                        "END;"), 0);
        try
        {
          statement.setObject("aId",getId());
          statement.setDate("aPaymentdate", getPaymentdate().dateValue());
          statement.setString("aCurrency", getCurrency());  
          statement.setObject("aAmount", getAmount());
          statement.setObject("aContact", getContact());  
          statement.execute();
        }
        catch (SQLException sqlerr)
        {
          throw new JboException(sqlerr);
        }
        finally
        {
          try
          {
            if (statement != null)
            {
              statement.close();
            }
          }
          catch (SQLException closeerr)
          {
            throw new JboException(closeerr);
          }
        }
        
    }
Note, that there is no any magic to pass contact information as a parameter to Callable Statement. PaymentImpl class has usual getter getContact() for its Contact attribute with TcontactInfo class. And TcontactInfo class inherits oracle.jbo.domain.Struct class which is commonly used to work with complex SQL types. That's all.

17 Apr 2011

Working with Oracle SQL object types

Introduction
Sometimes, it could be convenient to represent real business entities using Oracle object types. For example, address, contact information or some payment instructions - all theses entities have standard set of attributes and, may be, have some internal business logic. It would be handy to define an object type, encapsulating all necessary attributes, and work with it in the same way if it were usual scalar type. In this post I'll show how to work with a simple Oracle object type at the business model level and how to create a declarative component working with this model at the view level.

Use Case
I need to store in my database information about payments. It should contain payment's date, currency, amount and contact information of the person connected with the payment. I'm going to use object type for contact info with the following structure:

create or replace type Tcontact_info as object
(Name Varchar2(100),
 PhoneNumber Varchar2(100),
 CellPhoneNumber Varchar2(100),
 email Varchar2(100)
 )

And the table for payments looks like this:

create table Payment
(ID Number,
 PaymentDate date,
 Currency Varchar2(3),
 Amount Number,
 Contact Tcontact_info
 )


Let's do it

In JDeveloper in the model project I created entity for Payment table using "Create Business Components from Tables" wizard.


The wizard has created entity object with the following structure:


Have a look at the Contact's type. And the wizard has created business domain object TcontactInfo representing Tcontact_info SQL object type:


After that I created entity based view object VPayment and Application Module containing an instance of this view object. If we now explore the Data Controls panel, we will see very interesting picture:



Contact attribute is defined like a child iterator with its own set of attributes and operations. And if we drag-n-drop VPayment from the Data Controls panel to the page, we will see interesting structure in the generated PageDef file:

  <executables>
    <variableIterator id="variables"/>
    <iterator Binds="VPayment" RangeSize="25" DataControl="AppModuleDataControl"
              id="VPaymentIterator"/>
    <accessorIterator MasterBinding="VPaymentIterator" Binds="Contact"
                      RangeSize="25" DataControl="AppModuleDataControl"
                      BeanClass="com.cs.blog.sqlobjectexample.model.common.TcontactInfo"
                      ObjectType="true" id="ContactIterator"/>
  </executables>
  <bindings>
    <!--General payment's attributes: -->   
    <attributeValues IterBinding="VPaymentIterator" id="Amount">
      <AttrNames>
        <Item Value="Amount"/>
      </AttrNames>
    </attributeValues>
    ... 

    <!--Contact's attributes: -->    
    <attributeValues IterBinding="ContactIterator" id="Name">
      <AttrNames>
        <Item Value="Name"/>
      </AttrNames>
    </attributeValues>
    ... 
  </bindings>
  

Access to Contact's attributes is provided via special "accessIterator"! And it works fine as we can see here:

At this point we could say "We are done!", but we are not looking for easy ways! I'm going to create declarative component for contact info in order to  use it widely in my applications.

In my previous post you can see how to create, deploy and use declarative components in details. In "Create JSF Declarative Component Wizard" we need to add attribute "value" with type of business domain TcontactInfo:

          

In jspx file for our declarative component ContactInfo I have added the following content:

<af:panelBox text="Contact Info" id="dc_pb1" showDisclosure="false"
              inlineStyle="width:350.0px;">
  <af:panelFormLayout id="dc_pfl1">
    <af:inputText value="#{attrs.value.name}" label="Person's name"
                  id="dc_it1"></af:inputText>
    <af:inputText value="#{attrs.value.phonenumber}" label="Phone number"
                  id="it6"></af:inputText>
    <af:inputText value="#{attrs.value.cellphonenumber}"
                  label="Cell phone number" id="it5"></af:inputText>
    <af:inputText value="#{attrs.value.email}" label="Email" id="dc_it2"></af:inputText>
    <f:facet name="footer"/>
  </af:panelFormLayout>
 </af:panelBox>

Note, that access to the Contact's attributes is provided using keyword "attrs.value", which is referring to an object of TcontactInfo class.

In my target jspx page I can use new declarative component like this:

<compLib:ContactInfo id="ci1" value="#{bindings.Contact.inputValue}"/> 

And my PageDef looks like this:

  <executables>
    <variableIterator id="variables"/>
    <iterator Binds="VPayment" RangeSize="25" DataControl="AppModuleDataControl"
              id="VPaymentIterator"/>
  </executables>
  <bindings>
    <!--General payment's attributes: --> 
    <attributeValues IterBinding="VPaymentIterator" id="Amount">
      <AttrNames>
        <Item Value="Amount"/>
      </AttrNames>
    </attributeValues>
    ...
    <attributeValues IterBinding="VPaymentIterator" id="Contact">
      <AttrNames>
        <Item Value="Contact"/>
      </AttrNames>
    </attributeValues>
 </bindings>


So, I don't need any "accessorIterator" and define "Contact" as usual scalar attribute. The following screen is presenting the result of our work. Sorry for design:

Are we done? Almost. We can get and show information from the database SQL object type. And we need to be able to put this information back, to save it to the database. Next time.