TMS Echo co-existing with an XData Server

Hi Wagner,

I'm looking for some advice regarding a TMS Echo project I trying to set up please. It consists of an integrated XData Server for the application's database access and an echo server to replicate data between mobile clients and the server. Echo works fine between the mobile clients and the server. The problem comes when trying to replicate data from the XData Server to the mobile clients. What I mean is when I make a change to the data using TXDataClient from a window's application.

I have created a TEchoEventSubscriber on the Server to log the changes. However it is creating entries in the ECHO_LOG table with a null ORIGIN_NODE_ID which never gets replicated to the mobile clients. I have registered the server as a self node. I suspect this might have something to do with avoiding circular references when processing the echo batches on the server. If this is the case I think I will need to separate the ECHO server and the XData Server in to two different applications and have an additional database for all the XData Clients to work with which is then replicated with Echo to the echo server.

This sounds a little convoluted when I try to explain it. I hope I am making it clear. Before I go to the trouble of doing this I wanted to check with you that I wasn't missing anything.

Kind Regards

Steve

Hi Steve,
Indeed it's a little bit convoluted to understand. :slight_smile:
Conceptually XData and Echo servers are totally different beasts, they have nothing to do with each other. Each receives/sends the packages with the deltas (modifications) to be applied to the other side. And XData is your regular API.

If you have added Echo events to the XData server, they it should behave as any other normal Echo client, logging the changes. Of course, you will need to push/pull your changes to the Echo server from the XData server, as you would do from the mobile applications. The XData server is just another node like any other.

Maybe what could be affecting your app is if you are mixing TMappingExplorer instances (models)? If you both servers are in the same application, then their Aurelius entities might get mixed up if you don't separated it correctly.,

Remember that the events are subscribed to a specific model (explorer). I'm not sure how is your setup in this regard for both servers.

Sorry about that Wagner. I tend to have that affect on a lot of people. I've managed to work round the problem so it's no longer an issue for me.

Good you solved, Steve. Is it relevant information for other users visiting this topic in case they have similar issues?

Perhaps, I'll try and explain what was trying to do again.

  1. I created an XData Server for desktop clients
  2. I added in an echo server for mobile clients to work off-line

I expected I could replicate the changes from the desktop clients down to the mobile clients. However this didn't work. When I looked at the ECHO_LOG.ORIGIN_NODE_ID it was null for changes made by the desktop clients.

The XData Server was very simple I just dropped the XData components on a data module. I made a little class for the echo server, just copied what you done in the demo project. I created a member field for the class on the data module.

Here is the class I created

unit uEchoServer;

interface

uses
  Aurelius.Drivers.Interfaces,
  Aurelius.Engine.DatabaseManager,
  XData.Server.Module,
  System.SysUtils,
  Sparkle.HttpSys.Server,
  Sparkle.HttpServer.Context,
  Sparkle.HttpServer.Module,
  Sparkle.Sys.Timer,
  Echo.entities,
  Echo.Listeners,
  Echo.Server,
  Echo.Main;

type
  TMyEchoServer = class
  private
    FBaseUrl       : string;
    FEcho          : TEcho;
    FEchoModule    : TEchoServerModule;
    FEchoSubscriber: TEchoEventSubscriber;
    FHttpSysServer : THttpSysServer;
    FNodeManager   : IEchoNodeManager;
    FPool          : IDBConnectionPool;
    FTimer         : TSparkleTimer;
  public
    constructor Create( ABaseUrl: string; APool: IDBConnectionPool );
    destructor Destroy; override;
    procedure Start;
    procedure Stop;
  end;

implementation

uses
  System.IOUtils;

constructor TMyEchoServer.Create( ABaseUrl: string; APool: IDBConnectionPool );
begin
  inherited Create;
  FBaseUrl       := ABaseUrl;
  FPool          := APool;
  FHttpSysServer := nil;
  FEcho          := nil;
  FTimer         := nil;
  TDatabaseManager.Update( APool.GetConnection, TEcho.Explorer );
end;

destructor TMyEchoServer.Destroy;
begin
  Stop;
  inherited;
end;

procedure TMyEchoServer.Start;
begin
  if Assigned( FHttpSysServer ) then
    Exit;

  FHttpSysServer := THttpSysServer.Create;

  FEchoModule := TEchoServerModule.Create( FBaseUrl, FPool );
  FHttpSysServer.AddModule( FEchoModule );

  FEcho := TEcho.Create( FPool );

  FNodeManager := FEcho.GetNodeManager;

  if FNodeManager.SelfNode = nil then
  begin
    FNodeManager.CreateNode( 'server' );
    FNodeManager.DefineSelfNode( 'server' );
  end;

  FEchoSubscriber := TEchoEventSubscriber.Create;
  FEchoSubscriber.SubscribeListeners;

  FTimer := TSparkleTimer.Create(
      procedure( FEcho: TObject )
    begin
      TEcho( FEcho ).BatchLoad;
      TEcho( FEcho ).Route(
          procedure( Log: TEchoLog; Node: TEchoNode; var Route: Boolean )
        begin
        // if SameText( Log.EntityClass, 'AppEntities.TEchoInvoice' )
        // and ( Node.Id = 'Client1' ) then
        // Route := false;
        end
        );
    end,
    FEcho, 2000, TTimerType.Periodic );

  FHttpSysServer.Start;

end;

procedure TMyEchoServer.Stop;
begin
  FEchoSubscriber.UnsubscribeListeners;
  FEchoSubscriber.Free;
  FreeAndNil( FHttpSysServer );
  FreeAndNil( FEcho );
  FreeAndNil( FTimer );
end;

end.

Here's what I got in the ECHO_LOG table. The null ORIGIN_NODE_ID's were created by the TMyEchoServer's FEchoEventSubscriber.

Is that any clearer?

Anyway, I gave up with the XData Server and just use the Echo Server which actually works better with what I need to do.

That's expected because it seems you are saving the changes made by the XData server directly in the server database. ORIGIN_NODE_ID is only set when data is transferred from one node to another. If those records are just logging of modifications made in the node itself, OriginNode is nil.