0

On the server side, I use Spring 4. On the browser side, I use Ember.js.

My application has entity classes such as Person and Product. These entities are in use both on the server and browser, and are modeled identically. For example:

//this is on the server side

public interface Person {    
    String getId();

    String getFirstName();
    void setFirstName(String firstName);

    String getLastName();
    void setLastName(String lastName);
}
//this is on the browser side, modeled with Ember Data

App.Person = DS.Model.extend({
    // id: DS.attr("string"), //property 'id' will be provided by Ember automatically
    firstName: DS.attr("string"),
    lastName: DS.attr("string")
});

I have the requirement to keep entities in sync between the server and the browser. So for example, when a Person's firstName property changes on the server side, this change shall be pushed to all interested browsers in real time.

I investigated Spring's WebSocket support, and after getting comfortable with Spring's "Hello WebSocket" example, I got convinced that using this technology is the right approach for my requirement.

As WebSocket/STOMP is quite low-level, I am in search for a solution that builds on top of this technology and provides observer pattern-like behavior between the browser (role of entities here would be observer) and the server (role of entities here would be subject/observable).

As I couldn't find an existing solution to this "keeping-entities-in-sync" challenge (neither a solution within Spring nor some third-party library), I want to build my own solution, yet the design already poses interesting questions, such as:

  • What should the protocol look like? Once a change happened, should the server send a minimal frame, only including the entity type and its ID? (e.g. once any property of a Person with ID "3" changes, then send {"type": "Person", "id": "3"} to all interested clients)
  • Are there real-life limitations on the number of entities that can be subscribed to? During a session, a single browser may come in contact with hundreds of Products.

I am interested in hearing which solutions have proven to successfully keep a Spring-based server's entities in sync with a JavaScript client's proxy entities (not necessarily Ember.js).

Abdull
  • 26,371
  • 26
  • 130
  • 172

1 Answers1

3

I'm going to give you a high level overview because giving all details requieres a blog post.

What You'll Need

  • Socket.io server.
  • Socket.io client, or one of their new libraries that pushes events to Redis. Ruby Socket.io client, Java Socket.io client
  • Hooks on all your server side data isolators to get notified of updates.
  • Observer on all of your Ember Data models.

You Have Two Options for Protocol

Option One: Only Event

Payload:

{
  meta: {
    type: 'NAME_OF_YOUR_MODEL'
    id:   'ID_OF_UPDATED_MODEL'
  }
}

Code:

window.socket = io()

App.ApplicationRoute = Ember.Route.extend({
  activate: function(){
    var store = this.store;

    socket.on('recordUpdated', function(payload){
      store.find(Ember.get(payload, 'meta.type'), Ember.get(payload, 'meta.id'));
    };
  }
}

App.Model = DS.Model.extend({
  lastUpdate: function(){
    var payload = {
      id: this.get('id'),
      type: this.constructor.toString()
    };

    socket.emit('recordUpdated', payload);

    this.save(); // You should save the record to get it in saved state.

    return payload;
  }.observes('isDirty') 
});

Option Two: JSON Representation of Model, With Event

Payload:

{
  "meta": {
    "type": "person"
    "id": "18"
  },

  "persons": [
    {"id": "18", "firstName": "Yahuda", "lastName": "Katz"}
  ]
}

Code:

window.socket = io();

App.ApplicationRoute = Ember.Route.extend({
  activate: function(){
    var store = this.store;

    socket.on('recordUpdated', function(payload){
      store.pushPayload(payload);
    };
  }
});

App.Model = DS.Model.extend({
  lastUpdate: function(){
    var payload = this.toJSON();

    socket.emit('recordUpdated', payload);

    this.save();

    return payload;
  }.observes('isDirty') 
});

Notes

You can use Stalkable for better observation of all properties. This also eliminates need to call save as part of lastUpdate property.

Pooyan Khosravi
  • 4,861
  • 1
  • 19
  • 20
  • op does not want to switch to socket.io but use his existing infrastructure based on spring and websockets. look into stompjs – arisalexis Jul 23 '15 at 19:48