Let us Consider a web transation called AppendText
#appendText(reportId, appendText)
#Append the passed in text to the identified report
request.appendText.classname=com.ai.db.DBPreTranslateArgsMultiRequestExecutor
request.appendText.db=reportsDB
request.appendText.query_type=update
request.appendText.request.1=AT.GetText
request.appendText.request.2=AT.ConcatenateText
request.appendText.request.3=AT.UpdateText
request.appendText.request=AT.UpdateDate
If the above transaction succeeds
request.appendText.redirectURL=\
/akc/servlet/DisplayServlet?\
url=DisplayNoteMPURL&\
reportId={reportId}\
&ownerUserId={ownerUserId}
A generic part to get original text
request.AT.GetText.classname=com.ai.db.DBRequestExecutor2
request.AT.GetText.stmt=\
select st.statement as item_text \
,st.statement_id as statementId \
from reports r \
,sql_statements st \
where 1=1 \
and r.report_content_id = st.statement_id \
and r.report_id = {reportId}
Use a part to append the new text to the old text
#concatenate
request.AT.concatenateText.classname=com.ai.parts.SubstitutionPart
request.AT.concatenateText.substitution={item_text} {appendtext}
request.AT.concatenateText.resultName=newText
A generic part to update the database
#final update
request.AT.UpdateText.classname=com.ai.db.DBRequestExecutor2
request.AT.UpdateText.query_type=update
request.AT.UpdateText.stmt=\
update sql_statements \
set statement={newText.quote} \
where statement_id = {statementId}
Another generic part to update the last updated date
request.AT.UpdateDate.classname=com.ai.db.DBRequestExecutor2
request.AT.UpdateDate.query_type=update
request.AT.UpdateDate.stmt=\
update reports \
set last_updated_on=Now() \
where report_id={reportId}
Let us investigate code for one of the parts
/**
* Transforms a specified string with substitution arguments in it and returns it
*
* Additional property file arguments
* 1. substitution=
*
* Output
* 1.resultName: The above value translated after substitution
*
*/
public class SubstitutionPart extends AFactoryPart
{
protected Object executeRequestForPart(String requestName, Map inArgs)
throws RequestExecutionException
{
try
{
String substString = AppObjects.getValue(requestName + ".substitution");
String newString =
SubstitutorUtils.generalSubstitute(substString,new MapDictionary(inArgs));
return newString;
}
catch(ConfigException x)
{
throw new RequestExecutionException("Error:config errror",x);
}
}//eof-function
}//eof-class
Lee me include the configuration one more time for this part
#concatenate
request.AT.concatenateText.classname=com.ai.parts.SubstitutionPart
request.AT.concatenateText.substitution={item_text} {appendtext}
request.AT.concatenateText.resultName=newText
How does the substitution part look using simple IOC
public class SubstitutionPart extends AFactoryPart
{
protected Object executeRequestForPart(String substitution, Map inArgs)
throws RequestExecutionException
{
try
{
String newString =
SubstitutorUtils.generalSubstitute(substitution,new MapDictionary(inArgs));
return newString;
}
catch(ConfigException x)
{
throw new RequestExecutionException("Error:config errror",x);
}
}//eof-function
}//eof-class
See how we no longer need the configuration context and how substitution is passed in by the container. The container will use the configuration context and configuration api to do this instead of the part.
How does the substitution part look using radical IOC
public class SubstitutionPart
{
protected Object generalSubstitute(String substitution, Map inArgs)
throws ConfigException
{
String newString =
SubstitutorUtils.generalSubstitute(substitution,new MapDictionary(inArgs));
return newString;
}//eof-function
}//eof-class
See how we no longer even derive from the class. The invoker will figure out the input parameters from the context and also the configuration file. Most likely this is where things are heading. In this case the properties will look like
#concatenate
request.AT.concatenateText.classname=com.ai.parts.SubstitutionPart
request.AT.concatenateText.substitution={item_text} {appendtext}
request.AT.concatenateText.resultName=newText
#invocation
request.AT.request.1=AT.concatenateText(#inArgs)
The invocation will rename the parameters to suit the method specification. The unmatched parameters will be resolved from configuration. This is paving the way for any class to play the role of a part.
Examples of some Parts that I have used
DBRequestExecutor
DBStoredProcedureRequestExecutor
RowFileReader
InvalidateCachePart
DBLoopPart
IfPart
SessionLoaderPart
StringToInputStreamPart
SubstitutionPart
URLExporterPart
ValueDecoderPart
DOMFileWriterPart
DOMUpdaterPart
GetDOMPart
DBLoopRequestExecutor: Loop Part example
public class DBLoopRequestExecutor extends DBBaseJavaProcedure
{
public Object executeProcedure(Connection con,
boolean bConnectionCreator,
String requestName,
Hashtable arguments )
throws DBException
{
String fieldSpec =
AppObjects.getIConfig().getValue(requestName + ".fieldSpec",null);
String individualRequest =
AppObjects.getIConfig().getValue(requestName + ".individualRequest",null);
if (fieldSpec == null)
{
throw new DBException("Error: Field spec required");
}
if (individualRequest == null)
{
throw new DBException("Error: Individual request not specified");
}
// field spec if mentioned
Vector fieldNameVector = Tokenizer.tokenize(fieldSpec,"|");
String pluralFieldName = (String)fieldNameVector.get(0);
String singularFieldName = (String)fieldNameVector.get(1);
String pluralFieldValue = (String)arguments.get(pluralFieldName);
if (pluralFieldValue == null)
{
throw new DBException(
"Error: No value for the plural field name: " + pluralFieldName);
}
// plural field value found
Vector singularFieldVector = Tokenizer.tokenize(pluralFieldValue,"|");
try
{
for(Enumeration e=singularFieldVector.elements();e.hasMoreElements();)
{
String singularFieldValue = (String)e.nextElement();
arguments.put(singularFieldName,singularFieldValue);
arguments.put("aspire.reserved.jdbc_connection",con);
Object obj = AppObjects.getIFactory().getObject(individualRequest,arguments);
}
}
catch(RequestExecutionException x)
{
throw new DBException("Error: Could not execute a request", x);
}
return new RequestExecutorResponse(true);
}
}
IfPart Example
public class IfPart extends AFactoryPart
{
protected Object executeRequestForPart(String requestName, Map inArgs)
throws RequestExecutionException
{
PrintWriter w = null;
String aspireFilename = null;
try
{
//mandatory args
String expression = AppObjects.getValue(requestName + ".expression");
String ifRequestName = AppObjects.getValue(requestName + ".if");
String elseRequestName = AppObjects.getValue(requestName + ".else",null);
boolean r
= ExpressionEvaluationUtils
.evaluateBooleanExpressionUsingDictionary(
expression,new MapDictionary(inArgs));
if (r == true)
{
return AppObjects.getObject(ifRequestName,inArgs);
}
else
{
if (elseRequestName == null)
return new Boolean(true);
return AppObjects.getObject(elseRequestName,inArgs);
}
}
catch(ConfigException x)
{
throw new RequestExecutionException
"Error: ConfigException. See the embedded exception for details", x);
}
catch(CommonException x)
{
throw new RequestExecutionException(
"Error: Expression evaluation error. See the embedded exception for details", x);
}
}
}
References
1. General Introduction to other Server side Patterns in this series