Sie sind auf Seite 1von 283

Java AppIication DeveIopment

OracIe UtiIities Framework


2
Day 1 Agenda
LogicaI ArchitecturaI Overview
OLTP
Batch
History
Version V1.x
Version V2.x
DeveIopment, Extension and Customization Overview
The Artifact Generator
Entities
Entity CIasses
Entity CRUD
Querying Entities
LogicaI ArchitecturaI Overview
4
LogicaI Web Architecture
Information is presented in HTML and JavaScript (no Java
appIets) through Internet ExpIorer 6.0
The browser communicates with the Web App Server via
HTTP
HTML
JavaScript/
XSLT
Session State
H
T
T
P
Web Browser
5
LogicaI Web Architecture
The Web App Server is divided into IogicaI tiers:
Presentation services
Business Iogic
Data access
HTML
JavaScript/
XSLT
Session State
Presentation
Servlets/XSLT
Caches
Data Access
Persistent
Entities
Hibernate
JDBC
Business
Services
Data Service
Objects
(Java/COBOL)
H
T
T
P
Web Browser Web AppIication Server
6
LogicaI Web Architecture
In the Presentation Layer .
Java servIets handIe the inbound HTTP requests from the browser
Various static data - e.g. controI tabIes, Ianguage-specific messages
and IabeIs - are cached
XSL/T technoIogy is used to create the HTML
The servIets invoke the data service objects in the business Iayer as
required
HTML
JavaScript/
XSLT
Session State
Presentation
Servlets/XSLT
Caches
Data Access
Persistent
Entities
Hibernate
JDBC
Business
Services
Data Service
Objects
(Java/COBOL)
H
T
T
P
Web Browser Web AppIication Server
7
LogicaI Web Architecture
In the Business Layer .
Data service objects are invoked from the presentation Iayer
These services uItimateIy perform the business functions
The service objects themseIves are Java, but the business Iogic
couId be impIemented in Java or COBOL, or a combination
The data access objects are used to communicate with the
database
HTML
JavaScript/
XSLT
Session State
Presentation
Servlets/XSLT
Caches
Data Access
Persistent
Entities
Hibernate
JDBC
Business
Services
Data Service
Objects
(Java/COBOL)
H
T
T
P
Web Browser Web AppIication Server
8
LogicaI Web Architecture
In the Data Access Layer .
The Hibernate Object ReIationaI ModeI (ORM) framework is used for
database access and persistence
The Java Database Connectivity API (JDBC) is used directIy (i.e.
Hibernate is bypassed) for SQL statements from COBOL
AII database caIIs are routed through the framework's data access Iayer
- appIication programs do not issue direct caIIs to database
HTML
JavaScript/
XSLT
Session State
Presentation
Servlets/XSLT
Caches
Data Access
Persistent
Entities
Hibernate
JDBC
Web Browser Web AppIication Server
Business
Services
Data Service
Objects
(Java/COBOL)
H
T
T
P
9
LogicaI Web Architecture
Database
Framework supports .
OracIe
DB2
Microsoft SQL Server.
HTML
JavaScript/
XSLT
Session State
Presentation
Servlets/XSLT
Caches
Data Access
Persistent
Entities
Hibernate
JDBC
Web Browser Web AppIication Server
Business
Services
Data Service
Objects
(Java/COBOL)
H
T
T
P
Oracle
DB2
MSSQL
Database
10
LogicaI Batch Architecture
Batch Processing
A scheduIer or the command-Iine is used to invoke the spIbatch script
(the scheduIer can be a 3
rd
party OUF's "cdxcronbatch" scheduIer)
spIbatch starts a batch instance of the framework
The framework controIs aII batch execution
Once initiaIized, spIbatch prompts for the batch code of the batch
process to execute
splbatch.sh / cmd
(command line)
Scheduler
Etc.
splbatch.sh / cmd
(command line)
Scheduler
Etc.
Submission
11
LogicaI Batch Architecture
Batch Processing
The StandaIone Executor invokes the Java/COBOL batch
process, based on the suppIied batch controI code
The business Iayer components perform the business functions
(same as onIine)
The data access Iayer is used to communicate with the database
(same as onIine)
splbatch.sh / cmd
(command line)
Scheduler
Etc.
splbatch.sh / cmd
(command line)
Scheduler
Etc.
Batch Control
Standalone
Executor
Batch Process
Data Access
Persistent
Entities
Hibernate
JDBC
Submission Batch Server
Business
Data Service
Objects
(Java/COBOL)
Oracle
DB2
MSSQL
Database
12
Embedded Batch Architecture (option)
Starting with FW 2.1.0 batch processing can optionaIIy
take pIace on the Web AppIication Server:
A scheduIing daemon poIIs for jobs submitted by the onIine
The IocaI business tier executes the work
Batch Control
Standalone
Executor
Batch Process
Data Access
Persistent
Entities
Hibernate
JDBC
Web AppIication Server
Business
Data Service
Objects
(Java/COBOL)
Oracle
DB2
MSSQL
Database
13
Servers
<BizTalk>
<Body>
<Accountnfo>
<Reques t docTynfo">
<Account>
<company>99ny>
<accountd>5ntd>
<area>001</area>
</Account>
</ Reques t>
</Accountnfo>
</Body>
</BizTalk>
XML: Web Services
Integration
ReaI time
interfaces:
CRM, MS Office,
Web Self Service, etc.
DBMS
UI
.etc.
Mass record
Integration
Outside Agents
Meter data
Billable Charges
ERP / GL
<BizTalk>
<Body>
<Accountnfo>
<Reques t docTynfo">
<Account>
<company>99ny>
<accountd>5ntd>
<area>001</area>
</Account>
</ Reques t>
</Accountnfo>
</Body>
</BizTalk>
<BizTalk>
<Body>
<Accountnfo>
<Reques t docTynfo">
<Account>
<company>99ny>
<accountd>5ntd>
<area>001</area>
</Account>
</ Reques t>
</Accountnfo>
</Body>
</BizTalk>
<BizTalk>
<Body>
<Accountnfo>
<Reques t docTynfo">
<Account>
<company>99ny>
<accountd>5ntd>
<area>001</area>
</Account>
</ Reques t>
</Accountnfo>
</Body>
</BizTalk>
Staging
<BizTalk>
<Body>
<Accountnfo>
<Reques t docTynfo">
<Account>
<company>99ny>
<accountd>5ntd>
<area>001</area>
</Account>
</ Reques t>
</Accountnfo>
</Body>
</BizTalk>
<BizTalk>
<Body>
<Accountnfo>
<Reques t docTynfo">
<Account>
<company>99ny>
<accountd>5ntd>
<area>001</area>
</Account>
</ Reques t>
</Accountnfo>
</Body>
</BizTalk>
<BizTalk>
<Body>
<Accountnfo>
<Reques t docTynfo">
<Account>
<company>99ny>
<accountd>5ntd>
<area>001</area>
</Account>
</ Reques t>
</Accountnfo>
</Body>
</BizTalk>
Mass XML
Integration
XML Staging
XA
MPL
Integration Architecture
History
Version 1.x
16
Page Server
(Servlet/JSP)
V1.x TechnicaI Architecture
Web Server to App Server
andles servIce
dIstrIbutIon
Web
ApplIcatIon
Server
8usIness
ApplIcatIon
Server
0atabase
Server
0ata Page
ConduIt
(EJ8)
X|L
Jolt
WebLogIc
Tuxedo
8usIness
Dbject
ConduIt
ContaIns
- Tuxedo commun.
- Flattener / expander
8usIness
Dbject
(CD8DL)
Tuxedo
17
Person
CI_PER
Name
CI_PER_NAME
D
CI_PER_ID
Phone
CI_PER_PHONE
Char
CI_PER_CHAR
The entities that hoId
person information
3 Types Of Programs InvoIved With The Maintenance
Of Objects
Let's use an exampIe of the programs used to maintain
the person object:
Person
Page
Person
Row
Name
List
D
List
Phone
List
Char.
List
Name
Row
D
Row
Phone
Row
Char.
Row
Page programs orchestrate
the caIIs to the various row
and Iist programs
List programs access and
updates the rows in a coIIection.
Note, we onIy update rows that
have been changed. You wiII
aIso find inter-row vaIidation
here
Row programs
perform vaIidation
and updates on a
specific row
Page programs perform inter-record
vaIidation after row vaIidation / update,
but prior to commit
18
Person
Page
Person
Row
Name
List
D
List
Phone
List
Char.
List
Name
Row
D
Row
Phone
Row
Char.
Row
Person
Wrapper
Issues the roIIback and commit
so that other programs can caII
the page program
Where's The Commit / RoIIback
Tuxedo doesn't caII the page program, it caIIs the page program's
wrapper
The commit / roIIback is issued by the page's wrapper (the program
that Tuxedo invokes)
Tuxed
o
Version 2.x
Transition to Java
20
Transition Strategies
Persistence
Java persistence Iayer based on Hibernate that interoperates with
existing COBOL Row program persistence.
Services
Java service impIementation as an aIternative to COBOL Page,
List, Search services
A service dispatcher that dispatches service requests
impIemented in either Java or COBOL
Business InteroperabiIity
Business Iogic impIemented in Java, COBOL or scripts can caII
each other, usuaIIy without knowing the impIementation
technoIogy of the caIIed code.
21
Business InteroperabiIity
Expand COBOL
Preprocesses COBOL code to make JNI caIIs to Java hosting it's
execution
AbstractCoboIProgram
A Java program that wraps a COBOL program so it can be caIIed
from Java. TypicaIIy, COBOL copybooks are processed and a
Java API is generated to make programming caIIs to COBOL easy.
JavaToCoboIGateway/CIPZCTJN
GeneraIized faciIity to caII arbitrary static Java methods from
COBOL by passing COBOL copybook structures
Database Session
One consistent session is shared among Java, COBOL and
scripting participants in a business transaction
22
Native Execution Hosting
Nal|ve 8us|ress
0ojecls
J2EE weo
App||cal|or 3e(ve(
Java 8us|ress
0ojecls
P(|ra(v Cr||d
J\V
Nor-TCP Corrur|cal|or
P(oloco|
Fa||ove( Cr||d
J\V|s)
DeveIopment, Extension and Customization
24
Resources
Wiki
http://sf-morpheus.spIwg.com/ccb
The "CookBook" is the best pIace to start for most things
WaIk-through: Iook at the wiki
Product documentation
//documentation/User Doc (MuIti Product)
JavaDocs
GeneraIIy, the code is weII commented and JavaDocs show up in EcIipse
quite easiIy.
Use cases
How are cIasses used by other cIasses
Junit tests
A fantastic resource for discovering how a deveIoper intended a cIass to be
used
A fantastic resource for discovering that the deveIoper misunderstood the
requirements or didn't test his or her code
25
The AppIication Stack
The running system is reaIIy a composite of stacked
appIications configured at runtime
ExampIe: base, ccb, mtm, cm
AppIications initiaIize the Iower appIication in the stack
and then overIay higher appIications
AppIications are deveIoped by independent teams:
May not change appIications Iower on the stack
May not depend on appIications higher on the stack
26
Perforce Locations
Each appIication has it's own root node in depot
ExampIe: FW, C1, O2
Within each version of the appIication (2.1.0, 2.2.0, etc)
there are three important foIders: moduIes, projects,
tooIs
ModuIes
Code that makes up the deIiverabIe appIication
"Iib" incIudes jar dependencies from third parties or Iower
appIications on the stack
"source" incIudes appIication source and tests
"dist" incIudes other resources/executabIes from third parties or
Iower appIications on the stack (I.e. COBOL object code)
27
Perforce Locations (cont)
Projects
Represents fiIes configuring the deveIopment process
EcIipse projects are configured here
Wiring for the Maven buiId
Configuration of the shared deveIopment servers
TooIs
Contains software needed to deveIop
EcIipse
Tomcat
Ant
Java
28
Introduction to EcIipse
WaIk-through
See project structure
TypicaI sync
Perforce sync
Artifact generator buiId
Refresh
Launch Tomcat
Look at Perforce integration
29
Package Structures
com.spIwg.base.api.*
Framework APIs that appIications may code against
com.spIwg.shared.*
CIasses that are shared between the runtime appIication and the
buiId-time code (I.e. the Artifact Generator)
IncIudes some very usefuI cIasses:
Logger
StringUtiIities
AppIicationException
com.spIwg.mtm.domain.*
Domain Iogic for the "mtm" appIication
TypicaIIy a new package for each Maintenance Object
The Artifact Generator
An Introduction
31
What is the Artifact Generator
We generate both Java source and XML documents via a
stand-aIong Java program caIIed the "Artifact Generator"
The Artifact generator:
Parsed Java source fiIes to extract
KnowIedge of pubIic methods and variabIes
Comments so that they can heIpfuIIy be added to generated business
interfaces
Annotations embedded in comments that define metadata coupIed to
the code
COBOL source to buiId up Java representations of the COBOL
programs and copybooks for COBOL-Java interoperabiIity
Database Metadata to understand the structure of TabIes, FieIds
and Constraints
32
Why do we generate artifacts?
To create cIasses that Humans can code to
Business Interfaces with proper "getters" and "setters"
HeIpfuI methods on abstract supercIasses specific to the cIass
that someone is coding
To capture detaiIs onIy avaiIabIe from the source code at
buiId time because the source code is not avaiIabIe at
runtime
ExampIe: the structure of COBOL copybooks
Entities
34
What are Entities?
Entity CIasses
CIasses wired into the Hibernate Object-ReIationaI Mapping
framework to provide persistence
Entity Objects
Instances of Entity CIasses representing rows on the database
Entity Layer
The Iayer IogicaIIy between the database and the service Iayer
Contains famiIies of cIasses that faciIitate the basic CRUD of rows
on the database
35
Entity Layer CIasses
WaIk-through: Take a Iook at "Currency" in FW
Hand-coded persistence cIasses
Entity "ImpI" (Currency_ImpI) defines basic persistence
Change HandIer (Currency_CHandIer) defines vaIidation and
cascading changes
Message Repository (MessageRepository) defines new messages
used by this package
Hand-coded maintenance (service Iayer) cIasses
List Maintenance (CurrencyListMaintenance) defines a service
caIIabIe via the onIine
Entity Code Description Query (CurrencyCodeDescriptionQuery)
defines a service that returns descriptions of the rows, ostensibIy
for caching
36
Generated Entity Layer CIasses
Business Interface (Currency)
Defines the interface that cIient objects shouId taIk to
ID (Currency_ID)
Defines a prime key cIass
Data Transfer Object (Currency_DTO)
Defines a transient data structure hoIding the properties of the entity
Entity "Gen" (Currency_Gen)
Defines the abstract supercIass of the "ImpI". MostIy this give
convenient accessors to program business methods on the "ImpI".
Language cIasses (Currency_Language and Currency_LanguageId)
Provides Ianguage support
POJO (Currency_POJO and others)
Provides support for the HQL query tooI. Not used by the running
system.
37
Generated Entity Configuration FiIes
Hibernate Mappings (*.hbm.xmI)
Loaded at runtime to wire up Hiberate
Info Data (*.info.xmI)
Provides runtime metadata about the entity for the framework
packageMetaInfo.xmI
Bootstrapping metadata used by the framework to discover and
wire up the package
38
Prerequisite Database Metadata
Some metadata data needs to be defined in framework
tabIes before the artifact generator is run
TabIe, FieId, TabIeFieId and Contraint defines the structure of the
tabIes that the entities must map to
Lookups need to be defined because cIasses are generated which
aIIow Java code to directIy reference Iookup vaIues
Maintenance Objects vaIues drive
VaIidations in the artifact generator that prevent incorrect parent-chiId
reIationships from being defined and other issues
Maintenance generation using the "MO Wizard" which we'II discuss
Iater.
Working with Entities
40
Inside Business Entities
In generaI, a Business Entity cIass exists for each tabIe in
the system
The exampIe here iIIustrates the Person and Person Name
tabIes and their reIated cIasses
+createDTO()
AbstractBusinessEntity
+getd()
+getAddress()
-id
-address1
Person_Gen
Person_ImpI
+getd()
+getEntityName()
-id
-entityName
PersonName_Gen
PersonName_ImpI
Person nterface
PersonName
nterface
C_PER
PK PER_ID
ADDRESS1
C_PER_NAME
PK,FK1 PER_ID
PK SEQ
ENTTY_NAME
41
Business Entity reIated cIasses are divided into 3 categories:
1. Framework
2. Generated
3. Hand-coded
Business Entity and ReIated CIasses
+createDTO()
AbstractBusinessEntity
+getd()
+getAddress()
-id
-address1
Person_Gen
+getnfo()
Person_ImpI
+getId()
+getAddress1()
+getInfo()
+getDTO()()
+setDTO()()
interface
Person
AbstractDataTransferObject
Person_DTO
StringId
Person_Id
AbstractEntityList
+add()
+remove()
PersonNames_ImpI
interface
SimpIeEntityList
interface
PersonNames
42
The goaI of the framework was to keep hand-coded Iogic
to a minimum
When creating a new Business Entity, onIy the "ImpI"
cIass is hand coded; others are framework or generated
by the Artifact Generator
Business Entity and ReIated CIasses
+createDTO()
AbstractBusinessEntity
+getd()
+getAddress()
-id
-address1
Person_Gen
+getnfo()
Person_ImpI
+getId()
+getAddress1()
+getInfo()
+getDTO()()
+setDTO()()
interface
Person
AbstractDataTransferObject
Person_DTO
StringId
Person_Id
AbstractEntityList
+add()
+remove()
PersonNames_ImpI
interface
SimpIeEntityList
interface
PersonNames
43
Let's Iook at how the cIasses beIow are used
Business Entities
Data Transfer Objects (DTOs)
String Ids
Entity Lists
Business Entity and ReIated CIasses
+createDTO()
AbstractBusinessEntity
+getd()
+getAddress()
-id
-address1
Person_Gen
+getnfo()
Person_ImpI
+getId()
+getAddress1()
+getInfo()
+getDTO()()
+setDTO()()
interface
Person
AbstractDataTransferObject
Person_DTO
StringId
Person_Id
AbstractEntityList
+add()
+remove()
PersonNames_ImpI
interface
SimpIeEntityList
interface
PersonNames
44
The Java programs typicaIIy do not caII the database
directIy; they use the Business Entities where possibIe
For exampIe, to fetch a Person from the database
Person_Id perId = new Person_Id("1185477091");
Person perEntity = perId.getEntity();
Working with Business Entities
AbstractBusinessEntity
+getd()
+getAddress()
-id
-address1
Person_Gen
+getnfo()
Person_ImpI
+getId()
+getAddress1()
+getInfo()
+getDTO()()
+setDTO()()
interface
Person
45
Query query = createQuery("from Person");
Person perEntity = null;
QueryIterator qIter = query.iterate();
while (qIter.hasNext()) {
perEntity = (Person)qIter.next();
...
}
To fetch muItipIe persons from the database
Working with Business Entities
AbstractBusinessEntity
+getd()
+getAddress()
-id
-address1
Person_Gen
+getnfo()
Person_ImpI
+getId()
+getAddress1()
+getInfo()
+getDTO()()
+setDTO()()
interface
Person
This is an earIy introduction to our
Java Persistence Framework (JPF) &
Hibernate. JPF & Hibernate are
discussed in detaiI Iater, but we wiII
see more references to them over the
foIIowing sIides
46
The framework creates instances of Business Entities
when fetching data - for exampIe
Person perEntity = perId.getEntity();
or
Person perEntity = (Person)qIter.next();
wiII create a new instance of Person
Therefore: An instance (object) of a Business Entity cIass
represents a row in a database tabIe
Working with Business Entities
PER_ID ADDRESS1 .
1550000001 Easy Street .
7804500002 Penny Lane .
.
id = 1550000001
address1 = Easy Street
Person : Person_mpl
id = 7804500002
address1 = Penny Lane
Person : Person_mpl
47
Working with Business Entities
Creating a new instance of a Business Entity creates a new
database row (when the transaction commits)
Likewise, when changing or deIeting an instance, the
database row is updated or deIeted (when the transaction
commits)
The database commit happens at the framework's
discretion - the appIication code has no direct controI over
it
PER_ID ADDRESS1 .
1550000001 Easy Street .
7804500002 Penny Lane .
.
id = 1550000001
address1 = Easy Street
Person : Person_mpl
id = 7804500002
address1 = Penny Lane
Person : Person_mpl
48
A Business Entity has "getters" (get methods) for retrievaI of its
properties
ExampIe
Person perEntity = (Person)query.firstRow();
String emailAddress = perEntity.getEmailAddress();
WiII retrieve a person's emaiI address
Most getters are specific to an object (e.g. emaiIAddress on Person),
but there are common ones
W getId() retrieves identifier (Account Id,
Person Id, Premise Id, etc.) depending on the object
W getDTJ() retrieves an instance of a Data Transfer
Object (DTO) for the Business Entity
Getting Entity Properties
AbstractBusinessEntity
+getd()
+getAddress()
-id
-address1
Person_Gen
+getnfo()
Person_ImpI
+getId()
+getAddress1()
+getInfo()
+getDTO()()
+setDTO()()
interface
Person
More about Ids and DTOs in a
minute.
49
A Business Entity does not have "setters" for its
properties
Properties can onIy be updated via a DTO
A Business Entity has a setDTO() method to register a
modified DTO and thus update the database
Setting Entity Properties
AbstractBusinessEntity
+getd()
+getAddress()
-id
-address1
Person_Gen
+getnfo()
Person_ImpI
+getId()
+getAddress1()
+getInfo()
+getDTO()()
+setDTO()()
interface
Person
More about Ids and DTOs in a minute.
50
$tring emailAddress = perDTO.getEmailAddress();
...
perDTO.setEmailAddress(emailAddress);
Person perEntity = (Person)query.firstRow();
Person_DTO perDTO = perEntity.getDTO();
AbstractDataTransferObject
Person_DTO
Data Transfers Objects (DTOs) are transient (temporary /
non-persistent) hoIders of Business Entity properties
They are acquired via the Business Entity getDTO()
method, for exampIe
Use the DTO "getters" and "setters" (get/set methods) to
retrieve or update properties, for exampIe:
Data Transfer Objects
51
Updating a DTO property (via "setter" method) does not
update the entity (database object) automaticaIIy
A Business Entity has the setDTO method to update a
modified DTO, for exampIe
This effectively updates the database, but the database update
& commit happen at the discretion of the framework
Data Transfer Objects
AbstractDataTransferObject
Person_DTO
Person perEntity = (Person)query.firstRow();
Person_DTO perDTO = perEntity.getDTO();
perDTO.setEmailAddress(testemail@splwg.com);
perEntity.setDTO(perDTO);
52
String Ids
SimpIe 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 = perDTJ.getId();
or
Person_Id perId = perEntity.getId();
Use the getIdVaIue() method to get the vaIue of the Id
String perIdString = perId.getIdValue();
StringId
Person_Id
53
String Ids
An Id object can aIso be used to retrieve a Business Entity,
for exampIe
Person_Id perId = new Person_Id("6785704944");
Person perEntity = perId.getEntity();
Person_DTJ perDTJ = perEntity.getDTJ();
...
StringId
Person_Id
54
Entity Lists
AbstractEntityList
+add()
+remove()
PersonNames_ImpI
interface
SimpIeEntityList
interface
PersonNames
Entity Iists reference coIIections of entities, such as person names,
phone numbers, characteristics, etc.
They are retrieved from a Business Entity, e.g.
Person_Id perId = new Person_Id("1185477091");
Person perEntity = perId.getEntity();
PersonNames perNames = perEntity.getNames();
EIements in an entity Iist can be:
SequentiaIIy retrieved
Removed
Added
55
Entity Lists
For exampIe, to retrieve aII 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();
...

AbstractEntityList
+add()
+remove()
PersonNames_ImpI
interface
SimpIeEntityList
interface
PersonNames
56
Creating an Entity
To create a new Business Entity, you create the DTO first
. or you create an empty DTO from an "Id" cIass .
. and then create the Business Entity from the DTO
Person_DTO perDTO = (Person_DTO) createDTO(Person.class);
Person_Id perId = new Person_Id("1185477091");
Person_DTO perDTO = perId.newDTO();
Note: createDTO() is inherited from the parent GenericBusinessObject cIass
for aII Business Entity or Business Component cIasses (e.g. Change HandIers)
perDTO.setId(new Person_Id(1185477091));
perDTO.set...
Person person = perDTO.newEntity();
57
DeIeting an Entity
To deIete a Business Entity, you use the delete method on the entity .
. or you can deIete the resuIts of a query using the delete method on
Query
person.delete();
Query query = createQuery("from Person");
long rowsDeleted = query.delete();
58
Hibernate for SPL Framework - HQL
HQL queries must aIso go through the SPL Framework
The framework Query cIass impIements a subset of pure
HQL
The framework HQL queries return Business Entities
It is mostIy the same as the native HQL Ianguage, except
for a few differences .
The SELECT cIause is not aIIowed in the framework's HQL text
The ORDER BY cIause is not aIIowed in the framework's HQL text
UNIONs are catered for in the framework's HQL (native HQL does
not aIIow it)
The framework caters for raw SQL statements
The foIIowing sIides describe the framework's
impIementation of HQL
Querying Entities
60
SeIecting Entities
The SELECT cIause is not used in a framework Query caII
SimiIar to Hibernate, the foIIowing query is vaIid
In this exampIe, the List wiII contain the aIgorithm objects
seIected for the aIgorithm type (i.e. Business Entities are
returned)
AlgorithmType algorithmType = ... ;
Query query = createQuery("from Algorithm algorithm +
where algorithm.algorithmType = :algorithmType");
query.bindEntity("algorithmType", algorithmType);
List algorithms = query.list();
61
Specifying ResuIts
To seIect individuaI coIumns, you specify the "resuIt"
properties programmaticaIIy, giving each a unique name
The addResult method on the Query object specifies a
resuIt property (coIumn) to seIect
Now the List wiII contain QueryResultRow objects
Each QueryResultRow wiII have two vaIues, keyed by
"aIgorithm" and "aIgorithmId"
Query query = createQuery("from Algorithm algorithm+
where algorithm.algorithmType = :algorithmType");
query.bindEntity("algorithmType", algorithmType);
query.addResult("algorithm", "algorithm");
query.addResult("algorithmId", "algorithm.id");
List queryResults = query.list();
62
Ordering ResuIts
The ORDER BY cIause in HQL is not aIIowed by the
framework
Instead, the order must be programmaticaIIy specified .
The List wiII contain QueryResultRow objects, ordered by
"aIgorithmId"
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.A$ENDING);
List queryResults = query.list();
63
Using Query Iterators
For a Iarge voIume query, instead of using a List, better
performance can be gained using the iterate method on
Query
This is more efficient because the iterator Ioads objects on
demand
It aIso performs better if the objects have aIready been
Ioaded and cached by the session
Query query = createQuery("from Person");
Person perEntity = null;
QueryIterator qIter = query.iterate();
while (qIter.hasNext()) {
perEntity = (Person)qIter.next();
...
}
64
Union Queries
Hibernate does not provide for unions (it does not fit in with the object-oriented
principIes of HQL)
However, unions can be usefuI so the framework aIIows you to programmaticaIIy
code a union
Unioned queries must have identicaI .
ResuIt coIumns
Order by cIauses
Max resuIts settings
The unionWith() method of the Query cIass performs the initiaI union
To add a third (or Iater) query, you add it directIy to the union
&nionQuery union = query.unionWith(query2);
union.addQueryTo&nion(query3);
65
PIease note that this is not a recommended or preferred means of accessing the
database
Raw SQL
It may be necessary to code SQL instead of HQL
PotentiaI reasons are .
To specify performance hints
A tabIe is not mapped to a Java entity
Instead of createQuery(), you use the JDBC-Iike
createPreparedStatement() method on the session object
The text is simiIar to the HQL Query text, but you use the
tabIe and coIumn names instead of the Java entity and
property names
This feature is onIy mentioned here for information - we do
not cover it in the exercises
66
Extending Business Entities
Entities can be extended by appIications "higher" on the
appIication stack. For exampIe, the "cm" appIication can
extend "ccb" entities.
The BusinessEntity annotation has a speciaI parameter
to define this: extendedInterfaceName
OnIy new business methods can be added. Existing ones
may not be overridden or removed.
WaIk-through: User_ImpI in CCB
67
COBOL-Backed Entities
There are compIex COBOL row programs in the CCB
appIication that maintain tabIe data
So not to dupIicate this Iogic between COBOL and Java,
these row programs are "wrapped" by BusinessEntity
cIasses.
These cIasses can be interacted with just Iike any other
entity: queried, changed, etc
The persistence mechanism has been changed though
so that rather than Hibernate persisting changes, the
COBOL programs are caIIed instead
WaIk-through: ServiceAgreement in CCB
End of Day 1
69
Day 2 Agenda
Change HandIers-Standard VaIidations
Change HandIers
Standard VaIidations
71
Change HandIers
The way to change an entity's response to changes in it's
state is by creating Change HandIers
VaIidations disaIIow inappropriate modification
Cascading changes aIIow one change to cause another
One or more Change HandIers may exist for a Business
Entity - the framework wiII caII aII of them
The Business Entity is specified in the annotations - it
teIIs the framework which entity to attach the Change
HandIer to at runtime
A Change HandIer extends the AbstractChangeHandIer
framework cIass
A Change HandIer cIass name MUST end in "_CHandIer"
for the artifact generator to recognize it as such
72
ExampIe Change HandIer

@hangeHandler (entityName = characteristicType)

public class mharacteristicType_Handler


extends AbstracthangeHandler {
...
}
In this exampIe .
The annotation specifies a Change HandIer for Business Entity
"Characteristic Type"
It extends AbstractChangeHandIer
The cIass name ends in "_CHandIer"
73
Change HandIers
Change HandIers add event-driven Iogic to entities
(simiIar to COBOL row user exits)
They can perform 2 things:
1. VaIidate data changes
2. Cause cascading changes
We'II take a Iook at vaIidation first
74
Change HandIers - VaIidation RuIes
The framework uses VaIidation RuIes to determine how to
vaIidate a Business Entity at runtime
The VaIidation RuIes for a Business Entity are decIared in
a Change HandIer
The declarative styIe means the programmer specifies
WHAT to vaIidate, not HOW or WHEN
A number of standard ruIes exist that require minimaI
programming, but custom ruIes can be coded if needed
Custom ruIes require programming - these contain the
step-by-step Iogic of HOW to vaIidate
VaIidation ruIes are "side-effect free", which means .
They cannot change the persistent state of the system (can't
update)
It insures aII vaIidations are performed on a compIete set of
changes
75
Change HandIers - VaIidation RuIes
The foIIowing standard ruIes exist
AIIowAndRequireRuIe - both aIIows and requires a property to be
popuIated
AIIowRuIe - aIIows a vaIue to be popuIated
CustomRuIe - creates a ruIe out of a Custom VaIidation cIass (to
impIement Iogic not handIed by any of the above)
NotAIIowRuIe - one or more properties are not aIIowed
PIaceHoIderRuIe - this is a "pIace hoIder" when a Change
HandIer is deveIoped - they are repIaced with the actuaI ruIes
during deveIopment
ProtectRuIe - prevents a property from being changed
RequireRuIe - requires a property to be popuIated
RestrictRuIe - restricts a property to a set of vaIues
Refer to the SDK documentation for more detaiIs on these
ruIes
76
Change HandIers - VaIidation RuIes
The framework invokes the getValidationRules method on
a Change HandIer for aII the vaIidation ruIes for a
Business Entity
The getValidationRules method must return an array of
vaIidation ruIe objects
To use a standard ruIe, simpIy use the static "factory"
method on the ruIe itseIf - for exampIe
RequireRule.alwaysRequire() returns an instance of the
RequireRuIe cIass that insures an entity property has a vaIue
RestrictRule.validatedMustEqualReference() returns an instance
of the RestrictRuIe cIass that checks if a property is equaI to a
specific vaIue/reference
77
Change HandIers - VaIidation RuIes
A VaIidation RuIe requires a Property on the Business
Entity (i.e. the "fieId") to vaIidate
A property is a reference to an entity fieId
Properties exist as constants on the business interfaces -
for exampIe
Person.properties.emailAddress refers to emaiI address fieId on
Person Business Entity
Account.properties.setUpDate is the setup date fieId on the
Account entity
Properties are passed to the VaIidation RuIes as
parameters to teII a ruIe which property to vaIidate
78
Change HandIers - VaIidation RuIes
Here we see .
Static method emailRequiredRule to instantiate a RequiredRuIe object
using factory method alwaysRequire
Person.properties.email to teII the ruIe to vaIidate the EmaiI Address
property (i.e. "fieId") on Person
PubIic method getValidationRules to provide a Iist of the ruIes to the
framework (onIy one in this case)
public static ValidationRule emailRequiredRule() {
return RequireRule.alwaysRequire("Person:Email is required",
"The person's email address must be specified",
Person.properties.emailAddress);
}
public ValidationRule[] getValidationRules() {
return new ValidationRule[] {emailRequiredRule()};
}
ExampIe - make EmaiI Address fieId on Person required
79
Exercise 1 - Change HandIer VaIidation 1
AII Students
Create a Person change handIer in the java foIder of your project .
PIace it in package .om.splwg..m.domain..:stomerinfo.person
Name it CmPerson_CHandler
Add vaIidation ruIe address1Req:iredR:le to make address line 1 required
OptionaI
Note: this exercise is very simiIar to the above, but wiII Iead to a more chaIIenging
exercise 3
Create a Premise change handIer .
PIace it in package .om.splwg..m.domain..:stomerinfo.premise
Name it CmPremise_CHandler
Add a vaIidation ruIe to make city required
Test
Use the onIine system to test your change handIer
80
When do RuIes Fire?
Before we deIve into the topic of Testing, it heIps to
understand how vaIidation is triggered by the framework
To reiterate, vaIidation ruIes are "decIarative"; decIared in
a change handIer, but invoked at the discretion of the
framework
By defauIt, vaIidation ruIes "fire" when a Business Entity
is updated deIeted, created, etc.
For exampIe, using setDTO to update an entity wiII trigger
the vaIidation for it, as seen here .
This is caIIed "eager" vaIidation because it fires
immediateIy
Person_DTO perDTO = perEntity.getDTO();
perDTO.setEmailAddress(somebody@someplace.com);
perEntity.setDTO(perDTO);
81
When do RuIes Fire?
The triggering of vaIidation can be controIIed
programmaticaIIy if needed
It may be necessary where muItipIe entities require
vaIidation as a "coherent" set of changes
To iIIustrate this, consider the exampIe of vaIidating a new
Person and Person Name, but onIy once the entities have
been created - i.e. to defer vaIidation untiI both entities
are created
To defer vaIidation untiI Iater, use framework method
startChanges() before the update and saveChanges() after
the update
Let's take a Iook at the code for this exampIe .
NOTE: saveChanges() does not issue commit to database!
82
ExampIe: Defer VaIidation
1. Invokes startChanges to teII the framework to suspend vaIidation
2. Creates a new Person Business Entity
3. Creates a PersonName Business Entity for the new Person
4. Adds PersonName to Person
5. Invokes saveChanges to aIIow for vaIidation on the "coherent" set of
changes
starthanges();
Person_DTO perDTO = (Person_DTO)this.createDTO(Person.class);
Person_Id perId = new Person_Id(1234567890);
perDTO.setId(perId);
Person person = perDTO.newEntity();
PersonName_DTO perNameDTO =
(PersonName_DTO) createDTO(PersonName.class);
PersonName_Id perNameId = new PersonName_Id(person,
BigInteger.ONE);
perNameDTO.setId(perNameId);
perNameDTO.setEntityName(Blog,Joe");
perNameDTO.setNameType(NameTypeLookup.constants.PRIMARY);
PersonName perName = perNameDTO.newEntity();
person.getNames().add(perName);
savehanges();
1
2
3
4
5
JUnit Testing
84
JUnit Testing
To ensure quaIity code, an automated unit testing
procedure is required
The reasons for automated testing are .
One smaII change can unexpectedIy break other parts of the
system - automated tests provide earIy notification of these bugs
Studies show that to fix bugs costs more the Ionger they are
undiscovered - automated tests prevent this
Automated tests are usefuI (aIbeit technicaI) forms of functionaI
documentation - they describe to the programmers the expected
inputs/outputs
We use JUnit for automated testing
The EcIipse IDE is integrated with JUnit, making it easy to
create and run tests
JUnit test are part of our continuous buiId process.
85
JUnit Testing
The framework contains many abstract "tester" cIasses,
one for each type of test - for exampIe
AbstractEntityTestCase tests a Business Entity and its reIated
Change HandIers. It aIso ensures aII the VaIidation RuIes in the
Change HandIer have fired
AlgorithmImplementationTestCase tests an aIgorithm function
When coding your own test cIass, you must extend the
appropriate abstract "tester" cIass
The root of many tester cIass is ContextTestCase which
can be used to test most things that require generaI
framework services
86
JUnit Tests are Safe
. or shouId be.
The transaction Iogic in the tester cIasses is "hotwired".
Whenever you use the session provided within the tester
cIass:
AII your changes get roIIed back at the end of the test, pass or faiI
If you do data setup, it gets roIIed back
Other resource cIeanup (Iike temporary fiIes) shouId be
cIeaned up by overriding "tearDown()" method
Let's see how a test is created .
87
Creating a JUnit Test CIass
First step is to create a JUnit test cIass
This cIass is to test CmPerson_CHandler vaIidation ruIes
1. The cIass name ends in "_Test"
2. It extends AbstractEntityTestCase - to test a Business
Entity/Change HandIer
3. The getChangeHandlerClass method returns the cIass definition
of the Change HandIer being tested - the framework invokes this
method to get the name of the cIass to test
public class mPerson_Handler_Test extends AbstractEntityTestase {
protected lass gethangeHandlerlass() {
return mPerson_Handler.class;
}
}
88
Creating a JUnit Test Cases
Now we add a method for each test case .
Remember:
1. The method name must start with "test" - the framework wiII
execute aII cIasses that start with "test"
2. ALL the ruIes must be vioIated in the test - if a vaIidation ruIe
exists in the change handIer but is not vioIated in the test cIass,
the framework wiII faiI the test
3. The objective is to have aII test cases compIete successfuIIy (no
faiIures)
public void testEmailRequiredRule() {
}
Note Our change handIer onIy has one ruIe - "EmaiI Required" - so we
onIy have one test case method
89
FIeshing out a JUnit Test Case
Let's add some code to test our "emaiI required" ruIe .
What this code does is .
1. Fetches a person from the database and instantiates a Person
object
2. Acquires a Data Transfer Object (DTO) from Person
3. Updates the emaiI address on the DTO to a non-space vaIue
4. Modifies the DTO on Person, which triggers vaIidation
This tests for a positive outcome (which is necessary), but we
MUST aIso vioIate the condition to properIy test the vaIidation
ruIe .
public void testEmailRequiredRule() {
Person_Id perId = new Person_Id("5775933103");
Person person = perId.getEntity();
Person_DTO goodDTO = person.getDTO();
goodDTO.setEmailAddress("somebody@someplace.com");
person.setDTO(goodDTO);
}
1
2
3
4
90
FIeshing out a JUnit Test Case (cont)
So Iet's add some more code .
What this code does is .
1. Instantiates a "bad" DTO and cIears the emaiI address to vioIate the ruIe
2. Updates the Person's DTO to trigger vaIidation
3. Invokes JUnit fail method if setDTO does NOT cause expected ruIe
vioIation
4. Exception catch (what we expect), verifies that our ruIe - not some other
one - caused the exception
public void testEmailRequiredRule() {
...
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(mPerson_Handler.emailRequiredRule(),
exception);
}
}
1
2
3
4
91
The CompIete Test Case
Here's the compIete test method .
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
public void testEmailRequiredRule() {
Person_Id perId = new Person_Id("1648461517");
Person person = perId.getEntity();
Person_DTO goodDTO = person.getDTO();
goodDTO.setPersonOrBusiness(
PersonOrBusinessLookup.constants.PER$ON);
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(mPerson_Handler.emailRequiredRule(),
exception);
}
}
92
Exercise 2 - JUnit Test 1
AII Students
Create a JUnit test cIass for your Person vaIidation ruIe from exercise 1 in the
test foIder of your project .
PIace it in package .om.splwg..m.domain..:stomerinfo.person
Name your cIass CmPerson_CHandler_Test
Add a method to test your vaIidation ruIe
OptionaI
Create a JUnit test cIass for your Premise vaIidation ruIe from exercise 1
Test
From EcIipse, right-cIick on your test cIass and seIect Run As -> JUnit Test
The Continuous BuiId
94
The Continuous BuiId
Servers have been dedicated to continuousIy buiId and
test our appIications
Every 10 minutes or so, the buiId server Iooks for committed
changes in the appropriate Perforce Iocation. If none are found,
the buiId waits another 10 minutes and poIIs again.
When changes are found it does the foIIowing:
DownIoads aII changes
Removes aII artifacts, cIass fiIes and other remnants from the Iast
buiId
Generates aII artifacts
CompiIes aII code
Runs aII tests
If the buiId was unsuccessfuI it sends emaiIs to everyone who
committed changes since the Iast successfuI buiId.
95
When you "break the buiId"
If a deveIoper thinks the probIem is his/her fauIt, it is
customary to:
Send a note to other deveIopers on the Iist so they don't waste
time on the probIem
Fix the probIem, test it IocaIIy, commit changes to Perforce and
hope the buiId is appeased.
If no deveIoper confesses to the probIem, some
coIIaboration may be required. It may aIso require some
discussion with the "buiId master".
96
How not to break the buiId
Make sure everything compiIes
Make sure your changeIists are compIete
Run as many tests as you can. Run aII appearing reIated
to the changes made.
When you need to commit code you know is broken or
untested, disabIe the test as foIIows:
protected void test$endingEmails() {
disableTest(
"This test needs to be reworked so it doesn't hit the real oracle
email server and spam real people. This should be more like the other email
tests that hit an embedded server.",
"Brian onlon", new Date(2008, 04, 29));
ConditionaI VaIidation
98
ConditionaI VaIidation
In the Iast exercise we used the alwaysRequire method to
UNCONDITIONALLY require a vaIue
RuIes wouId not be very usefuI if onIy unconditionaI
vaIidation was aIIowed
VaIidation is usuaIIy based on some condition, for
exampIe
1. Prevent a "dependent" property from being changed if the
"primary" property matches a certain vaIue - e.g. FT freeze
date/time cannot be changed when the status is frozen
(ProtectRuIe)
2. The Iife support description on Person is required if the Iife
support fIag is set (RequiredRuIe)
RuIes have various constructs (and factory methods) to
handIe this, for exampIe
RequireRule.ifReferenceEqualsValue() requires a property if
another property equaIs a certain vaIue
99
ConditionaI VaIidation (cont)
ExampIe - emaiI address required if Iife support fIag is set
public static ValidationRule emailRequiredIfLife$upportIsYesRule() {
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.life$upport$ensitiveLoad,
Life$upport$ensitiveLoadLookup.constants
.LIFE_$&PPORT_$EN$ITIVE_LOAD,
com.splwg.base.domain.$tandardMessages.fieldMissing());
}
1
2
Here we introduce a few new things .
1. Using the ifReferenceEqualsValue factory method on RequireRuIe
2. The property that is required ("primary" property) - emailAddress
3. The property to compare for a vaIue ("dependent" property) -
lifeSupportSensitiveLoad
3
100
ConditionaI VaIidation (cont)
ExampIe - emaiI address required if Iife support fIag is set
public static ValidationRule emailRequiredIfLife$upportIsYesRule() {
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.life$upport$ensitiveLoad,
Life$upport$ensitiveLoadLookup.constants
.LIFE_$&PPORT_$EN$ITIVE_LOAD,
com.splwg.base.domain.$tandardMessages.fieldMissing());
}
Here we introduce a few new things .
4. The vaIue to compare the dependent property (no. 3) to -
LIFE_SUPPORT_SENSITIVE_LOAD is the Iookup vaIue for constant "Y"
(aII vaIid Iookup vaIues are generated onto "Iookup" cIasses)
5. The message to dispIay when the condition is true -
com.splwg.base.domain.StandardMessages.fieldMissing
Note: Here we use a standard message - we wiII create a custom
message Iater
4
5
3
101
Exercise 3 - ConditionaI VaIidation
AII Students
Modify your Person change handIer from exercise 1 .
Change the vaIidation ruIe to make address line 1 required onIy if the
person type is "Business"
Rename the vaIidation ruIe to indicate that it's conditionaI - e.g.
address1Req:iredIfB:sinessR:le
OptionaI
Modify your Premise change handIer from exercise 1 .
Change the vaIidation ruIe to make city required onIy if the county is not
equaI to constant vaIue "San Francisco"
Rename the vaIidation ruIe to indicate that it's conditionaI - e.g.
.ityReq:iredIfCo:ntyNotSFR:le
Test
Update your JUnit test cIass from exercise 2 to test the conditionaI
vaIidation
Base Messages
103
Message Categories
ALL appIication messages are stored in the framework's
message repository (the message text is not embedded in
the source code)
Messages are grouped into
categories
Use menu Admin -> M -> Message
to view/update the message
categories
The Iist here shows the standard
message categories
104
Within each category, the message text is numbered
This exampIe shows messages for "Standard" category
11001
Note message number 101 (" %1 fieId missing"); we used
it in the previous exercise
"%1" is a substitution variabIe to be suppIied when the
Java cIass dispIays the message (fieId name in this case)
A message may contain up to 9 substitution variabIes
Message Categories - Message Text
105
Message text may contain substitution variabIes
VariabIes are denoted by % foIIowed by a number from 1
to 9 - e.g. %1, %2, etc.
For exampIe, the message text
%1 field missing
wiII be dispIayed as
Bill Cycle field missing
%1
The appIication code must pass the vaIues for the
substitution variabIes when the message is dispIayed
Message Categories - Substitution VariabIes
addError($tandardMessages.FieldMissing(fieldName))
106
Base message text may not be modified (it is prevented by
the system) - changes wouId be overwritten at the next
upgrade anyway
However, you can ADD customized message text for a
base message on the Details tab
Base Messages - Modifying .
107
The Customer Specific Message Text must use the same
substitution variabIes as the base one
Base Messages - Modifying .
The framework wiII ALWAYS dispIay the customer
specific message if present - it is not possibIe to
conditionaIIy dispIay the base Message Text if
custom text for it exists
108
Base Messages - Java Definitions
Each category has its own cIass to define message variabIes and
methods
For exampIe, the StandardMessages cIass contains .
1. The category number definition for the standard messages
2. AII the standard message numbers
1
2
109
Base Messages - Runtime Definition
A message cIass aIso contains methods .
The appIication code caIIs these methods to dispIay messages at runtime -
for exampIe
addError($tandardMessages.fieldMissing("EMAILID"));
110
Base Messages - Runtime Definition
Note: in this case, the Ianguage-dependent description of EMAILID wouId be
dispIayed in the message - in EngIish, "EmaiI Address fieId missing"
As can be seen here, runtime message methods return objects of type
ServerMessage
111
Base Messages - DecIarative Definition
The previous sIide shows a RUNTIME message definition
Remember, vaIidation ruIes are decIarative
We therefore aIso need a decIarative version of the
message to use in the vaIidation ruIes
This methods returns a ServerMessageTempIate object to
use in the vaIidation ruIe decIaration
112
Base Messages - DecIarative Definition
In the Iast exercise we used the decIarative version of
StandardMessages.fieldMissing
fieldMissing has a runtime AND decIarative message
method, but not aII messages require both versions
Those used in vaIidation ruIes require decIarative ones; those
dispIayed from other "runtime" code (e.g. aIgorithms) require
runtime versions
We'II see in a moment how to use a runtime message .
public static ValidationRule emailRequiredIfLife$upportIsYesRule() {
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.life$upport$ensitiveLoad,
Life$upport$ensitiveLoadLookup.constants
.LIFE_$&PPORT_$EN$ITIVE_LOAD,
com.splwg.base.domain.$tandardMessages.fieldMissing());
}
Custom Messages
114
Custom Messages - Creating .
Over the foIIowing sIides, we'II Iook at creating and using
a custom message in Java
The custom message text we wiII work with is
"%1 required if %2 is activated"
The vaIidation that references this messages wiII therefore
be a conditional vaIidation
Remember this text - you couId even write it down to refer
to as we step through the sIides
First, Iet's Iook at creating the message onIine .
115
This is aII that is required
in the onIine to create a
new message
Custom Messages - Creating .
ONLY category Implementer's
messages may contain new custom
messages
To create a new message, you seIect
category 90000 and insert a new message
as shown beIow
% variabIes here must be suppIied in the
cIasses that dispIay the message
116
Custom Messages - Java Definition
On the Java side, these are the basic initiaI setup ruIes for
creating custom messages .
1. Create a CustomMessages cIass (suppIied with this course) to
contain aII your custom message definitions
2. CustomMessages must extend AbstractMessageRepository
3. In CustomMessages specify 90000 as the message category
4. In CustomMessages define aII your custom message numbers
5. PIace CustomMessages in the com.splwg.cm.domain package
6. In each individuaI sub-package under package cm you create a
MessageRepository cIass for the message methods specific to
that sub-package - Note: common message methods are pIaced
in the CustomMessages cIass
7. Each MessageRepository extends CustomMessages and contains
the runtime and decIarative methods for that sub-package
Let's take a cIoser Iook .
117
Custom Messages - Java Definition
These are the important cIass characteristics .
1. It is in package com.splwg.cm.domain
2. It imports our custom MessageRepository (to be created next)
3. CIass CustomMessages extends AbstractMessageRepository
4. It defines MESSAGE_CATEGORY 90000
5. It defines EVERY custom message (for now, we onIy have one)
package com.splwg.cm.domain;
import com.splwg.base.domain.common.message.AbstractMessageRepository;
import com.splwg.cm.domain.templates.MessageRepository;
public class ustomMessages extends AbstractMessageRepository {
public static final int ME$$AGE_ATEGORY = 90000;
public static final int REQ_IF_ONDITION = 10006;
private static MessageRepository instance;
public ustomMessages() {
super(ME$$AGE_ATEGORY);
}
static MessageRepository getInstance() {
if (instance == null) instance = new MessageRepository();
return instance;
}
}
1
2
3
4
5
118
Custom Messages - Java Definition
These are the important cIass characteristics .
6. It defines a MessageRepository instance variabIe (see point 8)
7. It invokes the supercIass to estabIish the message category at runtime
8. The getInstance method is a private method that provides the
MessageRepository instance to the to the message methods in the cIass
6
7
8
package com.splwg.cm.domain;
import com.splwg.base.domain.common.message.AbstractMessageRepository;
import com.splwg.cm.domain.templates.MessageRepository;
public class ustomMessages extends AbstractMessageRepository {
public static final int ME$$AGE_ATEGORY = 90000;
public static final int REQ_IF_ONDITION = 10006;
private static MessageRepository instance;
public ustomMessages() {
super(ME$$AGE_ATEGORY);
}
private static MessageRepository getInstance() {
if (instance == null) instance = new MessageRepository();
return instance;
}
}
119
Custom Messages - MessageRepository
Next we create the MessageRepository cIass in the sub-
package under package cm
It must extend the CustomMessages cIass
It onIy contains the methods for the messages reIevant to
the sub-package
AII static definitions for the message numbers shouId be in
CustomMessages
Let's Iook at the exampIe .
120
Custom Messages - MessageRepository
These are the important cIass characteristics .
1. It is in the sub-package to which it appIies - customerinfo.person in
this exampIe
2. It extends the parent CustomMessages cIass
3. It defines a MessageRepository instance variabIe
4. It has a getInstance method to provide the MessageRepository
instance - i.e. an instance of itseIf - to the message methods that
foIIow
package com.splwg.cm.domain.customerinfo.person;
import com.splwg.cm.domain.ustomMessages;
public class MessageRepository extends ustomMessages {
private static MessageRepository instance;
private static MessageRepository getInstance() {
if (instance == null) instance = new MessageRepository();
return instance;
}
}
1
2
3
4
MessageRepository cIass
121
Custom Messages - Runtime Method
The important method characteristics are .
1. a) The method is static
b) It returns a ServerMessage object type for a runtime message
c) It has a descriptive method name based on the message it handIes
d) The parameters correspond with the % variabIes in the message
public static $erverMessage requiredIfondition($tring fieldName1,
$tring fieldName2) {
MessageParameters parms = new MessageParameters();
parms.addField(fieldName1);
parms.addField(fieldName2);
return getInstance().getMessage(REQ_IF_ONDITION, parms);
}
Let's add a runtime method for our message in the MessageRepository
cIass
1
122
Custom Messages - Runtime Method
The important method characteristics are .
2. It defines a MessageParameters object to carry the substitution
vaIues for the message
3. It adds the substitution vaIues (the parameters) to the
MessageParameters object
4. It returns a ServerMessage object as instantiated by the getMessage
method, based on the suppIied message number and parameters -
the message number is defined in cIass CustomMessages
Let's add a runtime method for our message in the MessageRepository
cIass
2
4
3
public static $erverMessage requiredIfondition($tring fieldName1,
$tring fieldName2) {
MessageParameters parms = new MessageParameters();
parms.addField(fieldName1);
parms.addField(fieldName2);
return getInstance().getMessage(REQ_IF_ONDITION, parms);
}
123
Custom Messages - Using at Runtime
As seen on the previous sIide, the requiredIfCondition method uses
the addField method to set the parameters .
The MessageParameters.addField method uses the Ianguage-
dependent descriptions of the fieIds to repIace the % markers in the
message
Person_Id perId = new Person_Id("1234567890");
Person person = perId.getEntity();
Person_DTO perDTO = person.getDTO();
if ((perDTO.getLife$upport$ensitiveLoad().equals(
Life$upport$ensitiveLoadLookup.constants.
LIFE_$&PPORT_$EN$ITIVE_LOAD))
& perDTO.getEmailAddress().equals("")) {
addError(MessageRepository.requiredIfondition("EMAILID",
"L$_$L_FLG"));
}
Here we see how to set a message at runtime
parms.addField(fieldName1);
parms.addField(fieldName2);
124
Custom Messages - DecIarative Method
The important method characteristics are .
1. a) The method is static
b) It returns a ServerMessageTemplate object type for a
decIarative message
c) It has a descriptive method name based on the message it
handIes
d) It has a reference to the parameters if the message contains %
substitution variabIes
public static $erverMessageTemplate requiredIfondition(
LookupProperty prop) {
$erverMessageParameter[] messageParms = {
$erverMessageParameter.OFFENDING_PROPERTY_NAME,
$erverMessageParameter.createDisplayingName(prop)
};
return getInstance().getDeclarativeMessage(REQ_IF_ONDITION,
messageParms);
}
Let's aIso add a decIarative method for our vaIidation ruIe
1
125
Custom Messages - DecIarative Method
The important method characteristics are .
2. a) It has a message parameter array for the substitutions in the text
message
b) OFFENDING_PROPERTY_NAME is a static reference to the fieId
being vaIidated in the vaIidation ruIe - we substitute this name into
the message's 1
st
parameter
c) createDisplayingName gets the name of the LookupProperty
vaIue which we substitute into the message's 2
nd
parameter
Let's aIso add a decIarative method for our vaIidation ruIe
public static $erverMessageTemplate requiredIfondition(
LookupProperty prop) {
$erverMessageParameter[] messageParms = {
$erverMessageParameter.OFFENDING_PROPERTY_NAME,
$erverMessageParameter.createDisplayingName(prop)
};
return getInstance().getDeclarativeMessage(REQ_IF_ONDITION,
messageParms);
}
2
126
Custom Messages - DecIarative Method
The important method characteristics are .
3. It returns a decIarative message object based on the message
number and substitution parameters
Let's aIso add a decIarative method for our vaIidation ruIe
3
public static $erverMessageTemplate requiredIfondition(
LookupProperty prop) {
$erverMessageParameter[] messageParms = {
$erverMessageParameter.OFFENDING_PROPERTY_NAME,
$erverMessageParameter.createDisplayingName(prop)
};
return getInstance().getDeclarativeMessage(REQ_IF_ONDITION,
messageParms);
}
127
Custom Messages - Using DecIarative
Using the custom decIarative message in a vaIidation ruIe
public static ValidationRule emailRequiredIfLife$upportIsYesRule() {
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.life$upport$ensitiveLoad,
Life$upport$ensitiveLoadLookup.constants
.LIFE_$&PPORT_$EN$ITIVE_LOAD,
MessageRepository.requiredIfondition(
Person.properties.life$upport$ensitiveLoad));
}
. Person.properties.emailAddress is automaticaIIy set as the
OFFENDING_PROPERTY_NAME, so it does not need to be passed to
the decIarative method as a parameter - as seen on the previous sIide,
we use this name to substitute the 1
st
message parameter
2. We now reference our custom requiredIfCondition method in the
vaIidation ruIe
3. The parameter we pass in is the property of the fieId to substitute the
message's 2
nd
parameter
1
2
3
128
Exercise 4 - Custom DecIarative Message
AII Students
Use the onIine system to create a descriptive message for the Person
vaIidation ruIe in exercise 3
Each student shouId use a unique message number when working on a
shared database - the instructor can assign message numbers, starting at
message number 10001
Use your initiaIs in the message to distinguish it
Create the message with 2 parameters - the offending fieId name and the
fieId name used in the comparison
For exampIe: "%1 is required if %2 is BUSINESS (XX)" - where XX are your
initiaIs
Update the CustomMessages cIass and add a constant for your new
message number - e.g. REQUIRED_IF_ BUSINESS
Copy the suppIied MessageRepository tempIate to your person sub-
package and add a method for use in the vaIidation ruIe - e.g.
requiredIfBusiness(.)
129
Exercise 4 - Custom DecIarative Message
AII Students (continued)
Update your vaIidation ruIe from exercise 3 to reference the new
message
OptionaI
Perform the above steps to create a descriptive message for your
Premise vaIidation ruIe .
Start at message number 20001
For added compIexity, create a 3
rd
message parameter in which you
specify the string vaIue (constant) that the county is compared to
For exampIe: "%1 required if %2 not %3 (XX)" - where XX are your initiaIs
(see attached note)
Test
Use the onIine system to vaIidate that the new message is dispIayed
Condition Objects
131
Change HandIers - Conditions
RuIes can take as input one or more Conditions
The Condition interface currentIy has the foIIowing
impIementations (i.e. these are the supported conditions)
BetweenVaIues
EquaIs
Not
And
Or
GreaterThan / GreaterThanOrEquaIs
LessThan / LessThanOrEquaIs
Contains
(Descriptions of these conditions are documented)
You use conditions to conditionaIIy perform vaIidation
132
Conditions can be instantiated from factory methods on
certain properties
The isTrue() and isGreaterThan() methods instantiate a Condition
object
1. PersonName is being checked for a "primary" attribute
2. PersonName sequence is being checked for > 0
Conditions can aIso be instantiated using a constructor
This checks if the PersonOrBusiness property is set to "Person"
A Condition object such as this can be used in a
VaIidation RuIe to cause conditionaI vaIidation
ondition isPrimaryName = PersonName.properties.isPrimaryName.isTrue();
ondition greaterThan =
PersonName.properties.sequence.isGreaterThan(BigInteger.ZERO);
1
2
ondition isPerson =
new Equals(Person.properties.personOrBusiness,
PersonOrBusinessLookup.constants.PER$ON);
Change HandIers - Conditions
133
ExampIe - using a Condition to make emaiI address required
if Iife support fIag is set
public static ValidationRule emailRequiredIfLife$upportIsYesRule() {
ondition hasLife$upport =
Person.properties.life$upport$ensitiveLoad.
isEqualTo(Life$upport$ensitiveLoadLookup.constants.
LIFE_$&PPORT_$EN$ITIVE_LOAD);
return RequireRule.ifonditionTrue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
Person.properties.emailAddress,
hasLife$upport,
com.splwg.base.domain.$tandardMessages.fieldMissing());
}
1. This is the Condition to check if Iife support is on
2. We use the ifConditionTrue method of the RequireRule cIass
3. The ifConditionTrue method requires the Condition as a parameter,
which in this case is the condition created in point 1
1
3
2
Change HandIers - Conditions
134
Exercise 5 - Change HandIer Conditions
AII Students
Modify your Person change handIer from exercise 3 .
Introduce a Condition in your vaIidation ruIe to make address line 1
required if the person type is "Business" (same vaIidation as in exercise
3)
Change the vaIidation ruIe to use the Condition
OptionaI
Modify your Premise change handIer from exercise 3 .
Introduce a Condition in your vaIidation ruIe to make city required if the
county is not equaI to "San Francisco" (same vaIidation as in exercise 3)
Change the vaIidation ruIe to use the Condition
Test
Run the JUnit test cIass from exercise 3 to test
Startup the onIine system and test that your vaIidation ruIe works the
same as in exercise 4
Custom RuIes
136
Change HandIers - Custom RuIes
If vaIidation is too compIex for a decIarative ruIe, a custom
ruIe may be coded
A custom ruIe contains code to perform the specific
vaIidation - in other words, "if invaIid condition, dispIay
error message"
A custom ruIe cIass may impIement one or more abstract
methods
The methods correspond with "events" that may occur
with respect to the underIying business entity
The methods are divided into 2 categories .
1. Eager VaIidations
2. Lazy VaIidations
137
Custom RuIe - Eager VaIidation Methods
Eager vaIidations fire immediateIy when an entity is
changed by way of a delete(), setDTO() or createEntity())
The "event" methods that can be impIemented by a
custom ruIe cIass 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 deIeted
validateRegisteredChange() fires when a change is registered to
another object (e.g. a chiId) - this can be any business entity that
feeIs Iike 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
138
Custom RuIe - Lazy VaIidation Methods
Lazy vaIidations fire after a "coherent set of changes"
have been made - this is in contrast to eager vaIidations
that fire immediateIy when an entity is modified
OnIy one Iazy vaIidation method exists .
validateSave()
It fires at the "end of" a set of changes
VaIidation of chiId entities, for exampIe, can therefore be pIaced in
this method
AII types of changes (add, change, deIete or register change) wiII
trigger a validateSave()
139
Custom RuIe CIass
These are the basic steps to create and use a custom ruIe
.
1. Create a cIass that extends AbstractCustomValidation - this cIass
couId be an inner cIass of your Change HandIer if the custom
vaIidation ruIe is specific to the Business Entity being vaIidated
2. In your new cIass, provide the framework with an array of entity
properties associated with the custom ruIe - the framework uses
this to avoid additionaI vaIidations on properties aIready known to
be in error
3. In you new cIass, impIement the appropriate eager and/or Iazy
methods to perform the vaIidation
4. Reference the custom ruIe in your static vaIidation ruIe method,
as you wouId with a standard decIarative ruIe
Let's take a Iook at an exampIe .
140
Custom RuIe MapFieldNameRequired ExampIe
1. This cIass is an "inner cIass" of the ScriptFieIdMap_CHandIer
cIass - this is not required, but it makes sense if the custom
ruIe is specific to a Business Entity
2. The custom ruIe cIass extends AbstractCustomValidation
3. It passes back to the framework the property(s) being vaIidated
- in this case mapFieldName
1
3
2
141
Custom RuIe MapFieldNameRequired ExampIe
1. It overrides abstract method validateAddOrChange for immediate
(eager) vaIidation - this vaIidation code wiII get fired on either an add
or a change event
2. It casts the generic Business Entity object in the parameter to the type
of Business Entity being vaIidated - in this case ScriptFieldMap
3. If a vaIidation error is found, the addValidationError method registers
the error message with the framework
1
2
3
142
Custom RuIe MapFieldNameRequired ExampIe
1. In the Change HandIer cIass, it decIares a static method
mapFieldNameRequired - as a standard, the name ties in with the
custom ruIe cIass name of MapFieldNameRequired
2. The Change HandIer instantiates and returns a new CustomRule object
for custom ruIe cIass MapFieldNameRequired
3. The getValidationRules() method provides the framework the Iist of
ALL the ruIes in this Change HandIer - custom and standard ones
1
3
Change HandIer cIass - ScriptFieldMap_CHandler
2
143
Exercise 6 - Custom VaIidation RuIe
AII Students
Modify (or copy) your Person change handIer from exercise 5 and
make the Short Comment characteristic (characteristic type
"COMMENT") required .
Create a new message "Short Comment characteristic is required (XX)"
(where XX are your initiaIs) - the instructor can assign a unique message
number to each student
Create a runtime message method in your MessageRepository cIass
Override the ;alidateSa;e method - remember, you need to do "Iazy
vaIidation" when checking chiId entities
Characteristics are effective dated - use an iterator on PersonChara.teristi.
to scan for the "COMMENT" type
Test
Create cm.jar and startup the onIine system to test .
On a shared database, each student shouId test using a different person
144
Exercise 6 - Custom VaIidation RuIe
OptionaI
Create a JUnit test cIass for your custom vaIidation ruIe 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
beIow to test the vaIidation
Note: This remove couId trigger vaIidation on the Person, which at this
stage you want to avoid. See if you can come up with the soIution.
Create a PersonCharacteristic_DTO object from the
PersonCharacteristic_Id
Set the adhoc characteristic vaIue to something - e.g. "Test comment"
Create a new PersonCharacteristic object from the
PersonCharacteristic_DTO
Add the new PersonCharacteristic object to your coIIection 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
145
Exercise 6 - Custom VaIidation RuIe
OptionaI (continued)
Test that the ruIe gets vioIated by removing the newIy created
PersonCharacteristic object from the coIIection of characteristics - this shouId
cause an appIication exception to be thrown
Cascading Changes
147
Change HandIers - Cascading Changes
Up to now we've seen change handIers performing
vaIidation on a Business Entity
Change handIers can aIso impIement business Iogic based
on inserts, updates & deIetes to a Business Entity - i.e. to
cause "cascading changes" to occur
For exampIe, if a phone number for a Person changes,
update matching phone numbers for reIated Persons
automaticaIIy
Change handIers provide for a number of "handIe"
methods
HandIe methods are invoked when specific events occur
UnIike vaIidation, this Iogic fires immediateIy - it cannot be
deferred by the startChanges or saveChanges method caIIs
148
The foIIowing methods can be impIemented to
provide customized functionaIity .
For an Add or Copy Event
prepareToAdd()
handIeAddOrChange()
handIeAdd()
handIeRegisteredChange()
For an Update Event
prepareToChange()
handIeAddOrChange()
handIeChange()
For a DeIete Event
handIeDeIete()
Change HandIers - Cascading Changes
149
Events and Methods
Let's take a cIoser Iook at the methods .
prepareToAdd(DataTransferObject newDTO)
This method fires before a new Business Entity is added
It aIIows you to defauIt vaIues and perform other changes on a new
DTO before the add
handIeAddOrChange(BusinessEntity businessEntity,
DataTransferObject oIdDTO)
This fires before vaIidation when a entity is added OR changed
The oldDTO object contains a nuII on an add event
handIeAdd(BusinessEntity newBusinessEntity)
This fires before vaIidation when an entity is added
It aIIows for cascading updates on other objects or externaI
systems
150
Events and Methods
prepareToChange(BusinessEntity unchangedEntity,
DataTransferObject newDTO)
This fires before a change to a DTO is submitted
You can use this to defauIt vaIues and perform other changes on a DTO
before the change
handIeChange(BusinessEntity changedBusinessEntity,
DataTransferObject oIdDTO)
This fires before vaIidation when an entity is changed
It aIIows for cascading updates on other objects or externaI systems
151
Events and Methods
handIeRegisteredChange(BusinessEntity changedBusnessEnty,
RegisteredChangeDetaiI changeDetI)
This fires when a change is "registered" to the
changedBusnessEnty object via the business entity's
registerChange method
For exampIe, it can be fired when a chiId Iist associated with the
Business Entity has been changed
The RegisterChangeDetail object specifies the detaiIs of the
change
handIeDeIete(DataTransferObject oIdDTO)
This fires before vaIidation when an entity is deIeted
Let's now take a Iook at an exampIe .
Important . these are not preferred pIaces for vaIidation - vaIidation
shouId be done using vaIidation ruIes
152
handIeAdd exampIe
Create an aIert when a new account is added

@hangeHandler (entityName = account)

public class mAccount_Handler extends AbstracthangeHandler {


public void handleAdd(BusinessEntity newBusinessEntity) {
Account account = (Account) newBusinessEntity;
AccountAlerts acctAlerts = account.getAlerts();
AccountAlert_DTO acctAlertDTO = acctAlerts.newhildDTO();
acctAlerts.add(acctAlertDTO,
new AlertType_Id("PP EXEMPT"),
get$ystemDateTime().getDate());
}
}
1
2
3
1. It specifies the entity type in annotations (don't forget to do this!)
2. The cIass name ends in "_CHandIer" and extends
AbstractChangeHandler
3. It impIements the handleAdd method; the newBusinessEntity object is
a reference to the entity being added
153
handIeAdd exampIe (cont)
Create an aIert when a new account is added

@hangeHandler (entityName = account)

public class mAccount_Handler extends AbstracthangeHandler {


public void handleAdd(BusinessEntity newBusinessEntity) {
Account account = (Account) newBusinessEntity;
AccountAlerts acctAlerts = account.getAlerts();
AccountAlert_DTO acctAlertDTO = acctAlerts.newhildDTO();
acctAlerts.add(acctAlertDTO,
new AlertType_Id("PP EXEMPT"),
get$ystemDateTime().getDate());
}
}
4
5
6
7
4. It casts newBusinessEntity to an Account object
5. It gets the aIerts entity Iist (AccountAlerts) for the account - this wiII be
empty since it's a new account
6. It creates a new aIert DTO by using the entity Iist's newChildDTO
method
7. It adds the partiaIIy compIeted DTO to the account's aIert entity Iist -
the additionaI parameters are required for the entity Iist
The framework wiII add the row when the transaction commits
154
Change HandIers - Cascading Changes
The previous exampIe shows a "cascading change" to a
chiId entity (AIerts) of a Business Entity (Account)
The basic ruIes when working with chiId entities are .
ChiId entity Iists are acquired from a Business Entity via the
appropriate getter methods (e.g. getAlerts())
To add a new chiId entity, use the entity Iist's add methods
To remove a chiId entity, use the entity Iist's remove methods
155
Change HandIers - Cascading Changes
When inserting and deIeting entities that are NOT chiId
entities of the business entity being customized, more
expIicit code is required
In this case the getDTO and setDTO method caIIs need to be
used
Let's Iook at an exampIe .
156
Change HandIers V - handIeChange ExampIe
1. It impIements 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 maiIing premise Id is popuIated on the account -
maiIing premise Id is an optionaI foreign key reference (Note, on
the CI_ACCT tabIe the maiIing premise Id is a space, but on the
Business Entity object it is a nuII)
public void handlehange(BusinessEntity changedEntity,
DataTransferObject oldDTO) {
Account account = (Account) changedEntity;
if (account.getMailingPremiseId() != null) {
Premise premise = account.getMailingPremiseId().getEntity();
Premise_DTO premiseDTO = premise.getDTO();
premiseDTO.setAddress4(account.getAlertInformation());
premise.setDTO(premiseDTO);
}
}
Update the reIated premise when an account is changed
1
2
3
4
5
6
7
157
Change HandIers V - handIeChange ExampIe
4. It gets the Premise object referenced by the maiIing premise Id
fieId
5. It gets DTO for the Premise to modify the row
6. It updates the vaIue on the Premise DTO - address Iine 4 in this
case is set to the account's aIert information (i.e. the "Comment"
fieId on the account page)
7. It updates the Premise Business Entity using the setDTO()
method, which uItimateIy causes the row to be updated
public void handlehange(BusinessEntity changedEntity,
DataTransferObject oldDTO) {
Account account = (Account) changedEntity;
if (account.getMailingPremiseId() != null) {
Premise premise = account.getMailingPremiseId().getEntity();
Premise_DTO premiseDTO = premise.getDTO();
premiseDTO.setAddress4(account.getAlertInformation());
premise.setDTO(premiseDTO);
}
}
Update the reIated premise when an account is changed
1
2
3
4
5
6
7
158
Exercise 7 - Cascading Change HandIer
AII Students
Change your Person Change HandIer from the previous exercise
automaticaIIy add a Short Comment characteristic (characteristic type
"COMMENT") whenever a new Person is added
Test
Create cm.jar and startup the onIine system to test
Add a new person and verify that the Short Comment characteristic
was added by your Change HandIer
OptionaI
Create a JUnit test cIass that adds a new person and verifies that the
Short Comment characteristic was automaticaIIy added. In this
exercise, a compIeteIy new person, with aII its required coIIections of
names and Id numbers, must be created. In your test method .
Suspend vaIidation untiI aII the data has been added
Create a new Person_Id object
159
Exercise 7 - Cascading Change HandIer
OptionaI (continued)
Create a new Person_DTO object
Set the foIIowing required fieIds on the Person_DTO .
PersonOrBusiness
LifeSupportSensitiveLoad
LanguageId
Create a new Person object from the DTO
Create a PersonName_DTO object (use the getNames() method on the
Person object)
Set the foIIowing required fieIds on the PersonName_DTO .
EntityName
IsPrimaryName
NameType
Add the name to the Names coIIection on the Person object (use
sequence 1)
160
Exercise 7 - Cascading Change HandIer
OptionaI (continued)
Create a PersonId_DTO object (use the getIds() method on the Person object)
Set the foIIowing required fieIds on the PersonId_DTO .
IsPrimaryId
PersonIdNumber
Add the Id to the Ids coIIection on the Person object for Id Type "SSN" (SociaI
Security Number)
EnabIe vaIidation 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 nuII
object is returned, faiI the test as foIIows .
assertNotNull("$hort omment characteristic does not exist",
perhar);
Services and Maintenance CIasses
162
Services
Services expose business functionaIity via predefined
request and response data structures
Services may be invoked
from outside the appIication JVM (I.e. a browser)
from from within the appIication (I.e. by a service script).
These are the data access and update services
Many services are impIemented by either Java cIasses or
COBOL programs. The impIementations are caIIed
"maintenances".
163
Services
Each service has an XML metainfo document describing
its structure
For integration, the framework automates the mapping of
string-based browser data to a service's data structure
using this metainfo XML (the XAI cIass covers this)
The Service Dispatcher routes the service requests to the
Java or COBOL service .
164
Services - Service Dispatcher
The Service Dispatcher acts as conduit to the business
objects from the presentation Iayer
A service invocation represents a database transaction
It invokes a Java or COBOL service
Presentation Presentation
Service
Dispatcher
Service
Dispatcher
DB DB
Hibernate Hibernate
JDBC JDBC
JDBC JDBC
COBOL Svc
Wrapper
COBOL Svc
Wrapper
COBOL App COBOL App
Java
Maintenance
Business Objects Data Access
165
Service Dispatching
The Service Dispatcher is commonIy invoked from a Web
servIet
It invokes the appropriate service for the Web request,
which couId be one of the foIIowing
1. Page service
2. List service
3. Search service
Service Dispatcher Service Dispatcher Dispatched Service Dispatched Service
Page Service Page Service List Service List Service Search Service Search Service
1
2
3
166
Page Services
This is a "top IeveI" appIication service
It orchestrates the dispIay and update of aII data for a root object and
aII its chiId objects - e.g. Person, Person Name, Person Phone, Person
Id, etc.
The data is dispIayed on a singIe tab menu - across one or more chiId
tab pages
Page service names end with "P" - e.g. the Person service is
CILCPERP, Account service is CILCACCP, etc.
167
Page Service Dispatching
A Page service invoked in one of seven modes (actions)
Each service cIass determines if the maintenance service
is impIemented in COBOL or Java and uses the appropriate
caIIing mechanism to invoke it
Page Service Page Service
Change Change Copy Copy Default Default Delete Delete Read Read Add Add
Java Page
Add Service
Java Page
Add Service
Cobol Page
Add Service
Cobol Page
Add Service
. same for all modes
Cobol Svc
Wrapper
Cobol Svc
Wrapper
Validate Validate
168
List Services
This defines a Iist of objects
It couId contain nested Iists
It is used for Iist-oriented data - e.g. Customer Contacts
List service names end in "L" - e.g. CILCPCCL for
Customer Contact Iist
They do not support database updates
169
List Service Dispatching
A List service cIass is invoked in singIe mode ("List") from
the Service Dispatcher
It determines if the underIying Iist service is impIemented
in COBOL or Java and uses the appropriate caIIing
mechanism to invoke it
List Service List Service
Java List
Service
Java List
Service
Cobol List
Service
Cobol List
Service
Cobol Svc
Wrapper
Cobol Svc
Wrapper
170
Search Services
These are used to support ad-hoc user searches
The resuIts are simiIar to Iist services
The input is set of criteria and a search mode
Search service names end in "S" - e.g. CILCPERS for
Person search
171
Search Service Dispatching
A Search service cIass is invoked in singIe mode
("Search") from the Service Dispatcher
It determines if underIying search service impIemented in
COBOL or Java and uses the appropriate caIIing
mechanism to invoke it
Search Service Search Service
Java Search
Service
Java Search
Service
Cobol Search
Service
Cobol Search
Service
Cobol Svc
Wrapper
Cobol Svc
Wrapper
Java Maintenance CIasses
173
Java Maintenance CIasses
Important forms of maintenances:
PageMaintenances are generaI purpose and can conceivabIy do
anything. However, whatever that is must be coded by the
impIementer.
EntityPageMaintenance performs the CRUD for an MO
EntityListPageMaintenance performs CRUD on a coIIection of
entities without a singIe common maintained parent
SearchServices can perform searches based on varying input
fieIds
174
PageMaintenances
Remember, these are the generic ones
Use the @PageMaintenance annotation
Define the "body" based on the needs for request and response
DecIare actions that make sense
Supported actions are then impIemented by overriding
action methods, Iike "add" in the case of a service that
adds data to the system or "read" when it just returns
existing data.
WaIk-through: EmaiIService
175
EntityPageMaintenances
Provide CRUD for MOs
The actions interact with the Entities in the MO
Use the @EntityPageMaintenance annotation
For new MOs there is a wizard that creates a skeIetaI structure
based on metadata.
This shouId be a singIe root object. That is we are maintaining a
singIe entity instance that my have chiIdren. To maintain Iists, the
@EntityListPageMaintenance is more appropriate
176
EntityPageMaintenances
@EntityPageMaintenance vaIues
Important root vaIues:
"service" defines the name of the service
"entity" defines the entity being maintained
"body" is aIways a data eIement containing an array of "contents".
@RowFieId shouId be used for the entity being maintained
@ListFieIds reference Iists
@DataFieIds can be used to specify "Ioose fieIds"
@FieIdGroup can be used to group fieIds together
Lists
An array of Iists is kept that may be referenced by name by @ListFieId
annotations in the root node of the annotation or other Iists
The individuaI Iists have bodies Iike in the root eIement discussed above.
FiIters may be appIied using HQL snippets which bind vaIues in the
impImentation cIass
WaIk-through: FactMaintenance
177
EntityListPageMaintenances
Use the @EntityListPageMaintenance annotation
These are typicaIIy very simpIe impIementations
A @ListFieId wiII be used to define the maintained Iist in the root
body of the annotation
The reference Iist wiII refer to a @RowFieId corresponding to the
entity being maintained
orderBy" wiII specify ordering
WaIk-through: CurrencyMaintenance,
LanguageListMaintenance
178
Search Services
Use the @SearchService annotation
Provide some number of different search criteria that can be used
via the @SearchCriteria annotation. ImportantIy,
"hqI" defines how the rows are retrieved
"orderBy" specifies the order
"fieIds" specifies the vaIues that the search is based on
"returnVaIus" specifies the vaIues return be a search resuIt row
and incIudes HQL snippets to extract these vaIues from the query
resuIt object
WaIk-through: BatchControISearch
The EcIipse MO Wizard
180
The EcIipse MO Wizard
An EcIipse pIug-in was written to create defauIt
impIementation cIasses, with annotations based on MO
metadata definitions. This "wizard" wiII create:
Entity "ImpI" cIasses for each entity in the MO
An EntityPageMaintenance cIass
The user chooses the names for the cIass fiIes, the
package and fiIe Iocation and the wizard does the rest
Running the Wizard From EcIipse
End of Day 2
Business Components
184
Business Components
Business Components are cIasses that provide two
important features
A pIace to put reusabIe business Iogic without the other
responsibiIites that come with other types of appIication cIasses
(Iike entities, change handers, etc).
Provide a Iightweight repIacement strategy that aIIows customers
to fuIIy repIace some system Iogic without aII of the formaIity and
configuration of new pIugin spots.
185
Adding a Business Component
Use the @BusinessComponent annotation
With this simpIe anotation, the artifact generator wiII process the
business component and create business interface cIass.
customizationRepIaceabIe
Specify "customizationRepIaceabIe" to indicate if a customer may
repIace this component. Setting this vaIue to "true" aIso has the
affect of treating the component as a customization whether or not it
was actuaIIy provided by the base package or not.
customizationCaIIabIe
Specify if the component is "customizationCaIIabIe". This can be set
to true to aIIow customers to caII methods on the business component
but not repIace the component
.more.
186
Adding a Business Component
Use the @BusinessComponent annotation
repIacementComponent
In the case where the component is repIacing a component defined in
an appIication Iower on the appIication stack, setting the
"repIacementComponent" attribute to "true" wiII cause the component
to be the repIacement component for any repIaceabIe components
where this component impIements the same business interface as the
component being repaced.
Extend GenericBusinessComponet
AIgorithms
188
AIgorithms - Overview
Where the system requires a customization, we provide for
customizabIe aIgorithms (a.k.a pIug-ins)
Base aIgorithms exist, but can be cIoned and modified
They are Iike "user exits", but .
UnIike Change HandIers, they are more reIated to the business
functions and events
AIso, unIike Change HandIers, they use configurabIe ("soft")
parameters
For exampIe .
In the CC&B worId, if a CSR requests a customers recommended
deposit amount, the system caIIs a "deposit recommendation
aIgorithm" to caIcuIate the amount
If the base version of the aIgorithm is not appropriate for your
business, a new aIgorithm can be coded to repIace or suppIement
the base one
189
AIgorithms - Overview
At upgrades, custom aIgorithms wiII not be overwritten
Here are a few more exampIes where aIgorithms are used
VaIidating the format of a phone number entered by the user
VaIidating the format of a Iatitude/Iongitude geographic code
entered by the user.
CaIcuIating Iate payment charges in CC&B
CaIcuIating the recommended deposit amount in CC&B
In CC&B, constructing your GL account during the interface of a
financiaI transaction to your GL
Etc.
Let's take a Iook at how aIgorithms work internaIIy .
190
AIgorithms - Overview
AIgorithms are defined in 2 pIaces .
Database tabIes
The onIine Admin menu is used to define the database components,
which are .
AIgorithm Types
AIgorithms
The event or activity to which the aIgorithm appIies (e.g. FT freeze, phone
number vaIidation, etc.)
The OU Framework
The framework requires the "impIementation" cIass - the program
that contains the Iogic - and various generated artifacts (we wiII onIy
be Iooking at Java, not COBOL)
Let's take a Iook at these definitions more cIoseIy, database components
first and then the framework cIasses .
191
CI_ALG_TYPE
PK ALG_TYPE_CD
PGM_NAME
ALG_ENTTY_FLG
PGM_TYPE_FLG
CI_ALG
PK ALG_CD
FK1 ALG_TYPE_CD
VERSON
CI_ALG_TYPE_PRM
PK,FK1 ALG_TYPE_CD
PK SEQNO
PARM_REQ_SW
CI_ALG_PARM
PK,FK2 ALG_CD
PK EFFDT
PK,FK1 SEQNO
ALG_PARM_VAL
FK1 ALG_TYPE_CD
Customized Entity
FK1 ALG_CD
AIgorithm Database ModeI
These are the tabIes that define an aIgorithm
. Algorithm Type defines .
The entity - e.g. Char Type Adho. Val:e Validation, SA Type SA
Creation, etc.
The program name
The program type - JAVA or COBOL
1
192
AIgorithm Database ModeI
These are the tabIes that define an aIgorithm
2. Algorithm Type Parameter defines .
The parameters expected by the aIgorithm program
For each parameter, whether it is required or optionaI
CI_ALG_TYPE
PK ALG_TYPE_CD
PGM_NAME
ALG_ENTTY_FLG
PGM_TYPE_FLG
CI_ALG
PK ALG_CD
FK1 ALG_TYPE_CD
VERSON
CI_ALG_TYPE_PRM
PK,FK1 ALG_TYPE_CD
PK SEQNO
PARM_REQ_SW
CI_ALG_PARM
PK,FK2 ALG_CD
PK EFFDT
PK,FK1 SEQNO
ALG_PARM_VAL
FK1 ALG_TYPE_CD
Customized Entity
FK1 ALG_CD
1
2
193
CI_ALG_TYPE
PK ALG_TYPE_CD
PGM_NAME
ALG_ENTTY_FLG
PGM_TYPE_FLG
CI_ALG
PK ALG_CD
FK1 ALG_TYPE_CD
VERSON
CI_ALG_TYPE_PRM
PK,FK1 ALG_TYPE_CD
PK SEQNO
PARM_REQ_SW
CI_ALG_PARM
PK,FK2 ALG_CD
PK EFFDT
PK,FK1 SEQNO
ALG_PARM_VAL
FK1 ALG_TYPE_CD
Customized Entity
FK1 ALG_CD
AIgorithm Database ModeI
These are the tabIes that define an aIgorithm
. Algorithmdefines an "instance" of the aIgorithm type - many
aIgorithms may exist for one aIgorithm type
4. Algorithm Parameter defines the parameter vaIues for the
instance
4
1
2
3
194
CI_ALG_TYPE
PK ALG_TYPE_CD
PGM_NAME
ALG_ENTTY_FLG
PGM_TYPE_FLG
CI_ALG
PK ALG_CD
FK1 ALG_TYPE_CD
VERSON
CI_ALG_TYPE_PRM
PK,FK1 ALG_TYPE_CD
PK SEQNO
PARM_REQ_SW
CI_ALG_PARM
PK,FK2 ALG_CD
PK EFFDT
PK,FK1 SEQNO
ALG_PARM_VAL
FK1 ALG_TYPE_CD
Customized Entity
FK1 ALG_CD
AIgorithm Database ModeI
These are the tabIes that define an aIgorithm
5. The aIgorithm code is specified on the customized entity's
configuration tabIe - the aIgorithm wiII be invoked based on
this specification
Let's Iook at an exampIe .
5
ExampIes
Characteristic Type
SA Type
Etc.
4
1
2
3
195
AIgorithm Phone Format ExampIe
Phone format - aIgorithm definition diagram
AIgorithm Type:PHN-FMT
CI_ALG_TYPE
PK ALG_TYPE_CD
PGM_NAME
ALG_ENTTY_FLG
PGM_TYPE_FLG
CI_ALG
PK ALG_CD
FK1 ALG_TYPE_CD
VERSON
CI_ALG_TYPE_PRM
PK,FK1 ALG_TYPE_CD
PK SEQNO
PARM_REQ_SW
CI_ALG_PARM
PK,FK2 ALG_CD
PK EFFDT
PK,FK1 SEQNO
ALG_PARM_VAL
FK1 ALG_TYPE_CD
Phone Type
FK1 ALG_CD
Format 1 - required
Format 2 - optionaI
Format 3 - optionaI
AIgorithm:PHN-FMT-US
(999) 999-9999
Format 4 thru 9 - optionaI
AIgorithm:PHN-FMT-UK
999 9999-9999
99999 999999
9999 999-9999
Phone Type: BUSN
Phone Type: BUSN_UK
196
AIgorithm Phone Format ExampIe
Admin -> Algorithm Type - Phone format
1. AIgorithm Type name - 12 characters
2. The AIgorithm Entity determines where the system wiII aIIow this
aIgorithm to be specified - in this case, the PHN-FMT aIgorithm type
may onIy be specified on the Phone Type entity
3. The Program Type here is JAVA (it can aIso be COBOL)
2
3
4
1
5
197
AIgorithm Phone Format ExampIe
Admin -> Algorithm Type - Phone format
4. This is the aIgorithm component interface to format and vaIidate the
phone number
Note: for the JAVA class to be specified, the class must already exist as a
framework component
5. This specifies that at Ieast one phone format is required
2
3
4
1
5
198
AIgorithm Phone Format ExampIe
Admin -> Algorithm - Phone format US
1. This is the aIgorithm name - i.e. the 1st "instance" of the aIgorithm type
2. The AIgorithm Type that this aIgorithm corresponds to
3. The effective date
4. The phone format for this instance - onIy one for the U.S.
3
1
4
2
199
AIgorithm Phone Format ExampIe
Admin -> Algorithm - Phone format UK
1. This is the aIgorithm name - i.e. the 2nd "instance" of the aIgorithm
type
2. It has the same aIgorithm type as for the U.S. (i.e. it is the SAME
PROGRAM that formats U.S. and U.K. phone numbers)
1
3
2
200
AIgorithm Phone Format ExampIe
Admin -> Algorithm - Phone format UK
3. The U.K. has muItipIe phone formats - the aIgorithm wiII vaIidate a U.K.
phone number against aII of these formats
1
3
2
201
AIgorithm Phone Format ExampIe
Admin -> Phone Type - AIgorithm usage
1
2
This defines 2 types of business phones
1. U.S. phone numbers are to be vaIidated and formatted by the
"North American phone format" aIgorithm, as defined on the
previous sIides
2. U.K. phone numbers are to be vaIidated and formatted by the
"United Kingdom phone format" aIgorithm, as defined on the
previous sIides
202
AIgorithm Phone Format ExampIe
Main -> Person - AIgorithm activation
1
2
On the Person page, Phone Type now determines the aIgorithm to
invoke for the phone number formatting and vaIidation
In this topic we have so far Iooked at defining the database
entries required for an aIgorithm definition - next we'II see
how the framework components are buiIt to support these
definitions .
203
AIgorithm Spots
The "caII out" pIaces in the system (e.g. from Person to vaIidate phone
number) are known as aIgorithm spots
Each aIgorithm spot has an interface cIass
Communication with an aIgorithm takes pIace through the interface
An interface provides abstraction between the base and the
customization
Business
Component
AIgorithm
Component
AIgorithm Spot
Interface
Person Phone Person Phone
PhoneTypeFormat
VaIidationAIgComp
PhoneTypeFormat
VaIidationAIgComp
PhoneTypeFormat
ValidationAlgorithmSpot
PhoneTypeFormat
ValidationAlgorithmSpot
204
AIgorithm Spots
The attributes of an aIgorithm spot interface cIass are .
The API to the aIgorithm component (from the base appIication)
It is specific to the aIgorithm entity type (or system "event")
It defines the hard input parameters for an aIgorithm - these are the
parameters associated with a specific event
It defines the output parameters that can be retrieved after the
aIgorithm has been invoke
AIgorithm spots aIso specify the schema defined for a pIug-in script
205
AIgorithm Spots
These cIasses form part of the base code
They are invoked from the base code at appropriate times (events)
The methods on the interface are reIated to the aIgorithm type - for
exampIe, setPhoneValue() is onIy reIevant to
PhoneTypeFormatValidationAlgorithmSpot
+in;oke()
interface
AIgoritmSpot
+setFormatOnly() : ;oid
+setChara.teristi.Type() : ;oid
+setAdho.Val:e() : ;oid
+getReformattedVal:e() : String
+isValidAdho.() : Boolean
interface
AdhocCharacteristicVaIueVaIidationAIgorithmSpot
+setPhoneVal:e() : ;oid
+setPhoneType() : ;oid
+isValidPhoneVal:e() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneVal:e() : String
interface
PhoneTypeFormatVaIidationAIgorithmSpot
206
Adding AIgorithm Spots
AIgorithm spots reference an AIgorithmEntityLookup vaIue
so a new Iookup vaIue must be added to correspond to the
new spot
Add an interface that defines the spot using the
@AIgorithmSpot annotation. Properties incIude
aIgorithmEntity-One or more AIgorithmEntity vaIues corresponding
to the Iookup vaIue described above
caIIedFromCoboI-A booIean attribute that Iets the framework know if
inbound caII support is to be supported from COBOL
impIementabIeInCoboI-A booIean attribute that Iets the framework
know if it must be abIe to caII an aIgorithm impIemented in COBOL
Extend the AIgorithmSpot interface
Wire up the caII to the spot by accessing the AIgorithmComponent via
Algorithm.getAlgorithmomponent(.)
ExampIe: See TimeIineZoneAIgorithmSpot in FW
207
Supporting PIug-in Scripts
AIgorithms may aIso be impIemented in PIug-in Scripts
In these cases, the Java signature gets interpreted by the
framework at runtime to generate the "parm" schema
defining the parameters passed in and out of the pIug-in
script when invoked
The framework needs to be abIe to figure out how to make
XML out of the input parameters and make output parameter
objects out of the output parameters. This cannot be done
with every possibIe interface. The spot deveIoper must
heIp!
SimpIe JavaBean compIiant getters an setters shouId be
used where
"set" methods represent vaIues sent into the aIgorithm
"get" methods represent vaIues returned
208
Supporting PIug-in Scripts
CoIIections on the signature shouId have generic type
information so the framework knows the cIass of the
eIements that it may contain.
The ArtifactGenerator checks spot compatabiIity with
scripting and wiII issue an error if the spot cannot be used
by the framework for pIug-in scripts
For unusabIe spots, there are two approaches
For new spots, the spots shouId be reworked to compIy with
framework requirements
Some spots have been shipped before the pIug-in spot technoIogy
was created and were unknowingIy non-compIient. These spots
cannot be reworked because they have been depIoyed to customers.
Therefore a "BeanAdapter" cIass is necessary.
PIease see the Wiki for more information on BeanAdapters
209
AIgorithm Components
An aIgorithm requires a programmatic impIementation
The AIgorithm Type definition carries the program name,
for exampIe
com.splwg.base.domain.common.phoneType.
PhoneTypeFormatValidationAlgomp
This name in fact specifies another interface which is
generated from the impIementation cIass
The impIementation cIass name = the interface name +
"ImpI", for exampIe
com.splwg.base.domain.common.phoneType.
PhoneTypeFormatValidationAlgomp_Impl
The foIIowing diagram describes the fuII Phone Type
VaIidation aIgorithm component .
210
AIgorithm Components - Phone Type VaIidation
Remember .
An interface is "empty" - it requires an impIementation to perform
appropriate tasks
The impIementation for an aIgorithm spot is an AIgorithm
Component - i.e. Business Component
+setPhoneVal:e() : ;oid
+setPhoneType() : ;oid
+isValidPhoneVal:e() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneVal:e() : String
interface
PhoneTypeFormatVaIidationAIgorithmSpot
+getPhoneFormat1() : String
+getPhoneFormat2() : String
+getPhoneFormat3() : String
+getPhoneFormat4() : String
+getPhoneFormat5() : String
+getPhoneFormat6() : String
+getPhoneFormat7() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String
PhoneTypeFormatVaIidationAIgComp_Gen
+invoke() : void
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String
PhoneTypeFormatVaIidationAIgComp_ImpI
+in;oke()
interface
AIgoritmSpot
+setPhoneVal:e() : ;oid
+setPhoneType() : ;oid
+isValidPhoneVal:e() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneVal:e() : String
interface
PhoneTypeFormatVaIidationAIgComp
211
+setPhoneVal:e() : ;oid
+setPhoneType() : ;oid
+isValidPhoneVal:e() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneVal:e() : String
interface
PhoneTypeFormatVaIidationAIgorithmSpot
+getPhoneFormat1() : String
+getPhoneFormat2() : String
+getPhoneFormat3() : String
+getPhoneFormat4() : String
+getPhoneFormat5() : String
+getPhoneFormat6() : String
+getPhoneFormat7() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String
PhoneTypeFormatVaIidationAIgComp_Gen
+invoke() : void
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String
PhoneTypeFormatVaIidationAIgComp_ImpI
+in;oke()
interface
AIgoritmSpot
+setPhoneVal:e() : ;oid
+setPhoneType() : ;oid
+isValidPhoneVal:e() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneVal:e() : String
interface
PhoneTypeFormatVaIidationAIgComp
AIgorithm Components - Phone Type VaIidation
1
2
3
1. The impIementation cIass (._Impl) is hand-coded - it can be
customized
2. The component interface is generated by the artifact generator - a
customized version wiII be generated for a custom "impI" cIass
3. An aIgorithm is invoked via its component interface
212
1. The impIementation cIass contains the hand-coded Iogic
2. The _Gen cIass has the methods for the "soft" parameters (as
specified on the AIgorithm Type definition)
Note: These are generated from the annotations in the "_ImpI" cIass
+setPhoneVal:e() : ;oid
+setPhoneType() : ;oid
+isValidPhoneVal:e() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneVal:e() : String
interface
PhoneTypeFormatVaIidationAIgorithmSpot
+getPhoneFormat1() : String
+getPhoneFormat2() : String
+getPhoneFormat3() : String
+getPhoneFormat4() : String
+getPhoneFormat5() : String
+getPhoneFormat6() : String
+getPhoneFormat7() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String
PhoneTypeFormatVaIidationAIgComp_Gen
+invoke() : void
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String
PhoneTypeFormatVaIidationAIgComp_ImpI
+in;oke()
interface
AIgoritmSpot
+setPhoneVal:e() : ;oid
+setPhoneType() : ;oid
+isValidPhoneVal:e() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneVal:e() : String
interface
PhoneTypeFormatVaIidationAIgComp
AIgorithm Components - Phone Type VaIidation
1
2
213
3. The generated component interface cIass aIso contains a "factory" cIass to
create an instance of an aIgorithm component - we'II see an exampIe of this
shortIy
+setPhoneVal:e() : ;oid
+setPhoneType() : ;oid
+isValidPhoneVal:e() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneVal:e() : String
interface
PhoneTypeFormatVaIidationAIgorithmSpot
+getPhoneFormat1() : String
+getPhoneFormat2() : String
+getPhoneFormat3() : String
+getPhoneFormat4() : String
+getPhoneFormat5() : String
+getPhoneFormat6() : String
+getPhoneFormat7() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String
PhoneTypeFormatVaIidationAIgComp_Gen
+invoke() : void
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String
PhoneTypeFormatVaIidationAIgComp_ImpI
+in;oke()
interface
AIgoritmSpot
+setPhoneVal:e() : ;oid
+setPhoneType() : ;oid
+isValidPhoneVal:e() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneVal:e() : String
interface
PhoneTypeFormatVaIidationAIgComp
AIgorithm Components - Phone Type VaIidation
3
214
AIgorithm ImpIementation CIass
The base versions of aII aIgorithms are provided
To create a new one, it is easiest to dupIicate the
appropriate base one if it exists and modify it
The basic Java eIements of a new aIgorithm are:
An "_ImpI" cIass, the hand-coded impIementation cIass that contains
the Iogic
A "_Gen" cIass, the impIementation cIass for the "soft" parameters,
generated by the artifact generator
A component interface cIass, generated by the AG
A message method, if required
215
AIgorithm Phone Format ExampIe
This ImpI cIass's annotation specifies .
1. The soft parameters expected by the aIgorithm - these correspond with
the AIgorithm Type parameter definitions
2. Has an AIgorithm Component name (as specified on the AIgorithm
Type) + "_ImpI"
1
2
3
4
216
AIgorithm Phone Format ExampIe
The cIass name .
3. Extends the "_Gen" cIass - the "_Gen" cIass is generated by the
Artifact Generator
4. ImpIements the base AIgorithm Spot cIass for the aIgorithm type
1
2
3
4
217
AIgorithm Phone Format ExampIe
These methods are invoked by the business component to set the
hard parameters
1. This sets the phone number to vaIidate - it is stored here for use Iater
2. This sets the phone type - this method here is empty because it is
ignored in this aIgorithm
AIgorithm Spot interface methods that are impIemented in _ImpI cIass .
1
2
218
AIgorithm Phone Format ExampIe
The invoke() method is caIIed to vaIidate and format the phone
number
1. This sets a BooIean based on the vaIidity of the phone number
AIgorithm Spot interface methods that are impIemented in _ImpI cIass .
1
219
AIgorithm Phone Format ExampIe
AIgorithm Spot interface methods that are impIemented in _ImpI cIass .
These methods are caIIed from the business component after the
invoke() method
1. This returns a true/faIse to indicate the vaIidity of the phone number
(you may have noted that this BooIean is the one set in the invoke method)
2. This returns the reformatted vaIue, aIso formatted in invoke()
1
2
3
220
AIgorithm Phone Format ExampIe
AIgorithm Spot interface methods that are impIemented in _ImpI cIass .
These methods are caIIed from the business component after the
invoke() method
3. This returns the defauIt phone format - in this case it is aIways the first
one (e.g. 1
st
format for U.K. - "999 9999-9999")
1
2
3
221
AIgorithm Phone Format ExampIe
Generated artifacts that are based on the _ImpI cIass annotation .
The _Gen cIass has the methods for the soft parameters
The _ImpI cIass caIIs these methods to get the soft parameter vaIues, as set
on the AIgorithm definition
222
AIgorithm Phone Format ExampIe
Generated artifacts that are based on the _ImpI cIass annotation .
The component interface defines the required methods for the _ImpI
cIass as viewed from the appIication (the business component)
223
AIgorithm Phone Format ExampIe
Generated artifacts that are based on the _ImpI cIass annotation .
1. The Artifact Generator aIso generates a static Factory cIass in the
component interface cIass fiIe
2. It has the newInstance method to create an instance of the aIgorithm
component at runtime
1
2
224
AIgorithm ImpIementation CIass Review
The steps to create a new aIgorithm cIass are .
1. Determine the AIgorithm Spot interface name - the Javadocs couId be
used for this
2. Create the "_ImpI" cIass, impIementing the appropriate AIgorithm Spot
interface
3. Add defauIt impIementations for aII the AIgorithm Spot methods (e.g.
using the EcIipse Source Override/implement Methods. menu item)
4. Code the annotation
5. Run the Artifact Generator to create the "_Gen" and component interface
cIasses
In EcIipse, you MUST refresh the project after this!
225
AIgorithm ImpIementation CIass Review
The steps to create a new aIgorithm cIass are .
6. Edit the "_ImpI" cIass and .
Extend the "_Gen" cIass on the cIass definition
Store the required instances variabIes in the appropriate set. methods (these
instance variabIes wiII be referenced in the invoke() method)
Code the invoke() method - this contains the main Iogic
Return the vaIue(s) in the get. methods as required by the AIgorithm spot
7. Create the cm.jar fiIe and shutdown and restart the appIication server -
this is necessary for the Java cIass to be visibIe when creating the
AIgorithm Type definition (next step)
8. Create the AIgorithm Type definition - the Java cIass name wiII now be in
the Program Name drop-down Iist AND wiII automaticaIIy insert the
AIgorithm Type parameters from your annotation specification
NOTE: This is the reason for creating the Java impI cIass BEFORE adding the
AIgorithm Type and AIgorithm definitions in the UI
226
AIgorithm ImpIementation CIass Review
The steps to create a new aIgorithm cIass are .
9. Create the AIgorithm definition
10. Attach the aIgorithm to the business component
11. Test
227
Exercise 8 - Geographic Type AIgorithm
AII Students
In this exercise you wiII create a Geographic Type aIgorithm to
vaIidate geographic type "REGION" on Premise
Consider the foIIowing 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 aIIow for the region
code to be specified on Premise
5. The format of region code is CC, where .
W = WorId 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
228
Exercise 8 - Geographic Type AIgorithm
AII Students (continued)
6. The vaIid region code vaIues must be specified as soft parameters - i.e. no
hardcoding of vaIues in Java are aIIowed
Java Requirements
The AIgorithm Spot to impIement is GeoTypeFormatVaIidationAIgorithmSpot
Name your cIass CmGeoTypeRegionAlgComp_Impl in package
com.splwg.cm.domain.common.geographicType
Create 2 parameters .
1. worldRegion, string, req:ired
This wiII contain the 1-digit worId region code
2. .o:ntryCodes, string, req:ired
This wiII contain a comma-deIimited string of vaIid country codes for their associated
worId region code
229
Exercise 8 - Geographic Type AIgorithm
OnIine Configuration
Create AIgorithm Type GEOREGION (where are your initiaIs) .
The AIgorithm Entity is "Geographic Type - VaIue Format RuIe"
Program Type is "Java"
Program Name shouId be CmGeoTypeRegionAlgComp
Create two AIgorithm definitions .
1. GEOREG-E (where are your initiaIs)
Specifies Europe and its vaIid countries
2. GEOREG-N (where are your initiaIs)
Specifies North America and its vaIid countries
Create two new Geographic Type definitions, using the foIIowing vaIues
for Type, Description and Format AIgorithm respectiveIy .
1. REG-E, "Region Europe ()", GEOREG-E (where are your initiaIs)
2. REG-N, "Region North America ()", GEOREG-N (where are your
initiaIs)
230
Exercise 8 - Geographic Type AIgorithm
OnIine Configuration (continued)
From your browser, use URL
http://IocaIhost:6800/fIushDropdownCache.jsp to deIete the drop-down
cache on the server, and then cIear the browser cache by deIeting your
"temporary internet fiIes" to make the new Geographic Types known to
the Premise Geographic Data page
(Note: "IocaIhost" and "6800" above refer to the server name and port of
your web appIication server - it may be named differentIy in your specific
case)
Test
When adding or changing a Geographic Type on Premise, the
aIgorithm shouId vaIidate the format and content of geo type and
dispIay the generic message "Premise Geographic VaIue format
incorrect" if invaIid
OptionaI
The JUnit test cIass for this exercise shouId check aII possibIe
combinations of invaIid worId regions and country codes, but we wiII
onIy check two conditions - one vaIid and one invaIid
231
Exercise 8 - Geographic Type AIgorithm
OptionaI (continued)
Code a JUnit test cIass for your aIgorithm (the cIass must extend
AlgorithmImplementationTestCase) and in the test method - e.g.
testGeoTypeRegion .
SimiIar 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. "REG-E" or "REG-N")
Create a PremiseGeographicLocation_Id object for the Premise_Id (as
instantiated above) and GeographicType_Id
Suspend vaIidation for the foIIowing steps
Create a new PremiseGeographicLocation_DTO from the Id above
On the DTO, set the vaIue of GeographicVaIue (e.g. "E-UK")
Add the new GeographicLocation (via the DTO) to the coIIection of
GeographicLocations for the Premise (note: the add method can aIso
accept the DTO with the GeographicType_Id (e.g. "REG-E")
232
Exercise 8 - Geographic Type AIgorithm
OptionaI (continued)
Remove the suspension to vaIidate that the data currentIy entered is vaIid - an
appIication error is not expected at this point
Remove the existing PremiseGeographicLocation from the coIIection of
GeographicLocations
Set the GeographicValue to an invaIid vaIue (e.g. "E-US")
Re-add the PremiseGeographicLocation object to the GeographicLocations
Iocation which shouId trigger the vaIidation
Catch the Appli.ationError and use the foIIowing statement to verify that the correct
error was thrown .
assertServerMessage(e, 3, 33901);
Creating AIgorithm Spots
234
Creating AIgorithms Spots
Batch
236
SPL Batch I
In this section we wiII Iook at .
A brief overview of the SPL batch environment
An overview of batch controIs
Batch programming in Java
237
Batch Environment
Batch programs run outside of the web app server, but stiII
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, aII SQL caIIs are handIed by the framework -
there are no direct caIIs from COBOL to OracIe/DB2/SQL
Server (e.g. via PRO*CoboI)
238
Batch Threading
The system uses threading to achieve maximum
performance
What does a threaded process do?
It determines the fuII workIoad (e.g. how many accounts?)
It divides the workIoad into n number of threads
It dispatches each thread to perform the workIoad - the workIoads
are executed concurrentIy
For exampIe, instead of one task biIIing 50000 accounts, 5
tasks can each biII 10000 accounts simuItaneousIy - this is
naturaIIy much faster
The Artifact Generator creates the necessary components
for muIti-threading and the batch framework faciIitates its
execution
239
Batch ControI
Batch controIs are used in batch processing to controI
restartibiIity, program identification, parameters, etc.
Each batch process has its own batch controI code
A batch controI code defines .
The program name
The program type (COBOL / Java)
The batch parameters
For exampIe .
240
Batch ControI - Java ExampIe
1. The Batch ControI code
2. The Program Type
3. The Program Name
1
2
3
4
6
5
241
Batch ControI - Java ExampIe
4. The batch run number (for this batch controI) of the next submission
5. Check this to accumuIate the "records processed" counts for aII
instances of one job - if the job faiIs and restarts, it wiII add the
"faiIed" + "restarted" instances for the totaI records processed -
shouId be unchecked for programs that work with fIat fiIes
1
2
3
4
6
5
242
Batch ControI - Java ExampIe
6. These are the non-standard parameters for the batch process - these
parameters are prompted for after the standard parameters
They are suppIied at runtime using name=vaIue pairs, for exampIe
ILE-PATH=/spl/data
1
2
3
4
6
5
243
Batch Process Overview
A background process consists of 2 types of cIasses .
1. A BatchJob
2. A ThreadWorker
The BatchJob cIass determines the work to be processed
and spIits it into chunks based on a thread count
Each "chunk" of work is processed by an instance of
ThreadWorker
Let's take a Iook at these two components .
244
Batch Process Overview
BatchJob determines the work and divides it into manageabIe
chunks (ThreadWork)
Each ThreadWork consists of WorkUnits
WorkUnits represent fine-grained units of work - e.g. one biII
245
Batch Process Overview
The ThreadWorker is responsibIe for processing a singIe
ThreadWork instance
Each ThreadWorker corresponds to one batch instance row on the
database, which is used for restart after faiIure
246
The BatchJob CIass
The BatchJob cIass consists of an annotation and a number
of standard methods that the framework uses to invoke and
communicate with a batch process
Let's take a Iook at these components of a BatchJob cIass
.
247
BatchJob CIass Annotation
. rerunnable indicates if the job can be re-run - e.g. biII print extract
can be re-run
2. multiThreaded teIIs the framework if job can be submitted in
muItipIe threads - i.e. if it wiII accept a thread count > 1
. modules contains the moduIes the program beIongs to - this
should be empty for customizations
@BatchJob (rerunnable = false,
multiThreaded = true,
modules={todo},
softParameters = { @BatchJob$oftParameter
(name=O&TP&T-DIR, type=string) },
toDoreation = @ToDoreation (
drillKeyEntity = user,
sortKeys = {lastName, firstName},
messageParameters = {firstName, lastName}
)
)
1
2
3
4
5
A BatchJob cIass annotation Iooks as foIIows .
248
BatchJob CIass Annotation
4. These are the non-standard parameters to prompt for when the
job starts
5. This specifies how the "ToDo" entries shouId be created if
appIication errors are found
A BatchJob cIass annotation Iooks as foIIows .
@BatchJob (rerunnable = false,
multiThreaded = true,
modules={todo},
softParameters = { @BatchJob$oftParameter
(name=O&TP&T-DIR, type=string) },
toDoreation = @ToDoreation (
drillKeyEntity = user,
sortKeys = {lastName, firstName},
messageParameters = {firstName, lastName}
)
)
1
2
3
4
5
249
BatchJob CIass Definition
The BatchJob cIass must extend cIass
"<BatchJob class Name>_Gen", for exampIe
The _Gen cIass is generated by the artifact generator
based on the BatchJob annotation
public class BatchErrorToDoreation
extends BatchErrorToDoreation_Gen {
250
BatchJob CIass PubIic Methods
The foIIowing standard pubIic methods must exist in a
BatchJob cIass .
Method getJobWork()
This method determines the workIoad (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!
251
BatchJob CIass PubIic Methods
Method getThreadWorkerClass()
This method passes back to the framework the cIass name of the
"worker" cIass - i.e. the hand-coded cIass that wiII perform the batch
work
The framework wiII create an instance of this cIass for each ThreadWork
instance - i.e. each thread
Passing back the cIass name (instead of an object) aIIows the framework
to controI the instantiation of the ThreadWorker cIasses so that they can
be executed anywhere, even on different servers
252
The ThreadWorker CIass
The ThreadWorker cIass is responsibIe for processing a singIe
ThreadWork instance - in other words, it performs the "heavy Iifting"
A ThreadWorker can be executed on the same, or a different, server
as its associated BatchJob and other ThreadWorker instances
A ThreadWorker cIass must extend the artifact-generated cIass
"<ThreadWorker class name>_Gen" (the exampIe beIow iIIustrates)
By convention a ThreadWorker cIass is coded as a static inner cIass
in its parent BatchJob cIass
public class BatchErrorToDoreation
extends BatchErrorToDoreation_Gen {
... BatchJob methods ...
public static class BatchErrorToDoreationWorker
extends BatchErrorToDoreationWorker_Gen {
... ThreadWorker methods ...
}
}
253
ThreadWorker CIass PubIic Methods
The foIIowing standard pubIic methods are impIemented
in a ThreadWorker cIass .
254
ThreadWorker CIass PubIic Methods
Method createExecutionStrategy()
This methods teIIs the framework how the work for thread wiII be
processed
It returns to the framework an instance of
ThreadExecutionStrategy of which the foIIowing impIementations
currentIy exist .
SingIeTransactionStrategy
This teIIs the framework to process aII work in singIe transaction
(IogicaI unit-of-work)
FaiIure resuIts in a roIIback of the entire thread's updates
It is most appropriate for jobs that CANNOT toIerate errors in the
middIe of a run, for exampIe interfaces from fIat fiIes
CommitEveryUnitStrategy
This teIIs the framework to process each ThreadWorkUnit (e.g. one
biII) in its own transaction and to issue a commit after each
successfuI compIetion
255
ThreadWorker CIass PubIic Methods
Method createExecutionStrategy()
ThreadExecutionStrategy implementations continued.
StandardCommitTransactionStrategy
This teIIs the framework to process up to a configurabIe number of
work units within the same transaction to increase performance. If
an error occurs, the previousIy successfuI units are reprocessed and
the record and error skipped after Iogging the error.
It is most appropriate for jobs with high performance demands that must
aIso toIerate errors.
256
ThreadWorker CIass PubIic Methods
Method InitializeThreadWork(boolean)
This is caIIed by the framework at the start of a thread run to
perform initiaIization
By defauIt it does nothing, but can be overridden to open fiIes,
initiaIize variabIes, etc.
A BooIean parameter indicates if it was caIIed previousIy
Method executeWorkUnit(ThreadWorkUnit)
This is invoked once for each ThreadWorkerUnit assigned to a
ThreadWorker
For exampIe, for a thread processing 1000 accounts, this method
wiII be caIIed 1000 times
It performs the actuaI work, for exampIe to process an account for
biIIing
The ThreadWorkUnit parameter is a reference to the Business
Entity to be processed - you use this parameter's getPrimaryId
method to get the business entity's Id object
257
ThreadWorker CIass PubIic Methods
Method finalizeThreadWork()
This method is caIIed at the end of thread processing
It can be used to cIean up after a thread, for exampIe to cIose fiIes
These are the basic buiIding bIocks for a batch cIass
Let's take a Iook at a compIete exampIe that creates ToDos
for batch runs that ended in error .
258
BatchJob ExampIe - Create Batch Error ToDos

@BatchJob (rerunnable = false,


multiThreaded = false,
modules={todo})

public class mBatchErrorToDoreation


extends mBatchErrorToDoreation_Gen {
private static final Logger logger =
LoggerFactory.getLogger(mBatchErrorToDoreation.class);
...
1. The BatchJob annotation specifies this job is not rerunnabIe, not
muIti-threaded and a "ToDo" moduIe (remember, for a custom
batch cIass, moduIes shouId be empty - i.e. {})
2. The cIass extends its associated _Gen cIass
3. This is a static definition of the Log4j Iogger to Iog messages at
runtime (Note: You reaIIy shouId not Iog appIication messages to
the system Iog, but for these exercises we wiII)
1
2
3
The annotation and cIass definition
259
BatchJob ExampIe - Create Batch Error ToDos
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 variabIe in the query to the Iookup constant
ERROR
The BatchJob methods
public JobWork getJobWork() {
Query errorRunQuery = createQuery("from BatchRun run +
where run.run$tatus = :run$tatus");
errorRunQuery.bindLookup("run$tatus",
Run$tatusLookup.constants.ERROR);
return createJobWorkForEntityQuery(errorRunQuery);
}
public lass getThreadWorkerlass() {
return mBatchErrorToDoreationWorker.class;
}
1
2
3
4
260
BatchJob ExampIe - Create Batch Error ToDos
3. By passing the query to the convenience method
createJobWorkForEntity it returns to the framework a JobWork
object which wiII contain an array of ThreadWork objects, each
with ThreadWorkerUnits
4. The getThreadWorkerClass method returns to the framework the
name of the ThreadWorker cIass - this cIass is defined as an
inner cIass (as we'II see on the next sIide)
The BatchJob methods
public JobWork getJobWork() {
Query errorRunQuery = createQuery("from BatchRun run +
where run.run$tatus = :run$tatus");
errorRunQuery.bindLookup("run$tatus",
Run$tatusLookup.constants.ERROR);
return createJobWorkForEntityQuery(errorRunQuery);
}
public lass getThreadWorkerlass() {
return mBatchErrorToDoreationWorker.class;
}
1
2
3
4
261
BatchJob ExampIe - Create Batch Error ToDos
public static class mBatchErrorToDoreationWorker
extends mBatchErrorToDoreationWorker_Gen {
...
The cIass is defined in the same source fiIe as the BatchJob cIass
and is therefore an "inner" cIass
This is the cIass whose name is passed back to the framework in
the getThreadWorkerClass method - as seen on the previous
sIide
It extends its associated _Gen thread worker cIass, which is
created by the artifact generator
The inner ThreadWorker cIass definition
262
BatchJob ExampIe - Create Batch Error ToDos
public ThreadExecution$trategy createExecution$trategy() {
ommit on every todo. This is not expected to be a
performance intensive process.
return new ommitEvery&nit$trategy(this);
}
createExecutionStrategy passes back to the framework an object
of type CommitEveryUnitStrategy which teIIs the framework that
the job wants to commit after each transaction
A "transaction" in this case is after each ToDo has been created
Inner ThreadWorker method createExecutionStrategy
263
BatchJob ExampIe - Create Batch Error ToDos
public void initializeThreadWork(
boolean initializationPreviously$uccessful)
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 = :thisBatchontrolId");
...
initializeThreadWork here determines the ToDo type to be used by
the executeWorkUnit method (next sIide) when it creates the
ToDos
Inner ThreadWorker method initializeThreadWork
264
BatchJob ExampIe - Create Batch Error ToDos
public boolean executeWork&nit(ThreadWork&nit unit)
throws ThreadAbortedException, RunAbortedException {
BatchRun_Id errorBatchRunId = (BatchRun_Id) unit.getPrimaryId();
get the run
BatchRun batchRun = errorBatchRunId.getEntity();
...
createToDo(batchRun);
...
. executeWorkUnit is caIIed for each batch run in error, based on
the initiaI query
2. It gets the primary Id from the ThreadWorkUnit object parameter
and casts it to a BatchRun_Id cIass
3. It uses the Id object to get the BatchRun entity object for which
the ToDo is to be created
4. It creates the ToDo entry
Inner ThreadWorker method executeWorkUnit
1
2
3
4
265
BatchJob ExampIe - Create Batch Error ToDos
Inner ThreadWorker method finalizeThreadWork
This exampIe does not impIement the finalizeThreadWork method
public void finalizeThreadWork()
throws ThreadAbortedException, RunAbortedException {
}
266
BatchJob Creation Review
Before we get to the exercise, Iet's review how to create a
new BatchJob cIass .
1. Create the cIass fiIe and code the annotation
2. Run the Artifact Generator to create the _Gen cIasses (you must
refresh the EcIipse project after the AG has run)
3. Extend the cIass from the _Gen BatchJob cIass
4. Code the getJobWork and getThreadWorkerClass methods
5. Create the inner ThreadWorker cIass - extend it from the _Gen
ThreadWorker cIass
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 controI
267
Exercise 10 - Batch 1
AII Students
Create a batch program to identify Persons without Accounts and dispIay
their detaiIs on the Iog .
Name the program CmPersonsNoAccount in package com.splwg.cm.domain.batch
Identify the persons as foIIows .
In the executeWorkUnit method, the ThreadWorkUnit parameter has a method
getPrimaryId to get the Person_Id object - from this, determine the Person and the
"primary" PersonName
DispIay both the Person Id and the Entity Name on the Iog using the
logger.info(.) method - the output shouId Iook Iike this .
from Person as per where not exists (from AccountPerson ap
where ap.id.person = per)
Person without Account: 4470529669 French,John
Person without Account: 3909447990 Reliable Energy
...
268
Exercise 10 - Batch 1
AII Students (continued)
Add a new batch controI using the onIine Admin menu - use batch code
XXPNOA (where XX are your initiaIs)
Test
Use the Batch - Training Iaunch configuration from EcIipse to run your
job
The foIIowing run parameters shouId be specified:
Batch Code: Your batch code (e.g. XX-PNOA)
Batch Thread Number: 1
Batch Thread Count: 1
User ID: SPL
User Password: spIadmin
Language Code: ENG
Take the defauIts for aII the other parameters (i.e. hit Enter when prompted)
Batch II
270
SPL Batch II - ToDo's
In this section we Iook at how to create "ToDos" in a batch
process
FYI: The previous exampIe (CmBatchErrorToDoCreation)
cIass does that
It runs through aII the batch program errors
(CI_BATCH_RUN rows with status = "error") and creates a
ToDo for each
The ToDo tabIe structure Iooks as foIIows .
271
C_TD_ENTRY
PK TD_ENTRY_ID
FK1 TD_TYPE_CD
C_TD_TYPE
PK TD_TYPE_CD
CRE_BATCH_CD
FK1 MESSAGE_CAT_NBR
FK1 MESSAGE_NBR
FK2 BATCH_CD
C_TD_DRLKEY
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
KEY_VALUE
C_TD_SRTKEY
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
KEY_VALUE
C_TD_MSG_PARM
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
MSG_PARM_VAL
C_TD_SRTKEY_TY
PK,FK1 TD_TYPE_CD
PK SEQ_NUM
DEFAULT_SW
ORDER_FLG
C_TD_DRLKEY_TY
PK,FK1 TD_TYPE_CD
PK SEQ_NUM
FLD_NAME
TBL_NAME
C_MSG
PK MESSAGE_CAT_NBR
PK MESSAGE_NBR
FK1 TD_TYPE_CD
C_BATCH_CTRL
PK BATCH_CD
PROGRAM_NAME
SPL Batch II - ToDo Data ModeI
C
O
N
F
I
G
U
R
E
D
P
R
O
G
R
A
M
M
E
D
1
5
4
2
3
The tabIes on the Ieft are popuIated via the Admin menu
1. ToDo Type identifies the type of ToDo
2. DriII Key Type identifies which page to jump to when the user
seIects a ToDo to "work" on
3. Sort Key Type determines how the ToDo Iist is sorted
272
C_TD_ENTRY
PK TD_ENTRY_ID
FK1 TD_TYPE_CD
C_TD_TYPE
PK TD_TYPE_CD
CRE_BATCH_CD
FK1 MESSAGE_CAT_NBR
FK1 MESSAGE_NBR
FK2 BATCH_CD
C_TD_DRLKEY
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
KEY_VALUE
C_TD_SRTKEY
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
KEY_VALUE
C_TD_MSG_PARM
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
MSG_PARM_VAL
C_TD_SRTKEY_TY
PK,FK1 TD_TYPE_CD
PK SEQ_NUM
DEFAULT_SW
ORDER_FLG
C_TD_DRLKEY_TY
PK,FK1 TD_TYPE_CD
PK SEQ_NUM
FLD_NAME
TBL_NAME
C_MSG
PK MESSAGE_CAT_NBR
PK MESSAGE_NBR
FK1 TD_TYPE_CD
C_BATCH_CTRL
PK BATCH_CD
PROGRAM_NAME
SPL Batch II - ToDo Data ModeI
C
O
N
F
I
G
U
R
E
D
P
R
O
G
R
A
M
M
E
D
1
5
4
2
3
The tabIes on the Ieft are popuIated via the Admin menu
4. Message specifies the message to show in the ToDo Iist
5. Batch ControI contains the batch controI of the job that created the
ToDo
273
C_TD_ENTRY
PK TD_ENTRY_ID
FK1 TD_TYPE_CD
C_TD_TYPE
PK TD_TYPE_CD
CRE_BATCH_CD
FK1 MESSAGE_CAT_NBR
FK1 MESSAGE_NBR
FK2 BATCH_CD
C_TD_DRLKEY
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
KEY_VALUE
C_TD_SRTKEY
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
KEY_VALUE
C_TD_MSG_PARM
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
MSG_PARM_VAL
C_TD_SRTKEY_TY
PK,FK1 TD_TYPE_CD
PK SEQ_NUM
DEFAULT_SW
ORDER_FLG
C_TD_DRLKEY_TY
PK,FK1 TD_TYPE_CD
PK SEQ_NUM
FLD_NAME
TBL_NAME
C_MSG
PK MESSAGE_CAT_NBR
PK MESSAGE_NBR
FK1 TD_TYPE_CD
C_BATCH_CTRL
PK BATCH_CD
PROGRAM_NAME
SPL Batch II - ToDo Data ModeI
C
O
N
F
I
G
U
R
E
D
P
R
O
G
R
A
M
M
E
D
The tabIes on the right are popuIated programmaticaIIy
1. ToDo Entry has one row per ToDo entry and a foreign key to the
ToDo Type
2. DriII Key contains the key vaIue (e.g. person Id) to use for the
navigationaI "driII down" when the user seIects the ToDo to
"work" on
1
4
2
3
274
C_TD_ENTRY
PK TD_ENTRY_ID
FK1 TD_TYPE_CD
C_TD_TYPE
PK TD_TYPE_CD
CRE_BATCH_CD
FK1 MESSAGE_CAT_NBR
FK1 MESSAGE_NBR
FK2 BATCH_CD
C_TD_DRLKEY
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
KEY_VALUE
C_TD_SRTKEY
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
KEY_VALUE
C_TD_MSG_PARM
PK,FK1 TD_ENTRY_ID
PK SEQ_NUM
MSG_PARM_VAL
C_TD_SRTKEY_TY
PK,FK1 TD_TYPE_CD
PK SEQ_NUM
DEFAULT_SW
ORDER_FLG
C_TD_DRLKEY_TY
PK,FK1 TD_TYPE_CD
PK SEQ_NUM
FLD_NAME
TBL_NAME
C_MSG
PK MESSAGE_CAT_NBR
PK MESSAGE_NBR
FK1 TD_TYPE_CD
C_BATCH_CTRL
PK BATCH_CD
PROGRAM_NAME
SPL Batch II - ToDo Data ModeI
C
O
N
F
I
G
U
R
E
D
P
R
O
G
R
A
M
M
E
D
The tabIes on the right are popuIated programmaticaIIy
3. Sort Key contains the vaIue(s) to sort on (e.g. person name)
4. Message Parameter contains the vaIues for message
substitution
1
4
2
3
275
Exercise 11 - Batch 2
AII Students
Modify the previous exercise's cIass to create ToDo entries for Persons
without Accounts .
The ToDo creation methods to popuIate the right-sided tabIes as described on the
previous sIide have too much compIexity for this course, so the instructor wiII
suppIy a tempIate for the ToDo creation methods - you can simpIy copy and paste
those into your cIass
The suppIied methods are .
public void initializeThreadWork
private boolean toDoAlreadyExists
private void createToDo
private void addDrillKeyValue
private void addSortKeyValue
private void addMessageParameter
276
Exercise 11 - Batch 2
AII Students (continued)
In your executeWorkUnit method .
As in the previous exercise, determine the Person_Id and PersonName_Id vaIues
Using the suppIied method, determine if the ToDo aIready exists and, if so, write a
message to the system Iog indicating such and return with a BooIean of true
OptionaIIy, write a message to the system Iog to show the person id and name being
added to the ToDo
Use the suppIied method to create the ToDo entry
FoIIow the instructions over the foIIowing sIides to add the configuration data
for the batch controI, message and ToDo
Important note: Over the foIIowing sIides, aII the exampIes specify
names that contain XX. To avoid overwriting another student's
definitions, substitute XX in aII cases with your own 2-digit initiaIs
277
Exercise 11 - Batch 2
AII Students (continued)
Create new batch controI XX-TDPNA
Create new message "Person %1 has no Accounts (XX)"
278
Exercise 11 - Batch 2
AII Students (continued)
Create new ToDo type XXTDPNA - Main tab
ToDo Type XXTDPNA - RoIes tab
279
Exercise 11 - Batch 2
AII Students (continued)
ToDo Type XXTDPNA - Sort Keys tab
ToDo Type XXTDPNA - DriII Keys tab
280
Exercise 11 - Batch 2
Test
Use the Batch - Training Iaunch configuration from EcIipse to run your job
Verify in the onIine system that it created a ToDo entry for each Person
identified as not having an Account .
It shouId show the message with person name substituted
It shouId be sorted in person name ascending sequence
You shouId be abIe to driII into a person from the ToDo Iist
With this exercise we do not create a JUnit test cIass, but it can be done in
one of two ways .
1. Extending the BatchJobTestCase cIass and impIementing abstract methods
2. CaIIing the submitBatchJob(SubmissionParameters) method in any
ContextTestCase - this aIIows testing a mix of one or more background process
and other business Iogic to be tested
In both cases, the database does not get updated
281
Exercise 11 - Batch 2
delete from ci_td_drlkey
where td_entry_id in (select td_entry_id from ci_td_entry
where td_type_cd = `TDPNA');
delete from ci_td_srtkey
where td_entry_id in (select td_entry_id from ci_td_entry
where td_type_cd = `TDPNA');
delete from ci_td_msg_parm
where td_entry_id in (select td_entry_id from ci_td_entry
where td_type_cd = `TDPNA');
delete from ci_td_entry where td_type_cd = `TDPNA'
Test (continued)
Note: When testing your batch cIass and an error occurs, run the foIIowing
deIete statements before re-executing your batch cIass - these statements
wiII deIete aII previousIy created ToDo entries to prepare for the re-run
End of day 4
283

Das könnte Ihnen auch gefallen