diff --git a/bellatrix.sms/pom.xml b/bellatrix.sms/pom.xml
new file mode 100644
index 00000000..4e257fcb
--- /dev/null
+++ b/bellatrix.sms/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+
+ solutions.bellatrix
+ bellatrix
+ 1.0-SNAPSHOT
+
+
+ bellatrix.sms
+
+
+
+ solutions.bellatrix
+ bellatrix.core
+ 1.0
+
+
+ com.twilio.sdk
+ twilio
+ 10.3.0
+ compile
+
+
+
+
+ 19
+ 19
+ UTF-8
+
+
+
\ No newline at end of file
diff --git a/bellatrix.sms/src/main/java/solutions/bellatrix/sms/SmsEventArgs.java b/bellatrix.sms/src/main/java/solutions/bellatrix/sms/SmsEventArgs.java
new file mode 100644
index 00000000..8fa642f9
--- /dev/null
+++ b/bellatrix.sms/src/main/java/solutions/bellatrix/sms/SmsEventArgs.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2024 Automate The Planet Ltd.
+ * Author: Miriam Kyoseva
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package solutions.bellatrix.sms;
+
+import com.twilio.rest.api.v2010.account.Message;
+import lombok.Getter;
+
+@Getter
+public class SmsEventArgs {
+ private SmsListener smsListener;
+ private Message message;
+
+ public SmsEventArgs(SmsListener smsListener, Message message) {
+ this.smsListener = smsListener;
+ this.message = message;
+ }
+}
diff --git a/bellatrix.sms/src/main/java/solutions/bellatrix/sms/SmsListener.java b/bellatrix.sms/src/main/java/solutions/bellatrix/sms/SmsListener.java
new file mode 100644
index 00000000..3d1baff3
--- /dev/null
+++ b/bellatrix.sms/src/main/java/solutions/bellatrix/sms/SmsListener.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2024 Automate The Planet Ltd.
+ * Author: Miriam Kyoseva
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package solutions.bellatrix.sms;
+
+import com.twilio.rest.api.v2010.account.Message;
+import com.twilio.rest.api.v2010.account.MessageReader;
+import solutions.bellatrix.core.plugins.EventListener;
+
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
+
+public class SmsListener {
+ public static EventListener MESSAGE_RECEIVED = new EventListener<>();
+
+ private String phoneNumber;
+ private final List messages = new ArrayList<>();
+ private ScheduledExecutorService scheduler;
+ private Instant start;
+
+ public SmsListener(String phoneNumber) {
+ this.phoneNumber = phoneNumber;
+ }
+
+ public SmsListener() {
+ }
+
+ public List getMessages() {
+ return new ArrayList<>(messages);
+ }
+
+ public Message getMessage(Predicate condition) {
+ return messages.stream().filter(condition).findFirst().orElse(null);
+ }
+
+ public Message getFirstMessage() {
+ return messages.get(0);
+ }
+
+ public Message getLastMessage() {
+ return messages.get(messages.size() - 1);
+ }
+
+ public Message getLastMessage(Predicate condition) {
+ var foundMessages = messages.stream().filter(condition).toList();
+ return foundMessages.get(foundMessages.size() - 1);
+ }
+
+ public void listen() {
+ start = Instant.now();
+ this.scheduler = Executors.newScheduledThreadPool(1);
+ this.scheduler.schedule(this::checkForMessages, 0, TimeUnit.MILLISECONDS);
+ }
+
+ public void stopListening() {
+ if (this.scheduler != null) {
+ this.scheduler.shutdownNow();
+ this.scheduler = null;
+ }
+ }
+
+ private void checkForMessages() {
+ var messageReader = new MessageReader()
+ .setDateSentAfter(ZonedDateTime.ofInstant(start, ZoneId.of("UTC")));
+ if (phoneNumber != null && !phoneNumber.isBlank()) messageReader.setFrom(phoneNumber);
+
+ var foundMessages = messageReader.read();
+
+ while (foundMessages.iterator().hasNext()) {
+ var message = foundMessages.iterator().next();
+ messages.add(message);
+ MESSAGE_RECEIVED.broadcast(new SmsEventArgs(this, message));
+ }
+
+ start = Instant.now();
+ }
+}
diff --git a/bellatrix.sms/src/main/java/solutions/bellatrix/sms/SmsService.java b/bellatrix.sms/src/main/java/solutions/bellatrix/sms/SmsService.java
new file mode 100644
index 00000000..2baba9ff
--- /dev/null
+++ b/bellatrix.sms/src/main/java/solutions/bellatrix/sms/SmsService.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2024 Automate The Planet Ltd.
+ * Author: Miriam Kyoseva
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package solutions.bellatrix.sms;
+
+import com.twilio.Twilio;
+import com.twilio.rest.api.v2010.account.Message;
+import lombok.experimental.UtilityClass;
+import solutions.bellatrix.core.configuration.ConfigurationService;
+
+import java.util.List;
+
+@UtilityClass
+public class SmsService {
+ private static final TwilioSettings settings = ConfigurationService.get(TwilioSettings.class);
+
+ static {
+ Twilio.init(settings.getAccountSID(), settings.getAuthToken());
+ }
+
+ public static SmsListener listenForSms(String fromNumber) {
+ var smsListener = new SmsListener(fromNumber);
+ smsListener.listen();
+ return smsListener;
+ }
+
+ public static SmsListener listenForSms() {
+ var smsListener = new SmsListener();
+ smsListener.listen();
+ return smsListener;
+ }
+
+ public static void stopListeningForSms(SmsListener smsListener) {
+ smsListener.stopListening();
+ }
+
+ public static List getMessages(SmsListener smsListener) {
+ return smsListener.getMessages();
+ }
+
+ public static Message getFirstMessage(SmsListener smsListener) {
+ return smsListener.getFirstMessage();
+ }
+
+ public static Message getLastMessage(SmsListener smsListener) {
+ return smsListener.getLastMessage();
+ }
+}
diff --git a/bellatrix.sms/src/main/java/solutions/bellatrix/sms/TwilioSettings.java b/bellatrix.sms/src/main/java/solutions/bellatrix/sms/TwilioSettings.java
new file mode 100644
index 00000000..c446a138
--- /dev/null
+++ b/bellatrix.sms/src/main/java/solutions/bellatrix/sms/TwilioSettings.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2024 Automate The Planet Ltd.
+ * Author: Miriam Kyoseva
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package solutions.bellatrix.sms;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter @Setter @NoArgsConstructor
+public class TwilioSettings {
+ private String accountSID;
+ private String authToken;
+ private String phoneNumber;
+}
diff --git a/pom.xml b/pom.xml
index 5f098750..5cdb6a00 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,6 +28,7 @@
getting-started/bellatrix.web.getting.started
getting-started/bellatrix.playwright.getting.started
+ bellatrix.sms