Sei sulla pagina 1di 315

<Insert Picture Here> Technical Training

V2 for Developers
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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Introducing the Framework

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 framework’s data access layer
– application programs do not issue direct calls to database

© 2010 Oracle Corporation - Propietary and Confidential


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.

© 2010 Oracle Corporation - Propietary and Confidential


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 SPL’s “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

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Services

© 2010 Oracle Corporation - Propietary and Confidential


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 service’s 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 …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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.

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


COBOL Services

• SPL’s 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 SPL’s implementation of COBOL
services

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 framework’s
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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Inside COBOL Services
• As example, this shows the Person object maintenance in
COBOL
• We’ll 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 – we’ll
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

© 2010 Oracle Corporation - Propietary and Confidential


COBOL Services – Recap

• COBOL will continue to be maintained and


supported
• Programmers should in future use Java to code
extensions
• Let’s take a quick look at Java services …

© 2010 Oracle Corporation - Propietary and Confidential


Java Services

• Some services are now coded entirely in Java


• These are mostly Admin services – for example
– AlgorithmType
– SA Type
– Characteristic Type
– etc.

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Java Services
• The Java service invokes the maintenance, list or search
objects to satisfy the Web servlet’s 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Business Entities

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Business Entity and Related Classes
• Let’s 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()()

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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


Oracle’s Java Persistence Framework Person_Gen
-id

(JPF) & Hibernate. JPF & Hibernate are -address1


+getId()
+getAddress()
discussed in detail later, but we will «interface»
Person
see more references to them over the +getId() Person_Impl
+getAddress1()
following slides +getInfo()
+getDTO()()
+getInfo()

+setDTO()()

© 2010 Oracle Corporation - Propietary and Confidential


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
PER_ID ADDRESS1 …
id = 1550000001
address1 = Easy Street 1550000001 Easy Street …

Person : Person_Impl 7804500002 Penny Lane …


id = 7804500002 …
address1 = Penny Lane

© 2010 Oracle Corporation - Propietary and Confidential


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 framework’s discretion –
the application code has no direct control over it

Person : Person_Impl
PER_ID ADDRESS1 …
id = 1550000001
address1 = Easy Street 1550000001 Easy Street …

Person : Person_Impl
7804500002 Penny Lane …
id = 7804500002 …
address1 = Penny Lane

© 2010 Oracle Corporation - Propietary and Confidential


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 person’s 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
– getDTO() retrieves an instance of a Data Transfer Person_Gen

Object (DTO) for the Business Entity -id


-address1
+getId()
+getAddress()

«interface»
Person
More about Ids and DTOs in a +getId() Person_Impl

minute…
+getAddress1()
+getInfo() +getInfo()
+getDTO()()
+setDTO()()

© 2010 Oracle Corporation - Propietary and Confidential


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
-id
-address1
+getId()
+getAddress()

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

© 2010 Oracle Corporation - Propietary and Confidential


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:
AbstractDataTransferObject
String emailAddress = perDTO.getEmailAddress();
...
perDTO.setEmailAddress(emailAddress);

Person_DTO

© 2010 Oracle Corporation - Propietary and Confidential


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, AbstractDataTransferObject


but the database update & commit happen
at the discretion of the framework

Person_DTO

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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: «interface»


SimpleEntityList
AbstractEntityList

– Sequentially retrieved
– Removed
– Added
PersonNames_Impl
«interface»
PersonNames
+add()
+remove()

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Artifact Generator

© 2010 Oracle Corporation - Propietary and Confidential


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 –
upcoming exercises will illustrate this
• We’ll discuss annotations next
Person_Gen
-id
-address1
+getId()
+getAddress()

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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Class Annotations

Here’s an example:
/**
@SampleAnnotation (
simpleString = value,
complexString = "A string with spaces",
boolean = true,
arrayOfStrings = {abc, def, "g h i" },
fkAnnotation = @NestedAnnotation ( property = value ),
arrayOfAnnotations = { @ChildAnnotation (name=first),
@ChildAnnotation (name=second)}
)
*/
public class ExampleClass {
....
}

1. Java-doc comments
2. Annotation name
3. Property-value pairs – strings and Booleans
4. Array of annotations

© 2010 Oracle Corporation - Propietary and Confidential


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 handler’s 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

© 2010 Oracle Corporation - Propietary and Confidential


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 …

© 2010 Oracle Corporation - Propietary and Confidential


The Software Development Kit
(SDK)

© 2010 Oracle Corporation - Propietary and Confidential


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
• Let’s take a look at the SDK in more detail …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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
generator’s metadata references

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 workstation’s 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

Let’s take a look at these two folders in more detail

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Development Workstation for Training

• Everything we’ve 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
• Let’s take a look at the additional training folders …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 won’t necessarily
need to reference this folder

© 2010 Oracle Corporation - Propietary and Confidential


What next?

• Next we will walk through the Eclipse SDK to


configure it for the training and become familiar
with some of it’s basic features …

© 2010 Oracle Corporation - Propietary and Confidential


Introduction to Eclipse

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


The Eclipse SDK – Walkthrough
• Close the Welcome tab if it’s shown

• Go to Window -> Preferences… and in the filter text


box (top-left corner), type “linked res”

• Click on the Linked Resources node

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Eclipse Walkthrough – Linked Resources

• Click OK to save the “asBase” path variable


• Next we will import the Training project …

© 2010 Oracle Corporation - Propietary and Confidential


Eclipse Walkthrough – Import Training

• Go to menu File -> Import…


• Select “Existing Projects
into Workspace”
• Click Next

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


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”

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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!

© 2010 Oracle Corporation - Propietary and Confidential


What next?

• Now that we have some knowledge of the folder


structures and tools, we are ready to try a few
customizations …

© 2010 Oracle Corporation - Propietary and Confidential


Customizations

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers
Part I

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers I – Example 1

/**
* @ChangeHandler (entityName = characteristicType)
*/
public class CmCharacteristicType_CHandler
extends AbstractChangeHandler {
...
}

© 2010 Oracle Corporation - Propietary and Confidential


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
• We’ll take a look at validation first
• The topic of cascading changes requires
knowledge of Hibernate persistence and HQL –
will leave that for later

© 2010 Oracle Corporation - Propietary and Confidential


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 (can’t
update)
– It insures all validations are performed on a complete set of
changes

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Unit Testing

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

• Let’s take a look at the code for this example …

NOTE: saveChanges() does not issue commit to database!

© 2010 Oracle Corporation - Propietary and Confidential


Unit Testing – Example: Defer Validation

1 startChanges();
Person_DTO perDTO = (Person_DTO)this.createDTO(Person.class);
Person_Id perId = new Person_Id(“1234567890”);
perDTO.setId(perId);
2 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);
4 PersonName perName = perNameDTO.newEntity();
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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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
• Let’s see how a test is created …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


Unit Testing - JUnit

Let’s add some code to test our “email required” rule …


1 public void testEmailRequiredRule() {
Person_Id perId = new Person_Id("5775933103");
2 Person person = perId.getEntity();
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

© 2010 Oracle Corporation - Propietary and Confidential


Unit Testing - JUnit
So let’s add some more code …

1 public void testEmailRequiredRule() {


...
try {
Person_DTO badDTO = person.getDTO();
badDTO.setEmailAddress(null);
person.setDTO(badDTO);
fail("a validation error should have been thrown");
2 } catch (ApplicationException exception) {
// Make sure the correct rule was violated.
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 Person’s DTO to trigger validation

© 2010 Oracle Corporation - Propietary and Confidential


Unit Testing - JUnit
So let’s add some more code …

public void testEmailRequiredRule() {


...
try {
Person_DTO badDTO = person.getDTO();
badDTO.setEmailAddress(null);
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

© 2010 Oracle Corporation - Propietary and Confidential


Unit Testing - JUnit
Here’s 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers
Part II

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers II – Conditional Validation
Example – email address required if life support flag is set

1 public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {


return RequireRule.ifReferenceEqualsValue(
"Person:Email address is required if life support is active",
2 "Email address is required if life support is active",
Person.properties.emailAddress,
3 Person.properties.lifeSupportSensitiveLoad,
LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
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

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers II – Conditional Validation
Example – email address required if life support flag is set
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,
4
LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
com.splwg.base.domain.StandardMessages.fieldMissing());
5
}

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

© 2010 Oracle Corporation - Propietary and Confidential


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 it’s 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 it’s conditional – e.g.
cityRequiredIfCountyNotSFRule
Test
• Update your JUnit test class from exercise 2 to test the
conditional validation

© 2010 Oracle Corporation - Propietary and Confidential


Base Messages

© 2010 Oracle Corporation - Propietary and Confidential


Message Categories
• ALL application messages are stored in the
framework’s message repository (the message
text is not embedded in the source code)

• Messages are grouped into


categories
• Use menu Admin -> M -> Message
to view/update the message
categories
• The list here shows the standard
message categories

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

• For example, the StandardMessages class contains …


1. The category number definition for the standard messages
2. All the standard message numbers

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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”

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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
• We’ll see in a moment how to use a runtime message …

© 2010 Oracle Corporation - Propietary and Confidential


Custom Messages

© 2010 Oracle Corporation - Propietary and Confidential


Custom Messages – Creating …

• Over the following slides, we’ll 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, let’s look at creating the message online …

© 2010 Oracle Corporation - Propietary and Confidential


Custom Messages – Creating …
• ONLY category 90000, Implementer’s
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

© 2010 Oracle Corporation - Propietary and Confidential


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
• Let’s take a closer look …

© 2010 Oracle Corporation - Propietary and Confidential


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;
private static MessageRepository instance;
public CustomMessages() {
super(MESSAGE_CATEGORY);
}
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)

© 2010 Oracle Corporation - Propietary and Confidential


Custom Messages – Java Definition
package com.splwg.cm.domain;
import com.splwg.base.domain.common.message.AbstractMessageRepository;
import com.splwg.cm.domain.templates.MessageRepository;
public class CustomMessages extends AbstractMessageRepository {
public static final int MESSAGE_CATEGORY = 90000;
public static final int REQ_IF_CONDITION = 10006;
private static MessageRepository instance;
6 public CustomMessages() {
super(MESSAGE_CATEGORY);
7 }
static MessageRepository getInstance() {
8 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 is a private method that provides the
MessageRepository instance to the to the message methods in the class

© 2010 Oracle Corporation - Propietary and Confidential


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
• Let’s look at the example …

© 2010 Oracle Corporation - Propietary and Confidential


Custom Messages – MessageRepository
MessageRepository class

1 package com.splwg.cm.domain.customerinfo.person;
import com.splwg.cm.domain.CustomMessages;
public class MessageRepository extends CustomMessages {
2 private static MessageRepository instance;
3 private static MessageRepository getInstance() {
4 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 MessageRepository
instance – i.e. an instance of itself - to the message methods that
follow

© 2010 Oracle Corporation - Propietary and Confidential


Custom Messages – Runtime Method
Let’s add a runtime method for our message in the
MessageRepository class

public static ServerMessage requiredIfCondition(String fieldName1,


String fieldName2) {
MessageParameters parms = new MessageParameters();
parms.addField(fieldName1);
parms.addField(fieldName2);
return getInstance().getMessage(REQ_IF_CONDITION, parms);
}

The important method characteristics are …


 The method is static
 It returns a ServerMessage object type for a runtime message
 It has a descriptive method name based on the message it handles
 The parameters correspond with the % variables in the message

© 2010 Oracle Corporation - Propietary and Confidential


Custom Messages – Runtime Method
Let’s add a runtime method for our message in the
MessageRepository class

public static ServerMessage requiredIfCondition(String fieldName1,


String fieldName2) {
MessageParameters parms = new MessageParameters();
parms.addField(fieldName1);
parms.addField(fieldName2);
return getInstance().getMessage(REQ_IF_CONDITION, parms);
}

The important method characteristics are …


 It defines a MessageParameters object to carry the substitution
values for the message
 It adds the substitution values (the parameters) to the
MessageParameters object
 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

The important method characteristics are …


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

© 2010 Oracle Corporation - Propietary and Confidential


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

The important method characteristics are …


 It has a message parameter array for the substitutions in the
message
 OFFENDING_PROPERTY_NAME is a static reference to the field
being validated in the validation rule – we substitute this name into
the message’s 1st parameter
 createDisplayingName gets the name of the LookupProperty value
which we substitute into the message’s 2nd parameter

© 2010 Oracle Corporation - Propietary and Confidential


Custom Messages – Declarative Method
Let’s also add a declarative method for our validation rule
public static ServerMessageTemplate requiredIfCondition(
LookupProperty prop) {
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

© 2010 Oracle Corporation - Propietary and Confidential


Custom Messages – Using Declarative
Using the custom declarative message in a validation rule
public static ValidationRule emailRequiredIfLifeSupportIsYesRule() {
return RequireRule.ifReferenceEqualsValue(
1 "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,
2 MessageRepository.requiredIfCondition(
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

© 2010 Oracle Corporation - Propietary and Confidential


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",
Person.properties.emailAddress,
Person.properties.lifeSupportSensitiveLoad,
LifeSupportSensitiveLoadLookup.constants
.LIFE_SUPPORT_SENSITIVE_LOAD,
3 MessageRepository.requiredIfCondition(
Person.properties.lifeSupportSensitiveLoad));
}

3. The parameter we pass in is the property of the field to substitute the


message’s 2nd parameter

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers
Part III

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers III – Conditions
Conditions can be instantiated from factory methods on certain
properties

1 Condition isPrimaryName = PersonName.properties.isPrimaryName.isTrue();


Condition greaterThan =
2 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers
Part IV

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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
Let’s take a look at an example …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Custom Rule MapFieldNameRequired Example

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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


SPL Framework & Hibernate

© 2010 Oracle Corporation - Propietary and Confidential


SPL Framework & Hibernate - Overview

• SPL’s 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

© 2010 Oracle Corporation - Propietary and Confidential


Hibernate Architecture View

• This generic diagram shows Hibernate


positioned between the application (e.g.
SPL Framework) and the database Application
• The application accesses data via Persistent Objects
Persistent Objects – e.g. the Person
object maps to the CI_PER table,
Account to CI_ACCT, etc.
Hibernate
• The hibernate.properties file specifies
various parameters, for example the hibernate.
XML mapping
properties
database connection
• The XML Mapping files contain the
metadata that describes how to map the Database
DB tables to Java objects
(object/relational mapping)

© 2010 Oracle Corporation - Propietary and Confidential


SPL Framework & Hibernate Architecture

• This diagram shows


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

© 2010 Oracle Corporation - Propietary and Confidential


SPL Framework & Hibernate Architecture

• The Data Transfer Data Transfer


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

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

© 2010 Oracle Corporation - Propietary and Confidential


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 Framework’s
implementation of Hibernate

© 2010 Oracle Corporation - Propietary and Confidential


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;

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 …

© 2010 Oracle Corporation - Propietary and Confidential


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 - it’s 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

© 2010 Oracle Corporation - Propietary and Confidential


Hibernate – Deleting Persistent Objects
• The delete() method of a session removes an object’s 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 let’s take a look at the framework’s implementation of


Hibernate

© 2010 Oracle Corporation - Propietary and Confidential


Hibernate for SPL Framework

• The previous slides show native use of Hibernate


persistent objects and HQL
• As we’ve seen, internally the framework uses
Hibernate for persistence
• The framework’s 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 we’ll review
and add some new things over the following slides

© 2010 Oracle Corporation - Propietary and Confidential


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
– Properties on a Business Entity can only be updated via the
Data Transfer Object (DTO)

© 2010 Oracle Corporation - Propietary and Confidential


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();
while (qIter.hasNext()) {
perEntity = (Person)qIter.next();
...
}

© 2010 Oracle Corporation - Propietary and Confidential


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

… or you create an empty DTO from an “Id” class …


Note: createDTO() is inherited from the parent GenericBusinessObject class
for all Business Entity or Business Component classes (e.g. Change Handlers)

Person_Id perId = new Person_Id("1185477091");


Person_DTO perDTO = perId.newDTO();

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 framework’s HQL text
– The ORDER BY clause is not allowed in the framework’s HQL text
– UNIONs are catered for in the framework’s HQL (native HQL does not
allow it)
– The framework caters for raw SQL statements
• The following slides describe the framework’s implementation
of HQL

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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”

© 2010 Oracle Corporation - Propietary and Confidential


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”

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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
• We’ve only covered a small part – refer to
www.hibernate.org and the SPL SDK
documentation for more details

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers
Part V

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers V – Cascading Changes

• Up to now we’ve 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers V – Events and Methods

Let’s 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 entity’s 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

Let’s now take a look at an example …

© 2010 Oracle Corporation - Propietary and Confidential


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) {


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

1. It specifies the entity type in annotations (don’t 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

© 2010 Oracle Corporation - Propietary and Confidential


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

public void handleAdd(BusinessEntity newBusinessEntity) {


4 Account account = (Account) newBusinessEntity;
AccountAlerts acctAlerts = account.getAlerts();
5 AccountAlert_DTO acctAlertDTO = acctAlerts.newChildDTO();
6 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 it’s a new account
6. It creates a new alert DTO by using the entity list’s
newChildDTO method …

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers V – handleAdd example

Create an alert when a new account is added


/**
* @ChangeHandler (entityName = account)
*/
public class CmAccount_CHandler extends AbstractChangeHandler {

public void handleAdd(BusinessEntity newBusinessEntity) {


Account account = (Account) newBusinessEntity;
AccountAlerts acctAlerts = account.getAlerts();
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 account’s alert entity list –
the additional parameters are required for the entity list

The framework will add the row when the transaction commits

© 2010 Oracle Corporation - Propietary and Confidential


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 list’s add methods
– To remove a child entity, use the entity list’s remove methods

© 2010 Oracle Corporation - Propietary and Confidential


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
Let’s look at an example …

© 2010 Oracle Corporation - Propietary and Confidential


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;
if (account.getMailingPremiseId() != null) {
3 Premise premise = account.getMailingPremiseId().getEntity();
Premise_DTO premiseDTO = premise.getDTO();
premiseDTO.setAddress4(account.getAlertInformation());
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)

© 2010 Oracle Corporation - Propietary and Confidential


Change Handlers V – handleChange Example
Update the related premise when an account is changed

public void handleChange(BusinessEntity changedEntity,


DataTransferObject oldDTO) {
Account account = (Account) changedEntity;
if (account.getMailingPremiseId() != null) {
4 Premise premise = account.getMailingPremiseId().getEntity();
5 Premise_DTO premiseDTO = premise.getDTO();
premiseDTO.setAddress4(account.getAlertInformation());
6 premise.setDTO(premiseDTO);
7 }
}

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 account’s 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Algorithms
Part I

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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.
• Let’s take a look at how algorithms work internally …

© 2010 Oracle Corporation - Propietary and Confidential


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)

Let’s take a look at these definitions more closely, database components


first and then the framework classes …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Algorithm Database Model

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

© 2010 Oracle Corporation - Propietary and Confidential


Algorithm Database Model

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
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

© 2010 Oracle Corporation - Propietary and Confidential


Algorithm Database Model

CI_ALG_TYPE 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

CI_ALG_PARM Examples
CI_ALG_TYPE_PRM PK,FK2 ALG_CD
PK EFFDT
Characteristic Type
PK,FK1 ALG_TYPE_CD
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 entity’s
configuration table – the algorithm will be invoked based on this
specification
Let’s look at an example …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

2
3

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)

© 2010 Oracle Corporation - Propietary and Confidential


Algorithm Phone Format Example
Admin -> Algorithm Type – Phone format

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

© 2010 Oracle Corporation - Propietary and Confidential


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.

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Algorithm Phone Format Example
Main -> Person – Algorithm activation

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 we’ll see how the framework components are
built to support these definitions …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

PhoneTypeFormatValidationAlgComp_Gen
PhoneTypeFormatValidationAlgComp_Impl
«interface»
PhoneTypeFormatValidationAlgComp
2
+getPhoneFormat1() : String
+getPhoneFormat2() : String 1
+invoke() : void
3
+setPhoneValue() : void
+setPhoneType() : void
+getPhoneFormat3() : String
+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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Algorithm Components – Phone Type Validation
3. The generated component interface class also contains a “factory”
class to create an instance of an algorithm component – we’ll 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Algorithm Phone Format Example

This Impl class’s 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”

© 2010 Oracle Corporation - Propietary and Confidential


Algorithm Phone Format Example

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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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”)

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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!

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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”)

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Algorithms
Part II

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


Exercise 9 – Adhoc Char Value Algorithm

Don’t for get to add the Validation rule requirement online!


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

© 2010 Oracle Corporation - Propietary and Confidential


SPL Batch
Part I

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 …

© 2010 Oracle Corporation - Propietary and Confidential


Batch Control – Java Example

2
3

4
5

1. The Batch Control code


2. The Program Type
3. The Program Name

© 2010 Oracle Corporation - Propietary and Confidential


Batch Control – Java Example

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

© 2010 Oracle Corporation - Propietary and Confidential


Batch Control – Java Example

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

© 2010 Oracle Corporation - Propietary and Confidential


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
• Let’s take a look at these two components …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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
• Let’s take a look at these components of a
BatchJob class …

© 2010 Oracle Corporation - Propietary and Confidential


BatchJob Class Annotation
A BatchJob class annotation looks as follows …
@BatchJob (rerunnable = false, 1
2 multiThreaded = true,
3 modules={todo},
softParameters = { @BatchJobSoftParameter
(name=OUTPUT-DIR, type=string) },
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

© 2010 Oracle Corporation - Propietary and Confidential


BatchJob Class Annotation
A BatchJob class annotation looks as follows …
@BatchJob (rerunnable = false,
multiThreaded = true,
modules={todo},
4 softParameters = { @BatchJobSoftParameter
(name=OUTPUT-DIR, type=string) },
toDoCreation = @ToDoCreation (
5 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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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!

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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 ...
}
}

© 2010 Oracle Corporation - Propietary and Confidential


ThreadWorker Class Public Methods

• The following standard public methods are


implemented in a ThreadWorker class …

© 2010 Oracle Corporation - Propietary and Confidential


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 thread’s 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

© 2010 Oracle Corporation - Propietary and Confidential


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 parameter’s getPrimaryId
method to get the business entity’s Id object

© 2010 Oracle Corporation - Propietary and Confidential


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


Let’s take a look at a complete example that creates
ToDos for batch runs that ended in error …

© 2010 Oracle Corporation - Propietary and Confidential


BatchJob Example – Create Batch Error ToDos
The annotation and class definition
/**
* @BatchJob (rerunnable = false,
* multiThreaded = false, 1
* modules={todo})
*/
public class CmBatchErrorToDoCreation 2
extends CmBatchErrorToDoCreation_Gen {
private static final com.splwg.shared.logging.Logger logger =
com.splwg.shared.logging.LoggerFactory.
3 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)

© 2010 Oracle Corporation - Propietary and Confidential


BatchJob Example – Create Batch Error ToDos

The BatchJob methods


1 public JobWork getJobWork() {
2 Query errorRunQuery = createQuery("from BatchRun run “+
“where run.runStatus = :runStatus");
errorRunQuery.bindLookup("runStatus",
RunStatusLookup.constants.ERROR);
return createJobWorkForEntityQuery(errorRunQuery);
}

public Class getThreadWorkerClass() {


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

© 2010 Oracle Corporation - Propietary and Confidential


BatchJob Example – Create Batch Error ToDos

The BatchJob methods


public JobWork getJobWork() {
Query errorRunQuery = createQuery("from BatchRun run “+
“where run.runStatus = :runStatus");
errorRunQuery.bindLookup("runStatus",
RunStatusLookup.constants.ERROR);
3 return createJobWorkForEntityQuery(errorRunQuery);
}

4 public Class getThreadWorkerClass() {


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 we’ll see on the next slide)

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


BatchJob Example – Create Batch Error ToDos

Inner ThreadWorker method finalizeThreadWork

public void finalizeThreadWork()


throws ThreadAbortedException, RunAbortedException {
}

This example does not implement the finalizeThreadWork


method

© 2010 Oracle Corporation - Propietary and Confidential


BatchJob Creation Review

Before we get to the exercise, let’s 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

© 2010 Oracle Corporation - Propietary and Confidential


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
– 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
...

© 2010 Oracle Corporation - Propietary and Confidential


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)

© 2010 Oracle Corporation - Propietary and Confidential


SPL Batch
Part II

© 2010 Oracle Corporation - Propietary and Confidential


SPL Batch II - ToDo’s

• 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 …

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


Exercise 11 – Batch 2
All Students
• Modify the previous exercise’s 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

© 2010 Oracle Corporation - Propietary and Confidential


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
student’s definitions, substitute XX in all cases with your own 2-
digit initials

© 2010 Oracle Corporation - Propietary and Confidential


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

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

© 2010 Oracle Corporation - Propietary and Confidential


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

• ToDo Type XXTDPNA – Roles tab

© 2010 Oracle Corporation - Propietary and Confidential


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

• ToDo Type XXTDPNA – Drill Keys tab

© 2010 Oracle Corporation - Propietary and Confidential


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

© 2010 Oracle Corporation - Propietary and Confidential


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'

© 2010 Oracle Corporation - Propietary and Confidential


The End

Thank You

© 2010 Oracle Corporation - Propietary and Confidential

Potrebbero piacerti anche