diff --git a/install-oee-domain-jar.bat b/install-oee-domain-jar.bat
index fbc66cc..e831863 100644
--- a/install-oee-domain-jar.bat
+++ b/install-oee-domain-jar.bat
@@ -3,4 +3,4 @@ rmdir /Q /S C:\maven_repo\org\point85\oee-domain
call mvn -v
call mvn clean package
rem install jar in local repo
-call mvn install:install-file -Dfile=./target/OEE-Domain-3.10.0.jar -DgroupId=org.point85 -DartifactId=oee-domain -Dversion=3.10.0 -Dpackaging=jar
\ No newline at end of file
+call mvn install:install-file -Dfile=./target/OEE-Domain-3.10.1.jar -DgroupId=org.point85 -DartifactId=oee-domain -Dversion=3.10.1 -Dpackaging=jar
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 12c8689..af181c0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
org.point85
oee-domain
- 3.10.0
+ 3.10.1
jar
http://maven.apache.org
diff --git a/src/main/java/org/point85/domain/DomainUtils.java b/src/main/java/org/point85/domain/DomainUtils.java
index a605bf7..b0b1602 100644
--- a/src/main/java/org/point85/domain/DomainUtils.java
+++ b/src/main/java/org/point85/domain/DomainUtils.java
@@ -48,8 +48,8 @@ private DomainUtils() {
}
public static String getVersionInfo() {
- return DomainLocalizer.instance().getLangString("version") + " 3.10.0, "
- + LocalDate.of(2023, 12, 27).format(DateTimeFormatter.ISO_DATE);
+ return DomainLocalizer.instance().getLangString("version") + " 3.10.1, "
+ + LocalDate.of(2024, 1, 10).format(DateTimeFormatter.ISO_DATE);
}
// format a Duration
@@ -251,4 +251,12 @@ public static String gunzip(byte[] data) throws Exception {
return new String(bos.toByteArray());
}
+
+ public static String byteArrayToHex(byte[] byteArray) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b : byteArray) {
+ sb.append(String.format("%02X ", b));
+ }
+ return sb.toString();
+ }
}
diff --git a/src/main/java/org/point85/domain/http/HttpOeeClient.java b/src/main/java/org/point85/domain/http/HttpOeeClient.java
index 5f3c133..a23e0a5 100644
--- a/src/main/java/org/point85/domain/http/HttpOeeClient.java
+++ b/src/main/java/org/point85/domain/http/HttpOeeClient.java
@@ -20,6 +20,9 @@
import com.google.gson.Gson;
+/**
+ * Class for making HTTP GET and PUT requests
+ */
public class HttpOeeClient {
// logger
private Logger logger = LoggerFactory.getLogger(HttpOeeClient.class);
diff --git a/src/main/java/org/point85/domain/http/HttpSource.java b/src/main/java/org/point85/domain/http/HttpSource.java
index 7c1b98b..d80805d 100644
--- a/src/main/java/org/point85/domain/http/HttpSource.java
+++ b/src/main/java/org/point85/domain/http/HttpSource.java
@@ -10,9 +10,13 @@
import org.point85.domain.collector.DataSourceType;
import org.point85.domain.dto.HttpSourceDto;
+/**
+ * The HttpSource class represents an HTTP/HTTPS server as a source of
+ * application events.
+ *
+ */
@Entity
@DiscriminatorValue(DataSourceType.HTTP_VALUE)
-
public class HttpSource extends CollectorDataSource {
// overloaded for HTTPS port
@Column(name = "END_PATH")
diff --git a/src/main/java/org/point85/domain/mqtt/MqttOeeClient.java b/src/main/java/org/point85/domain/mqtt/MqttOeeClient.java
index 899dac4..3dc613c 100644
--- a/src/main/java/org/point85/domain/mqtt/MqttOeeClient.java
+++ b/src/main/java/org/point85/domain/mqtt/MqttOeeClient.java
@@ -4,6 +4,7 @@
import java.io.FileInputStream;
import java.net.InetAddress;
import java.security.KeyStore;
+import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
@@ -42,6 +43,10 @@ public class MqttOeeClient extends BaseMessagingClient {
private static final String TCP_PROTOCOL = "tcp://";
private static final String SSL_PROTOCOL = "ssl://";
+ // polling loop for replies
+ private static final int NUM_TRIES = 20;
+ private static final int RETRY_WAIT = 500;
+
// native client
private MqttClient mqttClient;
@@ -51,20 +56,42 @@ public class MqttOeeClient extends BaseMessagingClient {
// connection options
private MqttConnectOptions connectionOptions = new MqttConnectOptions();
+ // flag for response from publishing a message is available
+ private AtomicBoolean dataAvailable = new AtomicBoolean(false);
+
+ // the text of the message response
+ private String messageResponse;
+
public MqttOeeClient() {
connectionOptions.setAutomaticReconnect(true);
connectionOptions.setCleanSession(CLEAN_SESSION);
connectionOptions.setConnectionTimeout(10);
}
+ /**
+ * Register listener for replies
+ *
+ * @param listener {@link MqttMessageListener}
+ */
public void registerListener(MqttMessageListener listener) {
this.eventListener = listener;
}
+ /**
+ * Remove the reply listener
+ */
public void unregisterListener() {
this.eventListener = null;
}
+ /**
+ * Initialize the client
+ *
+ * @param hostName Broker name
+ * @param port Broker port
+ * @param listener {@link MqttMessageListener}
+ * @throws Exception Exception
+ */
public void startUp(String hostName, int port, MqttMessageListener listener) throws Exception {
// connect to server
connect(hostName, port);
@@ -110,6 +137,12 @@ public void connect(String hostName, int port) throws Exception {
}
}
+ /**
+ * Subscribe to message replies
+ *
+ * @param qos {@link QualityOfService}
+ * @throws Exception Exception
+ */
public void subscribeToEvents(QualityOfService qos) throws Exception {
mqttClient.subscribe(EVENT_TOPIC, (topic, msg) -> {
String json = new String(msg.getPayload());
@@ -140,6 +173,12 @@ public void subscribeToEvents(QualityOfService qos) throws Exception {
}
}
+ /**
+ * Subscribe to notification messages
+ *
+ * @param qos {@link QualityOfService}
+ * @throws Exception Exception
+ */
public void subscribeToNotifications(QualityOfService qos) throws Exception {
mqttClient.subscribe(STATUS_TOPIC, (topic, msg) -> {
String json = new String(msg.getPayload());
@@ -173,9 +212,21 @@ public void subscribeToNotifications(QualityOfService qos) throws Exception {
}
}
+ /**
+ * Publish an ApplicationMessage to the topic with the specified
+ * QualityOfService
+ *
+ * @param topic Topic
+ * @param message {@link ApplicationMessage}
+ * @param qos {@link QualityOfService}
+ * @throws Exception Exception
+ */
public void publish(String topic, ApplicationMessage message, QualityOfService qos) throws Exception {
String text = serialize(message);
+ publishMessage(topic, text, qos);
+ }
+ private void publishMessage(String topic, String text, QualityOfService qos) throws Exception {
MqttMessage mqttMessage = new MqttMessage();
mqttMessage.setQos(qos.getQos());
mqttMessage.setRetained(false);
@@ -188,6 +239,69 @@ public void publish(String topic, ApplicationMessage message, QualityOfService q
}
}
+ /**
+ * Publish a text message, then wait for a response message. A prior call to
+ * subscribeToTopic() is required.
+ *
+ * @param topic Topic to publish to
+ * @param text Payload of message
+ * @param qos {@link QualityOfService}
+ * @param maxWait Maximum time to wait in seconds
+ * @return Payload of message response
+ * @throws Exception Exception
+ */
+ public String publishAndWait(String topic, String text, QualityOfService qos, int maxWait) throws Exception {
+ dataAvailable.set(false);
+ messageResponse = null;
+
+ // send the message
+ publishMessage(topic, text, qos);
+
+ // wait for response
+ long start = System.currentTimeMillis();
+
+ for (int i = 0; i < NUM_TRIES; i++) {
+ Thread.sleep(RETRY_WAIT);
+ long delta = (System.currentTimeMillis() - start) / 1000;
+
+ if (dataAvailable.get() || delta >= maxWait) {
+ // response has been received or timed out
+ break;
+ }
+ }
+
+ if (messageResponse == null || messageResponse.isEmpty()) {
+ logger.warn("No response to publishing the message was received within " + maxWait + " seconds.");
+ }
+ return messageResponse;
+ }
+
+ /**
+ * Subscribe to this topic
+ *
+ * @param topic Topic to subscribe to
+ * @throws Exception Exception
+ */
+ public void subscribeToTopic(String topic) throws Exception {
+ mqttClient.subscribe(topic, (theTopic, msg) -> {
+ messageResponse = new String(msg.getPayload());
+
+ if (messageResponse != null && !messageResponse.isEmpty()) {
+ dataAvailable.set(true);
+ } else {
+ dataAvailable.set(false);
+ }
+
+ if (logger.isInfoEnabled()) {
+ logger.info("MQTT message received, topic: " + theTopic + ", payload:\n\t" + messageResponse);
+ }
+ });
+
+ if (logger.isInfoEnabled()) {
+ logger.info("Subscribed to topic " + topic);
+ }
+ }
+
/**
* Disconnect from the MQTT server
*
diff --git a/src/main/java/org/point85/domain/schedule/Rotation.java b/src/main/java/org/point85/domain/schedule/Rotation.java
index f089011..804df2d 100644
--- a/src/main/java/org/point85/domain/schedule/Rotation.java
+++ b/src/main/java/org/point85/domain/schedule/Rotation.java
@@ -71,6 +71,10 @@ public class Rotation extends Named implements Comparable {
@OneToMany(mappedBy = "rotation", cascade = CascadeType.ALL, orphanRemoval = true)
private final List rotationSegments = new ArrayList<>();
+ // teams
+ @OneToMany(mappedBy = "rotation", cascade = CascadeType.ALL, orphanRemoval = true)
+ private final List teams = new ArrayList<>();
+
// list of working and non-working days
@Transient
private List periods;
@@ -215,10 +219,24 @@ public WorkSchedule getWorkSchedule() {
return workSchedule;
}
+ /**
+ * Assign the work schedule to this rotation
+ *
+ * @param workSchedule {@link WorkSchedule}
+ */
public void setWorkSchedule(WorkSchedule workSchedule) {
this.workSchedule = workSchedule;
}
+ /**
+ * Get the rotation's related teams
+ *
+ * @return List of {@link Team}
+ */
+ public List getTeams() {
+ return this.teams;
+ }
+
@Override
public int compareTo(Rotation other) {
return getName().compareTo(other.getName());
diff --git a/src/main/java/org/point85/domain/schedule/RotationSegment.java b/src/main/java/org/point85/domain/schedule/RotationSegment.java
index ce7699b..a747924 100644
--- a/src/main/java/org/point85/domain/schedule/RotationSegment.java
+++ b/src/main/java/org/point85/domain/schedule/RotationSegment.java
@@ -27,12 +27,10 @@ of this software and associated documentation files (the "Software"), to deal
import java.util.Objects;
import javax.persistence.AttributeOverride;
-import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
-import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.point85.domain.dto.RotationSegmentDto;
@@ -61,7 +59,7 @@ public class RotationSegment extends KeyedObject implements Comparable {
@OneToMany(mappedBy = "shift", cascade = CascadeType.ALL, orphanRemoval = true)
private final List breaks = new ArrayList<>();
+ // shifts
+ @OneToMany(mappedBy = "startingShift", cascade = CascadeType.ALL, orphanRemoval = true)
+ private final List segments = new ArrayList<>();
+
/**
* Default constructor
*/
@@ -88,6 +92,15 @@ public List getBreaks() {
return this.breaks;
}
+ /**
+ * Get the rotations segments for this shift
+ *
+ * @return List {@link RotationSegment}
+ */
+ public List getRotationSegments() {
+ return this.segments;
+ }
+
/**
* Add a break period to this shift
*
diff --git a/src/main/java/org/point85/domain/schedule/Team.java b/src/main/java/org/point85/domain/schedule/Team.java
index c7ca58b..674483b 100644
--- a/src/main/java/org/point85/domain/schedule/Team.java
+++ b/src/main/java/org/point85/domain/schedule/Team.java
@@ -32,12 +32,10 @@ of this software and associated documentation files (the "Software"), to deal
import java.util.Objects;
import javax.persistence.AttributeOverride;
-import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
-import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.point85.domain.DomainUtils;
@@ -65,7 +63,7 @@ public class Team extends Named implements Comparable {
private LocalDate rotationStart;
// shift rotation days
- @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
+ @ManyToOne
@JoinColumn(name = "ROTATION_KEY")
private Rotation rotation;