classDiagram
class PlotJugglerDigitalAdapter {
-PlotJugglerConnectionManager connectionManager
-PlotJugglerMessageSerializer serializer
+onStateUpdate()
+onEventNotificationReceived()
+onAdapterStart()
+onAdapterStop()
}
class PlotJugglerDigitalAdapterConfiguration {
-PlotJugglerConnectionConfiguration connectionConfiguration
-PlotJugglerMessageFormat messageFormat
-StateOutgoingChannel stateChannel
-Map~String,PropertyOutgoingChannel~ propertyChannels
-Map~String,RelationshipInstanceOutgoingChannel~ relationshipChannels
-Map~String,EventOutgoingChannel~ eventChannels
+builder()
}
class PlotJugglerDigitalAdapterConfigurationBuilder {
+withStateChannel()
+addPropertyChannel()
+addRelationshipChannel()
+addEventChannel()
+build()
}
class PlotJugglerChannelKind {
<<enumeration>>
STATE
PROPERTY
EVENT
RELATIONSHIP
}
class PlotJugglerChannel {
-String name
-PlotJugglerChannelKind kind
}
class StateOutgoingChannel
class PropertyOutgoingChannel~T~
class RelationshipInstanceOutgoingChannel~T~
class EventOutgoingChannel~T~
PlotJugglerChannel <|-- StateOutgoingChannel
PlotJugglerChannel <|-- PropertyOutgoingChannel
PlotJugglerChannel <|-- RelationshipInstanceOutgoingChannel
PlotJugglerChannel <|-- EventOutgoingChannel
PlotJugglerChannel --> PlotJugglerChannelKind : carries
class PlotJugglerConnectionManager {
-PlotJugglerConnection connection
+connect()
+disconnect()
+sendMessage()
}
class PlotJugglerConnectionFactory {
+create() PlotJugglerConnection
}
class PlotJugglerConnection {
<<interface>>
+connect()
+disconnect()
+send()
}
class PlotJugglerConnectionConfiguration {
<<interface>>
+getType() PlotJugglerConnectionType
}
class MqttPlotJugglerConnection
class WebSocketPlotJugglerConnection
class UdpPlotJugglerConnection
class MqttConnectionConfiguration {
-String baseTopic
-boolean isSingleTopic
}
class WebSocketConnectionConfiguration
class UdpConnectionConfiguration
PlotJugglerConnection <|.. MqttPlotJugglerConnection
PlotJugglerConnection <|.. WebSocketPlotJugglerConnection
PlotJugglerConnection <|.. UdpPlotJugglerConnection
PlotJugglerConnectionConfiguration <|.. MqttConnectionConfiguration
PlotJugglerConnectionConfiguration <|.. WebSocketConnectionConfiguration
PlotJugglerConnectionConfiguration <|.. UdpConnectionConfiguration
PlotJugglerConnectionFactory ..> PlotJugglerConnectionConfiguration : reads getType()
PlotJugglerConnectionFactory ..> PlotJugglerConnection : creates
PlotJugglerConnectionManager --> PlotJugglerConnectionFactory : uses at construction
PlotJugglerConnectionManager --> PlotJugglerConnection : delegates to
class PlotJugglerMessageFactory {
+getSerializer() PlotJugglerMessageSerializer
}
class PlotJugglerMessageSerializer {
<<interface>>
+serialize(Object, PlotJugglerChannelKind) byte[]
+deserialize(byte[]) Map
}
class JsonMessageSerializer
class CborMessageSerializer
class MessagePackMessageSerializer
class BsonMessageSerializer
class ProtobufMessageSerializer
class PlotJugglerOutgoingMessage {
-double timestamp
-Object payload
}
PlotJugglerMessageSerializer <|.. JsonMessageSerializer
PlotJugglerMessageSerializer <|.. CborMessageSerializer
PlotJugglerMessageSerializer <|.. MessagePackMessageSerializer
PlotJugglerMessageSerializer <|.. BsonMessageSerializer
PlotJugglerMessageSerializer <|.. ProtobufMessageSerializer
PlotJugglerMessageFactory ..> PlotJugglerMessageSerializer : creates
PlotJugglerMessageSerializer ..> PlotJugglerOutgoingMessage : serializes
PlotJugglerDigitalAdapter --> PlotJugglerDigitalAdapterConfiguration : reads
PlotJugglerDigitalAdapter --> PlotJugglerConnectionManager : owns
PlotJugglerDigitalAdapter --> PlotJugglerMessageSerializer : owns
PlotJugglerDigitalAdapterConfigurationBuilder ..> PlotJugglerDigitalAdapterConfiguration : builds
PlotJugglerDigitalAdapterConfiguration --> PlotJugglerConnectionConfiguration : holds
PlotJugglerDigitalAdapterConfiguration --> StateOutgoingChannel : holds 0..1
PlotJugglerDigitalAdapterConfiguration --> PropertyOutgoingChannel : holds 0..*
PlotJugglerDigitalAdapterConfiguration --> RelationshipInstanceOutgoingChannel : holds 0..*
PlotJugglerDigitalAdapterConfiguration --> EventOutgoingChannel : holds 0..*
How the pieces cooperate at runtime, following a single property update end-to-end:
- WLDT core calls
PlotJugglerDigitalAdapter.onStateUpdate(...)with the new state and the list of changes. - For each
PROPERTY/PROPERTY_VALUEchange, the adapter looks upconfiguration.getPropertyChannels().get(propertyKey). If no channel was registered for that key, the change is silently ignored (visualization is opt-in per key). - If a
PropertyOutgoingChannelis found, itsapplyPayloadFunction(property)runs the user-suppliedFunction<DigitalTwinStateProperty<T>, Object>to extract the payload. - The adapter wraps
{timestamp, payload}in aPlotJugglerOutgoingMessage, keys it by the channel name, and callsserializer.serialize(..., channel.getKind()), using whicheverPlotJugglerMessageSerializermatches the configuredPlotJugglerMessageFormat. - The resulting bytes are handed to
connectionManager.sendMessage(channel.getName(), bytes), which delegates to the concretePlotJugglerConnection(MQTT publish, WebSocket send, or UDP datagram) created byPlotJugglerConnectionFactoryat adapter start-up.
The same flow applies to relationships (RelationshipInstanceOutgoingChannel, keyed by relationship name)
and to events (EventOutgoingChannel, keyed by event key, dispatched from
onEventNotificationReceived(...)); the whole-state channel (StateOutgoingChannel) instead fires
unconditionally on every onStateUpdate(...) call, independently of the per-change list.
timestamp is always a double expressed in seconds since epoch (sub-second precision as the
fractional part) - the unit PlotJuggler expects when a payload field is selected as the custom timestamp
source; feeding milliseconds instead makes the X axis read ~1000x too large. It is sourced from when the
underlying data was actually produced, not from adapter send time: state/property/relationship channels
use DigitalTwinState.getEvaluationInstant(); event channels use the notification's own
DigitalTwinStateEventNotification.getTimestamp().