From 4873053439b189823576ea452752de8a351327f3 Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Tue, 14 Sep 2021 15:51:41 +1200 Subject: [PATCH 01/14] Update dependencies. --- pom.xml | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index a41fb7c..083ee3d 100644 --- a/pom.xml +++ b/pom.xml @@ -12,38 +12,33 @@ junit junit - 4.12 + 4.13.2 test org.apache.httpcomponents httpclient - 4.3.6 + 4.5.13 org.apache.httpcomponents fluent-hc - 4.5.2 + 4.5.13 com.google.code.gson gson - 2.7 + 2.8.8 javax.xml.bind jaxb-api - 2.3.0 - - - com.sun.xml.bind - jaxb-core - 2.3.0 + 2.3.1 com.sun.xml.bind jaxb-impl - 2.3.0 + 2.3.5 javax.activation @@ -65,7 +60,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.5.1 + 3.8.1 1.8 1.8 From b775891479c300e8ff639490834f8874a72b7361 Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Wed, 15 Sep 2021 09:54:01 +1200 Subject: [PATCH 02/14] Remove unused JSON code. --- pom.xml | 5 ----- .../java/com/smsglobal/transport/RestTransport.java | 6 ------ .../com/smsglobal/transport/RestTransportTest.java | 11 ----------- 3 files changed, 22 deletions(-) diff --git a/pom.xml b/pom.xml index 083ee3d..6b21e7d 100644 --- a/pom.xml +++ b/pom.xml @@ -25,11 +25,6 @@ fluent-hc 4.5.13 - - com.google.code.gson - gson - 2.8.8 - javax.xml.bind jaxb-api diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index dee50ce..f7e944f 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -1,6 +1,5 @@ package com.smsglobal.transport; -import com.google.gson.Gson; import com.smsglobal.client.Message; import com.smsglobal.client.Transport; @@ -97,11 +96,6 @@ public String toXml(Message message) throws JAXBException { return stringWriter.toString(); } - public String toJson(Message message) { - Gson gson = new Gson(); - return gson.toJson(message); - } - public void extractVersion() { String[] paths = uri.getPath().split("/"); this.version = paths[1]; diff --git a/src/test/java/com/smsglobal/transport/RestTransportTest.java b/src/test/java/com/smsglobal/transport/RestTransportTest.java index d89dc99..d5fd290 100644 --- a/src/test/java/com/smsglobal/transport/RestTransportTest.java +++ b/src/test/java/com/smsglobal/transport/RestTransportTest.java @@ -18,9 +18,7 @@ import java.net.Socket; import java.net.URISyntaxException; -import static org.hamcrest.CoreMatchers.isA; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; /** * REST transport test suite @@ -101,13 +99,4 @@ public void toXml() throws Exception { assertEquals(expected, actual); } - @Test - public void toJson() throws Exception { - RestTransport transport = new RestTransport(); - Message message = new Message("1111", "2222", "Test message"); - String actual = transport.toJson(message); - String expected = "{\"origin\":\"1111\",\"destination\":\"2222\",\"message\":\"Test message\"}"; - assertEquals(expected, actual); - } - } \ No newline at end of file From 99d4939977b237d58c8e8ebbe5177b4c78c86042 Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Wed, 15 Sep 2021 15:44:56 +1200 Subject: [PATCH 03/14] Implement more endpoints. --- .../client/AbstractHasOffsetLimitTotal.java | 42 +++ .../smsglobal/client/AbstractMessages.java | 21 ++ .../java/com/smsglobal/client/AutoTopup.java | 29 ++ .../java/com/smsglobal/client/Client.java | 17 - .../java/com/smsglobal/client/Contact.java | 125 ++++++++ .../com/smsglobal/client/ContactGroup.java | 89 ++++++ .../com/smsglobal/client/ContactGroups.java | 35 +++ .../com/smsglobal/client/CreditBalance.java | 42 +++ .../smsglobal/client/DedicatedNumbers.java | 11 + .../smsglobal/client/IncomingMessages.java | 17 + .../smsglobal/client/InstantXmlAdapter.java | 20 ++ .../smsglobal/client/LocalDateXmlAdapter.java | 17 + .../smsglobal/client/LowBalanceAlerts.java | 54 ++++ .../java/com/smsglobal/client/Message.java | 168 ++++++++-- .../com/smsglobal/client/MessageStatus.java | 15 + .../java/com/smsglobal/client/Optout.java | 44 +++ .../java/com/smsglobal/client/Optouts.java | 33 ++ .../smsglobal/client/OutgoingMessages.java | 17 + .../java/com/smsglobal/client/Response.java | 7 - .../com/smsglobal/client/SharedPools.java | 11 + .../java/com/smsglobal/client/Transport.java | 10 - .../com/smsglobal/client/VerifiedNumbers.java | 32 ++ .../com/smsglobal/examples/HttpExample.java | 11 +- .../com/smsglobal/examples/RestExample.java | 63 +--- .../smsglobal/transport/HttpTransport.java | 45 ++- .../smsglobal/transport/RestTransport.java | 294 ++++++++++++------ .../smsglobal/transport/SmppTransport.java | 13 - .../transport/HttpTransportTest.java | 13 +- .../transport/RestTransportTest.java | 89 ++---- 29 files changed, 1064 insertions(+), 320 deletions(-) create mode 100644 src/main/java/com/smsglobal/client/AbstractHasOffsetLimitTotal.java create mode 100644 src/main/java/com/smsglobal/client/AbstractMessages.java create mode 100644 src/main/java/com/smsglobal/client/AutoTopup.java delete mode 100644 src/main/java/com/smsglobal/client/Client.java create mode 100644 src/main/java/com/smsglobal/client/Contact.java create mode 100644 src/main/java/com/smsglobal/client/ContactGroup.java create mode 100644 src/main/java/com/smsglobal/client/ContactGroups.java create mode 100644 src/main/java/com/smsglobal/client/CreditBalance.java create mode 100644 src/main/java/com/smsglobal/client/DedicatedNumbers.java create mode 100644 src/main/java/com/smsglobal/client/IncomingMessages.java create mode 100644 src/main/java/com/smsglobal/client/InstantXmlAdapter.java create mode 100644 src/main/java/com/smsglobal/client/LocalDateXmlAdapter.java create mode 100644 src/main/java/com/smsglobal/client/LowBalanceAlerts.java create mode 100644 src/main/java/com/smsglobal/client/MessageStatus.java create mode 100644 src/main/java/com/smsglobal/client/Optout.java create mode 100644 src/main/java/com/smsglobal/client/Optouts.java create mode 100644 src/main/java/com/smsglobal/client/OutgoingMessages.java delete mode 100644 src/main/java/com/smsglobal/client/Response.java create mode 100644 src/main/java/com/smsglobal/client/SharedPools.java delete mode 100644 src/main/java/com/smsglobal/client/Transport.java create mode 100644 src/main/java/com/smsglobal/client/VerifiedNumbers.java delete mode 100644 src/main/java/com/smsglobal/transport/SmppTransport.java diff --git a/src/main/java/com/smsglobal/client/AbstractHasOffsetLimitTotal.java b/src/main/java/com/smsglobal/client/AbstractHasOffsetLimitTotal.java new file mode 100644 index 0000000..be4e8e9 --- /dev/null +++ b/src/main/java/com/smsglobal/client/AbstractHasOffsetLimitTotal.java @@ -0,0 +1,42 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; + +@XmlAccessorType(XmlAccessType.FIELD) +public abstract class AbstractHasOffsetLimitTotal { + + @XmlElement(name = "offset") + protected Integer offset; + + @XmlElement(name = "limit") + protected Integer limit; + + @XmlElement(name = "total") + protected Integer total; + + public Integer getOffset() { + return this.offset; + } + + public void setOffset(final Integer offset) { + this.offset = offset; + } + + public Integer getLimit() { + return this.limit; + } + + public void setLimit(final Integer limit) { + this.limit = limit; + } + + public Integer getTotal() { + return this.total; + } + + public void setTotal(final Integer total) { + this.total = total; + } +} diff --git a/src/main/java/com/smsglobal/client/AbstractMessages.java b/src/main/java/com/smsglobal/client/AbstractMessages.java new file mode 100644 index 0000000..c83443f --- /dev/null +++ b/src/main/java/com/smsglobal/client/AbstractMessages.java @@ -0,0 +1,21 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import java.util.List; + +@XmlAccessorType(XmlAccessType.FIELD) +public abstract class AbstractMessages extends AbstractHasOffsetLimitTotal { + + @XmlElement(name = "message") + protected List messages; + + public List getMessages() { + return this.messages; + } + + public void setMessages(final List messages) { + this.messages = messages; + } +} diff --git a/src/main/java/com/smsglobal/client/AutoTopup.java b/src/main/java/com/smsglobal/client/AutoTopup.java new file mode 100644 index 0000000..ddc3e58 --- /dev/null +++ b/src/main/java/com/smsglobal/client/AutoTopup.java @@ -0,0 +1,29 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "auto-topup") +public class AutoTopup { + + @XmlElement(name = "disabled") + protected Boolean disabled; + + public Boolean getDisabled() { + return this.disabled; + } + + public void setDisabled(final Boolean disabled) { + this.disabled = disabled; + } + + @Override + public String toString() { + return "AutoTopup{" + + "disabled=" + this.disabled + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/client/Client.java b/src/main/java/com/smsglobal/client/Client.java deleted file mode 100644 index 24526da..0000000 --- a/src/main/java/com/smsglobal/client/Client.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.smsglobal.client; - -/** - * SMSGlobal Client - */ -public class Client { - - private Transport transport; - - public Client(Transport transport) { - this.transport = transport; - } - - public String sendMessage(Message message) throws Exception { - return transport.sendMessage(message); - } -} diff --git a/src/main/java/com/smsglobal/client/Contact.java b/src/main/java/com/smsglobal/client/Contact.java new file mode 100644 index 0000000..021bfcb --- /dev/null +++ b/src/main/java/com/smsglobal/client/Contact.java @@ -0,0 +1,125 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "contact") +public class Contact { + + @XmlElement(name = "id") + protected String id; + + @XmlElement(name = "name") + protected String name; + + @XmlElement(name = "phone") + protected String phone; + + @XmlElement(name = "email") + protected String email; + + @XmlElement(name = "address") + protected String address; + + @XmlElement(name = "city") + protected String city; + + @XmlElement(name = "state") + protected String state; + + @XmlElement(name = "postcode") + protected String postcode; + + @XmlElement(name = "country") + protected String country; + + public String getId() { + return this.id; + } + + public void setId(final String id) { + this.id = id; + } + + public String getName() { + return this.name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getPhone() { + return this.phone; + } + + public void setPhone(final String phone) { + this.phone = phone; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(final String email) { + this.email = email; + } + + public String getAddress() { + return this.address; + } + + public void setAddress(final String address) { + this.address = address; + } + + public String getCity() { + return this.city; + } + + public void setCity(final String city) { + this.city = city; + } + + public String getState() { + return this.state; + } + + public void setState(final String state) { + this.state = state; + } + + public String getPostcode() { + return this.postcode; + } + + public void setPostcode(final String postcode) { + this.postcode = postcode; + } + + public String getCountry() { + return this.country; + } + + public void setCountry(final String country) { + this.country = country; + } + + @Override + public String toString() { + return "Contact{" + + "id=" + this.id + + ", name='" + this.name + '\'' + + ", phone='" + this.phone + '\'' + + ", email='" + this.email + '\'' + + ", address='" + this.address + '\'' + + ", city='" + this.city + '\'' + + ", state='" + this.state + '\'' + + ", postcode='" + this.postcode + '\'' + + ", country='" + this.country + '\'' + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/client/ContactGroup.java b/src/main/java/com/smsglobal/client/ContactGroup.java new file mode 100644 index 0000000..2280a20 --- /dev/null +++ b/src/main/java/com/smsglobal/client/ContactGroup.java @@ -0,0 +1,89 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "group") +public class ContactGroup { + + @XmlElement(name = "id") + protected String id; + + @XmlElement(name = "name") + protected String name; + + @XmlElement(name = "keyword") + protected String keyword; + + @XmlElement(name = "isGlobal") + protected Boolean global; + + @XmlElement(name = "contactCount") + protected Integer contactCount; + + @XmlElement(name = "defaultOrigin") + protected String defaultOrigin; + + public String getId() { + return this.id; + } + + public void setId(final String id) { + this.id = id; + } + + public String getName() { + return this.name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getKeyword() { + return this.keyword; + } + + public void setKeyword(final String keyword) { + this.keyword = keyword; + } + + public Boolean getGlobal() { + return this.global; + } + + public void setGlobal(final Boolean global) { + this.global = global; + } + + public Integer getContactCount() { + return this.contactCount; + } + + public void setContactCount(final Integer contactCount) { + this.contactCount = contactCount; + } + + public String getDefaultOrigin() { + return this.defaultOrigin; + } + + public void setDefaultOrigin(final String defaultOrigin) { + this.defaultOrigin = defaultOrigin; + } + + @Override + public String toString() { + return "ContactGroup{" + + "id=" + this.id + + ", name='" + this.name + '\'' + + ", keyword='" + this.keyword + '\'' + + ", global=" + this.global + + ", contactCount=" + this.contactCount + + ", defaultOrigin='" + this.defaultOrigin + '\'' + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/client/ContactGroups.java b/src/main/java/com/smsglobal/client/ContactGroups.java new file mode 100644 index 0000000..4d2ba55 --- /dev/null +++ b/src/main/java/com/smsglobal/client/ContactGroups.java @@ -0,0 +1,35 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "result") +public class ContactGroups extends AbstractHasOffsetLimitTotal { + + @XmlElementWrapper(name = "groups") + @XmlElement(name = "group") + protected List contactGroups; + + public List getGroups() { + return this.contactGroups; + } + + public void setGroups(final List contactGroups) { + this.contactGroups = contactGroups; + } + + @Override + public String toString() { + return "ContactGroups{" + + "offset=" + this.offset + + ", limit=" + this.limit + + ", total=" + this.total + + ", contactGroups=" + this.contactGroups + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/client/CreditBalance.java b/src/main/java/com/smsglobal/client/CreditBalance.java new file mode 100644 index 0000000..8bc2907 --- /dev/null +++ b/src/main/java/com/smsglobal/client/CreditBalance.java @@ -0,0 +1,42 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.math.BigDecimal; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "user") +public class CreditBalance { + + @XmlElement(name = "balance") + protected BigDecimal balance; + + @XmlElement(name = "currency") + protected String currency; + + public BigDecimal getBalance() { + return this.balance; + } + + public void setBalance(final BigDecimal balance) { + this.balance = balance; + } + + public String getCurrency() { + return this.currency; + } + + public void setCurrency(final String currency) { + this.currency = currency; + } + + @Override + public String toString() { + return "CreditBalance{" + + "balance=" + this.balance + + ", currency='" + this.currency + '\'' + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/client/DedicatedNumbers.java b/src/main/java/com/smsglobal/client/DedicatedNumbers.java new file mode 100644 index 0000000..35167bf --- /dev/null +++ b/src/main/java/com/smsglobal/client/DedicatedNumbers.java @@ -0,0 +1,11 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "dedicatedNumbers") +public class DedicatedNumbers { + +} diff --git a/src/main/java/com/smsglobal/client/IncomingMessages.java b/src/main/java/com/smsglobal/client/IncomingMessages.java new file mode 100644 index 0000000..d4ce39a --- /dev/null +++ b/src/main/java/com/smsglobal/client/IncomingMessages.java @@ -0,0 +1,17 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "incoming") +public class IncomingMessages extends AbstractMessages { + + @Override + public String toString() { + return "IncomingMessages{" + + "offset=" + this.offset + + ", limit=" + this.limit + + ", total=" + this.total + + ", messages=" + this.messages + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/client/InstantXmlAdapter.java b/src/main/java/com/smsglobal/client/InstantXmlAdapter.java new file mode 100644 index 0000000..6b3f2fc --- /dev/null +++ b/src/main/java/com/smsglobal/client/InstantXmlAdapter.java @@ -0,0 +1,20 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.adapters.XmlAdapter; +import java.time.Instant; +import java.time.format.DateTimeFormatter; + +public class InstantXmlAdapter extends XmlAdapter { + + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss Z"); + + @Override + public Instant unmarshal(final String value) { + return DATE_TIME_FORMATTER.parse(value, Instant::from); + } + + @Override + public String marshal(final Instant value) { + return value.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/smsglobal/client/LocalDateXmlAdapter.java b/src/main/java/com/smsglobal/client/LocalDateXmlAdapter.java new file mode 100644 index 0000000..f44e438 --- /dev/null +++ b/src/main/java/com/smsglobal/client/LocalDateXmlAdapter.java @@ -0,0 +1,17 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.adapters.XmlAdapter; +import java.time.LocalDate; + +public class LocalDateXmlAdapter extends XmlAdapter { + + @Override + public LocalDate unmarshal(final String value) { + return LocalDate.parse(value); + } + + @Override + public String marshal(final LocalDate value) { + return value.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/smsglobal/client/LowBalanceAlerts.java b/src/main/java/com/smsglobal/client/LowBalanceAlerts.java new file mode 100644 index 0000000..e7b66d0 --- /dev/null +++ b/src/main/java/com/smsglobal/client/LowBalanceAlerts.java @@ -0,0 +1,54 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.math.BigDecimal; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "settings") +public class LowBalanceAlerts { + + @XmlElement(name = "enabled") + protected Boolean enabled; + + @XmlElement(name = "threshold") + protected BigDecimal threshold; + + @XmlElement(name = "sendto") + protected String sendto; + + public Boolean getEnabled() { + return this.enabled; + } + + public void setEnabled(final Boolean enabled) { + this.enabled = enabled; + } + + public BigDecimal getThreshold() { + return this.threshold; + } + + public void setThreshold(final BigDecimal threshold) { + this.threshold = threshold; + } + + public String getSendto() { + return this.sendto; + } + + public void setSendto(final String sendto) { + this.sendto = sendto; + } + + @Override + public String toString() { + return "LowBalanceAlerts{" + + "enabled=" + this.enabled + + ", threshold=" + this.threshold + + ", sendto='" + this.sendto + '\'' + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/client/Message.java b/src/main/java/com/smsglobal/client/Message.java index 40cb8ac..5cab93c 100644 --- a/src/main/java/com/smsglobal/client/Message.java +++ b/src/main/java/com/smsglobal/client/Message.java @@ -1,70 +1,188 @@ package com.smsglobal.client; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import java.util.Date; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.time.Instant; /** * SMSGlobal Message */ -@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "message") public class Message { - private String origin; - private String destination; - private String message; - private Integer maxSplit; - private Date scheduled; + @XmlElement(name = "id") + protected String id; + + @XmlElement(name = "outgoing_id") + protected String outgoingId; + + @XmlElement(name = "origin") + protected String origin; + + @XmlElement(name = "destination") + protected String destination; + + @XmlElement(name = "message") + protected String message; + + @XmlElement(name = "isUnicode") + protected Boolean unicode; + + @XmlElement(name = "status") + protected MessageStatus status; + + @XmlJavaTypeAdapter(InstantXmlAdapter.class) + @XmlElement(name = "dateTime") + protected Instant dateTime; + + @XmlElement(name = "isMultipart") + protected Boolean multipart; + + @XmlElement(name = "partNumber") + protected Integer partNumber; + + @XmlElement(name = "totalParts") + protected Integer totalParts; + + @XmlElement(name = "notifyUrl") + protected String notifyUrl; + + @XmlElement(name = "incomingUrl") + protected String incomingUrl; public Message() { } - public Message(String origin, String destination, String message) { + public Message(final String origin, final String destination, final String message) { this.origin = origin; this.destination = destination; this.message = message; } + public String getId() { + return this.id; + } + + public void setId(final String id) { + this.id = id; + } + + public String getOutgoingId() { + return this.outgoingId; + } + + public void setOutgoingId(final String outgoingId) { + this.outgoingId = outgoingId; + } + public String getOrigin() { - return origin; + return this.origin; } - @XmlElement - public void setOrigin(String origin) { + public void setOrigin(final String origin) { this.origin = origin; } public String getDestination() { - return destination; + return this.destination; } - @XmlElement - public void setDestination(String destination) { + public void setDestination(final String destination) { this.destination = destination; } public String getMessage() { - return message; + return this.message; } - @XmlElement - public void setMessage(String message) { + public void setMessage(final String message) { this.message = message; } - public Integer getMaxSplit() { - return maxSplit; + public Boolean getUnicode() { + return this.unicode; + } + + public void setUnicode(final Boolean unicode) { + this.unicode = unicode; + } + + public MessageStatus getStatus() { + return this.status; + } + + public void setStatus(final MessageStatus status) { + this.status = status; + } + + public Instant getDateTime() { + return this.dateTime; + } + + public void setDateTime(final Instant dateTime) { + this.dateTime = dateTime; + } + + public Boolean getMultipart() { + return this.multipart; + } + + public void setMultipart(final Boolean multipart) { + this.multipart = multipart; + } + + public Integer getPartNumber() { + return this.partNumber; + } + + public void setPartNumber(final Integer partNumber) { + this.partNumber = partNumber; + } + + public Integer getTotalParts() { + return this.totalParts; + } + + public void setTotalParts(final Integer totalParts) { + this.totalParts = totalParts; + } + + public String getNotifyUrl() { + return this.notifyUrl; + } + + public void setNotifyUrl(final String notifyUrl) { + this.notifyUrl = notifyUrl; } - public void setMaxSplit(Integer maxSplit) { - this.maxSplit = maxSplit; + public String getIncomingUrl() { + return this.incomingUrl; } - public Date getScheduled() { - return scheduled; + public void setIncomingUrl(final String incomingUrl) { + this.incomingUrl = incomingUrl; } - public void setScheduled(Date scheduled) { - this.scheduled = scheduled; + @Override + public String toString() { + return "Message{" + + "id=" + this.id + + ", outgoingId=" + this.outgoingId + + ", origin='" + this.origin + '\'' + + ", destination='" + this.destination + '\'' + + ", message='" + this.message + '\'' + + ", unicode=" + this.unicode + + ", status=" + this.status + + ", dateTime=" + this.dateTime + + ", multipart=" + this.multipart + + ", partNumber=" + this.partNumber + + ", totalParts=" + this.totalParts + + ", notifyUrl='" + this.notifyUrl + '\'' + + ", incomingUrl='" + this.incomingUrl + '\'' + + '}'; } } diff --git a/src/main/java/com/smsglobal/client/MessageStatus.java b/src/main/java/com/smsglobal/client/MessageStatus.java new file mode 100644 index 0000000..a2b4b0d --- /dev/null +++ b/src/main/java/com/smsglobal/client/MessageStatus.java @@ -0,0 +1,15 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlEnumValue; + +@XmlEnum +public enum MessageStatus { + + @XmlEnumValue("delivered") delivered, + @XmlEnumValue("sent") sent, + @XmlEnumValue("scheduled") scheduled, + @XmlEnumValue("noCredits") noCredits, + @XmlEnumValue("invalidNumber") invalidNumber, + @XmlEnumValue("undelivered") undelivered +} diff --git a/src/main/java/com/smsglobal/client/Optout.java b/src/main/java/com/smsglobal/client/Optout.java new file mode 100644 index 0000000..bf50a33 --- /dev/null +++ b/src/main/java/com/smsglobal/client/Optout.java @@ -0,0 +1,44 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.time.LocalDate; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "optout") +public class Optout { + + @XmlJavaTypeAdapter(LocalDateXmlAdapter.class) + @XmlElement(name = "date") + protected LocalDate date; + + @XmlElement(name = "number") + protected String number; + + public LocalDate getDate() { + return this.date; + } + + public void setDate(final LocalDate date) { + this.date = date; + } + + public String getNumber() { + return this.number; + } + + public void setNumber(final String number) { + this.number = number; + } + + @Override + public String toString() { + return "Optout{" + + "date=" + this.date + + ", number='" + this.number + '\'' + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/client/Optouts.java b/src/main/java/com/smsglobal/client/Optouts.java new file mode 100644 index 0000000..b1b2fae --- /dev/null +++ b/src/main/java/com/smsglobal/client/Optouts.java @@ -0,0 +1,33 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "optouts") +public class Optouts extends AbstractHasOffsetLimitTotal { + + @XmlElement(name = "optout") + protected List optouts; + + public List getOptouts() { + return this.optouts; + } + + public void setOptouts(final List optouts) { + this.optouts = optouts; + } + + @Override + public String toString() { + return "Optouts{" + + "offset=" + this.offset + + ", limit=" + this.limit + + ", total=" + this.total + + ", optouts=" + this.optouts + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/client/OutgoingMessages.java b/src/main/java/com/smsglobal/client/OutgoingMessages.java new file mode 100644 index 0000000..83f67ff --- /dev/null +++ b/src/main/java/com/smsglobal/client/OutgoingMessages.java @@ -0,0 +1,17 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "outgoing") +public class OutgoingMessages extends AbstractMessages { + + @Override + public String toString() { + return "OutgoingMessages{" + + "offset=" + this.offset + + ", limit=" + this.limit + + ", total=" + this.total + + ", messages=" + this.messages + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/client/Response.java b/src/main/java/com/smsglobal/client/Response.java deleted file mode 100644 index 7b27fe7..0000000 --- a/src/main/java/com/smsglobal/client/Response.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.smsglobal.client; - -/** - * Transport response - */ -public class Response { -} diff --git a/src/main/java/com/smsglobal/client/SharedPools.java b/src/main/java/com/smsglobal/client/SharedPools.java new file mode 100644 index 0000000..404a3ea --- /dev/null +++ b/src/main/java/com/smsglobal/client/SharedPools.java @@ -0,0 +1,11 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "sharedPools") +public class SharedPools { + +} diff --git a/src/main/java/com/smsglobal/client/Transport.java b/src/main/java/com/smsglobal/client/Transport.java deleted file mode 100644 index 8ecc9a5..0000000 --- a/src/main/java/com/smsglobal/client/Transport.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.smsglobal.client; - -/** - * SMSGlobal Transport - */ -public interface Transport { - - String sendMessage(Message message) throws Exception; - -} diff --git a/src/main/java/com/smsglobal/client/VerifiedNumbers.java b/src/main/java/com/smsglobal/client/VerifiedNumbers.java new file mode 100644 index 0000000..6e80978 --- /dev/null +++ b/src/main/java/com/smsglobal/client/VerifiedNumbers.java @@ -0,0 +1,32 @@ +package com.smsglobal.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "verifiedNumbers") +public class VerifiedNumbers { + + @XmlElementWrapper(name = "numbers") + @XmlElement(name = "entry") + protected List numbers; + + public List getNumbers() { + return this.numbers; + } + + public void setNumbers(final List numbers) { + this.numbers = numbers; + } + + @Override + public String toString() { + return "VerifiedNumbers{" + + "numbers=" + this.numbers + + '}'; + } +} diff --git a/src/main/java/com/smsglobal/examples/HttpExample.java b/src/main/java/com/smsglobal/examples/HttpExample.java index 7bfbe29..20dc32e 100644 --- a/src/main/java/com/smsglobal/examples/HttpExample.java +++ b/src/main/java/com/smsglobal/examples/HttpExample.java @@ -1,6 +1,5 @@ package com.smsglobal.examples; -import com.smsglobal.client.Client; import com.smsglobal.client.Message; import com.smsglobal.transport.HttpTransport; @@ -9,13 +8,11 @@ */ public class HttpExample { - public static void main(String [ ] args) throws Exception { - Message message = new Message("SGTest", "614xx", "Build url test"); - HttpTransport httpTransport = new HttpTransport("xx", "xx", "https://www.smsglobal.com/http-api.php"); + public static void main(final String[] args) throws Exception { + final Message message = new Message("SGTest", "614xx", "Build url test"); + final HttpTransport httpTransport = new HttpTransport("xx", "xx", "https://www.smsglobal.com/http-api.php"); System.out.println(httpTransport.buildUrl(message)); - Client client = new Client(httpTransport); - String response = client.sendMessage(message); + final String response = httpTransport.sendMessage(message); System.out.println(response); } - } diff --git a/src/main/java/com/smsglobal/examples/RestExample.java b/src/main/java/com/smsglobal/examples/RestExample.java index 8b8cf2c..03ef39a 100644 --- a/src/main/java/com/smsglobal/examples/RestExample.java +++ b/src/main/java/com/smsglobal/examples/RestExample.java @@ -1,63 +1,30 @@ package com.smsglobal.examples; -import com.smsglobal.client.Client; import com.smsglobal.client.Message; import com.smsglobal.transport.RestTransport; -import org.apache.commons.beanutils.PropertyUtils; -import org.apache.http.HttpHost; -import org.apache.http.conn.ConnectTimeoutException; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLContexts; -import org.apache.http.protocol.HttpContext; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.net.InetSocketAddress; -import java.net.Socket; - /** * Send message via the HTTP transport */ public class RestExample { - public static void main(String [ ] args) throws Exception { - Message message = new Message("SGTest", "61426203571", "Build url test 33"); + public static void main(final String[] args) throws Exception { + final Message message = new Message("SGTest", "61426203571", "Build url test 33"); + final RestTransport restTransport = new RestTransport( + "5d8b1fd934a10e45d8b0476e5e9776da", "3a826f541af41127353d7f87ec73d36b", "https://api.smsglobal.com/v2"); + System.out.println(restTransport.getBaseUrl()); + System.out.println(RestTransport.toXml(message)); - SSLContext sslcontext = SSLContexts.createSystemDefault(); - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext) { - @Override - public Socket connectSocket( - int connectTimeout, - Socket socket, - HttpHost host, - InetSocketAddress remoteAddress, - InetSocketAddress localAddress, - HttpContext context) throws IOException, ConnectTimeoutException { - if (socket instanceof SSLSocket) { - try { - ((SSLSocket) socket).setEnabledProtocols(new String[] {"TLSv1.2"}); - PropertyUtils.setProperty(socket, "host", host.getHostName()); - } catch (NoSuchMethodException ex) { - } catch (IllegalAccessException ex) { - } catch (InvocationTargetException ex) { - } - } - return super.connectSocket(connectTimeout, socket, host, remoteAddress, - localAddress, context); - } - }; + System.out.println("sendMessage"); + System.out.println(restTransport.sendMessage(message)); + System.out.println("getOutgoingMessages"); + System.out.println(restTransport.getOutgoingMessages(null, null)); - RestTransport restTransport = new RestTransport("5d8b1fd934a10e45d8b0476e5e9776da", "3a826f541af41127353d7f87ec73d36b", "https://api.smsglobal.com/v2", 443,sslsf); - restTransport.setPath("/sms/"); - System.out.println(restTransport.getBaseUrl() + restTransport.getPath()); - System.out.println(restTransport.toXml(message)); - Client client = new Client(restTransport); - String response = client.sendMessage(message); - System.out.println(response); - } + System.out.println("getIncomingMessages"); + System.out.println(restTransport.getIncomingMessages(null, null)); + System.out.println("getUserCreditBalance"); + System.out.println(restTransport.getUserCreditBalance()); + } } diff --git a/src/main/java/com/smsglobal/transport/HttpTransport.java b/src/main/java/com/smsglobal/transport/HttpTransport.java index 8e96fc3..f703d1a 100644 --- a/src/main/java/com/smsglobal/transport/HttpTransport.java +++ b/src/main/java/com/smsglobal/transport/HttpTransport.java @@ -1,7 +1,6 @@ package com.smsglobal.transport; import com.smsglobal.client.Message; -import com.smsglobal.client.Transport; import org.apache.http.client.fluent.Content; import org.apache.http.client.fluent.Request; import org.apache.http.client.utils.URIBuilder; @@ -12,15 +11,15 @@ /** * HTTP Transport */ -public class HttpTransport implements Transport { +public class HttpTransport { - private String action = "sendsms"; + private final String action = "sendsms"; private String username; private String password; private String baseUrl; private URI uri; - public HttpTransport(String username, String password, String baseUrl) throws URISyntaxException { + public HttpTransport(final String username, final String password, final String baseUrl) throws URISyntaxException { this.username = username; this.password = password; this.baseUrl = baseUrl; @@ -28,20 +27,20 @@ public HttpTransport(String username, String password, String baseUrl) throws UR } - public String sendMessage(Message message) throws Exception { - String url = buildUrl(message); - Content response = Request.Get(url).execute().returnContent(); + public String sendMessage(final Message message) throws Exception { + final String url = buildUrl(message); + final Content response = Request.Get(url).execute().returnContent(); return response.asString(); } - public String buildUrl(Message message) { - URIBuilder builder = new URIBuilder(); - builder.setScheme(uri.getScheme()); - builder.setHost(uri.getHost()); - builder.setPath(uri.getPath()); - builder.addParameter("action", action); - builder.addParameter("user", username); - builder.addParameter("password", password); + public String buildUrl(final Message message) { + final URIBuilder builder = new URIBuilder(); + builder.setScheme(this.uri.getScheme()); + builder.setHost(this.uri.getHost()); + builder.setPath(this.uri.getPath()); + builder.addParameter("action", this.action); + builder.addParameter("user", this.username); + builder.addParameter("password", this.password); builder.addParameter("from", message.getOrigin()); builder.addParameter("to", message.getDestination()); builder.addParameter("text", message.getMessage()); @@ -50,34 +49,34 @@ public String buildUrl(Message message) { } public String getBaseUrl() { - return baseUrl; + return this.baseUrl; } - public void setBaseUrl(String baseUrl) { + public void setBaseUrl(final String baseUrl) { this.baseUrl = baseUrl; } public URI getUri() { - return uri; + return this.uri; } - public void setUri(URI uri) { + public void setUri(final URI uri) { this.uri = uri; } public String getUsername() { - return username; + return this.username; } - public void setUsername(String username) { + public void setUsername(final String username) { this.username = username; } public String getPassword() { - return password; + return this.password; } - public void setPassword(String password) { + public void setPassword(final String password) { this.password = password; } } diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index f7e944f..539bd3d 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -1,175 +1,271 @@ package com.smsglobal.transport; +import com.smsglobal.client.AutoTopup; +import com.smsglobal.client.Contact; +import com.smsglobal.client.ContactGroups; +import com.smsglobal.client.CreditBalance; +import com.smsglobal.client.DedicatedNumbers; +import com.smsglobal.client.IncomingMessages; +import com.smsglobal.client.LowBalanceAlerts; import com.smsglobal.client.Message; -import com.smsglobal.client.Transport; - - -import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.fluent.Content; -import org.apache.http.client.fluent.Request; - +import com.smsglobal.client.Optouts; +import com.smsglobal.client.OutgoingMessages; +import com.smsglobal.client.SharedPools; +import com.smsglobal.client.VerifiedNumbers; +import org.apache.http.HttpHeaders; +import org.apache.http.NameValuePair; +import org.apache.http.StatusLine; import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; - +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; - import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.stream.StreamSource; +import java.io.Closeable; import java.io.IOException; +import java.io.InputStream; import java.io.StringWriter; - import java.net.URI; import java.net.URISyntaxException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.Base64; +import java.util.List; import java.util.Random; /** * REST Transport */ -public class RestTransport implements Transport { - - private String key; - private String secret; - private String baseUrl; - private URI uri; - private String version; - private String path; - private int port; - private SSLConnectionSocketFactory sslConnectionSocketFactory; - - - public RestTransport() throws IOException { - - } - - public RestTransport(String key, String secret, String baseUrl, int port,SSLConnectionSocketFactory sslsf) throws URISyntaxException, IOException { +public class RestTransport implements Closeable { + + private final String key; + private final String secret; + private final String baseUrl; + private final String host; + private final int port; + private final String version; + private final CloseableHttpClient httpClient; + private final Random random = new Random(); + + public RestTransport(final String key, final String secret, final String baseUrl, final CloseableHttpClient httpClient) throws URISyntaxException { this.key = key; this.secret = secret; + this.httpClient = httpClient; + this.baseUrl = baseUrl; + final URI uri = new URI(baseUrl); + this.host = uri.getHost(); + int port = uri.getPort(); + if (port <= 0) { + final String scheme = uri.getScheme(); + switch (scheme) { + case "http": + port = 80; + break; + case "https": + port = 443; + break; + default: + throw new IllegalArgumentException(); + } + } else { + throw new IllegalArgumentException(); + } this.port = port; - this.sslConnectionSocketFactory = sslsf; - setBaseUrl(baseUrl); - + final String[] paths = uri.getPath().split("/"); + this.version = paths[1]; } - - - public String sendMessage(Message message) throws Exception { - long timestamp = System.currentTimeMillis() / 1000L; - int nonce = new Random().nextInt(); - String mac = getMac("POST", "/sms/", timestamp, nonce); - String messageXml = toXml(message); - - CloseableHttpClient httpclient = HttpClients.custom() - .setSSLSocketFactory(sslConnectionSocketFactory) - .build(); - - HttpPost httpPost = new HttpPost(baseUrl +path); - httpPost.setHeader("Accept", "application/xml"); - httpPost.setHeader("Authorization", getAuthHeader(mac, timestamp, nonce)); - StringEntity entity =new StringEntity(messageXml); - entity.setContentType("application/xml"); - httpPost.setEntity(entity); - CloseableHttpResponse response = httpclient.execute(httpPost); - return response.toString(); + public RestTransport(final String key, final String secret, final String baseUrl) throws URISyntaxException { + this(key, secret, baseUrl, HttpClients.createDefault()); } - public String toXml(Message message) throws JAXBException { - JAXBContext context = JAXBContext.newInstance(Message.class); - Marshaller marshaller = context.createMarshaller(); + public static String toXml(final Message message) throws JAXBException { + final JAXBContext jaxbContext = JAXBContext.newInstance(message.getClass()); + final Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - StringWriter stringWriter = new StringWriter(); + final StringWriter stringWriter = new StringWriter(); marshaller.marshal(message, stringWriter); return stringWriter.toString(); } - public void extractVersion() { - String[] paths = uri.getPath().split("/"); - this.version = paths[1]; + public static T fromXml(final InputStream inputStream, final Class elementClass) throws JAXBException { + final JAXBContext jaxbContext = JAXBContext.newInstance(elementClass); + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + return unmarshaller.unmarshal(new StreamSource(inputStream), elementClass).getValue(); + } + + public String getHost() { + return this.host; + } + + public int getPort() { + return this.port; + } + + public String getBaseUrl() { + return this.baseUrl; } public String getVersion() { - return version; + return this.version; } - public void setVersion(String version) throws URISyntaxException { - this.version = version; - URIBuilder builder = new URIBuilder(baseUrl).setPath(version); - this.baseUrl = builder.toString(); + @Override + public void close() throws IOException { + this.httpClient.close(); } - public String getMac(String httpMethod, String httpPath, long timestamp, int nonce) throws NoSuchAlgorithmException, InvalidKeyException { - Mac mac = Mac.getInstance("HmacSHA256"); - SecretKeySpec secretHash = new SecretKeySpec(secret.getBytes(), "HmacSHA256"); + public String getMac( + final String method, final String pathAndQuery, final long timestamp, final int nonce) throws NoSuchAlgorithmException, InvalidKeyException { + final Mac mac = Mac.getInstance("HmacSHA256"); + final SecretKeySpec secretHash = new SecretKeySpec(this.secret.getBytes(), "HmacSHA256"); mac.init(secretHash); - String message = timestamp + "\n" + nonce + "\n" + httpMethod + "\n/" + version + httpPath + "\n" + uri.getHost() + "\n" + port + "\n\n"; - return Base64.getEncoder().encodeToString((mac.doFinal(message.getBytes()))); + final String message = timestamp + "\n" + + nonce + "\n" + + method + "\n/" + + this.version + pathAndQuery + "\n" + + this.host + "\n" + + this.port + "\n\n"; + return Base64.getEncoder().encodeToString(mac.doFinal(message.getBytes())); } - public String getAuthHeader(String mac, long timestamp, int nonce) { - return "MAC id=\"" + key + "\", ts=\"" + timestamp + "\", nonce=\"" + nonce + "\", mac=\"" + mac + "\""; + public String getAuthHeader(final String mac, final long timestamp, final int nonce) { + return "MAC id=\"" + this.key + "\", ts=\"" + timestamp + "\", nonce=\"" + nonce + "\", mac=\"" + mac + "\""; } - public URI getUri() { - return uri; + public String getAuthHeader(final String method, final String pathAndQuery) throws NoSuchAlgorithmException, InvalidKeyException { + final long timestamp = System.currentTimeMillis() / 1000L; + final int nonce = this.random.nextInt(); + final String mac = getMac(method, pathAndQuery, timestamp, nonce); + return getAuthHeader(mac, timestamp, nonce); } - public void setUri(URI uri) { - this.uri = uri; + private T get(final String path, final List query, final Class responseType) throws Exception { + final String pathAndQuery = query != null && !query.isEmpty() ? new URIBuilder(path).addParameters(query).toString() : path; + final HttpGet httpRequest = new HttpGet(this.baseUrl + pathAndQuery); + httpRequest.setHeader(HttpHeaders.ACCEPT, "application/xml"); + httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), pathAndQuery)); + try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { + final StatusLine statusLine = httpResponse.getStatusLine(); + if (statusLine.getStatusCode() != 200) { + throw new RuntimeException( + statusLine.getStatusCode() + " " + statusLine.getReasonPhrase() + " " + EntityUtils.toString(httpResponse.getEntity())); + } + + return fromXml(httpResponse.getEntity().getContent(), responseType); + } } - public String getKey() { - return key; + private T get(final String path, final Class responseType) throws Exception { + return get(path, null, responseType); } - public void setKey(String key) { - this.key = key; + public AutoTopup getAutoTopup() throws Exception { + return get("/auto-topup", AutoTopup.class); } - public String getSecret() { - return secret; + public ContactGroups getContactGroups(final Integer offset, final Integer limit) throws Exception { + final List query = offset == null && limit == null ? null : new ArrayList<>(2); + if (offset != null) { + query.add(new BasicNameValuePair("offset", offset.toString())); + } + if (limit != null) { + query.add(new BasicNameValuePair("limit", limit.toString())); + } + return get("/group", query, ContactGroups.class); } - public void setSecret(String secret) { - this.secret = secret; + public DedicatedNumbers getDedicatedNumbers() throws Exception { + return get("/dedicated-number", DedicatedNumbers.class); } - public String getBaseUrl() { - return baseUrl; + public Optouts getOptOuts(final Integer offset, final Integer limit) throws Exception { + final List query = offset == null && limit == null ? null : new ArrayList<>(2); + if (offset != null) { + query.add(new BasicNameValuePair("offset", offset.toString())); + } + if (limit != null) { + query.add(new BasicNameValuePair("limit", limit.toString())); + } + return get("/opt-outs", query, Optouts.class); } - public void setBaseUrl(String baseUrl) throws URISyntaxException { - this.baseUrl = baseUrl; - this.uri = new URI(baseUrl); - extractVersion(); + public SharedPools getSharedPools() throws Exception { + return get("/sharedpool", SharedPools.class); } - public String getPath() { - return path; + public OutgoingMessages getOutgoingMessages(final Integer offset, final Integer limit) throws Exception { + final List query = offset == null && limit == null ? null : new ArrayList<>(2); + if (offset != null) { + query.add(new BasicNameValuePair("offset", offset.toString())); + } + if (limit != null) { + query.add(new BasicNameValuePair("limit", limit.toString())); + } + return get("/sms", query, OutgoingMessages.class); } - public void setPath(String path) { - this.path = path; + public OutgoingMessages sendMessage(final Message message) throws Exception { + final String messageXml = toXml(message); + final String path = "/sms"; + final HttpPost httpRequest = new HttpPost(this.baseUrl + path); + httpRequest.setHeader(HttpHeaders.ACCEPT, "application/xml"); + httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), path)); + final StringEntity entity = new StringEntity(messageXml); + entity.setContentType("application/xml"); + httpRequest.setEntity(entity); + try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { + final StatusLine statusLine = httpResponse.getStatusLine(); + if (statusLine.getStatusCode() != 200) { + throw new RuntimeException( + statusLine.getStatusCode() + " " + statusLine.getReasonPhrase() + " " + EntityUtils.toString(httpResponse.getEntity())); + } + + return fromXml(httpResponse.getEntity().getContent(), OutgoingMessages.class); + } } - public int getPort() { - return port; + public IncomingMessages getIncomingMessages(final Integer offset, final Integer limit) throws Exception { + final List query = offset == null && limit == null ? null : new ArrayList<>(2); + if (offset != null) { + query.add(new BasicNameValuePair("offset", offset.toString())); + } + if (limit != null) { + query.add(new BasicNameValuePair("limit", limit.toString())); + } + return get("/sms-incoming", query, IncomingMessages.class); } - public void setPort(int port) { - this.port = port; + public Contact getUserBillingDetails() throws Exception { + return get("/user/billing-details", Contact.class); + } + + public Contact getUserContactDetails() throws Exception { + return get("/user/contact-details", Contact.class); + } + + public CreditBalance getUserCreditBalance() throws Exception { + return get("/user/credit-balance", CreditBalance.class); + } + + public LowBalanceAlerts getUserLowBalanceAlerts() throws Exception { + return get("/user/low-balance-alerts", LowBalanceAlerts.class); + } + + public VerifiedNumbers getUserVerifiedNumbers() throws Exception { + return get("/user/verified-numbers", VerifiedNumbers.class); } } diff --git a/src/main/java/com/smsglobal/transport/SmppTransport.java b/src/main/java/com/smsglobal/transport/SmppTransport.java deleted file mode 100644 index 1073d96..0000000 --- a/src/main/java/com/smsglobal/transport/SmppTransport.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.smsglobal.transport; - -import com.smsglobal.client.Message; -import com.smsglobal.client.Transport; - -/** - * SMPP Transport - */ -public class SmppTransport implements Transport { - public String sendMessage(Message message) throws Exception { - return null; - } -} diff --git a/src/test/java/com/smsglobal/transport/HttpTransportTest.java b/src/test/java/com/smsglobal/transport/HttpTransportTest.java index 406df8c..387030d 100644 --- a/src/test/java/com/smsglobal/transport/HttpTransportTest.java +++ b/src/test/java/com/smsglobal/transport/HttpTransportTest.java @@ -14,7 +14,7 @@ public class HttpTransportTest { @Test public void baseParameters() throws URISyntaxException { - HttpTransport httpTransport = new HttpTransport("jsiuwmkd", "kjas98sk", "https://www.smsglobal.com/http-api.php"); + final HttpTransport httpTransport = new HttpTransport("jsiuwmkd", "kjas98sk", "https://www.smsglobal.com/http-api.php"); assertEquals("jsiuwmkd", httpTransport.getUsername()); assertEquals("kjas98sk", httpTransport.getPassword()); assertEquals("https://www.smsglobal.com/http-api.php", httpTransport.getBaseUrl()); @@ -22,14 +22,15 @@ public void baseParameters() throws URISyntaxException { @Test(expected = URISyntaxException.class) public void badUrl() throws URISyntaxException { - HttpTransport httpTransport = new HttpTransport("jsiuwmkd", "kjas98sk", "https://www.smsglobal.com/^^http-api.php"); + final HttpTransport httpTransport = new HttpTransport("jsiuwmkd", "kjas98sk", "https://www.smsglobal.com/^^http-api.php"); } @Test public void buildUrl() throws Exception { - Message message = new Message("SGTest", "61400000000", "Build url test"); - HttpTransport httpTransport = new HttpTransport("jsiuwmkd", "kjas98sk", "https://www.smsglobal.com/http-api.php"); - assertEquals("https://www.smsglobal.com/http-api.php?action=sendsms&user=jsiuwmkd&password=kjas98sk&from=SGTest&to=61400000000&text=Build+url+test", httpTransport.buildUrl(message)); + final Message message = new Message("SGTest", "61400000000", "Build url test"); + final HttpTransport httpTransport = new HttpTransport("jsiuwmkd", "kjas98sk", "https://www.smsglobal.com/http-api.php"); + assertEquals( + "https://www.smsglobal.com/http-api.php?action=sendsms&user=jsiuwmkd&password=kjas98sk&from=SGTest&to=61400000000&text=Build+url+test", + httpTransport.buildUrl(message)); } - } \ No newline at end of file diff --git a/src/test/java/com/smsglobal/transport/RestTransportTest.java b/src/test/java/com/smsglobal/transport/RestTransportTest.java index d5fd290..7bec6bf 100644 --- a/src/test/java/com/smsglobal/transport/RestTransportTest.java +++ b/src/test/java/com/smsglobal/transport/RestTransportTest.java @@ -1,21 +1,8 @@ package com.smsglobal.transport; import com.smsglobal.client.Message; -import org.apache.commons.beanutils.PropertyUtils; -import org.apache.http.HttpHost; -import org.apache.http.conn.ConnectTimeoutException; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLContexts; -import org.apache.http.protocol.HttpContext; - import org.junit.Test; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.net.InetSocketAddress; -import java.net.Socket; import java.net.URISyntaxException; import static org.junit.Assert.assertEquals; @@ -25,78 +12,50 @@ */ public class RestTransportTest { - SSLContext sslcontext = SSLContexts.createSystemDefault(); - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext) { - @Override - public Socket connectSocket( - int connectTimeout, - Socket socket, - HttpHost host, - InetSocketAddress remoteAddress, - InetSocketAddress localAddress, - HttpContext context) throws IOException, ConnectTimeoutException { - if (socket instanceof SSLSocket) { - try { - ((SSLSocket) socket).setEnabledProtocols(new String[] {"TLSv1.2"}); - PropertyUtils.setProperty(socket, "host", host.getHostName()); - } catch (NoSuchMethodException ex) { - } catch (IllegalAccessException ex) { - } catch (InvocationTargetException ex) { - } - } - return super.connectSocket(connectTimeout, socket, host, remoteAddress, - localAddress, context); - } - }; - @Test - public void baseParameters() throws URISyntaxException, IOException { - RestTransport restTransport = new RestTransport("aaaa", "bbbb", "https://api.smsglobal.com/v2", 443,sslsf); + public void baseParameters() throws URISyntaxException { + final RestTransport restTransport = new RestTransport("aaaa", "bbbb", "https://api.smsglobal.com/v2"); assertEquals("base url should be https://api.smsglobal.com/v2", "https://api.smsglobal.com/v2", restTransport.getBaseUrl()); - assertEquals("base scheme should be https", "https", restTransport.getUri().getScheme()); - assertEquals("base host should be api.smsglobal.com", "api.smsglobal.com", restTransport.getUri().getHost()); + assertEquals("base host should be api.smsglobal.com", "api.smsglobal.com", restTransport.getHost()); + assertEquals("base port should be 443", 443, restTransport.getPort()); assertEquals("base version should be v2", "v2", restTransport.getVersion()); - restTransport.setVersion("v1.1"); - assertEquals("base version should be v1.1", "v1.1", restTransport.getVersion()); } @Test - public void version() throws URISyntaxException, IOException { - RestTransport restTransport = new RestTransport("aaaa", "bbbb", "https://api.smsglobal.com/v2", 443,sslsf); - assertEquals("base version should be v2", "v2", restTransport.getVersion()); - restTransport.setVersion("v1.1"); - assertEquals("base version should be v1.1", "v1.1", restTransport.getVersion()); - restTransport.setBaseUrl("https://api.smsglobal.com/v2/some/other.stuff"); + public void version() throws URISyntaxException { + final RestTransport restTransport = new RestTransport("aaaa", "bbbb", "https://api.smsglobal.com/v2"); assertEquals("base version should be v2", "v2", restTransport.getVersion()); } @Test public void getMac() throws Exception { - RestTransport restTransport = new RestTransport("945a7aca9f05a78a194b77f76c6bb653", "a8dfa0dc19c7439914c74c6c92a95d25", "https://api.smsglobal.com/v2", 443,sslsf); - String mac = restTransport.getMac("GET", "/sms/", 1471398353, 1174249); + final RestTransport restTransport = new RestTransport( + "945a7aca9f05a78a194b77f76c6bb653", "a8dfa0dc19c7439914c74c6c92a95d25", "https://api.smsglobal.com/v2"); + final String mac = restTransport.getMac("GET", "/sms/", 1471398353, 1174249); assertEquals("iX34qsNi2hqcoeNVtA/W5D+Hj6eMO3mIThfcYNJPaPM=", mac); } @Test public void getAuthHeader() throws Exception { - RestTransport restTransport = new RestTransport("945a7aca9f05a78a194b77f76c6bb653", "a8dfa0dc19c7439914c74c6c92a95d25", "https://api.smsglobal.com/v2", 443,sslsf); - String mac = restTransport.getMac("GET", "/sms/", 1471398353, 1174249); - String authHeader = restTransport.getAuthHeader(mac, 1471398353, 1174249); - assertEquals("MAC id=\"945a7aca9f05a78a194b77f76c6bb653\", ts=\"1471398353\", nonce=\"1174249\", mac=\"iX34qsNi2hqcoeNVtA/W5D+Hj6eMO3mIThfcYNJPaPM=\"", authHeader); + final RestTransport restTransport = new RestTransport( + "945a7aca9f05a78a194b77f76c6bb653", "a8dfa0dc19c7439914c74c6c92a95d25", "https://api.smsglobal.com/v2"); + final String mac = restTransport.getMac("GET", "/sms/", 1471398353, 1174249); + final String authHeader = restTransport.getAuthHeader(mac, 1471398353, 1174249); + assertEquals( + "MAC id=\"945a7aca9f05a78a194b77f76c6bb653\", ts=\"1471398353\", nonce=\"1174249\", mac=\"iX34qsNi2hqcoeNVtA/W5D+Hj6eMO3mIThfcYNJPaPM=\"", + authHeader); } @Test public void toXml() throws Exception { - RestTransport transport = new RestTransport(); - Message message = new Message("1111", "2222", "Test message"); - String actual = transport.toXml(message); - String expected = "\n" + - "\n" + - " 2222\n" + - " Test message\n" + - " 1111\n" + - "\n"; + final Message message = new Message("1111", "2222", "Test message"); + final String actual = RestTransport.toXml(message); + final String expected = "\n" + + "\n" + + " 1111\n" + + " 2222\n" + + " Test message\n" + + "\n"; assertEquals(expected, actual); } - } \ No newline at end of file From 0bae4c704ddb2bae224cccddca7fb6d405871e6e Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Tue, 28 Sep 2021 11:59:08 +1300 Subject: [PATCH 04/14] Switch from XML to JSON for better Unicode support. --- pom.xml | 27 +--- .../client/AbstractHasOffsetLimitTotal.java | 11 +- .../smsglobal/client/AbstractMessages.java | 8 +- .../java/com/smsglobal/client/AutoTopup.java | 9 +- .../java/com/smsglobal/client/Contact.java | 25 ++-- .../com/smsglobal/client/ContactGroup.java | 19 +-- .../com/smsglobal/client/ContactGroups.java | 12 +- .../com/smsglobal/client/CreditBalance.java | 12 +- .../smsglobal/client/DedicatedNumbers.java | 25 +++- .../smsglobal/client/IncomingMessages.java | 3 - .../smsglobal/client/InstantXmlAdapter.java | 20 --- .../smsglobal/client/LocalDateXmlAdapter.java | 17 --- .../smsglobal/client/LowBalanceAlerts.java | 14 +- .../java/com/smsglobal/client/Message.java | 130 +++++++++--------- .../com/smsglobal/client/MessageStatus.java | 18 +-- .../java/com/smsglobal/client/Optout.java | 14 +- .../java/com/smsglobal/client/Optouts.java | 10 +- .../smsglobal/client/OutgoingMessages.java | 3 - .../com/smsglobal/client/SharedPools.java | 25 +++- .../com/smsglobal/client/VerifiedNumbers.java | 12 +- .../com/smsglobal/examples/RestExample.java | 6 +- .../smsglobal/transport/RestTransport.java | 49 +++---- .../transport/RestTransportTest.java | 14 -- 23 files changed, 188 insertions(+), 295 deletions(-) delete mode 100644 src/main/java/com/smsglobal/client/InstantXmlAdapter.java delete mode 100644 src/main/java/com/smsglobal/client/LocalDateXmlAdapter.java diff --git a/pom.xml b/pom.xml index 6b21e7d..e9c0128 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.smsglobal smglobal-java-client - 1.0-SNAPSHOT + 1.1-SNAPSHOT @@ -26,28 +26,15 @@ 4.5.13 - javax.xml.bind - jaxb-api - 2.3.1 + com.fasterxml.jackson.core + jackson-databind + 2.12.5 - com.sun.xml.bind - jaxb-impl - 2.3.5 + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.12.5 - - javax.activation - activation - 1.1.1 - - - - - commons-beanutils - commons-beanutils - 1.9.4 - - diff --git a/src/main/java/com/smsglobal/client/AbstractHasOffsetLimitTotal.java b/src/main/java/com/smsglobal/client/AbstractHasOffsetLimitTotal.java index be4e8e9..8ff0531 100644 --- a/src/main/java/com/smsglobal/client/AbstractHasOffsetLimitTotal.java +++ b/src/main/java/com/smsglobal/client/AbstractHasOffsetLimitTotal.java @@ -1,19 +1,16 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; +import com.fasterxml.jackson.annotation.JsonProperty; -@XmlAccessorType(XmlAccessType.FIELD) public abstract class AbstractHasOffsetLimitTotal { - @XmlElement(name = "offset") + @JsonProperty("offset") protected Integer offset; - @XmlElement(name = "limit") + @JsonProperty("limit") protected Integer limit; - @XmlElement(name = "total") + @JsonProperty("total") protected Integer total; public Integer getOffset() { diff --git a/src/main/java/com/smsglobal/client/AbstractMessages.java b/src/main/java/com/smsglobal/client/AbstractMessages.java index c83443f..c4a83f2 100644 --- a/src/main/java/com/smsglobal/client/AbstractMessages.java +++ b/src/main/java/com/smsglobal/client/AbstractMessages.java @@ -1,14 +1,12 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.List; -@XmlAccessorType(XmlAccessType.FIELD) public abstract class AbstractMessages extends AbstractHasOffsetLimitTotal { - @XmlElement(name = "message") + @JsonProperty("messages") protected List messages; public List getMessages() { diff --git a/src/main/java/com/smsglobal/client/AutoTopup.java b/src/main/java/com/smsglobal/client/AutoTopup.java index ddc3e58..a4ea5d1 100644 --- a/src/main/java/com/smsglobal/client/AutoTopup.java +++ b/src/main/java/com/smsglobal/client/AutoTopup.java @@ -1,15 +1,10 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "auto-topup") public class AutoTopup { - @XmlElement(name = "disabled") + @JsonProperty("disabled") protected Boolean disabled; public Boolean getDisabled() { diff --git a/src/main/java/com/smsglobal/client/Contact.java b/src/main/java/com/smsglobal/client/Contact.java index 021bfcb..cca37d4 100644 --- a/src/main/java/com/smsglobal/client/Contact.java +++ b/src/main/java/com/smsglobal/client/Contact.java @@ -1,39 +1,34 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "contact") public class Contact { - @XmlElement(name = "id") + @JsonProperty("id") protected String id; - @XmlElement(name = "name") + @JsonProperty("name") protected String name; - @XmlElement(name = "phone") + @JsonProperty("phone") protected String phone; - @XmlElement(name = "email") + @JsonProperty("email") protected String email; - @XmlElement(name = "address") + @JsonProperty("address") protected String address; - @XmlElement(name = "city") + @JsonProperty("city") protected String city; - @XmlElement(name = "state") + @JsonProperty("state") protected String state; - @XmlElement(name = "postcode") + @JsonProperty("postcode") protected String postcode; - @XmlElement(name = "country") + @JsonProperty("country") protected String country; public String getId() { diff --git a/src/main/java/com/smsglobal/client/ContactGroup.java b/src/main/java/com/smsglobal/client/ContactGroup.java index 2280a20..4f366bf 100644 --- a/src/main/java/com/smsglobal/client/ContactGroup.java +++ b/src/main/java/com/smsglobal/client/ContactGroup.java @@ -1,30 +1,25 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "group") public class ContactGroup { - @XmlElement(name = "id") + @JsonProperty("id") protected String id; - @XmlElement(name = "name") + @JsonProperty("name") protected String name; - @XmlElement(name = "keyword") + @JsonProperty("keyword") protected String keyword; - @XmlElement(name = "isGlobal") + @JsonProperty("isGlobal") protected Boolean global; - @XmlElement(name = "contactCount") + @JsonProperty("contactCount") protected Integer contactCount; - @XmlElement(name = "defaultOrigin") + @JsonProperty("defaultOrigin") protected String defaultOrigin; public String getId() { diff --git a/src/main/java/com/smsglobal/client/ContactGroups.java b/src/main/java/com/smsglobal/client/ContactGroups.java index 4d2ba55..ec5d512 100644 --- a/src/main/java/com/smsglobal/client/ContactGroups.java +++ b/src/main/java/com/smsglobal/client/ContactGroups.java @@ -1,18 +1,12 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementWrapper; -import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.List; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "result") public class ContactGroups extends AbstractHasOffsetLimitTotal { - @XmlElementWrapper(name = "groups") - @XmlElement(name = "group") + @JsonProperty("group") protected List contactGroups; public List getGroups() { diff --git a/src/main/java/com/smsglobal/client/CreditBalance.java b/src/main/java/com/smsglobal/client/CreditBalance.java index 8bc2907..b8cf483 100644 --- a/src/main/java/com/smsglobal/client/CreditBalance.java +++ b/src/main/java/com/smsglobal/client/CreditBalance.java @@ -1,19 +1,15 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.math.BigDecimal; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "user") public class CreditBalance { - @XmlElement(name = "balance") + @JsonProperty("balance") protected BigDecimal balance; - @XmlElement(name = "currency") + @JsonProperty("currency") protected String currency; public BigDecimal getBalance() { diff --git a/src/main/java/com/smsglobal/client/DedicatedNumbers.java b/src/main/java/com/smsglobal/client/DedicatedNumbers.java index 35167bf..6a84a79 100644 --- a/src/main/java/com/smsglobal/client/DedicatedNumbers.java +++ b/src/main/java/com/smsglobal/client/DedicatedNumbers.java @@ -1,11 +1,26 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "dedicatedNumbers") public class DedicatedNumbers { + @JsonProperty("dedicatedNumbers") + protected List dedicatedNumbers; + + public List getDedicatedNumbers() { + return this.dedicatedNumbers; + } + + public void setDedicatedNumbers(final List dedicatedNumbers) { + this.dedicatedNumbers = dedicatedNumbers; + } + + @Override + public String toString() { + return "DedicatedNumbers{" + + "dedicatedNumbers=" + this.dedicatedNumbers + + '}'; + } } diff --git a/src/main/java/com/smsglobal/client/IncomingMessages.java b/src/main/java/com/smsglobal/client/IncomingMessages.java index d4ce39a..d79ef17 100644 --- a/src/main/java/com/smsglobal/client/IncomingMessages.java +++ b/src/main/java/com/smsglobal/client/IncomingMessages.java @@ -1,8 +1,5 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlRootElement; - -@XmlRootElement(name = "incoming") public class IncomingMessages extends AbstractMessages { @Override diff --git a/src/main/java/com/smsglobal/client/InstantXmlAdapter.java b/src/main/java/com/smsglobal/client/InstantXmlAdapter.java deleted file mode 100644 index 6b3f2fc..0000000 --- a/src/main/java/com/smsglobal/client/InstantXmlAdapter.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.smsglobal.client; - -import javax.xml.bind.annotation.adapters.XmlAdapter; -import java.time.Instant; -import java.time.format.DateTimeFormatter; - -public class InstantXmlAdapter extends XmlAdapter { - - private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss Z"); - - @Override - public Instant unmarshal(final String value) { - return DATE_TIME_FORMATTER.parse(value, Instant::from); - } - - @Override - public String marshal(final Instant value) { - return value.toString(); - } -} \ No newline at end of file diff --git a/src/main/java/com/smsglobal/client/LocalDateXmlAdapter.java b/src/main/java/com/smsglobal/client/LocalDateXmlAdapter.java deleted file mode 100644 index f44e438..0000000 --- a/src/main/java/com/smsglobal/client/LocalDateXmlAdapter.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.smsglobal.client; - -import javax.xml.bind.annotation.adapters.XmlAdapter; -import java.time.LocalDate; - -public class LocalDateXmlAdapter extends XmlAdapter { - - @Override - public LocalDate unmarshal(final String value) { - return LocalDate.parse(value); - } - - @Override - public String marshal(final LocalDate value) { - return value.toString(); - } -} \ No newline at end of file diff --git a/src/main/java/com/smsglobal/client/LowBalanceAlerts.java b/src/main/java/com/smsglobal/client/LowBalanceAlerts.java index e7b66d0..549077c 100644 --- a/src/main/java/com/smsglobal/client/LowBalanceAlerts.java +++ b/src/main/java/com/smsglobal/client/LowBalanceAlerts.java @@ -1,22 +1,18 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.math.BigDecimal; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "settings") public class LowBalanceAlerts { - @XmlElement(name = "enabled") + @JsonProperty("enabled") protected Boolean enabled; - @XmlElement(name = "threshold") + @JsonProperty("threshold") protected BigDecimal threshold; - @XmlElement(name = "sendto") + @JsonProperty("sendto") protected String sendto; public Boolean getEnabled() { diff --git a/src/main/java/com/smsglobal/client/Message.java b/src/main/java/com/smsglobal/client/Message.java index 5cab93c..822f5b6 100644 --- a/src/main/java/com/smsglobal/client/Message.java +++ b/src/main/java/com/smsglobal/client/Message.java @@ -1,59 +1,57 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.time.Instant; /** * SMSGlobal Message */ -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "message") +@JsonInclude(JsonInclude.Include.NON_NULL) public class Message { - @XmlElement(name = "id") - protected String id; - - @XmlElement(name = "outgoing_id") - protected String outgoingId; - - @XmlElement(name = "origin") + @JsonProperty("origin") protected String origin; - @XmlElement(name = "destination") + @JsonProperty("destination") protected String destination; - @XmlElement(name = "message") + @JsonProperty("message") protected String message; - @XmlElement(name = "isUnicode") + @JsonProperty("notifyUrl") + protected String notifyUrl; + + @JsonProperty("incomingUrl") + protected String incomingUrl; + + @JsonProperty("id") + protected String id; + + @JsonProperty("outgoing_id") + protected String outgoingId; + + @JsonProperty("isUnicode") protected Boolean unicode; - @XmlElement(name = "status") + @JsonProperty("status") protected MessageStatus status; - @XmlJavaTypeAdapter(InstantXmlAdapter.class) - @XmlElement(name = "dateTime") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "uuuu-MM-dd HH:mm:ss Z") + @JsonProperty("dateTime") protected Instant dateTime; - @XmlElement(name = "isMultipart") + @JsonProperty("isMultipart") protected Boolean multipart; - @XmlElement(name = "partNumber") + @JsonProperty("partNumber") protected Integer partNumber; - @XmlElement(name = "totalParts") + @JsonProperty("totalParts") protected Integer totalParts; - @XmlElement(name = "notifyUrl") - protected String notifyUrl; - - @XmlElement(name = "incomingUrl") - protected String incomingUrl; - public Message() { } @@ -63,22 +61,6 @@ public Message(final String origin, final String destination, final String messa this.message = message; } - public String getId() { - return this.id; - } - - public void setId(final String id) { - this.id = id; - } - - public String getOutgoingId() { - return this.outgoingId; - } - - public void setOutgoingId(final String outgoingId) { - this.outgoingId = outgoingId; - } - public String getOrigin() { return this.origin; } @@ -103,6 +85,38 @@ public void setMessage(final String message) { this.message = message; } + public String getNotifyUrl() { + return this.notifyUrl; + } + + public void setNotifyUrl(final String notifyUrl) { + this.notifyUrl = notifyUrl; + } + + public String getIncomingUrl() { + return this.incomingUrl; + } + + public void setIncomingUrl(final String incomingUrl) { + this.incomingUrl = incomingUrl; + } + + public String getId() { + return this.id; + } + + public void setId(final String id) { + this.id = id; + } + + public String getOutgoingId() { + return this.outgoingId; + } + + public void setOutgoingId(final String outgoingId) { + this.outgoingId = outgoingId; + } + public Boolean getUnicode() { return this.unicode; } @@ -151,38 +165,22 @@ public void setTotalParts(final Integer totalParts) { this.totalParts = totalParts; } - public String getNotifyUrl() { - return this.notifyUrl; - } - - public void setNotifyUrl(final String notifyUrl) { - this.notifyUrl = notifyUrl; - } - - public String getIncomingUrl() { - return this.incomingUrl; - } - - public void setIncomingUrl(final String incomingUrl) { - this.incomingUrl = incomingUrl; - } - @Override public String toString() { return "Message{" + - "id=" + this.id + - ", outgoingId=" + this.outgoingId + - ", origin='" + this.origin + '\'' + + "origin='" + this.origin + '\'' + ", destination='" + this.destination + '\'' + ", message='" + this.message + '\'' + + ", notifyUrl='" + this.notifyUrl + '\'' + + ", incomingUrl='" + this.incomingUrl + '\'' + + ", id='" + this.id + '\'' + + ", outgoingId='" + this.outgoingId + '\'' + ", unicode=" + this.unicode + ", status=" + this.status + ", dateTime=" + this.dateTime + ", multipart=" + this.multipart + ", partNumber=" + this.partNumber + ", totalParts=" + this.totalParts + - ", notifyUrl='" + this.notifyUrl + '\'' + - ", incomingUrl='" + this.incomingUrl + '\'' + '}'; } } diff --git a/src/main/java/com/smsglobal/client/MessageStatus.java b/src/main/java/com/smsglobal/client/MessageStatus.java index a2b4b0d..5ecc395 100644 --- a/src/main/java/com/smsglobal/client/MessageStatus.java +++ b/src/main/java/com/smsglobal/client/MessageStatus.java @@ -1,15 +1,15 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlEnum; -import javax.xml.bind.annotation.XmlEnumValue; +import com.fasterxml.jackson.annotation.JsonProperty; -@XmlEnum public enum MessageStatus { - @XmlEnumValue("delivered") delivered, - @XmlEnumValue("sent") sent, - @XmlEnumValue("scheduled") scheduled, - @XmlEnumValue("noCredits") noCredits, - @XmlEnumValue("invalidNumber") invalidNumber, - @XmlEnumValue("undelivered") undelivered + @JsonProperty("delivered") DELIVERED, + @JsonProperty("sent") SENT, + @JsonProperty("scheduled") SCHEDULED, + @JsonProperty("noCredits") NO_CREDITS, + @JsonProperty("invalidNumber") INVALID_NUMBER, + @JsonProperty("undelivered") UNDELIVERED, + @JsonProperty("rejected") REJECTED, + @JsonProperty("Error 1002") ERROR_1002 } diff --git a/src/main/java/com/smsglobal/client/Optout.java b/src/main/java/com/smsglobal/client/Optout.java index bf50a33..9658f16 100644 --- a/src/main/java/com/smsglobal/client/Optout.java +++ b/src/main/java/com/smsglobal/client/Optout.java @@ -1,21 +1,15 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.time.LocalDate; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "optout") public class Optout { - @XmlJavaTypeAdapter(LocalDateXmlAdapter.class) - @XmlElement(name = "date") + @JsonProperty("date") protected LocalDate date; - @XmlElement(name = "number") + @JsonProperty("number") protected String number; public LocalDate getDate() { diff --git a/src/main/java/com/smsglobal/client/Optouts.java b/src/main/java/com/smsglobal/client/Optouts.java index b1b2fae..363f0a5 100644 --- a/src/main/java/com/smsglobal/client/Optouts.java +++ b/src/main/java/com/smsglobal/client/Optouts.java @@ -1,16 +1,12 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.List; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "optouts") public class Optouts extends AbstractHasOffsetLimitTotal { - @XmlElement(name = "optout") + @JsonProperty("optouts") protected List optouts; public List getOptouts() { diff --git a/src/main/java/com/smsglobal/client/OutgoingMessages.java b/src/main/java/com/smsglobal/client/OutgoingMessages.java index 83f67ff..6a7264d 100644 --- a/src/main/java/com/smsglobal/client/OutgoingMessages.java +++ b/src/main/java/com/smsglobal/client/OutgoingMessages.java @@ -1,8 +1,5 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlRootElement; - -@XmlRootElement(name = "outgoing") public class OutgoingMessages extends AbstractMessages { @Override diff --git a/src/main/java/com/smsglobal/client/SharedPools.java b/src/main/java/com/smsglobal/client/SharedPools.java index 404a3ea..8f72f7c 100644 --- a/src/main/java/com/smsglobal/client/SharedPools.java +++ b/src/main/java/com/smsglobal/client/SharedPools.java @@ -1,11 +1,26 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "sharedPools") public class SharedPools { + @JsonProperty("SharedPools") + protected List sharedPools; + + public List getSharedPools() { + return this.sharedPools; + } + + public void setSharedPools(final List sharedPools) { + this.sharedPools = sharedPools; + } + + @Override + public String toString() { + return "SharedPools{" + + "sharedPools=" + this.sharedPools + + '}'; + } } diff --git a/src/main/java/com/smsglobal/client/VerifiedNumbers.java b/src/main/java/com/smsglobal/client/VerifiedNumbers.java index 6e80978..f890202 100644 --- a/src/main/java/com/smsglobal/client/VerifiedNumbers.java +++ b/src/main/java/com/smsglobal/client/VerifiedNumbers.java @@ -1,18 +1,12 @@ package com.smsglobal.client; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementWrapper; -import javax.xml.bind.annotation.XmlRootElement; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.List; -@XmlAccessorType(XmlAccessType.FIELD) -@XmlRootElement(name = "verifiedNumbers") public class VerifiedNumbers { - @XmlElementWrapper(name = "numbers") - @XmlElement(name = "entry") + @JsonProperty("numbers") protected List numbers; public List getNumbers() { diff --git a/src/main/java/com/smsglobal/examples/RestExample.java b/src/main/java/com/smsglobal/examples/RestExample.java index 03ef39a..20f4183 100644 --- a/src/main/java/com/smsglobal/examples/RestExample.java +++ b/src/main/java/com/smsglobal/examples/RestExample.java @@ -13,13 +13,13 @@ public static void main(final String[] args) throws Exception { final RestTransport restTransport = new RestTransport( "5d8b1fd934a10e45d8b0476e5e9776da", "3a826f541af41127353d7f87ec73d36b", "https://api.smsglobal.com/v2"); System.out.println(restTransport.getBaseUrl()); - System.out.println(RestTransport.toXml(message)); + System.out.println(message); System.out.println("sendMessage"); System.out.println(restTransport.sendMessage(message)); System.out.println("getOutgoingMessages"); - System.out.println(restTransport.getOutgoingMessages(null, null)); + System.out.println(restTransport.getOutgoingMessages(null, 1000)); System.out.println("getIncomingMessages"); System.out.println(restTransport.getIncomingMessages(null, null)); @@ -27,4 +27,4 @@ public static void main(final String[] args) throws Exception { System.out.println("getUserCreditBalance"); System.out.println(restTransport.getUserCreditBalance()); } -} +} \ No newline at end of file diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index 539bd3d..7244a45 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -1,5 +1,7 @@ package com.smsglobal.transport; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.smsglobal.client.AutoTopup; import com.smsglobal.client.Contact; import com.smsglobal.client.ContactGroups; @@ -27,15 +29,8 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; -import javax.xml.transform.stream.StreamSource; import java.io.Closeable; import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.security.InvalidKeyException; @@ -57,13 +52,19 @@ public class RestTransport implements Closeable { private final int port; private final String version; private final CloseableHttpClient httpClient; + private final ObjectMapper objectMapper; private final Random random = new Random(); - public RestTransport(final String key, final String secret, final String baseUrl, final CloseableHttpClient httpClient) throws URISyntaxException { + public RestTransport( + final String key, final String secret, final String baseUrl, final CloseableHttpClient httpClient, + final ObjectMapper objectMapper) throws URISyntaxException { + this.key = key; this.secret = secret; - this.httpClient = httpClient; this.baseUrl = baseUrl; + this.httpClient = httpClient; + this.objectMapper = objectMapper; + final URI uri = new URI(baseUrl); this.host = uri.getHost(); int port = uri.getPort(); @@ -88,23 +89,7 @@ public RestTransport(final String key, final String secret, final String baseUrl } public RestTransport(final String key, final String secret, final String baseUrl) throws URISyntaxException { - this(key, secret, baseUrl, HttpClients.createDefault()); - } - - public static String toXml(final Message message) throws JAXBException { - final JAXBContext jaxbContext = JAXBContext.newInstance(message.getClass()); - final Marshaller marshaller = jaxbContext.createMarshaller(); - marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); - marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - final StringWriter stringWriter = new StringWriter(); - marshaller.marshal(message, stringWriter); - return stringWriter.toString(); - } - - public static T fromXml(final InputStream inputStream, final Class elementClass) throws JAXBException { - final JAXBContext jaxbContext = JAXBContext.newInstance(elementClass); - final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); - return unmarshaller.unmarshal(new StreamSource(inputStream), elementClass).getValue(); + this(key, secret, baseUrl, HttpClients.createDefault(), new ObjectMapper().registerModule(new JavaTimeModule())); } public String getHost() { @@ -156,7 +141,7 @@ public String getAuthHeader(final String method, final String pathAndQuery) thro private T get(final String path, final List query, final Class responseType) throws Exception { final String pathAndQuery = query != null && !query.isEmpty() ? new URIBuilder(path).addParameters(query).toString() : path; final HttpGet httpRequest = new HttpGet(this.baseUrl + pathAndQuery); - httpRequest.setHeader(HttpHeaders.ACCEPT, "application/xml"); + httpRequest.setHeader(HttpHeaders.ACCEPT, "application/json"); httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), pathAndQuery)); try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { final StatusLine statusLine = httpResponse.getStatusLine(); @@ -165,7 +150,7 @@ private T get(final String path, final List query, final Clas statusLine.getStatusCode() + " " + statusLine.getReasonPhrase() + " " + EntityUtils.toString(httpResponse.getEntity())); } - return fromXml(httpResponse.getEntity().getContent(), responseType); + return this.objectMapper.readValue(httpResponse.getEntity().getContent(), responseType); } } @@ -219,13 +204,13 @@ public OutgoingMessages getOutgoingMessages(final Integer offset, final Integer } public OutgoingMessages sendMessage(final Message message) throws Exception { - final String messageXml = toXml(message); + final String messageXml = this.objectMapper.writeValueAsString(message); final String path = "/sms"; final HttpPost httpRequest = new HttpPost(this.baseUrl + path); - httpRequest.setHeader(HttpHeaders.ACCEPT, "application/xml"); + httpRequest.setHeader(HttpHeaders.ACCEPT, "application/json"); httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), path)); final StringEntity entity = new StringEntity(messageXml); - entity.setContentType("application/xml"); + entity.setContentType("application/json"); httpRequest.setEntity(entity); try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { final StatusLine statusLine = httpResponse.getStatusLine(); @@ -234,7 +219,7 @@ public OutgoingMessages sendMessage(final Message message) throws Exception { statusLine.getStatusCode() + " " + statusLine.getReasonPhrase() + " " + EntityUtils.toString(httpResponse.getEntity())); } - return fromXml(httpResponse.getEntity().getContent(), OutgoingMessages.class); + return this.objectMapper.readValue(httpResponse.getEntity().getContent(), OutgoingMessages.class); } } diff --git a/src/test/java/com/smsglobal/transport/RestTransportTest.java b/src/test/java/com/smsglobal/transport/RestTransportTest.java index 7bec6bf..914d11e 100644 --- a/src/test/java/com/smsglobal/transport/RestTransportTest.java +++ b/src/test/java/com/smsglobal/transport/RestTransportTest.java @@ -1,6 +1,5 @@ package com.smsglobal.transport; -import com.smsglobal.client.Message; import org.junit.Test; import java.net.URISyntaxException; @@ -45,17 +44,4 @@ public void getAuthHeader() throws Exception { "MAC id=\"945a7aca9f05a78a194b77f76c6bb653\", ts=\"1471398353\", nonce=\"1174249\", mac=\"iX34qsNi2hqcoeNVtA/W5D+Hj6eMO3mIThfcYNJPaPM=\"", authHeader); } - - @Test - public void toXml() throws Exception { - final Message message = new Message("1111", "2222", "Test message"); - final String actual = RestTransport.toXml(message); - final String expected = "\n" + - "\n" + - " 1111\n" + - " 2222\n" + - " Test message\n" + - "\n"; - assertEquals(expected, actual); - } } \ No newline at end of file From df301f5bf86f825cf4a5f16b339023dbf66e6242 Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Fri, 1 Oct 2021 12:50:22 +1300 Subject: [PATCH 05/14] Improved exception handling. --- pom.xml | 2 +- .../client/HttpStatusCodeException.java | 28 +++++++ .../smsglobal/transport/RestTransport.java | 79 +++++++++++++------ 3 files changed, 83 insertions(+), 26 deletions(-) create mode 100644 src/main/java/com/smsglobal/client/HttpStatusCodeException.java diff --git a/pom.xml b/pom.xml index e9c0128..f7e4829 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.smsglobal smglobal-java-client - 1.1-SNAPSHOT + 1.2-SNAPSHOT diff --git a/src/main/java/com/smsglobal/client/HttpStatusCodeException.java b/src/main/java/com/smsglobal/client/HttpStatusCodeException.java new file mode 100644 index 0000000..69d37b5 --- /dev/null +++ b/src/main/java/com/smsglobal/client/HttpStatusCodeException.java @@ -0,0 +1,28 @@ +package com.smsglobal.client; + +public class HttpStatusCodeException extends Exception { + + protected final int statusCode; + protected final String reasonPhrase; + protected final String body; + + public HttpStatusCodeException(final int statusCode, final String reasonPhrase, final String body) { + super(statusCode + " " + reasonPhrase + " " + body); + + this.statusCode = statusCode; + this.reasonPhrase = reasonPhrase; + this.body = body; + } + + public int getStatusCode() { + return this.statusCode; + } + + public String getReasonPhrase() { + return this.reasonPhrase; + } + + public String getBody() { + return this.body; + } +} diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index 7244a45..46759e3 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -7,6 +7,7 @@ import com.smsglobal.client.ContactGroups; import com.smsglobal.client.CreditBalance; import com.smsglobal.client.DedicatedNumbers; +import com.smsglobal.client.HttpStatusCodeException; import com.smsglobal.client.IncomingMessages; import com.smsglobal.client.LowBalanceAlerts; import com.smsglobal.client.Message; @@ -115,6 +116,7 @@ public void close() throws IOException { public String getMac( final String method, final String pathAndQuery, final long timestamp, final int nonce) throws NoSuchAlgorithmException, InvalidKeyException { + final Mac mac = Mac.getInstance("HmacSHA256"); final SecretKeySpec secretHash = new SecretKeySpec(this.secret.getBytes(), "HmacSHA256"); mac.init(secretHash); @@ -138,31 +140,53 @@ public String getAuthHeader(final String method, final String pathAndQuery) thro return getAuthHeader(mac, timestamp, nonce); } - private T get(final String path, final List query, final Class responseType) throws Exception { + private static void checkResponse(final CloseableHttpResponse httpResponse) throws HttpStatusCodeException { + final StatusLine statusLine = httpResponse.getStatusLine(); + final int statusCode = statusLine.getStatusCode(); + if (statusCode == 200) { + return; + } + + final String reasonPhrase = statusLine.getReasonPhrase(); + String body = null; + try { + body = EntityUtils.toString(httpResponse.getEntity()); + } catch (final IOException ignored) { + } + + throw new HttpStatusCodeException(statusCode, reasonPhrase, body); + } + + private T get( + final String path, final List query, + final Class responseType) throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { + final String pathAndQuery = query != null && !query.isEmpty() ? new URIBuilder(path).addParameters(query).toString() : path; final HttpGet httpRequest = new HttpGet(this.baseUrl + pathAndQuery); httpRequest.setHeader(HttpHeaders.ACCEPT, "application/json"); httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), pathAndQuery)); try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { - final StatusLine statusLine = httpResponse.getStatusLine(); - if (statusLine.getStatusCode() != 200) { - throw new RuntimeException( - statusLine.getStatusCode() + " " + statusLine.getReasonPhrase() + " " + EntityUtils.toString(httpResponse.getEntity())); - } + checkResponse(httpResponse); return this.objectMapper.readValue(httpResponse.getEntity().getContent(), responseType); } } - private T get(final String path, final Class responseType) throws Exception { + private T get( + final String path, + final Class responseType) throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { + return get(path, null, responseType); } - public AutoTopup getAutoTopup() throws Exception { + public AutoTopup getAutoTopup() throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { return get("/auto-topup", AutoTopup.class); } - public ContactGroups getContactGroups(final Integer offset, final Integer limit) throws Exception { + public ContactGroups getContactGroups( + final Integer offset, + final Integer limit) throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { + final List query = offset == null && limit == null ? null : new ArrayList<>(2); if (offset != null) { query.add(new BasicNameValuePair("offset", offset.toString())); @@ -173,11 +197,14 @@ public ContactGroups getContactGroups(final Integer offset, final Integer limit) return get("/group", query, ContactGroups.class); } - public DedicatedNumbers getDedicatedNumbers() throws Exception { + public DedicatedNumbers getDedicatedNumbers() throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { return get("/dedicated-number", DedicatedNumbers.class); } - public Optouts getOptOuts(final Integer offset, final Integer limit) throws Exception { + public Optouts getOptOuts( + final Integer offset, + final Integer limit) throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { + final List query = offset == null && limit == null ? null : new ArrayList<>(2); if (offset != null) { query.add(new BasicNameValuePair("offset", offset.toString())); @@ -188,11 +215,14 @@ public Optouts getOptOuts(final Integer offset, final Integer limit) throws Exce return get("/opt-outs", query, Optouts.class); } - public SharedPools getSharedPools() throws Exception { + public SharedPools getSharedPools() throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { return get("/sharedpool", SharedPools.class); } - public OutgoingMessages getOutgoingMessages(final Integer offset, final Integer limit) throws Exception { + public OutgoingMessages getOutgoingMessages( + final Integer offset, + final Integer limit) throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { + final List query = offset == null && limit == null ? null : new ArrayList<>(2); if (offset != null) { query.add(new BasicNameValuePair("offset", offset.toString())); @@ -203,7 +233,7 @@ public OutgoingMessages getOutgoingMessages(final Integer offset, final Integer return get("/sms", query, OutgoingMessages.class); } - public OutgoingMessages sendMessage(final Message message) throws Exception { + public OutgoingMessages sendMessage(final Message message) throws IOException, NoSuchAlgorithmException, InvalidKeyException, HttpStatusCodeException { final String messageXml = this.objectMapper.writeValueAsString(message); final String path = "/sms"; final HttpPost httpRequest = new HttpPost(this.baseUrl + path); @@ -213,17 +243,16 @@ public OutgoingMessages sendMessage(final Message message) throws Exception { entity.setContentType("application/json"); httpRequest.setEntity(entity); try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { - final StatusLine statusLine = httpResponse.getStatusLine(); - if (statusLine.getStatusCode() != 200) { - throw new RuntimeException( - statusLine.getStatusCode() + " " + statusLine.getReasonPhrase() + " " + EntityUtils.toString(httpResponse.getEntity())); - } + checkResponse(httpResponse); return this.objectMapper.readValue(httpResponse.getEntity().getContent(), OutgoingMessages.class); } } - public IncomingMessages getIncomingMessages(final Integer offset, final Integer limit) throws Exception { + public IncomingMessages getIncomingMessages( + final Integer offset, + final Integer limit) throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { + final List query = offset == null && limit == null ? null : new ArrayList<>(2); if (offset != null) { query.add(new BasicNameValuePair("offset", offset.toString())); @@ -234,23 +263,23 @@ public IncomingMessages getIncomingMessages(final Integer offset, final Integer return get("/sms-incoming", query, IncomingMessages.class); } - public Contact getUserBillingDetails() throws Exception { + public Contact getUserBillingDetails() throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { return get("/user/billing-details", Contact.class); } - public Contact getUserContactDetails() throws Exception { + public Contact getUserContactDetails() throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { return get("/user/contact-details", Contact.class); } - public CreditBalance getUserCreditBalance() throws Exception { + public CreditBalance getUserCreditBalance() throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { return get("/user/credit-balance", CreditBalance.class); } - public LowBalanceAlerts getUserLowBalanceAlerts() throws Exception { + public LowBalanceAlerts getUserLowBalanceAlerts() throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { return get("/user/low-balance-alerts", LowBalanceAlerts.class); } - public VerifiedNumbers getUserVerifiedNumbers() throws Exception { + public VerifiedNumbers getUserVerifiedNumbers() throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { return get("/user/verified-numbers", VerifiedNumbers.class); } } From e0661dfc8f394657c48ec4060c1c90be67513ee1 Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Mon, 4 Oct 2021 10:17:14 +1300 Subject: [PATCH 06/14] Tidy-up. --- pom.xml | 2 +- .../smsglobal/transport/HttpTransport.java | 48 ++++------ .../smsglobal/transport/RestTransport.java | 91 ++++++++++++++++--- .../transport/HttpTransportTest.java | 2 +- 4 files changed, 98 insertions(+), 45 deletions(-) diff --git a/pom.xml b/pom.xml index f7e4829..c9efb1e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.smsglobal smglobal-java-client - 1.2-SNAPSHOT + 1.4-SNAPSHOT diff --git a/src/main/java/com/smsglobal/transport/HttpTransport.java b/src/main/java/com/smsglobal/transport/HttpTransport.java index f703d1a..5f71f60 100644 --- a/src/main/java/com/smsglobal/transport/HttpTransport.java +++ b/src/main/java/com/smsglobal/transport/HttpTransport.java @@ -5,29 +5,37 @@ import org.apache.http.client.fluent.Request; import org.apache.http.client.utils.URIBuilder; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; /** * HTTP Transport + * https://www.smsglobal.com/http-api/ */ public class HttpTransport { - private final String action = "sendsms"; - private String username; - private String password; - private String baseUrl; - private URI uri; + public static final String PRODUCTION_URL = "https://www.smsglobal.com/http-api.php"; - public HttpTransport(final String username, final String password, final String baseUrl) throws URISyntaxException { + private static final String SEND_SMS_ACTION = "sendsms"; + + private final String username; + private final String password; + private final String url; + private final URI uri; + + public HttpTransport(final String username, final String password, final String url) throws URISyntaxException { this.username = username; this.password = password; - this.baseUrl = baseUrl; - this.uri = new URI(baseUrl); + this.url = url; + this.uri = new URI(url); } + public HttpTransport(final String username, final String password) throws URISyntaxException { + this(username, password, PRODUCTION_URL); + } - public String sendMessage(final Message message) throws Exception { + public String sendMessage(final Message message) throws IOException { final String url = buildUrl(message); final Content response = Request.Get(url).execute().returnContent(); return response.asString(); @@ -38,7 +46,7 @@ public String buildUrl(final Message message) { builder.setScheme(this.uri.getScheme()); builder.setHost(this.uri.getHost()); builder.setPath(this.uri.getPath()); - builder.addParameter("action", this.action); + builder.addParameter("action", SEND_SMS_ACTION); builder.addParameter("user", this.username); builder.addParameter("password", this.password); builder.addParameter("from", message.getOrigin()); @@ -48,35 +56,19 @@ public String buildUrl(final Message message) { return builder.toString(); } - public String getBaseUrl() { - return this.baseUrl; - } - - public void setBaseUrl(final String baseUrl) { - this.baseUrl = baseUrl; + public String getUrl() { + return this.url; } public URI getUri() { return this.uri; } - public void setUri(final URI uri) { - this.uri = uri; - } - public String getUsername() { return this.username; } - public void setUsername(final String username) { - this.username = username; - } - public String getPassword() { return this.password; } - - public void setPassword(final String password) { - this.password = password; - } } diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index 46759e3..eb40a1f 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -18,6 +18,7 @@ import org.apache.http.HttpHeaders; import org.apache.http.NameValuePair; import org.apache.http.StatusLine; +import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; @@ -43,9 +44,27 @@ /** * REST Transport + * https://www.smsglobal.com/rest-api/ */ public class RestTransport implements Closeable { + public static final String PRODUCTION_BASE_URL = "https://api.smsglobal.com/v2"; + + public static final int DEFAULT_TIMEOUT_MS = 60 * 1000; + + public static CloseableHttpClient createHttpClient(final int timeoutMs) { + final RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(timeoutMs) + .setConnectTimeout(timeoutMs) + .setSocketTimeout(timeoutMs) + .build(); + return HttpClients.custom().setDefaultRequestConfig(requestConfig).build(); + } + + public static ObjectMapper createObjectMapper() { + return new ObjectMapper().registerModule(new JavaTimeModule()); + } + private final String key; private final String secret; private final String baseUrl; @@ -89,8 +108,34 @@ public RestTransport( this.version = paths[1]; } + public RestTransport( + final String key, final String secret, final CloseableHttpClient httpClient, final ObjectMapper objectMapper) throws URISyntaxException { + + this(key, secret, PRODUCTION_BASE_URL, httpClient, objectMapper); + } + + public RestTransport(final String key, final String secret, final String baseUrl, final CloseableHttpClient httpClient) throws URISyntaxException { + this(key, secret, baseUrl, httpClient, createObjectMapper()); + } + + public RestTransport(final String key, final String secret, final CloseableHttpClient httpClient) throws URISyntaxException { + this(key, secret, PRODUCTION_BASE_URL, httpClient, createObjectMapper()); + } + + public RestTransport(final String key, final String secret, final String baseUrl, final int timeoutMs) throws URISyntaxException { + this(key, secret, baseUrl, createHttpClient(timeoutMs)); + } + + public RestTransport(final String key, final String secret, final int timeoutMs) throws URISyntaxException { + this(key, secret, PRODUCTION_BASE_URL, createHttpClient(timeoutMs)); + } + public RestTransport(final String key, final String secret, final String baseUrl) throws URISyntaxException { - this(key, secret, baseUrl, HttpClients.createDefault(), new ObjectMapper().registerModule(new JavaTimeModule())); + this(key, secret, baseUrl, DEFAULT_TIMEOUT_MS); + } + + public RestTransport(final String key, final String secret) throws URISyntaxException { + this(key, secret, PRODUCTION_BASE_URL); } public String getHost() { @@ -162,7 +207,7 @@ private T get( final Class responseType) throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { final String pathAndQuery = query != null && !query.isEmpty() ? new URIBuilder(path).addParameters(query).toString() : path; - final HttpGet httpRequest = new HttpGet(this.baseUrl + pathAndQuery); + final HttpGet httpRequest = new HttpGet(new URI(this.baseUrl + pathAndQuery)); httpRequest.setHeader(HttpHeaders.ACCEPT, "application/json"); httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), pathAndQuery)); try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { @@ -179,6 +224,32 @@ private T get( return get(path, null, responseType); } + private T post( + final String path, final List query, final U body, + final Class responseType) throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { + + final String bodyXml = this.objectMapper.writeValueAsString(body); + final String pathAndQuery = query != null && !query.isEmpty() ? new URIBuilder(path).addParameters(query).toString() : path; + final HttpPost httpRequest = new HttpPost(new URI(this.baseUrl + pathAndQuery)); + httpRequest.setHeader(HttpHeaders.ACCEPT, "application/json"); + httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), pathAndQuery)); + final StringEntity entity = new StringEntity(bodyXml); + entity.setContentType("application/json"); + httpRequest.setEntity(entity); + try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { + checkResponse(httpResponse); + + return this.objectMapper.readValue(httpResponse.getEntity().getContent(), responseType); + } + } + + private T post( + final String path, final U body, + final Class responseType) throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { + + return post(path, null, body, responseType); + } + public AutoTopup getAutoTopup() throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { return get("/auto-topup", AutoTopup.class); } @@ -233,20 +304,10 @@ public OutgoingMessages getOutgoingMessages( return get("/sms", query, OutgoingMessages.class); } - public OutgoingMessages sendMessage(final Message message) throws IOException, NoSuchAlgorithmException, InvalidKeyException, HttpStatusCodeException { - final String messageXml = this.objectMapper.writeValueAsString(message); - final String path = "/sms"; - final HttpPost httpRequest = new HttpPost(this.baseUrl + path); - httpRequest.setHeader(HttpHeaders.ACCEPT, "application/json"); - httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), path)); - final StringEntity entity = new StringEntity(messageXml); - entity.setContentType("application/json"); - httpRequest.setEntity(entity); - try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { - checkResponse(httpResponse); + public OutgoingMessages sendMessage( + final Message message) throws IOException, NoSuchAlgorithmException, InvalidKeyException, HttpStatusCodeException, URISyntaxException { - return this.objectMapper.readValue(httpResponse.getEntity().getContent(), OutgoingMessages.class); - } + return post("/sms", message, OutgoingMessages.class); } public IncomingMessages getIncomingMessages( diff --git a/src/test/java/com/smsglobal/transport/HttpTransportTest.java b/src/test/java/com/smsglobal/transport/HttpTransportTest.java index 387030d..cee3ac8 100644 --- a/src/test/java/com/smsglobal/transport/HttpTransportTest.java +++ b/src/test/java/com/smsglobal/transport/HttpTransportTest.java @@ -17,7 +17,7 @@ public void baseParameters() throws URISyntaxException { final HttpTransport httpTransport = new HttpTransport("jsiuwmkd", "kjas98sk", "https://www.smsglobal.com/http-api.php"); assertEquals("jsiuwmkd", httpTransport.getUsername()); assertEquals("kjas98sk", httpTransport.getPassword()); - assertEquals("https://www.smsglobal.com/http-api.php", httpTransport.getBaseUrl()); + assertEquals("https://www.smsglobal.com/http-api.php", httpTransport.getUrl()); } @Test(expected = URISyntaxException.class) From af20a2bd9040aa1ec3f0de5c2aaf74bdedcf9d78 Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Thu, 7 Oct 2021 12:31:03 +1300 Subject: [PATCH 07/14] Add expired message status. --- pom.xml | 2 +- src/main/java/com/smsglobal/client/MessageStatus.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c9efb1e..7688ddc 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.smsglobal smglobal-java-client - 1.4-SNAPSHOT + 1.5-SNAPSHOT diff --git a/src/main/java/com/smsglobal/client/MessageStatus.java b/src/main/java/com/smsglobal/client/MessageStatus.java index 5ecc395..0a21f16 100644 --- a/src/main/java/com/smsglobal/client/MessageStatus.java +++ b/src/main/java/com/smsglobal/client/MessageStatus.java @@ -1,5 +1,6 @@ package com.smsglobal.client; +import com.fasterxml.jackson.annotation.JsonEnumDefaultValue; import com.fasterxml.jackson.annotation.JsonProperty; public enum MessageStatus { @@ -11,5 +12,7 @@ public enum MessageStatus { @JsonProperty("invalidNumber") INVALID_NUMBER, @JsonProperty("undelivered") UNDELIVERED, @JsonProperty("rejected") REJECTED, - @JsonProperty("Error 1002") ERROR_1002 + @JsonProperty("expired") EXPIRED, + @JsonProperty("Error 1002") ERROR_1002, + @JsonEnumDefaultValue UNKNOWN } From 5f4b8894682571f92e8d6ba973e3b8b3abda1016 Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Mon, 11 Oct 2021 09:56:41 +1300 Subject: [PATCH 08/14] Tidy-up. --- src/main/java/com/smsglobal/transport/RestTransport.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index eb40a1f..4f25741 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -16,6 +16,7 @@ import com.smsglobal.client.SharedPools; import com.smsglobal.client.VerifiedNumbers; import org.apache.http.HttpHeaders; +import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; import org.apache.http.StatusLine; import org.apache.http.client.config.RequestConfig; @@ -188,7 +189,7 @@ public String getAuthHeader(final String method, final String pathAndQuery) thro private static void checkResponse(final CloseableHttpResponse httpResponse) throws HttpStatusCodeException { final StatusLine statusLine = httpResponse.getStatusLine(); final int statusCode = statusLine.getStatusCode(); - if (statusCode == 200) { + if (statusCode == HttpStatus.SC_OK) { return; } @@ -228,12 +229,12 @@ private T post( final String path, final List query, final U body, final Class responseType) throws HttpStatusCodeException, IOException, URISyntaxException, NoSuchAlgorithmException, InvalidKeyException { - final String bodyXml = this.objectMapper.writeValueAsString(body); + final String bodyJson = this.objectMapper.writeValueAsString(body); final String pathAndQuery = query != null && !query.isEmpty() ? new URIBuilder(path).addParameters(query).toString() : path; final HttpPost httpRequest = new HttpPost(new URI(this.baseUrl + pathAndQuery)); httpRequest.setHeader(HttpHeaders.ACCEPT, "application/json"); httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), pathAndQuery)); - final StringEntity entity = new StringEntity(bodyXml); + final StringEntity entity = new StringEntity(bodyJson); entity.setContentType("application/json"); httpRequest.setEntity(entity); try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { From 4ba33f2418cbad9673f205b1968efd033491659e Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Mon, 29 Nov 2021 09:22:17 +1300 Subject: [PATCH 09/14] New message status. --- pom.xml | 2 +- src/main/java/com/smsglobal/client/MessageStatus.java | 1 + src/main/java/com/smsglobal/transport/RestTransport.java | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7688ddc..5e3857f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.smsglobal smglobal-java-client - 1.5-SNAPSHOT + 1.6-SNAPSHOT diff --git a/src/main/java/com/smsglobal/client/MessageStatus.java b/src/main/java/com/smsglobal/client/MessageStatus.java index 0a21f16..c394428 100644 --- a/src/main/java/com/smsglobal/client/MessageStatus.java +++ b/src/main/java/com/smsglobal/client/MessageStatus.java @@ -14,5 +14,6 @@ public enum MessageStatus { @JsonProperty("rejected") REJECTED, @JsonProperty("expired") EXPIRED, @JsonProperty("Error 1002") ERROR_1002, + @JsonProperty("Error 255") ERROR_255, @JsonEnumDefaultValue UNKNOWN } diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index 4f25741..ebeb274 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -1,5 +1,6 @@ package com.smsglobal.transport; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.smsglobal.client.AutoTopup; @@ -63,7 +64,9 @@ public static CloseableHttpClient createHttpClient(final int timeoutMs) { } public static ObjectMapper createObjectMapper() { - return new ObjectMapper().registerModule(new JavaTimeModule()); + return new ObjectMapper() + .registerModule(new JavaTimeModule()) + .enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); } private final String key; From c338e4e2924f3051f06b2dbe9fbe19c2eeeccfd1 Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Tue, 30 Nov 2021 14:07:01 +1300 Subject: [PATCH 10/14] Fix bug with Unicode support. --- pom.xml | 2 +- src/main/java/com/smsglobal/transport/RestTransport.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 5e3857f..ff7a118 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.smsglobal smglobal-java-client - 1.6-SNAPSHOT + 1.7-SNAPSHOT diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index ebeb274..6cc9c2a 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -25,6 +25,7 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -235,10 +236,9 @@ private T post( final String bodyJson = this.objectMapper.writeValueAsString(body); final String pathAndQuery = query != null && !query.isEmpty() ? new URIBuilder(path).addParameters(query).toString() : path; final HttpPost httpRequest = new HttpPost(new URI(this.baseUrl + pathAndQuery)); - httpRequest.setHeader(HttpHeaders.ACCEPT, "application/json"); + httpRequest.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType()); httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), pathAndQuery)); - final StringEntity entity = new StringEntity(bodyJson); - entity.setContentType("application/json"); + final StringEntity entity = new StringEntity(bodyJson, ContentType.APPLICATION_JSON); httpRequest.setEntity(entity); try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { checkResponse(httpResponse); From 1d8dc212e1446ae3c6855cab34e60b7c14bd902a Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Thu, 16 Dec 2021 14:45:34 +1300 Subject: [PATCH 11/14] Fix bug with Unicode support. --- pom.xml | 2 +- src/main/java/com/smsglobal/transport/RestTransport.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ff7a118..dddd880 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.smsglobal smglobal-java-client - 1.7-SNAPSHOT + 1.8-SNAPSHOT diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index 6cc9c2a..9ee5113 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -213,7 +213,7 @@ private T get( final String pathAndQuery = query != null && !query.isEmpty() ? new URIBuilder(path).addParameters(query).toString() : path; final HttpGet httpRequest = new HttpGet(new URI(this.baseUrl + pathAndQuery)); - httpRequest.setHeader(HttpHeaders.ACCEPT, "application/json"); + httpRequest.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType()); httpRequest.setHeader(HttpHeaders.AUTHORIZATION, getAuthHeader(httpRequest.getMethod(), pathAndQuery)); try (final CloseableHttpResponse httpResponse = this.httpClient.execute(httpRequest)) { checkResponse(httpResponse); From f0d00cee493b2592b1e57095d8d9ef3c5766d555 Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Fri, 19 Aug 2022 14:21:13 +1200 Subject: [PATCH 12/14] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d3167f9..23ef529 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Requirements -- JDK 7 or 8 +- JDK 7+ - Maven 3.x ## How to build the jar From 256767e295cb9ae7daf29292062ae6d64c0d689c Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Fri, 19 Aug 2022 14:21:39 +1200 Subject: [PATCH 13/14] Update dependencies. --- pom.xml | 18 +++---- .../smsglobal/transport/HttpTransport.java | 8 ++-- .../smsglobal/transport/RestTransport.java | 48 ++++++++++--------- .../transport/HttpTransportTest.java | 2 +- 4 files changed, 39 insertions(+), 37 deletions(-) diff --git a/pom.xml b/pom.xml index dddd880..13c9af8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.smsglobal smglobal-java-client - 1.8-SNAPSHOT + 1.9-SNAPSHOT @@ -16,24 +16,24 @@ test - org.apache.httpcomponents - httpclient - 4.5.13 + org.apache.httpcomponents.client5 + httpclient5 + 5.1.3 - org.apache.httpcomponents - fluent-hc - 4.5.13 + org.apache.httpcomponents.client5 + httpclient5-fluent + 5.1.3 com.fasterxml.jackson.core jackson-databind - 2.12.5 + 2.13.3 com.fasterxml.jackson.datatype jackson-datatype-jsr310 - 2.12.5 + 2.13.3 diff --git a/src/main/java/com/smsglobal/transport/HttpTransport.java b/src/main/java/com/smsglobal/transport/HttpTransport.java index 5f71f60..3f19922 100644 --- a/src/main/java/com/smsglobal/transport/HttpTransport.java +++ b/src/main/java/com/smsglobal/transport/HttpTransport.java @@ -1,9 +1,9 @@ package com.smsglobal.transport; import com.smsglobal.client.Message; -import org.apache.http.client.fluent.Content; -import org.apache.http.client.fluent.Request; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.client5.http.fluent.Content; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.net.URIBuilder; import java.io.IOException; import java.net.URI; @@ -37,7 +37,7 @@ public HttpTransport(final String username, final String password) throws URISyn public String sendMessage(final Message message) throws IOException { final String url = buildUrl(message); - final Content response = Request.Get(url).execute().returnContent(); + final Content response = Request.get(url).execute().returnContent(); return response.asString(); } diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index 9ee5113..586a18c 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -16,21 +16,19 @@ import com.smsglobal.client.OutgoingMessages; import com.smsglobal.client.SharedPools; import com.smsglobal.client.VerifiedNumbers; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.StatusLine; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.*; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.http.message.BasicNameValuePair; +import org.apache.hc.core5.http.message.StatusLine; +import org.apache.hc.core5.net.URIBuilder; +import org.apache.hc.core5.util.Timeout; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -44,6 +42,7 @@ import java.util.Base64; import java.util.List; import java.util.Random; +import java.util.concurrent.TimeUnit; /** * REST Transport @@ -55,15 +54,19 @@ public class RestTransport implements Closeable { public static final int DEFAULT_TIMEOUT_MS = 60 * 1000; - public static CloseableHttpClient createHttpClient(final int timeoutMs) { + public static CloseableHttpClient createHttpClient(final Timeout timeout) { final RequestConfig requestConfig = RequestConfig.custom() - .setConnectionRequestTimeout(timeoutMs) - .setConnectTimeout(timeoutMs) - .setSocketTimeout(timeoutMs) + .setConnectionRequestTimeout(timeout) + .setConnectTimeout(timeout) + .setResponseTimeout(timeout) .build(); return HttpClients.custom().setDefaultRequestConfig(requestConfig).build(); } + public static CloseableHttpClient createHttpClient(final int timeoutMs) { + return createHttpClient(Timeout.of(timeoutMs, TimeUnit.MILLISECONDS)); + } + public static ObjectMapper createObjectMapper() { return new ObjectMapper() .registerModule(new JavaTimeModule()) @@ -191,17 +194,16 @@ public String getAuthHeader(final String method, final String pathAndQuery) thro } private static void checkResponse(final CloseableHttpResponse httpResponse) throws HttpStatusCodeException { - final StatusLine statusLine = httpResponse.getStatusLine(); - final int statusCode = statusLine.getStatusCode(); + final int statusCode = httpResponse.getCode(); if (statusCode == HttpStatus.SC_OK) { return; } - final String reasonPhrase = statusLine.getReasonPhrase(); + final String reasonPhrase = httpResponse.getReasonPhrase(); String body = null; try { body = EntityUtils.toString(httpResponse.getEntity()); - } catch (final IOException ignored) { + } catch (final IOException | ParseException ignored) { } throw new HttpStatusCodeException(statusCode, reasonPhrase, body); diff --git a/src/test/java/com/smsglobal/transport/HttpTransportTest.java b/src/test/java/com/smsglobal/transport/HttpTransportTest.java index cee3ac8..8c45a0a 100644 --- a/src/test/java/com/smsglobal/transport/HttpTransportTest.java +++ b/src/test/java/com/smsglobal/transport/HttpTransportTest.java @@ -30,7 +30,7 @@ public void buildUrl() throws Exception { final Message message = new Message("SGTest", "61400000000", "Build url test"); final HttpTransport httpTransport = new HttpTransport("jsiuwmkd", "kjas98sk", "https://www.smsglobal.com/http-api.php"); assertEquals( - "https://www.smsglobal.com/http-api.php?action=sendsms&user=jsiuwmkd&password=kjas98sk&from=SGTest&to=61400000000&text=Build+url+test", + "https://www.smsglobal.com/http-api.php?action=sendsms&user=jsiuwmkd&password=kjas98sk&from=SGTest&to=61400000000&text=Build%20url%20test", httpTransport.buildUrl(message)); } } \ No newline at end of file From 39ec6d648a8f9e8d43c54a3c874b3c80f214e6eb Mon Sep 17 00:00:00 2001 From: Paul Beard Date: Wed, 24 Aug 2022 16:48:57 +1200 Subject: [PATCH 14/14] Optimize Imports. --- src/main/java/com/smsglobal/transport/RestTransport.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/smsglobal/transport/RestTransport.java b/src/main/java/com/smsglobal/transport/RestTransport.java index 586a18c..0a1fe9c 100644 --- a/src/main/java/com/smsglobal/transport/RestTransport.java +++ b/src/main/java/com/smsglobal/transport/RestTransport.java @@ -22,11 +22,14 @@ import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.core5.http.*; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.ParseException; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.message.BasicNameValuePair; -import org.apache.hc.core5.http.message.StatusLine; import org.apache.hc.core5.net.URIBuilder; import org.apache.hc.core5.util.Timeout;