HTTP
HTML
JavaScript/
XSLT
Session State
Web Browser
5
Logical Web Architecture
HTTP
HTML Presentation Business Data Access
Servlets/XSLT Services Persistent
JavaScript/
Entities
XSLT Caches Data Service
Objects Hibernate
Session State (Java/COBOL)
JDBC
6
Logical Web Architecture
HTTP
HTML Presentation Business Data Access
Servlets/XSLT Services Persistent
JavaScript/
Entities
XSLT Caches Data Service
Objects Hibernate
Session State (Java/COBOL)
JDBC
HTTP
HTML Presentation Business Data Access
Servlets/XSLT Services Persistent
JavaScript/
Entities
XSLT Caches Data Service
Objects Hibernate
Session State (Java/COBOL)
JDBC
HTTP
HTML Presentation Business Data Access
Servlets/XSLT Services Persistent
JavaScript/
Entities
XSLT Caches Data Service
Objects Hibernate
Session State (Java/COBOL)
JDBC
HTTP
HTML Presentation Business Data Access
Oracle
Servlets/XSLT Services Persistent
JavaScript/ DB2
Entities
XSLT Caches Data Service
Objects Hibernate MSSQL
Session State (Java/COBOL)
JDBC
Database
Framework supports
Oracle
DB2
Microsoft SQL Server.
10
Logical Batch Architecture
splbatch.sh / cmd
(command line)
Scheduler
Etc.
Submission
Batch Processing
A scheduler or the command-line is used to invoke the splbatch script
(the scheduler can be a 3rd party or SPLs cdxcronbatch scheduler)
splbatch starts a batch instance of the framework
The framework controls all batch execution
Once initialized, splbatch prompts for the batch code of the batch
process to execute
11
Logical Batch Architecture
splbatch.sh / cmd
Batch Control Business Data Access
(command line) Oracle
Standalone Data Service Persistent
Scheduler Executor Objects Entities DB2
(Java/COBOL) MSSQL
Batch Process Hibernate
Etc.
JDBC
Batch Processing
The Standalone Executor invokes the Java/COBOL batch process,
based on the supplied batch control code
The business layer components perform the business functions (same
as online)
The data access layer is used to communicate with the database
(same as online)
12
Logical Architecture
The remainder of this class focuses on
Customizing the business layer
Using the data access layer
Creating batch
However
Some tools and concepts need to be introduced
before we can look at this more closely
13
SPL Services
COBOL App
Java Service
JDBC
Business Objects Data Access
Hibernate JDBC DB
16
Service Dispatching
The Service Dispatcher is invoked from a Web servlet
It invokes the appropriate service for the Web request,
which could be one of the following
1. Page service
2. List service
3. Search service
1 2 3 Search Service
Page Service List Service
17
Page Services
This is a top level application service
It orchestrates the display and update of all data for a root
object and all its child objects e.g. Person, Person
Name, Person Phone, Person Id, etc.
The data is displayed on a single tab menu across one
or more child tab pages
18
Page Service Dispatching
A Page service invoked in one of seven modes (actions)
Each service class determines if the maintenance service
is implemented in COBOL or Java and uses the
appropriate calling mechanism to invoke it
Page Service
Java Page
Add Service
same for all modes
19
List Services
This defines a list of objects
It could contain nested lists
It is used for list-oriented data e.g. Customer Contacts
20
List Service Dispatching
A List service class is invoked in single mode (List)
from the Service Dispatcher
It determines if the underlying list service is implemented
in COBOL or Java and uses the appropriate calling
mechanism to invoke it
List Service
Java List
Service
21
Search Services
These are used to support ad-hoc user searches
The results are similar to list services
The input is set of criteria and a search mode
Search Service
Java Search
Service
23
Services in General
A Web servlet invokes the Service Dispatcher for
page, list and search requests
The dispatcher executes the COBOL or Java
service, depending on the implementation
We will now take a separate look at COBOL and
Java implemented services
24
COBOL Services
COBOL App
Java Service
JDBC
Business Objects Data Access
Hibernate JDBC DB
26
COBOL Services
The Service Dispatcher checks if a Java implementation
for the service exists if not, it assumes a COBOL service
The Service Dispatcher (Java) invokes the COBOL service
wrapper in a separate child Java Virtual Machine (JVM)
The Wrapper calls the COBOL service program (like 1.5)
Service COBOL Svc
Presentation
Dispatcher Wrapper
Child
JVM
COBOL App
Java Service
JDBC
Business Objects Data Access
Hibernate JDBC DB
27
COBOL Services
The COBOL application programs do callbacks to the
framework for data access & Java objects (e.g. Java-
coded algorithms)
This technique enables COBOL to use the frameworks
database connections for data access (in the same logical
unit of work)
Service COBOL Svc
Presentation
Dispatcher Wrapper
Child
JVM
COBOL App
Java Service
JDBC
Business Objects Data Access
Hibernate JDBC DB
28
Inside COBOL Services
Page Maintenance programs orchestrate calls to
the List Maintenance programs
The List & Page programs call the Row
Maintenance programs for DB access
Service COBOL Svc
Dispatcher Wrapper
Page Row
Maintenance Maintenance
29
Inside COBOL Services
As example, this shows the Person object maintenance in
COBOL
Well use this example on the following slides
Note the row maintenance program names
Person Person
Page Row
30
Inside COBOL Services
See how this maps to the entity relationship for the
Person at the data level
There is one row maintenance program per table
The Entity relationship for the main CCB object (e.g.
Person, Account, etc.) is known as a Maintenance Object
Service COBOL Svc
Dispatcher Wrapper
Person
CI_PER
Page
31
Inside COBOL Services User Exits
COBOL user exit points exist in the Row and Page
Maintenance programs and will continue to work on V2
HOWEVER, in the Java world we use Change Handlers
well learn more about this later
32
COBOL Services Recap
COBOL will continue to be maintained and
supported
Programmers should in future use Java to code
extensions
Lets take a quick look at Java services
33
Java Services
Some services are now coded entirely in Java
These are mostly Admin services for example
AlgorithmType
SA Type
Characteristic Type
etc.
34
Java Services
The Service Dispatcher checks if a Java implementation
for a service exists (if not, it assumes a COBOL service)
The Service Dispatcher invokes the Java service e.g.
Java Page or Search service
COBOL App
Java Service
JDBC
Business Objects Data Access
Hibernate JDBC DB
35
Java Services
The Java service invokes the maintenance, list or search
objects to satisfy the Web servlets request
In general, Java objects communicate with the DB using
HQL (Hibernate) in the data access layer
They can also contain JDBC (SQL) calls
Service COBOL Svc
Presentation
Dispatcher Wrapper
COBOL App
Java Service
JDBC
Business Objects Data Access
Hibernate JDBC DB
36
Java Services
Java services consist of many components:
Framework ones
Generated ones
Application based hand-coded ones
37
Business Entities
+createDTO()
Person_Gen PersonName_Gen
-id -id
-address1 CI_PER_NAME -entityName
CI_PER
+getId() +getId()
+getAddress() PK,FK1 PER_ID +getEntityName()
PK PER_ID PK SEQ
Person_Impl ADDRESS1 ENTITY_NAME PersonName_Impl
PersonName
Person Interface
Interface
39
Inside Business Entities
A class for an entity has a superclass and a number of
subclasses (in reality, there is more than shown here)
Most of these are framework or generated
Only a small number require human coding (e.g. the
starred ones ( ) below)
AbstractBusinessEntity
+createDTO()
Person_Gen PersonName_Gen
-id -id
-address1 CI_PER_NAME -entityName
CI_PER
+getId() +getId()
+getAddress() PK,FK1 PER_ID +getEntityName()
PK PER_ID PK SEQ
Person_Impl ADDRESS1 ENTITY_NAME PersonName_Impl
PersonName
Person Interface
Interface
40
Business Entity and Related Classes
Business Entity related classes are divided into 3
categories:
1. Framework
2. Generated
3. Hand-coded
AbstractDataTransferObject StringId AbstractBusinessEntity interface AbstractEntityList
SimpleEntityList
+createDTO()
Person_Id Person_Gen
Person_DTO
-id PersonNames_Impl
-address1 interface
PersonNames
+getId()
+getAddress() +add()
+remove()
interface
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()
41
Business Entity and Related Classes
The goal of the framework was to keep hand-coded logic
to a minimum
When creating a new Business Entity, only the Impl
class is hand coded; others are framework or generated
by the Artifact Generator more about this later
AbstractDataTransferObject StringId AbstractBusinessEntity interface AbstractEntityList
SimpleEntityList
+createDTO()
Person_Id Person_Gen
Person_DTO
-id PersonNames_Impl
-address1 interface
PersonNames
+getId()
+getAddress() +add()
+remove()
interface
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()
42
Business Entity and Related Classes
Lets look at how the classes below are used
Business Entities
Data Transfer Objects (DTOs)
String Ids
Entity Lists
AbstractDataTransferObject StringId AbstractBusinessEntity interface AbstractEntityList
SimpleEntityList
+createDTO()
Person_Id Person_Gen
Person_DTO
-id PersonNames_Impl
-address1 interface
PersonNames
+getId()
+getAddress() +add()
+remove()
interface
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()
43
Business Entities
Business Entities handle database persistence i.e. they
are responsible for the retrieval and storage of data
The Java programs typically do not call the database
directly; they use the Business Entities where possible
For example, to fetch a Person from the database
Person_Id perId = new Person_Id("1185477091");
Person perEntity = perId.getEntity();
AbstractBusinessEntity
Person_Gen
-id
-address1
+getId()
+getAddress()
interface
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()
44
Business Entities
To fetch multiple persons from the database
Query query = SessionHolder.getSession().createQuery("from Person");
Person perEntity = null;
QueryIterator qIter = query.iterate();
while (qIter.hasNext()) {
perEntity = (Person)qIter.next();
...
}
AbstractBusinessEntity
+getInfo() +getInfo()
+getDTO()()
+setDTO()()
45
Business Entities
The framework creates instances of Business Entities
when fetching data for example
Person perEntity = perId.getEntity();
or
Person perEntity = (Person)qIter.next();
Person : Person_Impl
id = 1550000001 PER_ID ADDRESS1
address1 = Easy Street 1550000001 Easy Street
Person : Person_Impl 7804500002 Penny Lane
id = 7804500002
address1 = Penny Lane
46
Business Entities
Creating a new instance of a Business Entity creates a
new database row (when the transaction commits)
Likewise, when changing or deleting an instance, the
database row is updated or deleted (when the transaction
commits)
The database commit happens at the frameworks
discretion the application code has no direct control
over it
Person : Person_Impl
id = 1550000001 PER_ID ADDRESS1
address1 = Easy Street 1550000001 Easy Street
Person : Person_Impl 7804500002 Penny Lane
id = 7804500002
address1 = Penny Lane
47
Business Entities
A Business Entity has getters (get methods) for
retrieval of its properties
Example
Person perEntity = (Person)query.firstRow();
String emailAddress = perEntity.getEmailAddress();
Will retrieve a persons email address
Most getters are specific to an object (e.g. emailAddress
on Person), but there are common ones
AbstractBusinessEntity
getId() retrieves identifier (Account Id,
Person Id, Premise Id, etc.) depending on the object
Person_Gen
getDTO() retrieves an instance of a Data Transfer -id
-address1
+getId()
Object (DTO) for the Business Entity +getAddress()
interface
Person
Person_Impl
More about Ids and DTOs in a +getId()
+getAddress1()
minute +getInfo()
+getDTO()()
+getInfo()
+setDTO()()
48
Business Entities
A Business Entity does not have setters for its
properties
Properties can only be updated via a DTO
A Business Entity has a setDTO() method to
register a modified DTO and thus update the
database
AbstractBusinessEntity
Person_Gen
More about Ids and DTOs in a minute -id
-address1
+getId()
+getAddress()
interface
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()
49
Data Transfer Objects
Data Transfers Objects (DTOs) are transient (temporary /
non-persistent) holders of Business Entity properties
They are acquired via the Business Entity getDTO()
method, for example
Person perEntity = (Person)query.firstRow();
Person_DTO perDTO = perEntity.getDTO();
Person_DTO
50
Data Transfer Objects
Updating a DTO property (via setter method) does not
update the entity (database object) automatically
A Business Entity has the setDTO method to update a
modified DTO, for example
Person perEntity = (Person)query.firstRow();
Person_DTO perDTO = perEntity.getDTO();
perDTO.setEmailAddress(testemail@splwg.com);
perEntity.setDTO(perDTO);
Person_DTO
51
String Ids
Simple string keys (e.g. Person Id) are defined as objects
in the framework
An ID is retrieved from a DTO or Business Entity, e.g.
Person_Id perId = perDTO.getId();
or
Person_Id perId = perEntity.getId();
Person_Id
52
String Ids
An Id object can also be used to retrieve a
Business Entity, for example
Person_Id perId = new Person_Id("6785704944");
Person perEntity = perId.getEntity();
Person_DTO perDTO = perEntity.getDTO();
...
StringId
Person_Id
53
Entity Lists
PersonNames_Impl
interface
PersonNames
+add()
+remove()
54
Entity Lists
For example, to retrieve all person names for a person:
Person_Id perId = new Person_Id("1185477091");
Person perEntity = perId.getEntity();
PersonNames perNames = perEntity.getNames();
Iterator iterator = perNames.iterator();
while (iterator.hasNext()) {
PersonName perName = (PersonName)iterator.next();
String entityName = perName.getEntityName();
...
}
interface AbstractEntityList
SimpleEntityList
PersonNames_Impl
interface
PersonNames
+add()
+remove()
55
Artifact Generator
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()
57
Class Annotations
Meta-data is used to describe the Java objects to the
Artifact Generator - the Meta-data therefore lives in the
Java code (although some is still in the database)
We use annotations to define the metadata for a class
Annotations are stored in Java-doc comments before the
class definition (enclosed in /** and */)
We use structured annotations:
Demarked by @ followed by annotation name (e.g. @BusinessEntity)
Contain comma-separated property-value pairs (i.e. property=value)
Value can be string, Boolean, array or another annotation
58
Class Annotations
Heres an example
1 /**
2 @SampleAnnotation (
simpleString = value,
complexString = "A string with spaces",
3 boolean = true,
arrayOfStrings = {abc, def, "g h i" },
fkAnnotation = @NestedAnnotation ( property = value ),
4 arrayOfAnnotations = { @ChildAnnotation (name=first),
@ChildAnnotation (name=second)}
)
1 */
public class ExampleClass {
....
}
1. Java-doc comments
2. Annotation name
3. Property-value pairs strings and Booleans
4. Array of annotations
59
Class Annotations
Different annotations exist for different
components, for example:
@BusinessEntity defines how to create artifacts for
persistent objects (the Artifact Generator creates
Hibernate mapping files and objects based on this)
@ChangeHandler declares a change handlers class and
binds it to the persistent entity which is to be monitored for
events
@AlgorithmComponent binds the algorithm class to the
business entity and declares the soft parameters
61
The Software Development
Kit (SDK)
63
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code
Sy
st
em
D
at
a
Project
Dev DB
Sy
st
em
D
at
a
Project
Dev DB
Sy
st
em
D
at
a
Project
Dev DB
Sy
st
em
D
at
a
Project
Dev DB
67
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code
Sy
st
em
D
at
a
Project
Dev DB
A development workstation
1. Is created as an image of the project repository initially
2. Is where a developer codes and tests customizations for a project
unit-tested code is submitted back to the project repository
68
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code
Sy
st
em
D
at
a
Project
Dev DB
69
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code
Sy
st
em
D
at
a
Project
Dev DB
70
Development Workstation Setup
The development workstation and the project repository
are setup with the same software, 3rd party development
tools and contain the same components required for
development
Basically, a development workstation consists of the
following
A full web/application server installation of the SPL product being
customized besides the database, a development workstation is a
standalone system of the product
The SDK client containing COBOL development tools (to be phased
out over time)
The Net Express IDE for COBOL development
The Eclipse SDK for Java development
71
Development Workstation Folders
A development workstation will contain the following
folders under the SPL environment folder (the
<SPLEBASE> folder, e.g. C:\spl\CCBDEMO)
72
Development Workstation Folders
Most of these folders are base application server folders
The java and SPLSDKCommon folders are created
during the SDK installation
73
Development Workstation Folders
The Java folder contains the following sub-folders
source contains the Java source code the source is created and
edited using Eclipse
sourcegen is where the artifact generator places the generated Java
classes
target is where the Java compiler places the compiled Java classes
(the .class files)
74
Development Workstation Folders
The SPLSDKCommon folder contains the following sub-
folders
75
Development Workstation Folders
There is also the <SPLSDKROOT> folder, which by default
is called SPLSDK it has the following structure
76
Development Workstation Folders
There is also the <SPLSDKROOT> folder, which by default
is called SPLSDK it has the following structure
78
Development Workstation Folders
applications\root\WEB-INF\lib
This folder contains all the jar files for the online application server
Included here are the framework jars
spl-base-2.0.10.jar
spl-shared-2.0.10.jar
and the product jars, for example for CC&B
spl-ccb-2.0.5.jar
and many others
79
Development Workstation Folders
applications\root\WEB-INF\lib
This folder will also house your cm.jar file, which contains all your
customization class files (programs)
We will see in the next topic how to create this jar file from Eclipse
80
Development Workstation Folders
standalone\lib
This standalone folder contains all the jar files for the batch server
and remote COBOL JVMs
It contains mostly the same jar files as the online app server folder,
including the framework and product ones mentioned earlier
You need to also place your cm.jar file in this folder to run your Java
batch programs
81
Development Workstation for Training
Everything weve seen up to now applies to a
standard SDK environment
For this training, the following differences exist
There is no project repository each training workstation
is a developers workstation
There are some additional folders created to avoid
overwriting the standard SDK ones
82
The Additional Training Folders
Under the SPL environment folder, javaTraining exists as
a substitute for the standard java folder
As with the java folder, it contains the source, sourcegen and target
folders for the Java source, artifact-generated and Java class files
respectively
In addition, it has a test folder for Java source related to unit testing
we will see later when we get to the unit testing (JUnit) topic what
goes into this folder
It also has a config folder with a training-specific spl.properties file
83
The Additional Training Folders
Under the SPLSDKCommon folder, eclipseTrainingProject
exists as a substitute for the standard eclipseProject
folder
84
Starting the SDK
The SDK installation creates a Program Group on
the Windows Start menu
85
SDK Folders Walkthrough
Open Windows Explorer and navigate to your
SPL folder
Make a note of the name of your application
environment folder (e.g. C:\spl\CCBDEMO) you
will need this name when configuring the Eclipse
environment
Confirm that the javaTraining and
SPLSDKCommon\eclipseTrainingProject folders
exist
Also verify that the <SPLSDKROOT> folder (e.g.
C:\SPLSDK) exists although we wont
necessarily need to reference this folder
86
What next?
Next we will walk through the Eclipse SDK to
configure it for the training and become familiar
with some of its basic features
87
Introduction to Eclipse
90
The Eclipse SDK Walkthrough
Close the Welcome tab if its shown
93
Eclipse Walkthrough Import Training
Go to menu File ->
Import
Select Existing
Projects into
Workspace
Click Next
94
Eclipse Walkthrough Import Training
Enter the
SPLSDKCommon
folder name under
your SPL
environment folder
in the root
directory text box
Make sure that
only the Training
project is selected
Make sure that the
Copy projects into
workspace box is
unchecked!
Click Finish
95
Eclipse Walkthrough Training Project
Once the project has been fully imported, you should see
the Training project defined in your Package Explorer
view
You will recognize the folders from the ones discussed
under the SDK section these folders are linked to the
appropriate folders in your SPL environment folder
right-click and view the folder properties to find its actual
location on the file system
96
Eclipse Walkthrough Training Project
99
Eclipse Walkthrough Compile / Refresh
To compile your source, simply save it it will be
compiled and checked automatically
To rebuild the project, which must be done after artifact
generation, refresh it by selecting the project in the
Package Explorer view and hitting the F5 key
The refresh will also synchronize the project with the file
system, which would be necessary if you have applied
updates outside of Eclipse e.g. after synchronization
with the Project Repository
A refresh will recompile only those files that have
changed sometimes it may be necessary to do a full
rebuild of the project use the Project -> Clean menu
item to do that
100
Eclipse Walkthrough Miscellaneous
101
Eclipse Walkthrough Miscellaneous
102
Eclipse Walkthrough Miscellaneous
103
What next?
Now that we have some knowledge of the folder
structures and tools, we are ready to try a few
customizations
104
Customizations
106
Change Handlers
Part I
108
Change Handlers I Example 1
/**
* @ChangeHandler (entityName = characteristicType)
*/
public class CmCharacteristicType_CHandler
extends AbstractChangeHandler {
...
}
In this example
The annotation specifies a Change Handler for Business
Entity Characteristic Type
It extends AbstractChangeHandler
The class name ends in _CHandler
109
Change Handlers I
Change Handlers add event-driven logic to
entities (similar to COBOL row user exits)
They can perform 2 things:
1. Validate data changes
2. Cause cascading changes
110
Change Handlers I Validation Rules
The framework uses Validation Rules to determine how
to validate a Business Entity at runtime
The Validation Rules for a Business Entity are declared
in a Change Handler
The declarative style means the programmer specifies
WHAT to validate, not HOW or WHEN
A number of standard rules exist that require minimal
programming, but custom rules can be coded if needed
Custom rules require programming these contain the
step-by-step logic of HOW to validate
Validation rules are side-effect free, which means
They cannot change the persistent state of the system (cant update)
It insures all validations are performed on a complete set of changes
111
Change Handlers I Validation Rules
The following standard rules exist
AllowAndRequireRule both allows and requires a property to be
populated
AllowRule allows a value to be populated
CustomRule creates a rule out of a Custom Validation class (to
implement logic not handled by any of the above)
NotAllowRule one or more properties are not allowed
PlaceHolderRule this is a place holder when a Change Handler is
developed they are replaced with the actual rules during
development
ProtectRule prevents a property from being changed
RequireRule requires a property to be populated
RestrictRule restricts a property to a set of values
Refer to the SDK documentation for more details on
these rules
112
Change Handlers I Validation Rules
The framework invokes the getValidationRules
method on a Change Handler for all the
validation rules for a Business Entity
The getValidationRules method must return an
array of validation rule objects
To use a standard rule, simply use the static
factory method on the rule itself for example
RequireRule.alwaysRequire() returns an instance of the
RequireRule class that insures an entity property has a
value
RestrictRule.validatedMustEqualReference() returns an
instance of the RestrictRule class that checks if a
property is equal to a specific value/reference
113
Change Handlers I Validation Rules
A Validation Rule requires a Property on the
Business Entity (i.e. the field) to validate
A property is a reference to an entity field
Properties exist as constants on the business
interfaces for example
Person.properties.emailAddress refers to email address
field on Person Business Entity
Account.properties.setUpDate is the setup date field on
the Account entity
Properties are passed to the Validation Rules as
parameters to tell a rule which property to
validate
114
Change Handlers I Validation Rules
Example make Email Address field on Person required
public static ValidationRule emailRequiredRule() {
return RequireRule.alwaysRequire("Person:Email is required",
"The person's email address must be specified",
Person.properties.emailAddress);
}
Here we see
Static method emailRequiredRule to instantiate a
RequiredRule object using factory method alwaysRequire
Person.properties.email to tell the rule to validate the
Email Address property (i.e. field) on Person
Public method getValidationRules to provide a list of the
rules to the framework (only one in this case)
115
Exercise 1 Change Handler Validation 1
All Students
Create a Person change handler in the java folder of your project
Place it in package com.splwg.cm.domain.customerinfo.person
Name it CmPerson_CHandler
Add validation rule address1RequiredRule to make address line 1 required
Optional
Note: this exercise is very similar to the above, but will lead to a more challenging
exercise 3
Test
Use the online system to test your change handler
116
Unit Testing
118
Unit Testing More About Validation
The triggering of validation can be controlled
programmatically if needed
It may be necessary where multiple entities require
validation as a coherent set of changes
To illustrate this, consider the example of validating a
new Person and Person Name, but only once the entities
have been created i.e. to defer validation until both
entities are created
To defer validation until later, use framework method
startChanges() before the update and saveChanges()
after the update
NOTE: saveChanges() does not issue commit to database!
Lets take a look at the code for this example
119
Unit Testing Example: Defer Validation
1 startChanges();
Person_DTO perDTO = (Person_DTO)this.createDTO(Person.class);
Person_Id perId = new Person_Id(1234567890);
2 perDTO.setId(perId);
Person person = perDTO.newEntity();
PersonName_DTO perNameDTO =
(PersonName_DTO) createDTO(PersonName.class);
PersonName_Id perNameId = new PersonName_Id(person,
BigInteger.ONE);
3 perNameDTO.setId(perNameId);
perNameDTO.setEntityName(Blog,Joe");
perNameDTO.setNameType(NameTypeLookup.constants.PRIMARY);
PersonName perName = perNameDTO.newEntity();
4 person.getNames().add(perName);
5 saveChanges();
120
Unit Testing Back to Testing: JUnit
To ensure quality code, an automated unit testing
procedure is required
The reasons for automated testing are
One small change can unexpectedly break other parts of the system
automated tests provide early notification of these bugs
Studies show that to fix bugs costs more the longer they are
undiscovered automated tests prevent this
Automated tests are useful (albeit technical) forms of functional
documentation they describe to the programmers the expected
inputs/outputs
121
Unit Testing - JUnit
The framework contains many abstract tester
classes, one for each type of test for example
AbstractEntityTestCase tests a Business Entity and its
related Change Handlers. It also ensures all the
Validation Rules in the Change Handler have fired
AlgorithmImplementationTestCase tests an algorithm
function
122
Unit Testing - JUnit
First step is to create a JUnit test class
public class CmPerson_CHandler_Test extends AbstractEntityTestCase {
123
Unit Testing - JUnit
Now we add a method for each test case
public void testEmailRequiredRule() {
124
Unit Testing - JUnit
Lets add some code to test our email required rule
public void testEmailRequiredRule() {
Person_Id perId = new Person_Id("5775933103");
1 Person person = perId.getEntity();
2 Person_DTO goodDTO = person.getDTO();
3 goodDTO.setEmailAddress("somebody@someplace.com");
4 person.setDTO(goodDTO);
}
126
Unit Testing - JUnit
So lets add some more code
public void testEmailRequiredRule() {
...
try {
Person_DTO badDTO = person.getDTO();
1 badDTO.setEmailAddress(null);
2 person.setDTO(badDTO);
3 fail("a validation error should have been thrown");
} catch (ApplicationException exception) {
// Make sure the correct rule was violated.
4 verifyViolatedRule(CmPerson_CHandler.emailRequiredRule(),
exception);
}
}
127
Unit Testing - JUnit
Heres the complete test method
public void testEmailRequiredRule() {
Person_Id perId = new Person_Id("1648461517");
Person person = perId.getEntity();
Person_DTO goodDTO = person.getDTO();
goodDTO.setPersonOrBusiness(
PersonOrBusinessLookup.constants.PERSON);
goodDTO.setEmailAddress("somebody@someplace.com");
person.setDTO(goodDTO);
try {
Person_DTO badDTO = person.getDTO();
badDTO.setEmailAddress(null);
person.setDTO(badDTO);
fail("a validation error should have been thrown");
} catch (ApplicationException exception) {
// Make sure the correct rule was violated.
verifyViolatedRule(CmPerson_CHandler.emailRequiredRule(),
exception);
}
}
With this method, the JUnit test should run with no errors or failures an error
or failure would mean a problem in the test class or application code
128
Exercise 2 JUnit Test 1
All Students
Create a JUnit test class for your Person validation rule from
exercise 1 in the test folder of your project
Place it in package com.splwg.cm.domain.customerinfo.person
Name your class CmPerson_CHandler_Test
Add a method to test your validation rule
Optional
Create a JUnit test class for your Premise validation rule from
exercise 1
Test
From Eclipse, right-click on your test class and select Run As ->
JUnit Test
129
Change Handlers
Part II
132
Change Handlers II Conditional Validation
Example email address required if life support flag is set
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
1 return RequireRule.ifReferenceEqualsValue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
2 Person.properties.emailAddress,
3 Person.properties.lifeSupportSensitiveLoad,
4 LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
5 com.splwg.base.domain.StandardMessages.fieldMissing());
}
Optional
Modify your Premise change handler from exercise 1
Change the validation rule to make city required only if the county is not
equal to constant value San Francisco
Rename the validation rule to indicate that its conditional e.g.
cityRequiredIfCountyNotSFRule
Test
Update your JUnit test class from exercise 2 to test the conditional
validation
134
Base Messages
will be displayed as
Bill Cycle field missing
%1
138
Base Messages Modifying
Base message text may not be modified (it is
prevented by the system) - changes would be
overwritten at the next upgrade anyway
However, you can ADD customized message text
for a base message on the Details tab
139
Base Messages Modifying
The Customer Specific Message Text must use
the same substitution variables as the base one
The framework will ALWAYS display the customer
specific message if present it is not possible to
conditionally display the base Message Text if
custom text for it exists
140
Base Messages Java Definitions
Each category has its own class to define message variables and
methods
addError(StandardMessages.fieldMissing("EMAILID"));
142
Base Messages Runtime Definition
143
Base Messages Declarative Definition
The previous slide shows a RUNTIME message definition
Remember, validation rules are declarative
We therefore also need a declarative version of the
message to use in the validation rules
144
Base Messages Declarative Definition
In the last exercise we used the declarative version of
StandardMessages.fieldMissing
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
return RequireRule.ifReferenceEqualsValue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
Person.properties.emailAddress,
Person.properties.lifeSupportSensitiveLoad,
LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
com.splwg.base.domain.StandardMessages.fieldMissing());
}
fieldMissing has a runtime AND declarative message
method, but not all messages require both versions
Those used in validation rules require declarative ones; those
displayed from other runtime code (e.g. algorithms) require runtime
versions
Well see in a moment how to use a runtime message
145
Custom Messages
147
Custom Messages Creating
ONLY category 90000, Implementers
messages, may contain new custom
messages
To create a new message, you select
category 90000 and insert a new
message as shown below
% variables here must be supplied in
the classes that display the message
148
Custom Messages Java Definition
On the Java side, these are the basic initial setup rules
for creating custom messages
1. Create a CustomMessages class (supplied with this course) to
contain all your custom message definitions
2. CustomMessages must extend AbstractMessageRepository
3. In CustomMessages, specify 90000 as the message category
4. In CustomMessages, define all your custom message numbers
5. Place CustomMessages in the com.splwg.cm.domain package
6. In each individual sub-package under package cm, you create a
MessageRepository class for the message methods specific to that
sub-package Note: common message methods are placed in the
CustomMessages class
7. Each MessageRepository extends CustomMessages and contains
the runtime and declarative methods for that sub-package
Lets take a closer look
149
Custom Messages Java Definition
1 package com.splwg.cm.domain;
import com.splwg.base.domain.common.message.AbstractMessageRepository;
2 import com.splwg.cm.domain.templates.MessageRepository;
3 public class CustomMessages extends AbstractMessageRepository {
4 public static final int MESSAGE_CATEGORY = 90000;
5 public static final int REQ_IF_CONDITION = 10006;
6 private static MessageRepository instance;
public CustomMessages() {
7 super(MESSAGE_CATEGORY);
}
8 static MessageRepository getInstance() {
if (instance == null) instance = new MessageRepository();
return instance;
}
}
151
Custom Messages MessageRepository
Next we create the MessageRepository class in
the sub-package under package cm
It must extend the CustomMessages class
It only contains the methods for the messages
relevant to the sub-package
All static definitions for the message numbers
should be in CustomMessages
Lets look at the example
152
Custom Messages MessageRepository
MessageRepository class
1 package com.splwg.cm.domain.customerinfo.person;
import com.splwg.cm.domain.CustomMessages;
2 public class MessageRepository extends CustomMessages {
3 private static MessageRepository instance;
4 private static MessageRepository getInstance() {
if (instance == null) instance = new MessageRepository();
return instance;
}
}
154
Custom Messages Runtime Method
Lets add a runtime method for our message in the
MessageRepository class
1 public static ServerMessage requiredIfCondition(String fieldName1,
String fieldName2) {
2 MessageParameters parms = new MessageParameters();
parms.addField(fieldName1);
3 parms.addField(fieldName2);
4 return getInstance().getMessage(REQ_IF_CONDITION, parms);
}
155
Custom Messages Using at Runtime
Here we see how to set a message at runtime
Person_Id perId = new Person_Id("1234567890");
Person person = perId.getEntity();
Person_DTO perDTO = person.getDTO();
if ((perDTO.getLifeSupportSensitiveLoad().equals(
LifeSupportSensitiveLoadLookup.constants.
LIFE_SUPPORT_SENSITIVE_LOAD))
& perDTO.getEmailAddress().equals("")) {
addError(MessageRepository.requiredIfCondition("EMAILID",
"LS_SL_FLG"));
}
157
Custom Messages Declarative Method
Lets also add a declarative method for our validation rule
1 public static ServerMessageTemplate requiredIfCondition(
LookupProperty prop) {
2 ServerMessageParameter[] messageParms = {
ServerMessageParameter.OFFENDING_PROPERTY_NAME,
ServerMessageParameter.createDisplayingName(prop)
};
3 return getInstance().getDeclarativeMessage(REQ_IF_CONDITION,
messageParms);
}
158
Custom Messages Declarative Method
Lets also add a declarative method for our validation rule
1 public static ServerMessageTemplate requiredIfCondition(
LookupProperty prop) {
2 ServerMessageParameter[] messageParms = {
ServerMessageParameter.OFFENDING_PROPERTY_NAME,
ServerMessageParameter.createDisplayingName(prop)
};
3 return getInstance().getDeclarativeMessage(REQ_IF_CONDITION,
messageParms);
}
159
Custom Messages Using Declarative
Using the custom declarative message in a validation rule
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
return RequireRule.ifReferenceEqualsValue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
1 Person.properties.emailAddress,
Person.properties.lifeSupportSensitiveLoad,
LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
2 MessageRepository.requiredIfCondition(
3 Person.properties.lifeSupportSensitiveLoad));
}
1. Person.properties.emailAddress is automatically set as the
OFFENDING_PROPERTY_NAME, so it does not need to be passed
to the declarative method as a parameter as seen on the previous
slide, we use this name to substitute the 1st message parameter
2. We now reference our custom requiredIfCondition method in the
validation rule
160
Custom Messages Using Declarative
Using the custom declarative message in a validation rule
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
return RequireRule.ifReferenceEqualsValue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
1 Person.properties.emailAddress,
Person.properties.lifeSupportSensitiveLoad,
LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
2 MessageRepository.requiredIfCondition(
3 Person.properties.lifeSupportSensitiveLoad));
}
3. The parameter we pass in is the property of the field to substitute the
messages 2nd parameter
161
Exercise 4 Custom Declarative Message
All Students
Use the online system to create a descriptive message for the Person
validation rule in exercise 3
Each student should use a unique message number when working on a
shared database the instructor can assign message numbers, starting at
message number 10001
Use your initials in the message to distinguish it
Create the message with 2 parameters the offending field name and the field
name used in the comparison
For example: %1 is required if %2 is BUSINESS (XX) where XX are your
initials
Update the CustomMessages class and add a constant for your new
message number e.g. REQUIRED_IF_ BUSINESS
Copy the supplied MessageRepository template to your person sub-
package and add a method for use in the validation rule e.g.
requiredIfBusiness()
162
Exercise 4 Custom Declarative Message
All Students (continued)
Update your validation rule from exercise 3 to reference the new
message
Optional
Perform the above steps to create a descriptive message for your
Premise validation rule
Start at message number 20001
For added complexity, create a 3rd message parameter in which you specify
the string value (constant) that the county is compared to
For example: %1 required if %2 not %3 (XX) where XX are your initials
(see attached note)
Test
Use the online system to validate that the new message is displayed
163
Change Handlers
Part III
167
Exercise 5 Change Handler Validation 3
All Students
Modify your Person change handler from exercise 3
Introduce a Condition in your validation rule to make address line 1
required if the person type is Business (same validation as in exercise 3)
Change the validation rule to use the Condition
Optional
Modify your Premise change handler from exercise 3
Introduce a Condition in your validation rule to make city required if the
county is not equal to San Francisco (same validation as in exercise 3)
Change the validation rule to use the Condition
Test
Run the JUnit test class from exercise 3 to test
Startup the online system and test that your validation rule works
the same as in exercise 4
168
Change Handlers
Part IV
170
Custom Rule Eager Validation Methods
Eager validations fire immediately when an entity is
changed by way of a delete(), setDTO() or createEntity())
The event methods that can be implemented by a
custom rule class are
validateAdd() fires when a business entity is added
validateChangeOnly() fires when a business entity is changed
validateAddOrChange() fires when a business entity is added or
changed (in addition to an add or change event)
validateDelete() fires when a business entity is deleted
validateRegisteredChange() fires when a change is registered to
another object (e.g. a child) - this can be any business entity that
feels like notifying you of a change
A parameter passed to this method, RegisteredChangeDetail, can be
queried (via its getChangeToList() method) to determine if the
change affects you
171
Custom Rule Lazy Validation Methods
Lazy validations fire after a coherent set of
changes have been made this is in contrast to
eager validations that fire immediately when an
entity is modified
Only one lazy validation method exists
validateSave()
It fires at the end of a set of changes
Validation of child entities, for example, can therefore be
placed in this method
All types of changes (add, change, delete or register
change) will trigger a validateSave()
172
Custom Rule Class
These are the basic steps to create and use a custom
rule
1. Create a class that extends AbstractCustomValidation this class
could be an inner class of your Change Handler if the custom
validation rule is specific to the Business Entity being validated
2. In your new class, provide the framework with an array of entity
properties associated with the custom rule the framework uses this
to avoid additional validations on properties already known to be in
error
3. In you new class, implement the appropriate eager and/or lazy
methods to perform the validation
4. Reference the custom rule in your static validation rule method, as
you would with a standard declarative rule
173
Custom Rule MapFieldNameRequired Example
174
Custom Rule MapFieldNameRequired Example
1
2
Test
Create cm.jar and startup the online system to test
On a shared database, each student should test using a different person
177
Exercise 6 Custom Validation Rule
Optional
Create a JUnit test class for your custom validation rule and in your
testShortCommentRequiredRule() method
Create a PersonCharacteristic_Id object for the COMMENT characteristic
for your Person_Id
Because this is for an existing Person on the database, remove any existing
Short Comment characteristic before continuing with the steps below to test
the validation
Note: This remove could trigger validation on the Person, which at this stage
you want to avoid. See if you can come up with the solution.
Create a PersonCharacteristic_DTO object from the PersonCharacteristic_Id
Set the adhoc characteristic value to something e.g. Test comment
Create a new PersonCharacteristic object from the
PersonCharacteristic_DTO
Add the new PersonCharacteristic object to your collection of characteristics
All the steps up to this point perform the positive validation i.e. they
test that your validation rule does NOT get violated
178
Exercise 6 Custom Validation Rule
Optional (continued)
Test that the rule gets violated by removing the newly created
PersonCharacteristic object from the collection of characteristics this
should cause an application exception to be thrown
179
SPL Framework &
Hibernate
181
Hibernate Architecture View
This generic diagram shows
Hibernate positioned between the Application
application (e.g. SPL Framework) and
the database Persistent Objects
182
SPL Framework & Hibernate Architecture
This diagram shows
how the framework Data Transfer
implements Objects (DTO) SPL Framework
Hibernate Business
Entities
The SessionFactory SessionFactory
is a cache of Session
compiled O/R ConnectionProvider
mappings JDBC
The
ConnectionProvider JDBC
is a factory & pool of
JDBC connections
The Business Database
Entities (Persistent
Objects) are short-
lived, single-
threaded and have a
persistent state
183
SPL Framework & Hibernate Architecture
The Data Transfer
Objects (Transient Data Transfer
Objects (DTO) SPL Framework
Objects) are
Business
persistent objects Entities
that are not SessionFactory
associated with a Session
session ConnectionProvider
JDBC
A Session is a short-
lived object that JDBC
represents a
conversation
between the app and
the DB; it wraps a Database
JDBC connection
As indicated by the JDBC block on the right, the SPL Framework also
provides for direct JDBC calls if needed
184
Hibernate Background
The SPL Framework wraps Hibernate, so native
Hibernate calls are not used
We have already seen some of this, for example
the statement
Person perEntity = perId.getEntity();
This instantiates an object of class Cat from the DB table for Cat
The load() method throws an unrecoverable exception if the row does
not exist
Use the get() method to avoid the exception instead, it returns a null
if the row is not found, as shown below
186
Hibernate HQL
The Hibernate Query Language (HQL) allows for SQL-like queries
Use the find() method to query for objects
List cats = sess.find(
"from Cat as cat where cat.birthdate = ?",
date,
Hibernate.DATE
);
187
Hibernate Updating Persistent Objects
Persistent objects can be updated
At its most straightforward, you load the object, manipulate it (using
the setter methods) and then flush() the session
188
Hibernate Updating Persistent Objects
For updates across session boundaries (e.g. in an online
environment), you use the update() method of the session object
// in the first session, cat is instantiated from a db row
Cat cat = (Cat) firstSession.load(Cat.class, catId);
Cat potentialMate = new Cat();
firstSession.save(potentialMate);
189
Hibernate Deleting Persistent Objects
The delete() method of a session removes an objects
state from the database
sess.delete(cat);
190
Hibernate for SPL Framework
The previous slides show native use of Hibernate
persistent objects and HQL
As weve seen, internally the framework uses
Hibernate for persistence
The frameworks database persistence therefore
is similar to native Hibernate it just uses some
different terminology
Persistent Objects = Business Entities
Transient Objects = Data Transfer Objects
Much of this has been covered before, but well
review and add some new things over the
following slides
191
Hibernate for SPL Framework
Business Entity / DTO
Creating a new Business Entity equates to creating a new
database row
Likewise, when a Business Entity is changed or deleted,
the same action is performed on the database
Actual inserts, updates and deletes on the DB are
controlled by the framework
Properties on a Business Entity can only be updated via
the Data Transfer Object (DTO)
192
Hibernate for SPL Framework
Business Entity / DTO
To instantiate a new Business Entity from the DB
Person_Id perId = new Person_Id("1185477091");
Person perEntity = perId.getEntity();
or
Person perEntity = (Person)query.firstRow();
or
Query query = SessionHolder.getSession()
.createQuery("from Person");
Person perEntity = null;
QueryIterator qIter = query.iterate();
wile (qIter.hasNext()) {
perEntity = (Person)qIter.next();
...
}
193
Hibernate for SPL Framework
Business Entity / DTO
To update a property, you use the DTO
Person_DTO perDTO = perEntity.getDTO();
perDTO.setEmailAddress(testemail@splwg.com);
perEntity.setDTO(perDTO);
194
Hibernate for SPL Framework
Business Entity / DTO
and then create the Business Entity from the DTO
perDTO.setId(new Person_Id(1185477091));
perDTO.set...
Person person = perDTO.newEntity();
195
Hibernate for SPL Framework - HQL
HQL queries must also go through the SPL Framework
The framework Query class implements a subset of pure
HQL
The framework HQL queries return Business Entities
It is mostly the same as the native HQL language, except
for a few differences
The SELECT clause is not allowed in the frameworks HQL text
The ORDER BY clause is not allowed in the frameworks HQL text
UNIONs are catered for in the frameworks HQL (native HQL does not
allow it)
The framework caters for raw SQL statements
The following slides describe the frameworks
implementation of HQL
196
SPL Query SELECT clause
The SELECT clause is not used in a framework
Query call
Similar to Hibernate, the following query is valid
AlgorithmType algorithmType = ... ;
Query query = createQuery("from Algorithm algorithm +
where algorithm.algorithmType = :algorithmType");
query.bindEntity("algorithmType", algorithmType);
List algorithms = query.list();
198
SPL Query ORDER BY clause
The ORDER BY clause in HQL is not allowed by
the framework
Instead, the order must be programmatically
specified
Query query = createQuery("from Algorithm algorithm+
where algorithm.algorithmType = :algorithmType");
query.bindEntity("algorithmType", algorithmType);
query.addResult("algorithm", "algorithm");
query.addResult("algorithmId", "algorithm.id");
query.orderBy(algorithmId, Query.ASCENDING);
List queryResults = query.list();
199
SPL Query Iterate Method
For a large volume query, instead of using a List,
better performance can be gained using the
iterate method on Query
Query query = SessionHolder.getSession().createQuery("from Person");
Person perEntity = null;
QueryIterator qIter = query.iterate();
while (qIter.hasNext()) {
perEntity = (Person)qIter.next();
...
}
To add a third (or later) query, you add it directly to the union
union.addQueryToUnion(query3);
201
SPL Query Raw SQL
It may be necessary to code SQL instead of HQL
Potential reasons are
To specify performance hints
A table is not mapped to a Java entity
Instead of createQuery(), you use the JDBC-like
createPreparedStatement() method on the session object
The text is similar to the HQL Query text, but you use the
table and column names instead of the Java entity and
property names
This feature is only mentioned here for information we
do not cover it in the exercises
Please note that this is not a recommended or preferred means of
accessing the database
202
SPL Framework & Hibernate Review
The framework uses Hibernate for its database
access
All application code MUST use the framework
interfaces for Hibernate
Most of the HQL syntax is the same as for native
HQL, except for the SELECT clause, ORDER BY
clause and UNION
You can bypass Hibernate and use native SQL
Weve only covered a small part refer to
www.hibernate.org and the SPL SDK
documentation for more details
203
Change Handlers
Part V
handleAddOrChange(BusinessEntity businessEntity,
DataTransferObject oldDTO)
This fires before validation when a entity is added OR changed
The oldDTO object contains a null on an add event
handleAdd(BusinessEntity newBusinessEntity)
This fires before validation when an entity is added
It allows for cascading updates on other objects or external systems
207
Change Handlers V Events and Methods
prepareToChange(BusinessEntity unchangedEntity,
DataTransferObject newDTO)
This fires before a change to a DTO is submitted
You can use this to default values and perform other changes on a
DTO before the change
handleChange(BusinessEntity changedBusinessEntity,
DataTransferObject oldDTO)
This fires before validation when an entity is changed
It allows for cascading updates on other objects or external systems
208
Change Handlers V Events and Methods
handleRegisteredChange(BusinessEntity changedBusnessEnty,
RegisteredChangeDetail changeDetl)
This fires when a change is registered to the changedBusnessEnty
object via the business entitys registerChange method
For example, it can be fired when a child list associated with the
Business Entity has been changed
The RegisterChangeDetail object specifies the details of the change
handleDelete(DataTransferObject oldDTO)
This fires before validation when an entity is deleted
7. It adds the partially completed DTO to the accounts alert entity list
the additional parameters are required for the entity list
The framework will add the row when the transaction commits
212
Change Handlers V Cascading Changes
The previous example shows a cascading
change to a child entity (Alerts) of a Business
Entity (Account)
The basic rules when working with child entities
are
Child entity lists are acquired from a Business Entity via
the appropriate getter methods (e.g. getAlerts())
To add a new child entity, use the entity lists add methods
To remove a child entity, use the entity lists remove
methods
213
Change Handlers V Cascading Changes
When inserting and deleting entities that are NOT
child entities of the business entity being
customized, more explicit code is required
In this case the getDTO and setDTO method calls
need to be used
214
Change Handlers V handleChange Example
Update the related premise when an account is changed
1 public void handleChange(BusinessEntity changedEntity,
DataTransferObject oldDTO) {
2 Account account = (Account) changedEntity;
3 if (account.getMailingPremiseId() != null) {
4 Premise premise = account.getMailingPremiseId().getEntity();
5 Premise_DTO premiseDTO = premise.getDTO();
6 premiseDTO.setAddress4(account.getAlertInformation());
7 premise.setDTO(premiseDTO);
}
}
1. It implements the handleChange method the changedEntity object
is a reference to the account entity being changed; oldDTO is the
DTO before the change was made
2. It casts changedEntity to an Account object
3. It checks if the mailing premise Id is populated on the account
mailing premise Id is an optional foreign key reference (Note, on the
CI_ACCT table the mailing premise Id is a space, but on the
Business Entity object it is a null)
215
Change Handlers V handleChange Example
Update the related premise when an account is changed
1 public void handleChange(BusinessEntity changedEntity,
DataTransferObject oldDTO) {
2 Account account = (Account) changedEntity;
3 if (account.getMailingPremiseId() != null) {
4 Premise premise = account.getMailingPremiseId().getEntity();
5 Premise_DTO premiseDTO = premise.getDTO();
6 premiseDTO.setAddress4(account.getAlertInformation());
7 premise.setDTO(premiseDTO);
}
}
4. It gets the Premise object referenced by the mailing premise Id field
5. It gets DTO for the Premise to modify the row
6. It updates the value on the Premise DTO address line 4 in this case
is set to the accounts alert information (i.e. the Comment field on
the account page)
7. It updates the Premise Business Entity using the setDTO() method,
which ultimately causes the row to be updated
216
Exercise 7 Cascading Change Handler
All Students
Change your Person Change Handler from the previous exercise
automatically add a Short Comment characteristic (characteristic
type COMMENT) whenever a new Person is added
Test
Create cm.jar and startup the online system to test
Add a new person and verify that the Short Comment characteristic
was added by your Change Handler
Optional
Create a JUnit test class that adds a new person and verifies that the
Short Comment characteristic was automatically added. In this
exercise, a completely new person, with all its required collections
of names and Id numbers, must be created. In your test method
Suspend validation until all the data has been added
Create a new Person_Id object
217
Exercise 7 Cascading Change Handler
Optional (continued)
Create a new Person_DTO object
Set the following required fields on the Person_DTO
PersonOrBusiness
LifeSupportSensitiveLoad
LanguageId
Add the name to the Names collection on the Person object (use sequence
1)
218
Exercise 7 Cascading Change Handler
Optional (continued)
Create a PersonId_DTO object (use the getIds() method on the Person
object)
Set the following required fields on the PersonId_DTO
IsPrimaryId
PersonIdNumber
Add the Id to the Ids collection on the Person object for Id Type SSN (Social
Security Number)
Enable validation at this point (i.e. remove the suspension)
Verify that the short comment characteristic was added by getting a
PersonCharacteristic object for the expected COMMENT characteristic if
a null object is returned, fail the test as follows
219
Algorithms
Part I
222
Algorithms - Overview
Algorithms are defined in 2 places
Database tables
The online Admin menu is used to define the database components,
which are
Algorithm Types
Algorithms
The event or activity to which the algorithm applies (e.g. FT freeze, phone
number validation, etc.)
CI_ALG_PARM
CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK,FK1 ALG_TYPE_CD PK EFFDT
PK SEQNO PK,FK1 SEQNO
PARM_REQ_SW ALG_PARM_VAL
FK1 ALG_TYPE_CD
CI_ALG_PARM
2 CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK,FK1 ALG_TYPE_CD PK EFFDT
PK SEQNO PK,FK1 SEQNO
PARM_REQ_SW ALG_PARM_VAL
FK1 ALG_TYPE_CD
225
Algorithm Database Model
1 CI_ALG_TYPE 3 CI_ALG Customized Entity
PK ALG_TYPE_CD PK ALG_CD
4 CI_ALG_PARM
2 CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK,FK1 ALG_TYPE_CD PK EFFDT
PK SEQNO PK,FK1 SEQNO
PARM_REQ_SW ALG_PARM_VAL
FK1 ALG_TYPE_CD
226
Algorithm Database Model
1 CI_ALG_TYPE 3 CI_ALG 5 Customized Entity
PK ALG_TYPE_CD PK ALG_CD
4 CI_ALG_PARM Examples
2 CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK,FK1 ALG_TYPE_CD PK EFFDT Characteristic Type
PK SEQNO PK,FK1 SEQNO SA Type
PARM_REQ_SW ALG_PARM_VAL Etc.
FK1 ALG_TYPE_CD
227
Algorithm Phone Format Example
Phone format - algorithm definition diagram
Algorithm Type:PHN-FMT Algorithm:PHN-FMT-US Phone Type: BUSN
Format 1 required (999) 999-9999
Format 2 optional
Format 3 optional Algorithm:PHN-FMT-UK Phone Type: BUSN_UK
Format 4 thru 9 optional 999 9999-9999
99999 999999
9999 999-9999
CI_ALG_PARM
CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK,FK1 ALG_TYPE_CD PK EFFDT
PK SEQNO PK,FK1 SEQNO
PARM_REQ_SW ALG_PARM_VAL
FK1 ALG_TYPE_CD
228
Algorithm Phone Format Example
Admin -> Algorithm Type Phone format
1
2
3
4
229
Algorithm Phone Format Example
Admin -> Algorithm Type Phone format
1
2
3
4
230
Algorithm Phone Format Example
Admin -> Algorithm Phone format US
1
1. This is the algorithm name i.e. the 1st instance of the algorithm
type
2. The Algorithm Type that this algorithm corresponds to
3. The effective date
4. The phone format for this instance only one for the U.S.
231
Algorithm Phone Format Example
Admin -> Algorithm Phone format UK
1
1. This is the algorithm name - i.e. the 2nd instance of the algorithm
type
2. It has the same algorithm type as for the U.S. (i.e. it is the SAME
PROGRAM that formats U.S. and U.K. phone numbers)
232
Algorithm Phone Format Example
Admin -> Algorithm Phone format UK
1
3. The U.K. has multiple phone formats the algorithm will validate a
U.K. phone number against all of these formats
233
Algorithm Phone Format Example
Admin -> Phone Type Algorithm usage
1
2
234
Algorithm Phone Format Example
Main -> Person Algorithm activation
1
Business Algorithm
Algorithm Spot
Component Interface Component
PhoneTypeFormat
PhoneTypeFormat
Person Phone ValidationAlgorithmSpot
ValidationAlgComp
236
Algorithm Spots
The attributes of an algorithm spot interface class
are
It is internal to the framework, only ever created by
Product Development
It is the API to the algorithm component (from the base
application)
It is specific to the algorithm entity type (or system event)
It defines the hard input parameters for an algorithm
these are the parameters associated with a specific event
It defines the output parameters that can be retrieved after
the algorithm has been invoked
237
Algorithm Spots
These classes form part of the base code
They are invoked from the base code at appropriate times (events)
The methods on the interface are related to the algorithm type for
example, setPhoneValue() is only relevant to
PhoneTypeFormatValidationAlgorithmSpot
interface
AdhocCharacteristicValueValidationAlgorithmSpot
+setFormatOnly() : void
+setCharacteristicType() : void
+setAdhocValue() : void
+getReformattedValue() : String
interface
+isValidAdhoc() : Boolean
AlgoritmSpot
+invoke()
interface
PhoneTypeFormatValidationAlgorithmSpot
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String
238
Algorithm Components
An algorithm requires a programmatic implementation
The Algorithm Type definition carries the program name,
for example
com.splwg.base.domain.common.phoneType.
PhoneTypeFormatValidationAlgComp
Remember
An interface is empty it requires an implementation to perform
appropriate tasks
The implementation for an algorithm spot is an Algorithm Component
i.e. Business Component
interface
AlgoritmSpot
+invoke()
interface
PhoneTypeFormatValidationAlgorithmSpot
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String
PhoneTypeFormatValidationAlgComp_Gen
PhoneTypeFormatValidationAlgComp_Impl
interface
+getPhoneFormat1() : String
PhoneTypeFormatValidationAlgComp
+getPhoneFormat2() : String
+setPhoneValue() : void +invoke() : void
+getPhoneFormat3() : String
+setPhoneType() : void +setPhoneValue() : void
+getPhoneFormat4() : String
+isValidPhoneValue() : Boolean +setPhoneType() : void
+getPhoneFormat5() : String
+getPreferredFormatString() : String +isValidPhoneValue() : Boolean
+getPhoneFormat6() : String
+getReformattedPhoneValue() : String +getPreferredFormatString() : String
+getPhoneFormat7() : String
+getReformattedPhoneValue() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String
240
Algorithm Components Phone Type Validation
1. The implementation class (_Impl) is hand-coded it can be
customized
2. The component interface is generated by the artifact generator a
customized version will be generated for a custom impl class
3. An algorithm is invoked via its component interface
interface
AlgoritmSpot
+invoke()
interface
PhoneTypeFormatValidationAlgorithmSpot
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String
2
PhoneTypeFormatValidationAlgComp_Gen 1
3 PhoneTypeFormatValidationAlgComp_Impl
interface
+getPhoneFormat1() : String
PhoneTypeFormatValidationAlgComp
+getPhoneFormat2() : String
+setPhoneValue() : void +invoke() : void
+getPhoneFormat3() : String
+setPhoneType() : void +setPhoneValue() : void
+getPhoneFormat4() : String
+isValidPhoneValue() : Boolean +setPhoneType() : void
+getPhoneFormat5() : String
+getPreferredFormatString() : String +isValidPhoneValue() : Boolean
+getPhoneFormat6() : String
+getReformattedPhoneValue() : String +getPreferredFormatString() : String
+getPhoneFormat7() : String
+getReformattedPhoneValue() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String
241
Algorithm Components Phone Type Validation
interface
PhoneTypeFormatValidationAlgorithmSpot
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String
2
PhoneTypeFormatValidationAlgComp_Gen 1
PhoneTypeFormatValidationAlgComp_Impl
interface
+getPhoneFormat1() : String
PhoneTypeFormatValidationAlgComp
+getPhoneFormat2() : String
+setPhoneValue() : void +invoke() : void
+getPhoneFormat3() : String
+setPhoneType() : void +setPhoneValue() : void
+getPhoneFormat4() : String
+isValidPhoneValue() : Boolean +setPhoneType() : void
+getPhoneFormat5() : String
+getPreferredFormatString() : String +isValidPhoneValue() : Boolean
+getPhoneFormat6() : String
+getReformattedPhoneValue() : String +getPreferredFormatString() : String
+getPhoneFormat7() : String
+getReformattedPhoneValue() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String
242
Algorithm Components Phone Type Validation
interface
AlgoritmSpot
+invoke()
interface
PhoneTypeFormatValidationAlgorithmSpot
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String
PhoneTypeFormatValidationAlgComp_Gen
3
PhoneTypeFormatValidationAlgComp_Impl
interface
+getPhoneFormat1() : String
PhoneTypeFormatValidationAlgComp
+getPhoneFormat2() : String
+setPhoneValue() : void +invoke() : void
+getPhoneFormat3() : String
+setPhoneType() : void +setPhoneValue() : void
+getPhoneFormat4() : String
+isValidPhoneValue() : Boolean +setPhoneType() : void
+getPhoneFormat5() : String
+getPreferredFormatString() : String +isValidPhoneValue() : Boolean
+getPhoneFormat6() : String
+getReformattedPhoneValue() : String +getPreferredFormatString() : String
+getPhoneFormat7() : String
+getReformattedPhoneValue() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String
243
Algorithm Implementation Class
The base versions of all algorithms are provided
To create a new one, it is easiest to duplicate the
appropriate base one if it exists and modify it
The basic Java elements of a new algorithm are:
An _Impl class, the hand-coded implementation class
that contains the logic
A _Gen class, the implementation class for the soft
parameters, generated by the artifact generator
A component interface class, generated by the AG
A message method, if required
244
Algorithm Phone Format Example
2
3
4
245
Algorithm Phone Format Example
2
3
4
246
Algorithm Phone Format Example
Algorithm Spot interface methods that are implemented in _Impl class
247
Algorithm Phone Format Example
Algorithm Spot interface methods that are implemented in _Impl class
248
Algorithm Phone Format Example
Algorithm Spot interface methods that are implemented in _Impl class
1
250
Algorithm Phone Format Example
Generated artifacts that are based on the _Impl class annotation
The _Gen class has the methods for the soft parameters
The _Impl class calls these methods to get the soft parameter
values, as set on the Algorithm definition
251
Algorithm Phone Format Example
Generated artifacts that are based on the _Impl class annotation
252
Algorithm Phone Format Example
Generated artifacts that are based on the _Impl class annotation
1
2
253
Algorithm Implementation Class Review
The steps to create a new algorithm class are
1. Determine the Algorithm Spot interface name the Javadocs could
be used for this
2. Create the _Impl class, implementing the appropriate Algorithm
Spot interface
3. Add default implementations for all the Algorithm Spot methods (e.g.
using the Eclipse Source, Override/implement Methods menu item)
4. Code the annotation
5. Run the Artifact Generator to create the _Gen and component
interface classes
254
Algorithm Implementation Class Review
The steps to create a new algorithm class are
6. Edit the _Impl class and
Extend the _Gen class on the class definition
Store the required instances variables in the appropriate set methods
(these instance variables will be referenced in the invoke() method)
Code the invoke() method this contains the main logic
Return the value(s) in the get methods as required by the Algorithm
spot
7. Create the cm.jar file and shutdown and restart the application server
this is necessary for the Java class to be visible when creating the
Algorithm Type definition (next step)
8. Create the Algorithm Type definition the Java class name will now
be in the Program Name drop-down list AND will automatically insert
the Algorithm Type parameters from your annotation specification
NOTE: This is the reason for creating the Java impl class BEFORE
adding the Algorithm Type and Algorithm definitions in the UI
255
Algorithm Implementation Class Review
The steps to create a new algorithm class are
9. Create the Algorithm definition
10. Attach the algorithm to the business component
11. Test
256
Exercise 8 Geographic Type Algorithm
All Students
In this exercise you will create a Geographic Type algorithm to
validate geographic type REGION on Premise
Consider the following scenario
1. Premises may be in North America or Europe
2. Within North America, the country may be U.S.A. or Canada
3. Within Europe, the country may be United Kingdom or France
4. A geographic type of region must be created to allow for the region code to
be specified on Premise
5. The format of region code is W-CC, where
W = World Region N (North America); E (Europe)
CC = Country Code US (USA); CN (Canada); UK (UK); FR (France)
The algorithm must validate that the country code falls within its region
for example E-FR is valid; E-US is invalid
257
Exercise 8 Geographic Type Algorithm
All Students (continued)
6. The valid region code values must be specified as soft parameters i.e. no
hardcoding of values in Java are allowed
Java Requirements
The Algorithm Spot to implement is GeoTypeFormatValidationAlgorithmSpot
Name your class CmGeoTypeRegionAlgComp_Impl in package
com.splwg.cm.domain.common.geographicType
Create 2 parameters
1. worldRegion, string, required
This will contain the 1-digit world region code
2. countryCodes, string, required
This will contain a comma-delimited string of valid country codes for their
associated world region code
258
Exercise 8 Geographic Type Algorithm
Online Configuration
Create Algorithm Type XXGEOREGION (where XX are your initials)
The Algorithm Entity is Geographic Type Value Format Rule
Program Type is Java
Program Name should be CmGeoTypeRegionAlgComp
Create two new Geographic Type definitions, using the following values for
Type, Description and Format Algorithm respectively
1. XXREG-E, Region Europe (XX), XXGEOREG-E (where XX are your initials)
2. XXREG-N, Region North America (XX), XXGEOREG-N (where XX are your
initials)
259
Exercise 8 Geographic Type Algorithm
Online Configuration (continued)
From your browser, use URL http://localhost:6800/flushDropDownCache.jsp
to delete the drop-down cache on the server, and then clear the browser
cache by deleting your temporary internet files to make the new Geographic
Types known to the Premise Geographic Data page
(Note: localhost and 6800 above refer to the server name and port of your
web application server it may be named differently in your specific case)
Test
When adding or changing a Geographic Type on Premise, the
algorithm should validate the format and content of geo type and
display the generic message Premise Geographic Value format
incorrect if invalid
Optional
The JUnit test class for this exercise should check all possible
combinations of invalid world regions and country codes, but we will
only check two conditions one valid and one invalid
260
Exercise 8 Geographic Type Algorithm
Optional (continued)
Code a JUnit test class for your algorithm (the class must extend
AlgorithmImplementationTestCase) and in the test method e.g.
testGeoTypeRegion
Similar to previous exercises, create a Premise object from an existing
premise on the database
Create a new GeographicType_Id object for one of the geographic types you
defined (e.g. XXREG-E or XXREG-N)
Create a PremiseGeographicLocation_Id object for the Premise_Id (as
instantiated above) and GeographicType_Id
Suspend validation for the following steps
Create a new PremiseGeographicLocation_DTO from the Id above
On the DTO, set the value of GeographicValue (e.g. E-UK)
Add the new GeographicLocation (via the DTO) to the collection of
GeographicLocations for the Premise (note: the add method can also accept
the DTO with the GeographicType_Id (e.g. XXREG-E)
261
Exercise 8 Geographic Type Algorithm
Optional (continued)
Remove the suspension to validate that the data currently entered is valid
an application error is not expected at this point
Remove the existing PremiseGeographicLocation from the collection of
GeographicLocations
Set the GeographicValue to an invalid value (e.g. E-US)
Re-add the PremiseGeographicLocation object to the GeographicLocations
location which should trigger the validation
Catch the ApplicationError and use the following statement to verify that the
correct error was thrown
assertServerMessage(e, 3, 33901);
262
Algorithms
Part II
265
Exercise 9 Adhoc Char Value Algorithm
Java Requirements (continued)
The Algorithm Spot to implement is
AdhocCharacteristicValueValidationAlgorithmSpot
Name your class CmAdhocRegionValidationAlg_Impl in package
com.splwg.cm.domain.common.characteristicType
Create the same two parameters as before in your annotation
The invoke() method must
1. Format the region code for example
CN must be formatted to N-CN
EFR must be formatted to E-FR
2. The setFormatOnly() method is invoked from the framework to indicate whether a
format AND validate is required, or just a format. If it had been invoked with true,
return from the invoke method after the region code has been formatted,
otherwise validate it as well
3. Display the custom error message if the region code is invalid the method to
display the error is addError(ServerMessage serverMessage)
266
Exercise 9 Adhoc Char Value Algorithm
Online Configuration
Create Algorithm Type XX-AV-REGION with the necessary parameter
definitions (the Algorithm Entity is Characteristic Type Adhoc Value
Validation
Create 2 Algorithm definitions
1. XX-AV-REG-E - specifies Europe and its valid countries
2. XX-AV-REG-N - specifies North America and its valid countries
Create 2 Characteristic Type definitions
1. XX-REG-E to validate the European region
2. XX-REG-N to validate the North American region
267
Exercise 9 Adhoc Char Value Algorithm
Test
When adding or changing a Premise Characteristic of region, the
algorithm should format the region code, validate it and display your
custom message if invalid
Optional
Create a JUnit test class to validate that the region characteristic
being formatted and validate correctly
Copy the previous exercises test class and modify it to reference the
Characteristic classes instead of the GeographicLocation ones
Because the algorithm also formats the adhoc characteristic value, you
should check that the formatting is working for example, set your adhoc
characteristic value to UK (without E-); this should pass validation
268
SPL Batch
Part I
270
Batch Environment
Batch programs run outside of the web app
server, but still within the context of the
framework
The framework provides access to the business
entities and other objects
Therefore, ALL programs run under Java even
COBOL
For COBOL, all SQL calls are handled by the
framework there are no direct calls from
COBOL to Oracle/DB2/SQL Server (e.g. via
PRO*Cobol)
271
Batch Threading
The system uses threading to achieve maximum
performance
What does a threaded process do?
It determines the full workload (e.g. how many accounts?)
It divides the workload into n number of threads
It dispatches each thread to perform the workload the
workloads are executed concurrently
For example, instead of one task billing 50000
accounts, 5 tasks can each bill 10000 accounts
simultaneously this is naturally much faster
The Artifact Generator creates the necessary
components for multi-threading
272
Batch Control
Batch controls are used in batch processing to
control restartibility, program identification,
parameters, etc.
Each batch process has its own batch control
code
A batch control code defines
The program name
The program type (COBOL / Java)
The batch parameters
For example
273
Batch Control Java Example
1
2
3
4
5
274
Batch Control Java Example
1
2
3
4
5
4. The batch run number (for this batch control) of the next submission
5. Check this to accumulate the records processed counts for all
instances of one job if the job fails and restarts, it will add the
failed + restarted instances for the total records processed
should be unchecked for programs that work with flat files
275
Batch Control Java Example
1
2
3
4
5
6. These are the non-standard parameters for the batch process these
parameters are prompted for after the standard parameters
They are supplied at runtime using name=value pairs, for example
FILE-PATH=/spl/data
276
Batch Process Overview
A background process consists of 2 types of
classes
1. A BatchJob
2. A ThreadWorker
277
Batch Process Overview
280
BatchJob Class Annotation
A BatchJob class annotation looks as follows
@BatchJob (rerunnable = false, 1
2 multiThreaded = true,
3 modules={todo},
4 softParameters = { @BatchJobSoftParameter
(name=OUTPUT-DIR, type=string) },
5 toDoCreation = @ToDoCreation (
drillKeyEntity = user,
sortKeys = {lastName, firstName},
messageParameters = {firstName, lastName}
)
)
282
BatchJob Class Definition
The BatchJob class must extend class
<BatchJob class Name>_Gen, for example
283
BatchJob Class Public Methods
The following standard public methods must exist in a
BatchJob class
Method getJobWork()
This method determines the workload (using a Hibernate query)
It passes back to the framework an instance of JobWork, describing
the work to be done
The JobWork instance contains the appropriate number of
ThreadWork instances (based on the runtime thread count)
Each ThreadWork instance contains the same number of
ThreadWorkUnits
The good news: a convenience framework method exists to
handle this for you!
284
BatchJob Class Public Methods
Method getThreadWorkerClass()
This method passes back to the framework the class name of the
worker class i.e. the hand-coded class that will perform the batch
work
The framework will create an instance of this class for each
ThreadWork instance i.e. each thread
Passing back the class name (instead of an object) allows the
framework to control the instantiation of the ThreadWorker classes so
that they can be executed anywhere, even on different servers
285
The ThreadWorker Class
The ThreadWorker class is responsible for processing a single
ThreadWork instance in other words, it performs the heavy
lifting
A ThreadWorker can be executed on the same, or a different, server
as its associated BatchJob and other ThreadWorker instances
A ThreadWorker class must extend the artifact-generated class
<ThreadWorker class name>_Gen (the example below illustrates)
By convention a ThreadWorker class is coded as a static inner class
in its parent BatchJob class
public class BatchErrorToDoCreation
extends BatchErrorToDoCreation_Gen {
... BatchJob methods ...
public static class BatchErrorToDoCreationWorker
extends BatchErrorToDoCreationWorker_Gen {
... ThreadWorker methods ...
}
}
286
ThreadWorker Class Public Methods
The following standard public methods are
implemented in a ThreadWorker class
287
ThreadWorker Class Public Methods
Method createExecutionStrategy()
This methods tells the framework how the work for thread will be
processed
It returns to the framework an instance of ThreadExecutionStrategy,
of which the following implementations currently exist
1. SingleTransactionStrategy
This tells the framework to process all work in single transaction (logical
unit-of-work)
Failure results in a rollback of the entire threads updates
It is most appropriate for jobs that CANNOT tolerate errors in the middle
of a run, for example interfaces from flat files
2. CommitEveryUnitStrategy
This tells the framework to process each ThreadWorkUnit (e.g. one bill)
in its own transaction and to issue a commit after each successful
completion
It is most appropriate for jobs that CAN tolerate errors e.g. Billing
288
ThreadWorker Class Public Methods
Method InitializeThreadWork(boolean)
This is called by the framework at the start of a thread run to perform
initialization
By default it does nothing, but can be overridden to open files,
initialize variables, etc.
A Boolean parameter indicates if it was called previously
Method executeWorkUnit(ThreadWorkUnit)
This is invoked once for each ThreadWorkerUnit assigned to a
ThreadWorker
For example, for a thread processing 1000 accounts, this method will
be called 1000 times
It performs the actual work, for example to process an account for
billing
The ThreadWorkUnit parameter is a reference to the Business Entity
to be processed you use this parameters getPrimaryId method to
get the business entitys Id object
289
ThreadWorker Class Public Methods
Method finalizeThreadWork()
This method is called at the end of thread processing
It can be used to clean up after a thread, for example to
close files
290
BatchJob Example Create Batch Error ToDos
The annotation and class definition
/**
* @BatchJob (rerunnable = false,
* multiThreaded = false, 1
* modules={todo})
*/
public class CmBatchErrorToDoCreation
extends CmBatchErrorToDoCreation_Gen { 2
private static final com.splwg.shared.logging.Logger logger =
3 com.splwg.shared.logging.LoggerFactory.
getLogger(CmBatchErrorToDoCreation.class);
...
1. The getJobWork method sets up query for the work this query
retrieves BatchRun objects (CI_BATCH_RUN) that have an error
status
2. It sets the runStatus bind variable in the query to the lookup constant
ERROR
292
BatchJob Example Create Batch Error ToDos
The BatchJob methods
public JobWork getJobWork() {
1 Query errorRunQuery = createQuery("from BatchRun run +
where run.runStatus = :runStatus");
2 errorRunQuery.bindLookup("runStatus",
RunStatusLookup.constants.ERROR);
3 return createJobWorkForEntityQuery(errorRunQuery);
}
294
BatchJob Example Create Batch Error ToDos
Inner ThreadWorker method createExecutionStrategy
public ThreadExecutionStrategy createExecutionStrategy() {
// Commit on every todo. This is not expected to be a
// performance intensive process.
return new CommitEveryUnitStrategy(this);
}
295
BatchJob Example Create Batch Error ToDos
Inner ThreadWorker method initializeThreadWork
public void initializeThreadWork(
boolean initializationPreviouslySuccessful)
throws ThreadAbortedException, RunAbortedException {
// determine the ToDoType_Id that should be used by querying
// the ToDoTypes for an entry with the creation process equal
// to this one.
Query toDoTypeQuery = createQuery("from ToDoType type
where type.creationProcessId = :thisBatchControlId");
...
initializeThreadWork here determines the ToDo type to be
used by the executeWorkUnit method (next slide) when it
creates the ToDos
296
BatchJob Example Create Batch Error ToDos
Inner ThreadWorker method executeWorkUnit
1 public boolean executeWorkUnit(ThreadWorkUnit unit)
throws ThreadAbortedException, RunAbortedException {
2 BatchRun_Id errorBatchRunId = (BatchRun_Id) unit.getPrimaryId();
// get the run
3 BatchRun batchRun = errorBatchRunId.getEntity();
...
4 createToDo(batchRun);
...
298
BatchJob Creation Review
Before we get to the exercise, lets review how to create
a new BatchJob class
1. Create the class file and code the annotation
2. Run the Artifact Generator to create the _Gen classes (you must
refresh the Eclipse project after the AG has run)
3. Extend the class from the _Gen BatchJob class
4. Code the getJobWork and getThreadWorkerClass methods
5. Create the inner ThreadWorker class - extend it from the _Gen
ThreadWorker class
6. Code the createExecutionStrategy method
7. Code the initializeThreadWork method (if needed)
8. Code the executeWorkUnit method
9. Code the finalizeThreadWork method (if needed)
10. Create the batch control
299
Exercise 10 Batch 1
All Students
Create a batch program to identify Persons without Accounts and
display their details on the log
Name the program CmPersonsNoAccount in package
com.splwg.cm.domain.batch
Identify the persons as follows
from Person as per where not exists (from AccountPerson ap
where ap.id.person = per)
Test
Use the Batch - Training launch configuration from Eclipse to run
your job
The following run parameters should be specified:
Batch Code: Your batch code (e.g. XX-PNOA)
Batch Thread Number: 1
Batch Thread Count: 1
User ID: SPL
User Password: spladmin
Language Code: ENG
Take the defaults for all the other parameters (i.e. hit Enter when prompted)
301
SPL Batch
Part II
303
SPL Batch II ToDo Data Model
4 CI_MSG 5 CI_BATCH_CTRL CI_TD_MSG_PARM
C PK
PK
MESSAGE_CAT_NBR
MESSAGE_NBR
PK BATCH_CD
PK,FK1 TD_ENTRY_ID P
PK SEQ_NUM
O FK1 TD_TYPE_CD
PROGRAM_NAME R
MSG_PARM_VAL
N O
2 CI_TD_DRLKEY_TY
F PK,FK1 TD_TYPE_CD
1 CI_TD_TYPE CI_TD_ENTRY CI_TD_DRLKEY
G
PK TD_ENTRY_ID PK,FK1 TD_ENTRY_ID
I PK SEQ_NUM PK TD_TYPE_CD
PK SEQ_NUM R
CRE_BATCH_CD FK1 TD_TYPE_CD
G FLD_NAME
TBL_NAME FK1 MESSAGE_CAT_NBR KEY_VALUE
A
FK1 MESSAGE_NBR
U 3 CI_TD_SRTKEY_TY FK2 BATCH_CD CI_TD_SRTKEY M
R PK,FK1
PK
TD_TYPE_CD
SEQ_NUM
PK,FK1
PK
TD_ENTRY_ID
SEQ_NUM
M
E DEFAULT_SW KEY_VALUE E
D ORDER_FLG
D
The tables on the left are populated via the Admin menu
1. ToDo Type identifies the type of ToDo
2. Drill Key Type identifies which page to jump to when the user selects
a ToDo to work on
3. Sort Key Type determines how the ToDo list is sorted
304
SPL Batch II ToDo Data Model
4 CI_MSG 5 CI_BATCH_CTRL CI_TD_MSG_PARM
C PK
PK
MESSAGE_CAT_NBR
MESSAGE_NBR
PK BATCH_CD
PK,FK1 TD_ENTRY_ID P
PK SEQ_NUM
O FK1 TD_TYPE_CD
PROGRAM_NAME R
MSG_PARM_VAL
N O
2 CI_TD_DRLKEY_TY
F PK,FK1 TD_TYPE_CD
1 CI_TD_TYPE CI_TD_ENTRY CI_TD_DRLKEY
G
PK TD_ENTRY_ID PK,FK1 TD_ENTRY_ID
I PK SEQ_NUM PK TD_TYPE_CD
PK SEQ_NUM R
CRE_BATCH_CD FK1 TD_TYPE_CD
G FLD_NAME
TBL_NAME FK1 MESSAGE_CAT_NBR KEY_VALUE
A
FK1 MESSAGE_NBR
U 3 CI_TD_SRTKEY_TY FK2 BATCH_CD CI_TD_SRTKEY M
R PK,FK1
PK
TD_TYPE_CD
SEQ_NUM
PK,FK1
PK
TD_ENTRY_ID
SEQ_NUM
M
E DEFAULT_SW KEY_VALUE E
D ORDER_FLG
D
The tables on the left are populated via the Admin menu
4. Message specifies the message to show in the ToDo list
5. Batch Control contains the batch control of the job that created the
ToDo
305
SPL Batch II ToDo Data Model
CI_MSG CI_BATCH_CTRL
4 CI_TD_MSG_PARM
C PK
PK
MESSAGE_CAT_NBR
MESSAGE_NBR
PK BATCH_CD
PK,FK1 TD_ENTRY_ID P
PK SEQ_NUM
O FK1 TD_TYPE_CD
PROGRAM_NAME R
MSG_PARM_VAL
N O
CI_TD_DRLKEY_TY
F CI_TD_TYPE 1 CI_TD_ENTRY 2 CI_TD_DRLKEY
G
PK,FK1 TD_TYPE_CD PK,FK1 TD_ENTRY_ID
PK TD_ENTRY_ID
I PK SEQ_NUM PK TD_TYPE_CD
PK SEQ_NUM R
CRE_BATCH_CD FK1 TD_TYPE_CD
G FLD_NAME
TBL_NAME FK1 MESSAGE_CAT_NBR KEY_VALUE
A
FK1 MESSAGE_NBR
U CI_TD_SRTKEY_TY FK2 BATCH_CD
3 CI_TD_SRTKEY M
R PK,FK1
PK
TD_TYPE_CD
SEQ_NUM
PK,FK1
PK
TD_ENTRY_ID
SEQ_NUM
M
E DEFAULT_SW KEY_VALUE E
D ORDER_FLG
D
The tables on the right are populated programmatically
1. ToDo Entry has one row per ToDo entry and a foreign key to the
ToDo Type
2. Drill Key contains the key value (e.g. person Id) to use for the
navigational drill down when the user selects the ToDo to work on
306
SPL Batch II ToDo Data Model
CI_MSG CI_BATCH_CTRL
4 CI_TD_MSG_PARM
C PK
PK
MESSAGE_CAT_NBR
MESSAGE_NBR
PK BATCH_CD
PK,FK1 TD_ENTRY_ID P
PK SEQ_NUM
O FK1 TD_TYPE_CD
PROGRAM_NAME R
MSG_PARM_VAL
N O
CI_TD_DRLKEY_TY
F CI_TD_TYPE 1 CI_TD_ENTRY 2 CI_TD_DRLKEY
G
PK,FK1 TD_TYPE_CD PK,FK1 TD_ENTRY_ID
PK TD_ENTRY_ID
I PK SEQ_NUM PK TD_TYPE_CD
PK SEQ_NUM R
CRE_BATCH_CD FK1 TD_TYPE_CD
G FLD_NAME
TBL_NAME FK1 MESSAGE_CAT_NBR KEY_VALUE
A
FK1 MESSAGE_NBR
U CI_TD_SRTKEY_TY FK2 BATCH_CD
3 CI_TD_SRTKEY M
R PK,FK1
PK
TD_TYPE_CD
SEQ_NUM
PK,FK1
PK
TD_ENTRY_ID
SEQ_NUM
M
E DEFAULT_SW KEY_VALUE E
D ORDER_FLG
D
The tables on the right are populated programmatically
3. Sort Key contains the value(s) to sort on (e.g. person name)
4. Message Parameter contains the values for message substitution
307
Exercise 11 Batch 2
All Students
Modify the previous exercises class to create ToDo entries for
Persons without Accounts
The ToDo creation methods to populate the right-sided tables as described
on the previous slide have too much complexity for this course, so the
instructor will supply a template for the ToDo creation methods you can
simply copy and paste those into your class
The supplied methods are
public void initializeThreadWork
private boolean toDoAlreadyExists
private void createToDo
private void addDrillKeyValue
private void addSortKeyValue
private void addMessageParameter
308
Exercise 11 Batch 2
All Students (continued)
In your executeWorkUnit method
As in the previous exercise, determine the Person_Id and PersonName_Id values
Using the supplied method, determine if the ToDo already exists and, if so, write a
message to the system log indicating such and return with a Boolean of true
Optionally, write a message to the system log to show the person id and name
being added to the ToDo
Use the supplied method to create the ToDo entry
309
Exercise 11 Batch 2
All Students (continued)
Create new batch control XX-TDPNA
310
Exercise 11 Batch 2
All Students (continued)
Create new ToDo type XXTDPNA Main tab
311
Exercise 11 Batch 2
All Students (continued)
ToDo Type XXTDPNA Sort Keys tab
312
Exercise 11 Batch 2
Test
Use the Batch - Training launch configuration from Eclipse to run
your job
Verify in the online system that it created a ToDo entry for each
Person identified as not having an Account
It should show the message with person name substituted
It should be sorted in person name ascending sequence
You should be able to drill into a person from the ToDo list
With this exercise we do not create a JUnit test class, but it can be
done in one of two ways
1. Extending the BatchJobTestCase class and implementing abstract methods
2. Calling the submitBatchJob(SubmissionParameters) method in any
ContextTestCase - this allows testing a mix of one or more background
process and other business logic to be tested
In both cases, the database does not get updated
313
Exercise 11 Batch 2
Test (continued)
Note: When testing your batch class and an error occurs, run the
following delete statements before re-executing your batch class
these statements will delete all previously created ToDo entries to
prepare for the re-run
314
The End
Thank You
315