Livespaces
Livespace Developer Tips

Livespace Development Tips & Gotchas

Threading issues

None of the methods that change Livespaces databeans are thread-safe: this includes setValue (), getValue () and entity registry add and remove methods. This means you may experience variable behaviour if you don't synchronize access to beans/entities that are in a Livespace container due to the fact that Livespace updates are coming in on a separate thread. Variable behaviour most often happens when you have rapidly changing property values.

In general, read operations (getValue ()) don't need to be synchronized, but if you modify a published object, you should hold the lock on the object's container's entity registry first. e.g.


   EntityClient client = new EntityClient (room, elvin, "room");

   client.waitForEntity (1);

   RoomEntity room = (RoomEntity)client.singleton ();

   synchronized (room.mutex ())
   {
      room.setValue ("Description", "A room");
      room.setValue ("Web page", "http://www.livespace.org");
   }

  ...

For user interface applications (i.e. dashboard panels etc), you can reduce or eliminate the need to worry about threading issues by making entity updates occur within the UI thread. This happens automatically for any entity containers created inside the UI thread, and can be enabled for containers in general by using the updateContainerFromUI () method on IDashboard or SWTRuntime. For example:

  // from livespace.ui.clipboard

  IDashboard dashboard = 
    (IDashboard)dependencies.value ("dashboard");
  ClipboardEntity clipboard =
    (ClipboardEntity)dependencies.value ("clipboard");

  // clipboard container was created by
  // SingleEntityDependency class and won't be updated
  // in UI thread unless we do this
  dashboard.updateContainerFromUI (clipboard.container);

  clipboardPanel =
    new ClipboardPanel (dashboard, clipboard);

Using waitForEntity() on the SWT thread

Another gotcha is when creating an EntityClient on the SWT thread. Although EntityContainers on the SWT thread are updated on the SWT thread, if you call .waitForEntity() on your client container, it will block the SWT thread, preventing any updates from Elvin from being executed (as they're pushed onto the end of the SWT queue, which isn't being processed because you're waiting). Attach a listener to the container's EntityRegistry and react to it asynchronously or inject the reference using the Dependency system instead.

Lists

For various reasons lists (e.g. ListDataObject) do not work in distributed data object land. This is due to changes not being idempotent and the fact that list indexes change when you insert or delete items.

For collections of complex objects, you should use EntityRegistry's of Entity-derived objects. This allows the objects in registry set to be identified and addressed by a global ID. For collections of simple objects (strings, numbers, date's, etc, anything that has a defined equals () and hashCode ()) you should use SetDataObject.

For collections where ordering is required, consider using an EntityList. Or, even better, consider whether you really need ordering at the data level or whether the ordering would be better done at the presentation layer.

Reacting to events

When you want to react to changes to an EntityRegistry including additions and removals of Entities as soon as an EntityContainer is created, the easiest way to do this is to create the EntityRegistry the EntityContainer will use and add your listener to it before the EntityContainer is created. You might want to do this when a GUI is showing the available Entities.

EntityRegistry registry = new EntityRegistry ();
registry.addPropertyListener (myListener);
EntityClient client = new EntityClient (elvin, room, "computer", registry);

Programming pessimistically

When you change an Entity property, try to make sure you don't make multiple changes to the same property in quick succession. Because the Livespace protocol is optimistic in that when a client makes a change to a property, it expects the change to be made. If two changes are made in quick succession, the server may miss the second change and revert the property to the first change unexpectedly.

  1. Client changes foo property to "bar".
  2. Server considers the request.
  3. Client changes the foo property to "boo".
  4. Server agrees with the change and responds with foo is now "bar".
  5. Client is now confused - it thought it had changed foo from "bar" to "boo" but now it's "bar" again.