SEPA Processor 5 Manual

PAYMENTCOMPONENTS BY DATAMATION

Accessible Expertise, Empowering Great Solutions

SEPA CT Processor

User Manual

A java-bean library for SEPA messages

Current major version: SEPACTprocessor 5.0

web http://www.paymentcomponents.com

e-mail info@paymentcomponents.com

Phone +30 210 61 45 050 • Fax +30 210 61 45 055

Table of Contents

Overview

Introduction

SEPA CTprocessor is a java library. It contains several JavaBeans that provide assistance in building, validating and editing SEPA messages or extracting information from them.

SEPA is built on a subset of the UNIFI "Payments Clearing and Settlement" and “Payments Initiation” messages. UNIFI, which stands for UNIversal Financial Industry message scheme is an International Standard (ISO 20022) which aims to provide the financial industry with a common platform for the development of messages in a standardized XML syntax. Using a modeling methodology (based on UML) to capture in a syntax-independent way financial business areas, business transactions and associated message flows. It also provides a set of XML design rules to convert the messages described in UML into XML schemas.

SEPA CT processor includes all of the "Payments Clearing and Settlement" messages defined in the EPC SEPA CT Rulebook v5.0. See appendix A for the list of included messages.

The following document is organized in a number of sections.

In the section Building a new SEPA message we describe the procedure a user must follow in order o build a new SEPA message using SEPACTprocessor JavaBeans.

In Section Editing a SEPA message we describe the procedure a user must follow in order to edit a preexistent SEPA message. By “edit” we mean adding new information to the message, deleting information from the message or altering information of the message. By “preexistent” we mean a message that is stored in a File as XML, or in a character String, or in a SEPACTprocessor JavaBean.

In the section Extracting data we describe the procedure a user must follow in order to extract information from an existent SEPA message that has been converted to a SEPACTprocessor JavaBean.

In the section Building the Reply Message we describe the procedure a user must follow in order to create the reply message of an existing SEPA message.

The section Working with the evaluation covers the installation and usage of the evaluation version.

Finally in the section Summary we summarize the most important methods and code fragments, for a quick reference.

Usefulness of SEPACTprocessor

SEPA was born from the need for more structured and well formed communication messages for financial institutions and has been built on a subset of the XML based UNIFI (ISO 20022) messages. Unlike the previous standard, ISO 15022, where the messages were formed in a difficult and non standard format, SEPA (ISO 20022), brings the advantages of XML to the financial institution focused software developer.

This new XML based standard, enables software developers to choose among a plethora of free or commercial tools and runtime libraries for handling the messages. Therefore, one could think that SEPACTprocessor is nothing more than just another XML handling tool. However, this is not the case.

It is true that SEPACTprocessor performs all of the tasks of the XML tools, i.e. it can parse an XML file, edit some elements in it, delete or add elements, validate it against an XML schema and finally export the message as XML file or character String. In addition there are many more actions that a complete SEPA message handling tool must be capable of doing apart from the common XML actions listed above. The most important being the message validation beyond the XML schema. Each SEPA message enforces many “Rules” as they are called in the SEPA literature. These Rules are described in detail in the definition of each SEPA message. Hard coding in some programming language is needed.

Another advantage of SEPACTprocessor is its simplicity of usage. It is easily integrated with your development environment and every action is carried out by simple calls.

The following list summarizes the key advantages of the SEPACTprocessor.

Building a new SEPA message

All SEPA messages are identified by a code id and a name. The code id looks like this FIToFICstmrCdtTrf and is located in the .xsd file describing the XML schema of the current message. The name of the message is more descriptive and looks like FIToFICustomerCreditTransfer. Both the name and the code id of the message are available in the SEPA messages catalogue.

For every SEPA message there is one SEPACTprocessor JavaBean. The name of the JavaBean is identical to the name of the message. For example the name of the JavaBean for the message named FIToFICustomerCreditTransfer is FIToFICustomerCreditTransfer.

There are three steps the user must follow in order to build a new SEPA message:

  1. Initialize the JavaBean corresponding to the message.
  2. Add data to the JavaBean.
  3. Validate the message.

In the following three paragraphs we describe in detail those three steps.

Initialize the class corresponding to the message

The initialization of the class is as simple as initializing any class in Java. For the example message we are using here (FIToFICustomerCreditTransfer) the initialization would be

FIToFICustomerCreditTransfer message = new FIToFICustomerCreditTransfer();

The above command will initialize a class for this message named FIToFICustomerCreditTransfer which is initially empty.

Add data to the class

The next step is to add data to the new message. In order to add some data to the message the user must know which element in the message tree he wants to add. The element he wants to add is identified by an XML path. The value of the element the user wants to add may be a String, a Boolean or a complex type that is described in the SEPA type catalogue.

So to enter some data into the message, the user must call the following method of the class

message.setElement(path, value);

Where the path argument is a String identifying the element to add and the value argument is an Object.

Or

message.set_X_Y_Z(idxX, idxZ, value);

Where X_Y_Z indicates the path which specifies the element and idxX, idxZ are the indices which indicate the sibling of the element X and Z respectively (in case X and Z are present more than once in the message).

The benefit of this method is that the signature provides information about the type of the object that the user should construct.

Validate the message

After building a SEPA message using the appropriate SEPACTprocessor class, the user may want to validate this message. Of course validation is not mandatory but is the only way to prove that the message is correct. Validation is performed by calling the validate() method of the class and internally is a two step process:

  1. Validation against the schema of the message in order to ensure that the message is a well formed instance of it.
  2. Validation against any Validation Rule as described for that message by the SEPA rules.

To perform those two levels of validation the use must call the following method

List<String> errors = message.validate();

The validate() method performs two level validation on the message and returns an ArrayList containing the validation errors that may occur. Each error is contained in the ArrayList as a String describing the error.

A more complex example

We will assume that the SEPA message named FIToFICustomerCreditTransfer with code id FIToFICstmrCdtTrf has an XML schema described by the following code. This code is just a fragment of the original schema description for the message FIToFICustomerCreditTransfer and of course the following description is not the description for the real FIToFICustomerCreditTransfer message.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02"
		   elementFormDefault="qualified" targetNamespace="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02">
	<xs:element name="Document" type="Document"/>
	<xs:complexType name="Document">
		<xs:sequence>
			<xs:element name="FIToFICstmrCdtTrf" type="FIToFICustomerCreditTransferV02"/>
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="FIToFICustomerCreditTransferV02">
		<xs:sequence>
			<xs:element name="GrpHdr" type="GroupHeader19"/>
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="GroupHeader19">
		<xs:sequence>
			<xs:element name="MsgId" type="Max35Text"/>
			<xs:element name="CreDtTm" type="ISODateTime"/>
			<xs:element name="NbOfTxs" type="Max15NumericText"/>
		</xs:sequence>
	</xs:complexType>
	<xs:simpleType name="Max35Text">
		<xs:restriction base="xs:string">
			<xs:minLength value="1"/>
			<xs:maxLength value="35"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:simpleType name="ISODateTime">
		<xs:restriction base="xs:dateTime"/>
	</xs:simpleType>
	<xs:simpleType name="Max15NumericText">
		<xs:restriction base="xs:string">
			<xs:pattern value="[0-9]{1,15}"/>
		</xs:restriction>
	</xs:simpleType>
</xs:schema>

One XML path for the previous schema would be

/Document/FIToFICstmrCdtTrf/GrpHdr

another one would be

/Document/FIToFICstmrCdtTrf/GrpHdr/MsgId

another one would be

/Document/FIToFICstmrCdtTrf/GrpHdr[1]/CreDtTm[1]

Notice that the path is free to contain location predicates. This means that we can refer to the first GrpHdr element as /Document/pacs.008.002.02/GrpHdr[1]/ and to the second GrpHdr element as /Document/pacs.008.002.02/GrpHdr[2]/. If the location predicate is missing then it is implied that the path refers to the first such element.

A sample XML describing a message of our FIToFICustomerCreditTransfer would be

<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.002.02">
	<FIToFICstmrCdtTrf>
		<GrpHdr>
			<MsgId>messageNo555</MsgId>
			<CreDtTm>2006-01-01T23:10:00</CreDtTm>
			<NbOfTxs>4</NbOfTxs>
		</GrpHdr>
	</FIToFICstmrCdtTrf>
</Document>

Let’s now try to build a FIToFICustomerCreditTransfer_CoreV02 message containing the above data using the SEPACTprocessor class.

We have seen how to initialize the appropriate class. After the initialization we can enter data.

The paths needed are the following

Every path of every SEPA message starts with /Document/xxx and so we integrated this prefix in every message in order to make the paths the user enters simpler. In other words the paths that the user must add is now

The user now can add the appropriate data by calling the following methods

message.setElement("/GrpHdr/MsgId", anObject1);
message.setElement("/GrpHdr/CreDtTm", anObject2);
message.setElement("/GrpHdr/NbOfTxs", anObject3);

Notice that each call of the setElement method takes as arguments a String identifying the path of the element and an Object containing the value for the element. We mentioned before that this Object can be a String, a Boolean or a more complex type.

There are two ways for the user to know which type must use for a specific element. The first way is from the SEPA reference of the message. This reference is a comprehensive description of the elements of the message and the corresponding types. The second way is by calling the getElementType() method of the message.

By using either method the user will find out that the elements and the corresponding types for the message he/she wants to build are:

So the user will make the following calls

message.setElement("/GrpHdr/MsgId", Max35Text.Factory.newInstance());
message.setElement("/GrpHdr/CreDtTm", ISODateTime.Factory.newInstance());
message.setElement("/GrpHdr/NbOfTxs", Max15NumericText.Factory.newInstance());

Another way to build the message is to find the type of the /GrpHdr element by calling

message.getElementType("/GrpHdr");

Or

message.get_GrpHdr();

and then constructing an Object of this type, filling it with the appropriate data and setting it as value of the /GrpHdr element by calling the method

message.setElement("/GrpHdr", aGrpHdrTypeObject);

Note that if you set data to an element that has already been set then the element will be overwritten.

The method setElement throws an Exception of type Error if something goes wrong during the operation of setting data on an element. There are two reasons for something going wrong at this stage. The first is when the path entered by the user as the first argument of the setElement method is invalid. The second is when the data set for an element is invalid. In either case the operation is aborted and an Error Exception is thrown. The user must catch this Error object and get the message from it in order to identify the error.

For example a sample code would look like

try {
	message.setElement("some_path", anObject);
} catch (Error e) {
	System.err.println(e.getMessage());
	System.exit(1);
} 

As previously mentioned, you can also use the alternative method of setElement to set the data as follows:

message.set_GrpHdr_MsgID(anObject1);
message.set_GrpHdr_CreDtTm(anObject2);
message.set_GrpHdr_NbOfTxs(anObject3);

Editing a SEPA message

In the previous section we saw how you can create a new SEPA message from scratch using SEPACTprocessor JavaBeans. In this section we will see how the user is able to edit an existing SEPA message. By “editing” we mean either altering a piece of information in the message, or deleting some, or adding new.

Note that all this procedures apply also to the case where the user creates a new message. After the user creates the new message, following the procedures in Section 4, he is able to alter, delete, or add information to the message.

So in this section we assume that there is a SEPA message. The format of the message varies. It may have been just created by the user following the procedures of the previous section. It may also have been created in the past and saved in an XML file. Or it may have been created by another part of the user’s software and it is available as a String. So a SEPA message may exist as a File, as a String, or as a SEPACTprocessor JavaBean.

The procedures we will describe in this section apply only to the SEPACTprocessor form of an existing SEPA message. The user must load the File or String version of a message into a SEPACTprocessor JavaBean in order to be able to alter, delete or add data to it.

Fortunately the SEPACTprocessor framework provides the tools to do this conversion. By “conversion” we mean loading a SEPA message from a File or a String into the equivalent SEPACTprocessor class.

Loading

We will assume that the user has a SEPA message saved as XML in an XML File called message.xml. The procedures we will describe apply also to the case where the message is in a String form.

The loading of a message is done via the parseMessageFromXML method of SEPACTprocessor JavaBean of the corresponding message. This method takes a single argument. The argument may be a File or a String. It is obvious which one to call when a user has a message in a File or a String format.

Continuing the example we will assume that the user has in the message.xml file a SEPA message of code pacs.008.001.02. Searching through the SEPA documentation he will find that the name of this message with code pacs.008.001.02 is FIToFICustomerCreditTransfer.

Therefore to load the message in the message.xml file he must execute the following commands.

FIToFICustomerCreditTransfer message = null;
message = new FIToFICustomerCreditTransfer();
message.parseMessageFromXML(new File("/path/to/message.xml"));

These commands must be surrounded by a try-catch block, so if something goes wrong during the loading, the user will be informed.

The procedure is identical in the case where the message is in a string format: method parseMessageFromXML is overloaded with a File and a String argument.

Editing

After loading a SEPA message in a SEPACTprocessor bean, a user is able to apply any editing action, like deleting elements, adding new, or altering the existing ones.

Deleting

In order to delete an element, the user must call the deleteElement(String s) method of the SEPACTprocessor JavaBean holding the SEPA message.

For example a user in order to delete the second GroupHeader element of a FIToFICustomerCreditTransfer message would call the following methods:

FIToFICustomerCreditTransfer message = new FIToFICustomerCreditTransfer();
message.parseMessageFromXML(new File("/path/to/message.xml"));
message.deleteElement("/GrpHdr");

The alternative deleteElement method can be used as follows:

FIToFICustomerCreditTransfer message = new FIToFICustomerCreditTransfer();
message.parseMessageFromXML(new File("/path/to/message.xml"));
message.del_GrpHdr();

Of course those calls must be surrounded by try-catch statements.

Adding

Addition to a loaded message is done just like adding new information while building a new SEPACTprocessor message, as we have seen in the Section 4 describing the creation of a new SEPACTprocessor message.

Altering

Altering a piece of information in a SEPACTprocessor message is done just like adding new ones. Let’s assume that a user wants to alter the MsgId of the first GroupHeader element of a FIToFICustomerCreditTransfer message and set the value newId. This is done as follows:

FIToFICustomerCreditTransfer message = new FIToFICustomerCreditTransfer();
message.parseMessageFromXML(new File("/path/to/message.xml"));
Max35Text m = Max35Text.Factory.newInstance();
m.setStringValue(“newId”);
message.setElement("/GrpHdr/MsgId", m);

Extracting data

Extracting data from a SEPA message is as simple as calling one line of code. It is assumed that previously the message is loaded to a SEPACTprocessor JavaBean object or it has been built. The following code fragment shows how easy it is to get a piece of information from a message.

FIToFICustomerCreditTransfer message = new FIToFICustomerCreditTransfer();
message.parseMessageFromXML(new File("/path/to/message.xml"));
Object data = message.getElement("/GrpHdr");

Of course the user is responsible to cast this Object, the data object, to the appropriate structure.

The alternative version of getElement can be used as follows:

FIToFICustomerCreditTransfer message = new FIToFICustomerCreditTransfer();
message.parseMessageFromXML(new File("/path/to/message.xml"));
GroupHeader1 data = message.get_GrpHdr();

The advantage of using the alternative version of getElement is that the user does not have to make an explicit casting as the information is contained in the methods signature.

In addition to the getElement methods, the resolveXXX methods can be used to greatly simplify the parsing of messages, the following uses a  CustomerCreditTransferInitiation (pain.001.001.03) message as an example.

These methods return vectors of vectors of LeafInfo objects.

LeafInfo objects have 3 fields

So for the path in XML /GrpHdr/InitgPty/Nm with value "ABC Corporation" the fields would be populated as follows:

fieldPath

/GrpHdr/InitgPty

fieldcd

Nm

value

ABC Corporation

The resolveGroupHeader method for example, searches for /GrpHdr tags and stores this information in Lists.

Why lists of Lists? Because there is a chance of having multiple occurrences of the same tag, so information should be stored in a different place.

With an XML file with one GrpHdr tag (only one instance), the resolveGroupHeader method would return a list with one element (the list containing all the LeafInfo objects)

The following demonstrates the 10 LeafInfo objects which will be stored in a list for GrpHdr tag.

The resolveTransactions method searches for PmtInf tags.

A sample output is as follows:

Examples of the resolve method include:

List<List<LeafInfo>> listGH = message.resolveGroupHeader();
List<List<LeafInfo>> listPmtInf = message.resolveTransactions();

The resolveALL method enables all elements of the message to be retrieved:

List<List<LeafInfo>> listALL = message.resolveAll();

It is likely that the number of transactions will be > 1 so listPmtInf will return a vector with more than 1 element. There are equivalent resolveXXX methods for other messages e.g resolveOriginalGroupInfo method for PaymentReversal message.

Example code demonstrating the use of these methods can be found in the Working with the evaluation section.

Building the Reply Message

The Reply Message (R-Transactions, RT) is a SEPA message that is used to provide an automatic response to a message. An RT can be constructed and modified according to the following instructions.

This feature is designed to simplify the creation of an RT since it can be automatically constructed by following the specification of the initiating message. The construction of the RT is defined by an internal mechanism whose prime purpose is to:

The resulting RT contains all the "reusable" data extracted from the initial message and only requires the addition of any further necessary data to complete the creation of the RT.

Until all mandatory data has been added, the RT object will not be able to produce a valid message.

The construction of an RT is implemented in the class of the respective SEPA message, via the autoReply(String, Boolean) method. The first parameter specifies the unique code of the RT (since an existing message could have more than one possible RT) whereas the second designates whether the RT applies to all transactions or not.

For example, assuming that:

Then, the calling of the autoReply method using the following code fiTofi.autoReply("pacs.004.001.02", false) will return a PaymentReturn object.

Working with the evaluation

The evaluation version of SEPACTprocessor is fully functional but is limited in the number of different ISO20022 messages it can handle.

The evaluation version is capable of processing SEPA messages of pain.001.001.03 with the type CstmrCdtTrfInitn and name CustomerCreditTransferInitiation. The evaluation is also time limited and will expire after 30 days. The user can find the full description of this message, as with all other ISO20022 based messages, in the official web site of the ISO20022 organization available at the following URL. www.iso20022.org. Additional SEPA specific information is available on the EPC’s website at the following URL. http://www.europeanpaymentscouncil.eu/

Using the evaluation, a developer can execute all the actions described in this manual. Namely parse, build, edit, delete and extract, but only when the message is of the type CstmrCdtTrfInitn with a schema designation of pain-001-001-03.

The evaluation includes the following files that need to be copied to your projects lib directory and then imported into the project.

Main evaluation library

Support libraries

The sample file should be placed in a sub directory called messages.

Sample file

The following samples will provide a quick start to test that the environment is configured correctly.

package eval;

import gr.datamation.sepa.core.messages.common.UnifiError;
import gr.datamation.sepa.core.messages.groupheaders.Pain001Header;
import gr.datamation.sepa.core.messages.groups.CustomerCreditTransferInitiation;
import gr.datamation.sepa.types.pain001.*;

import java.io.File;
import java.util.ArrayList;

public class SEPATest {
	public static void main(String args[]) {
		CustomerCreditTransferInitiation message = new CustomerCreditTransferInitiation();
		Pain001Header groupHeader = null;
		PaymentInstructionInformation3 pmtInf = null;
		try {
			message.parseMessageFromXML(new File("/path/to/pain.001.001.03.xml"));
			groupHeader = message.getGroupHeader();
			pmtInf = (PaymentInstructionInformation3) message.getElement("/PmtInf[0]");
		} catch (UnifiError e) {
			e.printStackTrace();
		}
		ArrayList errors = message.validate();
		for (int i = 0; i < errors.size(); i++) {
			System.out.println("Error #" + i + ": " + errors.get(i).toString());
		}
		System.out.println("-------------------");
		System.out.println(groupHeader.getMsgId());
		System.out.println(groupHeader.getCreDtTm().getTime());
		System.out.println(groupHeader.getNbOfTxs());
		System.out.println(groupHeader.getCtrlSum());
		System.out.println("-------------------");
		System.out.println(pmtInf.getReqdExctnDt());
		for (int j = 0; j < Integer.parseInt(groupHeader.getNbOfTxs()); j++) {
			System.out.println(pmtInf.getCdtTrfTxInfArray(j).getAmt().getInstdAmt().getBigDecimalValue());
			System.out.println(pmtInf.getCdtTrfTxInfArray(j).getAmt().getInstdAmt().getCcy());
		}
		System.out.println("-------------------");
	}
}
package eval;

import gr.datamation.sepa.core.messages.common.UnifiError;
import gr.datamation.sepa.core.messages.groups.CustomerCreditTransferInitiation;
import gr.datamation.sepa.core.utils.NodeExtractor$LeafInfo;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;

public class Tester {
	/**
	 * @param args
	 */
	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
		CustomerCreditTransferInitiation message = new CustomerCreditTransferInitiation();
		try {
			message.parseMessageFromXML(new File("/path/to/pain.001.001.03.xml"));
		} catch (UnifiError e) {
			e.printStackTrace();
		}
		try {
			Vector<Vector<NodeExtractor$LeafInfo>> listGH = message.resolveGroupHeader();
			//Each vector inside listPmtInf has all LeafInfos for one PmntInf tag
			Vector<Vector<NodeExtractor$LeafInfo>> listPmtInf = message.resolveTransactions();
			listGH.addAll(listPmtInf);
			Iterator<Vector<NodeExtractor$LeafInfo>> it = listGH.iterator();
			while (it.hasNext()) {
				Vector<NodeExtractor$LeafInfo> current = it.next();
				Iterator<NodeExtractor$LeafInfo> it2 = current.iterator();
				while (it2.hasNext()) {
					NodeExtractor$LeafInfo li = it2.next();
					System.out.println("value: " + li.getFieldpath() + "/" + li.getFieldcd() + ":    " + li.getFielddata() + " " + (li.getCcyAttr() == null ? "" : li.getCcyAttr()));
				}
			}
			System.out.println(message.get_GrpHdr().getCreDtTm());
		} catch (UnifiError e) {
			e.printStackTrace();
		}
		ArrayList errors = message.validate();
		for (int i = 0; i < errors.size(); i++)
			System.out.println("Error #" + i + ": " + errors.get(i).toString());
		System.out.println("-------------------");
	}
}

Summary

Initialize SEPACTProcessor message

Name_Of_SEPA_msg message = null;
message = new Name_Of_SEPA_msg();

Add new data to a SEPACTprocessor message

message.setElement("path", anObject);
set_X_Y_Z_...(Xidx, Yidx, Zidx, ..., value);

Delete data from a SEPACTprocessor message

message.deleteElement("path");
del_X_Y_Z_...(Xidx, Yidx, Zidx, ...);

Get data from a SEPACTprocessor message

MessageType mt = get_X_Y_Z_...(Xidx, Yidx, Zidx, ...); // “MessageType” denotes the object type of the message

Installation Instructions

The component is packaged as jar file and can be added to any Java IDE project as jar reference. This implementation was currently deployed and tested in Eclipse.

It requires at least JDK 1.6.x

SEPACTprocessor includes:

Contact and Support

The support team is available to answer questions on using the component, code assistance, error determination, ideas, examples etc.

Please forward your questions to: info@paymentcomponents.com

Also visit www.paymentcomponents.com for other components and services by PaymentComponents.

Appendix A

SEPACTprocessor supports:

The following messages as defined in the EPC SEPA CT Rulebook v5.0

 Message Name

Msg ID

Schema ID

FIToFICustomerCreditTransfer

FIToFICstmrCdtTrf

pacs.008.001.02

PaymentStatusReport

FIToFIPmtStsRpt

pacs.002.001.03

PaymentReturn

PmtRtr

pacs.004.001.02

FIToFIPaymentCancellationRequest

FIToFIPmtCxlReq

camt.056.001.01

ResolutionOfInvestigation

RsltnOfInvstgtn

camt.029.001.03

CustomerCreditTransferInitiation

CstmrCdtTrfInitn

pain.001.001.03

PaymentStatusReport

CstmrPmtStsRpt

pain.002.001.03