Multitier applications replicate the same
data item, such as a "Last Name", at various levels:
database tables, Java classes (for both business logic and system
infrastructure), user interface dialogs.
A familiar example of this is shown by the following
code fragment, where data items retrieved from a database
are copied to Java variables:
// Get results from "results" by column name
int rCustId = results.getInt("CUST_ID");
String rFirstName = results.getString("FIRST_NAME");
String rLastName = results.getString("LAST_NAME");
float rBalance = results.getFloat("BALANCE");
String rEmail = results.getString("EMAIL");
Similar code fragments are frequent and lend themselves
to be generated by a tjpp macro. The new user-defined
macro will directly generate a block of code, instead of returning
a short string of code as do my_macro/timestamp and
my_macro/perc.
The new macro my_macro/get_results
is commented below, as are
the input "Results.tj" and output "Results.java" files. Input
and output fragments are listed below.
Input:
: MY_MEMBERS=int/cust_id ,%
String/first_name ,%
String/last_name ,%
float/balance ,%
String/email
$ my_macros/get_results(BY_NUMBER,rs,MY_MEMBERS)
$ my_macros/get_results(BY_NAME,results,MY_MEMBERS)
Output:
int rCustId = rs.getInt( 1);
String rFirstName = rs.getString( 2);
String rLastName = rs.getString( 3);
float rBalance = rs.getFloat( 4);
String rEmail = rs.getString( 5);
int rCustId = results.getInt( "CUST_ID");
String rFirstName = results.getString( "FIRST_NAME");
String rLastName = results.getString( "LAST_NAME");
float rBalance = results.getFloat( "BALANCE");
String rEmail = results.getString( "EMAIL");
An alternative and more exhaustive solution to
the problems deriving from multitier data
redundancy is discussed in booklet
"somusar/SoProTech: A Sample Project".
Code Example 10 - Input code to generate Results.java
|
Line 8 uses column numbers to get the query result values.
Line 11 uses column names to get the query result values.
Note that reuse of tjpp variable
MY_MEMBERS can help increase consistency
across different sections or classes of Java code.
|
|
Source code - File "input_code/Results.tj"
|
1 : MY_MEMBERS=int/cust_id ,%
2 String/first_name ,%
3 String/last_name ,%
4 float/balance ,%
5 String/email ,%
6 wrongType/sthg_else
7 // Get results from "rs" by column number
8 $ my_macros/get_results(BY_NUMBER,rs,MY_MEMBERS)
9
10 // Get results from "results" by column name
11 $ my_macros/get_results(BY_NAME,results,MY_MEMBERS)
|
|
Code Example 11 - Code generated from Results.tj
|
Lines 5-10 result from calling my_macro/get_results
with mode BY_NUMBER.
Lines 13-18 result from calling my_macro/get_results
with mode BY_NAME.
Note that a wrongType, supplied to get_results,
purposely produced the wrong statements of lines 10 and 18,
and caused tjpp to issue a warning message.
The Java compiler would then detect the error and the generated code
would not be compiled.
|
|
Source code - File "generated_code/Results.java"
|
1 // WARNING: file "Results.java" generated from "Results.tj"
2 // Changes should be applied on the source file.
3
4 // Get results from "rs" by column number
5 int rCustId = rs.getInt( 1);
6 String rFirstName = rs.getString( 2);
7 String rLastName = rs.getString( 3);
8 float rBalance = rs.getFloat( 4);
9 String rEmail = rs.getString( 5);
10 wrongType rSthgElse = rs.get UNKNOWN ( 6);
11
12 // Get results from "results" by column name
13 int rCustId = results.getInt( "CUST_ID");
14 String rFirstName = results.getString( "FIRST_NAME");
15 String rLastName = results.getString( "LAST_NAME");
16 float rBalance = results.getFloat( "BALANCE");
17 String rEmail = results.getString( "EMAIL");
18 wrongType rSthgElse = results.get UNKNOWN ( "STHG_ELSE");
19
20 // WARNING: file "Results.java" generated from "Results.tj"
21 // Changes should be applied on the source file.
|
|
|
Source code - File "input_code/tjpp_lib/my_macros/get_results"
|
1 @ INTERFACE(mode,source)
2 |
3 | Generate statements in the form (mode = BY_NUMBER)
4 | int rCustId = source.getInt(1);
5 | or (mode = BY_NAME)
6 | int rCustId = source.getInt("CUST_ID");
7 | Actually, more arguments are supplied, namely a
8 | list of type/id arguments, like in "int/cust_id".
9 |
10 @ DASH ^
11 | Create a mapping between Java types and getXXX accessors
12 @ SET jmap^int=Int
13 @ SET jmap^float=Float
14 @ SET jmap^double=Double
15 @ SET jmap^String=String
16 @ SET jmap^boolean=Boolean
17 | Scan list of type/id pairs, skipping mode and source
18 @ SET I=2
19 @ WHILE I<REG_COUNT
20 @ SET FIELD=REG_^I
21 | Strip leading and trailing blanks
22 @ SET FIELD=$WORD(FIELD,0)
23 | Retrieve type
24 @ SET JTYPE=$FIELD(FIELD,0,/)
25 | Retrieve identifier
26 @ SET JID=$FIELD(FIELD,1,/)
27 | Check if type mapping is known, issue a warning otherwise
28 | and propagate error into Java code
29 @ SET JRESTYPE=$VALUE(jmap^JTYPE)
30 @ IF JRESTYPE~jmap
31 @ SET JRESTYPE= UNKNOWN
32 $ warning($jfileloc(src_only): don't know how to map type "JTYPE")
33 @ ENDIF
34 | Select mode of getXXX
35 @ IF mode=BY_NAME
36 @ SET JKEY="$MAKE_ID(JID,ABC_DEF)"
37 @ ELSE
38 @ SET JKEY=I
39 @ SUB JKEY 1
40 @ ENDIF
41 | Prepare a local identifier
42 @ SET JID=$MAKE_ID(r_^JID,abcDef)
43 | Prepare right-hand side of assignment
44 @ SET JVAL=source.get^JRESTYPE( JKEY)
45 | Generate tab-aligned code
46 @ ECHO $TABS( JTYPE JID = JVAL;,8,20,32,48)
47 @ ADD I 1
48 @ ENDWHILE
49 @ DASH
|
|
[Previous chapter]
[Next chapter]
[Back to top]
|