Generating binary files as content

A binary file is an operating-system file, which is represented as a Java File object. For an ODA to generate binary-file content, its ODA class must implement the IGeneratesBinFiles interface. Table 45 lists the methods that the ODA class must define to implement the IGeneratesBinFiles interface.

Table 45. Methods in the IGeneratesBinFiles interface

Method IGeneratesBinFiles method Description
Source-node-generation method

None

Generation of source nodes must be performed by the getTreeNodes() method of the IGeneratesBoDefs interface. For more information, see Using files.
Content-generation method generateBinFiles() Generates the binary files, writing them to ODA memory
Content-retrieval method getBinFile() Retrieves either a specified binary file or all binary files from ODA memory

Note:
In addition to the methods in Table 45, IGeneratesBinFiles also includes the getContentProtocol() method to specify the content protocol that the ODA supports for file generation. For more information, see Choosing the ODA content protocol.

Business Object Wizard generates and retrieves content while it displays the Generating Business Objects (Step 5) dialog. With the IGeneratesBinFiles interface implemented, Business Object Wizard invokes the methods shown in Table 46 to generate and retrieve content.

Table 46. Business Object Wizard and IGeneratesBinFiles methods

Use of method IGeneratesBinFiles method For more information
Generate files as content generateBinFiles() Generating files
Retrieve the generated files getBinFile() Providing access to generated files

The following sections discuss the implementation of each of the methods in Table 46.

Using files

When an ODA that implements the IGeneratesBinFiles interface, it can support the use of operating-system files in the following contexts:

Creating files for file content

When an ODA implements the IGeneratesBinFiles interface, it supports creation of files as content. The files that the ODA creates hold the information that the ODA collects from the business-object-definition generation process and elsewhere. If the file-generation process needs the array of user-selected source nodes (which Business Object Wizard creates as a result of Step 3, Select Source), the ODA can receive this array from Business Object Wizard. For information on how to implement the method that generates the files, see Generating files.

However, the IGeneratesBinFiles interface does not define a source-node-generation method, which discovers source nodes and generates the array of tree nodes for Business Object Wizard to display in the Select Source dialog. Instead, if the ODA supports generation of file content and this file generation requires an array of user-selected source nodes, the ODA must use the source-node-generation method in the IGeneratesBoDefs interface, getTreeNodes(). This method queries the data source for the child nodes of the specified parent node and constructs the associated tree nodes, as described in Generating source nodes.

Note:
In this release, every ODA is required to support generation of business object definitions. Therefore, it must implement the IGeneratesBoDefs interface and all its methods (including the getTreeNodes() method).

If an ODA supports only creation of new files (file generation), it can use the getTreeNodes() method as defined in IGeneratesBoDefs. This method queries the data source for the child nodes of the specified parent node and constructs the associated tree nodes, as described in Generating source nodes.

Reading files for source data

When an ODA implements the IGeneratesBinFiles interface, it can support reading operating system files that the user associates with source nodes (For information on how to associate a file with a node, see Associating an operating-system file.). The files that the ODA reads hold source data, which the ODA must search for objects that are represented as source nodes. To support the association of files with nodes, an ODA must take the following steps:

Important

An ODA must implement the IGeneratesBinFiles interface for the getClientFile() method to successfully retrieve a specified operating-system file. If the ODA implements only the IGeneratesBoDefs interface, getClientFile() throws the UnsupportedContentException exception.

The getClientFile() method expects as an argument the source-node path of the file to retrieve. This source-node path has the following format:

fileNodePath:filePath

where fileNodePath is the node path (node names separated by colon (:)) of the node that has an associated file and filePath is the operating-system path of the associated file. When the user expands or selects a node that is an associated file, Business Object Wizard creates this path for the node.

For example, the ArmyAgent5 class of the sample Roman Army ODA supports both the IGeneratesBinFiles interface and the association of files with nodes. Suppose the user associates the Flavius.xml file (in the directory C:\IBM\XMLFiles) to the Vulso source node, as shown in Figure 52.. If the user selects the Flavius.xml node (see Figure 53) from the source-node hierarchy, Business Object Wizard puts the following node path into the array of source nodes:

Apollo:Vulso:Flavius.xml:C:\IBM\XMLFiles\Flavius.xml

This ODA provides the findSon() method to parse a source-node path and locate the associated object that the source node represents. The version of findSon() in the ArmyAgent3 class queries only the ODA's data source (an XML file called RomanArmy.xml) for the object associated with the specified source node. A revised version in the ArmyAgent4 class adds the ability to query an associated file by providing the remoteSon() method, which uses getClientFile() to obtain the contents of the specified file and return this content as a Son object.

Note:
The ArmyAgent4 class, which implements the remoteSon() method, does not support the IGeneratesBinFiles interface. Therefore, the remoteSon() method catches the UnsupportedContentException exception that getClientFile() throws and creates a "dummy" Son object (see Figure 79). The ArmyAgent5 class, which extends ArmyAgent4, does implement IGeneratesBinFiles. Therefore, this version of the ODA can fully support access to files associated with source nodes with getClientFile().

If a source node can have a file associated with it, then the ability to interpret the file's source-node path and to read the contents of this file is needed during content generation, the method that generates content must be able to access information in nodes that are in a file. Implement the method that generates content so that it uses getClientFile() to retrieve an operating-system file that is associated with a node. The method that provides this support is as follows:

For more information on how to generate file content, see Generating files.

Generating files

After the user has selected the source nodes in the Select Nodes dialog, the ODA is ready to begin content generation. The goal of the file generation process is to create some file (or files) that the ODA or other process requires. The step that initiates the generation of files depends on the content protocol associated with the file content type (ContentType.BinaryFile), as follows:

This section describes the following steps that the generateBinFiles() method should take to generate files:

  1. Defining the generateBinFiles() method
  2. Requesting properties for file information
  3. Creating the files
  4. Providing generated files

Defining the generateBinFiles() method

The generateBinFiles() method is defined in the IGeneratesBinFiles interface. Therefore, your ODA class (derived from ODKAgentBase2) must implement this method when it implements the IGeneratesBinFiles interface. The purpose of the generateBinFiles() method depends on the content protocol that the ODA uses for generation of file ( ContentType.BinaryFile) content, as follows:

Generating files on request

If the ODA generates files "on request", Business Object Wizard explicitly calls the generateBinFiles() method to initiate generation of the files. Therefore, you must implement generateBinFiles() so that it handles generating the file objects, storing them in the generated-content structure, and returning of content meta-data to Business Object Wizard.

While the generateBinFiles() method executes, Business Object Wizard displays its Generating Business Objects screen (Step 5). As its last step, generateBinFiles() returns a content-meta-data (ContentMetaData) object, which describes the generated files it has generated (though it does not contain the actual generated files).

Generating files through callbacks

If the ODA generates files through callbacks, Business Object Wizard never explicitly calls the generateBinFiles() method. Instead, the ODA uses some other way to "spontaneously" generate the files. You must develop some method to handle generating the files, storing them in the generated-content structure, and notifying Business Object Wizard that content generation is complete. However, the IGeneratesBinFiles interface requires that you define the generateBinFiles() method. Therefore, you must implement generateBinFiles() so that it warns the caller that it should never be called.

The sample Roman Army ODA supports the callback content protocol for the generation of files (see Figure 61). It defines the generateBinDefs() method in the ArmyAgent5 class. This implementation of the method includes the code in Figure 72, which defines the generateBinFiles() method so that it throws an exception if it is ever called.

Figure 72. Defining the generateBinFiles() method

public ContentMetaData generateBinFiles(String[] nodes)
    throws ODKException
{
   throw new ODKException(
      "Files are produced as callbacks. Do not call for file generation.");
}

As an alternative to throwing an exception, the generateBinFiles() method can use the contentUnavailable() method (defined in ContentMetaData) to return its content meta-data to Business Object Wizard, as follows:

return (ContentMetaData.contentUnavailable(ContentType.BinaryFile));

Requesting properties for file information

If, during the process of generating the files, the ODA requires additional information from the user, it can display the BO Properties dialog and have the user provide values for business-object properties. Even though these properties are called business-object properties, you can use the getBOSpecificProps() method to display information that the file-generation process might require. For more information on how to use the BO Properties dialog, see Requesting business-object properties.

Creating the files

The ODK API does not provide a special class to represent a binary file because Java already provides the File class in its java.io package. This package contains many input/output classes that might be useful in the generation and access of files. For each file that the ODA generates, it must take the following steps:

The actual file generation that your ODA performs depends on the design of the ODA. Implement the file generation as best fits the requirements of your ODA and any components that require the files.

The ArmyAgent5 class of the sample Roman Army ODA defines a separate class, FileCreator, to handle the actual generation of the files. To simulate "spontaneous" file generation, the sample calls the FileCreator() constructor from the generateBoDefs() method, as the following code fragment shows:

public ContentMetaData generateBoDefs(String[] nodes) throws ODKException
{
   ContentMetaData cmd = super.generateBoDefs(nodes);

   new FileCreator(this, nodes).start();

   return cmd;
}

The FileCreator() constructor spawns a thread to generate the files. It receives as an argument a reference to the current ODA object (this) and the array with the node paths of the user-selected source nodes. It then creates the following files:

Providing generated files

As discussed in Providing generated content, the ODA must return the generated content to Business Object Wizard in two parts. Therefore, if the ODA generates files as content, it must return the following:

The method that provides this information depends on the content protocol that the ODA uses to generate files, as follows:

Providing content for on-request files

If the ODA generates files "on request", Business Object Wizard invokes the generateBinFiles() method to handle file generation. Therefore, generateBinFiles() provides the generated content as follows:

For more information on getBinFile() , see Providing access to generated files.

Providing content for callback-generated files

If the ODA generates files through callbacks, Business Object Wizard does not invoke the generateBinFiles() method to handle file generation. Instead, the ODA uses some user-defined method to "spontaneously" generate files. This method could be part of the ODA class or in some class within the ODA's package. However, it must provide the generated content as follows:

Note:
For more information on getBinFiles(), see Providing access to generated files.

In the ArmyAgent5 class of the sample Roman Army ODA, the generated-content structure is defined an array of File objects called m_files, as follows:

File[] m_files = null;

The code fragment in Figure 73 shows the last part of the FileCreator.run() method (defined in the ArmyAgent5.java file):

Figure 73. Providing file content

           for (int i=0; i<fileV.size(); i++)
              m_agent.m_files[i] = (File) fileV.get(i);
      }
      ODKUtility.getODKUtility.contentComplete(
         new ContentMetaData(ContentType.BinaryFile, 0,
         m_agent.m_files.length);
} // end of run() in FileCreator class 

Figure 73 handles the generated content as follows:

Providing access to generated files

The generateBinFiles() method does not return the actual generated business object definitions. For Business Object Wizard to be able to access the generated content, the ODA class must implement the content-retrieval method for files. Business Object Wizard uses the information in the content-meta-data object (which generateBinFiles() does return) to determine which content-retrieval method to call. For file content, Business Object Wizard calls the getBinFile() method to retrieve the generated business object definitions.

Note:
Business Object Wizard calls the generateBinFile() method for generation of files if the ODA supports the on-request content protocol. If the ODA supports the callback content protocol for generation of files, some user-defined method actually generates the files. However, this method does not return the actual generated content either. Therefore, Business Object Wizard still requires the getBinFile() method to access the generated files.

Regardless of the content protocol your ODA supports for generation of files, the ODA class must implement the getBinFile() method. This method is defined as part of the IGeneratesBinFiles interface. The method accepts as an argument an index, which identifies the number of files to return. It accesses these files in the generated-content structure and returns an array of the retrieved file (File) objects. The number of files in this array depends on the value of the index argument, as Table 48 shows.

Table 48. Retrieving files

Value of index Description Number of elements in array that getBinFile() returns
In the range 0 to count - 1, where count is the total number of files in the generated-content structure Specifies the index position into the generated-content structure of the file to retrieve One file object

ODKConstant.GET_ALL_OBJECTS
Special constant to indicate the return of all files in the generated-content structure All file objects in the generated-content structure (count)

For the sample Roman Army ODA, the FileCreator.run() method (defined in the ArmyAgent5 class) populates the m_files array with the generated files. Therefore, the getBinFile() method (also defined in ArmyAgent5) retrieves the specified number of files from this array. The following code shows the getBinFile() method for the sample Roman Army ODA:

public File[] getBinFile(long index) throws ODKException
{
   if (index == ODKConstant.GET_ALL_OBJECTS)
      return m_files;
   else
      return new File[] {m_files[(int)index]};
}

Copyright IBM Corp. 1997, 2003