├── .gitignore
├── src
└── main
│ └── java
│ └── com
│ └── paymentcomponents
│ └── mt
│ └── demo
│ ├── Main.java
│ ├── Utils.java
│ ├── ConvertMT2XML.java
│ ├── BuildMT101_1.java
│ ├── BuildMT101_2.java
│ ├── ParseValidMT01.java
│ └── ParseInvalidMT01.java
├── pom.xml
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .idea/
3 | target/
--------------------------------------------------------------------------------
/src/main/java/com/paymentcomponents/mt/demo/Main.java:
--------------------------------------------------------------------------------
1 | package com.paymentcomponents.mt.demo;
2 |
3 | public class Main {
4 | public static void main(String[] args) {
5 |
6 | ParseValidMT01.execute();
7 | ParseInvalidMT01.execute();
8 | ConvertMT2XML.execute();
9 | BuildMT101_1.execute();
10 | BuildMT101_2.execute();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/paymentcomponents/mt/demo/Utils.java:
--------------------------------------------------------------------------------
1 | package com.paymentcomponents.mt.demo;
2 |
3 | import gr.datamation.mt.validator.SwiftValidObj;
4 |
5 | public class Utils {
6 | public static void printErrors(SwiftValidObj swiftValidObj) {
7 | swiftValidObj.getValidationErrorList().stream().forEach(error -> {
8 | System.err.println(
9 | "Error Code: " + error.getErrorCode() + "\n" +
10 | "Error Description: " + error.getDescription() + "\n" +
11 | "Tag in error: " + error.getTagName() + "\n" +
12 | "Line number in error inside the tag: " + error.getLine() + "\n" +
13 | "Ocurrency: " + error.getOccurs() //In case the tag is repeated in the message, the occurs property contains the occurency in error
14 | );
15 | });
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.paymentcomponents
8 | demo-mt
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | paymentcomponents
14 | https://nexus.paymentcomponents.com/repository/public
15 |
16 |
17 |
18 |
19 |
20 | gr.datamation
21 | smv
22 | 24.2.0
23 | demo
24 |
25 |
26 |
27 |
28 | 8
29 | 8
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/main/java/com/paymentcomponents/mt/demo/ConvertMT2XML.java:
--------------------------------------------------------------------------------
1 | package com.paymentcomponents.mt.demo;
2 |
3 | import gr.datamation.mt.common.InvalidMessageFormatException;
4 | import gr.datamation.mt.common.SwiftMessage;
5 | import gr.datamation.mt.processor.SwiftMsgProcessor;
6 | import gr.datamation.mt.swift2xml.XMLWriter;
7 | import gr.datamation.mt.validator.SwiftMsgValidator;
8 | import gr.datamation.mt.validator.SwiftValidObj;
9 |
10 | import java.io.PrintWriter;
11 |
12 | public class ConvertMT2XML {
13 |
14 | public static void execute() {
15 | System.out.println("Convert MT to XML");
16 | String mt101String = "{1:F01COPZBEB0AXXX0377002843}{2:O1011519110804LRLRXXXX4A1100009044661108041720N}{3:{108:MT101 006 OF 020}{433:/AOK/NO HIT DETECTED }}{4:\n" +
17 | ":20:00043\n" +
18 | ":28D:1/1\n" +
19 | ":50F:/409074-293-45/786\n" +
20 | "1/George Philips\n" +
21 | "2/High Street 1\n" +
22 | "3/GB/London\n" +
23 | ":30:011231\n" +
24 | ":21:PQR-27ZZ-01\n" +
25 | ":32B:USD2564,50\n" +
26 | ":57D:/C/Clementine Nuggets-1842-Y\n" +
27 | "MynR49R RailRoad Trust\n" +
28 | "Cloudsboro ARTUI\n" +
29 | ":59F:1/Beneficiary Name-1234567891234123\n" +
30 | "2/QWERT\n" +
31 | "3/US/Beneficiary Address Line 21\n" +
32 | "3/Beneficiary Name-1234567891234123\n" +
33 | ":71A:OUR\n" +
34 | "-}{5:{MAC:00000000}{CHK:19DA346889CC}{TNG:}}{S:{SAC:}{COP:P}}";
35 | SwiftMsgProcessor parser = new SwiftMsgProcessor("\n");
36 | try {
37 | SwiftMessage smObj = parser.ParseMsgStringToObject(mt101String);
38 | //Validate the message
39 | SwiftValidObj swiftValidObj = new SwiftMsgValidator().validateMsg(smObj);
40 | //Check if it has any errors
41 | if (swiftValidObj.hasErrors()) {
42 | Utils.printErrors(swiftValidObj);
43 | } else {
44 | XMLWriter xmlWriter = new XMLWriter();
45 | xmlWriter.buildXML(swiftValidObj.getSwiftMessage(), System.out);
46 | PrintWriter printWriter = new PrintWriter("./mt.xml");
47 | xmlWriter.buildXML(swiftValidObj.getSwiftMessage(), "./", "mt2.xml");
48 | }
49 | } catch (InvalidMessageFormatException e) {
50 | System.err.println("Message cannot be parsed");
51 | } catch (Exception e) {
52 | System.err.println("Cannot produce XML for this message");
53 | }
54 |
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/paymentcomponents/mt/demo/BuildMT101_1.java:
--------------------------------------------------------------------------------
1 | package com.paymentcomponents.mt.demo;
2 |
3 | import gr.datamation.mt.common.RepSeq;
4 | import gr.datamation.mt.common.SwiftMessage;
5 | import gr.datamation.mt.common.Tag;
6 | import gr.datamation.mt.processor.SwiftMsgProcessor;
7 | import gr.datamation.mt.validator.SwiftMsgValidator;
8 | import gr.datamation.mt.validator.SwiftValidObj;
9 |
10 | import java.util.Vector;
11 |
12 | public class BuildMT101_1 {
13 |
14 | public static void execute() {
15 | System.out.println("Build MT 101 Way 1");
16 | SwiftMessage message = new SwiftMessage();
17 |
18 | // Set Tags for block1
19 | message.setArgApplid("F");
20 | message.setArgServid("01");
21 | message.setArgLTaddrBlk1("COPZBEB0AXXX");
22 |
23 | // Set Tags for block2
24 | message.setArgInoutind("I");
25 | message.setArgMsgtype("101");
26 | message.setArgLTaddrBlk2("LRLRXXXX4A11");
27 | message.setArgMsgprior("N");
28 |
29 | // Set Tags for block3
30 |
31 | message.getBlock3().add(new Tag("108", new Vector() {{
32 | add("MT103 005 OF 020");
33 | }}));
34 |
35 |
36 | // Set Tags for block4
37 | message.getBlock4().add(new Tag("20", new Vector(){{add("5387354");}}));
38 | message.getBlock4().add(new Tag("28D", new Vector(){{add("1/1");}}));
39 | message.getBlock4().add(new Tag("50F", new Vector(){{
40 | add("/409074-293-45/786");
41 | add("1/George Philips");
42 | add("2/High Street 1");
43 | add("3/GB/London");
44 | }}));
45 | message.getBlock4().add(new Tag("30", new Vector(){{add("011231");}}));
46 |
47 | RepSeq repSeqB = new RepSeq();
48 | repSeqB.addTag(new Tag("21", new Vector(){{add("PQR-27ZZ-01");}}));
49 | repSeqB.addTag(new Tag("32B", new Vector(){{add("USD2564,50");}}));
50 | repSeqB.addTag(new Tag("57D", new Vector(){{
51 | add("/C/Clementine Nuggets-1842-Y");
52 | add("MynR49R RailRoad Trust");
53 | add("Cloudsboro ARTUI");
54 | }}));
55 | repSeqB.addTag(new Tag("59F", new Vector(){{
56 | add("1/Beneficiary Name-1234567891234123");
57 | add("2/QWERT");
58 | add("3/US/Beneficiary Address Line 21");
59 | add("3/Beneficiary Name-1234567891234123");
60 | }}));
61 | repSeqB.addTag(new Tag("71A", new Vector(){{add("OUR");}}));
62 | message.getBlock4().add(repSeqB);
63 |
64 | // Set Tags for block5
65 | message.getBlock5().add(new Tag("MAC", new Vector() {{
66 | add("00000000");
67 | }}));
68 |
69 | message.getBlock5().add(new Tag("CHK", new Vector() {{
70 | add("4BCF59104AF9");
71 | }}));
72 |
73 | SwiftValidObj swiftValidObj = new SwiftMsgValidator().validateMsg(message);
74 | if (swiftValidObj.hasErrors()){
75 | Utils.printErrors(swiftValidObj);
76 | } else {
77 | try {
78 | System.out.println(new SwiftMsgProcessor().BuildMsgStringFromObject(message));
79 | } catch (Exception e) {
80 | e.printStackTrace();
81 | }
82 | }
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/com/paymentcomponents/mt/demo/BuildMT101_2.java:
--------------------------------------------------------------------------------
1 | package com.paymentcomponents.mt.demo;
2 |
3 | import gr.datamation.mt.common.RepSeq;
4 | import gr.datamation.mt.common.SwiftMessage;
5 | import gr.datamation.mt.common.Tag;
6 | import gr.datamation.mt.processor.SwiftMsgProcessor;
7 | import gr.datamation.mt.validator.SwiftMsgValidator;
8 | import gr.datamation.mt.validator.SwiftValidObj;
9 |
10 | import java.util.Collections;
11 | import java.util.Vector;
12 |
13 | public class BuildMT101_2 {
14 |
15 | public static void execute() {
16 | System.out.println("Build MT 101 - Way2");
17 | SwiftMessage message = new SwiftMessage();
18 |
19 | // Set Tags for block1
20 | message.setArgApplid("F");
21 | message.setArgServid("01");
22 | message.setArgLTaddrBlk1("COPZBEB0AXXX");
23 |
24 | // Set Tags for block2
25 | message.setArgInoutind("I");
26 | message.setArgMsgtype("101");
27 | message.setArgLTaddrBlk2("LRLRXXXX4A11");
28 | message.setArgMsgprior("N");
29 |
30 | message.getBlock3().addAll(createTagList("108:MT101 005 OF 020"));
31 |
32 | message.getBlock4().addAll(createTagList(":20:00043\n" +
33 | ":28D:1/1\n" +
34 | ":50F:/409074-293-45/786\n" +
35 | "1/George Philips\n" +
36 | "2/High Street 1\n" +
37 | "3/GB/London\n" +
38 | ":30:011231"));
39 | message.getBlock4().add(createRepSeq(":21:PQR-27ZZ-01\n" +
40 | ":32B:USD2564,50\n" +
41 | ":57D:/C/Clementine Nuggets-1842-Y\n" +
42 | "MynR49R RailRoad Trust\n" +
43 | "Cloudsboro ARTUI\n" +
44 | ":59F:1/Beneficiary Name-1234567891234123\n" +
45 | "2/QWERT\n" +
46 | "3/US/Beneficiary Address Line 21\n" +
47 | "3/Beneficiary Name-1234567891234123\n" +
48 | ":71A:OUR"));
49 |
50 | message.getBlock5().addAll(createTagList("MAC:00000000", "CHK:4BCF59104AF9"));
51 | SwiftValidObj swiftValidObj = new SwiftMsgValidator().validateMsg(message);
52 | if(swiftValidObj.hasErrors()) {
53 | Utils.printErrors(swiftValidObj);
54 | } else {
55 | try {
56 | System.out.println(new SwiftMsgProcessor().BuildMsgStringFromObject(message));
57 | } catch (Exception e) {
58 | e.printStackTrace();
59 | }
60 | }
61 | }
62 |
63 | public static RepSeq createRepSeq(String repSeqString) {
64 | return new RepSeq(createTagList(repSeqString.split("\n:")));
65 | }
66 |
67 | public static Vector createTagList(String block4Text) {
68 | return createTagList(block4Text.split("\n:"));
69 | }
70 |
71 | public static Vector createTagList(String... tagValues) {
72 | Vector tagList = new Vector();
73 | for (String tag : tagValues) {
74 | tagList.add(createTag(tag));
75 | }
76 | return tagList;
77 | }
78 |
79 | public static Tag createTag(String tag) {
80 | String tagKey = tag.replaceAll("(?s):?(.*):.*", "$1");
81 | String tagValueString = tag.replaceAll("(?s):?.*:(.*)", "$1");
82 | String[] lines = tagValueString.split("\n");
83 |
84 | Vector tagValue = new Vector();
85 | Collections.addAll(tagValue, lines);
86 |
87 | return new Tag(tagKey, tagValue);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/paymentcomponents/mt/demo/ParseValidMT01.java:
--------------------------------------------------------------------------------
1 | package com.paymentcomponents.mt.demo;
2 |
3 | import gr.datamation.mt.common.InvalidMessageFormatException;
4 | import gr.datamation.mt.common.SwiftMessage;
5 | import gr.datamation.mt.common.Tag;
6 | import gr.datamation.mt.processor.SwiftMsgProcessor;
7 | import gr.datamation.mt.validator.SwiftMsgValidator;
8 | import gr.datamation.mt.validator.SwiftValidObj;
9 |
10 | public class ParseValidMT01 {
11 | private static final String mt101String =
12 | "{1:F01COPZBEB0AXXX0377002843}{2:O1011519110804LRLRXXXX4A1100009044661108041720N}{3:{108:MT101 006 OF 020}{433:/AOK/NO HIT DETECTED }}{4:\n" +
13 | ":20:00043\n" +
14 | ":28D:1/1\n" +
15 | ":50F:/409074-293-45/786\n" +
16 | "1/George Philips\n" +
17 | "2/High Street 1\n" +
18 | "3/GB/London\n" +
19 | ":30:011231\n" +
20 | ":21:PQR-27ZZ-01\n" +
21 | ":32B:USD2564,50\n" +
22 | ":57D:/C/Clementine Nuggets-1842-Y\n" +
23 | "MynR49R RailRoad Trust\n" +
24 | "Cloudsboro ARTUI\n" +
25 | ":59F:1/Beneficiary Name-1234567891234123\n" +
26 | "2/QWERT\n" +
27 | "3/US/Beneficiary Address Line 21\n" +
28 | "3/Beneficiary Name-1234567891234123\n" +
29 | ":71A:OUR\n" +
30 | "-}{5:{MAC:00000000}{CHK:19DA346889CC}{TNG:}}{S:{SAC:}{COP:P}}";
31 |
32 | public static void execute() {
33 | //You can instatiate the SwiftMsgProcessor with the EOL of your choice.
34 | //\n for linux based systems or \r\b for Windows
35 | //If the default constructor is used then the \n will be used by default
36 | SwiftMsgProcessor parser = new SwiftMsgProcessor("\n");
37 | try {
38 | System.out.println("Parsing a valid MT101 message");
39 | SwiftMessage smObj = parser.ParseMsgStringToObject(mt101String);
40 | System.out.println("Sender " + smObj.getArgLTaddrBlk1());
41 | System.out.println("Receiver " + smObj.getArgLTaddrBlk2());
42 | Tag tag20 = smObj.getTag("20");
43 | Tag tag50a = smObj.getTag("50F");
44 | //Get specific tag from the SwiftMessage object
45 | System.out.println("Tag " + tag20.getName() + " " +
46 | " " + tag20.getValueAsString());
47 | System.out.println("Tag " + tag50a.getName() + " Number of Lines "
48 | + tag50a.getNumberOfDataLines());
49 | tag50a.getData().stream().forEach(line ->
50 | System.out.println(tag50a.getName() + " line " + line));
51 | //In the full version of the product you will have access to the tag's
52 | // description as given by swift by calling the following method
53 | //System.out.println("Description: " +
54 | // tag20.getDescription(smObj.getArgMsgtype()));
55 | //Output "Description: Sender's Reference"
56 |
57 | //Validate the message
58 | SwiftValidObj swiftValidObj = new SwiftMsgValidator().validateMsg(smObj);
59 | //Check if it has any errors
60 | if (!swiftValidObj.hasErrors()) {
61 | System.out.println("Message is valid");
62 | } else {
63 | Utils.printErrors(swiftValidObj);
64 | }
65 | } catch (InvalidMessageFormatException e) {
66 | System.err.println("Message cannot be parsed");
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/main/java/com/paymentcomponents/mt/demo/ParseInvalidMT01.java:
--------------------------------------------------------------------------------
1 | package com.paymentcomponents.mt.demo;
2 |
3 | import gr.datamation.mt.common.InvalidMessageFormatException;
4 | import gr.datamation.mt.common.SwiftMessage;
5 | import gr.datamation.mt.processor.SwiftMsgProcessor;
6 | import gr.datamation.mt.validator.SwiftMsgValidator;
7 | import gr.datamation.mt.validator.SwiftValidObj;
8 |
9 | public class ParseInvalidMT01 {
10 |
11 | public static void execute() {
12 | System.out.println("Parsing invalid MT101 message");
13 | invalidCurrencyCode();
14 | nonExpectedCharacter();
15 | invalidFormat();
16 | mandatoryFieldMissing();
17 | networkValidationError();
18 | }
19 |
20 | private static void validate(String mt101String){
21 | SwiftMsgProcessor parser = new SwiftMsgProcessor("\n");
22 | try {
23 | SwiftMessage smObj = parser.ParseMsgStringToObject(mt101String);
24 | //Validate the message
25 | SwiftValidObj swiftValidObj = new SwiftMsgValidator().validateMsg(smObj);
26 | //Check if it has any errors
27 | if (swiftValidObj.hasErrors()) {
28 | Utils.printErrors(swiftValidObj);
29 | }
30 | } catch (InvalidMessageFormatException e) {
31 | System.err.println("Message cannot be parsed");
32 | }
33 | }
34 |
35 | private static void invalidCurrencyCode(){
36 | validate("{1:F01COPZBEB0AXXX0377002843}{2:O1011519110804LRLRXXXX4A1100009044661108041720N}{3:{108:MT101 006 OF 020}{433:/AOK/NO HIT DETECTED }}{4:\n" +
37 | ":20:00043\n" +
38 | ":28D:1/1\n" +
39 | ":50F:/409074-293-45/786\n" +
40 | "1/George Philips\n" +
41 | "2/High Street 1\n" +
42 | "3/GB/London\n" +
43 | ":30:011231\n" +
44 | ":21:PQR-27ZZ-01\n" +
45 | ":32B:AAA2564,50\n" +
46 | ":57D:/C/Clementine Nuggets-1842-Y\n" +
47 | "MynR49R RailRoad Trust\n" +
48 | "Cloudsboro ARTUI\n" +
49 | ":59F:1/Beneficiary Name-1234567891234123\n" +
50 | "2/QWERT\n" +
51 | "3/US/Beneficiary Address Line 21\n" +
52 | "3/Beneficiary Name-1234567891234123\n" +
53 | ":71A:OUR\n" +
54 | "-}{5:{MAC:00000000}{CHK:19DA346889CC}{TNG:}}{S:{SAC:}{COP:P}}");
55 |
56 | }
57 |
58 | private static void nonExpectedCharacter(){
59 | validate("{1:F01COPZBEB0AXXX0377002843}{2:O1011519110804LRLRXXXX4A1100009044661108041720N}{3:{108:MT101 006 OF 020}{433:/AOK/NO HIT DETECTED }}{4:\n" +
60 | ":20:00043@\n" +
61 | ":28D:1/1\n" +
62 | ":50F:/409074-293-45/786\n" +
63 | "1/George Philips\n" +
64 | "2/High Street 1\n" +
65 | "3/GB/London\n" +
66 | ":30:011231\n" +
67 | ":21:PQR-27ZZ-01\n" +
68 | ":32B:USD2564,50\n" +
69 | ":57D:/C/Clementine Nuggets-1842-Y\n" +
70 | "MynR49R RailRoad Trust\n" +
71 | "Cloudsboro ARTUI\n" +
72 | ":59F:1/Beneficiary Name-1234567891234123\n" +
73 | "2/QWERT\n" +
74 | "3/US/Beneficiary Address Line 21\n" +
75 | "3/Beneficiary Name-1234567891234123\n" +
76 | ":71A:OUR\n" +
77 | "-}{5:{MAC:00000000}{CHK:19DA346889CC}{TNG:}}{S:{SAC:}{COP:P}}");
78 |
79 | }
80 |
81 | private static void invalidFormat(){
82 | validate("{1:F01COPZBEB0AXXX0377002843}{2:O1011519110804LRLRXXXX4A1100009044661108041720N}{3:{108:MT101 006 OF 020}{433:/AOK/NO HIT DETECTED }}{4:\n" +
83 | ":20:0004322222222222222\n" +
84 | ":28D:1/1\n" +
85 | ":50F:/409074-293-45/786\n" +
86 | "1/George Philips\n" +
87 | "2/High Street 1\n" +
88 | "3/GB/London\n" +
89 | ":30:011231\n" +
90 | ":21:PQR-27ZZ-01\n" +
91 | ":32B:USD2564,50\n" +
92 | ":57D:/C/Clementine Nuggets-1842-Y\n" +
93 | "MynR49R RailRoad Trust\n" +
94 | "Cloudsboro ARTUI\n" +
95 | ":59F:1/Beneficiary Name-1234567891234123\n" +
96 | "2/QWERT\n" +
97 | "3/US/Beneficiary Address Line 21\n" +
98 | "3/Beneficiary Name-1234567891234123\n" +
99 | ":71A:OUR\n" +
100 | "-}{5:{MAC:00000000}{CHK:19DA346889CC}{TNG:}}{S:{SAC:}{COP:P}}");
101 |
102 | }
103 |
104 | private static void mandatoryFieldMissing(){
105 | validate("{1:F01COPZBEB0AXXX0377002843}{2:O1011519110804LRLRXXXX4A1100009044661108041720N}{3:{108:MT101 006 OF 020}{433:/AOK/NO HIT DETECTED }}{4:\n" +
106 | ":28D:1/1\n" +
107 | ":50F:/409074-293-45/786\n" +
108 | "1/George Philips\n" +
109 | "2/High Street 1\n" +
110 | "3/GB/London\n" +
111 | ":30:011231\n" +
112 | ":21:PQR-27ZZ-01\n" +
113 | ":32B:USD2564,50\n" +
114 | ":57D:/C/Clementine Nuggets-1842-Y\n" +
115 | "MynR49R RailRoad Trust\n" +
116 | "Cloudsboro ARTUI\n" +
117 | ":59F:1/Beneficiary Name-1234567891234123\n" +
118 | "2/QWERT\n" +
119 | "3/US/Beneficiary Address Line 21\n" +
120 | "3/Beneficiary Name-1234567891234123\n" +
121 | ":71A:OUR\n" +
122 | "-}{5:{MAC:00000000}{CHK:19DA346889CC}{TNG:}}{S:{SAC:}{COP:P}}");
123 |
124 | }
125 |
126 | private static void networkValidationError(){
127 | validate("{1:F01COPZBEB0AXXX0377002843}{2:O1011519110804LRLRXXXX4A1100009044661108041720N}{3:{108:MT101 006 OF 020}{433:/AOK/NO HIT DETECTED }}{4:\n" +
128 | ":20:1234567890123456\n" +
129 | ":28D:1/1\n" +
130 | ":50F:/409074-293-45/786\n" +
131 | "1/George Philips\n" +
132 | "2/High Street 1\n" +
133 | "3/GB/London\n" +
134 | ":30:011231\n" +
135 | ":21:PQR-27ZZ-01\n" +
136 | ":32B:USD2564,50\n" +
137 | ":57D:/C/Clementine Nuggets-1842-Y\n" +
138 | "MynR49R RailRoad Trust\n" +
139 | "Cloudsboro ARTUI\n" +
140 | ":59F:1/Beneficiary Name-1234567891234123\n" +
141 | "2/QWERT\n" +
142 | "3/US/Beneficiary Address Line 21\n" +
143 | "3/Beneficiary Name-1234567891234123\n" +
144 | ":33B:EUR2564,50\n" +
145 | ":71A:OUR\n" +
146 | "-}{5:{MAC:00000000}{CHK:19DA346889CC}{TNG:}}{S:{SAC:}{COP:P}}");
147 |
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Swift MT Message Validator Demo
6 |
7 | This project is part of the [FINaplo](https://finaplo.paymentcomponents.com) product and is here to demonstrate how our [SDK](https://finaplo.paymentcomponents.com/financial-messages) for Swift MT Messages Validation works.
8 | For our demonstration we are going to use the demo SDK which can parse/validate/generate an MT101 message.
9 |
10 | It's a simple maven project, you can download it and run it, with Java 1.8 or above.
11 |
12 | ## API Specification
13 |
14 | ### Installation
15 | Incorporate the SDK [jar](https://nexus.paymentcomponents.com/repository/public/gr/datamation/smv/24.2.0/smv-24.2.0-demo.jar)
16 | into your project by the regular IDE means. This process will vary depending upon your specific IDE and you should consult your documentation on how to deploy a bean. For example in Eclipse all that needs to be done is to import the jar files into a project.
17 | Alternatively, you can import it as a Maven or Gradle dependency
18 |
19 | #### Maven
20 | Define repository in the repositories section
21 | ```xml
22 |
23 | paymentcomponents
24 | https://nexus.paymentcomponents.com/repository/public
25 |
26 | ```
27 |
28 | Import the SDK
29 | ```xml
30 |
31 | gr.datamation
32 | smv
33 | 24.2.0
34 | demo
35 |
36 | ```
37 |
38 | #### Gradle
39 | Define repository in the repositories section
40 | ```groovy
41 | repositories {
42 | maven {
43 | url "https://nexus.paymentcomponents.com/repository/public"
44 | }
45 | }
46 | ```
47 |
48 | Import the SDK
49 | ```groovy
50 | implementation 'gr.datamation:smv:24.2.0:demo@jar'
51 | ```
52 | In case you purchase the SDK you will be given a protected Maven repository with a user name and a password. You can configure your project to download the SDK from there.
53 |
54 | #### Other dependencies
55 | There is a dependency in jdom2 library which is used for XML generation. In case it's a maven projects the following dependency it will added to your project, otherwise you need to include the jar manually to the classpath
56 | ```xml
57 |
58 | org.jdom
59 | jdom2
60 | 2.0.6
61 |
62 | ```
63 |
64 | In this project you can see code for all the basic manipulation of an MT message, like:
65 | - [Parse a valid MT](src/main/java/com/paymentcomponents/mt/demo/demo/ParseValidMT01.java)
66 | - [Parse invalid MTs](src/main/java/com/paymentcomponents/mt/demo/demo/ParseInvalidMT01.java) and get the syntax and network validations error
67 | - [Build an MT - Way 1](src/main/java/com/paymentcomponents/mt/demo/demo/BuildMT101_1.java)
68 | - [Build an MT - Way 2](src/main/java/com/paymentcomponents/mt/demo/demo/BuildMT101_2.java)
69 | - [Convert an MT from text to xml](src/main/java/com/paymentcomponents/mt/demo/demo/ConvertMT2XML.java)
70 |
71 |
72 |
73 | ### SwiftMsgParser object
74 | This object has two methods encapsulating all the functionality needed to handle a SWIFT message
75 |
76 | #### ParseMsgStringToObject method
77 | This is the method used to parse a swift message. It takes as input a string containing a single message as it arrives from the SWIFT network. The method first validates the message for syntax errors, to ensure that the message string was extracted correctly from the SWIFT system. Then parses it producing the SwiftMessage object containing the values of the message tags. The parser uses an efficient and fast algorithm that ensures the correct breakdown of the message to its information in the minimum time.
78 | {1:F01ABCDGRA0AXXX0057000289}{2:O1030919010321DDDDGRA0AXXX00570001710103210920N}{3:{113:ABCD}{111:111}{121:01911b73-1f15-4932-934a-609149301922}}{4:crlf
79 | :20:494930/DEVcrlf
80 | :32A:020527EUR1958,47crlf
81 | :50:BIODATA GJBHcrlf
82 | ZURICHcrlf
83 | :59:S.T JANSSENcrlf
84 | LEDEBOERSTRAAT 29crlf
85 | AMSTERDAMcrlf
86 | -}{5:{MAC:75D138E4}{CHK:DE1B0D71FA96}{TNG:}}{S:{SAC:}{COP}}
87 |
88 | Observe there are carriage-return line-feeds (crlf) separating each line. So when using your own examples, make sure you use the appropriate crlf's.
89 | To parse it, do the following:
90 |
91 | ```java
92 | //Put your SWIFT message in a string
93 | String message = "{1:F01ABCDGRA0AXXX0057000289}{2:O1000919010321DDDDGRA0AXXX00570001710103210920N}{3:{113:ABCD}{111:111}{121:01911b73-1f15-4932-934a-609149301922}}{4:\n:20:494930/DEV\n:32A:020527EUR1958,47\n:50:BIODATA GJBH\nZURICH\n:59:S.T JANSSEN\nLEDEBOERSTRAAT 29\nAMSTERDAM\n}{5:{MAC:75D138E4}{CHK:DE1B0D71FA96}{TNG:}}{S:{SAC:}{COP}}";
94 | //Create the parser object as below
95 | SwiftMsgProcessor parser = new SwiftMsgProcessor();
96 | //Create the return object to get back the results
97 | SwiftMessage smObj = parser.ParseMsgStringToObject(Message);
98 | ```
99 |
100 | You are done! Now the smObj contains the parsed message. To see how to get or manipulate this object read the "SwiftMessage object" section below.
101 |
102 | #### ParseMsgStringsToObject method
103 | Since the version 14.1.0 you can use this method to construct a SwiftMessage object from multiple related SWIFT messages. The parser will undertake the merging process. The message types supported are:
104 | MT700 (with the MT701 sequence messages)
105 | MT710 (with the MT711 sequence messages)
106 | MT720 (with the MT721 sequence messages)
107 | The library will process tags 45B, 46B and 47B in the sequence messages and will assign the concatenated results inside the corresponding master message (i.e. MT700 or MT710 or MT720) in tags 45A, 46A and 47A respectively. Pagination (Field 27 in the resulting message) will be handled automatically. The messages passed as arguments should have correct pagination, but they do not necessarily need to be provided in the correct order as the library will sort them prior to proceeding further.
108 |
109 | Sample parsing multiple messages
110 | ```java
111 | SwiftMsgProcessor processor = new SwiftMsgProcessor();
112 |
113 | String messageContentMaster = //... mt700
114 | String messageContent1 = //... mt701
115 | String messageContent2 = //... mt701
116 | String messageContent3 = //... mt701
117 |
118 | //the result message will be an MT700 message holding the content of all messages passed as the arguments
119 | SwiftMessage result = processor.ParseMsgStringsToObject(Arrays.asList(messageContentMaster, messageContent1, messageContent2, messageContent3));
120 | ```
121 |
122 | #### BuildMsgStringFromObject method
123 | Use this method to construct a SWIFT message before sending it to the SWIFT network. It takes as input a SwiftMessage object that has been constructed by the programmer (see next section) and performs all the necessary formatting to produce a message with valid syntax. In other words programmer just assigns the right values to the tags of the SwiftMessage object and calls the method to build the SWIFT string ready to be transmitted to the SWIFT network. To enforce or check semantic rules such as tag sequence required fields etc, the SwiftMessageValidator, another PaymentComponents component should be called. To build a valid Swift string so that it can be transmitted to the SWIFT network follow the steps below:
124 |
125 | ```java
126 | //Create the component as below
127 | SwiftMsgProcessor SMP = new SwiftMsgProcessor();
128 |
129 | //Create the "SwiftMessage" object to set its Tags.
130 | SwiftMessage smObj = new SwiftMessage();
131 |
132 | //Set all the needed tags for the message. Start with block1 and block2
133 | smObj.setArgApplid("F");
134 | smObj.setArgServid("01");
135 | smObj.setArgLTaddrBlk1 ("FFFFGRA0AXXX");
136 | smObj.setArgInoutind("I");
137 | smObj.setArgMsgtype("103");
138 | smObj.setArgLTaddrBlk2("UUUUGRA0AXXX");
139 | smObj.setArgMsgprior("N");
140 |
141 | smObj.setServiceTypeIdentifier("111");
142 | smObj.setUniqueEndToEndTrxRef("01911b73-1f15-4932-934a-609149301922");
143 | smObj.setPaymentControlsInformation("/AAA/someScreeningInfo");
144 |
145 | //When finished with block1 and block2 continue with block4,
146 | //Create vector to store the line data of tag 20.
147 | java.util.Vector vec20 = new java.util.Vector();
148 | //add one data line
149 | vec20.addElement("12345678");
150 | // Create Tag object to store name and data line for tag 20.
151 | Tag tag20 = new Tag("20",vec20);
152 | //add tag 20 to block4 vector
153 | smObj.getBlock4().addElement(tag20);
154 |
155 | //Do the same for 52A
156 | java.util.Vector vec52A = new java.util.Vector();
157 | vec52A.addElement("/12345"); // add first data line
158 | vec52A.addElement("ABCDE"); // add second data line
159 | Tag tag52A = new Tag("52A", vec52A);
160 | smObj.getBlock4().addElement(tag52A); //add tag 52A to block4 vector
161 |
162 | //Now build the outgoing message in a string format as SWIFT expects it.
163 | String message = SMP.BuildMsgStringFromObject(smObj);
164 |
165 | You are done! Now variable message contains all the Tags of the "SwiftMessage" – including the necessary carriage return linefeeds - and looks like the string below
166 | {1:F01FFFFGRA0AXXX0000000000}{2:I103UUUUGRA0AXXXN}{3:{111:111}{121:01911b73-1f15-4932-934a-609149301922}{434:/AAA/someScreeningInfo}}{4:
167 | :20:12345678
168 | :52A:/12345
169 | ABCDE
170 | -}
171 | ```
172 |
173 | #### SwiftMessage object
174 | This is the heart of the component. It is the object that the parser populates with the values of the incoming message. This is the object the programmer accesses to get the values. It keeps the message information in vectors of Tag objects (see next section) and provides various methods to access and manipulate the object. There are more than 70 methods available. The programmer will need a small subset of them. Some of those are described below. The rest are straightforward in their usage and can be seen in the JavaDoc.
175 |
176 | ##### clear()
177 | Clears all the fields of the "SwiftMessage". This includes all block vectors and message property fields.
178 | ```java
179 | smobj.clear();
180 | ```
181 | ##### displayMessage()
182 | Displays at the standard output a text representation of the SWIFT message filled Tags
183 | ```java
184 | smobj.displayMessage();
185 | The above will display as the output the following
186 | Applid : F
187 | Servid : 01
188 | LTaddrBlk1: FFFFGRA0AXXX
189 | Sesno : 0000
190 | Osn : 000000
191 | Inoutind : I
192 | Msgtype : 103
193 | LTaddrBlk2 : UUUUGRA0AXXX
194 | Msgprior: N
195 | 113 : ABCD
196 | 20 : 494930/DEV
197 | 32A : 020527EUR1958,47
198 | 21 : 2222222
199 | 50 : BIODATA GJBH
200 | 50 : ZURICH
201 | 59 : S.T JANSSEN
202 | 59 : LEDEBOERSTRAAT
203 | 59 : AMSTERDAM
204 | ```
205 |
206 | ##### getArgApplid()
207 | Returns "Application Identifier" of the SWIFT message.
208 | ```java
209 | smobj.getArgApplid();
210 | ```
211 | The above returns "F".
212 |
213 | ##### getArgLTaddrBlk1()
214 | Returns "LT address" of the SWIFT message (Basic Header Block (1))
215 | ```java
216 | smobj.getArgLTaddrBlk1();
217 | ```
218 | The above returns "FFFFGRA0AXXX".
219 |
220 | ##### getArgMsgtype()
221 | Returns "Message Type" of the SWIFT message
222 | ```java
223 | smobj.getArgMsgtype();
224 | ```
225 | The above returns "103".
226 |
227 | ##### getBlockx()
228 | Returns a vector with all the tags of block x of the message.
229 | ```java
230 | smobj.getBlock1();
231 | ```
232 | The above returns
233 | ```
234 | [Applid[0]:F, Servid[0]:01, LTaddrBlk1[0]:FFFFGRA0AXXX, Sesno[0]:0000, Osn[0]:000000]
235 | ```
236 |
237 | ##### getMessageAsVector()
238 | Returns a vector containing all the tags of the message in their original sequence.
239 | ```java
240 | smobj.getMessageAsVector();
241 | ```
242 | The above returns
243 | ```
244 | [Applid[0]:F, Servid[0]:01, LTaddrBlk1[0]:FFFFGRA0AXXX, Sesno[0]:0000, Osn[0]:000000,Inoutind[0]:I , Msgtype[0]:103, LTaddrBlk2[0]:UUUUGRA0AXXX, Msgprior[0]:N, 3[0]:ABCD , 20[0]:494930/DEV, 32A[0]:020527EUR1958,47, 21[0]:2222222, 50[0]:BIODATA GJBH 50[1]:ZURICH, 59[0]:S.T JANSSEN 59[1]:LEDEBOERSTRAAT 29 59[2]:AMSTERDAM]
245 | ```
246 |
247 | ##### getNumbertOfTagInstances(String name)
248 | Returns the number of instances for the specific Tag. If tag does not exist then it returns 0.
249 | ```java
250 | smobj.getNumbertOfTagInstances("20");
251 | ```
252 | The above returns the integer 1.
253 |
254 | ##### getTag(String name)
255 | ```java
256 | smobj.getTag("20");
257 | ```
258 | The above returns a Tag object with all the information of tag 20 of the message.
259 | A tag may exist more than once. This method returns the first instance of the tag.
260 |
261 | ##### getTag(String tagName, int index)
262 | Returns the specified (if exists) instance of the tag with name tagName in the message (i.e. if tag20 exists three times in a message then getTag("20",1) returns the first occurrence of tag20 and getTag("20",3) returns the third. If tag does not exist or index is greater than the maximum number of tag representation then it returns null.
263 | ```java
264 | smobj.getTag("20",1);
265 | ```
266 | The above returns a Tag object having all the information of tag 20 of the message.
267 |
268 | ##### isblockEmpty(int index)
269 | Returns true when the specific block vector has no Tags.
270 | ```java
271 | isblockEmpty(4);
272 | ```
273 | The above returns false.
274 |
275 | ##### getUniqueEndToEndTrxRef()
276 | Returns the "Unique end-to-end transaction Reference or UETR (121) " of a SWIFT message
277 | ```java
278 | smobj.getUniqueEndToEndTrxRef();
279 | ```
280 |
281 | ##### getPaymentControlsInformation()
282 | Returns the "Payment Controls Info (434) " of a SWIFT message
283 | ```java
284 | smobj.getPaymentControlsInformation();
285 | ```
286 |
287 | ##### getServiceTypeIdentifier()
288 | Returns the "Service Type Identifier (111) " of a SWIFT message
289 | ```java
290 | smobj.getServiceTypeIdentifier();
291 | ```
292 |
293 | ##### setArgLTaddrBlk1(String newArgLTaddrBlk1)
294 | Sets the text part for "LT address" of the SWIFT message (Basic Header Block (1))
295 | ```java
296 | smobj.setArgLTaddrBlk1("FFFFGRA0AXXX");
297 | ```
298 | The above sets FFFFGRA0AXXX to LTaddrBlk1 property.
299 |
300 | ##### setArgMsgtype(String newArgMsgtype)
301 | Sets the "Message Type" of a SWIFT message
302 | ```java
303 | smobj.setArgMsgtype("103");
304 | ```
305 | The above sets 103 to MsgType property.
306 |
307 | ##### setBlockx(Vector newBlockx)
308 | Sets a vector containing all the tags of a specific block in their original sequence.
309 | ```java
310 | java.util.Vector tmpVec = new java.util.Vector();
311 | tmpVec.addElement("I");
312 | tmpVec.addElement("103");
313 | tmpVec.addElement("UUUUGRA0AXXX");
314 | tmpVec.addElement("N");
315 | SwiftMessage smobj = new SwiftMessage();
316 | smobj.setBlock2(tmpVec);
317 | ```
318 | The above sets tmpVec vector to block2 property.
319 |
320 | ##### setUniqueEndToEndTrxRef(String newUniqueEndToEndTrxRef)
321 | Sets the "Unique end-to-end transaction Reference or UETR (121) " of a SWIFT message
322 | ```java
323 | smobj.setUniqueEndToEndTrxRef("01911b73-1f15-4932-934a-609149301922");
324 | ```
325 | The above sets the UETR to the 121 field of MT103.
326 |
327 | ##### setServiceTypeIdentifier(String newServiceTypeIdentifier)
328 | Sets the "Service Type Identifier (111)" of a SWIFT message
329 | ```java
330 | smobj.setServiceTypeIdentifier("111");
331 | ```
332 | The above sets the Service Type Identifier to the 111 field of Block 3.
333 |
334 |
335 | ##### setPaymentControlsInformation(String newPaymentControlsInformation)
336 | Sets the "Payment Controls Information (434) " of a SWIFT message
337 | ```java
338 | smobj.setPaymentControlsInformation("/AAA/someScreeningInfo");
339 | ```
340 | The above sets the Payment Controls Info to the 434 field of MT103.
341 |
342 | ##### toString()
343 | Returns the String representation of this SWIFT Message
344 | ```java
345 | smobj.toString();
346 | ```
347 | The above returns the string
348 | ```java
349 | Applid[0]:F Servid[0]:01 LTaddrBlk1[0]:FFFFGRA0AXXX Sesno[0]:0000 Osn[0]:000000 Inoutind[0]:I Msgtype[0]:103 LTaddrBlk2[0]:UUUUGRA0AXXX Msgprior[0]:N 113[0]:ABCD 20[0]:494930/DEV 32A[0]:020527EUR1958,47 21[0]:2222222 50[0]:BIODATA GJBH 50[1]:ZURICH 59[0]:S.T JANSSEN 59[1]:LEDEBOERSTRAAT 29 59[2]:AMSTERDAM
350 | ```
351 |
352 | ##### autoReply(final String confirmationId, final String statusCode, final String reasonCode, final String forwardTo, final String settlementCode, final String clearingSystem)
353 | Since release 20.2.0, and in the paid version only, you have the option to create an MT199, with acctepance/rejection/in process status codes, for an MT103, according to the Univeral Confirmations rule book. See the [gist here](https://gist.github.com/pc14-alexandrakis/4ec4ac8fbb8cffcbe9a7ea5605a4747d)
354 |
355 | #### Tag object
356 | This object is used to handle the message tags. Its properties are name and data. Name is a string containing the name of the tag (i.e. 52A). Data is a vector of strings containing the lines of tag information. It is accompanied by a number of utility methods to set and get the values or do other manipulation. Only the most important of these methods are described below. The rest are straight forward in usage and can be seen in the JavaDoc.
357 |
358 | ##### addDataLine(String line)
359 | Adds a string containing the information of a Tag line to Data vector.
360 | ```java
361 | tag59.addDataLine("S.T JANSSEN");
362 | tag59.addDataLine("LEDEBOERSTRAAT 29");
363 | tag59.addDataLine("AMSTERDAM");
364 | ```
365 |
366 | ##### clearAll()
367 | Clears the Tag properties name and data.
368 | ```java
369 | tag59.clearAll();
370 | ```
371 |
372 | ##### getData()
373 | Returns a vector of strings containing the tag information. Each line of information is a vector element.
374 | ```java
375 | Vector tempVec = tag59.getData();
376 | ```
377 | Now tempVec vector contains the value:
378 | ```[S.T JANSSEN, LEDEBOERSTRAAT 29, AMSTERDAM]```
379 | ##### getDataLineAt(int index)
380 | Returns a string containing the information of the specified line of the tag. e.g. Assuming that in the original tag looks like the following
381 | ```
382 | :59:S.T JANSSEN
383 | LEDEBOERSTRAAT 29
384 | AMSTERDAM
385 | ```
386 |
387 | ```
388 | String data59l0 = tag59.getDataLineAt(0);
389 | String data59l2 = tag59.getDataLineAt(2);
390 | ```
391 | The above will set "S.T JANSSEN" to data59l0 and "AMSTERDAM" to data59l2 variable.
392 |
393 | ##### getName()
394 | Returns a string containing the name of the tag.
395 | ```java
396 | tag59.getName();
397 | ```
398 | The above will return "59".
399 |
400 | ##### getNumberOfDataLines()
401 | Returns the number of lines that a tag has. Assuming that in the original tag looks like the following
402 | ```
403 | :59:S.T JANSSEN
404 | LEDEBOERSTRAAT 29
405 | AMSTERDAM
406 | ```
407 | ```java
408 | tag59.getNumberOfDataLines();
409 | ```
410 | The above returns the integer 3.
411 |
412 | ##### insertDataLineAt(String line, int index )
413 | Inserts the specified line in Data vector at the specified index. Each line with an index greater or equal to the specified index is shifted upward.
414 | Throws InvalidActionAttemptedException when the index is invalid. Assuming that in the original tag looks like the following
415 | ```
416 | :59:S.T JANSSEN
417 | LEDEBOERSTRAAT 29
418 | AMSTERDAM
419 | ```
420 | ```java
421 | tag59.InsertDataLineAt("HOLLAND",2);
422 | ```
423 | Now tag 59 looks like the following
424 | ```
425 | :59:S.T JANSSEN
426 | LEDEBOERSTRAAT 29
427 | HOLLAND
428 | AMSTERDAM
429 | ```
430 |
431 | ##### isEmpty()
432 | Returns true when Tag infromation is empty.
433 | ```java
434 | tag59.isEmpty();
435 | ```
436 |
437 | ##### setData(Vector Data)
438 | Sets the Data property (Vector) value.
439 |
440 | ```java
441 | Vector tmpVec = new Vector();
442 | tmpVec.addElement("S.T JANSSEN");
443 | tmpVec.addElement("LEDEBOERSTRAAT 29");
444 | tmpVec.addElement("AMSTERDAM");
445 | Tag tag59 = new Tag();
446 | tag59.setName("59");
447 | tag59.setData(tmpVec);
448 | ```
449 |
450 | ##### setDataLineAt(String line, int index )
451 | Inserts the specified line in Data vector at the specified index overwriting the old line. Throws InvalidActionAttemptedException when the index is invalid.
452 | Assuming that in the original tag looks like the following
453 | ```
454 | :59:S.T JANSSEN
455 | LEDEBOERSTRAAT 29
456 | AMSTERDAM
457 | ```
458 | ```java
459 | tag59.setDataLineAt("HOLLAND",1);
460 | ```
461 | Now tag 59 looks like the following
462 | ```
463 | :59:S.T JANSSEN
464 | HOLLAND
465 | AMSTERDAM
466 | ```
467 |
468 | ##### setName(String newName)
469 | Sets the Tags Name property (String) value.
470 | ```java
471 | Tag tag59 = new Tag();
472 | tag59.setName("59");
473 | ```
474 |
475 | ##### setTag(String name, Vector data)
476 | Sets Tags properties name and data.
477 | ```java
478 | Vector tmpVec = new Vector();
479 | tmpVec.addElement("S.T JANSSEN");
480 | tmpVec.addElement("LEDEBOERSTRAAT 29");
481 | tmpVec.addElement("AMSTERDAM");
482 | Tag tag59 = new Tag();
483 | tag59.setTag("59",tmpVec);
484 | ```
485 |
486 | ##### toString()
487 | Returns the String representation of this Tag.
488 | ```java
489 | tag59.toString();
490 | ```
491 | The above returns
492 | ```
493 | 59[0]:S.T JANSSEN 59[1]:LEDEBOERSTRAAT 29 59[2]:AMSTERDAM
494 | ```
495 |
496 | ##### Tag description
497 | **In the paid version**, you can now get each tag's description by using the `getDescription` method of the `Tag` object. So, if you have the tag object and you know the MT message it belongs to, you can use the following code
498 | ```java
499 | Tag tag20 = smObj.getTag("20");
500 | //Get specific tag from the SwiftMessage object
501 | System.out.println("Tag " + tag20.getName() + " " +
502 | " " + tag20.getValueAsString());
503 | System.out.println("Description: " +
504 | tag20.getDescription(smObj.getArgMsgtype()));
505 | ```
506 | and it will return the description of the tag. `MT_MESSAGE_NUMBER` is the mt message e.g. 103, 202, 700 etc. We have created a [gist here](https://gist.github.com/pc14-alexandrakis/067c319e37deec5bb357d526a953ebf4)
507 |
508 | #### The use of Repetitive Sequences in SWIFT messages
509 | Repetitive Sequences are used in certain SWIFT messages to enable groups of tags to be repeated more than once. The component represent these repetitive sequences by means of the `RepSeq` object. This means that a message can contain a combination of simple Tags and Repetitive Sequences, each of which is defined as optional or mandatory.
510 | The RepSeq object includes simple Tag objects (i.e. tag 21 will be included in this RepSeq object as a simple Tag object), or even other (nested) RepSeq objects since there are SWIFT messages that are more complicated and include repetitive sequences inside repetitive sequences.
511 | Check [here](src/main/java/com/paymentcomponents/mt/demo/demo/BuildMT101_1.java) how the Reppetitive Sequnece B, is being added to the Swift Message Object.
512 | ##### Note
513 | If we want to build a "Block" with a repetitive sequence named Rep1 (BlockRepSeq Rep1) which has another repetitive sequence named Rep2 inside it (BlockRepSeq Rep2), then: We create the second (inner) repetitive sequence (BlockRepSeq Rep2), we fill it with values, then we put it inside the first BlockRepSeq calling the addSubSequence method of the BlockRepSeq class, like this:
514 | ```java
515 | Rep1.addSubSequence(Rep2);
516 | ```
517 |
518 | #### SwiftMsgValidator object
519 | SwiftMsgValidator has just one method encapsulating the entire functionality needed to validate and build a SWIFT MT message.
520 | ##### Validating Objects - validateMsg method
521 | This method takes as input a SwiftMessage object that has been manually constructed by a developer [(as here)](src/main/java/com/paymentcomponents/mt/demo/demo/BuildMT101_1.java), performs SWIFT validations and returns a list of error messages (if the message it correct, then an empty list is returned; null is never returned). The `validateMsg` will also return a SwiftMessage object that might be sligthly different from the given one. For example the SK reorder the tags if they are in a wrong position in the message, so it's recommented to use the returned message object after the validation.
522 |
523 | #### Splitting Oversized Messages
524 | Since version 14.1.0, SwiftMsgValidator is able to split oversized messages if they belong in one of the supported categories (MT700, MT710, MT720). The validator will handle splitting automatically depending on the category of the input message.
525 | In case where the message type falls into one of the supported categories, additional sequence messages will be produced based on the input message type, and based on the following rules (applied in this order):
526 | If one or more of fields 45A, 46A, 47A of the input message have more lines than the allowed limit, according to the SWIFT standard, each field will be broken into multiple chunks, each being encapsulated inside a sequence message.
527 | If the message as a whole has more characters than the allowed limit per message, according to the SWIFT standard, each of the fields 45A, 46A, 47A will begin being transferred into new sequence messages (priority is given to the tags that have the most lines) up until the point where the message is not oversized anymore.
528 | In the case where the message will be split, pagination in field 27 will be handled automatically, and field 20 of the sequence messages will hold the value of field 20 of the original input message.
529 | Maximum amount of sequence messages that the original input message should be split into is 8 (to result in 9 messages along with the input one); this will allow to keep the syntax of the field 27 intact. If the original message is required to be split into a number of sequence messages greater than 8, the library will still proceed with the splitting, but the validation that follows will report errors in all messages regarding field 27, where the allowed format is 1!n/1!n.
530 | After splitting, all messages will be validated, and errors will be reported.
531 |
532 | #### Validation Results
533 | ##### getSwiftMessage() and getSwiftMessages()
534 | Since version 14.1.0, the SwiftValidObj object is able to return multiple message objects as a result of the validation process. The legacy getSwiftMessage method will always return the first message of the resulting array of message objects. The new method `getSwiftMessages` will return an array of SwiftMessages that are the result of the validation process. The validation error list inside the SwiftValidObj will hold errors that concern the entire array of messages.
535 |
536 | ##### getMessageIndex()
537 | Since version 14.1.0, the ValidationError objects have a new method, getMessageIndex which returns an integer indicating the index in the input array of the message this error corresponds to.
538 |
539 | #### XMLWriter object
540 | It is used to serialize the SwiftMessage object to a generic XML document. It does it with the use of buildXML method. It also uses Java Document Object Model (JDOM) that is delivered with the deployment jar. These open source classes can also be downloaded from www.jdom.org.
541 | Note: This article talks about gr.datamation.mt.swift2xml.XMLWriter. Avoid confusing with javax.sql.rowset.spi.XmlWriter.
542 |
543 | ##### buildXML method
544 | It is a method within XMLWriter object, and is the only one used to build a generic XML document. It has three inputs:
545 | 1. The SMP object after it has been created by the SMP parser
546 | 2. String containing the path where to write the XML Document (if the String is null, the current path will be used)
547 | 3. String containing the XML filename to be created.
548 |
549 | The method first validates the file name for syntax errors, to ensure that the XML will have alphanumeric characters.
550 | Example
551 | Check [here](src/main/java/com/paymentcomponents/mt/demo/demo/ConvertMT2XML.java) how to create XMLs from an MT
552 |
553 | ##### Tag61.splitTag()
554 | Since Tag61 includes many pieces of information, library offers a parsing of the Tag's fields. You get a map with fields name and field value.
555 | The below code
556 | ```java
557 | SwiftMessage message = new Msg940();
558 |
559 | message.getBlock4().clear();
560 | message.getBlock4().addAll(createTagList(
561 | ":61:1501080109D184,50NCHKNONREF ////D101 100771017\nCHQ WITHDR-DISSE"
562 | ));
563 | for (Object object : message.getBlock4()) {
564 | if (object instanceof Tag) {
565 | Tag tag = (Tag) object;
566 | if (tag.getName().equals("61")) {
567 | System.out.println(Tag61.splitTag(tag.getValueAsString()));
568 | }
569 |
570 | }
571 | }
572 | ```
573 | results to
574 | ```
575 | {dcMark=D, accOwnerRef=NONREF //, amount=184,50, entryDate=0109, idCode=CHK, accServRef=D101 100771017, valueDate=150108, supDetails=CHQ WITHDR-DISSE, fundsCode=null, tranType=N}
576 | ```
577 |
578 |
579 | ### More features are included in the paid version like
580 |
581 | [MT199 according to Universal Confirmations rules ](https://gist.github.com/pc14-alexandrakis/4ec4ac8fbb8cffcbe9a7ea5605a4747d)
582 |
583 | [Tag Descriptions](https://gist.github.com/pc14-alexandrakis/067c319e37deec5bb357d526a953ebf4)
584 |
585 | [Trade Finance Message Build](https://gist.github.com/apolichronopoulos/5039d48fca54791f0952799357482a14)
586 |
587 | [Trade Finance Message Parse](https://gist.github.com/apolichronopoulos/ab184196d3ae26d231b9bb031f1a9c5a)
588 |
589 | ### Error Codes Appendix
590 |
591 | |Code|Error Message|
592 | |---|---|
593 | |SV00|Swift Validator Error|
594 | |SV01|Field length exceeded|
595 | |SV02|Code word must be placed between slashes '/'|
596 | |SV03|Code word length exceeded|
597 | |SV04|Field not valid|
598 | |SV05|Amount must have a comma|
599 | |SV06|Amount must have only one comma|
600 | |SV07|Party Identifier format not valid|
601 | |SV08|Party Identifier must start with a slash '/'|
602 | |SV09|Does not contain a valid code word|
603 | |SV10|- Field must start with a double slash '//' or a '/'code word'/'.
- Field must start with a double slash '//'|
604 | |SV11|Maximum lines for this option are 2|
605 | |SV12|BIC is mandatory|
606 | |SV13|- At least one line must be present.
- Minimum lines for this option are: |
607 | |SV14|Maximum lines for this option are 5|
608 | |SV15|Option must be|
609 | |SV16|Mandatory Tag is missing|
610 | |SV17|Field must start with a '/'code word'/'|
611 | |SV18|Field must start with a double slash '//'|
612 | |SV19|Narrative text must not start with a slash|
613 | |SV20|Account line must start with a slash '/'|
614 | |SV21|Maximum lines for this option|
615 | |SV22|- Use a '/' to separate Message Index and Total fields.
- Use a '/' to separate Statement number and Sequence number|
616 | |SV23|- Message Index field must not be more than 5 digits.
- Statement number must not be more than 5 digits or less than 1 digit|
617 | |SV24|Total field length must be 4 digits|
618 | |SV25|- Message Index field must be numeric.
- Statement number must be numeric|
619 | |SV26|- Total field must be numeric. - Sequence number must be numeric.
- Number of days field is invalid or empty.
- Invalid function code word|
620 | |SV27|Use a '/' to separate Type and Market fields|
621 | |SV28|Use a '/' to separate Market and Data fields|
622 | |SV29|Repetitive sequence must not be present in message type|
623 | |SV30|At least one Repetitive sequence must be present|
624 | |SV31|Narrative text must start with a slash '/'|
625 | |SV32|Narrative text must be present|
626 | |SV33|Rate must have a comma|
627 | |SV34|Rate must have only one comma|
628 | |SV35|Rate must not start with a comma|
629 | |SV36|Field length must be : |
630 | |SV37|Both the account number and BEI line must be present|
631 | |SV38|The second character must be a slash '/'|
632 | |SV39|Invalid Session Number or ISN|
633 | |SV40|Message Type Number and Date fields must be present|
634 | |SV41|Country field is missing or invalid|
635 | |SV42|Account is mandatory|
636 | |SV43|Index field must not be more than 1 digit|
637 | |SV44|Partial Code Line must not be more than 33 digits|
638 | |SV45|Check the format option for field 50a (Instruction Party or Creditor)|
639 | |SV46|Tag 50a must not be present more than 2 times|
640 | |SV47|Second line must be present|
641 | |SV48|Tag 52 must not be present more than 2 times|
642 | |SV49|Check the format option for field 50a (Instruction Party or Ordering Customer)|
643 | |SV50|- Total field length must not be more than 5 digits.
- Sequence number must not be more than 5 digits or less than 1 digit.
- Sequence number must not be more than 2 digits or less than 1 digit|
644 | |SV51|Additional Information must start with a slash '/'|
645 | |SV52|BEI is mandatory|
646 | |SV53|Application Identifier is missing (Basic Header Block)|
647 | |SV54|Application Identifier is invalid (Basic Header Block)|
648 | |SV55|Service Identifier is missing (Basic Header Block)|
649 | |SV56|Service Identifier is invalid (Basic Header Block)|
650 | |SV57|LT Identifier is missing (Basic Header Block)|
651 | |SV58|LT Identifier is invalid (Basic Header Block)|
652 | |SV59|Session Number is invalid (Basic Header Block)|
653 | |SV60|Sequence Number is invalid (Basic Header Block)|
654 | |SV61|Input/Output Identifier must be 'I' or 'O' (Application Header Block)|
655 | |SV62|Message Type is missing (Application Header Block)|
656 | |SV63|Message Type is invalid (Application Header Block)|
657 | |SV64|Receiver Address is missing (Application Header Block)|
658 | |SV65|Receiver Address is invalid (Application Header Block)|
659 | |SV66|Message Priority is missing (Application Header Block)|
660 | |SV67|Message Priority is invalid (Application Header Block)|
661 | |SV68|Delivery Monitoring must be '1' or '3' (Application Header Block)|
662 | |SV69|Delivery Monitoring must be '2' or blank (Application Header Block)|
663 | |SV70|Delivery Monitoring must not be used (Application Header Block)|
664 | |SV71|Obsolescence period must not be used (Application Header Block)|
665 | |SV72|Obsolescence period must be '003' (Application Header Block)|
666 | |SV73|Obsolescence period must be '020' (Application Header Block)|
667 | |SV74|Obsolescence period is missing (Application Header Block).|
668 | |SV75|Swift Validator cannot handle this Type of Message|
669 | |SV76|Message Type is missing from the message|
670 | |SV77|At least one line of the subfield Name & Address is required|
671 | |SV78|Invalid format. Format is :|
672 | |SV78|Invalid format. Field must be empty|
673 | |SV79|Mandatory Subfield is missing or invalid|
674 | |SV79|Subfield is invalid|
675 | |SV80|Field length invalid|
676 | |SV81|Field must start with symbol ' : '|
677 | |SV82|Field after qualifier , must contain double slash '//'|
678 | |SV83|Use a '/' to separate Function and Subfunction fields|
679 | |SV84|Use a '/' to separate Qualifier , Data Source Scheme and Proprietary Code fields|
680 | |SV85|Use a '/' to separate Function and Name & Address fields|
681 | |SV86|Subfield must start with a slash '/'.|
682 | |SV87|Frequency/Timing in Period subfields are missing or invalid|
683 | |SV88|Use a '/' to separate Frequency and Timing in Period subfields|
684 | |SV89|Use a '/' to separate Timing in Period and Day subfields|
685 | |SV90|When subfield Day is present, it must consist of 2 numbers|
686 | |SV93|- Use a '/' to separate Qualifier , Data Source Scheme, Account Type Code and Account Number.
- Use a '/' to separate Code and Function|
687 | |SV94|Qualifier of Tag is Mandatory|
688 | |SV95|Invalid length of Qualifier|
689 | |SV96|Codes must start and end with a slash '/'.|
690 | |SV97|When an ISIN identifier is not used it is strongly recommended that one of the following codes be used at the first four characters of the description of security : The ISO two digit country code or /TS/ or /XX/.|
691 | |SV98|The decimal comma occurs more than one time(s)|
692 | |SV99|In field 72, if the code /INS/ is used at the beginning of a line, it must be followed by a valid financial institution BIC and be the only information on that line|
693 | |SV100|Missing Mandatory Sequence(s)|
694 | |SV101|Number of Days specifies the number of days notice (for example, 07). It must only be used when Function is NOTICE|
695 | |SV102|In field 72, when first line starts with one of the codes /RETN/ or /REJT/, the third line must start with the code /MREF/ and follow the format : 16x|
696 | |SV103|In field 72, when first line starts with one of the codes /RETN/ or /REJT/, code words must not be duplicated|
697 | |SV104|In field 72, when first line starts with one of the codes /RETN/ or /REJT/, code words on the lines 2-6 must be in proper sequence : reason code (format 2!c2!n), MREF, TREF (optional), CHGS (optional), TEXT (optional)|
698 | |SV105|In field 72, when first line starts with one of the codes /RETN/ or /REJT/, the information component following all code words, except for reason code (for example, /AC01/) is mandatory. This component must not be empty, nor consist entirely of blanks|
699 | |SV106|In field 72, information following the code /RETN/ or /REJT/ must consist of the field causing the reject or return, and possibly other message elements (for example, letter option and sequence identification), which may be helpful to the sender in isolating the specific error; format : 2!n[1!a][/2c].|
700 | |SV107|In field 72, when first line starts with one of the codes /RETN/ or /REJT/, each line must begin with the format : /'code word'/.|
701 | |SV108|One of the following codes must be used:|
702 | |SV109|Slash absent or in wrong position|
703 | |SV110|Left part not present|
704 | |SV111|Field must contain the following codes : |
705 | |SV112| must contain the following codes : |
706 | |SV113|Narrative text must not start with a slash and, if used, must begin on a new line and be the last information in the field|
707 | |SV115|At least one of the following codes should be used, placed between slashes \ /\ : |
708 | |SV116|For field in sequence the following values must not be repeated : |
709 | |SV117|At least one of fields 95P, 95Q, 95R must be present in sequence |
710 |
711 |
712 | ### NVD Data Usage
713 |
714 | This software uses data retrieved from the [National Vulnerability Database (NVD)](https://nvd.nist.gov/) API.
715 | **This product uses the NVD API but is not endorsed or certified by the NVD.**
716 |
717 | - NVD content is provided on an "as-is" and "as-available" basis by NIST.
718 | - Data returned by this SDK may be cached, normalized, or transformed before being exposed to clients.
719 | - Users of this SDK are responsible for supplying and managing their own NVD API key in accordance with the [NVD Terms of Use](https://nvd.nist.gov/developers).
720 | - Excessive use without caching may result in rate limiting or blocked access by NVD.
721 | - For enterprise-scale usage, consult NVD’s official guidance on mirroring or bulk data feeds.
--------------------------------------------------------------------------------