Disclaimer
Please note that these are only examples to demonstrate the pattern of usage. If you were to try the code with Aspire minor changes may be needed such as classnames or some anticipated features
A thousand mile journey starts with a simple first step
Consider the following properties file
request.getRows.classname=com.ai.db.DBRequestExecutor2
request.getRows.db=my-database
request.getRows.stmt=\
select * from my-table \
where 1=1 \
and my-col-1={arg1} \
and my-col-2={arg2.quote} \
and my-col-3=16
This section defines a transaction called "getRows". Two parameters "arg1" and "arg2" are required to retrieve data for this transaction. The reusable part responsible for retrieving the data in this case is DBRequestExecutor2. The data is to be retrieved from a database called "my-database" and using the select statement listed. Once this definition is available, a programmer can do the following in the code
Map args = new HashMap();
args.put("arg1","some-int-value");
args.put("arg2","some-string-value");
IDataCollection col = Data.ExecuteQueryTransaction("getRows",args);
IIterator itr = col.getIIterator();
for(itr.moveToFirst();itr.isNotAtTheEnd();itr.moveToNext())
{
IDataRow dr = (IDataRow)col.getCurrentElement();
}
col.close();
Typed relational data sets
Change the configuration slightly
request.getRows.classname=com.ai.db.DBRequestExecutor2
request.getRows.db=my-database
request.getRows.stmt=\
select * from my-table \
where 1=1 \
and my-col-1={arg1} \
and my-col-2={arg2.quote} \
and my-col-3=16
request.getRows.domain-object=com.mypkg.MyDomainObject
See how the domain object is used in code
Map args = new HashMap();
args.put("arg1","some-int-value");
args.put("arg2","some-string-value");
IDataCollection col = Data.ExecuteQueryTransaction("getRows",args);
IIterator itr = col.getIIterator();
for(itr.moveToFirst();itr.isNotAtTheEnd();itr.moveToNext())
{
MyDomainObject typedDomainObject = (MyDomainObject)col.getCurrentElement();
}
col.close();
Same client code but the data comes from a simulated local file
Only change is to the properties file, client won't know the difference
request.getRows.classname=com.ai.data.FileReader
request.getRows.filename=c:\some-root\{arg1}\{arg2}.txt
Same client code but the data comes from a stored procedure
Only change is to the configuration file
request.getRows.classname=com.ai.db.StoredProcExecutor2
request.getRows.db=my-database
request.getRows.stmt=\
call pkg1.sp_getRows({arg1},{arg2.quote});
Let us do some updates
Let us start with a definition of our transaction
request.updateRow.classname=com.ai.db.DBRequestExecutor2
request.updateRow.db=my-database
request.updateRow.stmt=some-update-statement-with-args
Let us see what happens to the client code
Map args = new HashMap();
args.put("arg1","some-int-value");
args.put("arg2","some-string-value");
Data.ExecuteUpdateTransaction("updateRow",args);
If anything goes wrong an exception will result. The result is automatically wrapped in a transaction
Let us raise the bar with updates
Let us define one more transaction
request.updateRow1.classname=com.ai.db.DBRequestExecutor2
request.updateRow1.db=my-database
request.updateRow1.stmt=some-update-statement-with-args.
Let us combine the two updates into a single composite transaction:
request.compositeUpdate.classname=com.ai.db.MultiRequestExecutor
request.compositeUpdate.db=my-database
request.compositeUpdate.query_type=update
request.compositeUpdate.request.1=updateRow
request.compositeUpdate.request.2=updateRow1
Both updates will take place with in a single transaction context. And the client code to invoke the "compositeUpdate" will look very similar to the first client code.
Map args = new HashMap();
args.put("arg1","some-int-value");
args.put("arg2","some-string-value");
Data.ExecuteUpdateTransaction("compositeUpdate",args);
Selects in the middle of an update
request.compositeUpdate.classname=com.ai.db.MultiRequestExecutor
request.compositeUpdate.db=my-database
request.compositeUpdate.query_type=update
request.compositeUpdate.request.1=getRows
request.compositeUpdate.request.2=updateRow1
request.compositeUpdate.request.3=updateRow1
Assuming getRows will retrieve only one row, the values are available as arguments to the components down the pipeline
Writing one of these parts is quite simple
public class MyDataCollectionProducer
extends AbstractDataCollectionProducer
{
IDataCollection execute(String requestName, Map args)
{
//Read any additiona configuration parameters for this class
String param1 =
config.getValue(requestName + ".param1","default-value");
//Some how produce a data collection
}
}
Here is how you specify this part in the config file
request.getRows.classname=MyDataCollectionProducer
request.getRows.param1=some-value
Same is true for an update part.