Real-time capabilities

Introduction

In the current world, accessibility to information is crucial. Moreover, it’s not only important to have the information available, but when it’s available has gained great importance; the time to access new information is a key factor that many companies heavily rely on. To address this issue, Carbon LDP™ provides real-time capabilities in its platform.

To use real-time features, the platform instance must have access to a message broker.
If you haven’t configured your instance to do so, read this guide to learn how to do it:
Configuring the platform

Connecting to the broker

The platform uses WebSocket communication to allow for real-time message transmission with clients. Furthermore, it uses the Simple Text Oriented Messaging Protocol (STOMP) to compose its messages. Therefore, whichever client connects to the broker needs to be able to understand this protocol.

You can connect your WebSocket client to the broker through this address: ws://localhost:8083/broker/websocket.

What is more, the platform also exposes a SockJS endpoint for clients to connect to. It is located in the following address: http://localhost:8083/broker.

In conclusion, to be able to work with Carbon LDP™’s real-time features you will need to write your own WebSocket or SockJS client, capable of receiving STOMP messages.

Subscribing to events

The real-time capabilities that Carbon LDP™ provides come in the form of subscriptions to events that occur within the platform. Carbon LDP™ uses an Advanced Message Queuing Protocol (AMQP) implementation as a broker relay, so whenever you want to subscribe to an event you’ll use a path similar to this:

/topic/{event-target}.{event-type}.{document-slug-1}.{document-slug-n}

To subscribe to any event, then, you first need to identify two main things: the event you’re going to subscribe to, and the subject (document) you are interested in.

With this in mind, let’s continue detailing our subscription process.

To specify the event, Carbon LDP™ provides a series of predefined events that it can subscribe to; such events are the following:

Child created
Whenever a subject’s child is created.
Document modified
Whenever any of a document’s properties are modified.
Document deleted
Whenever a document is deleted.
Member added
Whenever a new member is added to a document.
Member removed
Whenever an existing member is removed from a document.

To subscribe to any of these events you need to include them on your subscription path in the following way:

Event Event target Event type Sample path
Child created child created /topic/child.created.{...}
Document modified document modified /topic/document.modified.{...}
Document deleted document deleted /topic/document.deleted.{...}
Member added member added /topic/document.added.{...}
Member removed member removed /topic/document.removed.{...}

Depending on the type of event you are subscribed to, the return messages will differ. You should always expect a bNode, containing the type of event that triggered the message emission. Also, every message received will include a c:target property, detailing the subject you’re subscribed to, which caused the event notification.

Moreover, if the event type was one of c:ChildCreatedEvent, c:MemberAddedEvent, or c:MemberRemovedEvent, the message will also include a c:details property pointing to a new bNode. This bNode will have a specific type and properties.

Take a look at the following table to get all the details regarding the structure of the messages you might receive, based on the type of event you’re subscribed to.

Event type Return message model
Child created
  • type:c:ChildCreatedEvent
  • c:target: Contains the subject of the document you’re subscribed to which triggered the notification.
  • c:details: Points to another resource, containing specific event details.
    • type:c:DocumentCreatedEventDetails
    • c:createdDocument: Contains the subject of the recently created document.
Document modified
  • type:c:DocumentModifiedEvent
  • c:target: Contains the subject of the document you’re subscribed to which triggered the notification.
Document deleted
  • type:c:DocumentDeletedEvent
  • c:target: Contains the subject of the document you’re subscribed to which triggered the notification.
Member added
  • type:c:MemberAddedEvent
  • c:target: Contains the subject of the document you’re subscribed to which triggered the notification.
  • c:details: Points to another resource, containing specific event details.
    • type:c:MemberAddedEventDetails
    • c:member: Contains the subject of the document recently added as a member of another document.
Member removed
  • type:c:MemberRemovedEvent
  • c:target: Contains the subject of the document you’re subscribed to which triggered the notification.
  • c:details: Points to another resource, containing specific event details.
    • type:c:MemberRemovedEventDetails
    • c:member: Contains the subject of the document recently removed from another document’s members.

Alternatively, on the subscription path you could also include an asterisk (*) as a wild card for an event target or an event type. This will allow you to subscribe to multiple event types with a single subscription path.

For example, if you wanted to monitor a document’s member events, both a member addition and a member removal, you could use a path similar to this:

/topics/member.*.{...}

In addition, if you wanted to monitor all possible events that could occur within a document, you could use a path similar to this:

/topic/*.*.{...}

Be careful since this could cause that a single action emits messages of different types within a single subscription. For example, when creating a child document you would expect to receive a notification of type c:ChildCreatedEvent; however, creating a child also adds that document as a member of its parent. Therefore, a child creation would also emit a message of type c:MemberAddedEvent; which you would be listening to using the last subscription path we detailed.

Now, let’s review how you would determine which subject you want to subscribe to.

Subject

Now, we need to determine which subject we will be subscribing to. While you can specify a particular resource to subscribe to, you can also use certain wild cards in your subscription path to subscribe to all the resource contained in or below a specific level.

These are the following structures you can use to detail your subscription’s subject:

  • document-slug: indicates a particular resource.
    E.g. /topics/{event-target}.{event-type}.projects means events that happen on the projects/ document.
  • *: indicates any resource on that specific level.
    E.g. /topics/{event-target}.{event-type}.projects.* means events that happen one level below the projects/ document.
  • #: indicates any resource below that specific level.
    E.g. /topics/{event-target}.{event-type}.projects.# means events that happen on any level below the projects/ document.

In order to subscribe to an application’s root document, you would simply omit including a subject within your subscription path, i.e. /topic/{event-target}.{event-type}.

Also, since dots (.) are reserved characters in AMQP paths, they need to be replaced in your subscription path with a caret (^). For example, if your platform contained a .private/ document, your subscription path would be /topic/{event-target}.{event-type}.^private

Putting it all together

Let’s use an example to better explain this topic. Imagine that you have a company and that you have defined the following structure in your platform instance:

  • /
    Your platform’s root (usually http://your-platform-domain:8083/)
    • clients/
      The document that contains the clients
      • client-1/
        Document defining client 1 properties
      • client-2/
        Document defining client 2 properties
      • client-n…/
        And so on…
    • department/
      Document that contains the departments of your company
    • etc…
      Other aspects your company has

First, let’s imagine you want to know whenever a client is added to your company so that you can perform some adjustments to the company’s budget.

In this case, since we want to know whenever a client is added to our clients list, let’s subscribe to the clients/ document, which contains all the clients as children. This is our subscription’s subject.

Furthermore, we want to be notified whenever a child is created within the clients/ container, therefore, we are subscribing to a child created event.

Our final subscription path would look like this: /topics/child.created.clients.

Finally, the payload received will look similar to this:

[
    {
        "@id" : "_:node1cqm2c7pax250",
        "@type" : [ "https://carbonldp.com/ns/v1/platform#ChildCreatedEvent" ],
        "https://carbonldp.com/ns/v1/platform#details" : [ {
        "@id" : "_:node1cqm2c7pax251"
        } ],
        "https://carbonldp.com/ns/v1/platform#target" : [ {
        "@id" : "http://localhost:8083/clients/"
        } ]
    }, {
        "@id" : "_:node1cqm2c7pax251",
        "@type" : [ "https://carbonldp.com/ns/v1/platform#DocumentCreatedEventDetails" ],
        "https://carbonldp.com/ns/v1/platform#createdDocument" : [ {
        "@id" : "http://localhost:8083/clients/client-3/"
        } ]
    }
]

In a separate situation, let’s now imagine that you also want to monitor whenever a client document is altered, this means modified or removed, to alter a contact list contained in a separate service.

Here, we want to monitor all the resources contained in the clients/ document, therefore, we could use a wild card to subscribe to that specific level.

Also, we are looking for different event types that are related to documents, so we could also add a wild card when defining the event type in our subscription.

In the end, our subscription path would look like this: /topics/document.*.clients.*.

A message received due to this subscription will look similar to this:

[
    {
        "@id" : "_:node1cqm2c7pax331",
        "@type" : [ "https://carbonldp.com/ns/v1/platform#DocumentModifiedEvent" ],
        "https://carbonldp.com/ns/v1/platform#target" : [ {
        "@id" : "http://localhost:8083/clients/client-1/"
        } ]
    }
]

Conclusion

By developing a WebSocket or SockJS client capable of handling STOMP messages, you can receive notifications whenever events occur in your Carbon LDP™ platform thanks to its real-time capabilities.

A subscription can be created using a AMQP path detailing the event target, event type, and an optional document path.

Subscription paths support the use of wild cards to subscribe to multiple event types and/or multiple levels of an endpoint. Bear in mind that this might lead to multiple messages being emitted on a single subscription from a single action.

Normally, developers will prefer use of the Carbon LDP™ Workbench (GUI) and an SDK, which together simplify the process of building and working with the platform. Still, all functions of the platform can be accessed through the REST API and those developers who understand the REST API may find it advantageous to use in some cases.