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
This commit is contained in:
parent
f6cfff3f9d
commit
a48e062598
|
@ -710,6 +710,11 @@
|
|||
<classifier>test</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.milyn</groupId>
|
||||
<artifactId>milyn-smooks-all</artifactId>
|
||||
<version>${smooks.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
|
@ -789,6 +794,7 @@
|
|||
<google-api.version>1.23.0</google-api.version>
|
||||
<google-sheets.version>v4-rev493-1.21.0</google-sheets.version>
|
||||
<kafka.version>1.0.0</kafka.version>
|
||||
<smooks.version>1.7.0</smooks.version>
|
||||
<docker.version>3.0.14</docker.version>
|
||||
</properties>
|
||||
</project>
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -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<Item> 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<Item> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public void setItems(List<Item> items) {
|
||||
this.items = items;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package com.baeldung.smooks.model;
|
||||
|
||||
public enum Status {
|
||||
NEW, IN_PROGRESS, FINISHED
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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})
|
||||
</#list>
|
|
@ -0,0 +1 @@
|
|||
"max_total","item.quantity * item.price < 300.00"
|
|
|
@ -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}'
|
||||
</#list>
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<order creation-date="2018-01-14">
|
||||
<order-number>771</order-number>
|
||||
<order-status>IN_PROGRESS</order-status>
|
||||
<supplier>
|
||||
<name>CompanyX</name>
|
||||
<phone>1234567</phone>
|
||||
</supplier>
|
||||
<order-items>
|
||||
<item>
|
||||
<quantity>1</quantity>
|
||||
<code>PX1234</code>
|
||||
<price>9.99</price>
|
||||
</item>
|
||||
<item>
|
||||
<quantity>2</quantity>
|
||||
<code>RX990</code>
|
||||
<price>120.32</price>
|
||||
</item>
|
||||
</order-items>
|
||||
</order>
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0"?>
|
||||
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
|
||||
xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.2.xsd">
|
||||
|
||||
<jb:bean beanId="order" class="com.baeldung.smooks.model.Order" createOnElement="order">
|
||||
<jb:value property="number" data="order/order-number" />
|
||||
<jb:value property="status" data="order/order-status" />
|
||||
<jb:value property="creationDate" data="order/@creation-date" decoder="Date">
|
||||
<jb:decodeParam name="format">yyyy-MM-dd</jb:decodeParam>
|
||||
</jb:value>
|
||||
<jb:wiring property="supplier" beanIdRef="supplier" />
|
||||
<jb:wiring property="items" beanIdRef="items" />
|
||||
</jb:bean>
|
||||
|
||||
<jb:bean beanId="supplier" class="com.baeldung.smooks.model.Supplier" createOnElement="supplier">
|
||||
<jb:value property="name" data="name" />
|
||||
<jb:value property="phoneNumber" data="phone" />
|
||||
</jb:bean>
|
||||
|
||||
<jb:bean beanId="items" class="java.util.ArrayList" createOnElement="order">
|
||||
<jb:wiring beanIdRef="item" />
|
||||
</jb:bean>
|
||||
<jb:bean beanId="item" class="com.baeldung.smooks.model.Item" createOnElement="item">
|
||||
<jb:value property="code" data="item/code" />
|
||||
<jb:value property="price" decoder="Double" data="item/price" />
|
||||
<jb:value property="quantity" decoder="Integer" data="item/quantity" />
|
||||
</jb:bean>
|
||||
|
||||
</smooks-resource-list>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0"?>
|
||||
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
|
||||
xmlns:ftl="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd">
|
||||
|
||||
<import file="smooks-validation.xml" />
|
||||
|
||||
<ftl:freemarker applyOnElement="#document">
|
||||
<ftl:template>/smooks/order.ftl</ftl:template>
|
||||
</ftl:freemarker>
|
||||
|
||||
</smooks-resource-list>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0"?>
|
||||
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
|
||||
xmlns:ftl="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd">
|
||||
|
||||
|
||||
<import file="smooks-validation.xml" />
|
||||
|
||||
<ftl:freemarker applyOnElement="#document">
|
||||
<ftl:template>/smooks/email.ftl</ftl:template>
|
||||
</ftl:freemarker>
|
||||
|
||||
</smooks-resource-list>
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0"?>
|
||||
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
|
||||
xmlns:rules="http://www.milyn.org/xsd/smooks/rules-1.0.xsd"
|
||||
xmlns:validation="http://www.milyn.org/xsd/smooks/validation-1.0.xsd">
|
||||
|
||||
<import file="/smooks/smooks-mapping.xml" />
|
||||
|
||||
<rules:ruleBases>
|
||||
<rules:ruleBase name="supplierValidation" src="/smooks/supplier.properties" provider="org.milyn.rules.regex.RegexProvider"/>
|
||||
<rules:ruleBase name="itemsValidation" src="/smooks/item-rules.csv" provider="org.milyn.rules.mvel.MVELProvider"/>
|
||||
</rules:ruleBases>
|
||||
|
||||
<validation:rule executeOn="supplier/name" name="supplierValidation.supplierName" onFail="ERROR"/>
|
||||
<validation:rule executeOn="supplier/phone" name="supplierValidation.supplierPhone" onFail="ERROR"/>
|
||||
<validation:rule executeOn="order-items/item" name="itemsValidation.max_total" onFail="ERROR"/>
|
||||
|
||||
</smooks-resource-list>
|
|
@ -0,0 +1,2 @@
|
|||
supplierName=[A-Za-z0-9]*
|
||||
supplierPhone=^[0-9\\-\\+]{9,15}$
|
|
@ -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));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue