From a48e0625987442bd490766828d10187afc1ebbce Mon Sep 17 00:00:00 2001 From: mkuligowski Date: Tue, 30 Jan 2018 22:49:54 +0100 Subject: [PATCH] BAEL-1204 (#3508) * Initialize smooks subproject * Add Smooks dependency * Delete files form badly created submodule * Add domain classes * Create class responsible for converting Orders * Create class responsible for validating messages * Add configuration file * Add integration tests for Smooks converters and validators * ADd en_US locale and fix date format * Fix number format in expected messages * Delete unused mapping * Remove unused conversion to JSON * Add assertion for ruleName in givenIncorrectOrderXML_whenValidate_thenExpectValidationErrors --- libraries/pom.xml | 6 ++ .../smooks/converter/OrderConverter.java | 45 ++++++++++++ .../smooks/converter/OrderValidator.java | 27 +++++++ .../java/com/baeldung/smooks/model/Item.java | 71 +++++++++++++++++++ .../java/com/baeldung/smooks/model/Order.java | 52 ++++++++++++++ .../com/baeldung/smooks/model/Status.java | 5 ++ .../com/baeldung/smooks/model/Supplier.java | 49 +++++++++++++ libraries/src/main/resources/smooks/email.ftl | 8 +++ .../src/main/resources/smooks/item-rules.csv | 1 + libraries/src/main/resources/smooks/order.ftl | 7 ++ .../src/main/resources/smooks/order.json | 21 ++++++ libraries/src/main/resources/smooks/order.xml | 20 ++++++ .../main/resources/smooks/smooks-mapping.xml | 29 ++++++++ .../resources/smooks/smooks-transform-edi.xml | 11 +++ .../smooks/smooks-transform-email.xml | 12 ++++ .../resources/smooks/smooks-validation.xml | 17 +++++ .../main/resources/smooks/supplier.properties | 2 + .../converter/SmooksIntegrationTest.java | 70 ++++++++++++++++++ 18 files changed, 453 insertions(+) create mode 100644 libraries/src/main/java/com/baeldung/smooks/converter/OrderConverter.java create mode 100644 libraries/src/main/java/com/baeldung/smooks/converter/OrderValidator.java create mode 100644 libraries/src/main/java/com/baeldung/smooks/model/Item.java create mode 100644 libraries/src/main/java/com/baeldung/smooks/model/Order.java create mode 100644 libraries/src/main/java/com/baeldung/smooks/model/Status.java create mode 100644 libraries/src/main/java/com/baeldung/smooks/model/Supplier.java create mode 100644 libraries/src/main/resources/smooks/email.ftl create mode 100644 libraries/src/main/resources/smooks/item-rules.csv create mode 100644 libraries/src/main/resources/smooks/order.ftl create mode 100644 libraries/src/main/resources/smooks/order.json create mode 100644 libraries/src/main/resources/smooks/order.xml create mode 100644 libraries/src/main/resources/smooks/smooks-mapping.xml create mode 100644 libraries/src/main/resources/smooks/smooks-transform-edi.xml create mode 100644 libraries/src/main/resources/smooks/smooks-transform-email.xml create mode 100644 libraries/src/main/resources/smooks/smooks-validation.xml create mode 100644 libraries/src/main/resources/smooks/supplier.properties create mode 100644 libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java diff --git a/libraries/pom.xml b/libraries/pom.xml index 3e802e76c8..a330494bb3 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -710,6 +710,11 @@ test test + + org.milyn + milyn-smooks-all + ${smooks.version} + @@ -789,6 +794,7 @@ 1.23.0 v4-rev493-1.21.0 1.0.0 + 1.7.0 3.0.14 \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/smooks/converter/OrderConverter.java b/libraries/src/main/java/com/baeldung/smooks/converter/OrderConverter.java new file mode 100644 index 0000000000..d11f5a29b2 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/converter/OrderConverter.java @@ -0,0 +1,45 @@ +package com.baeldung.smooks.converter; + +import com.baeldung.smooks.model.Order; +import org.milyn.Smooks; +import org.milyn.payload.JavaResult; +import org.milyn.payload.StringResult; +import org.xml.sax.SAXException; + +import javax.xml.transform.stream.StreamSource; +import java.io.IOException; + +public class OrderConverter { + + public Order convertOrderXMLToOrderObject(String path) throws IOException, SAXException { + Smooks smooks = new Smooks(OrderConverter.class.getResourceAsStream("/smooks/smooks-mapping.xml")); + try { + JavaResult javaResult = new JavaResult(); + smooks.filterSource(new StreamSource(OrderConverter.class.getResourceAsStream(path)), javaResult); + return (Order) javaResult.getBean("order"); + } finally { + smooks.close(); + } + } + + + public String convertOrderXMLtoEDIFACT(String path) throws IOException, SAXException { + return convertDocumentWithTempalte(path, "/smooks/smooks-transform-edi.xml"); + } + + public String convertOrderXMLtoEmailMessage(String path) throws IOException, SAXException { + return convertDocumentWithTempalte(path, "/smooks/smooks-transform-email.xml"); + } + + private String convertDocumentWithTempalte(String path, String config) throws IOException, SAXException { + Smooks smooks = new Smooks(config); + + try { + StringResult stringResult = new StringResult(); + smooks.filterSource(new StreamSource(OrderConverter.class.getResourceAsStream(path)), stringResult); + return stringResult.toString(); + } finally { + smooks.close(); + } + } +} diff --git a/libraries/src/main/java/com/baeldung/smooks/converter/OrderValidator.java b/libraries/src/main/java/com/baeldung/smooks/converter/OrderValidator.java new file mode 100644 index 0000000000..3975921da0 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/converter/OrderValidator.java @@ -0,0 +1,27 @@ +package com.baeldung.smooks.converter; + +import org.milyn.Smooks; +import org.milyn.payload.JavaResult; +import org.milyn.payload.StringResult; +import org.milyn.validation.ValidationResult; +import org.xml.sax.SAXException; + +import javax.xml.transform.stream.StreamSource; +import java.io.IOException; + +public class OrderValidator { + + public ValidationResult validate(String path) throws IOException, SAXException { + Smooks smooks = new Smooks(OrderValidator.class.getResourceAsStream("/smooks/smooks-validation.xml")); + + try { + StringResult xmlResult = new StringResult(); + JavaResult javaResult = new JavaResult(); + ValidationResult validationResult = new ValidationResult(); + smooks.filterSource(new StreamSource(OrderValidator.class.getResourceAsStream(path)), xmlResult, javaResult, validationResult); + return validationResult; + } finally { + smooks.close(); + } + } +} diff --git a/libraries/src/main/java/com/baeldung/smooks/model/Item.java b/libraries/src/main/java/com/baeldung/smooks/model/Item.java new file mode 100644 index 0000000000..a7f7783b3f --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/model/Item.java @@ -0,0 +1,71 @@ +package com.baeldung.smooks.model; + +public class Item { + + public Item() { + } + + public Item(String code, Double price, Integer quantity) { + this.code = code; + this.price = price; + this.quantity = quantity; + } + + private String code; + private Double price; + private Integer quantity; + + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Item item = (Item) o; + + if (code != null ? !code.equals(item.code) : item.code != null) return false; + if (price != null ? !price.equals(item.price) : item.price != null) return false; + return quantity != null ? quantity.equals(item.quantity) : item.quantity == null; + } + + @Override + public int hashCode() { + int result = code != null ? code.hashCode() : 0; + result = 31 * result + (price != null ? price.hashCode() : 0); + result = 31 * result + (quantity != null ? quantity.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Item{" + + "code='" + code + '\'' + + ", price=" + price + + ", quantity=" + quantity + + '}'; + } +} diff --git a/libraries/src/main/java/com/baeldung/smooks/model/Order.java b/libraries/src/main/java/com/baeldung/smooks/model/Order.java new file mode 100644 index 0000000000..047e1fe8a3 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/model/Order.java @@ -0,0 +1,52 @@ +package com.baeldung.smooks.model; + +import java.util.Date; +import java.util.List; + +public class Order { + private Date creationDate; + private Long number; + private Status status; + private Supplier supplier; + private List items; + + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + public Long getNumber() { + return number; + } + + public void setNumber(Long number) { + this.number = number; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public Supplier getSupplier() { + return supplier; + } + + public void setSupplier(Supplier supplier) { + this.supplier = supplier; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } +} diff --git a/libraries/src/main/java/com/baeldung/smooks/model/Status.java b/libraries/src/main/java/com/baeldung/smooks/model/Status.java new file mode 100644 index 0000000000..53c50bdf46 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/model/Status.java @@ -0,0 +1,5 @@ +package com.baeldung.smooks.model; + +public enum Status { + NEW, IN_PROGRESS, FINISHED +} diff --git a/libraries/src/main/java/com/baeldung/smooks/model/Supplier.java b/libraries/src/main/java/com/baeldung/smooks/model/Supplier.java new file mode 100644 index 0000000000..31a9e1f43f --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/model/Supplier.java @@ -0,0 +1,49 @@ +package com.baeldung.smooks.model; + +public class Supplier { + + private String name; + private String phoneNumber; + + public Supplier() { + } + + public Supplier(String name, String phoneNumber) { + this.name = name; + this.phoneNumber = phoneNumber; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Supplier supplier = (Supplier) o; + + if (name != null ? !name.equals(supplier.name) : supplier.name != null) return false; + return phoneNumber != null ? phoneNumber.equals(supplier.phoneNumber) : supplier.phoneNumber == null; + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (phoneNumber != null ? phoneNumber.hashCode() : 0); + return result; + } +} diff --git a/libraries/src/main/resources/smooks/email.ftl b/libraries/src/main/resources/smooks/email.ftl new file mode 100644 index 0000000000..8413046508 --- /dev/null +++ b/libraries/src/main/resources/smooks/email.ftl @@ -0,0 +1,8 @@ +<#setting locale="en_US"> +Hi, +Order number #${order.number} created on ${order.creationDate?string["yyyy-MM-dd"]} is currently in ${order.status} status. +Consider contact supplier "${supplier.name}" with phone number: "${supplier.phoneNumber}". +Order items: +<#list items as item> +${item.quantity} X ${item.code} (total price ${item.price * item.quantity}) + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/item-rules.csv b/libraries/src/main/resources/smooks/item-rules.csv new file mode 100644 index 0000000000..c93c453f25 --- /dev/null +++ b/libraries/src/main/resources/smooks/item-rules.csv @@ -0,0 +1 @@ +"max_total","item.quantity * item.price < 300.00" diff --git a/libraries/src/main/resources/smooks/order.ftl b/libraries/src/main/resources/smooks/order.ftl new file mode 100644 index 0000000000..9d40eb55c7 --- /dev/null +++ b/libraries/src/main/resources/smooks/order.ftl @@ -0,0 +1,7 @@ +<#setting locale="en_US"> +UNA:+.? ' +UNH+${order.number}+${order.status}+${order.creationDate?string["yyyy-MM-dd"]}' +CTA+${supplier.name}+${supplier.phoneNumber}' +<#list items as item> +LIN+${item.quantity}+${item.code}+${item.price}' + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/order.json b/libraries/src/main/resources/smooks/order.json new file mode 100644 index 0000000000..bf6bc5fe93 --- /dev/null +++ b/libraries/src/main/resources/smooks/order.json @@ -0,0 +1,21 @@ +{ + "creationDate":"2018-01-14", + "orderNumber":771, + "orderStatus":"IN_PROGRESS", + "supplier":{ + "name":"CompanyX", + "phone":"1234567" + }, + "orderItems":[ + { + "quantity":1, + "code":"PX1234", + "price":9.99 + }, + { + "quantity":2, + "code":"RX1990", + "price":120.32 + } + ] +} \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/order.xml b/libraries/src/main/resources/smooks/order.xml new file mode 100644 index 0000000000..343c5cab38 --- /dev/null +++ b/libraries/src/main/resources/smooks/order.xml @@ -0,0 +1,20 @@ + + 771 + IN_PROGRESS + + CompanyX + 1234567 + + + + 1 + PX1234 + 9.99 + + + 2 + RX990 + 120.32 + + + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/smooks-mapping.xml b/libraries/src/main/resources/smooks/smooks-mapping.xml new file mode 100644 index 0000000000..7996834e38 --- /dev/null +++ b/libraries/src/main/resources/smooks/smooks-mapping.xml @@ -0,0 +1,29 @@ + + + + + + + + yyyy-MM-dd + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/smooks-transform-edi.xml b/libraries/src/main/resources/smooks/smooks-transform-edi.xml new file mode 100644 index 0000000000..1dae4055a8 --- /dev/null +++ b/libraries/src/main/resources/smooks/smooks-transform-edi.xml @@ -0,0 +1,11 @@ + + + + + + + /smooks/order.ftl + + + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/smooks-transform-email.xml b/libraries/src/main/resources/smooks/smooks-transform-email.xml new file mode 100644 index 0000000000..101aa67f0d --- /dev/null +++ b/libraries/src/main/resources/smooks/smooks-transform-email.xml @@ -0,0 +1,12 @@ + + + + + + + + /smooks/email.ftl + + + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/smooks-validation.xml b/libraries/src/main/resources/smooks/smooks-validation.xml new file mode 100644 index 0000000000..b66722ffc5 --- /dev/null +++ b/libraries/src/main/resources/smooks/smooks-validation.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/libraries/src/main/resources/smooks/supplier.properties b/libraries/src/main/resources/smooks/supplier.properties new file mode 100644 index 0000000000..cc17e45eb4 --- /dev/null +++ b/libraries/src/main/resources/smooks/supplier.properties @@ -0,0 +1,2 @@ +supplierName=[A-Za-z0-9]* +supplierPhone=^[0-9\\-\\+]{9,15}$ diff --git a/libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java b/libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java new file mode 100644 index 0000000000..4d2cb71329 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java @@ -0,0 +1,70 @@ +package com.baeldung.smooks.converter; + +import com.baeldung.smooks.model.Item; +import com.baeldung.smooks.model.Order; +import com.baeldung.smooks.model.Status; +import com.baeldung.smooks.model.Supplier; +import org.junit.Test; +import org.milyn.validation.ValidationResult; +import java.text.SimpleDateFormat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + + +public class SmooksIntegrationTest { + + private static final String EDIFACT_MESSAGE = + "UNA:+.? '\r\n" + + "UNH+771+IN_PROGRESS+2018-01-14'\r\n" + + "CTA+CompanyX+1234567'\r\n" + + "LIN+1+PX1234+9.99'\r\n" + + "LIN+2+RX990+120.32'\r\n"; + private static final String EMAIL_MESSAGE = + "Hi,\r\n" + + "Order number #771 created on 2018-01-14 is currently in IN_PROGRESS status.\r\n" + + "Consider contact supplier \"CompanyX\" with phone number: \"1234567\".\r\n" + + "Order items:\r\n" + + "1 X PX1234 (total price 9.99)\r\n" + + "2 X RX990 (total price 240.64)\r\n"; + + @Test + public void givenOrderXML_whenConvert_thenPOJOsConstructedCorrectly() throws Exception { + + OrderConverter xmlToJavaOrderConverter = new OrderConverter(); + Order order = xmlToJavaOrderConverter.convertOrderXMLToOrderObject("/smooks/order.xml"); + + assertThat(order.getNumber(),is(771L)); + assertThat(order.getStatus(),is(Status.IN_PROGRESS)); + assertThat(order.getCreationDate(),is(new SimpleDateFormat("yyyy-MM-dd").parse("2018-01-14"))); + assertThat(order.getSupplier(),is(new Supplier("CompanyX","1234567"))); + assertThat(order.getItems(),containsInAnyOrder( + new Item("PX1234",9.99,1), + new Item("RX990",120.32,2)) + ); + + } + + @Test + public void givenIncorrectOrderXML_whenValidate_thenExpectValidationErrors() throws Exception { + OrderValidator orderValidator = new OrderValidator(); + ValidationResult validationResult = orderValidator.validate("/smooks/order.xml"); + + assertThat(validationResult.getErrors(), hasSize(1)); + // 1234567 didn't match ^[0-9\\-\\+]{9,15}$ + assertThat(validationResult.getErrors().get(0).getFailRuleResult().getRuleName(),is("supplierPhone")); + } + + @Test + public void givenOrderXML_whenApplyEDITemplate_thenConvertedToEDIFACT() throws Exception { + OrderConverter orderConverter = new OrderConverter(); + String edifact = orderConverter.convertOrderXMLtoEDIFACT("/smooks/order.xml"); + assertThat(edifact,is(EDIFACT_MESSAGE)); + } + + @Test + public void givenOrderXML_whenApplyEmailTemplate_thenConvertedToEmailMessage() throws Exception { + OrderConverter orderConverter = new OrderConverter(); + String emailMessage = orderConverter.convertOrderXMLtoEmailMessage("/smooks/order.xml"); + assertThat(emailMessage,is(EMAIL_MESSAGE)); + } +} \ No newline at end of file