Create & Add Data Adapter

In this section we will discuss how to implement different kind of adapters to implement specific functionality to feature pages. This is the only new development in the web feature development process.

Lets start off with a small description on the different kinds of adapters in use.

The contents of this tutorial section will walk you through the following areas regarding adapter development.

  1. Create an Empty Adapter
  2. Adding the Query Data Adapter Interface
  3. Adding the Populate Data Adapter Interface
  4. Adding the Save Data Adapter Interface
  5. Combination of adapter interfaces

Create an Empty Data Adapter

Creating an empty data adapter is no more than creating an empty java class. We will use this empty class to gradually add implementation interfaces and finally add the adapter to the feature page.

package ifs.demow.features.managemytodo;
        
/**
 * Adaptor for the manage MyTodo webfeature.
 */
public class MyToDoTaskAdapter
{
    public MyToDoTaskAdapter() 
    { } 
}

Adding the Query Data Adapter Interface

In order to add the query functionality we can add the FndQueryDataAdapter interface to our empty adapter class. This interface implements the following abstract methods, thus we need to override these method in our adapter class..

Implementation of the above abstract methods are as followed.

package ifs.demow.features.managemytodo;

import ifs.fnd.asp.*;
import ifs.fnd.base.*;
import ifs.fnd.record.*;
import ifs.fnd.webfeature.*;
import ifs.application.managemytodo.*;
import ifs.application.todoitem.TodoItem;
import ifs.application.mytodoitem.MyTodoItem;
import ifs.application.personinfo.PersonInfo;
        
/**
 * Adaptor for the manage MyTodo webfeature.
 */
public class MyToDoTaskAdapter implements FndQueryDataAdapter
{
   public MyToDoTaskAdapter()
   { }

   public FndAbstractRecord getTemplate() {
      return new MyTodoItem();
   }
   
   public FndQueryRecord getQueryRecord(ASPBlock block) {
   
      //Include attrubutes for aggregate reference ITEM
      TodoItem todo_item = new TodoItem();
      todo_item.excludeQueryResults();
      todo_item.priority.include();
      ...
      block.getASPManager().getConditions(todo_item,"ITEM",block);

      //Include attrubutes for aggregate reference SENDER
      PersonInfo sender = new PersonInfo();
      sender.excludeQueryResults();
      sender.name.include();
      ...
      mytodo_item.item.include();
      mytodo_item.sender.include();
      block.getASPManager().getConditions(sender,"SENDER",block);
      
      //Include attrubutes for entity
      MyTodoItem mytodo_item = new MyTodoItem();
      mytodo_item.excludeQueryResults();
      mytodo_item.itemId.include();
      ...
      block.getASPManager().getConditions(mytodo_item,null,block);
      
      //Include detail conditions for ITEM into entity
      FndDetailCondition _itemCondition = mytodo_item.item.createDetailCondition(todo_item, 
      					  FndQueryReferenceCategory.EXISTS_IN);
      if(_itemCondition != null)
         mytodo_item.addCondition(_itemCondition);
      
      //Include detail conditions for SENDER into entity
      FndDetailCondition _senderCondition = mytodo_item.sender.createDetailCondition(sender, 
                          FndQueryReferenceCategory.EXISTS_IN);
      if(_senderCondition != null)
         mytodo_item.addCondition(_senderCondition);
      
      return new FndQueryRecord(mytodo_item);
   }
   
   public FndAbstractArray query(FndQueryRecord record, ASPPage page) {
      try {
         ManageMyTodo manage_mytodo = ManageMyTodoFactory.getHandler();
         
         //include customized code
         ...
         
         FndAbstractArray resultSet = manage_mytodo.queryMyTodoItem(record);
         return resultSet;
      } catch (SystemException ex) {
         ex.printStackTrace();
      } catch (IfsException ex) {
         ex.printStackTrace();
      }
      return null;
   }
   
   public int count(FndQueryRecord record, ASPPage page) {
      FndAbstractArray arr =  query(record, page);
      if(arr!=null)
         return arr.getLength();
      return 0;
   }
}

Download Java source code

When a user performs a query function from a web feature, the web client framework will call upon the query adapter methods we just implemented. Thus by customizing these methods, developers have the freedom to manipulate how the web feature behaves.

As you can see the getTemplate() method simply returns a reference to a new entity object.

The getQueryRecord() method is used to include all attributes and finally create the query record. In this method we include all the attributes bound to ASPField objects in the preDefine() method.

If you look at this implementation closely you can see that an object reference is created for each aggregate (e.g.: TodoItem, PersonInfo ) and all its attributes are excluded. Then one by one all aggregate attributes that are mapped to ASPFields are included, and the conditions for those aggregates are created using the getConditions() method. This will actually add the relevant query conditions to the given aggregate object. In our example this is done for both ITEM and SENDER aggregates.

TodoItem todo_item = new TodoItem();
todo_item.excludeQueryResults();
todo_item.priority.include();
...
block.getASPManager().getConditions(todo_item,"ITEM",block);
PersonInfo sender = new PersonInfo();
sender.excludeQueryResults();
sender.name.include();
...
block.getASPManager().getConditions(sender,"SENDER",block);

The reference name that you give here (e.g.: "SENDER") should match the reference name that you have given when mapping the aggregate attributes to ASPFields.

From previous section

blk.addField("NAME", myToDo_item.sender().name).
    setAggregateReference("SENDER").
    setLabel("FWWEBFEATUREMYTODOFROM: From").
    setReadOnly();

Then you need to create an object reference to your entity type, include the attributes for the entity and add conditions using the framework functionality. This time you pass "null" as the aggregate reference because you are adding conditions to the entity.

MyTodoItem mytodo_item = new MyTodoItem();
mytodo_item.excludeQueryResults();
mytodo_item.itemId.include();
...
mytodo_item.item.include();
mytodo_item.sender.include();
block.getASPManager().getConditions(mytodo_item,null,block);

Then you add the aggregate elements to the entity as detail conditions

FndDetailCondition _itemCondition = mytodo_item.item.createDetailCondition(todo_item, 
                                    FndQueryReferenceCategory.EXISTS_IN);
if(_itemCondition != null)
   mytodo_item.addCondition(_itemCondition);
      
FndDetailCondition _senderCondition = mytodo_item.sender.createDetailCondition(sender, 
                                    FndQueryReferenceCategory.EXISTS_IN);
if(_senderCondition != null)
   mytodo_item.addCondition(_senderCondition);

 Finally creates a query record from the entity object and returns it so the webclient framework can use it to implement the query functionality.

return new FndQueryRecord(mytodo_item);

Important: If you do not have any aggregates mapped with your ASPFields, there is no need to create aggregate references or add them as detail conditions. However we would still need to create and include all the entity attributes in use.

The query() method simply creates a handler object for the entity reference and calls the implementation methods inside, to query the database with the given query record

public FndAbstractArray query(FndQueryRecord record, ASPPage page) {
   try {
      ManageMyTodo manage_mytodo = ManageMyTodoFactory.getHandler();
      FndAbstractArray resultSet = manage_mytodo.queryMyTodoItem(record);
      return resultSet;
   } catch (Exception ex) {
      ex.printStackTrace();
   }
   return null;
}

The count() method simply counts the number of array elements returned by the query() method.

Adding the Populate Data Adapter Interface

In order to add the master-detail table populating functionality we can add the FndPopulateDataAdapter interface to our empty adapter class. This interface implements the following abstract methods, thus we need to override these method in our adapter class..

In practice this adapter interface is often used in combination with the query adapter interface. This enables the feature page to query and populate master-detail like layouts with data.

package ifs.demow.features.managemytodo;

import ...

public class MyToDoTaskAdapter implements FndQueryDataAdapter, FndPopulateDataAdapter
{
   ...
   ...
   public FndAbstractRecord getTemplate()
   {
      return new MyTodoItem();
   }
   
   public FndAbstractRecord populate(FndAbstractRecord record) {
      try {
         /* insert code to query for detail records*/
         return record;
      } catch (SystemException ex) {
         ex.printStackTrace();
      } catch (IfsException ex) {
         ex.printStackTrace();
      }
      return null;
   }
}

Adding the Save Data Adapter Interface

In order to add the data modification functionality we can add the FndSaveDataAdapter interface to our empty adapter class. This interface implements the following abstract methods, thus we need to override these method in our adapter class..

package ifs.demow.features.managemytodo;

import ...

public class MyToDoTaskAdapter implements FndSaveDataAdapter
{
   ...
   ...
   public FndAbstractRecord getTemplate()
   {
      return new MyTodoItem();
   }
   
   public FndAbstractRecord save(FndAbstractRecord record, ASPPage page) {
      try {
         ManageMyTodo manage_mytodo = ManageMyTodoFactory.getHandler();
         manage_mytodo.saveMyTodoItem((MyTodoItem)record);
         return record;
      } catch (SystemException ex) {
         ex.printStackTrace();
      } catch (IfsException ex) {
         ex.printStackTrace();
      }
      return null;
   }

   public FndAbstractRecord remove(FndAbstractRecord record, ASPPage page) {
      try {
         ManageMyTodo manage_mytodo = ManageMyTodoFactory.getHandler();
         manage_mytodo.removeMyTodoItem((MyTodoItem)record);
         return record;
      } catch (SystemException ex) {
         ex.printStackTrace();
      } catch (IfsException ex) {
         ex.printStackTrace();
      }
      return null;
   }
}

Combination of adapter interfaces

The interfaces we talked about can be combined to add multiple functionality to web features. When implementing more than one interface to the adapter we need to override all the abstract methods in the implemented interface combination.