Anda di halaman 1dari 315

SPL Technical Training

565 Java Development

Copyright 2007, Oracle. All rights reserved.


Agenda
1. Introduction to SPL Framework
2. SPL Services
3. Business Entities
4. Artifact Generator
5. The Software Development Kit (SDK)
6. Introduction to Eclipse
7. Change Handlers Part I Validation Rules
8. Unit Testing
9. Change Handlers Part II Conditional Validation
2
Agenda
10. Messages
11. Change Handlers Part III Conditions
12. Change Handlers Part IV Custom Validation
Rule
13. Change Handlers Part V Cascading Changes
14. Algorithms Part I Validation
15. Algorithms Part II Validation & Formatting
16. SPL Batch Part I Simple Batch
17. SPL Batch Part II ToDo Creation
3
Introducing the SPL
Framework

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Logical Web Architecture

HTTP
HTML

JavaScript/
XSLT

Session State

Web Browser

Information is presented in HTML and JavaScript


(no Java applets) through Internet Explorer 6.0
The browser communicates with the Web App
Server via HTTP

5
Logical Web Architecture

HTTP
HTML Presentation Business Data Access
Servlets/XSLT Services Persistent
JavaScript/
Entities
XSLT Caches Data Service
Objects Hibernate
Session State (Java/COBOL)
JDBC

Web Browser Web Application Server

The Web App Server is divided into logical tiers:


Presentation services
Business logic
Data access

6
Logical Web Architecture

HTTP
HTML Presentation Business Data Access
Servlets/XSLT Services Persistent
JavaScript/
Entities
XSLT Caches Data Service
Objects Hibernate
Session State (Java/COBOL)
JDBC

Web Browser Web Application Server

In the Presentation Layer


Java servlets handle the inbound HTTP requests from the browser
Various static data e.g. control tables, language-specific messages
and labels are cached
XSL/T technology is used to create the HTML
The servlets invoke the data service objects in the business layer as
required
7
Logical Web Architecture

HTTP
HTML Presentation Business Data Access
Servlets/XSLT Services Persistent
JavaScript/
Entities
XSLT Caches Data Service
Objects Hibernate
Session State (Java/COBOL)
JDBC

Web Browser Web Application Server

In the Business Layer


Data service objects are invoked from the presentation layer
These services ultimately perform the business functions
The service objects themselves are Java, but the business logic could
be implemented in Java or COBOL, or a combination
The data access objects are used to communicate with the database
8
Logical Web Architecture

HTTP
HTML Presentation Business Data Access
Servlets/XSLT Services Persistent
JavaScript/
Entities
XSLT Caches Data Service
Objects Hibernate
Session State (Java/COBOL)
JDBC

Web Browser Web Application Server

In the Data Access Layer


The Hibernate Object Relational Model (ORM) framework is used for
database access and persistence
The Java Database Connectivity API (JDBC) is used directly (i.e.
Hibernate is bypassed) for SQL statements from COBOL
All database calls are routed through the frameworks data access
layer application programs do not issue direct calls to database
9
Logical Web Architecture

HTTP
HTML Presentation Business Data Access
Oracle
Servlets/XSLT Services Persistent
JavaScript/ DB2
Entities
XSLT Caches Data Service
Objects Hibernate MSSQL
Session State (Java/COBOL)
JDBC

Web Browser Web Application Server Database

Database
Framework supports
Oracle
DB2
Microsoft SQL Server.

10
Logical Batch Architecture

splbatch.sh / cmd
(command line)

Scheduler

Etc.

Submission

Batch Processing
A scheduler or the command-line is used to invoke the splbatch script
(the scheduler can be a 3rd party or SPLs cdxcronbatch scheduler)
splbatch starts a batch instance of the framework
The framework controls all batch execution
Once initialized, splbatch prompts for the batch code of the batch
process to execute
11
Logical Batch Architecture

splbatch.sh / cmd
Batch Control Business Data Access
(command line) Oracle
Standalone Data Service Persistent
Scheduler Executor Objects Entities DB2
(Java/COBOL) MSSQL
Batch Process Hibernate
Etc.
JDBC

Submission Batch Server Database

Batch Processing
The Standalone Executor invokes the Java/COBOL batch process,
based on the supplied batch control code
The business layer components perform the business functions (same
as online)
The data access layer is used to communicate with the database
(same as online)
12
Logical Architecture
The remainder of this class focuses on
Customizing the business layer
Using the data access layer
Creating batch

However
Some tools and concepts need to be introduced
before we can look at this more closely

13
SPL Services

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Services
The SPL system makes heavy use of services
These are the data access and update services
They are implemented in Java at a high level Java or
COBOL at the lower levels
They access Oracle, DB2 or SQL Server
Each service has an XML metainfo document describing
its structure
The framework automates the mapping of string-based
browser data to a services data structure using this
metainfo XML (the XAI class covers this)
The Service Dispatcher routes the Web servlet requests
to the Java or COBOL service
15
Services - Service Dispatcher
The Service Dispatcher acts as conduit to the business
objects from the presentation layer
A service invocation represents a database transaction
It invokes a Java or COBOL service

Service COBOL Svc


Presentation
Dispatcher Wrapper

COBOL App
Java Service
JDBC
Business Objects Data Access

Hibernate JDBC DB

16
Service Dispatching
The Service Dispatcher is invoked from a Web servlet
It invokes the appropriate service for the Web request,
which could be one of the following
1. Page service
2. List service
3. Search service

Service Dispatcher Dispatched Service

1 2 3 Search Service
Page Service List Service

17
Page Services
This is a top level application service
It orchestrates the display and update of all data for a root
object and all its child objects e.g. Person, Person
Name, Person Phone, Person Id, etc.
The data is displayed on a single tab menu across one
or more child tab pages

Page service names end with P e.g. the Person


service is CILCPERP, Account service is CILCACCP, etc.

18
Page Service Dispatching
A Page service invoked in one of seven modes (actions)
Each service class determines if the maintenance service
is implemented in COBOL or Java and uses the
appropriate calling mechanism to invoke it
Page Service

Add Change Copy Default Delete Read Validate

Cobol Page Cobol Svc


Add Service Wrapper

Java Page
Add Service
same for all modes
19
List Services
This defines a list of objects
It could contain nested lists
It is used for list-oriented data e.g. Customer Contacts

List service names end in L e.g. CILCPCCL for


Customer Contact list
They do not support database updates

20
List Service Dispatching
A List service class is invoked in single mode (List)
from the Service Dispatcher
It determines if the underlying list service is implemented
in COBOL or Java and uses the appropriate calling
mechanism to invoke it

List Service

Cobol List Cobol Svc


Service Wrapper

Java List
Service

21
Search Services
These are used to support ad-hoc user searches
The results are similar to list services
The input is set of criteria and a search mode

Search service names end in S e.g.


CILCPERS for Person search
22
Search Service Dispatching
A Search service class is invoked in single mode
(Search) from the Service Dispatcher
It determines if underlying search service implemented in
COBOL or Java and uses the appropriate calling
mechanism to invoke it

Search Service

Cobol Search Cobol Svc


Service Wrapper

Java Search
Service

23
Services in General
A Web servlet invokes the Service Dispatcher for
page, list and search requests
The dispatcher executes the COBOL or Java
service, depending on the implementation
We will now take a separate look at COBOL and
Java implemented services

24
COBOL Services

SPLs COBOL support is for backward


compatibility
It allows us to run COBOL under control of the
Java framework
The COBOL topic here serves as an overview
only
All application extensions algorithms (a.k.a.
plug-ins) and user-exits (Java Change Handlers)
are to be coded in Java
To provide background, following is a high-level
discussion of SPLs implementation of COBOL
services
25
COBOL Services
Portions of the CC&B application is currently still coded
in COBOL
The COBOL is the same as pre-V2, except for
SQL calls are routed through the Java framework ultimately JDBC
Extensions (plug-ins, user exits) can, and SHOULD, be done in Java
Service COBOL Svc
Presentation
Dispatcher Wrapper

COBOL App
Java Service
JDBC
Business Objects Data Access

Hibernate JDBC DB

26
COBOL Services
The Service Dispatcher checks if a Java implementation
for the service exists if not, it assumes a COBOL service
The Service Dispatcher (Java) invokes the COBOL service
wrapper in a separate child Java Virtual Machine (JVM)
The Wrapper calls the COBOL service program (like 1.5)
Service COBOL Svc
Presentation
Dispatcher Wrapper

Child
JVM
COBOL App
Java Service
JDBC
Business Objects Data Access

Hibernate JDBC DB

27
COBOL Services
The COBOL application programs do callbacks to the
framework for data access & Java objects (e.g. Java-
coded algorithms)
This technique enables COBOL to use the frameworks
database connections for data access (in the same logical
unit of work)
Service COBOL Svc
Presentation
Dispatcher Wrapper

Child
JVM
COBOL App
Java Service
JDBC
Business Objects Data Access

Hibernate JDBC DB

28
Inside COBOL Services
Page Maintenance programs orchestrate calls to
the List Maintenance programs
The List & Page programs call the Row
Maintenance programs for DB access
Service COBOL Svc
Dispatcher Wrapper

Page Row
Maintenance Maintenance

List List List List


Maintenance Maintenance Maintenance Maintenance

Row Row Row Row


Maintenance Maintenance Maintenance Maintenance

29
Inside COBOL Services
As example, this shows the Person object maintenance in
COBOL
Well use this example on the following slides
Note the row maintenance program names

Service COBOL Svc


Dispatcher Wrapper

Person Person
Page Row

Name ID Phone Characteristic


List List List List

Name ID Phone Characteristic


Row Row Row Row

30
Inside COBOL Services
See how this maps to the entity relationship for the
Person at the data level
There is one row maintenance program per table
The Entity relationship for the main CCB object (e.g.
Person, Account, etc.) is known as a Maintenance Object
Service COBOL Svc
Dispatcher Wrapper

Person
CI_PER
Page

Name ID Phone Characteristic


List List List List

CI_PER_NAME CI_PER_ID CI_PER_PHONE CI_PER_CHAR

31
Inside COBOL Services User Exits
COBOL user exit points exist in the Row and Page
Maintenance programs and will continue to work on V2
HOWEVER, in the Java world we use Change Handlers
well learn more about this later

Page Person Person Row


User Exit Page Row User Exit

Name ID Phone Characteristic


List List List List

Name ID Phone Characteristic


Row Row Row Row

Row Row Row Row


User Exit User Exit User Exit User Exit

32
COBOL Services Recap
COBOL will continue to be maintained and
supported
Programmers should in future use Java to code
extensions
Lets take a quick look at Java services

33
Java Services
Some services are now coded entirely in Java
These are mostly Admin services for example
AlgorithmType
SA Type
Characteristic Type
etc.

34
Java Services
The Service Dispatcher checks if a Java implementation
for a service exists (if not, it assumes a COBOL service)
The Service Dispatcher invokes the Java service e.g.
Java Page or Search service

Service COBOL Svc


Presentation
Dispatcher Wrapper

COBOL App
Java Service
JDBC
Business Objects Data Access

Hibernate JDBC DB

35
Java Services
The Java service invokes the maintenance, list or search
objects to satisfy the Web servlets request
In general, Java objects communicate with the DB using
HQL (Hibernate) in the data access layer
They can also contain JDBC (SQL) calls
Service COBOL Svc
Presentation
Dispatcher Wrapper

COBOL App
Java Service
JDBC
Business Objects Data Access

Hibernate JDBC DB

36
Java Services
Java services consist of many components:
Framework ones
Generated ones
Application based hand-coded ones

For the remainder of the course we will take a


more in-depth look at the main hand-coded
components and introduce the framework and
generated ones as needed

37
Business Entities

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Inside Business Entities
Business Entities handle database persistence
In general, a Business Entity class exists for each table in
the system
The example here illustrates the Person and Person Name
tables and their related classes
AbstractBusinessEntity

+createDTO()

Person_Gen PersonName_Gen
-id -id
-address1 CI_PER_NAME -entityName
CI_PER
+getId() +getId()
+getAddress() PK,FK1 PER_ID +getEntityName()
PK PER_ID PK SEQ
Person_Impl ADDRESS1 ENTITY_NAME PersonName_Impl

PersonName
Person Interface
Interface
39
Inside Business Entities
A class for an entity has a superclass and a number of
subclasses (in reality, there is more than shown here)
Most of these are framework or generated
Only a small number require human coding (e.g. the
starred ones ( ) below)
AbstractBusinessEntity

+createDTO()

Person_Gen PersonName_Gen
-id -id
-address1 CI_PER_NAME -entityName
CI_PER
+getId() +getId()
+getAddress() PK,FK1 PER_ID +getEntityName()
PK PER_ID PK SEQ
Person_Impl ADDRESS1 ENTITY_NAME PersonName_Impl

PersonName
Person Interface
Interface

40
Business Entity and Related Classes
Business Entity related classes are divided into 3
categories:
1. Framework
2. Generated
3. Hand-coded
AbstractDataTransferObject StringId AbstractBusinessEntity interface AbstractEntityList
SimpleEntityList
+createDTO()

Person_Id Person_Gen
Person_DTO
-id PersonNames_Impl
-address1 interface
PersonNames
+getId()
+getAddress() +add()
+remove()
interface
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()
41
Business Entity and Related Classes
The goal of the framework was to keep hand-coded logic
to a minimum
When creating a new Business Entity, only the Impl
class is hand coded; others are framework or generated
by the Artifact Generator more about this later
AbstractDataTransferObject StringId AbstractBusinessEntity interface AbstractEntityList
SimpleEntityList
+createDTO()

Person_Id Person_Gen
Person_DTO
-id PersonNames_Impl
-address1 interface
PersonNames
+getId()
+getAddress() +add()
+remove()
interface
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()
42
Business Entity and Related Classes
Lets look at how the classes below are used
Business Entities
Data Transfer Objects (DTOs)
String Ids
Entity Lists
AbstractDataTransferObject StringId AbstractBusinessEntity interface AbstractEntityList
SimpleEntityList
+createDTO()

Person_Id Person_Gen
Person_DTO
-id PersonNames_Impl
-address1 interface
PersonNames
+getId()
+getAddress() +add()
+remove()
interface
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()
43
Business Entities
Business Entities handle database persistence i.e. they
are responsible for the retrieval and storage of data
The Java programs typically do not call the database
directly; they use the Business Entities where possible
For example, to fetch a Person from the database
Person_Id perId = new Person_Id("1185477091");
Person perEntity = perId.getEntity();
AbstractBusinessEntity

Person_Gen
-id
-address1
+getId()
+getAddress()

interface
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()

44
Business Entities
To fetch multiple persons from the database
Query query = SessionHolder.getSession().createQuery("from Person");
Person perEntity = null;
QueryIterator qIter = query.iterate();
while (qIter.hasNext()) {
perEntity = (Person)qIter.next();
...
}

AbstractBusinessEntity

This is an early introduction to SPLs


Java Persistence Framework (JPF) &
Person_Gen
Hibernate. JPF & Hibernate are -id
-address1
discussed in detail later, but we will +getId()
+getAddress()
see more references to them over the interface
Person
following slides +getId()
+getAddress1()
Person_Impl

+getInfo() +getInfo()
+getDTO()()
+setDTO()()

45
Business Entities
The framework creates instances of Business Entities
when fetching data for example
Person perEntity = perId.getEntity();
or
Person perEntity = (Person)qIter.next();

will create a new instance of Person


Therefore: An instance (object) of a Business Entity
class represents a row in a database table

Person : Person_Impl
id = 1550000001 PER_ID ADDRESS1
address1 = Easy Street 1550000001 Easy Street
Person : Person_Impl 7804500002 Penny Lane
id = 7804500002
address1 = Penny Lane

46
Business Entities
Creating a new instance of a Business Entity creates a
new database row (when the transaction commits)
Likewise, when changing or deleting an instance, the
database row is updated or deleted (when the transaction
commits)
The database commit happens at the frameworks
discretion the application code has no direct control
over it

Person : Person_Impl
id = 1550000001 PER_ID ADDRESS1
address1 = Easy Street 1550000001 Easy Street
Person : Person_Impl 7804500002 Penny Lane
id = 7804500002
address1 = Penny Lane

47
Business Entities
A Business Entity has getters (get methods) for
retrieval of its properties
Example
Person perEntity = (Person)query.firstRow();
String emailAddress = perEntity.getEmailAddress();
Will retrieve a persons email address
Most getters are specific to an object (e.g. emailAddress
on Person), but there are common ones
AbstractBusinessEntity
getId() retrieves identifier (Account Id,
Person Id, Premise Id, etc.) depending on the object
Person_Gen
getDTO() retrieves an instance of a Data Transfer -id
-address1
+getId()
Object (DTO) for the Business Entity +getAddress()

interface
Person
Person_Impl
More about Ids and DTOs in a +getId()
+getAddress1()
minute +getInfo()
+getDTO()()
+getInfo()

+setDTO()()

48
Business Entities
A Business Entity does not have setters for its
properties
Properties can only be updated via a DTO
A Business Entity has a setDTO() method to
register a modified DTO and thus update the
database
AbstractBusinessEntity

Person_Gen
More about Ids and DTOs in a minute -id
-address1
+getId()
+getAddress()

interface
Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()

49
Data Transfer Objects
Data Transfers Objects (DTOs) are transient (temporary /
non-persistent) holders of Business Entity properties
They are acquired via the Business Entity getDTO()
method, for example
Person perEntity = (Person)query.firstRow();
Person_DTO perDTO = perEntity.getDTO();

Use the DTO getters and setters (get/set methods) to


retrieve or update properties, for example:
String emailAddress = perDTO.getEmailAddress();
...
perDTO.setEmailAddress(emailAddress); AbstractDataTransferObject

Person_DTO

50
Data Transfer Objects
Updating a DTO property (via setter method) does not
update the entity (database object) automatically
A Business Entity has the setDTO method to update a
modified DTO, for example
Person perEntity = (Person)query.firstRow();
Person_DTO perDTO = perEntity.getDTO();
perDTO.setEmailAddress(testemail@splwg.com);
perEntity.setDTO(perDTO);

This effectively updates the database, but the database


update & commit happen at the discretion of the framework
AbstractDataTransferObject

Person_DTO

51
String Ids
Simple string keys (e.g. Person Id) are defined as objects
in the framework
An ID is retrieved from a DTO or Business Entity, e.g.
Person_Id perId = perDTO.getId();
or
Person_Id perId = perEntity.getId();

Use the getIdValue() method to get the value of the Id


String perIdString = perId.getIdValue();
StringId

Person_Id

52
String Ids
An Id object can also be used to retrieve a
Business Entity, for example
Person_Id perId = new Person_Id("6785704944");
Person perEntity = perId.getEntity();
Person_DTO perDTO = perEntity.getDTO();
...

StringId

Person_Id

53
Entity Lists

Entity lists reference collections 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();

Elements in an entity list can be:


Sequentially retrieved
Removed interface AbstractEntityList
SimpleEntityList
Added

PersonNames_Impl
interface
PersonNames
+add()
+remove()

54
Entity Lists
For example, to retrieve all person names for a person:
Person_Id perId = new Person_Id("1185477091");
Person perEntity = perId.getEntity();
PersonNames perNames = perEntity.getNames();
Iterator iterator = perNames.iterator();
while (iterator.hasNext()) {
PersonName perName = (PersonName)iterator.next();
String entityName = perName.getEntityName();
...
}

interface AbstractEntityList
SimpleEntityList

PersonNames_Impl
interface
PersonNames
+add()
+remove()

55
Artifact Generator

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Artifact Generator
The Artifact Generator is an SPL tool to generate the
supporting classes for an SPL object
For example, in this implementation of Person object,
Person_Gen class and Person interface are generated by
the Artifact Generator
The generation is based on Class Annotations in the hand
coded class Person_Impl in this example
The Artifact Generator is executed from AbstractBusinessEntity

the Eclipse development environment


Person_Gen

upcoming exercises will illustrate this -id


-address1
+getId()

Well discuss annotations next interface


+getAddress()

Person
+getId() Person_Impl
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()

57
Class Annotations
Meta-data is used to describe the Java objects to the
Artifact Generator - the Meta-data therefore lives in the
Java code (although some is still in the database)
We use annotations to define the metadata for a class
Annotations are stored in Java-doc comments before the
class definition (enclosed in /** and */)
We use structured annotations:
Demarked by @ followed by annotation name (e.g. @BusinessEntity)
Contain comma-separated property-value pairs (i.e. property=value)
Value can be string, Boolean, array or another annotation

58
Class Annotations
Heres an example
1 /**
2 @SampleAnnotation (
simpleString = value,
complexString = "A string with spaces",
3 boolean = true,
arrayOfStrings = {abc, def, "g h i" },
fkAnnotation = @NestedAnnotation ( property = value ),
4 arrayOfAnnotations = { @ChildAnnotation (name=first),
@ChildAnnotation (name=second)}
)
1 */
public class ExampleClass {
....
}
1. Java-doc comments
2. Annotation name
3. Property-value pairs strings and Booleans
4. Array of annotations
59
Class Annotations
Different annotations exist for different
components, for example:
@BusinessEntity defines how to create artifacts for
persistent objects (the Artifact Generator creates
Hibernate mapping files and objects based on this)
@ChangeHandler declares a change handlers class and
binds it to the persistent entity which is to be monitored for
events
@AlgorithmComponent binds the algorithm class to the
business entity and declares the soft parameters

Refer to the SDK documentation for all the


annotations and their parameters
60
What next?
We will begin coding some Java classes shortly,
but before we get to that, we need to look at the
SDK and the Eclipse development environment

61
The Software Development
Kit (SDK)

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


SDK Overview
The SDK provides the scripts and other components to
develop for the framework
The SDK also describes the methodology to follow for
onsite development
It uses the Eclipse development platform for all Java
coding and testing and supplies an Eclipse project to help
get you started
We do not bundle Eclipse with the SDK you have to
download and install it separately
Refer to the installation document and www.eclipse.org
for more information
Lets take a look at the SDK in more detail

63
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code

Sy
st
em
D
at
a

Project
Dev DB

As can be seen here, a development workstation and the project


repository both reference the same database server
For a project, only one project repository will exist
Each developer will have their own development workstation
configured for development
64
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code

Sy
st
em
D
at
a

Project
Dev DB

The project repository


1. Is initially installed and configured as a self-standing development
environment
2. Is then used as the source from which to install development
workstations
65
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code

Sy
st
em
D
at
a

Project
Dev DB

The project repository


3. Is the central storage for all completed unit-tested code
4. Provides the environment from which to build the latest state of the
project all developers continually synchronize their workstations to
this using something like Perforce
66
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code

Sy
st
em
D
at
a

Project
Dev DB

The project repository


5. Is the central source for CM packaging

67
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code

Sy
st
em
D
at
a

Project
Dev DB

A development workstation
1. Is created as an image of the project repository initially
2. Is where a developer codes and tests customizations for a project
unit-tested code is submitted back to the project repository
68
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code

Sy
st
em
D
at
a

Project
Dev DB

The project development database


1. Is accessed by both the development workstations and project
repository to ensure consistent results, especially for the artifact
generators metadata references

69
Our Development Methodology
Development Project
Workstation Repository
Sync / Submit Code

Sy
st
em
D
at
a

Project
Dev DB

The project development database


2. Is a standard database of the product could be initially installed as
a demo database

70
Development Workstation Setup
The development workstation and the project repository
are setup with the same software, 3rd party development
tools and contain the same components required for
development
Basically, a development workstation consists of the
following
A full web/application server installation of the SPL product being
customized besides the database, a development workstation is a
standalone system of the product
The SDK client containing COBOL development tools (to be phased
out over time)
The Net Express IDE for COBOL development
The Eclipse SDK for Java development

This training focuses on Java development COBOL


development is not discussed in detail

71
Development Workstation Folders
A development workstation will contain the following
folders under the SPL environment folder (the
<SPLEBASE> folder, e.g. C:\spl\CCBDEMO)

72
Development Workstation Folders
Most of these folders are base application server folders
The java and SPLSDKCommon folders are created
during the SDK installation

73
Development Workstation Folders
The Java folder contains the following sub-folders

source contains the Java source code the source is created and
edited using Eclipse
sourcegen is where the artifact generator places the generated Java
classes
target is where the Java compiler places the compiled Java classes
(the .class files)

These folders are all updated from Eclipse you should


not have to manually update them from Windows

74
Development Workstation Folders
The SPLSDKCommon folder contains the following sub-
folders

eclipseLaunchScripts contains the Eclipse run configurations for


various things by default it is setup to launch artifact generator, but
other run configurations can be added over time
eclipseProject contains the Eclipse project definition for the
development workstations customizations by convention, the
Eclipse project is named the same as the environment to which it
applies (e.g. CCBDEMO), but it could be any name (as you will see
shortly with the training project)
tools is used for installation purposes only it contains our Eclipse
plug-ins for the artifact generator and source editing

75
Development Workstation Folders
There is also the <SPLSDKROOT> folder, which by default
is called SPLSDK it has the following structure

It has a sub-folder for the application server environment (CCBDEMO


in this example) the name depends on the name of the environment
eclipseWorkspace is used internally by Eclipse for us, the most
important thing about this folder: it contains the Eclipse log file which lists
the internal Eclipse errors

76
Development Workstation Folders
There is also the <SPLSDKROOT> folder, which by default
is called SPLSDK it has the following structure

The SDK sub-folder contains the following SDK components


The help documentation
The Application Workbench (AWB)
Various scripts, including to compile COBOL programs
Eclipse this is downloaded separately from www.eclipse.org and
unzipped to this folder
77
Development Workstation Folders
Under the SPL environment folder, the application server
is located in the splapp sub-folder
This folder has a deep hierarchy of sub-folders, but the
ones we are most interested in for development are
1. applications\root\WEB-INF\lib
2. standalone\lib

Lets take a look at these two folders in more detail

78
Development Workstation Folders
applications\root\WEB-INF\lib

This folder contains all the jar files for the online application server
Included here are the framework jars
spl-base-2.0.10.jar
spl-shared-2.0.10.jar
and the product jars, for example for CC&B
spl-ccb-2.0.5.jar
and many others
79
Development Workstation Folders
applications\root\WEB-INF\lib

This folder will also house your cm.jar file, which contains all your
customization class files (programs)
We will see in the next topic how to create this jar file from Eclipse

80
Development Workstation Folders
standalone\lib

This standalone folder contains all the jar files for the batch server
and remote COBOL JVMs
It contains mostly the same jar files as the online app server folder,
including the framework and product ones mentioned earlier
You need to also place your cm.jar file in this folder to run your Java
batch programs

81
Development Workstation for Training
Everything weve seen up to now applies to a
standard SDK environment
For this training, the following differences exist
There is no project repository each training workstation
is a developers workstation
There are some additional folders created to avoid
overwriting the standard SDK ones

Lets take a look at the additional training folders


82
The Additional Training Folders
Under the SPL environment folder, javaTraining exists as
a substitute for the standard java folder

As with the java folder, it contains the source, sourcegen and target
folders for the Java source, artifact-generated and Java class files
respectively
In addition, it has a test folder for Java source related to unit testing
we will see later when we get to the unit testing (JUnit) topic what
goes into this folder
It also has a config folder with a training-specific spl.properties file

83
The Additional Training Folders
Under the SPLSDKCommon folder, eclipseTrainingProject
exists as a substitute for the standard eclipseProject
folder

This folder allows us to have a separate Training project


in Eclipse

84
Starting the SDK
The SDK installation creates a Program Group on
the Windows Start menu

From this group


The Application Workbench (AWB) can be launched
The client scripts to do various things can be invoked the
one we are most interested in here is the one to start the
Eclipse SDK, startEclipse
The SDK help documentation can be accessed

85
SDK Folders Walkthrough
Open Windows Explorer and navigate to your
SPL folder
Make a note of the name of your application
environment folder (e.g. C:\spl\CCBDEMO) you
will need this name when configuring the Eclipse
environment
Confirm that the javaTraining and
SPLSDKCommon\eclipseTrainingProject folders
exist
Also verify that the <SPLSDKROOT> folder (e.g.
C:\SPLSDK) exists although we wont
necessarily need to reference this folder

86
What next?
Next we will walk through the Eclipse SDK to
configure it for the training and become familiar
with some of its basic features

87
Introduction to Eclipse

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


The Eclipse SDK
Definition:
The Eclipse Platform is designed for building integrated development
environments (IDEs), and arbitrary tools.
(www.eclipse.org)
In fact, it can also be used as an application platform, but we only use
it for Java development

Java Development Tooling (JDT) is a Java IDE for the


Eclipse platform which includes the following features
Java projects Compare
Editing Compile
Code formatting Run
Refactoring Debug
Search
89
The Eclipse SDK Walkthrough
Over the following slides, the instructor will walk
you through the steps to setup your Training
project for the upcoming exercises
Use the Eclipse for Training shortcut on your SPL
Java Training program group to start the Eclipse
SDK

This will take quite a few seconds to load

90
The Eclipse SDK Walkthrough
Close the Welcome tab if its shown

Go to Window -> Preferences and in the filter


text box (top-left corner), type linked res

Click on the Linked Resources node


91
Eclipse Walkthrough Linked Resources
Check Enable linked
resources and click
the New button
You are now going to
define a path variable
that is used in your
project definition
Name must be
asBase (case-
sensitive)
Location must be your
SPL environment
folder e.g.
C:\spl\CCBDEMO
Click OK
92
Eclipse Walkthrough Linked Resources

Click OK to save the asBase path variable


Next we will import the Training project

93
Eclipse Walkthrough Import Training
Go to menu File ->
Import
Select Existing
Projects into
Workspace
Click Next

94
Eclipse Walkthrough Import Training
Enter the
SPLSDKCommon
folder name under
your SPL
environment folder
in the root
directory text box
Make sure that
only the Training
project is selected
Make sure that the
Copy projects into
workspace box is
unchecked!
Click Finish
95
Eclipse Walkthrough Training Project

Once the project has been fully imported, you should see
the Training project defined in your Package Explorer
view
You will recognize the folders from the ones discussed
under the SDK section these folders are linked to the
appropriate folders in your SPL environment folder
right-click and view the folder properties to find its actual
location on the file system
96
Eclipse Walkthrough Training Project

About the folders


projectconfig contains the spl.properties file specific to this project
config contains the hibernate and log properties files
gen is where the artifact generator will place its files
java is where you will add your customized hand-coded source
test is where you will create your test classes
97
Eclipse Walkthrough Training Project

The java folder contains package com.splwg.cm.domain


under this, the packages will be divided into the various
sub-packages for the sub-systems, batch, etc.
The templates package is provided for this training it
has some sample code to get you started
The CustomMessages class is for the global custom
message definitions you will be adding (we will learn
more about that later)
98
Eclipse Walkthrough Training Project

The project also contains a few default launch


configurations used during training these launch
configurations are executed from the Run and/or
Debug toolbar buttons (more about that next )
The Deploy.jardesc file is used to generate the cm.jar file
when testing your exercise from the online to generate
the jar, right-click on Deploy.jardesc and select Create
JAR

99
Eclipse Walkthrough Compile / Refresh
To compile your source, simply save it it will be
compiled and checked automatically
To rebuild the project, which must be done after artifact
generation, refresh it by selecting the project in the
Package Explorer view and hitting the F5 key
The refresh will also synchronize the project with the file
system, which would be necessary if you have applied
updates outside of Eclipse e.g. after synchronization
with the Project Repository
A refresh will recompile only those files that have
changed sometimes it may be necessary to do a full
rebuild of the project use the Project -> Clean menu
item to do that

100
Eclipse Walkthrough Miscellaneous

On the toolbar we will be using two icons frequently


The Debug button runs a Java class in debug mode it is also
used to debug Tomcat for online debugging
The Run button runs a Java class normally it is used to run
the Artifact Generator, JUnit tests and batch
Click on the small arrow next to the run button you
should see the following drop-down menu
You select from this menu which
Java task to submit the two
shown here have been loaded for
the training

101
Eclipse Walkthrough Miscellaneous

The Source menu has some useful features


It can generate method stubs for the methods that you
want to override when you extend or implement another
class
It can generate try/catch blocks
It can generate getter and setter methods
It can comment and uncomment blocks of code

102
Eclipse Walkthrough Miscellaneous

The project will be compiled when a class is


modified and saved
However, when generating files, the project must be
manually rebuilt use the F5 key to refresh and rebuild

Remember these few points for the Eclipse


exercises coming up, but also feel free to
explore all features!

103
What next?
Now that we have some knowledge of the folder
structures and tools, we are ready to try a few
customizations

104
Customizations

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Customizations Overview
Customizations refers to system (not base program)
modifications for specific customer behavior
The SPL base code framework or application is never
modified for customization purposes
The system can be customized using the following
methods:
1. Change Handlers (analogous to user exits)
2. Algorithms (a.k.a plug-ins)
3. Batch programs
4. New Maintenance Objects (new transactions)
(XAI may be included in this list, but falls outside of scope)
This training covers numbers 1, 2 and 3 and we will look
at them in that sequence for the remainder of the class

106
Change Handlers
Part I

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Change Handlers I
The framework implements custom extensions (user
exits) as Change Handlers
They extend baseline behavior
One or more Change Handlers may exist for a Business
Entity the framework will call all of them
The Business Entity is specified in the annotations it
tells the framework which entity to attach the Change
Handler to at runtime
A Change Handler extends the AbstractChangeHandler
framework class
A Change Handler class name MUST end in _CHandler
for the artifact generator to recognize it as such

108
Change Handlers I Example 1
/**
* @ChangeHandler (entityName = characteristicType)
*/
public class CmCharacteristicType_CHandler
extends AbstractChangeHandler {
...
}

In this example
The annotation specifies a Change Handler for Business
Entity Characteristic Type
It extends AbstractChangeHandler
The class name ends in _CHandler

109
Change Handlers I
Change Handlers add event-driven logic to
entities (similar to COBOL row user exits)
They can perform 2 things:
1. Validate data changes
2. Cause cascading changes

Well take a look at validation first


The topic of cascading changes requires
knowledge of Hibernate persistence and HQL
will leave that for later

110
Change Handlers I Validation Rules
The framework uses Validation Rules to determine how
to validate a Business Entity at runtime
The Validation Rules for a Business Entity are declared
in a Change Handler
The declarative style means the programmer specifies
WHAT to validate, not HOW or WHEN
A number of standard rules exist that require minimal
programming, but custom rules can be coded if needed
Custom rules require programming these contain the
step-by-step logic of HOW to validate
Validation rules are side-effect free, which means
They cannot change the persistent state of the system (cant update)
It insures all validations are performed on a complete set of changes

111
Change Handlers I Validation Rules
The following standard rules exist
AllowAndRequireRule both allows and requires a property to be
populated
AllowRule allows a value to be populated
CustomRule creates a rule out of a Custom Validation class (to
implement logic not handled by any of the above)
NotAllowRule one or more properties are not allowed
PlaceHolderRule this is a place holder when a Change Handler is
developed they are replaced with the actual rules during
development
ProtectRule prevents a property from being changed
RequireRule requires a property to be populated
RestrictRule restricts a property to a set of values
Refer to the SDK documentation for more details on
these rules
112
Change Handlers I Validation Rules
The framework invokes the getValidationRules
method on a Change Handler for all the
validation rules for a Business Entity
The getValidationRules method must return an
array of validation rule objects
To use a standard rule, simply use the static
factory method on the rule itself for example
RequireRule.alwaysRequire() returns an instance of the
RequireRule class that insures an entity property has a
value
RestrictRule.validatedMustEqualReference() returns an
instance of the RestrictRule class that checks if a
property is equal to a specific value/reference
113
Change Handlers I Validation Rules
A Validation Rule requires a Property on the
Business Entity (i.e. the field) to validate
A property is a reference to an entity field
Properties exist as constants on the business
interfaces for example
Person.properties.emailAddress refers to email address
field on Person Business Entity
Account.properties.setUpDate is the setup date field on
the Account entity
Properties are passed to the Validation Rules as
parameters to tell a rule which property to
validate
114
Change Handlers I Validation Rules
Example make Email Address field on Person required
public static ValidationRule emailRequiredRule() {
return RequireRule.alwaysRequire("Person:Email is required",
"The person's email address must be specified",
Person.properties.emailAddress);
}

public ValidationRule[] getValidationRules() {


return new ValidationRule[] {emailRequiredRule()};
}

Here we see
Static method emailRequiredRule to instantiate a
RequiredRule object using factory method alwaysRequire
Person.properties.email to tell the rule to validate the
Email Address property (i.e. field) on Person
Public method getValidationRules to provide a list of the
rules to the framework (only one in this case)
115
Exercise 1 Change Handler Validation 1
All Students
Create a Person change handler in the java folder of your project
Place it in package com.splwg.cm.domain.customerinfo.person
Name it CmPerson_CHandler
Add validation rule address1RequiredRule to make address line 1 required

Optional
Note: this exercise is very similar to the above, but will lead to a more challenging
exercise 3

Create a Premise change handler


Place it in package com.splwg.cm.domain.customerinfo.premise
Name it CmPremise_CHandler
Add a validation rule to make city required

Test
Use the online system to test your change handler
116
Unit Testing

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Unit Testing More About Validation
Before we delve into the topic of Testing, it helps to
understand how validation is triggered by the framework
To reiterate, validation rules are declarative; declared
in a change handler, but invoked at the discretion of the
framework
By default, validation rules fire when a Business Entity
is updated, deleted, created, etc.
For example, using setDTO to update an entity will
trigger the validation for it, as seen here
Person_DTO perDTO = perEntity.getDTO();
perDTO.setEmailAddress(somebody@someplace.com);
perEntity.setDTO(perDTO);

This is called eager validation because it fires


immediately

118
Unit Testing More About Validation
The triggering of validation can be controlled
programmatically if needed
It may be necessary where multiple entities require
validation as a coherent set of changes
To illustrate this, consider the example of validating a
new Person and Person Name, but only once the entities
have been created i.e. to defer validation until both
entities are created
To defer validation until later, use framework method
startChanges() before the update and saveChanges()
after the update
NOTE: saveChanges() does not issue commit to database!
Lets take a look at the code for this example

119
Unit Testing Example: Defer Validation
1 startChanges();
Person_DTO perDTO = (Person_DTO)this.createDTO(Person.class);
Person_Id perId = new Person_Id(1234567890);
2 perDTO.setId(perId);
Person person = perDTO.newEntity();
PersonName_DTO perNameDTO =
(PersonName_DTO) createDTO(PersonName.class);
PersonName_Id perNameId = new PersonName_Id(person,
BigInteger.ONE);
3 perNameDTO.setId(perNameId);
perNameDTO.setEntityName(Blog,Joe");
perNameDTO.setNameType(NameTypeLookup.constants.PRIMARY);
PersonName perName = perNameDTO.newEntity();
4 person.getNames().add(perName);
5 saveChanges();

1. Invokes startChanges to tell the framework to suspend validation


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 allow for validation on the coherent set of changes

120
Unit Testing Back to Testing: JUnit
To ensure quality code, an automated unit testing
procedure is required
The reasons for automated testing are
One small change can unexpectedly break other parts of the system
automated tests provide early notification of these bugs
Studies show that to fix bugs costs more the longer they are
undiscovered automated tests prevent this
Automated tests are useful (albeit technical) forms of functional
documentation they describe to the programmers the expected
inputs/outputs

We use JUnit at SPL for automated testing


The Eclipse IDE is integrated with JUnit, making it easy
to create and run tests

121
Unit Testing - JUnit
The framework contains many abstract tester
classes, one for each type of test for example
AbstractEntityTestCase tests a Business Entity and its
related Change Handlers. It also ensures all the
Validation Rules in the Change Handler have fired
AlgorithmImplementationTestCase tests an algorithm
function

When coding your own test class, you must


extend the appropriate abstract tester class
Lets see how a test is created

122
Unit Testing - JUnit
First step is to create a JUnit test class
public class CmPerson_CHandler_Test extends AbstractEntityTestCase {

protected Class getChangeHandlerClass() {


return CmPerson_CHandler.class;
}
}

This class is to test CmPerson_CHandler validation rules


1. The class name ends in _Test
2. It extends AbstractEntityTestCase to test a Business
Entity/Change Handler
3. The getChangeHandlerClass method returns the class definition of
the Change Handler being tested the framework invokes this
method to get the name of the class to test

123
Unit Testing - JUnit
Now we add a method for each test case
public void testEmailRequiredRule() {

Note Our change handler only has one rule Email


Required so we only have one test case method
Remember:
1. The method name must start with test the framework will execute
all classes that start with test
2. ALL the rules must be violated in the test - if a validation rule exists in
the change handler but is not violated in the test class, the framework
will fail the test
3. The objective is to have all test cases complete successfully (no
failures)

124
Unit Testing - JUnit
Lets add some code to test our email required rule
public void testEmailRequiredRule() {
Person_Id perId = new Person_Id("5775933103");
1 Person person = perId.getEntity();
2 Person_DTO goodDTO = person.getDTO();
3 goodDTO.setEmailAddress("somebody@someplace.com");
4 person.setDTO(goodDTO);
}

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 email address on the DTO to a non-space value
4. Modifies the DTO on Person, which triggers validation
This tests for a positive outcome (which is necessary), but
we MUST also violate the condition to properly test the
validation rule
125
Unit Testing - JUnit
So lets add some more code
public void testEmailRequiredRule() {
...
try {
Person_DTO badDTO = person.getDTO();
1 badDTO.setEmailAddress(null);
2 person.setDTO(badDTO);
3 fail("a validation error should have been thrown");
} catch (ApplicationException exception) {
// Make sure the correct rule was violated.
4 verifyViolatedRule(CmPerson_CHandler.emailRequiredRule(),
exception);
}
}

What this code does is


1. Instantiates a bad DTO and clears the email address to violate the rule
2. Updates the Persons DTO to trigger validation

126
Unit Testing - JUnit
So lets add some more code
public void testEmailRequiredRule() {
...
try {
Person_DTO badDTO = person.getDTO();
1 badDTO.setEmailAddress(null);
2 person.setDTO(badDTO);
3 fail("a validation error should have been thrown");
} catch (ApplicationException exception) {
// Make sure the correct rule was violated.
4 verifyViolatedRule(CmPerson_CHandler.emailRequiredRule(),
exception);
}
}

What this code does is


3. Invokes JUnit fail method if setDTO does NOT cause expected rule violation
4. Exception catch (what we expect), verifies that our rule not some other one
- caused the exception

127
Unit Testing - JUnit
Heres the complete test method
public void testEmailRequiredRule() {
Person_Id perId = new Person_Id("1648461517");
Person person = perId.getEntity();
Person_DTO goodDTO = person.getDTO();
goodDTO.setPersonOrBusiness(
PersonOrBusinessLookup.constants.PERSON);
goodDTO.setEmailAddress("somebody@someplace.com");
person.setDTO(goodDTO);
try {
Person_DTO badDTO = person.getDTO();
badDTO.setEmailAddress(null);
person.setDTO(badDTO);
fail("a validation error should have been thrown");
} catch (ApplicationException exception) {
// Make sure the correct rule was violated.
verifyViolatedRule(CmPerson_CHandler.emailRequiredRule(),
exception);
}
}

With this method, the JUnit test should run with no errors or failures an error
or failure would mean a problem in the test class or application code
128
Exercise 2 JUnit Test 1
All Students
Create a JUnit test class for your Person validation rule from
exercise 1 in the test folder of your project
Place it in package com.splwg.cm.domain.customerinfo.person
Name your class CmPerson_CHandler_Test
Add a method to test your validation rule

Optional
Create a JUnit test class for your Premise validation rule from
exercise 1

Test
From Eclipse, right-click on your test class and select Run As ->
JUnit Test

129
Change Handlers
Part II

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Change Handlers II Conditional Validation
In the last exercise we used the alwaysRequire method
to UNCONDITIONALLY require a value
Rules would not be very useful if only unconditional
validation was allowed
Validation is usually based on some condition, for
example
1. Prevent a dependent property from being changed if the primary
property matches a certain value e.g. FT freeze date/time cannot
be changed when the status is frozen (ProtectRule)
2. The life support description on Person is required if the life support
flag is set (RequiredRule)
Rules have various constructs (and factory methods) to
handle this, for example
RequireRule.ifReferenceEqualsValue() requires a property if another
property equals a certain value
131
Change Handlers II Conditional Validation
Example email address required if life support flag is set
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
1 return RequireRule.ifReferenceEqualsValue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
2 Person.properties.emailAddress,
3 Person.properties.lifeSupportSensitiveLoad,
4 LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
5 com.splwg.base.domain.StandardMessages.fieldMissing());
}

Here we introduce a few new things


1. Using the ifReferenceEqualsValue factory method on RequireRule
2. The property that is required (primary property) - emailAddress
3. The property to compare for a value (dependent property) -
lifeSupportSensitiveLoad

132
Change Handlers II Conditional Validation
Example email address required if life support flag is set
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
1 return RequireRule.ifReferenceEqualsValue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
2 Person.properties.emailAddress,
3 Person.properties.lifeSupportSensitiveLoad,
4 LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
5 com.splwg.base.domain.StandardMessages.fieldMissing());
}

Here we introduce a few new things


4. The value to compare the dependent property (no. 3) to
LIFE_SUPPORT_SENSITIVE_LOAD is the lookup value for constant
Y (all valid lookup values are generated onto lookup classes)
5. The message to display when the condition is true -
com.splwg.base.domain.StandardMessages.fieldMissing
Note: Here we use a standard message we will create a custom
message later
133
Exercise 3 Change Handler Validation 2
All Students
Modify your Person change handler from exercise 1
Change the validation rule to make address line 1 required only if the
person type is Business
Rename the validation rule to indicate that its conditional e.g.
address1RequiredIfBusinessRule

Optional
Modify your Premise change handler from exercise 1
Change the validation rule to make city required only if the county is not
equal to constant value San Francisco
Rename the validation rule to indicate that its conditional e.g.
cityRequiredIfCountyNotSFRule

Test
Update your JUnit test class from exercise 2 to test the conditional
validation

134
Base Messages

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Message Categories
ALL application messages are stored in the
frameworks 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 list here shows the
standard message
categories
136
Message Categories Message Text
Within each category, the message text is numbered

This example shows messages for Standard category


11001
Note message number 101 ( %1 field missing); we used
it in the previous exercise
%1 is a substitution variable to be supplied when the
Java class displays the message (field name in this case)
A message may contain up to 9 substitution variables
137
Message Categories Substitution Variables

Message text may contain substitution variables


Variables are denoted by % followed by a number from 1
to 9 e.g. %1, %2, etc.
For example, the message text
%1 field missing

will be displayed as
Bill Cycle field missing
%1

The application code must pass the values for the


substitution variables when the message is displayed
addError(StandardMessages.FieldMissing(fieldName))

138
Base Messages Modifying
Base message text may not be modified (it is
prevented by the system) - changes would be
overwritten at the next upgrade anyway
However, you can ADD customized message text
for a base message on the Details tab

139
Base Messages Modifying
The Customer Specific Message Text must use
the same substitution variables as the base one
The framework will ALWAYS display the customer
specific message if present it is not possible to
conditionally display the base Message Text if
custom text for it exists

140
Base Messages Java Definitions
Each category has its own class to define message variables and
methods

For example, the StandardMessages class contains


1. The category number definition for the standard messages
2. All the standard message numbers
141
Base Messages Runtime Definition
A message class also contains methods

The application code calls these methods to display messages at


runtime for example

addError(StandardMessages.fieldMissing("EMAILID"));

142
Base Messages Runtime Definition

As can be seen here, runtime message methods return objects of


type ServerMessage

Note: in this case, the language-dependent description of EMAILID


would be displayed in the message in English, Email Address field
missing

143
Base Messages Declarative Definition
The previous slide shows a RUNTIME message definition
Remember, validation rules are declarative
We therefore also need a declarative version of the
message to use in the validation rules

This methods returns a ServerMessageTemplate object


to use in the validation rule declaration

144
Base Messages Declarative Definition
In the last exercise we used the declarative version of
StandardMessages.fieldMissing
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
return RequireRule.ifReferenceEqualsValue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
Person.properties.emailAddress,
Person.properties.lifeSupportSensitiveLoad,
LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
com.splwg.base.domain.StandardMessages.fieldMissing());
}
fieldMissing has a runtime AND declarative message
method, but not all messages require both versions
Those used in validation rules require declarative ones; those
displayed from other runtime code (e.g. algorithms) require runtime
versions
Well see in a moment how to use a runtime message
145
Custom Messages

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Custom Messages Creating
Over the following slides, well look at creating
and using a custom message in Java
The custom message text we will work with is
%1 required if %2 is activated
The validation that references this messages will
therefore be a conditional validation
Remember this text you could even write it
down to refer to as we step through the slides
First, lets look at creating the message online

147
Custom Messages Creating
ONLY category 90000, Implementers
messages, may contain new custom
messages
To create a new message, you select
category 90000 and insert a new
message as shown below
% variables here must be supplied in
the classes that display the message

This is all that is


required in the online
to create a new
message

148
Custom Messages Java Definition
On the Java side, these are the basic initial setup rules
for creating custom messages
1. Create a CustomMessages class (supplied with this course) to
contain all your custom message definitions
2. CustomMessages must extend AbstractMessageRepository
3. In CustomMessages, specify 90000 as the message category
4. In CustomMessages, define all your custom message numbers
5. Place CustomMessages in the com.splwg.cm.domain package
6. In each individual sub-package under package cm, you create a
MessageRepository class for the message methods specific to that
sub-package Note: common message methods are placed in the
CustomMessages class
7. Each MessageRepository extends CustomMessages and contains
the runtime and declarative methods for that sub-package
Lets take a closer look
149
Custom Messages Java Definition
1 package com.splwg.cm.domain;
import com.splwg.base.domain.common.message.AbstractMessageRepository;
2 import com.splwg.cm.domain.templates.MessageRepository;
3 public class CustomMessages extends AbstractMessageRepository {
4 public static final int MESSAGE_CATEGORY = 90000;
5 public static final int REQ_IF_CONDITION = 10006;
6 private static MessageRepository instance;
public CustomMessages() {
7 super(MESSAGE_CATEGORY);
}
8 static MessageRepository getInstance() {
if (instance == null) instance = new MessageRepository();
return instance;
}
}

These are the important class characteristics


1. It is in package com.splwg.cm.domain
2. It imports our custom MessageRepository (to be created next)
3. Class CustomMessages extends AbstractMessageRepository
4. It defines MESSAGE_CATEGORY 90000
5. It defines EVERY custom message (for now, we only have one)
150
Custom Messages Java Definition
1 package com.splwg.cm.domain;
import com.splwg.base.domain.common.message.AbstractMessageRepository;
2 import com.splwg.cm.domain.templates.MessageRepository;
3 public class CustomMessages extends AbstractMessageRepository {
4 public static final int MESSAGE_CATEGORY = 90000;
5 public static final int REQ_IF_CONDITION = 10006;
6 private static MessageRepository instance;
public CustomMessages() {
7 super(MESSAGE_CATEGORY);
}
8 static MessageRepository getInstance() {
if (instance == null) instance = new MessageRepository();
return instance;
}
}

These are the important class characteristics


6. It defines a MessageRepository instance variable (see point 8)
7. It invokes the superclass to establish the message category at runtime
8. The getInstance method provides the MessageRepository instance to the
framework at runtime

151
Custom Messages MessageRepository
Next we create the MessageRepository class in
the sub-package under package cm
It must extend the CustomMessages class
It only contains the methods for the messages
relevant to the sub-package
All static definitions for the message numbers
should be in CustomMessages
Lets look at the example

152
Custom Messages MessageRepository
MessageRepository class
1 package com.splwg.cm.domain.customerinfo.person;
import com.splwg.cm.domain.CustomMessages;
2 public class MessageRepository extends CustomMessages {
3 private static MessageRepository instance;
4 private static MessageRepository getInstance() {
if (instance == null) instance = new MessageRepository();
return instance;
}
}

These are the important class characteristics


1. It is in the sub-package to which it applies - customerinfo.person in
this example
2. It extends the parent CustomMessages class
3. It defines a MessageRepository instance variable
4. It has a getInstance method to provide the appropriate
MessageRepository instance i.e. an instance of itself - to the
framework
153
Custom Messages Runtime Method
Lets add a runtime method for our message in the
MessageRepository class
1 public static ServerMessage requiredIfCondition(String fieldName1,
String fieldName2) {
2 MessageParameters parms = new MessageParameters();
parms.addField(fieldName1);
3 parms.addField(fieldName2);
4 return getInstance().getMessage(REQ_IF_CONDITION, parms);
}

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 handles
d) The parameters correspond with the % variables in the message

154
Custom Messages Runtime Method
Lets add a runtime method for our message in the
MessageRepository class
1 public static ServerMessage requiredIfCondition(String fieldName1,
String fieldName2) {
2 MessageParameters parms = new MessageParameters();
parms.addField(fieldName1);
3 parms.addField(fieldName2);
4 return getInstance().getMessage(REQ_IF_CONDITION, parms);
}

The important method characteristics are


2. It defines a MessageParameters object to carry the substitution
values for the message
3. It adds the substitution values (the parameters) to the
MessageParameters object
4. It returns a ServerMessage object as instantiated by the getMessage
method, based on the supplied message number and parameters
the message number is defined in class CustomMessages

155
Custom Messages Using at Runtime
Here we see how to set a message at runtime
Person_Id perId = new Person_Id("1234567890");
Person person = perId.getEntity();
Person_DTO perDTO = person.getDTO();
if ((perDTO.getLifeSupportSensitiveLoad().equals(
LifeSupportSensitiveLoadLookup.constants.
LIFE_SUPPORT_SENSITIVE_LOAD))
& perDTO.getEmailAddress().equals("")) {
addError(MessageRepository.requiredIfCondition("EMAILID",
"LS_SL_FLG"));
}

As seen on the previous slide, the requiredIfCondition method uses


the addField method to set the parameters
parms.addField(fieldName1);
parms.addField(fieldName2);

The MessageParameters.addField method uses the language-


dependent descriptions of the fields to replace the % markers in the
message
156
Custom Messages Declarative Method
Lets also add a declarative method for our validation rule
1 public static ServerMessageTemplate requiredIfCondition(
LookupProperty prop) {
2 ServerMessageParameter[] messageParms = {
ServerMessageParameter.OFFENDING_PROPERTY_NAME,
ServerMessageParameter.createDisplayingName(prop)
};
3 return getInstance().getDeclarativeMessage(REQ_IF_CONDITION,
messageParms);
}

The important method characteristics are


1. a) The method is static
b) It returns a ServerMessageTemplate object type for a
declarative message
c) It has a descriptive method name based on the message it
handles
d) It has a reference to the parameters if the message contains %
substitution variables

157
Custom Messages Declarative Method
Lets also add a declarative method for our validation rule
1 public static ServerMessageTemplate requiredIfCondition(
LookupProperty prop) {
2 ServerMessageParameter[] messageParms = {
ServerMessageParameter.OFFENDING_PROPERTY_NAME,
ServerMessageParameter.createDisplayingName(prop)
};
3 return getInstance().getDeclarativeMessage(REQ_IF_CONDITION,
messageParms);
}

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 field
being validated in the validation rule we substitute this name into
the messages 1st parameter
c) createDisplayingName gets the name of the LookupProperty
value which we substitute into the messages 2nd parameter

158
Custom Messages Declarative Method
Lets also add a declarative method for our validation rule
1 public static ServerMessageTemplate requiredIfCondition(
LookupProperty prop) {
2 ServerMessageParameter[] messageParms = {
ServerMessageParameter.OFFENDING_PROPERTY_NAME,
ServerMessageParameter.createDisplayingName(prop)
};
3 return getInstance().getDeclarativeMessage(REQ_IF_CONDITION,
messageParms);
}

The important method characteristics are


3. It returns a declarative message object based on the message
number and substitution parameters

159
Custom Messages Using Declarative
Using the custom declarative message in a validation rule
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
return RequireRule.ifReferenceEqualsValue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
1 Person.properties.emailAddress,
Person.properties.lifeSupportSensitiveLoad,
LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
2 MessageRepository.requiredIfCondition(
3 Person.properties.lifeSupportSensitiveLoad));
}
1. Person.properties.emailAddress is automatically set as the
OFFENDING_PROPERTY_NAME, so it does not need to be passed
to the declarative method as a parameter as seen on the previous
slide, we use this name to substitute the 1st message parameter
2. We now reference our custom requiredIfCondition method in the
validation rule

160
Custom Messages Using Declarative
Using the custom declarative message in a validation rule
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
return RequireRule.ifReferenceEqualsValue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
1 Person.properties.emailAddress,
Person.properties.lifeSupportSensitiveLoad,
LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
2 MessageRepository.requiredIfCondition(
3 Person.properties.lifeSupportSensitiveLoad));
}
3. The parameter we pass in is the property of the field to substitute the
messages 2nd parameter

161
Exercise 4 Custom Declarative Message
All Students
Use the online system to create a descriptive message for the Person
validation rule in exercise 3
Each student should use a unique message number when working on a
shared database the instructor can assign message numbers, starting at
message number 10001
Use your initials in the message to distinguish it
Create the message with 2 parameters the offending field name and the field
name used in the comparison
For example: %1 is required if %2 is BUSINESS (XX) where XX are your
initials
Update the CustomMessages class and add a constant for your new
message number e.g. REQUIRED_IF_ BUSINESS
Copy the supplied MessageRepository template to your person sub-
package and add a method for use in the validation rule e.g.
requiredIfBusiness()

162
Exercise 4 Custom Declarative Message
All Students (continued)
Update your validation rule from exercise 3 to reference the new
message

Optional
Perform the above steps to create a descriptive message for your
Premise validation rule
Start at message number 20001
For added complexity, create a 3rd message parameter in which you specify
the string value (constant) that the county is compared to
For example: %1 required if %2 not %3 (XX) where XX are your initials
(see attached note)

Test
Use the online system to validate that the new message is displayed

163
Change Handlers
Part III

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Change Handlers III Conditions
Rules can take as input one or more Conditions
The Condition interface currently has the following
implementations (i.e. these are the supported conditions)
BetweenValues
Equals
Not
And
Or
GreaterThan / GreaterThanOrEquals
LessThan / LessThanOrEquals
Contains
(Descriptions of these conditions are documented)
You use conditions to conditionally perform validation
165
Change Handlers III Conditions
Conditions can be instantiated from factory methods on
certain properties
1 Condition isPrimaryName = PersonName.properties.isPrimaryName.isTrue();
2 Condition greaterThan =
PersonName.properties.sequence.isGreaterThan(BigInteger.ZERO);
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 also be instantiated using a constructor
Condition isPerson =
new Equals(Person.properties.personOrBusiness,
PersonOrBusinessLookup.constants.PERSON);
This checks if the PersonOrBusiness property is set to Person

A Condition object such as this can be used in a


Validation Rule to cause conditional validation
166
Change Handlers III Conditions
Example using a Condition to make email address required
if life support flag is set
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
1 Condition hasLifeSupport =
Person.properties.lifeSupportSensitiveLoad.
isEqualTo(LifeSupportSensitiveLoadLookup.constants.
LIFE_SUPPORT_SENSITIVE_LOAD);
2 return RequireRule.ifConditionTrue(
"Person:Email address is required if life support is active",
"Email address is required if life support is active",
Person.properties.emailAddress,
3 hasLifeSupport,
com.splwg.base.domain.StandardMessages.fieldMissing());
}

1. This is the Condition to check if life support is on


2. We use the ifConditionTrue method of the RequireRule class
3. The ifConditionTrue method requires the Condition as a parameter,
which in this case is the condition created in point 1

167
Exercise 5 Change Handler Validation 3
All Students
Modify your Person change handler from exercise 3
Introduce a Condition in your validation rule to make address line 1
required if the person type is Business (same validation as in exercise 3)
Change the validation rule to use the Condition

Optional
Modify your Premise change handler from exercise 3
Introduce a Condition in your validation rule to make city required if the
county is not equal to San Francisco (same validation as in exercise 3)
Change the validation rule to use the Condition

Test
Run the JUnit test class from exercise 3 to test
Startup the online system and test that your validation rule works
the same as in exercise 4

168
Change Handlers
Part IV

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Change Handlers IV Custom Rules
If validation is too complex for a declarative rule, a
custom rule may be coded
A custom rule contains code to perform the specific
validation in other words, if invalid condition, display
error message
A custom rule class may implement one or more abstract
methods
The methods correspond with events that may occur
with respect to the underlying business entity
The methods are divided into 2 categories
1. Eager Validations
2. Lazy Validations

170
Custom Rule Eager Validation Methods
Eager validations fire immediately when an entity is
changed by way of a delete(), setDTO() or createEntity())
The event methods that can be implemented by a
custom rule class are
validateAdd() fires when a business entity is added
validateChangeOnly() fires when a business entity is changed
validateAddOrChange() fires when a business entity is added or
changed (in addition to an add or change event)
validateDelete() fires when a business entity is deleted
validateRegisteredChange() fires when a change is registered to
another object (e.g. a child) - this can be any business entity that
feels like notifying you of a change
A parameter passed to this method, RegisteredChangeDetail, can be
queried (via its getChangeToList() method) to determine if the
change affects you

171
Custom Rule Lazy Validation Methods
Lazy validations fire after a coherent set of
changes have been made this is in contrast to
eager validations that fire immediately when an
entity is modified
Only one lazy validation method exists
validateSave()
It fires at the end of a set of changes
Validation of child entities, for example, can therefore be
placed in this method
All types of changes (add, change, delete or register
change) will trigger a validateSave()
172
Custom Rule Class
These are the basic steps to create and use a custom
rule
1. Create a class that extends AbstractCustomValidation this class
could be an inner class of your Change Handler if the custom
validation rule is specific to the Business Entity being validated
2. In your new class, provide the framework with an array of entity
properties associated with the custom rule the framework uses this
to avoid additional validations on properties already known to be in
error
3. In you new class, implement the appropriate eager and/or lazy
methods to perform the validation
4. Reference the custom rule in your static validation rule method, as
you would with a standard declarative rule

Lets take a look at an example

173
Custom Rule MapFieldNameRequired Example

1. This class is an inner class of the ScriptFieldMap_CHandler class


this is not required, but it makes sense if the custom rule is specific to
a Business Entity
2. The custom rule class extends AbstractCustomValidation
3. It passes back to the framework the property(s) being validated in
this case mapFieldName

174
Custom Rule MapFieldNameRequired Example

1
2

1. It overrides abstract method validateAddOrChange for immediate


(eager) validation this validation code will 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 validated in this case ScriptFieldMap
3. If a validation error is found, the addValidationError method registers
the error message with the framework
175
Custom Rule MapFieldNameRequired Example

Change Handler class ScriptFieldMap_CHandler


1

1. In the Change Handler class, it declares a static method


mapFieldNameRequired as a standard, the name ties in with the
custom rule class name of MapFieldNameRequired
2. The Change Handler instantiates and returns a new CustomRule
object for custom rule class MapFieldNameRequired
3. The getValidationRules() method provides the framework the list of
ALL the rules in this Change Handler custom and standard ones
176
Exercise 6 Custom Validation Rule
All Students
Modify (or copy) your Person change handler 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 initials) the instructor can assign a unique message
number to each student
Create a runtime message method in your MessageRepository class
Override the validateSave method remember, you need to do lazy
validation when checking child entities
Characteristics are effective dated use an iterator on
PersonCharacteristic to scan for the COMMENT type

Test
Create cm.jar and startup the online system to test
On a shared database, each student should test using a different person
177
Exercise 6 Custom Validation Rule
Optional
Create a JUnit test class for your custom validation rule and in your
testShortCommentRequiredRule() method
Create a PersonCharacteristic_Id object for the COMMENT characteristic
for your Person_Id
Because this is for an existing Person on the database, remove any existing
Short Comment characteristic before continuing with the steps below to test
the validation
Note: This remove could trigger validation on the Person, which at this stage
you want to avoid. See if you can come up with the solution.
Create a PersonCharacteristic_DTO object from the PersonCharacteristic_Id
Set the adhoc characteristic value to something e.g. Test comment
Create a new PersonCharacteristic object from the
PersonCharacteristic_DTO
Add the new PersonCharacteristic object to your collection of characteristics
All the steps up to this point perform the positive validation i.e. they
test that your validation rule does NOT get violated
178
Exercise 6 Custom Validation Rule
Optional (continued)
Test that the rule gets violated by removing the newly created
PersonCharacteristic object from the collection of characteristics this
should cause an application exception to be thrown

179
SPL Framework &
Hibernate

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


SPL Framework & Hibernate - Overview
SPLs Java Persistence Framework (JPF) uses Hibernate
for database persistence
What is Hibernate?
It is an object/relational mapping (ORM) tool for Java environments
ORM refers to the technique of mapping the data representation from
an object model to a relational data model with a SQL-based schema
It takes care of the mapping from Java classes to DB tables
It also provides data query and retrieval facilities
It significantly reduces development time otherwise spent with manual
data handling in SQL and JDBC

We have seen a lot of it already in the Business Entity,


DTO and JUnit topics

181
Hibernate Architecture View
This generic diagram shows
Hibernate positioned between the Application
application (e.g. SPL Framework) and
the database Persistent Objects

The application accesses data via


Persistent Objects e.g. the Person Hibernate
object maps to the CI_PER table,
hibernate.
Account to CI_ACCT, etc. properties
XML mapping

The hibernate.properties file


specifies various parameters, for
Database
example the database connection
The XML Mapping files contain the
metadata that describes how to map
the DB tables to Java objects
(object/relational mapping)

182
SPL Framework & Hibernate Architecture
This diagram shows
how the framework Data Transfer
implements Objects (DTO) SPL Framework
Hibernate Business
Entities
The SessionFactory SessionFactory
is a cache of Session
compiled O/R ConnectionProvider
mappings JDBC
The
ConnectionProvider JDBC
is a factory & pool of
JDBC connections
The Business Database
Entities (Persistent
Objects) are short-
lived, single-
threaded and have a
persistent state

183
SPL Framework & Hibernate Architecture
The Data Transfer
Objects (Transient Data Transfer
Objects (DTO) SPL Framework
Objects) are
Business
persistent objects Entities
that are not SessionFactory
associated with a Session
session ConnectionProvider
JDBC
A Session is a short-
lived object that JDBC
represents a
conversation
between the app and
the DB; it wraps a Database
JDBC connection

As indicated by the JDBC block on the right, the SPL Framework also
provides for direct JDBC calls if needed

184
Hibernate Background
The SPL Framework wraps Hibernate, so native
Hibernate calls are not used
We have already seen some of this, for example
the statement
Person perEntity = perId.getEntity();

will call Hibernate to create a Person object from


the CI_PER database table it is not a native
Hibernate call
To provide a deeper understanding, the following
slides give an overview of native Hibernate
We will then compare that to the SPL
Frameworks implementation of Hibernate
185
Hibernate Persistent Objects
With Hibernate you access tables as objects
An object can be loaded from the DB if the identifier is known
Cat fritz = (Cat) sess.load(Cat.class, generatedId);

This instantiates an object of class Cat from the DB table for Cat
The load() method throws an unrecoverable exception if the row does
not exist
Use the get() method to avoid the exception instead, it returns a null
if the row is not found, as shown below

Cat cat = (Cat) sess.get(Cat.class, id);


if (cat==null) {
cat = new Cat();
sess.save(cat, id);
}
return cat;

186
Hibernate HQL
The Hibernate Query Language (HQL) allows for SQL-like queries
Use the find() method to query for objects
List cats = sess.find(
"from Cat as cat where cat.birthdate = ?",
date,
Hibernate.DATE
);

This will select all the properties (columns) of table Cat


You can also specify scalar queries (e.g. to retrieve one column)
For this, use the select clause in HQL
List mates = sess.find(
"select mate from Cat as cat join cat.mate as mate " +
"where cat.name = ?",
name,
Hibernate.STRING
);

187
Hibernate Updating Persistent Objects
Persistent objects can be updated
At its most straightforward, you load the object, manipulate it (using
the setter methods) and then flush() the session

DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );


cat.setName("PK");
sess.flush(); // changes to cat are automatically detected & persisted

This can be an inefficient model since it requires a SQL select and


SQL update in the same session
The following slide shows a different approach

188
Hibernate Updating Persistent Objects
For updates across session boundaries (e.g. in an online
environment), you use the update() method of the session object
// in the first session, cat is instantiated from a db row
Cat cat = (Cat) firstSession.load(Cat.class, catId);
Cat potentialMate = new Cat();
firstSession.save(potentialMate);

// in a higher tier of the application, cat is modified


cat.setMate(potentialMate);

// later, in a new session, cat is updated on the database


secondSession.update(cat); // update cat
In this example
A existing Cat object, cat, is instantiated from a database row through the
session load method a new Cat, potentialMate, is also created
cat is then modified in some other part of the application - its mate is set to
the new potentialMate object
In a second session, cat it is updated on the database this does the update
directly, instead of first selecting the object

189
Hibernate Deleting Persistent Objects
The delete() method of a session removes an objects
state from the database
sess.delete(cat);

The application may still hold a reference to the object


delete() therefore makes a persistent object transient
You may also delete many objects at once by passing a
Hibernate query string to the delete method

Refer to www.hibernate.org for detailed documentation

Now lets take a look at the frameworks implementation


of Hibernate

190
Hibernate for SPL Framework
The previous slides show native use of Hibernate
persistent objects and HQL
As weve seen, internally the framework uses
Hibernate for persistence
The frameworks database persistence therefore
is similar to native Hibernate it just uses some
different terminology
Persistent Objects = Business Entities
Transient Objects = Data Transfer Objects
Much of this has been covered before, but well
review and add some new things over the
following slides
191
Hibernate for SPL Framework
Business Entity / DTO
Creating a new Business Entity equates to creating a new
database row
Likewise, when a Business Entity is changed or deleted,
the same action is performed on the database
Actual inserts, updates and deletes on the DB are
controlled by the framework
Properties on a Business Entity can only be updated via
the Data Transfer Object (DTO)

192
Hibernate for SPL Framework
Business Entity / DTO
To instantiate a new Business Entity from the DB
Person_Id perId = new Person_Id("1185477091");
Person perEntity = perId.getEntity();

or
Person perEntity = (Person)query.firstRow();

or
Query query = SessionHolder.getSession()
.createQuery("from Person");
Person perEntity = null;
QueryIterator qIter = query.iterate();
wile (qIter.hasNext()) {
perEntity = (Person)qIter.next();
...
}

193
Hibernate for SPL Framework
Business Entity / DTO
To update a property, you use the DTO
Person_DTO perDTO = perEntity.getDTO();
perDTO.setEmailAddress(testemail@splwg.com);
perEntity.setDTO(perDTO);

To create a new Business Entity, you create the DTO first


Person_DTO perDTO = (Person_DTO) createDTO(Person.class);

Note: createDTO() is inherited from the parent GenericBusinessObject


class for all Business Entity or Business Component classes (e.g.
Change Handlers)

or you create an empty DTO from an Id class


Person_Id perId = new Person_Id("1185477091");
Person_DTO perDTO = perId.newDTO();

194
Hibernate for SPL Framework
Business Entity / DTO
and then create the Business Entity from the DTO
perDTO.setId(new Person_Id(1185477091));
perDTO.set...
Person person = perDTO.newEntity();

To delete a Business Entity, you use the delete method on


the entity
person.delete();

or you can delete the results of a query using the delete


method on Query
Query query = SessionHolder.getSession()
.createQuery("from Person");
long rowsDeleted = query.delete();

195
Hibernate for SPL Framework - HQL
HQL queries must also go through the SPL Framework
The framework Query class implements a subset of pure
HQL
The framework HQL queries return Business Entities
It is mostly the same as the native HQL language, except
for a few differences
The SELECT clause is not allowed in the frameworks HQL text
The ORDER BY clause is not allowed in the frameworks HQL text
UNIONs are catered for in the frameworks HQL (native HQL does not
allow it)
The framework caters for raw SQL statements
The following slides describe the frameworks
implementation of HQL

196
SPL Query SELECT clause
The SELECT clause is not used in a framework
Query call
Similar to Hibernate, the following query is valid
AlgorithmType algorithmType = ... ;
Query query = createQuery("from Algorithm algorithm +
where algorithm.algorithmType = :algorithmType");
query.bindEntity("algorithmType", algorithmType);
List algorithms = query.list();

In this example, the List will contain the algorithm


objects selected for the algorithm type (i.e.
Business Entities are returned)
However, unlike Hibernate, select property from
object is invalid in a framework query
197
SPL Query SELECT clause
To select individual columns, you specify the result
properties programmatically, giving each a unique name

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();

The addResult method on the Query object specifies a


result property (column) to select
Now the List will contain QueryResultRow objects
Each QueryResultRow will have two values, keyed by
algorithm and algorithmId

198
SPL Query ORDER BY clause
The ORDER BY clause in HQL is not allowed by
the framework
Instead, the order must be programmatically
specified
Query query = createQuery("from Algorithm algorithm+
where algorithm.algorithmType = :algorithmType");
query.bindEntity("algorithmType", algorithmType);
query.addResult("algorithm", "algorithm");
query.addResult("algorithmId", "algorithm.id");
query.orderBy(algorithmId, Query.ASCENDING);
List queryResults = query.list();

The List will contain QueryResultRow objects,


ordered by algorithmId

199
SPL Query Iterate Method
For a large volume query, instead of using a List,
better performance can be gained using the
iterate method on Query
Query query = SessionHolder.getSession().createQuery("from Person");
Person perEntity = null;
QueryIterator qIter = query.iterate();
while (qIter.hasNext()) {
perEntity = (Person)qIter.next();
...
}

This is more efficient because the iterator loads


objects on demand
It also performs better if the objects have already
been loaded and cached by the session
200
SPL Query UNION
Hibernate does not provide for unions (it does not fit in with the
object-oriented principles of HQL)
However, unions can be useful so the framework allows you to
programmatically code a union
Unioned queries must have identical
Result columns
Order by clauses
Max results settings
The unionWith() method of the Query class performs the initial union
UnionQuery union = query.unionWith(query2);

To add a third (or later) query, you add it directly to the union
union.addQueryToUnion(query3);

201
SPL Query Raw SQL
It may be necessary to code SQL instead of HQL
Potential reasons are
To specify performance hints
A table is not mapped to a Java entity
Instead of createQuery(), you use the JDBC-like
createPreparedStatement() method on the session object
The text is similar to the HQL Query text, but you use the
table and column names instead of the Java entity and
property names
This feature is only mentioned here for information we
do not cover it in the exercises
Please note that this is not a recommended or preferred means of
accessing the database

202
SPL Framework & Hibernate Review
The framework uses Hibernate for its database
access
All application code MUST use the framework
interfaces for Hibernate
Most of the HQL syntax is the same as for native
HQL, except for the SELECT clause, ORDER BY
clause and UNION
You can bypass Hibernate and use native SQL
Weve only covered a small part refer to
www.hibernate.org and the SPL SDK
documentation for more details
203
Change Handlers
Part V

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Change Handlers V Cascading Changes
Up to now weve seen change handlers performing
validation on a Business Entity
Change handlers can also implement business logic
based on inserts, updates & deletes to a Business Entity
i.e. to cause cascading changes to occur
For example, if a phone number for a Person changes,
update matching phone numbers for related Persons
automatically
Change handlers provide for a number of handle
methods
Handle methods are invoked when specific events occur
Unlike validation, this logic fires immediately it cannot
be deferred by the startChanges or saveChanges method
calls
205
Change Handlers V Events and Methods
The following methods can be implemented to
provide customized functionality
For an Add or Copy Event
prepareToAdd()
handleAddOrChange()
handleAdd()
handleRegisteredChange()
For an Update Event
prepareToChange()
handleAddOrChange()
handleChange()
For a Delete Event
handleDelete()
206
Change Handlers V Events and Methods
Lets take a closer look at the methods
prepareToAdd(DataTransferObject newDTO)
This method fires before a new Business Entity is added
It allows you to default values and perform other changes on a new
DTO before the add

handleAddOrChange(BusinessEntity businessEntity,
DataTransferObject oldDTO)
This fires before validation when a entity is added OR changed
The oldDTO object contains a null on an add event

handleAdd(BusinessEntity newBusinessEntity)
This fires before validation when an entity is added
It allows for cascading updates on other objects or external systems
207
Change Handlers V Events and Methods
prepareToChange(BusinessEntity unchangedEntity,
DataTransferObject newDTO)
This fires before a change to a DTO is submitted
You can use this to default values and perform other changes on a
DTO before the change

handleChange(BusinessEntity changedBusinessEntity,
DataTransferObject oldDTO)
This fires before validation when an entity is changed
It allows for cascading updates on other objects or external systems

208
Change Handlers V Events and Methods
handleRegisteredChange(BusinessEntity changedBusnessEnty,
RegisteredChangeDetail changeDetl)
This fires when a change is registered to the changedBusnessEnty
object via the business entitys registerChange method
For example, it can be fired when a child list associated with the
Business Entity has been changed
The RegisterChangeDetail object specifies the details of the change
handleDelete(DataTransferObject oldDTO)
This fires before validation when an entity is deleted

Important these are not preferred places for validation


validation should be done using validation rules

Lets now take a look at an example


209
Change Handlers V handleAdd example
Create an alert when a new account is added
/**
1 * @ChangeHandler (entityName = account)
*/
2 public class CmAccount_CHandler extends AbstractChangeHandler {

3 public void handleAdd(BusinessEntity newBusinessEntity) {


4 Account account = (Account) newBusinessEntity;
5 AccountAlerts acctAlerts = account.getAlerts();
6 AccountAlert_DTO acctAlertDTO = acctAlerts.newChildDTO();
7 acctAlerts.add(acctAlertDTO,
new AlertType_Id("PP EXEMPT"),
getSystemDateTime().getDate());
}
}
1. It specifies the entity type in annotations (dont forget to do this!)
2. The class name ends in _CHandler and extends
AbstractChangeHandler
3. It implements the handleAdd method; the newBusinessEntity object
is a reference to the entity being added
210
Change Handlers V handleAdd example
Create an alert when a new account is added
/**
1 * @ChangeHandler (entityName = account)
*/
2 public class CmAccount_CHandler extends AbstractChangeHandler {

3 public void handleAdd(BusinessEntity newBusinessEntity) {


4 Account account = (Account) newBusinessEntity;
5 AccountAlerts acctAlerts = account.getAlerts();
6 AccountAlert_DTO acctAlertDTO = acctAlerts.newChildDTO();
7 acctAlerts.add(acctAlertDTO,
new AlertType_Id("PP EXEMPT"),
getSystemDateTime().getDate());
}
}

4. It casts newBusinessEntity to an Account object


5. It gets the alerts entity list (AccountAlerts) for the account this will
be empty since its a new account
6. It creates a new alert DTO by using the entity lists newChildDTO
method
211
Change Handlers V handleAdd example
Create an alert when a new account is added
/**
1 * @ChangeHandler (entityName = account)
*/
2 public class CmAccount_CHandler extends AbstractChangeHandler {

3 public void handleAdd(BusinessEntity newBusinessEntity) {


4 Account account = (Account) newBusinessEntity;
5 AccountAlerts acctAlerts = account.getAlerts();
6 AccountAlert_DTO acctAlertDTO = acctAlerts.newChildDTO();
7 acctAlerts.add(acctAlertDTO,
new AlertType_Id("PP EXEMPT"),
getSystemDateTime().getDate());
}
}

7. It adds the partially completed DTO to the accounts alert entity list
the additional parameters are required for the entity list
The framework will add the row when the transaction commits

212
Change Handlers V Cascading Changes
The previous example shows a cascading
change to a child entity (Alerts) of a Business
Entity (Account)
The basic rules when working with child entities
are
Child entity lists are acquired from a Business Entity via
the appropriate getter methods (e.g. getAlerts())
To add a new child entity, use the entity lists add methods
To remove a child entity, use the entity lists remove
methods

213
Change Handlers V Cascading Changes
When inserting and deleting entities that are NOT
child entities of the business entity being
customized, more explicit code is required
In this case the getDTO and setDTO method calls
need to be used

Lets look at an example

214
Change Handlers V handleChange Example
Update the related premise when an account is changed
1 public void handleChange(BusinessEntity changedEntity,
DataTransferObject oldDTO) {
2 Account account = (Account) changedEntity;
3 if (account.getMailingPremiseId() != null) {
4 Premise premise = account.getMailingPremiseId().getEntity();
5 Premise_DTO premiseDTO = premise.getDTO();
6 premiseDTO.setAddress4(account.getAlertInformation());
7 premise.setDTO(premiseDTO);
}
}
1. It implements the handleChange method the changedEntity object
is a reference to the account entity being changed; oldDTO is the
DTO before the change was made
2. It casts changedEntity to an Account object
3. It checks if the mailing premise Id is populated on the account
mailing premise Id is an optional foreign key reference (Note, on the
CI_ACCT table the mailing premise Id is a space, but on the
Business Entity object it is a null)
215
Change Handlers V handleChange Example
Update the related premise when an account is changed
1 public void handleChange(BusinessEntity changedEntity,
DataTransferObject oldDTO) {
2 Account account = (Account) changedEntity;
3 if (account.getMailingPremiseId() != null) {
4 Premise premise = account.getMailingPremiseId().getEntity();
5 Premise_DTO premiseDTO = premise.getDTO();
6 premiseDTO.setAddress4(account.getAlertInformation());
7 premise.setDTO(premiseDTO);
}
}
4. It gets the Premise object referenced by the mailing premise Id field
5. It gets DTO for the Premise to modify the row
6. It updates the value on the Premise DTO address line 4 in this case
is set to the accounts alert information (i.e. the Comment field on
the account page)
7. It updates the Premise Business Entity using the setDTO() method,
which ultimately causes the row to be updated
216
Exercise 7 Cascading Change Handler
All Students
Change your Person Change Handler from the previous exercise
automatically add a Short Comment characteristic (characteristic
type COMMENT) whenever a new Person is added
Test
Create cm.jar and startup the online system to test
Add a new person and verify that the Short Comment characteristic
was added by your Change Handler
Optional
Create a JUnit test class that adds a new person and verifies that the
Short Comment characteristic was automatically added. In this
exercise, a completely new person, with all its required collections
of names and Id numbers, must be created. In your test method
Suspend validation until all the data has been added
Create a new Person_Id object

217
Exercise 7 Cascading Change Handler
Optional (continued)
Create a new Person_DTO object
Set the following required fields on the Person_DTO
PersonOrBusiness
LifeSupportSensitiveLoad
LanguageId

Create a new Person object from the DTO


Create a PersonName_DTO object (use the getNames() method on the
Person object)
Set the following required fields on the PersonName_DTO
EntityName
IsPrimaryName
NameType

Add the name to the Names collection on the Person object (use sequence
1)
218
Exercise 7 Cascading Change Handler
Optional (continued)
Create a PersonId_DTO object (use the getIds() method on the Person
object)
Set the following required fields on the PersonId_DTO
IsPrimaryId
PersonIdNumber

Add the Id to the Ids collection on the Person object for Id Type SSN (Social
Security Number)
Enable validation at this point (i.e. remove the suspension)
Verify that the short comment characteristic was added by getting a
PersonCharacteristic object for the expected COMMENT characteristic if
a null object is returned, fail the test as follows

assertNotNull("Short Comment characteristic does not exist",


perChar);

219
Algorithms
Part I

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Algorithms - Overview
Where the system requires a customization, SPL provides
for customizable algorithms (a.k.a plug-ins)
Base algorithms exist, but can be cloned and modified
They are like user exits, but
Unlike Change Handlers, they are more related to the business
functions and events
Also, unlike Change Handlers, they use configurable (soft)
parameters
For example
In the CC&B world, if a CSR requests a customers recommended
deposit amount, the system calls a deposit recommendation
algorithm to calculate the amount
If the base version of the algorithm is not appropriate for your
business, a new algorithm can be coded to replace or supplement the
base one
221
Algorithms - Overview
At upgrades, custom algorithms will not be overwritten
Here are a few more examples where algorithms are used
Validating the format of a phone number entered by the user
Validating the format of a latitude/longitude geographic code entered
by the user.
Calculating late payment charges in CC&B
Calculating the recommended deposit amount in CC&B
In CC&B, constructing your GL account during the interface of a
financial transaction to your GL
Etc.

Lets take a look at how algorithms work internally

222
Algorithms - Overview
Algorithms are defined in 2 places
Database tables
The online Admin menu is used to define the database components,
which are
Algorithm Types
Algorithms
The event or activity to which the algorithm applies (e.g. FT freeze, phone
number validation, etc.)

The SPL Framework


The framework requires the implementation class the program
that contains the logic and various generated artifacts (we will only
be looking at Java, not COBOL)

Lets take a look at these definitions more closely, database


components first and then the framework classes
223
Algorithm Database Model
1 CI_ALG_TYPE CI_ALG Customized Entity
PK ALG_TYPE_CD PK ALG_CD

PGM_NAME FK1 ALG_TYPE_CD FK1 ALG_CD


ALG_ENTITY_FLG VERSION
PGM_TYPE_FLG

CI_ALG_PARM
CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK,FK1 ALG_TYPE_CD PK EFFDT
PK SEQNO PK,FK1 SEQNO

PARM_REQ_SW ALG_PARM_VAL
FK1 ALG_TYPE_CD

These are the tables that define an algorithm


1. Algorithm Type defines
The entity e.g. Char Type Adhoc Value Validation, SA Type
SA Creation, etc.
The program name
The program type JAVA or COBOL
224
Algorithm Database Model
1 CI_ALG_TYPE CI_ALG Customized Entity
PK ALG_TYPE_CD PK ALG_CD

PGM_NAME FK1 ALG_TYPE_CD FK1 ALG_CD


ALG_ENTITY_FLG VERSION
PGM_TYPE_FLG

CI_ALG_PARM
2 CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK,FK1 ALG_TYPE_CD PK EFFDT
PK SEQNO PK,FK1 SEQNO

PARM_REQ_SW ALG_PARM_VAL
FK1 ALG_TYPE_CD

These are the tables that define an algorithm


2. Algorithm Type Parameter defines
The parameters expected by the algorithm program
For each parameter, whether it is required or optional

225
Algorithm Database Model
1 CI_ALG_TYPE 3 CI_ALG Customized Entity
PK ALG_TYPE_CD PK ALG_CD

PGM_NAME FK1 ALG_TYPE_CD FK1 ALG_CD


ALG_ENTITY_FLG VERSION
PGM_TYPE_FLG

4 CI_ALG_PARM
2 CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK,FK1 ALG_TYPE_CD PK EFFDT
PK SEQNO PK,FK1 SEQNO

PARM_REQ_SW ALG_PARM_VAL
FK1 ALG_TYPE_CD

These are the tables that define an algorithm


3. Algorithm defines an instance of the algorithm type
many algorithms may exist for one algorithm type
4. Algorithm Parameter defines the parameter values for the
instance

226
Algorithm Database Model
1 CI_ALG_TYPE 3 CI_ALG 5 Customized Entity
PK ALG_TYPE_CD PK ALG_CD

PGM_NAME FK1 ALG_TYPE_CD FK1 ALG_CD


ALG_ENTITY_FLG VERSION
PGM_TYPE_FLG

4 CI_ALG_PARM Examples
2 CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK,FK1 ALG_TYPE_CD PK EFFDT Characteristic Type
PK SEQNO PK,FK1 SEQNO SA Type
PARM_REQ_SW ALG_PARM_VAL Etc.
FK1 ALG_TYPE_CD

These are the tables that define an algorithm


5. The algorithm code is specified on the customized entitys
configuration table the algorithm will be invoked based
on this specification

Lets look at an example

227
Algorithm Phone Format Example
Phone format - algorithm definition diagram
Algorithm Type:PHN-FMT Algorithm:PHN-FMT-US Phone Type: BUSN
Format 1 required (999) 999-9999
Format 2 optional
Format 3 optional Algorithm:PHN-FMT-UK Phone Type: BUSN_UK
Format 4 thru 9 optional 999 9999-9999
99999 999999
9999 999-9999

CI_ALG_TYPE CI_ALG Phone Type


PK ALG_TYPE_CD PK ALG_CD

PGM_NAME FK1 ALG_TYPE_CD FK1 ALG_CD


ALG_ENTITY_FLG VERSION
PGM_TYPE_FLG

CI_ALG_PARM
CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK,FK1 ALG_TYPE_CD PK EFFDT
PK SEQNO PK,FK1 SEQNO

PARM_REQ_SW ALG_PARM_VAL
FK1 ALG_TYPE_CD

228
Algorithm Phone Format Example
Admin -> Algorithm Type Phone format
1

2
3
4

1. Algorithm Type name 12 characters


2. The Algorithm Entity determines where the system will allow this
algorithm to be specified in this case, the PHN-FMT algorithm type
may only be specified on the Phone Type entity
3. The Program Type here is JAVA (it can also be COBOL)

229
Algorithm Phone Format Example
Admin -> Algorithm Type Phone format
1

2
3
4

4. This is the algorithm component interface to format and validate 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 least one phone format is required

230
Algorithm Phone Format Example
Admin -> Algorithm Phone format US
1

1. This is the algorithm name i.e. the 1st instance of the algorithm
type
2. The Algorithm Type that this algorithm corresponds to
3. The effective date
4. The phone format for this instance only one for the U.S.
231
Algorithm Phone Format Example
Admin -> Algorithm Phone format UK
1

1. This is the algorithm name - i.e. the 2nd instance of the algorithm
type
2. It has the same algorithm type as for the U.S. (i.e. it is the SAME
PROGRAM that formats U.S. and U.K. phone numbers)
232
Algorithm Phone Format Example
Admin -> Algorithm Phone format UK
1

3. The U.K. has multiple phone formats the algorithm will validate a
U.K. phone number against all of these formats

233
Algorithm Phone Format Example
Admin -> Phone Type Algorithm usage

1
2

This defines 2 types of business phones


1. U.S. phone numbers are to be validated and formatted by
the North American phone format algorithm, as defined
on the previous slides
2. U.K. phone numbers are to be validated and formatted by
the United Kingdom phone format algorithm, as defined
on the previous slides

234
Algorithm Phone Format Example
Main -> Person Algorithm activation
1

On the Person page, Phone Type now determines the


algorithm to invoke for the phone number formatting and
validation

In this topic we have so far looked at defining the


database entries required for an algorithm definition
next well see how the framework components are
built to support these definitions
235
Algorithm Spots
The call out places in the system (e.g. from Person to
validate phone number) are known as algorithm spots
Each algorithm spot has an interface class
Communication with an algorithm takes place through the
interface
An interface provides abstraction between the base and
the customization

Business Algorithm
Algorithm Spot
Component Interface Component
PhoneTypeFormat
PhoneTypeFormat
Person Phone ValidationAlgorithmSpot
ValidationAlgComp

236
Algorithm Spots
The attributes of an algorithm spot interface class
are
It is internal to the framework, only ever created by
Product Development
It is the API to the algorithm component (from the base
application)
It is specific to the algorithm entity type (or system event)
It defines the hard input parameters for an algorithm
these are the parameters associated with a specific event
It defines the output parameters that can be retrieved after
the algorithm has been invoked

237
Algorithm Spots
These classes form part of the base code
They are invoked from the base code at appropriate times (events)
The methods on the interface are related to the algorithm type for
example, setPhoneValue() is only relevant to
PhoneTypeFormatValidationAlgorithmSpot
interface
AdhocCharacteristicValueValidationAlgorithmSpot
+setFormatOnly() : void
+setCharacteristicType() : void
+setAdhocValue() : void
+getReformattedValue() : String
interface
+isValidAdhoc() : Boolean
AlgoritmSpot
+invoke()
interface
PhoneTypeFormatValidationAlgorithmSpot
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String
238
Algorithm Components
An algorithm requires a programmatic implementation
The Algorithm Type definition carries the program name,
for example
com.splwg.base.domain.common.phoneType.
PhoneTypeFormatValidationAlgComp

This name in fact specifies another interface which is


generated from the implementation class
The implementation class name = the interface name +
Impl, for example
com.splwg.base.domain.common.phoneType.
PhoneTypeFormatValidationAlgComp_Impl

The following diagram describes the full Phone Type


Validation algorithm component
239
Algorithm Components Phone Type Validation

Remember
An interface is empty it requires an implementation to perform
appropriate tasks
The implementation for an algorithm spot is an Algorithm Component
i.e. Business Component
interface
AlgoritmSpot
+invoke()

interface
PhoneTypeFormatValidationAlgorithmSpot
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String

PhoneTypeFormatValidationAlgComp_Gen
PhoneTypeFormatValidationAlgComp_Impl
interface
+getPhoneFormat1() : String
PhoneTypeFormatValidationAlgComp
+getPhoneFormat2() : String
+setPhoneValue() : void +invoke() : void
+getPhoneFormat3() : String
+setPhoneType() : void +setPhoneValue() : void
+getPhoneFormat4() : String
+isValidPhoneValue() : Boolean +setPhoneType() : void
+getPhoneFormat5() : String
+getPreferredFormatString() : String +isValidPhoneValue() : Boolean
+getPhoneFormat6() : String
+getReformattedPhoneValue() : String +getPreferredFormatString() : String
+getPhoneFormat7() : String
+getReformattedPhoneValue() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String

240
Algorithm Components Phone Type Validation
1. The implementation class (_Impl) is hand-coded it can be
customized
2. The component interface is generated by the artifact generator a
customized version will be generated for a custom impl class
3. An algorithm is invoked via its component interface
interface
AlgoritmSpot
+invoke()

interface
PhoneTypeFormatValidationAlgorithmSpot
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String

2
PhoneTypeFormatValidationAlgComp_Gen 1
3 PhoneTypeFormatValidationAlgComp_Impl
interface
+getPhoneFormat1() : String
PhoneTypeFormatValidationAlgComp
+getPhoneFormat2() : String
+setPhoneValue() : void +invoke() : void
+getPhoneFormat3() : String
+setPhoneType() : void +setPhoneValue() : void
+getPhoneFormat4() : String
+isValidPhoneValue() : Boolean +setPhoneType() : void
+getPhoneFormat5() : String
+getPreferredFormatString() : String +isValidPhoneValue() : Boolean
+getPhoneFormat6() : String
+getReformattedPhoneValue() : String +getPreferredFormatString() : String
+getPhoneFormat7() : String
+getReformattedPhoneValue() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String

241
Algorithm Components Phone Type Validation

1. The implementation class contains the hand-coded logic


2. The _Gen class has the methods for the soft parameters (as
specified on the Algorithm Type definition)
Note: These are generated from the annotations in the _Impl class
interface
AlgoritmSpot
+invoke()

interface
PhoneTypeFormatValidationAlgorithmSpot
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String

2
PhoneTypeFormatValidationAlgComp_Gen 1
PhoneTypeFormatValidationAlgComp_Impl
interface
+getPhoneFormat1() : String
PhoneTypeFormatValidationAlgComp
+getPhoneFormat2() : String
+setPhoneValue() : void +invoke() : void
+getPhoneFormat3() : String
+setPhoneType() : void +setPhoneValue() : void
+getPhoneFormat4() : String
+isValidPhoneValue() : Boolean +setPhoneType() : void
+getPhoneFormat5() : String
+getPreferredFormatString() : String +isValidPhoneValue() : Boolean
+getPhoneFormat6() : String
+getReformattedPhoneValue() : String +getPreferredFormatString() : String
+getPhoneFormat7() : String
+getReformattedPhoneValue() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String
242
Algorithm Components Phone Type Validation

3. The generated component interface class also contains a factory


class to create an instance of an algorithm component well see an
example of this shortly

interface
AlgoritmSpot
+invoke()

interface
PhoneTypeFormatValidationAlgorithmSpot
+setPhoneValue() : void
+setPhoneType() : void
+isValidPhoneValue() : Boolean
+getPreferredFormatString() : String
+getReformattedPhoneValue() : String

PhoneTypeFormatValidationAlgComp_Gen
3
PhoneTypeFormatValidationAlgComp_Impl
interface
+getPhoneFormat1() : String
PhoneTypeFormatValidationAlgComp
+getPhoneFormat2() : String
+setPhoneValue() : void +invoke() : void
+getPhoneFormat3() : String
+setPhoneType() : void +setPhoneValue() : void
+getPhoneFormat4() : String
+isValidPhoneValue() : Boolean +setPhoneType() : void
+getPhoneFormat5() : String
+getPreferredFormatString() : String +isValidPhoneValue() : Boolean
+getPhoneFormat6() : String
+getReformattedPhoneValue() : String +getPreferredFormatString() : String
+getPhoneFormat7() : String
+getReformattedPhoneValue() : String
+getPhoneFormat8() : String
+getPhoneFormat9() : String

243
Algorithm Implementation Class
The base versions of all algorithms are provided
To create a new one, it is easiest to duplicate the
appropriate base one if it exists and modify it
The basic Java elements of a new algorithm are:
An _Impl class, the hand-coded implementation class
that contains the logic
A _Gen class, the implementation class for the soft
parameters, generated by the artifact generator
A component interface class, generated by the AG
A message method, if required

244
Algorithm Phone Format Example

2
3
4

This Impl classs annotation specifies


1. The soft parameters expected by the algorithm these correspond
with the Algorithm Type parameter definitions
2. Has an Algorithm Component name (as specified on the Algorithm
Type) + _Impl

245
Algorithm Phone Format Example

2
3
4

The class name


3. Extends the _Gen class the _Gen class is generated by the
Artifact Generator
4. Implements the base Algorithm Spot class for the algorithm type

246
Algorithm Phone Format Example
Algorithm Spot interface methods that are implemented in _Impl class

These methods are invoked by the business component


to set the hard parameters
1. This sets the phone number to validate it is stored here for use later
2. This sets the phone type this method here is empty because it is
ignored in this algorithm

247
Algorithm Phone Format Example
Algorithm Spot interface methods that are implemented in _Impl class

The invoke() method is called to validate and format the


phone number
1. This sets a Boolean based on the validity of the phone number

248
Algorithm Phone Format Example
Algorithm Spot interface methods that are implemented in _Impl class
1

These methods are called from the business component


after the invoke() method
1. This returns a true/false to indicate the validity of the phone number
(you may have noted that this Boolean is the one set in the invoke method)
2. This returns the reformatted value, also formatted in invoke()
249
Algorithm Phone Format Example
Algorithm Spot interface methods that are implemented in _Impl class
1

These methods are called from the business component


after the invoke() method
3. This returns the default phone format in this case it is always the
first one (e.g. 1st format for U.K. 999 9999-9999)

250
Algorithm Phone Format Example
Generated artifacts that are based on the _Impl class annotation

The _Gen class has the methods for the soft parameters
The _Impl class calls these methods to get the soft parameter
values, as set on the Algorithm definition
251
Algorithm Phone Format Example
Generated artifacts that are based on the _Impl class annotation

The component interface defines the required methods


for the _Impl class as viewed from the application (the
business component)

252
Algorithm Phone Format Example
Generated artifacts that are based on the _Impl class annotation

1
2

1. The Artifact Generator also generates a static Factory class in the


component interface class file
2. It has the newInstance method to create an instance of the algorithm
component at runtime

253
Algorithm Implementation Class Review
The steps to create a new algorithm class are
1. Determine the Algorithm Spot interface name the Javadocs could
be used for this
2. Create the _Impl class, implementing the appropriate Algorithm
Spot interface
3. Add default implementations for all the Algorithm Spot methods (e.g.
using the Eclipse Source, Override/implement Methods menu item)
4. Code the annotation
5. Run the Artifact Generator to create the _Gen and component
interface classes

In Eclipse, you MUST refresh the project


after this!

254
Algorithm Implementation Class Review
The steps to create a new algorithm class are
6. Edit the _Impl class and
Extend the _Gen class on the class definition
Store the required instances variables in the appropriate set methods
(these instance variables will be referenced in the invoke() method)
Code the invoke() method this contains the main logic
Return the value(s) in the get methods as required by the Algorithm
spot
7. Create the cm.jar file and shutdown and restart the application server
this is necessary for the Java class to be visible when creating the
Algorithm Type definition (next step)
8. Create the Algorithm Type definition the Java class name will now
be in the Program Name drop-down list AND will automatically insert
the Algorithm Type parameters from your annotation specification

NOTE: This is the reason for creating the Java impl class BEFORE
adding the Algorithm Type and Algorithm definitions in the UI

255
Algorithm Implementation Class Review
The steps to create a new algorithm class are
9. Create the Algorithm definition
10. Attach the algorithm to the business component
11. Test

256
Exercise 8 Geographic Type Algorithm
All Students
In this exercise you will create a Geographic Type algorithm to
validate geographic type REGION on Premise
Consider the following scenario
1. Premises may be in North America or Europe
2. Within North America, the country may be U.S.A. or Canada
3. Within Europe, the country may be United Kingdom or France
4. A geographic type of region must be created to allow for the region code to
be specified on Premise
5. The format of region code is W-CC, where
W = World Region N (North America); E (Europe)
CC = Country Code US (USA); CN (Canada); UK (UK); FR (France)

The algorithm must validate that the country code falls within its region
for example E-FR is valid; E-US is invalid

257
Exercise 8 Geographic Type Algorithm
All Students (continued)
6. The valid region code values must be specified as soft parameters i.e. no
hardcoding of values in Java are allowed
Java Requirements
The Algorithm Spot to implement is GeoTypeFormatValidationAlgorithmSpot
Name your class CmGeoTypeRegionAlgComp_Impl in package
com.splwg.cm.domain.common.geographicType
Create 2 parameters
1. worldRegion, string, required
This will contain the 1-digit world region code
2. countryCodes, string, required
This will contain a comma-delimited string of valid country codes for their
associated world region code

258
Exercise 8 Geographic Type Algorithm
Online Configuration
Create Algorithm Type XXGEOREGION (where XX are your initials)
The Algorithm Entity is Geographic Type Value Format Rule
Program Type is Java
Program Name should be CmGeoTypeRegionAlgComp

Create two Algorithm definitions


1. XXGEOREG-E (where XX are your initials)
Specifies Europe and its valid countries
2. XXGEOREG-N (where XX are your initials)
Specifies North America and its valid countries

Create two new Geographic Type definitions, using the following values for
Type, Description and Format Algorithm respectively
1. XXREG-E, Region Europe (XX), XXGEOREG-E (where XX are your initials)
2. XXREG-N, Region North America (XX), XXGEOREG-N (where XX are your
initials)

259
Exercise 8 Geographic Type Algorithm
Online Configuration (continued)
From your browser, use URL http://localhost:6800/flushDropDownCache.jsp
to delete the drop-down cache on the server, and then clear the browser
cache by deleting your temporary internet files to make the new Geographic
Types known to the Premise Geographic Data page
(Note: localhost and 6800 above refer to the server name and port of your
web application server it may be named differently in your specific case)

Test
When adding or changing a Geographic Type on Premise, the
algorithm should validate the format and content of geo type and
display the generic message Premise Geographic Value format
incorrect if invalid
Optional
The JUnit test class for this exercise should check all possible
combinations of invalid world regions and country codes, but we will
only check two conditions one valid and one invalid

260
Exercise 8 Geographic Type Algorithm
Optional (continued)
Code a JUnit test class for your algorithm (the class must extend
AlgorithmImplementationTestCase) and in the test method e.g.
testGeoTypeRegion
Similar to previous exercises, create a Premise object from an existing
premise on the database
Create a new GeographicType_Id object for one of the geographic types you
defined (e.g. XXREG-E or XXREG-N)
Create a PremiseGeographicLocation_Id object for the Premise_Id (as
instantiated above) and GeographicType_Id
Suspend validation for the following steps
Create a new PremiseGeographicLocation_DTO from the Id above
On the DTO, set the value of GeographicValue (e.g. E-UK)
Add the new GeographicLocation (via the DTO) to the collection of
GeographicLocations for the Premise (note: the add method can also accept
the DTO with the GeographicType_Id (e.g. XXREG-E)

261
Exercise 8 Geographic Type Algorithm
Optional (continued)
Remove the suspension to validate that the data currently entered is valid
an application error is not expected at this point
Remove the existing PremiseGeographicLocation from the collection of
GeographicLocations
Set the GeographicValue to an invalid value (e.g. E-US)
Re-add the PremiseGeographicLocation object to the GeographicLocations
location which should trigger the validation
Catch the ApplicationError and use the following statement to verify that the
correct error was thrown
assertServerMessage(e, 3, 33901);

262
Algorithms
Part II

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


Exercise 9 Adhoc Char Value Algorithm
The algorithm in the last exercise could not reformat
region code the Geographic Type algorithm does not
provide for that
Instead of Geographic Type, in this exercise you will
create an Adhoc Characteristic Value validation
algorithm to validate and format a new Premise
Characteristic Type of either XX-REG-E for Europe or
XX-REG-N for North America (where XX are your
initials)
The scenario is the same as before, except
A Characteristic Type of region must be created (see above)
A country code may be entered without a world region code
The algorithm will format the region code into the W-CC format, even
if no world region code or - is entered
It will display a custom error message for an invalid region code
264
Exercise 9 Adhoc Char Value Algorithm
All Students
Java Requirements
Create a new message constant and method for a runtime message (not
declarative)
The message text should be
Country code %1 not valid for region %2 (XX)
(Where XX are your initials)
Use a message number > 10000
Add a CustomMessages constant for your message
Add a method for the message to your MessageRepository class in the
com.splwg.cm.domain.common.characteristicType package
The message takes 2 parameters world region code and country code the
method must substitute them when setting up the message for display

265
Exercise 9 Adhoc Char Value Algorithm
Java Requirements (continued)
The Algorithm Spot to implement is
AdhocCharacteristicValueValidationAlgorithmSpot
Name your class CmAdhocRegionValidationAlg_Impl in package
com.splwg.cm.domain.common.characteristicType
Create the same two parameters as before in your annotation
The invoke() method must
1. Format the region code for example
CN must be formatted to N-CN
EFR must be formatted to E-FR
2. The setFormatOnly() method is invoked from the framework to indicate whether a
format AND validate is required, or just a format. If it had been invoked with true,
return from the invoke method after the region code has been formatted,
otherwise validate it as well
3. Display the custom error message if the region code is invalid the method to
display the error is addError(ServerMessage serverMessage)

266
Exercise 9 Adhoc Char Value Algorithm
Online Configuration
Create Algorithm Type XX-AV-REGION with the necessary parameter
definitions (the Algorithm Entity is Characteristic Type Adhoc Value
Validation
Create 2 Algorithm definitions
1. XX-AV-REG-E - specifies Europe and its valid countries
2. XX-AV-REG-N - specifies North America and its valid countries
Create 2 Characteristic Type definitions
1. XX-REG-E to validate the European region
2. XX-REG-N to validate the North American region

Both must be of type Adhoc Value


The Characteristic Entity (2nd Tab) must be Premise
Create a new message in category 90000
Country code %1 not valid for region %2 (XX)
(Where XX are your initials)

267
Exercise 9 Adhoc Char Value Algorithm
Test
When adding or changing a Premise Characteristic of region, the
algorithm should format the region code, validate it and display your
custom message if invalid

Optional
Create a JUnit test class to validate that the region characteristic
being formatted and validate correctly
Copy the previous exercises test class and modify it to reference the
Characteristic classes instead of the GeographicLocation ones
Because the algorithm also formats the adhoc characteristic value, you
should check that the formatting is working for example, set your adhoc
characteristic value to UK (without E-); this should pass validation

268
SPL Batch
Part I

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


SPL Batch I
In this section we will look at
A brief overview of the SPL batch environment
An overview of batch controls
Batch programming in Java

270
Batch Environment
Batch programs run outside of the web app
server, but still within the context of the
framework
The framework provides access to the business
entities and other objects
Therefore, ALL programs run under Java even
COBOL
For COBOL, all SQL calls are handled by the
framework there are no direct calls from
COBOL to Oracle/DB2/SQL Server (e.g. via
PRO*Cobol)
271
Batch Threading
The system uses threading to achieve maximum
performance
What does a threaded process do?
It determines the full workload (e.g. how many accounts?)
It divides the workload into n number of threads
It dispatches each thread to perform the workload the
workloads are executed concurrently
For example, instead of one task billing 50000
accounts, 5 tasks can each bill 10000 accounts
simultaneously this is naturally much faster
The Artifact Generator creates the necessary
components for multi-threading
272
Batch Control
Batch controls are used in batch processing to
control restartibility, program identification,
parameters, etc.
Each batch process has its own batch control
code
A batch control code defines
The program name
The program type (COBOL / Java)
The batch parameters

For example
273
Batch Control Java Example
1

2
3

4
5

1. The Batch Control code


2. The Program Type
3. The Program Name

274
Batch Control Java Example
1

2
3

4
5

4. The batch run number (for this batch control) of the next submission
5. Check this to accumulate the records processed counts for all
instances of one job if the job fails and restarts, it will add the
failed + restarted instances for the total records processed
should be unchecked for programs that work with flat files
275
Batch Control Java Example
1

2
3

4
5

6. These are the non-standard parameters for the batch process these
parameters are prompted for after the standard parameters
They are supplied at runtime using name=value pairs, for example
FILE-PATH=/spl/data
276
Batch Process Overview
A background process consists of 2 types of
classes
1. A BatchJob
2. A ThreadWorker

The BatchJob class determines the work to be


processed and splits it into pieces based on a
thread count
Each piece of work is processed by an
instance of ThreadWorker
Lets take a look at these two components

277
Batch Process Overview

BatchJob determines the work and divides it into manageable chunks


(ThreadWork)
Each ThreadWork consists of WorkUnits
WorkUnits represent fine-grained units of work e.g. one bill
278
Batch Process Overview

The ThreadWorker is responsible for processing a single ThreadWork


instance
Each ThreadWorker corresponds to one batch instance row on the
database, which is used for restart after failure
279
The BatchJob Class
The BatchJob class consists of an annotation
and a number of standard methods that the
framework uses to invoke and communicate with
a batch process
Lets take a look at these components of a
BatchJob class

280
BatchJob Class Annotation
A BatchJob class annotation looks as follows
@BatchJob (rerunnable = false, 1
2 multiThreaded = true,
3 modules={todo},
4 softParameters = { @BatchJobSoftParameter
(name=OUTPUT-DIR, type=string) },
5 toDoCreation = @ToDoCreation (
drillKeyEntity = user,
sortKeys = {lastName, firstName},
messageParameters = {firstName, lastName}
)
)

1. rerunnable indicates if the job can be re-run e.g. bill


print extract can be re-run
2. multiThreaded tells the framework if job can be submitted
in multiple threads i.e. if it will accept a thread count > 1
3. modules contains the modules the program belongs to
this should be empty for customizations
281
BatchJob Class Annotation
A BatchJob class annotation looks as follows
@BatchJob (rerunnable = false, 1
2 multiThreaded = true,
3 modules={todo},
4 softParameters = { @BatchJobSoftParameter
(name=OUTPUT-DIR, type=string) },
5 toDoCreation = @ToDoCreation (
drillKeyEntity = user,
sortKeys = {lastName, firstName},
messageParameters = {firstName, lastName}
)
)

4. These are the non-standard parameters to prompt for


when the job starts
5. This specifies how the ToDo entries should be created if
application errors are found

282
BatchJob Class Definition
The BatchJob class must extend class
<BatchJob class Name>_Gen, for example

public class BatchErrorToDoCreation


extends BatchErrorToDoCreation_Gen {

The _Gen class is generated by the artifact


generator based on the BatchJob annotation

283
BatchJob Class Public Methods
The following standard public methods must exist in a
BatchJob class
Method getJobWork()
This method determines the workload (using a Hibernate query)
It passes back to the framework an instance of JobWork, describing
the work to be done
The JobWork instance contains the appropriate number of
ThreadWork instances (based on the runtime thread count)
Each ThreadWork instance contains the same number of
ThreadWorkUnits
The good news: a convenience framework method exists to
handle this for you!

284
BatchJob Class Public Methods
Method getThreadWorkerClass()
This method passes back to the framework the class name of the
worker class i.e. the hand-coded class that will perform the batch
work
The framework will create an instance of this class for each
ThreadWork instance i.e. each thread
Passing back the class name (instead of an object) allows the
framework to control the instantiation of the ThreadWorker classes so
that they can be executed anywhere, even on different servers

285
The ThreadWorker Class
The ThreadWorker class is responsible for processing a single
ThreadWork instance in other words, it performs the heavy
lifting
A ThreadWorker can be executed on the same, or a different, server
as its associated BatchJob and other ThreadWorker instances
A ThreadWorker class must extend the artifact-generated class
<ThreadWorker class name>_Gen (the example below illustrates)
By convention a ThreadWorker class is coded as a static inner class
in its parent BatchJob class
public class BatchErrorToDoCreation
extends BatchErrorToDoCreation_Gen {
... BatchJob methods ...
public static class BatchErrorToDoCreationWorker
extends BatchErrorToDoCreationWorker_Gen {
... ThreadWorker methods ...
}
}

286
ThreadWorker Class Public Methods
The following standard public methods are
implemented in a ThreadWorker class

287
ThreadWorker Class Public Methods
Method createExecutionStrategy()
This methods tells the framework how the work for thread will be
processed
It returns to the framework an instance of ThreadExecutionStrategy,
of which the following implementations currently exist
1. SingleTransactionStrategy
This tells the framework to process all work in single transaction (logical
unit-of-work)
Failure results in a rollback of the entire threads updates
It is most appropriate for jobs that CANNOT tolerate errors in the middle
of a run, for example interfaces from flat files
2. CommitEveryUnitStrategy
This tells the framework to process each ThreadWorkUnit (e.g. one bill)
in its own transaction and to issue a commit after each successful
completion
It is most appropriate for jobs that CAN tolerate errors e.g. Billing

288
ThreadWorker Class Public Methods
Method InitializeThreadWork(boolean)
This is called by the framework at the start of a thread run to perform
initialization
By default it does nothing, but can be overridden to open files,
initialize variables, etc.
A Boolean parameter indicates if it was called previously
Method executeWorkUnit(ThreadWorkUnit)
This is invoked once for each ThreadWorkerUnit assigned to a
ThreadWorker
For example, for a thread processing 1000 accounts, this method will
be called 1000 times
It performs the actual work, for example to process an account for
billing
The ThreadWorkUnit parameter is a reference to the Business Entity
to be processed you use this parameters getPrimaryId method to
get the business entitys Id object
289
ThreadWorker Class Public Methods
Method finalizeThreadWork()
This method is called at the end of thread processing
It can be used to clean up after a thread, for example to
close files

These are the basic building blocks for a batch


class
Lets take a look at a complete example that creates
ToDos for batch runs that ended in error

290
BatchJob Example Create Batch Error ToDos
The annotation and class definition
/**
* @BatchJob (rerunnable = false,
* multiThreaded = false, 1
* modules={todo})
*/
public class CmBatchErrorToDoCreation
extends CmBatchErrorToDoCreation_Gen { 2
private static final com.splwg.shared.logging.Logger logger =
3 com.splwg.shared.logging.LoggerFactory.
getLogger(CmBatchErrorToDoCreation.class);
...

1. The BatchJob annotation specifies this job is not rerunnable, not


multi-threaded and a ToDo module (remember, for a custom batch
class, modules should be empty i.e. {})
2. The class extends its associated _Gen class
3. This is a static definition of the Log4j logger to log messages at
runtime (Note: You really should not log application messages to the
system log, but for these exercises we will)
291
BatchJob Example Create Batch Error ToDos
The BatchJob methods
public JobWork getJobWork() {
1 Query errorRunQuery = createQuery("from BatchRun run +
where run.runStatus = :runStatus");
2 errorRunQuery.bindLookup("runStatus",
RunStatusLookup.constants.ERROR);
3 return createJobWorkForEntityQuery(errorRunQuery);
}

public Class getThreadWorkerClass() {


4 return CmBatchErrorToDoCreationWorker.class;
}

1. The getJobWork method sets up query for the work this query
retrieves BatchRun objects (CI_BATCH_RUN) that have an error
status
2. It sets the runStatus bind variable in the query to the lookup constant
ERROR

292
BatchJob Example Create Batch Error ToDos
The BatchJob methods
public JobWork getJobWork() {
1 Query errorRunQuery = createQuery("from BatchRun run +
where run.runStatus = :runStatus");
2 errorRunQuery.bindLookup("runStatus",
RunStatusLookup.constants.ERROR);
3 return createJobWorkForEntityQuery(errorRunQuery);
}

public Class getThreadWorkerClass() {


4 return CmBatchErrorToDoCreationWorker.class;
}

3. By passing the query to the convenience method


createJobWorkForEntity, it returns to the framework a JobWork
object which will contain an array of ThreadWork objects, each with
ThreadWorkerUnits
4. The getThreadWorkerClass method returns to the framework the
name of the ThreadWorker class this class is defined as an inner
class (as well see on the next slide)
293
BatchJob Example Create Batch Error ToDos
The inner ThreadWorker class definition
public static class CmBatchErrorToDoCreationWorker
extends CmBatchErrorToDoCreationWorker_Gen {
...

The class is defined in the same source file as the


BatchJob class and is therefore an inner class
This is the class whose name is passed back to the
framework in the getThreadWorkerClass method as
seen on the previous slide
It extends its associated _Gen thread worker class, which
is created by the artifact generator

294
BatchJob Example Create Batch Error ToDos
Inner ThreadWorker method createExecutionStrategy
public ThreadExecutionStrategy createExecutionStrategy() {
// Commit on every todo. This is not expected to be a
// performance intensive process.
return new CommitEveryUnitStrategy(this);
}

createExecutionStrategy passes back to the framework


an object of type CommitEveryUnitStrategy, which tells
the framework that the job wants to commit after each
transaction
A transaction in this case is after each ToDo has been
created

295
BatchJob Example Create Batch Error ToDos
Inner ThreadWorker method initializeThreadWork
public void initializeThreadWork(
boolean initializationPreviouslySuccessful)
throws ThreadAbortedException, RunAbortedException {
// determine the ToDoType_Id that should be used by querying
// the ToDoTypes for an entry with the creation process equal
// to this one.
Query toDoTypeQuery = createQuery("from ToDoType type
where type.creationProcessId = :thisBatchControlId");
...
initializeThreadWork here determines the ToDo type to be
used by the executeWorkUnit method (next slide) when it
creates the ToDos

296
BatchJob Example Create Batch Error ToDos
Inner ThreadWorker method executeWorkUnit
1 public boolean executeWorkUnit(ThreadWorkUnit unit)
throws ThreadAbortedException, RunAbortedException {
2 BatchRun_Id errorBatchRunId = (BatchRun_Id) unit.getPrimaryId();
// get the run
3 BatchRun batchRun = errorBatchRunId.getEntity();
...
4 createToDo(batchRun);
...

1. executeWorkUnit is called for each batch run in error,


based on the initial query
2. It gets the primary Id from the ThreadWorkUnit object
parameter and casts it to a BatchRun_Id class
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
297
BatchJob Example Create Batch Error ToDos
Inner ThreadWorker method finalizeThreadWork
public void finalizeThreadWork()
throws ThreadAbortedException, RunAbortedException {
}

This example does not implement the finalizeThreadWork


method

298
BatchJob Creation Review
Before we get to the exercise, lets review how to create
a new BatchJob class
1. Create the class file and code the annotation
2. Run the Artifact Generator to create the _Gen classes (you must
refresh the Eclipse project after the AG has run)
3. Extend the class from the _Gen BatchJob class
4. Code the getJobWork and getThreadWorkerClass methods
5. Create the inner ThreadWorker class - extend it from the _Gen
ThreadWorker class
6. Code the createExecutionStrategy method
7. Code the initializeThreadWork method (if needed)
8. Code the executeWorkUnit method
9. Code the finalizeThreadWork method (if needed)
10. Create the batch control
299
Exercise 10 Batch 1
All Students
Create a batch program to identify Persons without Accounts and
display their details on the log
Name the program CmPersonsNoAccount in package
com.splwg.cm.domain.batch
Identify the persons as follows
from Person as per where not exists (from AccountPerson ap
where ap.id.person = per)

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 (sequence 1)
Display both the Person Id and the Entity Name on the log using the
logger.info() method the output should look like this
Person without Account: 4470529669 French,John
Person without Account: 3909447990 Reliable Energy
...
300
Exercise 10 Batch 1
All Students (continued)
Add a new batch control using the online Admin menu use batch code
XXPNOA (where XX are your initials)

Test
Use the Batch - Training launch configuration from Eclipse to run
your job
The following run parameters should be specified:
Batch Code: Your batch code (e.g. XX-PNOA)
Batch Thread Number: 1
Batch Thread Count: 1
User ID: SPL
User Password: spladmin
Language Code: ENG
Take the defaults for all the other parameters (i.e. hit Enter when prompted)

301
SPL Batch
Part II

SPL Technical Training

Copyright 2007, Oracle. All rights reserved.


SPL Batch II - ToDos
In this section we look at how to create ToDos
in a batch process
FYI: The previous example
(CmBatchErrorToDoCreation) class does that
It runs through all the batch program errors
(CI_BATCH_RUN rows with status = error) and
creates a ToDo for each
The ToDo table structure looks as follows

303
SPL Batch II ToDo Data Model
4 CI_MSG 5 CI_BATCH_CTRL CI_TD_MSG_PARM
C PK
PK
MESSAGE_CAT_NBR
MESSAGE_NBR
PK BATCH_CD
PK,FK1 TD_ENTRY_ID P
PK SEQ_NUM
O FK1 TD_TYPE_CD
PROGRAM_NAME R
MSG_PARM_VAL
N O
2 CI_TD_DRLKEY_TY
F PK,FK1 TD_TYPE_CD
1 CI_TD_TYPE CI_TD_ENTRY CI_TD_DRLKEY
G
PK TD_ENTRY_ID PK,FK1 TD_ENTRY_ID
I PK SEQ_NUM PK TD_TYPE_CD
PK SEQ_NUM R
CRE_BATCH_CD FK1 TD_TYPE_CD
G FLD_NAME
TBL_NAME FK1 MESSAGE_CAT_NBR KEY_VALUE
A
FK1 MESSAGE_NBR
U 3 CI_TD_SRTKEY_TY FK2 BATCH_CD CI_TD_SRTKEY M
R PK,FK1
PK
TD_TYPE_CD
SEQ_NUM
PK,FK1
PK
TD_ENTRY_ID
SEQ_NUM
M
E DEFAULT_SW KEY_VALUE E
D ORDER_FLG
D
The tables on the left are populated via the Admin menu
1. ToDo Type identifies the type of ToDo
2. Drill Key Type identifies which page to jump to when the user selects
a ToDo to work on
3. Sort Key Type determines how the ToDo list is sorted

304
SPL Batch II ToDo Data Model
4 CI_MSG 5 CI_BATCH_CTRL CI_TD_MSG_PARM
C PK
PK
MESSAGE_CAT_NBR
MESSAGE_NBR
PK BATCH_CD
PK,FK1 TD_ENTRY_ID P
PK SEQ_NUM
O FK1 TD_TYPE_CD
PROGRAM_NAME R
MSG_PARM_VAL
N O
2 CI_TD_DRLKEY_TY
F PK,FK1 TD_TYPE_CD
1 CI_TD_TYPE CI_TD_ENTRY CI_TD_DRLKEY
G
PK TD_ENTRY_ID PK,FK1 TD_ENTRY_ID
I PK SEQ_NUM PK TD_TYPE_CD
PK SEQ_NUM R
CRE_BATCH_CD FK1 TD_TYPE_CD
G FLD_NAME
TBL_NAME FK1 MESSAGE_CAT_NBR KEY_VALUE
A
FK1 MESSAGE_NBR
U 3 CI_TD_SRTKEY_TY FK2 BATCH_CD CI_TD_SRTKEY M
R PK,FK1
PK
TD_TYPE_CD
SEQ_NUM
PK,FK1
PK
TD_ENTRY_ID
SEQ_NUM
M
E DEFAULT_SW KEY_VALUE E
D ORDER_FLG
D
The tables on the left are populated via the Admin menu
4. Message specifies the message to show in the ToDo list
5. Batch Control contains the batch control of the job that created the
ToDo

305
SPL Batch II ToDo Data Model
CI_MSG CI_BATCH_CTRL
4 CI_TD_MSG_PARM
C PK
PK
MESSAGE_CAT_NBR
MESSAGE_NBR
PK BATCH_CD
PK,FK1 TD_ENTRY_ID P
PK SEQ_NUM
O FK1 TD_TYPE_CD
PROGRAM_NAME R
MSG_PARM_VAL
N O
CI_TD_DRLKEY_TY
F CI_TD_TYPE 1 CI_TD_ENTRY 2 CI_TD_DRLKEY
G
PK,FK1 TD_TYPE_CD PK,FK1 TD_ENTRY_ID
PK TD_ENTRY_ID
I PK SEQ_NUM PK TD_TYPE_CD
PK SEQ_NUM R
CRE_BATCH_CD FK1 TD_TYPE_CD
G FLD_NAME
TBL_NAME FK1 MESSAGE_CAT_NBR KEY_VALUE
A
FK1 MESSAGE_NBR
U CI_TD_SRTKEY_TY FK2 BATCH_CD
3 CI_TD_SRTKEY M
R PK,FK1
PK
TD_TYPE_CD
SEQ_NUM
PK,FK1
PK
TD_ENTRY_ID
SEQ_NUM
M
E DEFAULT_SW KEY_VALUE E
D ORDER_FLG
D
The tables on the right are populated programmatically
1. ToDo Entry has one row per ToDo entry and a foreign key to the
ToDo Type
2. Drill Key contains the key value (e.g. person Id) to use for the
navigational drill down when the user selects the ToDo to work on

306
SPL Batch II ToDo Data Model
CI_MSG CI_BATCH_CTRL
4 CI_TD_MSG_PARM
C PK
PK
MESSAGE_CAT_NBR
MESSAGE_NBR
PK BATCH_CD
PK,FK1 TD_ENTRY_ID P
PK SEQ_NUM
O FK1 TD_TYPE_CD
PROGRAM_NAME R
MSG_PARM_VAL
N O
CI_TD_DRLKEY_TY
F CI_TD_TYPE 1 CI_TD_ENTRY 2 CI_TD_DRLKEY
G
PK,FK1 TD_TYPE_CD PK,FK1 TD_ENTRY_ID
PK TD_ENTRY_ID
I PK SEQ_NUM PK TD_TYPE_CD
PK SEQ_NUM R
CRE_BATCH_CD FK1 TD_TYPE_CD
G FLD_NAME
TBL_NAME FK1 MESSAGE_CAT_NBR KEY_VALUE
A
FK1 MESSAGE_NBR
U CI_TD_SRTKEY_TY FK2 BATCH_CD
3 CI_TD_SRTKEY M
R PK,FK1
PK
TD_TYPE_CD
SEQ_NUM
PK,FK1
PK
TD_ENTRY_ID
SEQ_NUM
M
E DEFAULT_SW KEY_VALUE E
D ORDER_FLG
D
The tables on the right are populated programmatically
3. Sort Key contains the value(s) to sort on (e.g. person name)
4. Message Parameter contains the values for message substitution

307
Exercise 11 Batch 2
All Students
Modify the previous exercises class to create ToDo entries for
Persons without Accounts
The ToDo creation methods to populate the right-sided tables as described
on the previous slide have too much complexity for this course, so the
instructor will supply a template for the ToDo creation methods you can
simply copy and paste those into your class
The supplied methods are
public void initializeThreadWork
private boolean toDoAlreadyExists
private void createToDo
private void addDrillKeyValue
private void addSortKeyValue
private void addMessageParameter

308
Exercise 11 Batch 2
All Students (continued)
In your executeWorkUnit method
As in the previous exercise, determine the Person_Id and PersonName_Id values
Using the supplied method, determine if the ToDo already exists and, if so, write a
message to the system log indicating such and return with a Boolean of true
Optionally, write a message to the system log to show the person id and name
being added to the ToDo
Use the supplied method to create the ToDo entry

Follow the instructions over the following slides to add the


configuration data for the batch control, message and ToDo

Important note: Over the following slides, all the examples


specify names that contain XX. To avoid overwriting
another students definitions, substitute XX in all cases with
your own 2-digit initials

309
Exercise 11 Batch 2
All Students (continued)
Create new batch control XX-TDPNA

Create new message Person %1 has no Accounts (XX)

310
Exercise 11 Batch 2
All Students (continued)
Create new ToDo type XXTDPNA Main tab

ToDo Type XXTDPNA Roles tab

311
Exercise 11 Batch 2
All Students (continued)
ToDo Type XXTDPNA Sort Keys tab

ToDo Type XXTDPNA Drill Keys tab

312
Exercise 11 Batch 2
Test
Use the Batch - Training launch configuration from Eclipse to run
your job
Verify in the online system that it created a ToDo entry for each
Person identified as not having an Account
It should show the message with person name substituted
It should be sorted in person name ascending sequence
You should be able to drill into a person from the ToDo list
With this exercise we do not create a JUnit test class, but it can be
done in one of two ways
1. Extending the BatchJobTestCase class and implementing abstract methods
2. Calling the submitBatchJob(SubmissionParameters) method in any
ContextTestCase - this allows testing a mix of one or more background
process and other business logic to be tested
In both cases, the database does not get updated
313
Exercise 11 Batch 2
Test (continued)
Note: When testing your batch class and an error occurs, run the
following delete statements before re-executing your batch class
these statements will delete all previously created ToDo entries to
prepare for the re-run

delete from ci_td_drlkey


where td_entry_id in (select td_entry_id from ci_td_entry
where td_type_cd = XXTDPNA');
delete from ci_td_srtkey
where td_entry_id in (select td_entry_id from ci_td_entry
where td_type_cd = XXTDPNA');
delete from ci_td_msg_parm
where td_entry_id in (select td_entry_id from ci_td_entry
where td_type_cd = XXTDPNA');
delete from ci_td_entry where td_type_cd = XXTDPNA'

314
The End

Thank You

315

Anda mungkin juga menyukai