From e2405a8c1714ea4af4f633be8e2b75b9291291dd Mon Sep 17 00:00:00 2001 From: Jawad Kazmi <78086114+kazmijawad@users.noreply.github.com> Date: Wed, 1 Dec 2021 11:26:42 +0100 Subject: [PATCH 1/5] Initial instrumentation added to services Dependencies in pom.xml added in addition to adding instrumentation support to Service classes (only numbers) --- .classpath | 56 +++++++++++++++++++ .factorypath | 31 ++++++++++ .project | 34 +++++++++++ .settings/org.eclipse.core.resources.prefs | 6 ++ .settings/org.eclipse.jdt.apt.core.prefs | 4 ++ .settings/org.eclipse.jdt.core.prefs | 9 +++ .settings/org.eclipse.m2e.core.prefs | 4 ++ .vscode/settings.json | 3 + pom.xml | 27 +++++++++ .../ait/lablink/core/service/LlService.java | 18 ++++-- .../lablink/core/service/LlServiceBase.java | 23 +++++++- .../core/service/LlServiceBoolean.java | 6 +- .../lablink/core/service/LlServiceDouble.java | 8 +++ .../lablink/core/service/LlServiceLong.java | 9 +++ .../lablink/core/service/LlServicePseudo.java | 18 ++++-- .../core/service/LlServicePseudoDouble.java | 4 ++ .../core/service/LlServicePseudoLong.java | 5 ++ .../lablink/core/service/LlServiceString.java | 6 +- 18 files changed, 251 insertions(+), 20 deletions(-) create mode 100644 .classpath create mode 100644 .factorypath create mode 100644 .project create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 .settings/org.eclipse.jdt.apt.core.prefs create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 .vscode/settings.json diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..8c36262 --- /dev/null +++ b/.classpath @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.factorypath b/.factorypath new file mode 100644 index 0000000..7b5dacf --- /dev/null +++ b/.factorypath @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..56a2b36 --- /dev/null +++ b/.project @@ -0,0 +1,34 @@ + + + core + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + + + 1638288653335 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..bfaf8a6 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding//target/generated-sources/java-templates=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.apt.core.prefs b/.settings/org.eclipse.jdt.apt.core.prefs new file mode 100644 index 0000000..687ad91 --- /dev/null +++ b/.settings/org.eclipse.jdt.apt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.apt.aptEnabled=true +org.eclipse.jdt.apt.genSrcDir=target\\generated-sources\\annotations +org.eclipse.jdt.apt.genTestSrcDir=target\\generated-test-sources\\test-annotations diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..90f7a5b --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.processAnnotations=enabled +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e0f15db --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic" +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index fed6d06..8779122 100644 --- a/pom.xml +++ b/pom.xml @@ -385,6 +385,33 @@ test + + + + io.prometheus + simpleclient + 0.12.0 + + + + io.prometheus + simpleclient_hotspot + 0.12.0 + + + + io.prometheus + simpleclient_httpserver + 0.12.0 + + + + io.prometheus + simpleclient_pushgateway + 0.12.0 + + + org.hamcrest hamcrest-core diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlService.java b/src/main/java/at/ac/ait/lablink/core/service/LlService.java index 06476c5..100c96e 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlService.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlService.java @@ -63,6 +63,10 @@ public LlService(String name, boolean readonly) { super(name, readonly); } + public LlService(String name, boolean readonly, boolean exposedToPrometheus) { + super(name, readonly, exposedToPrometheus); + } + // ********************************************************************** // /** @@ -97,17 +101,21 @@ public T getCurState() { } private void notifyStateChange(T oldVal, T newVal) { + + this.setGage(); + if (this.notifiers.size() > 0) { logger.debug("Service [{}]: state changed from [{}] to [{}]!", this.getName(), oldVal, newVal); - logger.debug("Notifying to the [{}] registered listener...", this.notifiers.size()); + logger.debug("Notifying to the [{}] registered listener(s)...", this.notifiers.size()); - for (Entry> entry : this.notifiers - .entrySet()) { - entry.getValue().stateChanged(this, oldVal, newVal); - } + // for (Entry> entry : this.notifiers + // .entrySet()) { + // entry.getValue().stateChanged(this, oldVal, newVal); + // } + this.notifiers.forEach((k,v)-> v.stateChanged(this, oldVal, newVal)); } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java b/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java index ca148a1..4be0236 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java @@ -9,6 +9,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import io.prometheus.client.Gauge; + import java.util.HashMap; import java.util.Map; @@ -24,7 +26,10 @@ public abstract class LlServiceBase implements Cloneable { /** The read-only flag. */ protected boolean readOnly = false; + protected boolean exposeToPrometheus = false; + protected Gauge serviceGage; + /** * Instantiates a new instance with random alpha-numeric * name and read-only flag set to {@code false}. @@ -40,10 +45,14 @@ public LlServiceBase() { * @param readonly read-only flag */ public LlServiceBase(String name, boolean readonly) { + this(name, readonly, true); + } + + public LlServiceBase(String name, boolean readonly, boolean exposedToPrometheus) { this.setName(name); this.setReadOnly(readonly); - logger.debug("Service [{}] created with access [{}].", name, - (readonly ? "READONLY" : "READ/WRITE")); + this.exposeToPrometheus = exposedToPrometheus; + serviceGage = Gauge.build().name(name).register(); } /** @@ -92,7 +101,7 @@ public boolean isReadOnly() { } /** - * Sets the read-only falg. + * Sets the read-only flag. * * @param readOnly read-only flag */ @@ -152,4 +161,12 @@ public Object duplicate() throws CloneNotSupportedException { LlServiceBase base = (LlServiceBase) super.clone(); return base; } + + public boolean isExposedToPrometheus() { + return this.exposeToPrometheus; + } + + protected void setGage() { + + } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServiceBoolean.java b/src/main/java/at/ac/ait/lablink/core/service/LlServiceBoolean.java index a4cf452..1bc1292 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServiceBoolean.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServiceBoolean.java @@ -14,17 +14,17 @@ public LlServiceBoolean() { public LlServiceBoolean(String name) { super(name); - setCurState(false); + setCurState(false); } public LlServiceBoolean(String name, boolean readonly) { super(name, readonly); - setCurState(false); + setCurState(false); } public LlServiceBoolean(boolean readonly) { super(readonly); - setCurState(false); + setCurState(false); } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServiceDouble.java b/src/main/java/at/ac/ait/lablink/core/service/LlServiceDouble.java index eb28c18..b83a71c 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServiceDouble.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServiceDouble.java @@ -10,6 +10,7 @@ public abstract class LlServiceDouble extends LlService { public LlServiceDouble(String name) { super(name); setCurState(0.0); + this.exposeToPrometheus = true; } public LlServiceDouble() { @@ -20,10 +21,17 @@ public LlServiceDouble() { public LlServiceDouble(String name, boolean readonly) { super(name, readonly); setCurState(0.0); + this.exposeToPrometheus = true; } public LlServiceDouble(boolean readonly) { super(readonly); setCurState(0.0); + this.exposeToPrometheus = true; } + + @Override + protected void setGage() { + this.serviceGage.set(this.getCurState()); + } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServiceLong.java b/src/main/java/at/ac/ait/lablink/core/service/LlServiceLong.java index cc21912..1303ff8 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServiceLong.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServiceLong.java @@ -10,20 +10,29 @@ public abstract class LlServiceLong extends LlService { public LlServiceLong() { super(); setCurState(0L); + this.exposeToPrometheus = true; } public LlServiceLong(String name) { super(name); setCurState(0L); + this.exposeToPrometheus = true; } public LlServiceLong(String name, boolean readonly) { super(name, readonly); setCurState(0L); + this.exposeToPrometheus = true; } public LlServiceLong(boolean readonly) { super(readonly); setCurState(0L); + this.exposeToPrometheus = true; + } + + @Override + protected void setGage() { + this.serviceGage.set(this.getCurState()); } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java index 6eef3fe..66c2f0a 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java @@ -49,18 +49,20 @@ public boolean set(T currentState) { } private void notifyStateChange(T oldVal, T newVal) { + if (this.notifiers.size() > 0) { logger.debug("Service [{}]: state changed from [{}] to [{}]!", this.getName(), oldVal, newVal); - logger.debug("Notifying to the [{}] registered listener...", this.getName(), - this.notifiers.size()); + logger.debug("Notifying to the [{}] registered listener...", this.getName(), this.notifiers.size()); + + this.notifiers.forEach((k,v)-> v.stateChanged(this, oldVal, newVal)); - for (Entry> entry : this.notifiers - .entrySet()) { - entry.getValue().stateChanged(this, oldVal, newVal); - } + // for (Entry> entry : this.notifiers + // .entrySet()) { + // entry.getValue().stateChanged(this, oldVal, newVal); + // } } } @@ -81,6 +83,10 @@ public LlServicePseudo(String name, boolean readonly) { super(name, readonly); } + public LlServicePseudo(String name, boolean readonly, boolean exposedToPrometheus) { + super(name, readonly, exposedToPrometheus); + } + /** * Instantiates a new ll service pscudo. * diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoDouble.java b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoDouble.java index bb2855d..46de784 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoDouble.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoDouble.java @@ -27,4 +27,8 @@ public LlServicePseudoDouble(boolean readonly) { this.set(0.0); } + @Override + protected void setGage() { + this.serviceGage.set(this.get()); + } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoLong.java b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoLong.java index 01c9d06..e8a8f50 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoLong.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoLong.java @@ -24,4 +24,9 @@ public LlServicePseudoLong(boolean readonly) { super(readonly); } + @Override + protected void setGage() { + this.serviceGage.set(this.get()); + } + } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServiceString.java b/src/main/java/at/ac/ait/lablink/core/service/LlServiceString.java index d6769cb..2878d84 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServiceString.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServiceString.java @@ -9,17 +9,17 @@ public abstract class LlServiceString extends LlService { public LlServiceString() { super(); - setCurState(""); + setCurState(""); } public LlServiceString(String name) { super(name); - setCurState(""); + setCurState(""); } public LlServiceString(String name, boolean readonly) { super(name, readonly); - setCurState(""); + setCurState(""); } } From 81a5254edff29b89f8ad596d0a72f728b7c05f0d Mon Sep 17 00:00:00 2001 From: Jawad Kazmi <78086114+kazmijawad@users.noreply.github.com> Date: Wed, 1 Dec 2021 12:48:56 +0100 Subject: [PATCH 2/5] Shutdown hook and Prometheus server added to client --- .checkstyle | 16 ++ .classpath | 6 - .project | 6 + .../core/client/ILlClientFsmLogic.java | 3 +- .../core/client/LlClientShutdownHook.java | 12 + .../lablink/core/client/impl/LlClient.java | 243 +++++++++++++++--- .../ait/lablink/core/service/LlService.java | 11 +- .../lablink/core/service/LlServicePseudo.java | 2 +- 8 files changed, 247 insertions(+), 52 deletions(-) create mode 100644 .checkstyle create mode 100644 src/main/java/at/ac/ait/lablink/core/client/LlClientShutdownHook.java diff --git a/.checkstyle b/.checkstyle new file mode 100644 index 0000000..8bc0c81 --- /dev/null +++ b/.checkstyle @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/.classpath b/.classpath index 8c36262..ab3f951 100644 --- a/.classpath +++ b/.classpath @@ -38,17 +38,11 @@ - - - - - - diff --git a/.project b/.project index 56a2b36..765d3cd 100644 --- a/.project +++ b/.project @@ -10,6 +10,11 @@ + + net.sf.eclipsecs.core.CheckstyleBuilder + + + org.eclipse.m2e.core.maven2Builder @@ -19,6 +24,7 @@ org.eclipse.jdt.core.javanature org.eclipse.m2e.core.maven2Nature + net.sf.eclipsecs.core.CheckstyleNature diff --git a/src/main/java/at/ac/ait/lablink/core/client/ILlClientFsmLogic.java b/src/main/java/at/ac/ait/lablink/core/client/ILlClientFsmLogic.java index fd4e1ca..70835e1 100644 --- a/src/main/java/at/ac/ait/lablink/core/client/ILlClientFsmLogic.java +++ b/src/main/java/at/ac/ait/lablink/core/client/ILlClientFsmLogic.java @@ -14,6 +14,7 @@ import org.apache.commons.configuration.ConfigurationException; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; public interface ILlClientFsmLogic { @@ -30,7 +31,7 @@ public void onInitSuccess() throws PseudoHostException; public void onStartSuccess() throws - ClientNotReadyException, PseudoHostException; + ClientNotReadyException, PseudoHostException, IOException; public void onShutdownSuccess() throws ClientNotReadyException; diff --git a/src/main/java/at/ac/ait/lablink/core/client/LlClientShutdownHook.java b/src/main/java/at/ac/ait/lablink/core/client/LlClientShutdownHook.java new file mode 100644 index 0000000..40adb95 --- /dev/null +++ b/src/main/java/at/ac/ait/lablink/core/client/LlClientShutdownHook.java @@ -0,0 +1,12 @@ +package at.ac.ait.lablink.core.client; + +import at.ac.ait.lablink.core.client.impl.LlClient; + +abstract public class LlClientShutdownHook extends Thread { + + private LlClient client; + + public LlClientShutdownHook(LlClient client) { + this.client = client; + } +} diff --git a/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java b/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java index 8805f04..a8fdacb 100644 --- a/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java +++ b/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java @@ -36,6 +36,7 @@ import at.ac.ait.lablink.core.service.LlServicePseudo; import at.ac.ait.lablink.core.utility.LlAddressUtility; import at.ac.ait.lablink.core.utility.Utility; +import io.prometheus.client.exporter.HTTPServer; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.databind.JsonMappingException; @@ -51,6 +52,7 @@ import java.util.Map; import java.util.Optional; +// TODO: Auto-generated Javadoc /** * Implementation of Lablink client base functionality, including * the client logic and communication interface. @@ -60,6 +62,9 @@ public final class LlClient implements ILlClientLogic, ILlClientCommInterface, I /** The id. */ private final long id = LlAddressUtility.getRandomClientId(); + /** The port on which this client's measures would be exposed to Prometheus.*/ + private static final int PROMETHEUS_MEASURES_PORT = 7979; + /** The logger. */ private static Logger logger = LogManager.getLogger("LlClient"); @@ -72,21 +77,22 @@ public final class LlClient implements ILlClientLogic, ILlClientCommInterface, I /** The state. */ private ELlClientStates state = ELlClientStates.LABLINK_CLIENT_INTERFACE_STATE_NOTINSTANTIATED; - /** The rd server. */ + /** The REsource Discovery Server. */ private ResourceDiscoveryPeriodicServer rdServer; - /** The fsm. */ + /** The FSM. */ private LlClientFsm fsm; /** The name. */ private String name; - /** The yellopages. */ + /** The Yellow Pages for DP broadcast on LAN */ private MqttYellowPageForClient yellopages; /** The gen yellowpages. */ private String genYellowpages; + /** The ypages client scope. */ private String[] ypagesClientScope; /** The properties. */ @@ -122,35 +128,54 @@ public final class LlClient implements ILlClientLogic, ILlClientCommInterface, I /** The show shell. */ private boolean showShell = false; - /** + /** The prometheus measures port. */ + private int prometheusMeasuresPort = PROMETHEUS_MEASURES_PORT; + + private HTTPServer prometheusMeasuresServer; + private boolean runPrometheusServer = false; + + /** * Instantiates a new ll client. * * @param cname the name this client will be identified with * @param hostSp the access name of the host implementation to use * @param giveShell the flag to indicated if ishell should be shown * @param isPseudo the is the flag indicating a pseudo client + * @param pmport the port number on which the Prometheus measures will be available * @param scope scope */ - public LlClient(String cname, String hostSp, boolean giveShell, boolean isPseudo, - String... scope) { - + public LlClient(String cname, String hostSp, boolean giveShell, boolean isPseudo, int pmport, String... scope) { if (isPseudo) { - logger.info( - "PseudoClient will be instantiated with name={} and will work with the PseudoHost={}.", - cname, hostSp); - } else { - logger.info( - "CustomClient will be instantiated with name={} and will work with the CustomHost={}.", - cname, hostSp); - } + logger.info( + "PseudoClient will be instantiated with name={} and will work with the PseudoHost={}.", + cname, hostSp); + } else { + logger.info( + "CustomClient will be instantiated with name={} and will work with the CustomHost={}.", + cname, hostSp); + } + + // this.clientCommInterfaceType = null; + this.setName(cname); + this.fsm = new LlClientFsm(this); + this.showShell = giveShell; + this.pseudoClient = isPseudo; + // this.pseudoHostType = null; + this.hostImplementation = hostSp; + this.prometheusMeasuresPort = pmport; +} - // this.clientCommInterfaceType = null; - this.setName(cname); - this.fsm = new LlClientFsm(this); - this.showShell = giveShell; - this.pseudoClient = isPseudo; - // this.pseudoHostType = null; - this.hostImplementation = hostSp; + /** + * Instantiates a new ll client. + * + * @param cname the name this client will be identified with + * @param hostSp the access name of the host implementation to use + * @param giveShell the flag to indicated if ishell should be shown + * @param isPseudo the is the flag indicating a pseudo client + * @param scope scope + */ + public LlClient(String cname, String hostSp, boolean giveShell, boolean isPseudo, String... scope) { + this(cname, hostSp, giveShell, isPseudo, PROMETHEUS_MEASURES_PORT, scope); } /** @@ -226,7 +251,10 @@ public void create() throws ClientNotReadyException, NoSuchCommInterfaceExceptio // ///////////////////////////////////////////////////////////////////////////////// - /** + /** + * + * + * @return the properties * @see at.ac.ait.lablink.core.client.ILlClientLogic#getProperties() */ @Override @@ -234,7 +262,10 @@ public Map getProperties() { return this.properties; } - /** + /** + * + * + * @return the services * @see at.ac.ait.lablink.core.client.ILlClientLogic#getServices() */ @Override @@ -242,7 +273,10 @@ public Map getServices() { return this.services; } - /** + /** + * + * + * @return the adv properties * @see at.ac.ait.lablink.core.client.ILlClientLogic#getAdvProperties() */ @Override @@ -296,7 +330,13 @@ public Object getAdvProperty(ELlClientAdvProperties key) { // ///////////////////////////////////////////////////////////////////////////////// - /** + /** + * + * + * @throws ClientNotReadyException the client not ready exception + * @throws ConfigurationException the configuration exception + * @throws NoServicesInClientLogicException the no services in client logic exception + * @throws DataTypeNotSupportedException the data type not supported exception * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#init() */ @Override @@ -307,7 +347,10 @@ public void init() throws ClientNotReadyException, ConfigurationException, this.fsm.transitionTo(LlClientFsm.EPossibleTransitionTriggers.INIT); } - /** + /** + * + * + * @throws ClientNotReadyException the client not ready exception * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#start() */ @Override @@ -317,7 +360,10 @@ public void start() throws ClientNotReadyException { } - /** + /** + * + * + * @throws ClientNotReadyException the client not ready exception * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#stop() */ @Override @@ -325,7 +371,10 @@ public void stop() throws ClientNotReadyException { // clientCommInterface.stop(); } - /** + /** + * + * + * @throws ClientNotReadyException the client not ready exception * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#shutdown() */ @Override @@ -408,7 +457,10 @@ private void runRd() { // CommInterface Logic // =========================================================================== - /** + /** + * + * + * @return the state * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#getState() */ @Override @@ -416,7 +468,10 @@ public ELlClientStates getState() { return this.clientCommInterface.getState(); } - /** + /** + * + * + * @return the yellow page json * @see at.ac.ait.lablink.core.client.ILlClientLogic#getYellowPageJson() */ @Override @@ -424,7 +479,10 @@ public String getYellowPageJson() { return this.clientCommInterface.getYellowPageJson(); } - /** + /** + * + * + * @return the resource discovery meta * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#getResourceDiscoveryMeta() */ @Override @@ -440,7 +498,16 @@ public ResourceDiscoveryClientMeta getResourceDiscoveryMeta() { // FSM Logic (ILlClientFsmLogic) // =========================================================================== - /** + /** + * + * + * @throws ClientNotReadyException the client not ready exception + * @throws NoSuchCommInterfaceException the no such comm interface exception + * @throws NoSuchPseudoHostException the no such pseudo host exception + * @throws NoSuchMethodException the no such method exception + * @throws IllegalAccessException the illegal access exception + * @throws InstantiationException the instantiation exception + * @throws InvocationTargetException the invocation target exception * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onCreateSuccess() */ @Override @@ -459,7 +526,14 @@ public void onCreateSuccess() throws } } - /** + /** + * + * + * @throws ConfigurationException the configuration exception + * @throws ClientNotReadyException the client not ready exception + * @throws NoServicesInClientLogicException the no services in client logic exception + * @throws DataTypeNotSupportedException the data type not supported exception + * @throws PseudoHostException the pseudo host exception * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onInitSuccess() */ @Override @@ -469,14 +543,20 @@ public void onInitSuccess() throws ConfigurationException, ClientNotReadyExcepti logger.info("Client [{}] Initialized.", this.name); } - /** + /** + * + * + * @throws ClientNotReadyException the client not ready exception + * @throws PseudoHostException the pseudo host exception + * @throws IOException * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onStartSuccess() */ @Override - public void onStartSuccess() throws ClientNotReadyException, PseudoHostException { + public void onStartSuccess() throws ClientNotReadyException, PseudoHostException, IOException { this.clientCommInterface.start(); logger.info("Client [{}] started. The runtime Id is [{}].", this.name, this.getRuntimeId()); this.runRd(); + this.runPrometheusMeasures(); if (this.showShell) { try { @@ -487,16 +567,22 @@ public void onStartSuccess() throws ClientNotReadyException, PseudoHostException } } - /** + /** + * + * + * @throws ClientNotReadyException the client not ready exception * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onShutdownSuccess() */ @Override public void onShutdownSuccess() throws ClientNotReadyException { this.clientCommInterface.shutdown(); - logger.info("Client [{}] shuted down.", this.name); + logger.info("Client [{}] shutdown.", this.name); } - /** + /** + * + * + * @return the implemented services * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#getImplementedServices() */ @Override @@ -619,6 +705,14 @@ public boolean setServiceValue(LlService service, double val) return setServiceValue(service.getName(), val); } + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client exception + */ public boolean setServiceValue(LlServicePseudo service, double val) throws ServiceIsNotRegisteredWithClientException { return setServiceValue(service.getName(), val); @@ -638,6 +732,14 @@ public boolean setServiceValue(LlService service, long val) return setServiceValue(service.getName(), val); } + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client exception + */ public boolean setServiceValue(LlServicePseudo service, long val) throws ServiceIsNotRegisteredWithClientException { return setServiceValue(service.getName(), val); @@ -657,6 +759,14 @@ public boolean setServiceValue(LlService service, String val) return setServiceValue(service.getName(), val); } + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client exception + */ public boolean setServiceValue(LlServicePseudo service, String val) throws ServiceIsNotRegisteredWithClientException { return setServiceValue(service.getName(), val); @@ -676,6 +786,14 @@ public boolean setServiceValue(LlService service, boolean val) return setServiceValue(service.getName(), val); } + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client exception + */ public boolean setServiceValue(LlServicePseudo service, boolean val) throws ServiceIsNotRegisteredWithClientException { return setServiceValue(service.getName(), val); @@ -923,6 +1041,9 @@ public boolean isPseudoClient() { } /** + * Gets the pseudo services. + * + * @return the pseudo services * @see at.ac.ait.lablink.core.client.ILlClientLogic#getPseudoServices() */ @Override @@ -930,16 +1051,60 @@ public Map getPseudoServices() { return this.pseudoServices; } + /** + * Sets the client logic. + * + * @param clogic the new client logic + */ @Override public void setClientLogic(ILlClientLogic clogic) { return; } + /** + * Gets the host implementation SP. + * + * @return the host implementation SP + */ @Override public String getHostImplementationSp() { return this.hostImplementation; } + + /** + * Adds the shutdown hook. + * + * @param hook the hook + */ + public void addShutdownHook(Thread hook) { + Runtime.getRuntime().addShutdownHook(hook); + } + + private void setRunPromethusMeasures() { + this.services.forEach((k,v) -> { + if(v.isExposedToPrometheus()) { + this.runPrometheusServer = true; + } + }); + } + + private void startPrometheusMeasures() throws IOException { + this.prometheusMeasuresServer = new HTTPServer.Builder() + .withPort(this.prometheusMeasuresPort) + .build(); + logger.info("Prometheus measures are now availabe for scraping."); + } + + private void runPrometheusMeasures() throws IOException { + this.setRunPromethusMeasures(); + if (this.runPrometheusServer) { + logger.info("Attempting to start Prometheus measures on port {}", this.prometheusMeasuresPort); + this.startPrometheusMeasures(); + } else { + logger.info("No service is configured to be exposed for Prometheus. No measures will be exposed."); + } + } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlService.java b/src/main/java/at/ac/ait/lablink/core/service/LlService.java index 100c96e..58deca7 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlService.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlService.java @@ -110,12 +110,13 @@ private void notifyStateChange(T oldVal, T newVal) { newVal); logger.debug("Notifying to the [{}] registered listener(s)...", this.notifiers.size()); - - // for (Entry> entry : this.notifiers - // .entrySet()) { - // entry.getValue().stateChanged(this, oldVal, newVal); - // } this.notifiers.forEach((k,v)-> v.stateChanged(this, oldVal, newVal)); + + // for (Entry> entry : this.notifiers + // .entrySet()) { + // entry.getValue().stateChanged(this, oldVal, newVal); + // } + } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java index 66c2f0a..da035a6 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java @@ -67,7 +67,7 @@ private void notifyStateChange(T oldVal, T newVal) { } /** - * Instantiates a new ll service pscudo. + * Instantiates a new ll service psecudo. */ public LlServicePseudo() { super(); From a7c66e3fa8090bfd4107af837c0172fc29b641df Mon Sep 17 00:00:00 2001 From: Jawad Kazmi <78086114+kazmijawad@users.noreply.github.com> Date: Wed, 1 Dec 2021 13:54:35 +0100 Subject: [PATCH 3/5] Incremented the version, fixed some typos in client --- .checkstyle | 1 - pom.xml | 2 +- .../at/ac/ait/lablink/core/client/impl/LlClient.java | 12 ++++++------ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.checkstyle b/.checkstyle index 8bc0c81..fc7d3ad 100644 --- a/.checkstyle +++ b/.checkstyle @@ -7,7 +7,6 @@ - diff --git a/pom.xml b/pom.xml index 8779122..11dfc34 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ at.ac.ait.lablink core - 0.0.1 + 0.0.2 AIT Lablink Core Java implementation of AIT Lablink's core application library. https://github.com/ait-lablink/lablink-core-java diff --git a/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java b/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java index a8fdacb..620b94e 100644 --- a/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java +++ b/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java @@ -423,9 +423,9 @@ private void setName(String name) { } /** - * Gets the resource discovery json. + * Gets the resource discovery JSON. * - * @return the resource discovery json + * @return the resource discovery JSON */ private String getResourceDiscoveryJson() { return Utility.getResourceDiscoveryMetaJson(this.getResourceDiscoveryMeta()); @@ -449,7 +449,7 @@ private void runRd() { logger.error(ex.getMessage()); } - logger.debug("Resource advertisement now running..."); + logger.debug("Resource advertisement now running."); } @@ -471,7 +471,7 @@ public ELlClientStates getState() { /** * * - * @return the yellow page json + * @return the yellow page JSON * @see at.ac.ait.lablink.core.client.ILlClientLogic#getYellowPageJson() */ @Override @@ -502,7 +502,7 @@ public ResourceDiscoveryClientMeta getResourceDiscoveryMeta() { * * * @throws ClientNotReadyException the client not ready exception - * @throws NoSuchCommInterfaceException the no such comm interface exception + * @throws NoSuchCommInterfaceException the no such communication interface exception * @throws NoSuchPseudoHostException the no such pseudo host exception * @throws NoSuchMethodException the no such method exception * @throws IllegalAccessException the illegal access exception @@ -1102,7 +1102,7 @@ private void runPrometheusMeasures() throws IOException { logger.info("Attempting to start Prometheus measures on port {}", this.prometheusMeasuresPort); this.startPrometheusMeasures(); } else { - logger.info("No service is configured to be exposed for Prometheus. No measures will be exposed."); + logger.info("No service is configured to be exposed for Prometheus. Server will run and no measures will be exposed."); } } } From d2ef59e66c8c75c378c318a33a777712ca0d8a46 Mon Sep 17 00:00:00 2001 From: Jawad Kazmi <78086114+kazmijawad@users.noreply.github.com> Date: Fri, 17 Dec 2021 16:32:26 +0100 Subject: [PATCH 4/5] Prometheus instrumentation completed with basic functionality --- pom.xml | 37 +- .../lablink/core/client/impl/LlClient.java | 2153 +++++++++-------- .../connection/mqtt/impl/MqttClientSync.java | 1650 ++++++------- .../ait/lablink/core/service/LlService.java | 30 + .../lablink/core/service/LlServiceBase.java | 309 +-- .../lablink/core/service/LlServiceDouble.java | 82 +- .../lablink/core/service/LlServiceLong.java | 71 +- .../lablink/core/service/LlServicePseudo.java | 8 +- .../core/service/LlServicePseudoDouble.java | 69 +- .../core/service/LlServicePseudoLong.java | 65 +- .../ait/lablink/core/services/ServiceIT.java | 2 +- .../datapoint/payloads/BooleanValueTest.java | 3 +- .../payloads/DataPointPropertiesTest.java | 3 +- .../datapoint/payloads/DoubleValueTest.java | 3 +- .../datapoint/payloads/LongValueTest.java | 3 +- .../datapoint/payloads/StringValueTest.java | 3 +- .../payloads/SyncClientConfigMessageTest.java | 3 +- .../sync/payloads/SyncGoReplyTest.java | 3 +- .../sync/payloads/SyncGoRequestTest.java | 3 +- .../sync/payloads/SyncParamMessageTest.java | 3 +- 20 files changed, 2408 insertions(+), 2095 deletions(-) diff --git a/pom.xml b/pom.xml index 11dfc34..de7c397 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 3.2.0 private true @@ -283,7 +283,8 @@ - + + + + + + org.slf4j + slf4j-api + 1.7.25 + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.8.2 + + + + org.apache.logging.log4j + log4j-api + 2.7 + + + + org.apache.logging.log4j + log4j-core + 2.7 diff --git a/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java b/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java index 620b94e..c01e053 100644 --- a/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java +++ b/src/main/java/at/ac/ait/lablink/core/client/impl/LlClient.java @@ -5,8 +5,21 @@ package at.ac.ait.lablink.core.client.impl; -import asg.cliche.ShellFactory; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.databind.JsonMappingException; + +import asg.cliche.ShellFactory; import at.ac.ait.lablink.core.Configuration; import at.ac.ait.lablink.core.client.ELlClientAdvProperties; import at.ac.ait.lablink.core.client.ELlClientProperties; @@ -37,1074 +50,1088 @@ import at.ac.ait.lablink.core.utility.LlAddressUtility; import at.ac.ait.lablink.core.utility.Utility; import io.prometheus.client.exporter.HTTPServer; - -import com.fasterxml.jackson.core.JsonGenerationException; -import com.fasterxml.jackson.databind.JsonMappingException; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; +import io.prometheus.client.hotspot.DefaultExports; // TODO: Auto-generated Javadoc /** - * Implementation of Lablink client base functionality, including - * the client logic and communication interface. + * Implementation of Lablink client base functionality, including the client + * logic and communication interface. */ public final class LlClient implements ILlClientLogic, ILlClientCommInterface, ILlClientFsmLogic { - /** The id. */ - private final long id = LlAddressUtility.getRandomClientId(); - - /** The port on which this client's measures would be exposed to Prometheus.*/ - private static final int PROMETHEUS_MEASURES_PORT = 7979; - - /** The logger. */ - private static Logger logger = LogManager.getLogger("LlClient"); - - /** The ready. */ - private boolean ready = false; - - /** The pseudo client. */ - private boolean pseudoClient = false; - - /** The state. */ - private ELlClientStates state = ELlClientStates.LABLINK_CLIENT_INTERFACE_STATE_NOTINSTANTIATED; - - /** The REsource Discovery Server. */ - private ResourceDiscoveryPeriodicServer rdServer; - - /** The FSM. */ - private LlClientFsm fsm; - - /** The name. */ - private String name; - - /** The Yellow Pages for DP broadcast on LAN */ - private MqttYellowPageForClient yellopages; - - /** The gen yellowpages. */ - private String genYellowpages; - - /** The ypages client scope. */ - private String[] ypagesClientScope; - - /** The properties. */ - private Map properties = new HashMap(); - - /** The advanced properties. */ - private Map advProperties = - new HashMap(); - - /** The client logic services. */ - private Map services = new HashMap(); - - /** The client logic Pseudo services. */ - private Map pseudoServices = new HashMap(); - - /** The client interface types. */ - // private ELlClientCommInterfaces clientCommInterfaceType; - - private String hostImplementation; - - /** The client communication interface. */ - private ILlClientCommInterface clientCommInterface = null; - - /** The pseudo host type. */ - // private ELlClientPseudoHosts pseudoHostType; - - /** The sthread. */ - private Thread sthread; - - /** The shell. */ - private LlClientIShell shell; - - /** The show shell. */ - private boolean showShell = false; - - /** The prometheus measures port. */ - private int prometheusMeasuresPort = PROMETHEUS_MEASURES_PORT; - - private HTTPServer prometheusMeasuresServer; - private boolean runPrometheusServer = false; - - /** - * Instantiates a new ll client. - * - * @param cname the name this client will be identified with - * @param hostSp the access name of the host implementation to use - * @param giveShell the flag to indicated if ishell should be shown - * @param isPseudo the is the flag indicating a pseudo client - * @param pmport the port number on which the Prometheus measures will be available - * @param scope scope - */ - public LlClient(String cname, String hostSp, boolean giveShell, boolean isPseudo, int pmport, String... scope) { - if (isPseudo) { - logger.info( - "PseudoClient will be instantiated with name={} and will work with the PseudoHost={}.", - cname, hostSp); - } else { - logger.info( - "CustomClient will be instantiated with name={} and will work with the CustomHost={}.", - cname, hostSp); - } - - // this.clientCommInterfaceType = null; - this.setName(cname); - this.fsm = new LlClientFsm(this); - this.showShell = giveShell; - this.pseudoClient = isPseudo; - // this.pseudoHostType = null; - this.hostImplementation = hostSp; - this.prometheusMeasuresPort = pmport; -} + /** The id. */ + private final long id = LlAddressUtility.getRandomClientId(); - /** - * Instantiates a new ll client. - * - * @param cname the name this client will be identified with - * @param hostSp the access name of the host implementation to use - * @param giveShell the flag to indicated if ishell should be shown - * @param isPseudo the is the flag indicating a pseudo client - * @param scope scope - */ - public LlClient(String cname, String hostSp, boolean giveShell, boolean isPseudo, String... scope) { - this(cname, hostSp, giveShell, isPseudo, PROMETHEUS_MEASURES_PORT, scope); - } - - /** - * Start shell. - * - * @throws IOException Signals that an I/O exception has occurred. - */ - private void startShell() throws IOException { - - this.shell = new LlClientIShell(this); - - this.sthread = new Thread() { - public void run() { - try { - ShellFactory.createConsoleShell(ShellUtility.SHELL_PROMT, - ShellUtility.SHELL_WELCOME_MESSAGE, shell).commandLoop(); - } catch (IOException ex) { - logger.error(ex.getMessage()); - } - } - }; - - sthread.setName("Shell"); - sthread.start(); - - } - - /** - * Adds the service. - * - * @param service the service - * @throws ServiceTypeDoesNotMatchClientType the service type do not match client type - */ - public void addService(LlService service) throws ServiceTypeDoesNotMatchClientType { - if (this.isPseudoClient()) { - throw new ServiceTypeDoesNotMatchClientType(); - } else { - this.services.put(service.getName(), service); - logger.debug("Service added with name=[{}], Readonly=[{}]", service.getName(), - service.isReadOnly()); - } - } - - /** - * Adds the service. - * - * @param service the service - * @throws ServiceTypeDoesNotMatchClientType the service type do not match client type - */ - public void addService(LlServicePseudo service) throws ServiceTypeDoesNotMatchClientType { - if (!this.isPseudoClient()) { - throw new ServiceTypeDoesNotMatchClientType(); - } else { - - this.pseudoServices.put(service.getName(), service); - logger.debug("Pseudo Service added with name=[{}], Readonly=[{}]", service.getName(), - service.isReadOnly()); - } - } - - /** - * Creates the client with the specified interface. This is the function where most of the work is - * being done of creating a client based on the specified interface. - * - * @throws ClientNotReadyException the client not ready exception - * @throws NoSuchCommInterfaceException the no such comm interface exception - */ - public void create() throws ClientNotReadyException, NoSuchCommInterfaceException { - this.fsm.transitionTo(LlClientFsm.EPossibleTransitionTriggers.CREATE); - } - - ///////////////////////////////////////////////////////////////////////////////// - // - ///////////////////////////////////////////////////////////////////////////////// - - /** - * - * - * @return the properties - * @see at.ac.ait.lablink.core.client.ILlClientLogic#getProperties() - */ - @Override - public Map getProperties() { - return this.properties; - } - - /** - * - * - * @return the services - * @see at.ac.ait.lablink.core.client.ILlClientLogic#getServices() - */ - @Override - public Map getServices() { - return this.services; - } - - /** - * - * - * @return the adv properties - * @see at.ac.ait.lablink.core.client.ILlClientLogic#getAdvProperties() - */ - @Override - public Map getAdvProperties() { - return this.advProperties; - } - - /** - * Adds the property. - * - * @param property the property - * @param value the value - */ - public void addProperty(ELlClientProperties property, String value) { - this.properties.put(property, value); - logger.debug("Client property={} value='{}' added.", property, value); - } - - /** - * Adds the adv property. - * - * @param property the property - * @param value the value - */ - public void addAdvProperty(ELlClientAdvProperties property, Object value) { - this.advProperties.put(property, value); - logger.debug("Advanced client property {} added.", property); - } - - /** - * Gets the property. - * - * @param key the key - * @return the property - */ - public String getProperty(ELlClientProperties key) { - return this.properties.get(key); - } - - /** - * Gets the adv property. - * - * @param key the key - * @return the adv property - */ - public Object getAdvProperty(ELlClientAdvProperties key) { - return this.advProperties.get(key); - } - - ///////////////////////////////////////////////////////////////////////////////// - // - ///////////////////////////////////////////////////////////////////////////////// - - /** - * - * - * @throws ClientNotReadyException the client not ready exception - * @throws ConfigurationException the configuration exception - * @throws NoServicesInClientLogicException the no services in client logic exception - * @throws DataTypeNotSupportedException the data type not supported exception - * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#init() - */ - @Override - public void init() throws ClientNotReadyException, ConfigurationException, - NoServicesInClientLogicException, DataTypeNotSupportedException { - // checkReady(); - // clientCommInterface.init(); - this.fsm.transitionTo(LlClientFsm.EPossibleTransitionTriggers.INIT); - } - - /** - * - * - * @throws ClientNotReadyException the client not ready exception - * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#start() - */ - @Override - public void start() throws ClientNotReadyException { - // checkReady(); - this.fsm.transitionTo(LlClientFsm.EPossibleTransitionTriggers.START); - } - - - /** - * - * - * @throws ClientNotReadyException the client not ready exception - * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#stop() - */ - @Override - public void stop() throws ClientNotReadyException { - // clientCommInterface.stop(); - } - - /** - * - * - * @throws ClientNotReadyException the client not ready exception - * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#shutdown() - */ - @Override - public void shutdown() throws ClientNotReadyException { - this.fsm.transitionTo(LlClientFsm.EPossibleTransitionTriggers.SHUTDOWN); - } - - ///////////////////////////////////////////////////////////////////////////////// - // - ///////////////////////////////////////////////////////////////////////////////// - - /** - * Checks if is ready. - * - * @return the ready - */ - public boolean isReady() { - return ready; - } - - /** - * Sets the ready. - * - * @param ready the ready to set - */ - public void setReady(boolean ready) { - this.ready = ready; - } - - /** - * Gets the name. - * - * @return the name - */ - public String getName() { - return name; - } - - /** - * Sets the name. - * - * @param name the name to set - */ - private void setName(String name) { - this.name = name; - } - - /** - * Gets the resource discovery JSON. - * - * @return the resource discovery JSON - */ - private String getResourceDiscoveryJson() { - return Utility.getResourceDiscoveryMetaJson(this.getResourceDiscoveryMeta()); - } - - /** - * Run Resource discovery advertisement. - */ - private void runRd() { - logger.debug("Starting resource advertisement server..."); - - try { - this.rdServer = new ResourceDiscoveryPeriodicServer(getResourceDiscoveryMeta()); - this.rdServer.start(); - logger.debug("Resource advertisement started."); - } catch (JsonGenerationException ex) { - logger.error(ex.getMessage()); - } catch (JsonMappingException ex) { - logger.error(ex.getMessage()); - } catch (IOException ex) { - logger.error(ex.getMessage()); - } - - logger.debug("Resource advertisement now running."); - - } - - // =========================================================================== - // CommInterface Logic - // =========================================================================== - - /** - * - * - * @return the state - * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#getState() - */ - @Override - public ELlClientStates getState() { - return this.clientCommInterface.getState(); - } - - /** - * - * - * @return the yellow page JSON - * @see at.ac.ait.lablink.core.client.ILlClientLogic#getYellowPageJson() - */ - @Override - public String getYellowPageJson() { - return this.clientCommInterface.getYellowPageJson(); - } - - /** - * - * - * @return the resource discovery meta - * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#getResourceDiscoveryMeta() - */ - @Override - public ResourceDiscoveryClientMeta getResourceDiscoveryMeta() { - ResourceDiscoveryClientMeta meta = this.clientCommInterface.getResourceDiscoveryMeta(); - meta.setClientScope(this.ypagesClientScope); - meta.setClientTransport("TRANSPORT_MQTT"); - meta.setClientEncoding(Configuration.RESOURCE_DISCOVERY_ENCODING_USE); - return meta; - } - - // =========================================================================== - // FSM Logic (ILlClientFsmLogic) - // =========================================================================== - - /** - * - * - * @throws ClientNotReadyException the client not ready exception - * @throws NoSuchCommInterfaceException the no such communication interface exception - * @throws NoSuchPseudoHostException the no such pseudo host exception - * @throws NoSuchMethodException the no such method exception - * @throws IllegalAccessException the illegal access exception - * @throws InstantiationException the instantiation exception - * @throws InvocationTargetException the invocation target exception - * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onCreateSuccess() - */ - @Override - public void onCreateSuccess() throws - ClientNotReadyException, NoSuchCommInterfaceException, - NoSuchPseudoHostException, NoSuchMethodException, - IllegalAccessException, InstantiationException, - InvocationTargetException { - this.clientCommInterface = LlClientCommInterfaceFactory.getHostImplementation(this); - this.clientCommInterface.create(); - if (this.isPseudoClient()) { - logger.info("Pseudo Client [{}] created for host [{}].", this.name, this.hostImplementation); - } else { - logger.info("Client [{}] created with requested interface [{}].", this.name, - this.hostImplementation); - } - } - - /** - * - * - * @throws ConfigurationException the configuration exception - * @throws ClientNotReadyException the client not ready exception - * @throws NoServicesInClientLogicException the no services in client logic exception - * @throws DataTypeNotSupportedException the data type not supported exception - * @throws PseudoHostException the pseudo host exception - * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onInitSuccess() - */ - @Override - public void onInitSuccess() throws ConfigurationException, ClientNotReadyException, - NoServicesInClientLogicException, DataTypeNotSupportedException, PseudoHostException { - this.clientCommInterface.init(); - logger.info("Client [{}] Initialized.", this.name); - } - - /** - * - * - * @throws ClientNotReadyException the client not ready exception - * @throws PseudoHostException the pseudo host exception - * @throws IOException - * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onStartSuccess() - */ - @Override - public void onStartSuccess() throws ClientNotReadyException, PseudoHostException, IOException { - this.clientCommInterface.start(); - logger.info("Client [{}] started. The runtime Id is [{}].", this.name, this.getRuntimeId()); - this.runRd(); - this.runPrometheusMeasures(); - - if (this.showShell) { - try { - this.startShell(); - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - - /** - * - * - * @throws ClientNotReadyException the client not ready exception - * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onShutdownSuccess() - */ - @Override - public void onShutdownSuccess() throws ClientNotReadyException { - this.clientCommInterface.shutdown(); - logger.info("Client [{}] shutdown.", this.name); - } - - /** - * - * - * @return the implemented services - * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#getImplementedServices() - */ - @Override - public Map getImplementedServices() { - return this.clientCommInterface.getImplementedServices(); - } - - - /** - * Gets the service description. - * - * @param service the service - * @return the service description - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client - * exception - */ - public String getServiceDescription(String service) - throws ServiceIsNotRegisteredWithClientException { - - if (!this.isServiceExists(service)) { - throw new ServiceIsNotRegisteredWithClientException(); - } - - return clientCommInterface.getImplementedServices().get(service).getName(); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client - * exception - */ - @SuppressWarnings( "unchecked" ) - public boolean setServiceValue(String service, double val) - throws ServiceIsNotRegisteredWithClientException { - - if (!this.isServiceExists(service)) { - throw new ServiceIsNotRegisteredWithClientException(); - } - - return clientCommInterface.getImplementedServices().get(service).setValue(Double.valueOf(val)); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client - * exception - */ - @SuppressWarnings( "unchecked" ) - public boolean setServiceValue(String service, long val) - throws ServiceIsNotRegisteredWithClientException { - - if (!this.isServiceExists(service)) { - throw new ServiceIsNotRegisteredWithClientException(); - } - - return clientCommInterface.getImplementedServices().get(service).setValue(Long.valueOf(val)); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client - * exception - */ - @SuppressWarnings( "unchecked" ) - public boolean setServiceValue(String service, boolean val) - throws ServiceIsNotRegisteredWithClientException { - - if (!this.isServiceExists(service)) { - throw new ServiceIsNotRegisteredWithClientException(); - } - - return clientCommInterface.getImplementedServices().get(service).setValue(Boolean.valueOf(val)); - } - - /** - * Sets the service value. - * - * @param servicename the servicename - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client - * exception - */ - @SuppressWarnings( "unchecked" ) - public boolean setServiceValue(String servicename, String val) - throws ServiceIsNotRegisteredWithClientException { - - if (!this.isServiceExists(servicename)) { - throw new ServiceIsNotRegisteredWithClientException(); - } - - // return clientCommInterface.getImplementedServices().get(servicename) - // .setValue(new String(val)); - return clientCommInterface.getImplementedServices().get(servicename).setValue(val); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client - * exception - */ - public boolean setServiceValue(LlService service, double val) - throws ServiceIsNotRegisteredWithClientException { - return setServiceValue(service.getName(), val); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client exception - */ - public boolean setServiceValue(LlServicePseudo service, double val) - throws ServiceIsNotRegisteredWithClientException { - return setServiceValue(service.getName(), val); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client - * exception - */ - public boolean setServiceValue(LlService service, long val) - throws ServiceIsNotRegisteredWithClientException { - return setServiceValue(service.getName(), val); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client exception - */ - public boolean setServiceValue(LlServicePseudo service, long val) - throws ServiceIsNotRegisteredWithClientException { - return setServiceValue(service.getName(), val); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client - * exception - */ - public boolean setServiceValue(LlService service, String val) - throws ServiceIsNotRegisteredWithClientException { - return setServiceValue(service.getName(), val); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client exception - */ - public boolean setServiceValue(LlServicePseudo service, String val) - throws ServiceIsNotRegisteredWithClientException { - return setServiceValue(service.getName(), val); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client - * exception - */ - public boolean setServiceValue(LlService service, boolean val) - throws ServiceIsNotRegisteredWithClientException { - return setServiceValue(service.getName(), val); - } - - /** - * Sets the service value. - * - * @param service the service - * @param val the val - * @return true, if successful - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client exception - */ - public boolean setServiceValue(LlServicePseudo service, boolean val) - throws ServiceIsNotRegisteredWithClientException { - return setServiceValue(service.getName(), val); - } - - /** - * Checks if is service exists. - * - * @param sname the sname - * @return true, if is service exists - */ - public boolean isServiceExists(String sname) { - return this.isPseudoClient() ? (this.getPseudoServices().get(sname) != null) - : (this.getServices().get(sname) != null); - } - - /** - * Gets the service value double. - * - * @param service the service - * @return the service value double - * @throws InvalidCastForServiceValueException the invalid cast for service value exception - */ - public Double getServiceValueDouble(String service) throws InvalidCastForServiceValueException { - Double curval = null; - - try { - curval = (Double) clientCommInterface.getImplementedServices().get(service).getValue(); - } catch (Exception ex) { - logger.error(ex.getMessage()); - throw new InvalidCastForServiceValueException(); - } - - return curval; - } - - - /** - * Gets the service value double. - * - * @param service the service - * @return the service value double - * @throws InvalidCastForServiceValueException the invalid cast for service value exception - */ - public Double getServiceValueDouble(LlService service) - throws InvalidCastForServiceValueException { - return getServiceValueDouble(service.getName()); - } - - /** - * Gets the service value long. - * - * @param service the service - * @return the service value long - * @throws InvalidCastForServiceValueException the invalid cast for service value exception - */ - public Long getServiceValueLong(LlService service) throws InvalidCastForServiceValueException { - return getServiceValueLong(service.getName()); - } - - /** - * Gets the service value long. - * - * @param service the service - * @return the service value long - * @throws InvalidCastForServiceValueException the invalid cast for service value exception - */ - public Long getServiceValueLong(String service) throws InvalidCastForServiceValueException { - Long curval = null; - - try { - curval = (Long) clientCommInterface.getImplementedServices().get(service).getValue(); - } catch (Exception ex) { - logger.error(ex.getMessage()); - throw new InvalidCastForServiceValueException(); - } - - return curval; - - } - - /** - * Gets the service value boolean. - * - * @param service the service - * @return the service value boolean - * @throws InvalidCastForServiceValueException the invalid cast for service value exception - */ - public Boolean getServiceValueBoolean(LlService service) - throws InvalidCastForServiceValueException { - - return getServiceValueBoolean(service.getName()); - } - - /** - * Gets the service value boolean. - * - * @param service the service - * @return the service value boolean - * @throws InvalidCastForServiceValueException the invalid cast for service value exception - */ - public Boolean getServiceValueBoolean(String service) throws InvalidCastForServiceValueException { - Boolean curval = null; - - try { - curval = (Boolean) clientCommInterface.getImplementedServices().get(service).getValue(); - } catch (Exception ex) { - logger.error(ex.getMessage()); - throw new InvalidCastForServiceValueException(); - } - - return curval; - - } - - /** - * Gets the service value string. - * - * @param service the service - * @return the service value string - * @throws InvalidCastForServiceValueException the invalid cast for service value exception - */ - public String getServiceValueString(LlService service) - throws InvalidCastForServiceValueException { - return getServiceValueString(service.getName()); - } - - /** - * Gets the service value string. - * - * @param service the service - * @return the service value string - */ - public String getServiceValueString(String service) { - return clientCommInterface.getImplementedServices().get(service).getValue().toString(); - } - - /** - * Gets the service string value. - * - * @param service the service - * @return the service string value - */ - public Optional getServiceStringValue(String service) { - return Optional.ofNullable( - clientCommInterface.getImplementedServices().get(service).getValue().toString()); - } - - - /** - * Gets the service value. - * - * @param service the service - * @return the service value - * @throws InvalidCastForServiceValueException the invalid cast for service value exception - */ - public ByteBuffer getServiceValue(LlService service) throws InvalidCastForServiceValueException { - - ByteBuffer bb = null; - - ELlServiceDataTypes stype = service.getServiceDataType(); - String sname = service.getName(); - - if (stype == null) { - throw new InvalidCastForServiceValueException(); - } - - switch (stype) { - case SERVICE_DATATYPE_DOUBLE: - bb = ByteBuffer.allocate(Double.SIZE); - bb.putDouble(getServiceValueDouble(sname)); - bb.rewind(); - break; - case SERVICE_DATATYPE_LONG: - bb = ByteBuffer.allocate(Long.SIZE); - bb.putLong(getServiceValueLong(sname)); - bb.rewind(); - break; - case SERVICE_DATATYPE_STRING: - String sval = getServiceValueString(sname); - ByteBuffer.allocate(sval.length()); - bb.put(sval.getBytes()); - bb.rewind(); - break; - case SERVICE_DATATYPE_BOOLEAN: - short bval = (short) (getServiceValueBoolean(sname).booleanValue() ? 1 : 0); - bb.putShort(bval); - bb.rewind(); - break; - default: - logger.error("Data type not supported [{}].", stype); - throw new InvalidCastForServiceValueException(); - } - - return bb.asReadOnlyBuffer(); - } - - /** - * Gets the service value as a String. The function will determine the service data type - * automatically. - * - * @param service the service - * @return the service value auto - */ - public String getServiceValueAuto(LlService service) { - - return service.getCurState().toString(); - } - - /** - * Gets the service value auto. - * - * @param service the service - * @return the service value auto - * @throws ServiceIsNotRegisteredWithClientException the service is not registered with client - * exception - */ - public String getServiceValueAuto(String service) - throws ServiceIsNotRegisteredWithClientException { - - if (!this.isServiceExists(service)) { - throw new ServiceIsNotRegisteredWithClientException(); - } - - return this.getServices().get(service).getCurState().toString(); - - } - - /** - * Gets the runtime id. - * - * @return the runtime id - */ - public long getRuntimeId() { - return this.id; - } - - /** - * Checks if this is a pseudo client. - * - * @return the pseudoClient - */ - public boolean isPseudoClient() { - return pseudoClient; - } - - /** - * Gets the pseudo services. - * - * @return the pseudo services - * @see at.ac.ait.lablink.core.client.ILlClientLogic#getPseudoServices() - */ - @Override - public Map getPseudoServices() { - return this.pseudoServices; - } - - /** - * Sets the client logic. - * - * @param clogic the new client logic - */ - @Override - public void setClientLogic(ILlClientLogic clogic) { - return; - } - - /** - * Gets the host implementation SP. - * - * @return the host implementation SP - */ - @Override - public String getHostImplementationSp() { - return this.hostImplementation; - } - - - /** - * Adds the shutdown hook. - * - * @param hook the hook - */ - public void addShutdownHook(Thread hook) { - Runtime.getRuntime().addShutdownHook(hook); - } - - private void setRunPromethusMeasures() { - this.services.forEach((k,v) -> { - if(v.isExposedToPrometheus()) { - this.runPrometheusServer = true; - } - }); - } - - private void startPrometheusMeasures() throws IOException { - this.prometheusMeasuresServer = new HTTPServer.Builder() - .withPort(this.prometheusMeasuresPort) - .build(); - logger.info("Prometheus measures are now availabe for scraping."); - } - - private void runPrometheusMeasures() throws IOException { - this.setRunPromethusMeasures(); - if (this.runPrometheusServer) { - logger.info("Attempting to start Prometheus measures on port {}", this.prometheusMeasuresPort); - this.startPrometheusMeasures(); - } else { - logger.info("No service is configured to be exposed for Prometheus. Server will run and no measures will be exposed."); - } - } -} + /** The port on which this client's measures would be exposed to Prometheus. */ + private static final int PROMETHEUS_MEASURES_PORT = 7979; + + /** The logger. */ + private static Logger logger = LogManager.getLogger("LlClient"); + + /** The ready. */ + private boolean ready = false; + /** The pseudo client. */ + private boolean pseudoClient = false; + /** The state. */ + private ELlClientStates state = ELlClientStates.LABLINK_CLIENT_INTERFACE_STATE_NOTINSTANTIATED; + + /** The REsource Discovery Server. */ + private ResourceDiscoveryPeriodicServer rdServer; + + /** The FSM. */ + private LlClientFsm fsm; + + /** The name. */ + private String name; + + /** The Yellow Pages for DP broadcast on LAN. */ + private MqttYellowPageForClient yellopages; + + /** The gen yellowpages. */ + private String genYellowpages; + + /** The ypages client scope. */ + private String[] ypagesClientScope; + + /** The properties. */ + private Map properties = new HashMap(); + + /** The advanced properties. */ + private Map advProperties = new HashMap(); + + /** The client logic services. */ + private Map services = new HashMap(); + + /** The client logic Pseudo services. */ + private Map pseudoServices = new HashMap(); + + /** The client interface types. */ + // private ELlClientCommInterfaces clientCommInterfaceType; + + private String hostImplementation; + + /** The client communication interface. */ + private ILlClientCommInterface clientCommInterface = null; + + /** The pseudo host type. */ + // private ELlClientPseudoHosts pseudoHostType; + + /** The sthread. */ + private Thread sthread; + + /** The shell. */ + private LlClientIShell shell; + + /** The show shell. */ + private boolean showShell = false; + + /** The Prometheus measures port. */ + private int prometheusMeasuresPort = PROMETHEUS_MEASURES_PORT; + + /** The Prometheus measures server. */ + private HTTPServer prometheusMeasuresServer; + + /** The run prometheus server. */ + private boolean runPrometheusServer = false; + + /** + * Instantiates a new ll client. + * + * @param cname the name this client will be identified with + * @param hostSp the access name of the host implementation to use + * @param giveShell the flag to indicated if ishell should be shown + * @param isPseudo the is the flag indicating a pseudo client + * @param pmport the port number on which the Prometheus measures will be + * available + * @param scope scope + */ + public LlClient(String cname, String hostSp, boolean giveShell, boolean isPseudo, int pmport, String... scope) { + if (isPseudo) { + logger.info("PseudoClient will be instantiated with name={} and will work with the PseudoHost={}.", cname, + hostSp); + } else { + logger.info("CustomClient will be instantiated with name={} and will work with the CustomHost={}.", cname, + hostSp); + } + + // this.clientCommInterfaceType = null; + this.setName(cname); + this.fsm = new LlClientFsm(this); + this.showShell = giveShell; + this.pseudoClient = isPseudo; + // this.pseudoHostType = null; + this.hostImplementation = hostSp; + this.prometheusMeasuresPort = pmport; + } + + /** + * Instantiates a new Lablink Client. + * + * @param cname the name this client will be identified with + * @param hostSp the access name of the host implementation to use + * @param giveShell the flag to indicated if ishell should be shown + * @param isPseudo the is the flag indicating a pseudo client + * @param scope scope + */ + public LlClient(String cname, String hostSp, boolean giveShell, boolean isPseudo, String... scope) { + this(cname, hostSp, giveShell, isPseudo, PROMETHEUS_MEASURES_PORT, scope); + } + + /** + * Start shell. + * + * @throws IOException Signals that an I/O exception has occurred. + */ + private void startShell() throws IOException { + + this.shell = new LlClientIShell(this); + + this.sthread = new Thread() { + @Override + public void run() { + try { + ShellFactory.createConsoleShell(ShellUtility.SHELL_PROMT, ShellUtility.SHELL_WELCOME_MESSAGE, shell) + .commandLoop(); + } catch (IOException ex) { + logger.error(ex.getMessage()); + } + } + }; + + sthread.setName("Shell"); + sthread.start(); + + } + + /** + * Adds the service. + * + * @param service the service + * @throws ServiceTypeDoesNotMatchClientType the service type do not match + * client type + */ + public void addService(LlService service) throws ServiceTypeDoesNotMatchClientType { + if (this.isPseudoClient()) { + throw new ServiceTypeDoesNotMatchClientType(); + } else { + this.services.put(service.getName(), service); + logger.debug("Service added with name=[{}], Readonly=[{}]", service.getName(), service.isReadOnly()); + } + } + + /** + * Adds the service. + * + * @param service the service + * @throws ServiceTypeDoesNotMatchClientType the service type do not match + * client type + */ + public void addService(LlServicePseudo service) throws ServiceTypeDoesNotMatchClientType { + if (!this.isPseudoClient()) { + throw new ServiceTypeDoesNotMatchClientType(); + } else { + + this.pseudoServices.put(service.getName(), service); + logger.debug("Pseudo Service added with name=[{}], Readonly=[{}]", service.getName(), service.isReadOnly()); + } + } + + /** + * Creates the client with the specified interface. This is the function where + * most of the work is being done of creating a client based on the specified + * interface. + * + * @throws ClientNotReadyException the client not ready exception + * @throws NoSuchCommInterfaceException the no such communication interface + * exception + */ + @Override + public void create() throws ClientNotReadyException, NoSuchCommInterfaceException { + this.fsm.transitionTo(LlClientFsm.EPossibleTransitionTriggers.CREATE); + } + + ///////////////////////////////////////////////////////////////////////////////// + // + ///////////////////////////////////////////////////////////////////////////////// + + /** + * + * + * @return the properties + * @see at.ac.ait.lablink.core.client.ILlClientLogic#getProperties() + */ + @Override + public Map getProperties() { + return this.properties; + } + + /** + * + * + * @return the services + * @see at.ac.ait.lablink.core.client.ILlClientLogic#getServices() + */ + @Override + public Map getServices() { + return this.services; + } + + /** + * + * + * @return the adv properties + * @see at.ac.ait.lablink.core.client.ILlClientLogic#getAdvProperties() + */ + @Override + public Map getAdvProperties() { + return this.advProperties; + } + + /** + * Adds the property. + * + * @param property the property + * @param value the value + */ + public void addProperty(ELlClientProperties property, String value) { + this.properties.put(property, value); + logger.debug("Client property={} value='{}' added.", property, value); + } + + /** + * Adds the adv property. + * + * @param property the property + * @param value the value + */ + public void addAdvProperty(ELlClientAdvProperties property, Object value) { + this.advProperties.put(property, value); + logger.debug("Advanced client property {} added.", property); + } + + /** + * Gets the property. + * + * @param key the key + * @return the property + */ + @Override + public String getProperty(ELlClientProperties key) { + return this.properties.get(key); + } + + /** + * Gets the adv property. + * + * @param key the key + * @return the adv property + */ + @Override + public Object getAdvProperty(ELlClientAdvProperties key) { + return this.advProperties.get(key); + } + + ///////////////////////////////////////////////////////////////////////////////// + // + ///////////////////////////////////////////////////////////////////////////////// + + /** + * + * + * @throws ClientNotReadyException the client not ready exception + * @throws ConfigurationException the configuration exception + * @throws NoServicesInClientLogicException the no services in client logic + * exception + * @throws DataTypeNotSupportedException the data type not supported + * exception + * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#init() + */ + @Override + public void init() throws ClientNotReadyException, ConfigurationException, NoServicesInClientLogicException, + DataTypeNotSupportedException { + // checkReady(); + // clientCommInterface.init(); + this.fsm.transitionTo(LlClientFsm.EPossibleTransitionTriggers.INIT); + } + + /** + * + * + * @throws ClientNotReadyException the client not ready exception + * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#start() + */ + @Override + public void start() throws ClientNotReadyException { + // checkReady(); + this.fsm.transitionTo(LlClientFsm.EPossibleTransitionTriggers.START); + } + + /** + * + * + * @throws ClientNotReadyException the client not ready exception + * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#stop() + */ + @Override + public void stop() throws ClientNotReadyException { + // clientCommInterface.stop(); + } + + /** + * + * + * @throws ClientNotReadyException the client not ready exception + * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#shutdown() + */ + @Override + public void shutdown() throws ClientNotReadyException { + this.fsm.transitionTo(LlClientFsm.EPossibleTransitionTriggers.SHUTDOWN); + } + + ///////////////////////////////////////////////////////////////////////////////// + // + ///////////////////////////////////////////////////////////////////////////////// + + /** + * Checks if is ready. + * + * @return the ready + */ + public boolean isReady() { + return ready; + } + + /** + * Sets the ready. + * + * @param ready the ready to set + */ + public void setReady(boolean ready) { + this.ready = ready; + } + + /** + * Gets the name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Sets the name. + * + * @param name the name to set + */ + private void setName(String name) { + this.name = name; + } + + /** + * Gets the resource discovery JSON. + * + * @return the resource discovery JSON + */ + private String getResourceDiscoveryJson() { + return Utility.getResourceDiscoveryMetaJson(this.getResourceDiscoveryMeta()); + } + + /** + * Run Resource discovery advertisement. + */ + private void runRd() { + logger.debug("Starting resource advertisement server..."); + + try { + this.rdServer = new ResourceDiscoveryPeriodicServer(getResourceDiscoveryMeta()); + this.rdServer.start(); + logger.debug("Resource advertisement started."); + } catch (JsonGenerationException ex) { + logger.error(ex.getMessage()); + } catch (JsonMappingException ex) { + logger.error(ex.getMessage()); + } catch (IOException ex) { + logger.error(ex.getMessage()); + } + + logger.debug("Resource advertisement now running."); + + } + + // =========================================================================== + // CommInterface Logic + // =========================================================================== + + /** + * + * + * @return the state + * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#getState() + */ + @Override + public ELlClientStates getState() { + return this.clientCommInterface.getState(); + } + + /** + * + * + * @return the yellow page JSON + * @see at.ac.ait.lablink.core.client.ILlClientLogic#getYellowPageJson() + */ + @Override + public String getYellowPageJson() { + return this.clientCommInterface.getYellowPageJson(); + } + + /** + * + * + * @return the resource discovery meta + * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#getResourceDiscoveryMeta() + */ + @Override + public ResourceDiscoveryClientMeta getResourceDiscoveryMeta() { + ResourceDiscoveryClientMeta meta = this.clientCommInterface.getResourceDiscoveryMeta(); + meta.setClientScope(this.ypagesClientScope); + meta.setClientTransport("TRANSPORT_MQTT"); + meta.setClientEncoding(Configuration.RESOURCE_DISCOVERY_ENCODING_USE); + return meta; + } + + // =========================================================================== + // FSM Logic (ILlClientFsmLogic) + // =========================================================================== + + /** + * + * + * @throws ClientNotReadyException the client not ready exception + * @throws NoSuchCommInterfaceException the no such communication interface + * exception + * @throws NoSuchPseudoHostException the no such pseudo host exception + * @throws NoSuchMethodException the no such method exception + * @throws IllegalAccessException the illegal access exception + * @throws InstantiationException the instantiation exception + * @throws InvocationTargetException the invocation target exception + * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onCreateSuccess() + */ + @Override + public void onCreateSuccess() + throws ClientNotReadyException, NoSuchCommInterfaceException, NoSuchPseudoHostException, + NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { + this.clientCommInterface = LlClientCommInterfaceFactory.getHostImplementation(this); + this.clientCommInterface.create(); + if (this.isPseudoClient()) { + logger.info("Pseudo Client [{}] created for host [{}].", this.name, this.hostImplementation); + } else { + logger.info("Client [{}] created with requested interface [{}].", this.name, this.hostImplementation); + } + } + + /** + * + * + * @throws ConfigurationException the configuration exception + * @throws ClientNotReadyException the client not ready exception + * @throws NoServicesInClientLogicException the no services in client logic + * exception + * @throws DataTypeNotSupportedException the data type not supported + * exception + * @throws PseudoHostException the pseudo host exception + * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onInitSuccess() + */ + @Override + public void onInitSuccess() throws ConfigurationException, ClientNotReadyException, + NoServicesInClientLogicException, DataTypeNotSupportedException, PseudoHostException { + this.clientCommInterface.init(); + logger.info("Client [{}] Initialized.", this.name); + } + + /** + * + * + * @throws ClientNotReadyException the client not ready exception + * @throws PseudoHostException the pseudo host exception + * @throws IOException Signals that an I/O exception has occurred. + * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onStartSuccess() + */ + @Override + public void onStartSuccess() throws ClientNotReadyException, PseudoHostException, IOException { + this.clientCommInterface.start(); + logger.info("Client [{}] started. The runtime Id is [{}].", this.name, this.getRuntimeId()); + this.runRd(); + this.runPrometheusMeasures(); + + if (this.showShell) { + try { + this.startShell(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + } + + /** + * + * + * @throws ClientNotReadyException the client not ready exception + * @see at.ac.ait.lablink.core.client.ILlClientFsmLogic#onShutdownSuccess() + */ + @Override + public void onShutdownSuccess() throws ClientNotReadyException { + this.clientCommInterface.shutdown(); + logger.info("Client [{}] shutdown.", this.name); + } + + /** + * + * + * @return the implemented services + * @see at.ac.ait.lablink.core.client.ci.ILlClientCommInterface#getImplementedServices() + */ + @Override + public Map getImplementedServices() { + return this.clientCommInterface.getImplementedServices(); + } + + /** + * Gets the service description. + * + * @param service the service + * @return the service description + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + public String getServiceDescription(String service) throws ServiceIsNotRegisteredWithClientException { + + if (!this.isServiceExists(service)) { + throw new ServiceIsNotRegisteredWithClientException(); + } + + return clientCommInterface.getImplementedServices().get(service).getName(); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + @SuppressWarnings("unchecked") + public boolean setServiceValue(String service, double val) throws ServiceIsNotRegisteredWithClientException { + + if (!this.isServiceExists(service)) { + throw new ServiceIsNotRegisteredWithClientException(); + } + + return clientCommInterface.getImplementedServices().get(service).setValue(Double.valueOf(val)); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + @SuppressWarnings("unchecked") + public boolean setServiceValue(String service, long val) throws ServiceIsNotRegisteredWithClientException { + + if (!this.isServiceExists(service)) { + throw new ServiceIsNotRegisteredWithClientException(); + } + + return clientCommInterface.getImplementedServices().get(service).setValue(Long.valueOf(val)); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + @SuppressWarnings("unchecked") + public boolean setServiceValue(String service, boolean val) throws ServiceIsNotRegisteredWithClientException { + + if (!this.isServiceExists(service)) { + throw new ServiceIsNotRegisteredWithClientException(); + } + + return clientCommInterface.getImplementedServices().get(service).setValue(Boolean.valueOf(val)); + } + + /** + * Sets the service value. + * + * @param servicename the servicename + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + @SuppressWarnings("unchecked") + public boolean setServiceValue(String servicename, String val) throws ServiceIsNotRegisteredWithClientException { + + if (!this.isServiceExists(servicename)) { + throw new ServiceIsNotRegisteredWithClientException(); + } + + // return clientCommInterface.getImplementedServices().get(servicename) + // .setValue(new String(val)); + return clientCommInterface.getImplementedServices().get(servicename).setValue(val); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + public boolean setServiceValue(LlService service, double val) throws ServiceIsNotRegisteredWithClientException { + return setServiceValue(service.getName(), val); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + public boolean setServiceValue(LlServicePseudo service, double val) + throws ServiceIsNotRegisteredWithClientException { + return setServiceValue(service.getName(), val); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + public boolean setServiceValue(LlService service, long val) throws ServiceIsNotRegisteredWithClientException { + return setServiceValue(service.getName(), val); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + public boolean setServiceValue(LlServicePseudo service, long val) throws ServiceIsNotRegisteredWithClientException { + return setServiceValue(service.getName(), val); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + public boolean setServiceValue(LlService service, String val) throws ServiceIsNotRegisteredWithClientException { + return setServiceValue(service.getName(), val); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + public boolean setServiceValue(LlServicePseudo service, String val) + throws ServiceIsNotRegisteredWithClientException { + return setServiceValue(service.getName(), val); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + public boolean setServiceValue(LlService service, boolean val) throws ServiceIsNotRegisteredWithClientException { + return setServiceValue(service.getName(), val); + } + + /** + * Sets the service value. + * + * @param service the service + * @param val the val + * @return true, if successful + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + public boolean setServiceValue(LlServicePseudo service, boolean val) + throws ServiceIsNotRegisteredWithClientException { + return setServiceValue(service.getName(), val); + } + + /** + * Checks if is service exists. + * + * @param sname the sname + * @return true, if is service exists + */ + public boolean isServiceExists(String sname) { + return this.isPseudoClient() ? (this.getPseudoServices().get(sname) != null) + : (this.getServices().get(sname) != null); + } + + /** + * Gets the service value double. + * + * @param service the service + * @return the service value double + * @throws InvalidCastForServiceValueException the invalid cast for service + * value exception + */ + public Double getServiceValueDouble(String service) throws InvalidCastForServiceValueException { + Double curval = null; + + try { + curval = (Double) clientCommInterface.getImplementedServices().get(service).getValue(); + } catch (Exception ex) { + logger.error(ex.getMessage()); + throw new InvalidCastForServiceValueException(); + } + + return curval; + } + + /** + * Gets the service value double. + * + * @param service the service + * @return the service value double + * @throws InvalidCastForServiceValueException the invalid cast for service + * value exception + */ + public Double getServiceValueDouble(LlService service) throws InvalidCastForServiceValueException { + return getServiceValueDouble(service.getName()); + } + + /** + * Gets the service value long. + * + * @param service the service + * @return the service value long + * @throws InvalidCastForServiceValueException the invalid cast for service + * value exception + */ + public Long getServiceValueLong(LlService service) throws InvalidCastForServiceValueException { + return getServiceValueLong(service.getName()); + } + + /** + * Gets the service value long. + * + * @param service the service + * @return the service value long + * @throws InvalidCastForServiceValueException the invalid cast for service + * value exception + */ + public Long getServiceValueLong(String service) throws InvalidCastForServiceValueException { + Long curval = null; + + try { + curval = (Long) clientCommInterface.getImplementedServices().get(service).getValue(); + } catch (Exception ex) { + logger.error(ex.getMessage()); + throw new InvalidCastForServiceValueException(); + } + + return curval; + + } + + /** + * Gets the service value boolean. + * + * @param service the service + * @return the service value boolean + * @throws InvalidCastForServiceValueException the invalid cast for service + * value exception + */ + public Boolean getServiceValueBoolean(LlService service) throws InvalidCastForServiceValueException { + + return getServiceValueBoolean(service.getName()); + } + + /** + * Gets the service value boolean. + * + * @param service the service + * @return the service value boolean + * @throws InvalidCastForServiceValueException the invalid cast for service + * value exception + */ + public Boolean getServiceValueBoolean(String service) throws InvalidCastForServiceValueException { + Boolean curval = null; + + try { + curval = (Boolean) clientCommInterface.getImplementedServices().get(service).getValue(); + } catch (Exception ex) { + logger.error(ex.getMessage()); + throw new InvalidCastForServiceValueException(); + } + + return curval; + + } + + /** + * Gets the service value string. + * + * @param service the service + * @return the service value string + * @throws InvalidCastForServiceValueException the invalid cast for service + * value exception + */ + public String getServiceValueString(LlService service) throws InvalidCastForServiceValueException { + return getServiceValueString(service.getName()); + } + + /** + * Gets the service value string. + * + * @param service the service + * @return the service value string + */ + public String getServiceValueString(String service) { + return clientCommInterface.getImplementedServices().get(service).getValue().toString(); + } + + /** + * Gets the service string value. + * + * @param service the service + * @return the service string value + */ + public Optional getServiceStringValue(String service) { + return Optional.ofNullable(clientCommInterface.getImplementedServices().get(service).getValue().toString()); + } + + /** + * Gets the service value. + * + * @param service the service + * @return the service value + * @throws InvalidCastForServiceValueException the invalid cast for service + * value exception + */ + public ByteBuffer getServiceValue(LlService service) throws InvalidCastForServiceValueException { + + ByteBuffer bb = null; + + ELlServiceDataTypes stype = service.getServiceDataType(); + String sname = service.getName(); + + if (stype == null) { + throw new InvalidCastForServiceValueException(); + } + + switch (stype) { + case SERVICE_DATATYPE_DOUBLE: + bb = ByteBuffer.allocate(Double.SIZE); + bb.putDouble(getServiceValueDouble(sname)); + bb.rewind(); + break; + case SERVICE_DATATYPE_LONG: + bb = ByteBuffer.allocate(Long.SIZE); + bb.putLong(getServiceValueLong(sname)); + bb.rewind(); + break; + case SERVICE_DATATYPE_STRING: + String sval = getServiceValueString(sname); + ByteBuffer.allocate(sval.length()); + bb.put(sval.getBytes()); + bb.rewind(); + break; + case SERVICE_DATATYPE_BOOLEAN: + short bval = (short) (getServiceValueBoolean(sname).booleanValue() ? 1 : 0); + bb.putShort(bval); + bb.rewind(); + break; + default: + logger.error("Data type not supported [{}].", stype); + throw new InvalidCastForServiceValueException(); + } + + return bb.asReadOnlyBuffer(); + } + + /** + * Gets the service value as a String. The function will determine the service + * data type automatically. + * + * @param service the service + * @return the service value auto + */ + public String getServiceValueAuto(LlService service) { + + return service.getCurState().toString(); + } + + /** + * Gets the service value auto. + * + * @param service the service + * @return the service value auto + * @throws ServiceIsNotRegisteredWithClientException the service is not + * registered with client + * exception + */ + public String getServiceValueAuto(String service) throws ServiceIsNotRegisteredWithClientException { + + if (!this.isServiceExists(service)) { + throw new ServiceIsNotRegisteredWithClientException(); + } + + return this.getServices().get(service).getCurState().toString(); + + } + + /** + * Gets the runtime id. + * + * @return the runtime id + */ + public long getRuntimeId() { + return this.id; + } + + /** + * Checks if this is a pseudo client. + * + * @return the pseudoClient + */ + @Override + public boolean isPseudoClient() { + return pseudoClient; + } + + /** + * Gets the pseudo services. + * + * @return the pseudo services + * @see at.ac.ait.lablink.core.client.ILlClientLogic#getPseudoServices() + */ + @Override + public Map getPseudoServices() { + return this.pseudoServices; + } + + /** + * Sets the client logic. + * + * @param clogic the new client logic + */ + @Override + public void setClientLogic(ILlClientLogic clogic) { + return; + } + + /** + * Gets the host implementation SP. + * + * @return the host implementation SP + */ + @Override + public String getHostImplementationSp() { + return this.hostImplementation; + } + + /** + * Adds the shutdown hook. + * + * @param hook the hook + */ + public void addShutdownHook(Thread hook) { + Runtime.getRuntime().addShutdownHook(hook); + } + + /** + * Sets the flag to run promethus measures. + */ + private void setRunPromethusMeasures() { + this.services.forEach((k, v) -> { + if (v.isExposedToPrometheus()) { + this.runPrometheusServer = true; + } + }); + } + + /** + * Start prometheus measures. + * + * @throws IOException Signals that an I/O exception has occurred. + */ + private void startPrometheusMeasures() throws IOException { + this.prometheusMeasuresServer = new HTTPServer.Builder().withPort(this.prometheusMeasuresPort).build(); + logger.info("Prometheus measures are now availabe for scraping."); + } + + /** + * Run prometheus measures. + * + * @throws IOException Signals that an I/O exception has occurred. + */ + private void runPrometheusMeasures() throws IOException { + this.setRunPromethusMeasures(); + if (this.runPrometheusServer) { + DefaultExports.initialize(); + logger.info("Attempting to start Prometheus measures on port {}", this.prometheusMeasuresPort); + this.startPrometheusMeasures(); + } else { + logger.info( + "No service is configured to be exposed for Prometheus. Server will not run and, therefore, no measures will be exposed."); + } + } +} diff --git a/src/main/java/at/ac/ait/lablink/core/connection/mqtt/impl/MqttClientSync.java b/src/main/java/at/ac/ait/lablink/core/connection/mqtt/impl/MqttClientSync.java index ecbc6f7..5acf8a6 100644 --- a/src/main/java/at/ac/ait/lablink/core/connection/mqtt/impl/MqttClientSync.java +++ b/src/main/java/at/ac/ait/lablink/core/connection/mqtt/impl/MqttClientSync.java @@ -5,863 +5,877 @@ package at.ac.ait.lablink.core.connection.mqtt.impl; -import at.ac.ait.lablink.core.connection.IConnectionHandler; -import at.ac.ait.lablink.core.connection.ex.LowLevelCommRuntimeException; -import at.ac.ait.lablink.core.connection.mqtt.IMqttConnectionListener; -import at.ac.ait.lablink.core.connection.mqtt.IMqttPublisher; -import at.ac.ait.lablink.core.connection.mqtt.IMqttReceiverCallback; -import at.ac.ait.lablink.core.connection.mqtt.IMqttSubscriber; -import at.ac.ait.lablink.core.connection.mqtt.impl.MqttUtils; -import at.ac.ait.lablink.core.ex.LlCoreRuntimeException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import org.apache.commons.configuration.BaseConfiguration; import org.apache.commons.configuration.Configuration; - import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; +import at.ac.ait.lablink.core.connection.IConnectionHandler; +import at.ac.ait.lablink.core.connection.ex.LowLevelCommRuntimeException; +import at.ac.ait.lablink.core.connection.mqtt.IMqttConnectionListener; +import at.ac.ait.lablink.core.connection.mqtt.IMqttPublisher; +import at.ac.ait.lablink.core.connection.mqtt.IMqttReceiverCallback; +import at.ac.ait.lablink.core.connection.mqtt.IMqttSubscriber; +import at.ac.ait.lablink.core.ex.LlCoreRuntimeException; /** * Implementation of the low level MQTT client. * - *

The low level MQTT client works as a wrapper interface to the MQTT client library. It - * extends the library with additional functionality like an automatic re-establishment of a lost - * connection to the broker or the possibility to register different listeners, which are informed - * by the client if the connection state changes. + *

+ * The low level MQTT client works as a wrapper interface to the MQTT client + * library. It extends the library with additional functionality like an + * automatic re-establishment of a lost connection to the broker or the + * possibility to register different listeners, which are informed by the client + * if the connection state changes. * - *

This MQTT client uses a synchronous communication with the MQTT core (sending methods). - * Therefore, every method call of the core library will be block until it's finished. This client - * can be used for simple use cases, where the reaction time of a method call isn't very important. + *

+ * This MQTT client uses a synchronous communication with the MQTT core (sending + * methods). Therefore, every method call of the core library will be block + * until it's finished. This client can be used for simple use cases, where the + * reaction time of a method call isn't very important. * *

Functionality of the low Level client

* - *

LowLevel client properties
- * The lowLevel client should have the ability to reconnect to the broker, if it lost its - * connection. Therefore a reconnection time period is necessary, where it tries to reconnect to - * a broker. The client tries to reconnect to the broker for certain times or for infinite. The - * reconnection functionality should be optionally be disabled by the settings. + *

+ * LowLevel client properties
+ * The lowLevel client should have the ability to reconnect to the broker, if it + * lost its connection. Therefore a reconnection time period is necessary, where + * it tries to reconnect to a broker. The client tries to reconnect to the + * broker for certain times or for infinite. The reconnection functionality + * should be optionally be disabled by the settings. * - *

The client needs some address parameters for the connection to the broker. These parameters - * should be used as properties in a configuration file. + *

+ * The client needs some address parameters for the connection to the broker. + * These parameters should be used as properties in a configuration file. * - *

The first implementation won't be able to change the properties during runtime. For future - * improvements the change of the properties should be handled dynamically during runtime. - * Therefore parameters concerning the connection settings (e.g., broker address), should only be - * handled during a disconnected period. + *

+ * The first implementation won't be able to change the properties during + * runtime. For future improvements the change of the properties should be + * handled dynamically during runtime. Therefore parameters concerning the + * connection settings (e.g., broker address), should only be handled during a + * disconnected period. * * - *

Initialization (Object creation)
- * After initialization the client isn't connected to the MQTT broker. The system isn't - * allowed to automatically reconnect to the broker. In this state it isn't possible to subscribe - * or publish a topic. It should be possible to add the MqttConnectionListeners or the - * MqttReceiver callback. + *

+ * Initialization (Object creation)
+ * After initialization the client isn't connected to the MQTT broker. The + * system isn't allowed to automatically reconnect to the broker. In this state + * it isn't possible to subscribe or publish a topic. It should be possible to + * add the MqttConnectionListeners or the MqttReceiver callback. * * - *

Registering a callback method
- * Some callback methods (IMqttReceiverCallback or IMqttConnectionListener) could be registered - * to the lowLevel client. The registrations could be dynamically added or removed from the - * client. The client will inform the callback methods during its operation. If no callback is - * registered to the client, the client will work in a correct way and it will drop all received + *

+ * Registering a callback method
+ * Some callback methods (IMqttReceiverCallback or IMqttConnectionListener) + * could be registered to the lowLevel client. The registrations could be + * dynamically added or removed from the client. The client will inform the + * callback methods during its operation. If no callback is registered to the + * client, the client will work in a correct way and it will drop all received * messages. * * - *

Connecting to the MQTT broker
- * After the initialization of the client it is possible to connect the client to a broker. - * Therefore the connect method is called. After a successful connection establishment the client - * will inform all MqttConnectionListeners by calling the - * onEstablishedMqttConnection() method. If the connection to the broker can't be - * established the client will inform the caller with an LowLevelCommRuntimeException - * and the reconnection will be activated. + *

+ * Connecting to the MQTT broker
+ * After the initialization of the client it is possible to connect the client + * to a broker. Therefore the connect method is called. After a successful + * connection establishment the client will inform all MqttConnectionListeners + * by calling the onEstablishedMqttConnection() method. If the + * connection to the broker can't be established the client will inform the + * caller with an LowLevelCommRuntimeException and the reconnection + * will be activated. * * - *

Operation Mode (connection established)
- * During the established connection it is possible to subscribe and publish messages or - * receive messages from the broker. + *

+ * Operation Mode (connection established)
+ * During the established connection it is possible to subscribe and publish + * messages or receive messages from the broker. * * - *

Receiving a MQTT message
- * If a message is received by the MQTT client it will redirect the incoming message to the - * registered MqttCallbackReceiver + *

+ * Receiving a MQTT message
+ * If a message is received by the MQTT client it will redirect the incoming + * message to the registered MqttCallbackReceiver * * - *

Disconnecting the MQTT client
- * By calling the disconnect method the client will perform the disconnection procedure. - * Therefore it will call the onDisconnectingMqttConnection of all registered - * MqttConnectionListeners and then it will disconnect from the Mqtt broker. - * If the disconnection fails a LowLevelCommRuntimeException will be thrown. + *

+ * Disconnecting the MQTT client
+ * By calling the disconnect method the client will perform the disconnection + * procedure. Therefore it will call the + * onDisconnectingMqttConnection of all registered + * MqttConnectionListeners and then it will disconnect from the Mqtt broker. If + * the disconnection fails a LowLevelCommRuntimeException will be + * thrown. * - *

The manual called disconnect method disables an automatic reconnection. + *

+ * The manual called disconnect method disables an automatic reconnection. * * - *

Lost the connection to the MQTT broker
- * If the client lost the connection to the broker (e.g., network errors, broker crashes) the - * MQTT lib will call the lost connection handler. This call will be redirected to all registered - * MqttConnectionListeners by calling the method onLostMqttConnection(). The client - * will trigger the automatic reconnection sequence (if enabled) and tries to reconnect to the - * MQTT broker. + *

+ * Lost the connection to the MQTT broker
+ * If the client lost the connection to the broker (e.g., network errors, broker + * crashes) the MQTT lib will call the lost connection handler. This call will + * be redirected to all registered MqttConnectionListeners by calling the method + * onLostMqttConnection(). The client will trigger the automatic + * reconnection sequence (if enabled) and tries to reconnect to the MQTT broker. * - *

During the disconnected state the client throws an exception if the publish or subscribe - * methods are called. + *

+ * During the disconnected state the client throws an exception if the publish + * or subscribe methods are called. */ @SuppressWarnings("FieldCanBeLocal") -public class MqttClientSync - implements MqttCallback, IMqttPublisher, IConnectionHandler, IMqttSubscriber { - - private static final Logger logger = LoggerFactory.getLogger(MqttClientSync.class); - - // Preset properties of the class - - /* Quality of service for published messages */ - @SuppressWarnings("FieldCanBeLocal") private final int qualityOfService = 0; - - /* Default settings of the class */ - - private final String defaultBrokerAddress = "localhost"; - private final int defaultBrokerPort = 1883; - private final String defaultConnectionProtocol = "tcp"; - private final boolean defaultEnableReconnection = true; - private final int defaultReconnectInterval = 10; - private final int defaultReconnectNumberOfTries = -1; - private final int defaultReceivedMessagesQueueSize = 2048; - - private int mqttConnectionTimeout = MqttConnectOptions.CONNECTION_TIMEOUT_DEFAULT; - - /* Client ID for MQTT communication (Not the clientId of the LablinkClient) */ - private final String clientId; - - /* - * current address string of the broker. - * The broker address uses the representation of the MQTT - * library ({@link MqttClient}), e.g., "tcp://localhost:1883". - */ - private final String brokerAddress; - - /* Mqtt synchronous client for publishing and receiving MQTT messages */ - private MqttClient mqttClient = null; - - /* Registered component to handle received messages */ - private IMqttReceiverCallback receiveCallback; - - private final Object receiveCallbackSyncMonitor = new Object(); - - /* Registered connection listeners that should be informed about a state change. */ - private final List - connectionListeners = - new ArrayList(); - - private final Object connectionListenersSyncMonitor = new Object(); - - /* Current state of the client for reconnection handling */ - private ELlClientState currentClientState = ELlClientState.DISCONNECTED_FROM_BROKER; - - - /* Own timer thread which handles the reconnection functionality */ - private final ReconnectionThread reconnectionThread; - - /* Worker thread for handling received messages */ - private final ReceivedMessageConsumer receivedMessageConsumerThread; - - private final Object publishMonitor = new Object(); - - - /** - * Constructor with optional configuration object - * - *

The MqttClientSync can be configured with a Configuration object. This object - * can be memory based or it can be loaded from a resources/properties file. The configuration - * will only be updated or taken during the creation of the client.
- * The following list shows the current implemented configuration properties withs their default - * values (between brackets): - *

    - *
  • lowLevelComm.enableReconnection (true, boolean): Switch for enabling the - * automatic reconnection, if the connection to the MQTT broker is lost.
  • - *
  • lowLevelComm.reconnectInterval (10, int): Time interval between two - * reconnection tries in Seconds.
  • - *
  • lowLevelComm.reconnectNumberOfTries (-1, int): Maximum number of reconnection - * tries. After this number of tries the client will switch to the disconnecting state. With - * -1 the reconnection will be try forever (infinite)
  • - *
  • lowLevelComm.brokerAddress ("localhost", string): Address of the MQTT broker to - * be connected.
  • - *
  • lowLevelComm.brokerPort (1883, int): Port of the MQTT broker to be connected.
  • - *
  • lowLevelComm.connectionProtocol ("tcp", string): Communication Protocol for the - * MQTT broker. Usually tcp or ssl
  • - *
  • lowLevelComm.mqttConnectionTimeout (30, int): Mqtt Connection Timeout in - * seconds
  • - *
  • lowLevelComm.receivedMessagesQueueSize (100, int): Queue Size for incoming - * (received) messages. Incoming messages will be buffered in a queue and decoupled from the - * incoming Mqtt thread.
  • - *
- * TODO add config parameters for SSL connection in the future - * - * @param mqttClientId MQTT client identifier (not the LablinkClient identifier) - * For identification of the client within the broker. - * @param config Configuration object that is used to parametrize the MQTT client. - * Different parameters can be set. If no parameter is set, the client - * will use the default settings. - */ - public MqttClientSync(String mqttClientId, Configuration config) { - - if (config == null) { - logger.info("No configuration is set for low-level MQTT client. Use default configuration."); - config = new BaseConfiguration(); /* Initialize empty configuration */ - } - - logger.info("Initialize low-level MQTT client '{}'.", mqttClientId); - this.clientId = mqttClientId; - - // Read configuration for MQTT broker address - String brokerAddress = config.getString("lowLevelComm.brokerAddress", defaultBrokerAddress); - int brokerPort = config.getInt("lowLevelComm.brokerPort", defaultBrokerPort); - String - connectionProtocol = - config.getString("lowLevelComm.connectionProtocol", defaultConnectionProtocol); - - this.brokerAddress = createMqttBrokerAddress(brokerAddress, brokerPort, connectionProtocol); - logger.info("BrokerAddress: {}", this.brokerAddress); - - this.mqttConnectionTimeout = - config.getInt("lowLevelComm.mqttConnectionTimeout", - MqttConnectOptions.CONNECTION_TIMEOUT_DEFAULT); - logger.info("Connection Timeout: {}", this.mqttConnectionTimeout + "s"); - - // Read configuration for Reconnection handling - reconnectionThread = new ReconnectionThread(this); - - this.reconnectionThread.setEnableReconnection( - config.getBoolean("lowLevelComm.enableReconnection", defaultEnableReconnection)); - this.reconnectionThread.setReconnectionInterval( - config.getInt("lowLevelComm.reconnectInterval", defaultReconnectInterval) * 1000); - this.reconnectionThread.setReconnectionTries( - config.getInt("lowLevelComm.reconnectNumberOfTries", defaultReconnectNumberOfTries)); - - logger.info("Reconnection Settings: Enabled: {} Interval: {}ms NoOfTries: {}", - reconnectionThread.isEnableReconnection(), reconnectionThread.getReconnectionInterval(), - reconnectionThread.getReconnectNumberOfTries()); - - reconnectionThread.start(); - - // Activate worker for receiving messages - int - queueSize = - config.getInt("lowLevelComm.receivedMessagesQueueSize", defaultReceivedMessagesQueueSize); - receivedMessageConsumerThread = new ReceivedMessageConsumer(queueSize, this.clientId); - logger.info("ReceivedMessageConsumer: Queue Size: {}", queueSize); - receivedMessageConsumerThread.start(); - } - - @Override - public String toString() { - return "MqttClientSync(" + clientId + ", " + brokerAddress + ')'; - } - - /** - * Create the Address String for the MQTT broker. - * - *

The method generated the address string for the MQTT broker without a validation of the - * input parameters. - * - * @param brokerAddress Address of the broker (e.g., "localhost") - * @param brokerPort Port of the broker (e.g., 1883) - * @param connectionProtocol protocol of the connection (e.g., "tcp" or "ssh") - * @return generated address string for the MQTT broker - */ - private String createMqttBrokerAddress(String brokerAddress, int brokerPort, - String connectionProtocol) { - return String.format("%s://%s:%d", connectionProtocol, brokerAddress, brokerPort); - } - - /** - * Factory method for creating the Mqtt client. - * Can be mocked for unit tests. - * - * @param brokerAddress Address of the broker - * @param clientId ID of the client - * @return the created MqttClient - * @throws MqttException will be thrown by the Mqtt client creation - */ - private static MqttClient createMqttClient(String brokerAddress, String clientId) - throws MqttException { - return new MqttClient(brokerAddress, clientId, null); - } - - /** - * Get the actual lowLevelMqttReceiver which contains the callback handler for received messages. - * - * @return actual used lowLevelMqttReceiver - */ - public IMqttReceiverCallback getReceiveCallback() { - return receiveCallback; - } - - /** - * Set the IMqttReceiverCallback which contains the callback handler for received messages. - * - * @param receiveCallback IMqttReceiverCallback to be set - */ - public void setReceiveCallback(IMqttReceiverCallback receiveCallback) { - if (receiveCallback == null) { - throw new LlCoreRuntimeException("Set ReceiveCallback failed: Parameter is a null."); - } - - logger.debug("Set new ReceiveCallback: {}", receiveCallback); - synchronized (this.receiveCallbackSyncMonitor) { - this.receiveCallback = receiveCallback; - this.receivedMessageConsumerThread.setReceiveCallback(this.receiveCallback); - } - } - - - /** - * Add a IMqttConnectionListener to the client. This connection listener will be informed by the - * the client, if an event regarding the connection will occur. - * - * @param listener IMqttConnectionListener to be added - */ - public void addMqttConnectionListener(IMqttConnectionListener listener) { - - if (listener == null) { - throw new LlCoreRuntimeException("Add ConnectionListener failed: Parameter is a null."); - } - - if (!this.connectionListeners.contains(listener)) { - logger.debug("Add connection listener: {}", listener.toString()); - - synchronized (this.connectionListenersSyncMonitor) { - this.connectionListeners.add(listener); - } - } - } - - /** - * Remove a connectionListener from the client. - * - * @param listener IMqttConnectionListener to be removed - */ - public void removeConnectionListener(IMqttConnectionListener listener) { - logger.trace("Remove connection listener: {}", listener.toString()); - synchronized (this.connectionListenersSyncMonitor) { - this.connectionListeners.remove(listener); - } - } - - /** - * Read the registered connection listeners (for testing purposes) - * - * @return the connection listeners. - */ - List getConnectionListeners() { - return connectionListeners; - } - - /** - * Read the clientId of the broker. - * - * @return the clientId of the broker. - */ - public String getClientId() { - return clientId; - } - - /** - * Read the broker address that the client uses. - * The broker address uses the representation of the MQTT library ({@link MqttClient}), - * e.g., "tcp://localhost:1883". - * - * @return broker address of the client. - */ - public String getBrokerAddress() { - return brokerAddress; - } - - /** - * Set the actual state of the client (thread safe) and trigger the reconnection timer. - * - * @param currentClientState set the current state - */ - private synchronized void setCurrentClientStateAndTriggerReconnect( - ELlClientState currentClientState) { - - this.currentClientState = currentClientState; - - synchronized (this.reconnectionThread) { - this.reconnectionThread.notify(); - } - } - - ELlClientState getCurrentClientState() { - return currentClientState; - } - - /** - * Shutdown the MQTT lowLevel client. - * - *

This method will be used for cleanup purposes. It should be called before the program's end. - * It will disconnect from the broker and clean up its states. - */ - public void shutdown() { - if (isConnected()) { - try { - disconnect(); - } catch (LowLevelCommRuntimeException ex) { - logger.warn("Error while disconnecting from broker during shutdown."); - } - } - - this.reconnectionThread.shutdown(); - this.receivedMessageConsumerThread.shutdown(); - } - - @Override - public void connect() { - - // Create MQTT client if it doesn't exist. - if (this.mqttClient == null) { - try { - this.mqttClient = MqttClientSync.createMqttClient(this.brokerAddress, this.clientId); - } catch (MqttException ex) { - throw new LowLevelCommRuntimeException(ex); - } - } - - // Ignore connect method if the client is already connected - if (isConnected()) { - return; - } - - // Connect to broker - MqttConnectOptions mqttOpt = new MqttConnectOptions(); - mqttOpt.setCleanSession(true); - mqttOpt.setConnectionTimeout(mqttConnectionTimeout); - this.mqttClient.setCallback(this); - - try { - this.mqttClient.connect(mqttOpt); - this.setCurrentClientStateAndTriggerReconnect(ELlClientState.CONNECTED_TO_BROKER); - - synchronized (this.connectionListenersSyncMonitor) { - for (IMqttConnectionListener listener : this.connectionListeners) { - listener.onEstablishedMqttConnection(); - } - } - } catch (MqttException ex) { - this.setCurrentClientStateAndTriggerReconnect(ELlClientState.TRY_TO_RECONNECT); - throw new LowLevelCommRuntimeException(ex); - } - logger.info("MqttClient connected to broker {}", mqttClient.getServerURI()); - - } - - @Override - public void disconnect() { - this.setCurrentClientStateAndTriggerReconnect(ELlClientState.DISCONNECTED_FROM_BROKER); - if (isConnected()) { - - synchronized (this.connectionListenersSyncMonitor) { - for (IMqttConnectionListener listener : this.connectionListeners) { - listener.onDisconnectingMqttConnection(); - } - } - - try { - this.mqttClient.disconnect(); - logger.info("MqttClient disconnected from broker {}", mqttClient.getServerURI()); - } catch (MqttException ex) { - throw new LowLevelCommRuntimeException(ex); - } - } - } - - @Override - public boolean isConnected() { - return this.mqttClient != null && this.mqttClient.isConnected(); - } - - @Override - public void publish(String mqttTopic, byte[] mqttPayload) { - if (!this.isConnected()) { - throw new LowLevelCommRuntimeException("MqttClientSync isn't connected to a broker"); - } - - MqttUtils.validateMqttTopic(mqttTopic); - - MqttMessage mqttMsg = new MqttMessage(mqttPayload); - mqttMsg.setQos(this.qualityOfService); - - synchronized (this.publishMonitor) { - try { - this.mqttClient.publish(mqttTopic, mqttMsg); - } catch (MqttException ex) { - throw new LowLevelCommRuntimeException(ex); - } - } - } - - @Override - public void subscribe(String mqttTopic) { - if (!this.isConnected()) { - throw new LowLevelCommRuntimeException("MqttClientSync isn't connected to a broker"); - } - - try { - this.mqttClient.subscribe(mqttTopic); - } catch (MqttException ex) { - throw new LowLevelCommRuntimeException(ex); - } - - } - - @Override - public void subscribe(List mqttTopics) { - if (!this.isConnected()) { - throw new LowLevelCommRuntimeException("MqttClientSync isn't connected to a broker"); - } - - for (String mqttTopic : mqttTopics) { - MqttUtils.validateMqttSubscription(mqttTopic); - } - - try { - this.mqttClient.subscribe(mqttTopics.toArray(new String[0])); - } catch (MqttException ex) { - throw new LowLevelCommRuntimeException(ex); - } - } - - @Override - public void unsubscribe(String mqttTopic) { - - if (!this.isConnected()) { - throw new LowLevelCommRuntimeException("MqttClientSync isn't connected to a broker"); - } - try { - this.mqttClient.unsubscribe(mqttTopic); - } catch (MqttException ex) { - throw new LowLevelCommRuntimeException(ex); - } - - } - - @Override - public void unsubscribe(List mqttTopics) { - if (!this.isConnected()) { - throw new LowLevelCommRuntimeException("MqttClientSync isn't connected to a broker"); - } - - for (String mqttTopic : mqttTopics) { - MqttUtils.validateMqttSubscription(mqttTopic); - } - - try { - this.mqttClient.unsubscribe(mqttTopics.toArray(new String[0])); - } catch (MqttException ex) { - throw new LowLevelCommRuntimeException(ex); - } - } - - @Override - public void connectionLost(Throwable throwable) { - - logger.warn("MQTT connection lost: {}", throwable.toString()); - - synchronized (this.connectionListenersSyncMonitor) { - for (IMqttConnectionListener listener : this.connectionListeners) { - listener.onLostMqttConnection(); - } - } - - this.setCurrentClientStateAndTriggerReconnect(ELlClientState.TRY_TO_RECONNECT); - } - - @Override - public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception { - logger.trace("New MQTT message received: Topic({}) ReceivedMessage()", topic, - mqttMessage.toString()); - - synchronized (this.receiveCallbackSyncMonitor) { - if (this.receiveCallback != null && !mqttMessage.isDuplicate()) { - this.receivedMessageConsumerThread.addNewMessage(topic, mqttMessage.getPayload()); - } - } - } - - @Override - public void deliveryComplete(IMqttDeliveryToken mqttDeliveryToken) { - /* not used by the synchronous client */ - } - - /** - * Inner enumeration to identify the current state of the client. - * - */ - enum ELlClientState { - DISCONNECTED_FROM_BROKER, CONNECTED_TO_BROKER, TRY_TO_RECONNECT - } - - /** - * Thread for controlling the reconnection to the broker. - * - *

The client provides the functionality to automatically reconnect to a broker, if the - * connection can't be created or the connection was lost. - * - *

The reconnection thread will periodically call the connect method of the client and tries to - * reconnect from it. The state variable of the client controls the reconnection. If it is set - * by the client the reconnection thread will be notified and it will trigger the reconnection if - * it is necessary. - */ - private class ReconnectionThread extends Thread { - - private final MqttClientSync parent; - private boolean keepRunning = true; - - /* Config values for reconnection */ - private boolean enableReconnection; - private int reconnectionInterval; // in milliseconds - private int reconnectionTries; // -1 or positive number - - /* actual reconnection try counter */ - private int actualTry = 1; - - /** - * Default constructor. - * - * @param parent MqttClientSync where the reconnection should be handled - */ - ReconnectionThread(MqttClientSync parent) { - this.parent = parent; - this.setDaemon(true); - this.setName("ReconnectionThread: " + parent.getClientId()); - - enableReconnection = parent.defaultEnableReconnection; - reconnectionInterval = parent.defaultReconnectInterval; - reconnectionTries = parent.defaultReconnectNumberOfTries; - } - - /** - * Shutdown and cleanup procedure. - * - */ - synchronized void shutdown() { - this.keepRunning = false; - this.interrupt(); - } - - @Override - public void run() { - - logger.trace("Reconnection timer thread started (activated: {}, Interval: {}, Tries: {})", - enableReconnection, reconnectionInterval, reconnectionTries); - - while (this.keepRunning) { - - ELlClientState beginClientState = parent.getCurrentClientState(); - logger.trace("ReconnectionTimerThread activated: {}", currentClientState); - - ELlClientState currentClientState = beginClientState; - - if (!this.enableReconnection) { - if (currentClientState == ELlClientState.TRY_TO_RECONNECT) { - parent.setCurrentClientStateAndTriggerReconnect( - ELlClientState.DISCONNECTED_FROM_BROKER - ); - currentClientState = parent.getCurrentClientState(); - } - } - - if (currentClientState == ELlClientState.CONNECTED_TO_BROKER - || currentClientState == ELlClientState.DISCONNECTED_FROM_BROKER) { - actualTry = 1; - } - - if (this.enableReconnection && currentClientState == ELlClientState.TRY_TO_RECONNECT) { - handleReconnection(); - } - - try { - synchronized (this) { - if (beginClientState != parent.getCurrentClientState()) { - continue; - } - if (currentClientState == ELlClientState.TRY_TO_RECONNECT) { - this.wait(reconnectionInterval); - } else { - this.wait(); - } - } - } catch (InterruptedException ign) { - // This is expected - } - - } - } - - private void handleReconnection() { - - logger.trace("Reconnection try: {}", actualTry); - try { - parent.connect(); - } catch (LowLevelCommRuntimeException ex) { - logger.debug("Reconnection try ({}) was not successful.", actualTry); - } - - if (this.reconnectionTries != -1 && actualTry >= this.reconnectionTries) { - logger.warn("Maximum number of reconnection tries exceeds. Stop to reconnect"); - parent.setCurrentClientStateAndTriggerReconnect(ELlClientState.DISCONNECTED_FROM_BROKER); - actualTry = 1; - } else { - actualTry++; - } - } - - - void setEnableReconnection(boolean enableReconnection) { - this.enableReconnection = enableReconnection; - } - - void setReconnectionInterval(int reconnectionInterval) { - - if (reconnectionInterval > 0) { - this.reconnectionInterval = reconnectionInterval; - } else { - throw new IllegalArgumentException(String.format( - "False reconnection interval in milliseconds (%d) was " - + "set. The parameter should be greater than 0.", reconnectionInterval)); - } - } - - void setReconnectionTries(int reconnectionTries) { - - if (reconnectionTries == -1 || reconnectionTries > 0) { - this.reconnectionTries = reconnectionTries; - } else { - throw new IllegalArgumentException(String.format( - "False reconnection tries (%d) want to be set. The parameter should " - + "be -1 for infinite tries or greater than 0", reconnectionTries)); - } - } - - int getReconnectNumberOfTries() { - return this.reconnectionTries; - } - - int getReconnectionInterval() { - return reconnectionInterval; - } - - boolean isEnableReconnection() { - return enableReconnection; - } - } - - /** - * Worker thread to handle received messages. - * - *

This inner class is used to implement a blocking queue for the received messages. This is - * necessary to decouple the Mqtt receiving callback from the further message handling. - * Especially if the message callback publishes new messages this decoupling is necessary. - */ - private class ReceivedMessageConsumer extends Thread { - - /** - * Data Bean for received messages. - * - */ - class ReceivedMessage { - public String topic; - public byte[] payload; - } - - private boolean isRunning = true; - - private final BlockingQueue receivedMsgQueue; - - private IMqttReceiverCallback receiverCallback; - - private final Object syncMonitor = new Object(); - - /** - * Construct the receiving messages' handler. - * - * @param queueSize Size of the Queue for receiving messages - * @param clientId client ID - */ - ReceivedMessageConsumer(int queueSize, String clientId) { - this.setDaemon(true); - this.setName("ReceivedMessageConsumer: " + clientId); - receivedMsgQueue = new ArrayBlockingQueue(queueSize); - } - - /** - * Set the callback handler for handling receiving messages. - * - * @param receiveCallback handler to be set - */ - void setReceiveCallback(IMqttReceiverCallback receiveCallback) { - synchronized (this.syncMonitor) { - this.receiverCallback = receiveCallback; - } - } - - /** - * Add a new received message to the worker queue. - * - * @param topic of the received message - * @param payload of the received message - */ - void addNewMessage(String topic, byte[] payload) { - - ReceivedMessage msg = new ReceivedMessage(); - msg.topic = topic; - msg.payload = payload; - - try { - receivedMsgQueue.put(msg); - } catch (InterruptedException ex) { - // expected - } - } - - /** - * Shutdown the ReceivedMessageConsumer Thread. - * - */ - void shutdown() { - isRunning = false; - this.interrupt(); - } - - @Override - public void run() { - - while (isRunning) { - try { - ReceivedMessage msg = receivedMsgQueue.take(); - logger.trace( - "Process received message (Topic: {} IPayload: {}) No of waiting objects: {}", - msg.topic, new String(msg.payload), receivedMsgQueue.size() - ); - - synchronized (this.syncMonitor) { - if (this.receiverCallback == null) { - logger.warn("No ReceiverCallback is set in ReceivedMessageConsumerThread."); - continue; - } - this.receiverCallback.handleRawMqttMessage(msg.topic, msg.payload); - } - } catch (InterruptedException ignore) { - // ignore - } - } - } - } +public class MqttClientSync implements MqttCallback, IMqttPublisher, IConnectionHandler, IMqttSubscriber { + + private static final Logger logger = LoggerFactory.getLogger(MqttClientSync.class); + + // Preset properties of the class + + /* Quality of service for published messages */ + @SuppressWarnings("FieldCanBeLocal") + private final int qualityOfService = 0; + + /* Default settings of the class */ + + private final String defaultBrokerAddress = "localhost"; + private final int defaultBrokerPort = 1883; + private final String defaultConnectionProtocol = "tcp"; + private final boolean defaultEnableReconnection = true; + private final int defaultReconnectInterval = 10; + private final int defaultReconnectNumberOfTries = -1; + private final int defaultReceivedMessagesQueueSize = 2048; + + private int mqttConnectionTimeout = MqttConnectOptions.CONNECTION_TIMEOUT_DEFAULT; + + /* Client ID for MQTT communication (Not the clientId of the LablinkClient) */ + private final String clientId; + + /* + * current address string of the broker. The broker address uses the + * representation of the MQTT library ({@link MqttClient}), e.g., + * "tcp://localhost:1883". + */ + private final String brokerAddress; + + /* Mqtt synchronous client for publishing and receiving MQTT messages */ + private MqttClient mqttClient = null; + + /* Registered component to handle received messages */ + private IMqttReceiverCallback receiveCallback; + + private final Object receiveCallbackSyncMonitor = new Object(); + + /* + * Registered connection listeners that should be informed about a state change. + */ + private final List connectionListeners = new ArrayList(); + + private final Object connectionListenersSyncMonitor = new Object(); + + /* Current state of the client for reconnection handling */ + private ELlClientState currentClientState = ELlClientState.DISCONNECTED_FROM_BROKER; + + /* Own timer thread which handles the reconnection functionality */ + private final ReconnectionThread reconnectionThread; + + /* Worker thread for handling received messages */ + private final ReceivedMessageConsumer receivedMessageConsumerThread; + + private final Object publishMonitor = new Object(); + + /** + * Constructor with optional configuration object + * + *

+ * The MqttClientSync can be configured with a Configuration + * object. This object can be memory based or it can be loaded from a + * resources/properties file. The configuration will only be updated or taken + * during the creation of the client.
+ * The following list shows the current implemented configuration properties + * withs their default values (between brackets): + *

    + *
  • lowLevelComm.enableReconnection (true, boolean): Switch for + * enabling the automatic reconnection, if the connection to the MQTT broker is + * lost.
  • + *
  • lowLevelComm.reconnectInterval (10, int): Time interval between + * two reconnection tries in Seconds.
  • + *
  • lowLevelComm.reconnectNumberOfTries (-1, int): Maximum number of + * reconnection tries. After this number of tries the client will switch to the + * disconnecting state. With -1 the reconnection will be try forever + * (infinite)
  • + *
  • lowLevelComm.brokerAddress ("localhost", string): Address of the + * MQTT broker to be connected.
  • + *
  • lowLevelComm.brokerPort (1883, int): Port of the MQTT broker to be + * connected.
  • + *
  • lowLevelComm.connectionProtocol ("tcp", string): Communication + * Protocol for the MQTT broker. Usually tcp or ssl
  • + *
  • lowLevelComm.mqttConnectionTimeout (30, int): Mqtt Connection + * Timeout in seconds
  • + *
  • lowLevelComm.receivedMessagesQueueSize (100, int): Queue Size for + * incoming (received) messages. Incoming messages will be buffered in a queue + * and decoupled from the incoming Mqtt thread.
  • + *
+ * TODO add config parameters for SSL connection in the future + * + * @param mqttClientId MQTT client identifier (not the LablinkClient identifier) + * For identification of the client within the broker. + * @param config Configuration object that is used to parametrize the MQTT + * client. Different parameters can be set. If no parameter + * is set, the client will use the default settings. + */ + public MqttClientSync(String mqttClientId, Configuration config) { + + if (config == null) { + logger.info("No configuration is set for low-level MQTT client. Use default configuration."); + config = new BaseConfiguration(); /* Initialize empty configuration */ + } + + logger.info("Initialize low-level MQTT client '{}'.", mqttClientId); + this.clientId = mqttClientId; + + // Read configuration for MQTT broker address + String brokerAddress = config.getString("lowLevelComm.brokerAddress", defaultBrokerAddress); + int brokerPort = config.getInt("lowLevelComm.brokerPort", defaultBrokerPort); + String connectionProtocol = config.getString("lowLevelComm.connectionProtocol", defaultConnectionProtocol); + + this.brokerAddress = createMqttBrokerAddress(brokerAddress, brokerPort, connectionProtocol); + logger.info("BrokerAddress: {}", this.brokerAddress); + + this.mqttConnectionTimeout = config.getInt("lowLevelComm.mqttConnectionTimeout", + MqttConnectOptions.CONNECTION_TIMEOUT_DEFAULT); + logger.info("Connection Timeout: {}", this.mqttConnectionTimeout + "s"); + + // Read configuration for Reconnection handling + reconnectionThread = new ReconnectionThread(this); + + this.reconnectionThread + .setEnableReconnection(config.getBoolean("lowLevelComm.enableReconnection", defaultEnableReconnection)); + this.reconnectionThread.setReconnectionInterval( + config.getInt("lowLevelComm.reconnectInterval", defaultReconnectInterval) * 1000); + this.reconnectionThread.setReconnectionTries( + config.getInt("lowLevelComm.reconnectNumberOfTries", defaultReconnectNumberOfTries)); + + logger.info("Reconnection Settings: Enabled: {} Interval: {}ms NoOfTries: {}", + reconnectionThread.isEnableReconnection(), reconnectionThread.getReconnectionInterval(), + reconnectionThread.getReconnectNumberOfTries()); + + reconnectionThread.start(); + + // Activate worker for receiving messages + int queueSize = config.getInt("lowLevelComm.receivedMessagesQueueSize", defaultReceivedMessagesQueueSize); + receivedMessageConsumerThread = new ReceivedMessageConsumer(queueSize, this.clientId); + logger.info("ReceivedMessageConsumer: Queue Size: {}", queueSize); + receivedMessageConsumerThread.start(); + } + + @Override + public String toString() { + return "MqttClientSync(" + clientId + ", " + brokerAddress + ')'; + } + + /** + * Create the Address String for the MQTT broker. + * + *

+ * The method generated the address string for the MQTT broker without a + * validation of the input parameters. + * + * @param brokerAddress Address of the broker (e.g., "localhost") + * @param brokerPort Port of the broker (e.g., 1883) + * @param connectionProtocol protocol of the connection (e.g., "tcp" or "ssh") + * @return generated address string for the MQTT broker + */ + private String createMqttBrokerAddress(String brokerAddress, int brokerPort, String connectionProtocol) { + return String.format("%s://%s:%d", connectionProtocol, brokerAddress, brokerPort); + } + + /** + * Factory method for creating the Mqtt client. Can be mocked for unit tests. + * + * @param brokerAddress Address of the broker + * @param clientId ID of the client + * @return the created MqttClient + * @throws MqttException will be thrown by the Mqtt client creation + */ + private static MqttClient createMqttClient(String brokerAddress, String clientId) throws MqttException { + return new MqttClient(brokerAddress, clientId, null); + } + + /** + * Get the actual lowLevelMqttReceiver which contains the callback handler for + * received messages. + * + * @return actual used lowLevelMqttReceiver + */ + public IMqttReceiverCallback getReceiveCallback() { + return receiveCallback; + } + + /** + * Set the IMqttReceiverCallback which contains the callback handler for + * received messages. + * + * @param receiveCallback IMqttReceiverCallback to be set + */ + public void setReceiveCallback(IMqttReceiverCallback receiveCallback) { + if (receiveCallback == null) { + throw new LlCoreRuntimeException("Set ReceiveCallback failed: Parameter is a null."); + } + + logger.debug("Set new ReceiveCallback: {}", receiveCallback); + synchronized (this.receiveCallbackSyncMonitor) { + this.receiveCallback = receiveCallback; + this.receivedMessageConsumerThread.setReceiveCallback(this.receiveCallback); + } + } + + /** + * Add a IMqttConnectionListener to the client. This connection listener will be + * informed by the the client, if an event regarding the connection will occur. + * + * @param listener IMqttConnectionListener to be added + */ + public void addMqttConnectionListener(IMqttConnectionListener listener) { + + if (listener == null) { + throw new LlCoreRuntimeException("Add ConnectionListener failed: Parameter is a null."); + } + + if (!this.connectionListeners.contains(listener)) { + logger.debug("Add connection listener: {}", listener.toString()); + + synchronized (this.connectionListenersSyncMonitor) { + this.connectionListeners.add(listener); + } + } + } + + /** + * Remove a connectionListener from the client. + * + * @param listener IMqttConnectionListener to be removed + */ + public void removeConnectionListener(IMqttConnectionListener listener) { + logger.trace("Remove connection listener: {}", listener.toString()); + synchronized (this.connectionListenersSyncMonitor) { + this.connectionListeners.remove(listener); + } + } + + /** + * Read the registered connection listeners (for testing purposes) + * + * @return the connection listeners. + */ + List getConnectionListeners() { + return connectionListeners; + } + + /** + * Read the clientId of the broker. + * + * @return the clientId of the broker. + */ + public String getClientId() { + return clientId; + } + + /** + * Read the broker address that the client uses. The broker address uses the + * representation of the MQTT library ({@link MqttClient}), e.g., + * "tcp://localhost:1883". + * + * @return broker address of the client. + */ + public String getBrokerAddress() { + return brokerAddress; + } + + /** + * Set the actual state of the client (thread safe) and trigger the reconnection + * timer. + * + * @param currentClientState set the current state + */ + private synchronized void setCurrentClientStateAndTriggerReconnect(ELlClientState currentClientState) { + + this.currentClientState = currentClientState; + + synchronized (this.reconnectionThread) { + this.reconnectionThread.notify(); + } + } + + ELlClientState getCurrentClientState() { + return currentClientState; + } + + /** + * Shutdown the MQTT lowLevel client. + * + *

+ * This method will be used for cleanup purposes. It should be called before the + * program's end. It will disconnect from the broker and clean up its states. + */ + public void shutdown() { + if (isConnected()) { + try { + disconnect(); + } catch (LowLevelCommRuntimeException ex) { + logger.warn("Error while disconnecting from broker during shutdown."); + } + } + + this.reconnectionThread.shutdown(); + this.receivedMessageConsumerThread.shutdown(); + } + + @Override + public void connect() { + + // Create MQTT client if it doesn't exist. + if (this.mqttClient == null) { + try { + this.mqttClient = MqttClientSync.createMqttClient(this.brokerAddress, this.clientId); + } catch (MqttException ex) { + throw new LowLevelCommRuntimeException(ex); + } + } + + // Ignore connect method if the client is already connected + if (isConnected()) { + return; + } + + // Connect to broker + MqttConnectOptions mqttOpt = new MqttConnectOptions(); + mqttOpt.setCleanSession(true); + mqttOpt.setConnectionTimeout(mqttConnectionTimeout); + this.mqttClient.setCallback(this); + + try { + this.mqttClient.connect(mqttOpt); + this.setCurrentClientStateAndTriggerReconnect(ELlClientState.CONNECTED_TO_BROKER); + + synchronized (this.connectionListenersSyncMonitor) { + for (IMqttConnectionListener listener : this.connectionListeners) { + listener.onEstablishedMqttConnection(); + } + } + } catch (MqttException ex) { + this.setCurrentClientStateAndTriggerReconnect(ELlClientState.TRY_TO_RECONNECT); + throw new LowLevelCommRuntimeException(ex); + } + logger.info("MqttClient connected to broker {}", mqttClient.getServerURI()); + + } + + @Override + public void disconnect() { + this.setCurrentClientStateAndTriggerReconnect(ELlClientState.DISCONNECTED_FROM_BROKER); + if (isConnected()) { + + synchronized (this.connectionListenersSyncMonitor) { + for (IMqttConnectionListener listener : this.connectionListeners) { + listener.onDisconnectingMqttConnection(); + } + } + + try { + this.mqttClient.disconnect(); + logger.info("MqttClient disconnected from broker {}", mqttClient.getServerURI()); + } catch (MqttException ex) { + throw new LowLevelCommRuntimeException(ex); + } + } + } + + @Override + public boolean isConnected() { + return this.mqttClient != null && this.mqttClient.isConnected(); + } + + @Override + public void publish(String mqttTopic, byte[] mqttPayload) { + if (!this.isConnected()) { + throw new LowLevelCommRuntimeException("MqttClientSync isn't connected to a broker"); + } + + MqttUtils.validateMqttTopic(mqttTopic); + + MqttMessage mqttMsg = new MqttMessage(mqttPayload); + mqttMsg.setQos(this.qualityOfService); + + synchronized (this.publishMonitor) { + try { + this.mqttClient.publish(mqttTopic, mqttMsg); + } catch (MqttException ex) { + throw new LowLevelCommRuntimeException(ex); + } + } + } + + @Override + public void subscribe(String mqttTopic) { + if (!this.isConnected()) { + throw new LowLevelCommRuntimeException("MqttClientSync isn't connected to a broker"); + } + + try { + this.mqttClient.subscribe(mqttTopic); + } catch (MqttException ex) { + throw new LowLevelCommRuntimeException(ex); + } + + } + + @Override + public void subscribe(List mqttTopics) { + if (!this.isConnected()) { + throw new LowLevelCommRuntimeException("MqttClientSync isn't connected to a broker"); + } + + for (String mqttTopic : mqttTopics) { + MqttUtils.validateMqttSubscription(mqttTopic); + } + + try { + this.mqttClient.subscribe(mqttTopics.toArray(new String[0])); + } catch (MqttException ex) { + throw new LowLevelCommRuntimeException(ex); + } + } + + @Override + public void unsubscribe(String mqttTopic) { + + if (!this.isConnected()) { + throw new LowLevelCommRuntimeException("MqttClientSync isn't connected to a broker"); + } + try { + this.mqttClient.unsubscribe(mqttTopic); + } catch (MqttException ex) { + throw new LowLevelCommRuntimeException(ex); + } + + } + + @Override + public void unsubscribe(List mqttTopics) { + if (!this.isConnected()) { + throw new LowLevelCommRuntimeException("MqttClientSync isn't connected to a broker"); + } + + for (String mqttTopic : mqttTopics) { + MqttUtils.validateMqttSubscription(mqttTopic); + } + + try { + this.mqttClient.unsubscribe(mqttTopics.toArray(new String[0])); + } catch (MqttException ex) { + throw new LowLevelCommRuntimeException(ex); + } + } + + @Override + public void connectionLost(Throwable throwable) { + + logger.warn("MQTT connection lost: {}", throwable.toString()); + + synchronized (this.connectionListenersSyncMonitor) { + for (IMqttConnectionListener listener : this.connectionListeners) { + listener.onLostMqttConnection(); + } + } + + this.setCurrentClientStateAndTriggerReconnect(ELlClientState.TRY_TO_RECONNECT); + } + + @Override + public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception { + logger.trace("New MQTT message received: Topic({}) ReceivedMessage()", topic, mqttMessage.toString()); + + synchronized (this.receiveCallbackSyncMonitor) { + if (this.receiveCallback != null && !mqttMessage.isDuplicate()) { + this.receivedMessageConsumerThread.addNewMessage(topic, mqttMessage.getPayload()); + } + } + } + + @Override + public void deliveryComplete(IMqttDeliveryToken mqttDeliveryToken) { + /* not used by the synchronous client */ + } + + /** + * Inner enumeration to identify the current state of the client. + * + */ + enum ELlClientState { + DISCONNECTED_FROM_BROKER, CONNECTED_TO_BROKER, TRY_TO_RECONNECT + } + + /** + * Thread for controlling the reconnection to the broker. + * + *

+ * The client provides the functionality to automatically reconnect to a broker, + * if the connection can't be created or the connection was lost. + * + *

+ * The reconnection thread will periodically call the connect method of the + * client and tries to reconnect from it. The state variable of the client + * controls the reconnection. If it is set by the client the reconnection thread + * will be notified and it will trigger the reconnection if it is necessary. + */ + private class ReconnectionThread extends Thread { + + private final MqttClientSync parent; + private boolean keepRunning = true; + + /* Config values for reconnection */ + private boolean enableReconnection; + private int reconnectionInterval; // in milliseconds + private int reconnectionTries; // -1 or positive number + + /* actual reconnection try counter */ + private int actualTry = 1; + + /** + * Default constructor. + * + * @param parent MqttClientSync where the reconnection should be handled + */ + ReconnectionThread(MqttClientSync parent) { + this.parent = parent; + this.setDaemon(true); + this.setName("ReconnectionThread: " + parent.getClientId()); + + enableReconnection = parent.defaultEnableReconnection; + reconnectionInterval = parent.defaultReconnectInterval; + reconnectionTries = parent.defaultReconnectNumberOfTries; + } + + /** + * Shutdown and cleanup procedure. + * + */ + synchronized void shutdown() { + this.keepRunning = false; + this.interrupt(); + } + + @Override + public void run() { + + logger.trace("Reconnection timer thread started (activated: {}, Interval: {}, Tries: {})", + enableReconnection, reconnectionInterval, reconnectionTries); + + while (this.keepRunning) { + + ELlClientState beginClientState = parent.getCurrentClientState(); + logger.trace("ReconnectionTimerThread activated: {}", currentClientState); + + ELlClientState currentClientState = beginClientState; + + if (!this.enableReconnection) { + if (currentClientState == ELlClientState.TRY_TO_RECONNECT) { + parent.setCurrentClientStateAndTriggerReconnect(ELlClientState.DISCONNECTED_FROM_BROKER); + currentClientState = parent.getCurrentClientState(); + } + } + + if (currentClientState == ELlClientState.CONNECTED_TO_BROKER + || currentClientState == ELlClientState.DISCONNECTED_FROM_BROKER) { + actualTry = 1; + } + + if (this.enableReconnection && currentClientState == ELlClientState.TRY_TO_RECONNECT) { + handleReconnection(); + } + + try { + synchronized (this) { + if (beginClientState != parent.getCurrentClientState()) { + continue; + } + if (currentClientState == ELlClientState.TRY_TO_RECONNECT) { + this.wait(reconnectionInterval); + } else { + this.wait(); + } + } + } catch (InterruptedException ign) { + // This is expected + } + + } + } + + private void handleReconnection() { + + logger.trace("Reconnection try: {}", actualTry); + try { + parent.connect(); + } catch (LowLevelCommRuntimeException ex) { + logger.debug("Reconnection try ({}) was not successful.", actualTry); + } + + if (this.reconnectionTries != -1 && actualTry >= this.reconnectionTries) { + logger.warn("Maximum number of reconnection tries exceeds. Stop to reconnect"); + parent.setCurrentClientStateAndTriggerReconnect(ELlClientState.DISCONNECTED_FROM_BROKER); + actualTry = 1; + } else { + actualTry++; + } + } + + void setEnableReconnection(boolean enableReconnection) { + this.enableReconnection = enableReconnection; + } + + void setReconnectionInterval(int reconnectionInterval) { + + if (reconnectionInterval > 0) { + this.reconnectionInterval = reconnectionInterval; + } else { + throw new IllegalArgumentException(String.format("False reconnection interval in milliseconds (%d) was " + + "set. The parameter should be greater than 0.", reconnectionInterval)); + } + } + + void setReconnectionTries(int reconnectionTries) { + + if (reconnectionTries == -1 || reconnectionTries > 0) { + this.reconnectionTries = reconnectionTries; + } else { + throw new IllegalArgumentException( + String.format("False reconnection tries (%d) want to be set. The parameter should " + + "be -1 for infinite tries or greater than 0", reconnectionTries)); + } + } + + int getReconnectNumberOfTries() { + return this.reconnectionTries; + } + + int getReconnectionInterval() { + return reconnectionInterval; + } + + boolean isEnableReconnection() { + return enableReconnection; + } + } + + /** + * Worker thread to handle received messages. + * + *

+ * This inner class is used to implement a blocking queue for the received + * messages. This is necessary to decouple the Mqtt receiving callback from the + * further message handling. Especially if the message callback publishes new + * messages this decoupling is necessary. + */ + private class ReceivedMessageConsumer extends Thread { + + /** + * Data Bean for received messages. + * + */ + class ReceivedMessage { + public String topic; + public byte[] payload; + } + + private boolean isRunning = true; + + private final BlockingQueue receivedMsgQueue; + + private IMqttReceiverCallback receiverCallback; + + private final Object syncMonitor = new Object(); + + /** + * Construct the receiving messages' handler. + * + * @param queueSize Size of the Queue for receiving messages + * @param clientId client ID + */ + ReceivedMessageConsumer(int queueSize, String clientId) { + this.setDaemon(true); + this.setName("ReceivedMessageConsumer: " + clientId); + receivedMsgQueue = new ArrayBlockingQueue(queueSize); + } + + /** + * Set the callback handler for handling receiving messages. + * + * @param receiveCallback handler to be set + */ + void setReceiveCallback(IMqttReceiverCallback receiveCallback) { + synchronized (this.syncMonitor) { + this.receiverCallback = receiveCallback; + } + } + + /** + * Add a new received message to the worker queue. + * + * @param topic of the received message + * @param payload of the received message + */ + void addNewMessage(String topic, byte[] payload) { + + ReceivedMessage msg = new ReceivedMessage(); + msg.topic = topic; + msg.payload = payload; + + try { + receivedMsgQueue.put(msg); + } catch (InterruptedException ex) { + // expected + } + } + + /** + * Shutdown the ReceivedMessageConsumer Thread. + * + */ + void shutdown() { + isRunning = false; + this.interrupt(); + } + + @Override + public void run() { + + while (isRunning) { + try { + ReceivedMessage msg = receivedMsgQueue.take(); + logger.trace("Process received message (Topic: {} IPayload: {}) No of waiting objects: {}", + msg.topic, new String(msg.payload), receivedMsgQueue.size()); + + synchronized (this.syncMonitor) { + if (this.receiverCallback == null) { + logger.warn("No ReceiverCallback is set in ReceivedMessageConsumerThread."); + continue; + } + this.receiverCallback.handleRawMqttMessage(msg.topic, msg.payload); + } + } catch (InterruptedException ignore) { + // ignore + } + } + } + } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlService.java b/src/main/java/at/ac/ait/lablink/core/service/LlService.java index 58deca7..18e47f4 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlService.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlService.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Map.Entry; +// TODO: Auto-generated Javadoc /** * Abstract class extending the Lablink service base class. * @@ -19,6 +20,7 @@ public abstract class LlService extends LlServiceBase { /** The current state value of the service. */ private T curState; + /** The notifiers. */ protected Map> notifiers = new HashMap>(); @@ -42,6 +44,16 @@ public LlService(boolean readonly) { super(readonly); } + /** + * Instantiates a new ll service. + * + * @param readonly the readonly + * @param exposedToPrometheus the exposed to prometheus + */ + public LlService(boolean readonly, boolean exposedToPrometheus) { + super(readonly, exposedToPrometheus); + } + /** * Instantiates a new Lablink service with the name provided. The resulting instance will be * read/write enabled. @@ -63,6 +75,13 @@ public LlService(String name, boolean readonly) { super(name, readonly); } + /** + * Instantiates a new ll service. + * + * @param name the name + * @param readonly the readonly + * @param exposedToPrometheus the exposed to prometheus + */ public LlService(String name, boolean readonly, boolean exposedToPrometheus) { super(name, readonly, exposedToPrometheus); } @@ -100,6 +119,12 @@ public T getCurState() { return curState; } + /** + * Notify state change. + * + * @param oldVal the old val + * @param newVal the new val + */ private void notifyStateChange(T oldVal, T newVal) { this.setGage(); @@ -146,6 +171,11 @@ public void setCurState(T curVal) { */ public abstract boolean set(T newval); + /** + * Adds the state change notifier. + * + * @param notifier the notifier + */ public void addStateChangeNotifier(IServiceStateChangeNotifier notifier) { this.notifiers.put(this.notifiers.size() + 1, notifier); logger.debug("Another notifier added for service [{}].", this.getName()); diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java b/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java index 4be0236..d8dbbba 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java @@ -5,168 +5,171 @@ package at.ac.ait.lablink.core.service; +import java.util.HashMap; +import java.util.Map; + import org.apache.commons.lang.RandomStringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import io.prometheus.client.Gauge; -import java.util.HashMap; -import java.util.Map; - /** * Base class for Lablink services. */ public abstract class LlServiceBase implements Cloneable { - protected static final Logger logger = LogManager.getLogger("LlServiceBase"); - - /** The name of the service. */ - protected String name; - - /** The read-only flag. */ - protected boolean readOnly = false; - protected boolean exposeToPrometheus = false; - - protected Gauge serviceGage; - - /** - * Instantiates a new instance with random alpha-numeric - * name and read-only flag set to {@code false}. - */ - public LlServiceBase() { - this(RandomStringUtils.randomAlphabetic(10), false); - } - - /** - * Instantiates a new instance. - * - * @param name service name - * @param readonly read-only flag - */ - public LlServiceBase(String name, boolean readonly) { - this(name, readonly, true); - } - - public LlServiceBase(String name, boolean readonly, boolean exposedToPrometheus) { - this.setName(name); - this.setReadOnly(readonly); - this.exposeToPrometheus = exposedToPrometheus; - serviceGage = Gauge.build().name(name).register(); - } - - /** - * Instantiates a new instance with read-only flag set to {@code false}. - * - * @param name service name - */ - public LlServiceBase(String name) { - this(name, false); - } - - /** - * Instantiates a new instance with random alpha-numeric name. - * - * @param readonly read-only flag - */ - public LlServiceBase(boolean readonly) { - this(RandomStringUtils.randomAlphabetic(10), readonly); - } - - /** - * Gets the name. - * - * @return the name - */ - public String getName() { - return name; - } - - /** - * Sets the name. - * - * @param name the name to set - */ - public void setName(String name) { - this.name = name; - } - - /** - * Checks if is read-only. - * - * @return read-only flag - */ - public boolean isReadOnly() { - return readOnly; - } - - /** - * Sets the read-only flag. - * - * @param readOnly read-only flag - */ - public void setReadOnly(boolean readOnly) { - this.readOnly = readOnly; - } - - /** The properties. */ - protected Map properties = - new HashMap(); - - /** - * Gets the collection of properties stored. - * - * @return the properties - */ - public Map getProperties() { - return properties; - } - - /** - * Sets the properties as a complete collection. - * - * @param properties the properties - */ - public void setProperties(Map properties) { - this.properties = properties; - } - - /** - * Adds the property. - * - * @param key the key - * @param val the val - */ - public void addProperty(ELlServiceProperties key, String val) { - this.properties.put(key, val); - logger.debug("Property [{}] updated with value [{}] for service [{}]", key, val, this.name); - } - - /** - * Gets the property. - * - * @param key the key - * @return the property - */ - public String getProperty(ELlServiceProperties key) { - return this.properties.get(key); - } - - @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - public Object duplicate() throws CloneNotSupportedException { - LlServiceBase base = (LlServiceBase) super.clone(); - return base; - } - - public boolean isExposedToPrometheus() { - return this.exposeToPrometheus; - } - - protected void setGage() { - - } + protected static final Logger logger = LogManager.getLogger("LlServiceBase"); + + /** The name of the service. */ + protected String name; + + /** The read-only flag. */ + protected boolean readOnly = false; + protected boolean exposeToPrometheus = false; + + protected Gauge serviceGage; + + /** + * Instantiates a new instance with random alpha-numeric name and read-only flag + * set to {@code false}. + */ + public LlServiceBase() { + this(RandomStringUtils.randomAlphabetic(10), false); + } + + /** + * Instantiates a new instance. + * + * @param name service name + * @param readonly read-only flag + */ + public LlServiceBase(String name, boolean readonly) { + this(name, readonly, true); + } + + public LlServiceBase(String name, boolean readonly, boolean exposedToPrometheus) { + this.setName(name); + this.setReadOnly(readonly); + this.exposeToPrometheus = exposedToPrometheus; + serviceGage = Gauge.build().namespace("lablinksim").name(name).help(name).register(); + } + + /** + * Instantiates a new instance with read-only flag set to {@code false}. + * + * @param name service name + */ + public LlServiceBase(String name) { + this(name, false); + } + + /** + * Instantiates a new instance with random alpha-numeric name. + * + * @param readonly read-only flag + */ + public LlServiceBase(boolean readonly) { + this(RandomStringUtils.randomAlphabetic(10), readonly); + } + + public LlServiceBase(boolean readonly, boolean exposedToPrometheus) { + this(RandomStringUtils.randomAlphabetic(10), readonly, exposedToPrometheus); + } + + /** + * Gets the name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Sets the name. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * Checks if is read-only. + * + * @return read-only flag + */ + public boolean isReadOnly() { + return readOnly; + } + + /** + * Sets the read-only flag. + * + * @param readOnly read-only flag + */ + public void setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + } + + /** The properties. */ + protected Map properties = new HashMap(); + + /** + * Gets the collection of properties stored. + * + * @return the properties + */ + public Map getProperties() { + return properties; + } + + /** + * Sets the properties as a complete collection. + * + * @param properties the properties + */ + public void setProperties(Map properties) { + this.properties = properties; + } + + /** + * Adds the property. + * + * @param key the key + * @param val the val + */ + public void addProperty(ELlServiceProperties key, String val) { + this.properties.put(key, val); + logger.debug("Property [{}] updated with value [{}] for service [{}]", key, val, this.name); + } + + /** + * Gets the property. + * + * @param key the key + * @return the property + */ + public String getProperty(ELlServiceProperties key) { + return this.properties.get(key); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + public Object duplicate() throws CloneNotSupportedException { + LlServiceBase base = (LlServiceBase) super.clone(); + return base; + } + + public boolean isExposedToPrometheus() { + return this.exposeToPrometheus; + } + + protected void setGage() { + + } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServiceDouble.java b/src/main/java/at/ac/ait/lablink/core/service/LlServiceDouble.java index b83a71c..dc25656 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServiceDouble.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServiceDouble.java @@ -5,33 +5,87 @@ package at.ac.ait.lablink.core.service; +// TODO: Auto-generated Javadoc +/** + * The Class LlServiceDouble. + */ public abstract class LlServiceDouble extends LlService { + /** + * Default constructor. (1) + */ + public LlServiceDouble() { + super(false, true); + init(); + } + + /** + * Constructor with service name only. (2) + * + * @param name the name + */ public LlServiceDouble(String name) { - super(name); - setCurState(0.0); - this.exposeToPrometheus = true; + super(name, false, true); + init(); } - public LlServiceDouble() { - super(); - setCurState(0.0); + /** + * Constructor with readonly flag only. (3) + * + * @param readonly the readonly + */ + public LlServiceDouble(boolean readonly) { + super(readonly, true); + init(); } + /** + * Instantiates a new ll service double. (4) + * + * @param name the name + * @param readonly the readonly + */ public LlServiceDouble(String name, boolean readonly) { - super(name, readonly); - setCurState(0.0); - this.exposeToPrometheus = true; + super(name, readonly, true); + init(); } - - public LlServiceDouble(boolean readonly) { - super(readonly); - setCurState(0.0); - this.exposeToPrometheus = true; + + /** + * Instantiates a new ll service double. (5) + * + * @param readonly the readonly + * @param expose the expose + */ + public LlServiceDouble(boolean readonly, boolean expose) { + super(readonly, expose); + init(); } + /** + * Instantiates a new ll service double. (6) + * + * @param name the name + * @param readonly the readonly + * @param expose the expose + */ + public LlServiceDouble(String name, boolean readonly, boolean expose) { + super(name, readonly, expose); + init(); + } + + /** + * Sets the gage. + */ @Override protected void setGage() { this.serviceGage.set(this.getCurState()); } + + /** + * Inits the. + */ + private void init() { + setCurState(0.0); + this.serviceGage.set(this.getCurState()); + } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServiceLong.java b/src/main/java/at/ac/ait/lablink/core/service/LlServiceLong.java index 1303ff8..a7b9f74 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServiceLong.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServiceLong.java @@ -7,32 +7,75 @@ public abstract class LlServiceLong extends LlService { + /** + * Default constructor. (1) + */ public LlServiceLong() { - super(); - setCurState(0L); - this.exposeToPrometheus = true; + super(false, true); + init(); } - + + /** + * Constructor with service name only. (2) + * + * @param name the name + */ public LlServiceLong(String name) { - super(name); - setCurState(0L); - this.exposeToPrometheus = true; + super(name, false, true); + init(); + } + + /** + * Constructor with readonly flag only. (3) + * + * @param readonly the readonly + */ + public LlServiceLong(boolean readonly) { + super(readonly, true); + init(); } + /** + * Instantiates a new ll service long. (4) + * + * @param name the name + * @param readonly the readonly + */ public LlServiceLong(String name, boolean readonly) { - super(name, readonly); - setCurState(0L); - this.exposeToPrometheus = true; + super(name, readonly, true); + init(); + } + + /** + * Instantiates a new ll service long. (5) + * + * @param readonly the readonly + * @param expose the expose + */ + public LlServiceLong(boolean readonly, boolean expose) { + super(readonly, expose); + init(); } - public LlServiceLong(boolean readonly) { - super(readonly); - setCurState(0L); - this.exposeToPrometheus = true; + /** + * Instantiates a new ll service long. (6) + * + * @param name the name + * @param readonly the readonly + * @param expose the expose + */ + public LlServiceLong(String name, boolean readonly, boolean expose) { + super(name, readonly, expose); + init(); } @Override protected void setGage() { this.serviceGage.set(this.getCurState()); } + + private void init() { + setCurState(0L); + this.serviceGage.set(this.getCurState()); + } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java index da035a6..29ebfed 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudo.java @@ -88,7 +88,7 @@ public LlServicePseudo(String name, boolean readonly, boolean exposedToPrometheu } /** - * Instantiates a new ll service pscudo. + * Instantiates a new ll service pseudo. * * @param name the name */ @@ -97,7 +97,7 @@ public LlServicePseudo(String name) { } /** - * Instantiates a new ll service pscudo. + * Instantiates a new ll service pseudo. * * @param readonly the readonly */ @@ -105,6 +105,10 @@ public LlServicePseudo(boolean readonly) { super(readonly); } + public LlServicePseudo(boolean readonly, boolean exposedToPrometheus) { + super(readonly, exposedToPrometheus); + } + /** * Gets the service data type class. * diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoDouble.java b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoDouble.java index 46de784..304afb7 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoDouble.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoDouble.java @@ -7,28 +7,75 @@ public class LlServicePseudoDouble extends LlServicePseudo { + /** + * Default constructor. (1) + */ public LlServicePseudoDouble() { - super(); - this.set(0.0); + super(false, true); + init(); + } + + /** + * Constructor with service name only. (2) + * + * @param name the name + */ + public LlServicePseudoDouble(String name) { + super(name, false, true); + init(); } - public LlServicePseudoDouble(String name, boolean readonly) { - super(name, readonly); - this.set(0.0); + /** + * Constructor with readonly flag only. (3) + * + * @param readonly the readonly + */ + public LlServicePseudoDouble(boolean readonly) { + super(readonly, true); + init(); } - public LlServicePseudoDouble(String name) { - super(name); - this.set(0.0); + /** + * Instantiates a new ll service PseudoDouble. (4) + * + * @param name the name + * @param readonly the readonly + */ + public LlServicePseudoDouble(String name, boolean readonly) { + super(name, readonly, true); + init(); + } + + /** + * Instantiates a new ll service PseudoDouble. (5) + * + * @param readonly the readonly + * @param expose the expose + */ + public LlServicePseudoDouble(boolean readonly, boolean expose) { + super(readonly, expose); + init(); } - public LlServicePseudoDouble(boolean readonly) { - super(readonly); - this.set(0.0); + /** + * Instantiates a new ll service PseudoDouble. (6) + * + * @param name the name + * @param readonly the readonly + * @param expose the expose + */ + public LlServicePseudoDouble(String name, boolean readonly, boolean expose) { + super(name, readonly, expose); + init(); } @Override protected void setGage() { this.serviceGage.set(this.get()); } + + private void init() { + set(0.0); + this.serviceGage.set(this.get()); + } } diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoLong.java b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoLong.java index e8a8f50..0c405e3 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoLong.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServicePseudoLong.java @@ -7,21 +7,66 @@ public class LlServicePseudoLong extends LlServicePseudo { + /** + * Default constructor. (1) + */ public LlServicePseudoLong() { - super(); - this.set(0L); + super(false, true); + init(); + } + + /** + * Constructor with service name only. (2) + * + * @param name the name + */ + public LlServicePseudoLong(String name) { + super(name, false, true); + init(); } - public LlServicePseudoLong(String name, boolean readonly) { - super(name, readonly); + /** + * Constructor with readonly flag only. (3) + * + * @param readonly the readonly + */ + public LlServicePseudoLong(boolean readonly) { + super(readonly, true); + init(); } - public LlServicePseudoLong(String name) { - super(name); + /** + * Instantiates a new ll service PseudoLong. (4) + * + * @param name the name + * @param readonly the readonly + */ + public LlServicePseudoLong(String name, boolean readonly) { + super(name, readonly, true); + init(); + } + + /** + * Instantiates a new ll service PseudoLong. (5) + * + * @param readonly the readonly + * @param expose the expose + */ + public LlServicePseudoLong(boolean readonly, boolean expose) { + super(readonly, expose); + init(); } - public LlServicePseudoLong(boolean readonly) { - super(readonly); + /** + * Instantiates a new ll service PseudoLong. (6) + * + * @param name the name + * @param readonly the readonly + * @param expose the expose + */ + public LlServicePseudoLong(String name, boolean readonly, boolean expose) { + super(name, readonly, expose); + init(); } @Override @@ -29,4 +74,8 @@ protected void setGage() { this.serviceGage.set(this.get()); } + private void init() { + set(0L); + this.serviceGage.set(this.get()); + } } diff --git a/src/test/java/at/ac/ait/lablink/core/services/ServiceIT.java b/src/test/java/at/ac/ait/lablink/core/services/ServiceIT.java index dea2584..899cbb5 100644 --- a/src/test/java/at/ac/ait/lablink/core/services/ServiceIT.java +++ b/src/test/java/at/ac/ait/lablink/core/services/ServiceIT.java @@ -3,7 +3,7 @@ // Distributed under the terms of the Modified BSD License. // -package at.ac.ait.lablink.core.service; +package at.ac.ait.lablink.core.services; import static org.junit.Assert.fail; diff --git a/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/BooleanValueTest.java b/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/BooleanValueTest.java index e382129..0594e9a 100644 --- a/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/BooleanValueTest.java +++ b/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/BooleanValueTest.java @@ -3,9 +3,10 @@ // Distributed under the terms of the Modified BSD License. // -package at.ac.ait.lablink.core.service.datapoint.payloads; +package at.ac.ait.lablink.core.services.datapoint.payloads; import at.ac.ait.lablink.core.connection.encoding.encodables.PayloadBaseTest; +import at.ac.ait.lablink.core.service.datapoint.payloads.BooleanValue; import org.junit.Before; diff --git a/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/DataPointPropertiesTest.java b/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/DataPointPropertiesTest.java index ae141ef..e0dc08f 100644 --- a/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/DataPointPropertiesTest.java +++ b/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/DataPointPropertiesTest.java @@ -3,9 +3,10 @@ // Distributed under the terms of the Modified BSD License. // -package at.ac.ait.lablink.core.service.datapoint.payloads; +package at.ac.ait.lablink.core.services.datapoint.payloads; import at.ac.ait.lablink.core.connection.encoding.encodables.PayloadBaseTest; +import at.ac.ait.lablink.core.service.datapoint.payloads.DataPointProperties; import org.junit.Before; diff --git a/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/DoubleValueTest.java b/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/DoubleValueTest.java index e7a8af4..c09874c 100644 --- a/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/DoubleValueTest.java +++ b/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/DoubleValueTest.java @@ -3,9 +3,10 @@ // Distributed under the terms of the Modified BSD License. // -package at.ac.ait.lablink.core.service.datapoint.payloads; +package at.ac.ait.lablink.core.services.datapoint.payloads; import at.ac.ait.lablink.core.connection.encoding.encodables.PayloadBaseTest; +import at.ac.ait.lablink.core.service.datapoint.payloads.DoubleValue; import org.junit.Before; diff --git a/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/LongValueTest.java b/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/LongValueTest.java index fdfd946..c71c4f1 100644 --- a/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/LongValueTest.java +++ b/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/LongValueTest.java @@ -3,9 +3,10 @@ // Distributed under the terms of the Modified BSD License. // -package at.ac.ait.lablink.core.service.datapoint.payloads; +package at.ac.ait.lablink.core.services.datapoint.payloads; import at.ac.ait.lablink.core.connection.encoding.encodables.PayloadBaseTest; +import at.ac.ait.lablink.core.service.datapoint.payloads.LongValue; import org.junit.Before; diff --git a/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/StringValueTest.java b/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/StringValueTest.java index 8dec4cf..eb6e853 100644 --- a/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/StringValueTest.java +++ b/src/test/java/at/ac/ait/lablink/core/services/datapoint/payloads/StringValueTest.java @@ -3,9 +3,10 @@ // Distributed under the terms of the Modified BSD License. // -package at.ac.ait.lablink.core.service.datapoint.payloads; +package at.ac.ait.lablink.core.services.datapoint.payloads; import at.ac.ait.lablink.core.connection.encoding.encodables.PayloadBaseTest; +import at.ac.ait.lablink.core.service.datapoint.payloads.StringValue; import org.junit.Before; diff --git a/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncClientConfigMessageTest.java b/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncClientConfigMessageTest.java index 30de710..decd3fc 100644 --- a/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncClientConfigMessageTest.java +++ b/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncClientConfigMessageTest.java @@ -3,9 +3,10 @@ // Distributed under the terms of the Modified BSD License. // -package at.ac.ait.lablink.core.service.sync.payloads; +package at.ac.ait.lablink.core.services.sync.payloads; import at.ac.ait.lablink.core.connection.encoding.encodables.PayloadBaseTest; +import at.ac.ait.lablink.core.service.sync.payloads.SyncClientConfigMessage; import org.junit.Before; diff --git a/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncGoReplyTest.java b/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncGoReplyTest.java index 5a9e7bd..e87279b 100644 --- a/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncGoReplyTest.java +++ b/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncGoReplyTest.java @@ -3,9 +3,10 @@ // Distributed under the terms of the Modified BSD License. // -package at.ac.ait.lablink.core.service.sync.payloads; +package at.ac.ait.lablink.core.services.sync.payloads; import at.ac.ait.lablink.core.connection.encoding.encodables.PayloadBaseTest; +import at.ac.ait.lablink.core.service.sync.payloads.SyncGoReply; import org.junit.Before; diff --git a/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncGoRequestTest.java b/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncGoRequestTest.java index 34192e8..e5757a5 100644 --- a/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncGoRequestTest.java +++ b/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncGoRequestTest.java @@ -3,9 +3,10 @@ // Distributed under the terms of the Modified BSD License. // -package at.ac.ait.lablink.core.service.sync.payloads; +package at.ac.ait.lablink.core.services.sync.payloads; import at.ac.ait.lablink.core.connection.encoding.encodables.PayloadBaseTest; +import at.ac.ait.lablink.core.service.sync.payloads.SyncGoRequest; import org.junit.Before; diff --git a/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncParamMessageTest.java b/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncParamMessageTest.java index da44994..148d82f 100644 --- a/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncParamMessageTest.java +++ b/src/test/java/at/ac/ait/lablink/core/services/sync/payloads/SyncParamMessageTest.java @@ -3,9 +3,10 @@ // Distributed under the terms of the Modified BSD License. // -package at.ac.ait.lablink.core.service.sync.payloads; +package at.ac.ait.lablink.core.services.sync.payloads; import at.ac.ait.lablink.core.connection.encoding.encodables.PayloadBaseTest; +import at.ac.ait.lablink.core.service.sync.payloads.SyncParamMessage; import org.junit.Before; From 53106ff81d208bcdcb6d4c04db836448ab1def8c Mon Sep 17 00:00:00 2001 From: Jawad Kazmi <78086114+kazmijawad@users.noreply.github.com> Date: Sun, 19 Dec 2021 15:35:25 +0100 Subject: [PATCH 5/5] namespace updated --- src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java b/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java index d8dbbba..44986ee 100644 --- a/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java +++ b/src/main/java/at/ac/ait/lablink/core/service/LlServiceBase.java @@ -52,7 +52,7 @@ public LlServiceBase(String name, boolean readonly, boolean exposedToPrometheus) this.setName(name); this.setReadOnly(readonly); this.exposeToPrometheus = exposedToPrometheus; - serviceGage = Gauge.build().namespace("lablinksim").name(name).help(name).register(); + serviceGage = Gauge.build().namespace("ait-lablink").name(name).help(name).register(); } /**