digraph {
  # PVA server components are red boxes
  # PVA client components are blue boxes
  # GW components are black ovals
  #
  # red lines are strong references either '1' (1 to 1) or 'N' (1 to N)
  # green lines are strong references which are explicitly broken on some event
  # blue lines are weak references
  
  subgraph clusterserver {
    label = "Server";
    ServerContextImpl [shape=box,color=red];
    BlockingServerTCPTransportCodec [shape=box,color=red];
    ServerChannelImpl [shape=box,color=red];
    ServerChannelRequesterImpl [shape=box,color=red];
    ServerChannelImpl [shape=box,color=red];
    ServerMonitorRequesterImpl [shape=box,color=red];

    ## Server Internals
    # Really goes through TransportRegistry
    ServerContextImpl -> BlockingServerTCPTransportCodec [color=green,style=dashed,label="N"];
    BlockingServerTCPTransportCodec -> ServerChannelImpl [color=green,style=dashed,label="N"];
    ServerChannelRequesterImpl -> BlockingServerTCPTransportCodec [color=blue,label="1"];
    ServerChannelRequesterImpl -> ServerChannelImpl [color=blue,label="1"];
    ServerMonitorRequesterImpl -> BlockingServerTCPTransportCodec [color=red,label="1"];
  }

  ## Server to GW
  ServerContextImpl -> GWServerChannelProvider [color=red,label="N"];
  ServerChannelImpl -> GWChannel [color=green,style=dashed,label="1"];
  GWChannel -> ServerChannelRequesterImpl [color=red,label="1"];
  MonitorUser -> ServerMonitorRequesterImpl [color=blue,label="1"];
  ServerMonitorRequesterImpl -> MonitorUser [color=red,label="1"];

  subgraph clustergw {
    label = "Gateway";
    GWServerChannelProvider;
    ChannelCache;
    ChannelCacheEntry;
    GWChannel;
    CRequester;
    MonitorCacheEntry;
    MonitorUser;

    ## GW internal
    GWServerChannelProvider -> ChannelCache [color=red,label="1"];
    GWChannel -> ChannelCacheEntry [color=red,label="1"];

    ChannelCache -> ChannelCacheEntry [color=green,style=dashed,label="N"];
    ChannelCache -> GWServerChannelProvider [color=blue,label="1"];

    ChannelCacheEntry -> ChannelCache [color=blue,label="1"];
    CRequester -> ChannelCacheEntry [color=blue,label="1"];
    ChannelCacheEntry -> GWChannel [color=blue,label="N"];
    ChannelCacheEntry -> MonitorCacheEntry [color=blue,label="N"];
    MonitorCacheEntry -> ChannelCacheEntry [color=blue,label="1"];
    MonitorCacheEntry -> MonitorUser [color=blue,label="N"];
    MonitorUser -> MonitorCacheEntry [color=red,label="1"];
  }

  ## GW to Client
  ChannelCache -> ChannelProviderImpl [color=red,label="1"];
  ChannelCacheEntry -> InternalChannelImpl [color=red,label="1"];
  MonitorCacheEntry -> ChannelMonitorImpl [color=red,label="1"];
  InternalChannelImpl -> CRequester [color=red,label="1"];
  ChannelMonitorImpl -> MonitorCacheEntry [color=red,style=dashed,label="1"];
  MonitorStrategyQueue -> MonitorCacheEntry [color=red,label="1"];

  subgraph clusterclient {
    label = "Client";
    InternalClientContextImpl [shape=box,color=blue];
    ChannelProviderImpl [shape=box,color=blue];
    BlockingClientTCPTransportCodec [shape=box,color=blue];
    InternalChannelImpl [shape=box,color=blue];
    ChannelMonitorImpl [shape=box,color=blue];
    MonitorStrategyQueue [shape=box,color=blue];

    ## Client internals
    ChannelProviderImpl -> InternalClientContextImpl [color=blue,label="1"];
    # Really goes through TransportRegistry
    InternalClientContextImpl -> BlockingClientTCPTransportCodec [color=green,style=dashed,label="N"];
    BlockingClientTCPTransportCodec -> InternalChannelImpl [color=blue,label="N"];
    InternalChannelImpl -> BlockingClientTCPTransportCodec [color=red,label="1"];
    InternalChannelImpl -> InternalClientContextImpl [color=red,label="1"];
    ChannelMonitorImpl -> MonitorStrategyQueue [color=red,label="1"];
    MonitorStrategyQueue -> InternalChannelImpl [color=red,label="1"];
  }
}
