Skip to content

Latest commit

 

History

History
163 lines (146 loc) · 6.86 KB

File metadata and controls

163 lines (146 loc) · 6.86 KB

Architecture reference

← Back to README

Class structure and relationships

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..*
Loading

Runtime flow

How the pieces cooperate at runtime, following a single property update end-to-end:

  1. WLDT core calls PlotJugglerDigitalAdapter.onStateUpdate(...) with the new state and the list of changes.
  2. For each PROPERTY/PROPERTY_VALUE change, the adapter looks up configuration.getPropertyChannels().get(propertyKey). If no channel was registered for that key, the change is silently ignored (visualization is opt-in per key).
  3. If a PropertyOutgoingChannel is found, its applyPayloadFunction(property) runs the user-supplied Function<DigitalTwinStateProperty<T>, Object> to extract the payload.
  4. The adapter wraps {timestamp, payload} in a PlotJugglerOutgoingMessage, keys it by the channel name, and calls serializer.serialize(..., channel.getKind()), using whichever PlotJugglerMessageSerializer matches the configured PlotJugglerMessageFormat.
  5. The resulting bytes are handed to connectionManager.sendMessage(channel.getName(), bytes), which delegates to the concrete PlotJugglerConnection (MQTT publish, WebSocket send, or UDP datagram) created by PlotJugglerConnectionFactory at 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().