Package com.objectwave.templateMerge

Templates provide the ability to create documents by merging application data with a predefined ascii based template.


Interface Summary
InformationRetrieval Implementers of this interface know how to get data for an information token.

Class Summary
InformationToken Generic class for creating the ability to allow a developer to define a token and how to get the data to replace the values in that token.
JspStyleRead Used to parse an XML file.
JspStyleRead.Test Unit Test
KnownTemplates Primarily exists for the sake of storing MergeTemplates.
MergeTemplate How do we handle the generation of code for which there is no corresponding data? For example, A package definition, is not mandatory.
TemplatePreprocessor Read a flatfile and convert it's contexts to a MergeTemplate object, possibly containing some MergeTemplates itself.
TokenTableModel How to display a WorkFlowRule in a table.
XMLTemplateRead This class is used to read the XML file and translate it into KnownTemplates
XMLTemplateRead.Test Unit Test
XMLTemplateWriter Used to dump the templates into an XML file

Package com.objectwave.templateMerge Description

Templates provide the ability to create documents by merging application data with a predefined ascii based template. This is usefull for report generation. You can predefine report templates and then generate documents that contain a merge of your application data and the report template. This can be alot better than doing your own printing since you'll delegate that to any program that can read your created document. There are several classes that collaborate to provide this functionality.

The interface com.objectwave.templateMerge.InformationRetrieval is the simplest participant in this collaboration. Implementors of this interface are the building blocks of the merge functionallity. For every data element that we will wish to provide as a potential merge data element, will need to be provided by one of these InformationRetrieval objects. There are two methods to get this information.

java.lang.String getStringDataFor(Object obj);
The implementor of this interface is probably expecting a certain type object Object to be passed as the parameter, however, any object could be provided. Normally the implmentor would cast this parameter to be an object of the appropriate type and then traverse the object strucutre using whatever methods necessary to get the data the implementor was intended to retrieve.

java.util.Enumeration getEnumeration(Object obj);
This differs from the previous method in only one way. This method is used when it is expected that the data we are retrieving will not be limited to a single data element.

For example: A Class has one 'name', so I would use one particular InformationRetrieval object to retreive the name with the getStringDataFor method. A Class has multiple variables. I would create another InformationRetrieval object to retrieve an Enumeration of all of the variable names. The method I would use would be the getEnumeration method. Both of these InformationRetrieval implementation may expect a java.lang.Class object to be the parameter 'obj' to their respective methods.

com.objectwave.templateMerge.InformationToken Is the work horse that will merge a string with the data returned from the InformationRetrieval object. This object has a TokenString that it will replace in the original template String with the data returned from the InformationRetrieval object. There are three types of InformationToken. For these types we will assume that we have been provided a sample Template with the following string body :
'This is a test %tokenstring%'.

The first is the default type. This type will use the getStringDataFor() method when interacting with the InformationRetrieval. The string returned by this method will then be substituted for all ocurrances of the the TokenString in the the provided template string body. This is basically a simple merge. Imagine that the InformationRetrieval object provided string data 'message'. The output of the template merge would be 'This is a test message'.

Secondly, there is a Iterator type. An iterator type will use the getEnumeration method when interacting with the InformationRetrieval object. It will create a single string that comma separates the elements found in the iteration. It will then replace all occurances of the TokenString found in the template string body with the new comma separated string. If I had two elements in the Enumeration, one & two, the output of the sample template would be : 'This is a test one, two'.

Finally there is the Collection type. A Collection type is similar to the Iterator type in the way it interacts with InformationRetrieval object. However, for each entry found in the enumeration it will generate a complete new copy of the original template string body. If I had two elements in the Enumeration, one & two, the output of the sample template would be : 'This is a test one This is a test two'. Note, since our template contained no new line operators, the two templates generated one after another.
If there are multiple enumerations in a given template, all enumerations will be advanced for each new merge. If we have two collection tokens with the token strings of %variablename% and %variabletype% and a template string body of '%variabletype% %variablename% \n'. Each token would getEnumeration from their respective InformationRetrieval object. Assuming that the %variablename% token found the two values one & two and the %variabletype% token found the two values int & String, the output would look like this:
'int one
String two'

com.objectwave.templateMerge.TokenProvider will provide a collection of InformationTokens that can be used in the creation of a MergeTemplate. Since tokens are going be very specific to the application at hand, we have the TokenProvider interface to allow each application to provide thier own set of InformationTokens. This interface is merely a way for the application developer to specify the object in which all of the InformationTokens can be found.

com.objectwave.templateMerge.MergeTemplate Is the class that pulls all of this together. Using some template builder, or just hardcoding them into code, you must create a merge template object. These objects are serializable and can be saved into a data file for later retreival. A merge template contains the string body that is the template to be used by the InformationToken. It also contains a collection InformationToken objects that are expected to be found in the string body.

The merge process is initiated by calling the following method on the MergeTemplate object.
void generateForOn(Object ci, OutputStream stream)
This first parameter is the object that will eventually be provided to the InformationRetrieval object. It is from this object that our StringData or Enumeration of data will be retrieved. When the merge string is created, the results will be written upon the provided OutputStream.
generateForOn(aObject, aStream)-> aMergeTemplate      

|-for Each Token--
InsertData(aObject, body)->




|-Write result of all
merge activity onto aStream

That was the basic flow of the merge process. Now lets add complexity with the reality of the process. Every merge template doesn't contain only one string body, but instead there are two, a preBody and a postBody. Additionally every merge template contains an ordered collection of other MergeTemplates. When we generateForOn we acutally generate the preBody, generateForOn() to each one of the MergeTemplates found in the collection, and generate the postBody. This allows a root level template to really be a composite of other templates. This is usefull when intermixing different InformationTokens.

MergeTemplates Preprocessor

To help provide system users with more freedom in defining the framework of a report to be generated using a collection of MergeTemplates, the class  com.objectwave.templateMerge.TemplatePreprocessor has been created.  This class' principle
methods, given an InputStream and a "master list" of tokens, will return a MergeTemplate object which will be ready to
merge all relevant tokens into the list.  The InputStream can contain some special tokens recognized by the TemplatePreprocessor to describe how the MergeTemplate object should be constructed. There are three tags supported:

The actual character strings which represents each of these tags are configurable and also have default values. In the InputStream, the BeginBlock and EndBlock tags must be properly nested, otherwise an IOException will be thrown.  That is, for every BeginBlock tag, an EndBlock tag must occur later in the InputStream.  All text between a BeginBlock and an EndBlock will become the preBody text of a new MergeTemplate object, which will become a child of the current MergeTemplate. Thus nested occurances of blocks will result in a deeper structure of MergeTemplate objects.
Also, for each block the TemplatePreprocessor searches for an identifies what InformationToken tags are associated with

Additionally, every ImportURL tag requires a parameter to follow it to specify the URL of the InputStream to go get.  This parameter is either a sequence of non-whitespace characters or any amount of text enclosed by double-quote (") characters.  To import another file, say c:\otherStuff.htm, the line of the InputStream may appear as

ImportURL "file:\\c:\otherStuff.htm"
All of the contents of c:\otherStuff.htm will replace the [ImportURL "file:\\c:\otherStuff.htm"].  Note the use of the ImportURL tag can be recursive.  That is, if c:\otherStuff.htm contains an "ImportURL <arg>" tag, then that import would be done as well.
Note that there is no cycle detection mechanism, so if a.htm imports b.htm and b.htm imports a.htm, then the TemplatePreprocessor object will enter an infinite recursion.

An example of the contents of a simple file to be "preprocessed" might be the following:

A simpler example describing the same structure is:

this will generate the following structure in the returned MergeTemplate object, supposing that xxx.htm contains xxxChunkOfText:
MergeTemplate preBody=xxxChunkOfText
MergeTemplate preBody=thirdChunkOfText
MergeTemplate preBody=fourthChunkOfText
MergeTemplate preBody=fifthChunkOfText
MergeTemplate preBody=sixthChunkOfText