If you are looking for Jitsi Meet, the WebRTC compatible video conferencing product click here.

previous | TOC | next

Implementing a Protocol

OperationSetBasicInstantMessaging.

Why basic? Because in here we only send single messages and receive events for incoming single messages. We don’t have concepts of conversations, chatrooms, rendezvous points or anything of that kind. Other operation sets cover these notions or will cover them one day whenever it is that we happen to need them.

So what it is, again that we do here?

Creating messages and the Message interface.

Since the send methods would take a Message parameter we would first have to implement that one and provide a method that would allow other bundles to instantiate it.

The MessageGibberishImpl implementation does this in a very straight forward manner. It simply keeps a String for the actual message body as well as an identifier, a subject (ofteh ignored), and som other details. Don’t hesitate to go have a look on the class itself.

We instantiate Gibberish messages in the createMessage()methods of the basic instant messaging operation set, like this:

public Message createMessage(byte[] content, String contentType,
                             String contentEncoding, String subject)
{
    return new MessageGibberishImpl(new String(content), contentType
                                   , contentEncoding, subject);
}

public Message createMessage(String messageText)
{
    return new MessageGibberishImpl(messageText, DEFAULT_MIME_TYPE
                                    , DEFAULT_MIME_ENCODING, null);
}

Sending messages.

This is an extremely simple business in general and implementing it would most of the time come down to simply wrapping the sendInstantMessage() method around the one that your stack is offering. In Gibberish this we have it this way:

public void sendInstantMessage(Contact to, Message message) throws
    IllegalStateException, IllegalArgumentException
{
    if( !(to instanceof ContactGibberishImpl) )
       throw new IllegalArgumentException(
           "The specified contact is not a Gibberish contact."
           + to);

    MessageDeliveredEvent msgDeliveredEvt
        = new MessageDeliveredEvent(
            message, to, new Date());

    //first fire an event that we've delivered the message.
    //Note that in a real world protocol implementation we would first wait
    //for a delivery confirmation coming from the protocol stack.
    fireMessageDelivered(message, to);

    //now do message delivery.
    deliverMessage(message, (ContactGibberishImpl)to);
}

Note, (and remember) the comment before the fireMessageDelivered() call.

In a real world implementation the deliverMessage() method would actually be a method coming from the protocol stack that sends the instant message in a protocol specific way. That’s kind of what it does here too:

private void deliverMessage(Message message, ContactGibberishImpl to)
{
    String userID = to.getAddress();

    //if the user id is owr own id, then this message is being routed to us
    //from another instance of the gibberish provider.
    if (userID.equals(this.parentProvider.getAccountID().getUserID()))
    {
        //check who is the provider sending the message
        String sourceUserID
            = to.getProtocolProvider().getAccountID().getUserID();

        //check whether they are in our contact list
        Contact from = opSetPersPresence.findContactByID(sourceUserID);


        //and if not - add them there as volatile.
        if(from == null)
        {
            from = opSetPersPresence.createVolatileContact(sourceUserID);
        }

        //and now fire the message received event.
        fireMessageReceived(message, from);
    }
    else
    {
        //if userID is not our own, try an check whether another provider
        //has that id and if yes - deliver the message to them.
        ProtocolProviderServiceGibberishImpl gibberishProvider
            = this.opSetPersPresence.findProviderForGibberishUserID(userID);
        if(gibberishProvider != null)
        {
            OperationSetBasicInstantMessagingGibberishImpl opSetIM
                = (OperationSetBasicInstantMessagingGibberishImpl)
                    gibberishProvider.getOperationSet(
                        OperationSetBasicInstantMessaging.class);
            opSetIM.deliverMessage(message, to);
        }
        else
        {
            //if we got here then "to" is simply someone in our contact
            //list so let's just echo the message.
            fireMessageReceived(message, to);
        }
    }
}

Reminder: what we want the Gibberish protocol to do is either echo messages back to us or, in case there is another provider registered with the same name as the account we’re writing to, deliver the message to that provider.

This gives us the following three cases in the deliverMessage() method:

  1. Another protocol provider would like to send us a message - in this case we check whether we have them in our contact list and if not we add them as a non-persistent contact, then we deliver the instant message to the user as one being sent from that contact.
  2. The second case is actually the opposite of the first one. The user id that we are trying to deliver the message to is not our own so we try to find whether another provider has that id, if they do, then we call their deliverMessage() method and it would execute its case 1 just as we described it above.
  3. The third case actually handles all the bogus contacts that a user can write to in the Gibberish protocol and it simply echos the message back to the user.

And that’s it!

previous | TOC | next