| Business Objects and Data Sources > Data Sources > Implementing a New Data Source |
Implementing a New Data Source |
INDEX
PREVIOUS
NEXT
|
This section explains how to implement a new data source. It is based on a sample that demonstrates how to implement a data source for loading on demand a hierarchy of objects and, more precisely, a file system. This sample can be found in the following directory:
<installdir>/samples/datasource/explorer
In this section, you will learn about:
The following code shows how to implement the data source.
IltDefaultDataSource class as follows:
IltDefaultDataSource includes support for any IlpClass instances and handles tables mapping IlpObject instances with identifiers. Deriving FileDataSource from that class allows you to benefit from this functionality.
java.io.File. In this sample code, java.io.File objects are defined by the IlpClass automatically generated by the class manager. Here, the class java.io.File is considered as a JavaBeans class (which is acceptable, as most of its methods comply with JavaBeans conventions). As an alternative, you could create a dedicated IlpClass implementation and the corresponding IlpObject implementation. See Defining the Business Model with Dynamic Classes and Adding Dynamic Business Objects.
getName method of the class java.io.File does not display labels correctly. This is why it is necessary here to subclass the IlpClass defining java.io.File to represent the roots of the file system.
IlpClass objects are known, the data source is initialized with the root objects returned by the listRoots method of the class java.io.File.
addFiles method, detailed below, iterates over an array of Files, creates the corresponding IlpObject instances if they are not yet present in the data source, and inserts these objects into the data source.
The current implementation of IltDefaultDataSource handles structural information (that is, child-parent relationships) pertaining to IlpObject instances independently of the objects themselves.
This implementation makes it possible for you to load objects on demand in two different ways:
or
getContainerInterface method
IlpContainer interface. This interface contains a getChildren method that returns the identifiers of the IlpObject children.
In our example, we have implemented load-on-demand by redefining the getContainerInterface of the data source (see Implementing the getContainerInterface Method). Since we do not use the access to structural information provided by the default data source in order not to duplicate it from the File class where it is already present, we also provide a specific implementation of the getChildInterface method (see Implementing the getChildInterface Method and the IlpChild Interface).
| Note |
You could also create IlpObject instances dynamically by reimplementing the method getObject(Object id).
|
The method getContainerInterface returns an IlpContainer. If the object is a container, the method should return a non-null value, whether this container has children or not, as illustrated below.
public synchronized IlpContainer getContainerInterface(Object idOrIlpObject) {
IlpObject object = idOrIlpObject instanceof IlpObject ? (IlpObject)idOrIlpObject : getObject(idOrIlpObject);
if (object != null && fileClass.isAssignableFrom(object.getIlpClass())) {
File file = (File)((IlpBeansObject)object).getBean();
if (file.isDirectory())
return DIRECTORY_LOADER;
else
return null;
}
return super.getContainerInterface(idOrIlpObject);
}
The getContainerInterface method takes an IlpObject or an identifier as parameter. It retrieves the IlpObject instance from its parameter and checks whether the returned object is an instance of the IlpClass corresponding to the File class and whether File is a directory. If it is not a directory, it returns null or the default implementation of the data source, if the object is not of the File IlpClass. If it is a directory, the method returns a specific implementation of the IlpContainer interface (see Implementing the IlpContainer Interface).
Note that in this example, the IlpObject is downcast to an instance of IlpBeansObject and that the Bean it contains is in turn downcast to a File instance. We could have used the directory attribute of the IlpClass directly as follows:
Boolean isDirectory =
Boolean)object.getAttributeValue(fileClass.getAttribute("directory")) ;
if (isDirectory.booleanValue())
return DIRECTORY_LOADER;
else
return null;
The default data source provides its own implementations of all the structural interfaces (such as IlpChild or IlpContainer). These implementations ensure that the information they contain is coherent. For example, if A is the child of B, B is the parent of A.
These implementations do not support load-on-demand. To support load on demand, you have to redefine the IlpContainer interface.
It is quite easy to retrieve the children of a File object and load them. Following is an implementation of IlpContainer for the class java.io.File. It uses a static instance of the class since the entire context of the getChildren method is contained in its parameter, which is the IlpObject instance itself.
IlpContainer DIRECTORY_LOADER = new IlpContainer(){
public Collection getChildren(IlpObject object) {
// the file is supposed to be a directory
File directory = (File)((IlpBeansObject)object).getBean();
File[] files = directory.listFiles();
List filesIds = new ArrayList(files.length);
for (int i = 0; i < files.length; i++) {
// 1st get all the identifiers
filesIds.add(files[i]);
}
// then add the files
addFiles(files, fileClass);
return filesIds;
}
};
Note that to avoid recreating the same IlpObject instance twice, no record is kept as to whether a directory has already been loaded. The test in the addFiles method (described in Implementing the Data Source) is used to check whether an IlpObject instance exists before creating it and adding it to the data source.
Since you do not use the access to structural information provided by the default data source, you have to provide specific implementations of the getChildInterface method and of the IlpChild interface. This is quite easy, since the java.io.File class has a getParentFile method.
public synchronized IlpChild getChildInterface(Object idOrIlpObject) {
IlpObject object = idOrIlpObject instanceof IlpObject ? (IlpObject)idOrIlpObject : getObject(idOrIlpObject);
if (object != null && fileClass.isAssignableFrom(object.getIlpClass())) {
File file = (File)((IlpBeansObject)object).getBean();
File parentFile = file.getParentFile();
if (parentFile != null) {
return FILE_PARENT;
} else {
return null;
}
}
return super.getChildInterface(idOrIlpObject);
}
The method gets the IlpObject and checks whether that object is a file. It then checks whether it has a parent file and returns the specific implementation of the IlpChild interface, described below.
Like the other structural interfaces, the IlpChild interface returns an identifier. Here, since the identifiers of the objects are the files themselves, it returns the parent file.
IlpChild FILE_PARENT = new IlpChild() {
public Object getParent(IlpObject object) {
File file = (File)((IlpBeansObject)object).getBean();
File parentFile = file.getParentFile();
return parentFile;
}
| Copyright © 1987-2007 ILOG S.A. All rights reserved. Documentation homepage. All rights reserved. Legal terms. | PREVIOUS NEXT |