This document provides an introduction to the SWIFT protocol and messages, and gives a guideline explaining how to process swift messages using the Java WIFE library
SWIFT or Society for Worldwide Interbank Financial Telecommunication provides a network to allow financial and non-financial institutions (e.g. corporates) to transfer financial transactions through a 'financial message'.
SWIFT messages consist of five blocks of data including three headers, message content, and a trailer.
- All blocks have the same basic format:{n:...}
- The curly braces ({}) indicate the beginning and end of a block.
- n is the block identifier, in this case a single integer between 1 and 5.
- Each block identifier is associated with a particular part of the message.
- Blocs 3 and 5 are optional.
A field is a logical subdivision of a message block, which consists of a sequence of components with a starting field tag and delimiters.
A field is always prefaced by a field tag that consists of two digits followed, optionally, by an alphabetic character.
The alphabetic character is referred to as an option.
For example, 16R is a tag (16) with an option (R) that indicates the start of a block; 16S is a tag (16) with an option (S) that indicates the end of a block. A field is always terminated by a field delimiter. The delimiter depends on the type of field used in a message block.
{1:F01ANASCH20AXXX0527012180}{2:O5020750040609LRLRXXXX4A0400004386330406090954U}{3:{108:MT502 001 OF 008}}{4:
:16R:GENL
:20C::SEME//01116
:23G:NEWM/CODU
:22F::TRTR//BASK
:16R:LINK
:20C::PREV//x
:16S:LINK
:16S:GENL
:16R:ORDRDET
:16R:PRIC
:90A::LIMI//DISC/1200
:16S:PRIC
:22H::BUSE//SWIT
:22F::TOOR//ALNO
:98A::EXPI//19991231
:16R:TRADPRTY
:95P::BUYR//P005
:16S:TRADPRTY
:19A::ORDR//NUSD1,34
:36B::ORDR//UNIT/7500
:35B:ISIN MA0000011058
:16S:ORDRDET
:16R:SETDET
:22F::SETR//COLL
:16R:SETPRTY
:95R::REAG/A2C4E6G8/34x
:16S:SETPRTY
:16R:SETPRTY
:95R::BUYR/A2C4E6G8/34x
:16S:SETPRTY
:16R:SETPRTY
:95R::RECU/A2C4E6G8/34x
:16S:SETPRTY
:16R:SETPRTY
:95R::DEAG/A2C4E6G8/34x
:16S:SETPRTY
:16R:SETPRTY
:95P::PSET//DATW
:16S:SETPRTY
:16S:SETDET
-}{5:{MAC:307F606D}{CHK:521A0E3826D3}{TNG:}}
Java WIFE library is an open source Java library for SWIFT messages
parsing, writing and processing. The component is heavily tested and
running in production environments since 2006.
Its main features are:
All SWIFT message categories (MT0xx to MT9xx) are supported, including
System and Service message. The current version is compliant with ISO
15022.
The following jar files, representing the Java WIFE API should be used.
The following example shows how to:
package com.sungard.isb.swift.test;
import java.math.BigDecimal;
import java.util.Calendar;
import junit.framework.TestCase;
import net.sourceforge.wife.services.ConversionService;
import net.sourceforge.wife.services.IConversionService;
import net.sourceforge.wife.swift.model.SwiftMessage;
import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import com.prowidesoftware.swift.model.MIR;
import com.prowidesoftware.swift.model.field.Field32A;
import com.prowidesoftware.swift.model.field.Field59;
public class TestSwiftParsing extends TestCase {
private String swiftStr;
private String xml;
private SwiftMessage msg;
private IConversionService service;
private static final Logger logger = Logger
.getLogger(TestSwiftGeneration.class);
/**
* set up the swift message and the service
*/
@Before
public void setUp() throws Exception {
service = new ConversionService();
swiftStr = "{1:F01BANKDEFMAXXX2039063581}"
+ "{2:O1031609050901BANKDEFXAXXX89549829458949811609N}"
+ "{3:{108:00750532785315}}{4:\n" + ":20:007505327853\n"
+ ":23B:CRED\n"
+ ":32A:050902JPY3520000\n"
+ ":33B:JPY3520000,\n"
+ ":50K:EUROXXXEI\n"
+ ":52A:FEBXXXM1\n"
+ ":53A:MHCXXXJT\n"
+ ":54A:FOOBICXX\n"
+ ":59:/13212312\n"
+ "RECEIVER NAME S.A\n"
+ ":70:FUTURES\n"
+ ":71A:SHA\n"
+ ":71F:EUR12,00\n"
+ ":71F:EUR2,34\n" + "-}";
msg = service.getMessageFromFIN(swiftStr);
xml = service.getXml(msg); //convert to xml
}
/**
* Test parse swift message
*/
@Test
public void testParseSwiftMessage() {
assertEquals(swiftStr.length(), 313);
assertEquals(xml.length(), 1623);
assertEquals(msg.getBlock1().getApplicationId(), "F");
assertEquals(msg.getBlock1().getServiceId(), "01");
assertEquals(msg.getBlock1().getLogicalTerminal(), "BANKDEFMAXXX");
assertEquals(msg.getBlock1().getSessionNumber(), "2039");
assertEquals(msg.getBlock1().getSequenceNumber(), "063581");
}
/**
* Test Block1
*/
@Test
public void testBlock1() {
assertEquals(msg.getBlock1().getValue(), "F01BANKDEFMAXXX2039063581");
assertEquals(msg.getBlock1().getApplicationId(), "F");
assertEquals(msg.getBlock1().getServiceId(), "01");
assertEquals(msg.getBlock1().getLogicalTerminal(), "BANKDEFMAXXX");
assertEquals(msg.getBlock1().getSessionNumber(), "2039");
assertEquals(msg.getBlock1().getSequenceNumber(), "063581");
}
/**
* Test Block2
*/
@Test
public void testBlock2() {
assertEquals(msg.getBlock2().getValue(),
"O1031609050901BANKDEFXAXXX89549829458949811609N");
assertNull(msg.getBlock2().getBlockType());
assertEquals(msg.getBlock2().getMessagePriority(), "N");
assertEquals(msg.getBlock2().getMessageType(), "103");
MIR mir = new MIR(msg.getBlock2().getValue().substring(8, 8+28));
assertEquals(mir.getDate(), "050901");
assertEquals(mir.getLogicalTerminal(), "BANKDEFXAXXX");
assertEquals(mir.getSessionNumber(), "8954");
}
/**
* Test Block3
*/
@Test
public void testBlock3() {
assertEquals(msg.getBlock3().getName(), "3");
assertNull(msg.getBlock3().getBlockType());
assertNull(msg.getBlock3().getId());
assertEquals(msg.getBlock3().getTagValue("108"), "00750532785315");
}
/**
* Test Block4
*/
@Test
public void testBlock4() {
assertEquals(msg.getBlock4().getTagCount(),13);
assertEquals(msg.getBlock4().getTagCount("23B"),1);
assertEquals(msg.getBlock4().getTagValue("23B"), "CRED");
}
/**
* Test Fields 71F
*/
@Test
public void testFieldList71F() {
String[] list71 = msg.getBlock4().getTagValues("71F");
assertEquals("71F: Size is incorrect", list71.length,2);
assertEquals("71F: Value(1) is incorrect", list71[0],"EUR12,00");
assertEquals("71F: Value(2) is incorrect", list71[1],"EUR2,34");
}
/**
* Test 32A field parsing
*/
@Test
public void testField32A() {
Field32A f32A = new Field32A(msg.getBlock4().getTagValue("32A"));
assertEquals("32A: Component not correct",f32A.getValue(), "050902JPY3520000");
assertEquals("32A: Date not correct",f32A.getComponent1(), "050902");
assertEquals("32A: Year is incorrect",
f32A.getComponent1AsCalendar().get(Calendar.YEAR), 2005);
assertEquals("32A: Currency is incorrect", f32A.getComponent2(),"JPY");
assertEquals("32A: Currency is incorrect", f32A.getComponent2AsCurrency()
.getSymbol(),"JPY");
assertEquals("32A: Amount is incorrect",
f32A.getComponent3AsNumber().doubleValue(),3520000.0);
}
}
The following example shows how to generate SWIFT MT messages from SwiftMessage Java objects.
package com.sungard.isb.swift.test;
import junit.framework.TestCase;
import net.sourceforge.wife.services.ConversionService;
import net.sourceforge.wife.services.IConversionService;
import net.sourceforge.wife.swift.model.SwiftBlock1;
import net.sourceforge.wife.swift.model.SwiftBlock4;
import net.sourceforge.wife.swift.model.SwiftMessage;
import net.sourceforge.wife.swift.model.Tag;
import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
public class TestSwiftGeneration extends TestCase {
private String swiftStr;
private SwiftMessage msg;
private IConversionService service;
private SwiftBlock1 b1;
private static final Logger logger = Logger
.getLogger(TestSwiftGeneration.class);
/**
* set up the swift message object and the service
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
service = new ConversionService();
msg = new SwiftMessage();
/**
* Block 1
*/
b1 = new SwiftBlock1();
b1.setApplicationId("F");
b1.setServiceId("21");
b1.setLogicalTerminal("ABNAGB2PAXXX");
b1.setSessionNumber("2766");
b1.setSequenceNumber("797510");
msg.setBlock1(b1);
/**
* Block4
*/
msg.setBlock4(new SwiftBlock4());
SwiftBlock4 b4 = msg.getBlock4();
b4.addTag(new Tag("16R:GENL"));
b4.addTag(new Tag("20C:CORP//1255"));
b4.addTag(new Tag("23G:NEWM"));
b4.addTag(new Tag("22F:CAEV//RHTS"));
b4.addTag(new Tag("98C::PREP//20010115101205"));
b4.addTag(new Tag("16S:GENL"));
b4.addTag(new Tag("16R:USECU"));
b4.addTag(new Tag("35B:ISIN//FR0000077844"));
b4.addTag(new Tag("16S:USECU"));
b4.addTag(new Tag("16R:ACCTINFO"));
b4.addTag(new Tag("97A::SAFE//AC1234"));
b4.addTag(new Tag("93B::ELIG//UNIT/2500"));
b4.addTag(new Tag("16S:ACCTINFO"));
b4.addTag(new Tag("16R:CAINST"));
b4.addTag(new Tag("13A::CAON//UNS"));
b4.addTag(new Tag("22H::CAOP//CASH"));
b4.addTag(new Tag("36B::QINS//UNIT/10"));
b4.addTag(new Tag("92A::TAXB//30"));
b4.addTag(new Tag("70E::INST//ABCDEFGH"));
b4.addTag(new Tag("16S:CAINST"));
}
/**
* Test generating swift message
*/
@Test
public void testGenerateSwiftMessage() {
swiftStr = service.getFIN(msg);
assertEquals(swiftStr, "{1:F21ABNAGB2PAXXX2766797510}{4:{16R:GENL}{20C:CORP//1255}{23G:NEWM}
{22F:CAEV//RHTS}{98C::PREP//20010115101205}{16S:GENL}{16R:USECU}
{35B:ISIN//FR0000077844}{16S:USECU}{16R:ACCTINFO}{97A::SAFE//AC1234}
{93B::ELIG//UNIT/2500}{16S:ACCTINFO}{16R:CAINST}{13A::CAON//UNS}
{22H::CAOP//CASH}{36B::QINS//UNIT/10}{92A::TAXB//30}{70E::INST//ABCDEFGH}
{16S:CAINST}}");
assertEquals(swiftStr.length(), 350);
assertEquals(b1.getApplicationId(), "F");
assertEquals(b1.getServiceId(), "21");
assertEquals(b1.getLogicalTerminal(), "ABNAGB2PAXXX");
assertEquals(b1.getSessionNumber(), "2766");
assertEquals(b1.getSequenceNumber(), "797510");
}
}