
[[writing]]
== Writing protocols

This chapter discusses how to write custom protocols.
    
=== Writing user defined headers

Headers are mainly used by protocols, to ship additional information around with a message, without
having to place it into the payload buffer, which is often occupied by the application already. However,
headers can also be used by an application, e.g. to add information to a message, without having to
squeeze it into the payload buffer.
        
A header has to extend `org.jgroups.Header`, have an empty public constructor and implement the
`Streamable` interface (`writeTo()` and `readFrom()` methods).
        
A header should also override `size()`, which returns the total number of bytes taken up in the
output stream when an instance is marshalled using Streamable. Streamable is an interface for
efficient marshalling with methods


[source,java]
----
public interface Streamable {

    /** Write the entire state of the current object (including superclasses)
        to outstream. Note that the output stream must not be closed */
    void writeTo(DataOutput out) throws IOException;

    /** Read the state of the current object (including superclasses) from
        instream. Note that the input stream must not be closed */
    void readFrom(DataInput in) throws IOException,
                                       IllegalAccessException,
                                       InstantiationException;
}
----

Method `writeTo()` needs to write all relevant instance variables to the output stream and `readFrom()` needs
to read them back in.

It is important that `size()` returns the correct number of bytes, because some components (such a message
bundling in the transport) depend on this, as they need to measure the exact number of bytes before sending
a message. If size() returns fewer bytes than what will actually be written to the stream, then it is
possible that (if we use UDP with a 65535 bytes maximum) the datagram packet is dropped by UDP!

The final requirement is to add the newly created header class to `jg-magic-map.xml` (in the `./conf` directory),
or - if this is not a JGroups internal protocol - to add the class to `ClassConfigurator`. This can be done
with method
        
[source,java]
----
ClassConfigurator.add((short) 1889, MyHeader.class);
----

The code below shows how an application defines a custom header, `MyHeader`, and uses it to attach additional
information to message sent (to itself):
        
[source,java]
----
public class bla {

    public static void main(String[] args) throws Exception {
        JChannel ch=new JChannel();
        ch.connect("demo");
        ch.setReceiver(new ReceiverAdapter() {
            public void receive(Message msg) {
                MyHeader hdr=(MyHeader)msg.getHeader("x");
                System.out.println("-- received " + msg +
                                   ", header is " + hdr);
            }
        });

        ClassConfigurator.add((short)1900, MyHeader.class);

        int cnt=1;
        for(int i=0; i < 5; i++) {
            Message msg=new Message();
            msg.putHeader((short)1900, new MyHeader(cnt++));
            ch.send(msg);
        }
        ch.close();
    }


    public static class MyHeader extends Header implements Streamable {
        int counter=0;

        public MyHeader() {
        }

        private MyHeader(int counter) {
            this.counter=counter;
        }

        public String toString() {
            return "counter=" + counter;
        }

        public int size() {
            return Global.INT_SIZE;
        }

       public void writeTo(DataOutputStream out) throws IOException {
            out.writeInt(counter);
       }

       public void readFrom(DataInputStream in) throws IOException,
                                                       IllegalAccessException,
                                                       InstantiationException {
            counter=in.readInt();
       }
    }
}
----

The `MyHeader` class has an empty public constructor and implements the `writeExternal()` and `readExternal()`
methods with no-op implementations.
        

The state is represented as an integer counter. Method `size()` returns 4 bytes (`Global.INT_SIZE`),
which is the number of bytes written by `writeTo()` and read by `readFrom()`.
        

Before sending messages with instances of `MyHeader` attached, the program registers the MyHeader class with
the `ClassConfigurator`. The example uses a magic number of 1900, but any number greater than 1024 can
be used. If the magic number was already taken, an IllegalAccessException would be thrown.
        

The final part is adding an instance of MyHeader to a message using `Message.putHeader()`. The first argument
is a name which has to be unique across all headers for a given message. Usually, protocols use the protocol
name (e.g. "UDP", "NAKACK"), so these names should not be used by an application. The second argument is
an instance of the header.

Getting a header is done through `Message.getHeader()` which takes the name as argument. This name of course
has to be the same as the one used in `putHeader()`.
        

