Creating Your Own Message Types


SmartSockets comes with many predefined standard message types, such as NUMERIC_DATA. These standard message types are described in detail the TIBCO SmartSockets User’s Guide.

When there is no standard message type to satisfy a requirement of your application, you can create your own (called a user-defined message type). Once you create it, the user-defined message type is handled in the same manner as a standard message type. To create a user-defined message type, use the TipcSvc.createMt method. This example creates a message type named XYZ_COORD_DATA with fields (X, Y, and Z coordinates) that are 4-byte integers:

// type number must be greater than zero 
static final int XYZ_COORD_DATA = 1001; 
try { 
    TipcMt xyzMt = TipcSvc.createMt("xyz_coord_data", 
                        XYZ_COORD_DATA, "int4 int4 int4"); 
    if (null == xyzMt) { 
      // error 
    } catch (TipcException e) { 
      // message type already exists or other error 
    } 

A message type is a template for a specific kind of message. Once the message type is created, any number of messages of that type can be created. The first argument to TipcSrv.createMt is the message type name, which should be an identifier (String). The second argument is the message type number, which is a signed four-byte integer (int). Message type numbers less than one are reserved for SmartSockets standard message types. The standard SmartSockets message types use similar names and numbers (for example, the message type with the name numeric_data has a defined number TipcMt.NUMERIC_DATA). The third argument to TipcMtCreate is the message type grammar, used to identify the layout of fields in messages that use this message type.

The message grammar consists of a list of field types. Each field type in the grammar corresponds to one field in the message. For example, the standard message type TIME has a grammar of real8, which defines the first and only field as being an eight-byte real number. The table lists the primitive types that can appear as a field in the grammar of a standard or user-defined message type. Comments (delimited by /* */ or (* *)) are also allowed in the grammar.

Field Type
Meaning
binary
non restrictive array of characters (such as an entire data structure or the entire contents of a file)
char
1-byte integer
int2
2-byte integer
int2_array
array of int2
int4
4-byte integer
int4_array
array of int4
int8
8-byte integer
int8_array
array of int8
msg
a message
msg_array
array of msg
real4
4-byte real number
real4_array
array of real4
real8
8-byte real number
real8_array
array of real8
str
a C string (’\0’-terminated array of characters)
str_array
array of str
xml
xml object

Occasionally, message types use a repetitive group of fields. For example, the NUMERIC_DATA message type allows zero or more name-value pairs. Curly braces ({}) can be used in the message type grammar to indicate such a group. The grammar for the NUMERIC_DATA message type is "{ id real8 }" and the grammar for HISTORY_STRING_DATA is "real8 { id str }". Groups must be at the end of the message type grammar and only one group is allowed per grammar.

Sample Programs

This section contains complete sample programs for creating, sending, reading, and processing a user-defined message type called XYZ_COORD_DATA.

Step 28

Copy the snd_umsg.java and rcv_umsg.java programs

Copy snd_umsg.java and rcv_umsg.java into your working directory.

This program creates and sends messages of user-defined type XYZ_COORD_DATA:

//---------------------------------------------------------------- 
// snd_umsg.java - create and send a series of messages of  
// user-defined type XYZ_COORD_DATA 
 
1 import java.io.*; 
2 import com.smartsockets.*; 
 
3 public class snd_umsg { 
4   private static final int XYZ_COORD_DATA = 1001; 
 
5  public static void main(String[] argv) { 
     try { 
       // set the ss.project 
6      Tut.setOption("ss.project", "smartsockets"); 
 
       // get handle to the RTserver 
7      TipcSrv srv = TipcSvc.getSrv(); 
 
8      if (!srv.create()) { 
9        Tut.exitFailure("Couldn't connect to RTserver!"); 
       }   // if 
   
       // define new message type 
10     TipcMt mt = null; 
       try { 
11       mt = TipcSvc.createMt("xyz_coord_data", XYZ_COORD_DATA, 
                              "int4 int4 int4"); 
12    } catch (TipcException e) { 
13       Tut.exitFailure("Message type already exists!"); 
14    } // catch 
 
      // create a nessage of type XYZ_COORD_DATA 
15    TipcMsg msg = TipcSvc.createMsg(mt); 
 
      // set message destination 
16    msg.setDest("/ss/tutorial/lesson4"); 
 
17    for (int i = 0; i < 30; i += 3) { 
        // in order to re-use message, reset number of fields to 0 
18      msg.setNumFields(0); 
19      msg.appendInt4(i); 
20      msg.appendInt4(i + 1); 
21      msg.appendInt4(i + 2); 
 
       // send and flush the message 
22     srv.send(msg); 
23     srv.flush(); 
    } // for 
 
      // disconnect from RTserver 
24    srv.destroy(); 
    } catch (TipcException e) { 
25    Tut.fatal(e); 
    } // catch 
  } // main 
} // snd_umsg 

Let’s examine some of the key lines in this program:

Line 4
Defines the unique number that identifies the new message type. This number must be used consistently in all programs that reference the user-defined message type.
Line 11
Creates the new message type. This call to TipcMtCreate must be included in all programs that refer to the new message type.
Line 15
Creates a message of type XYZ_COORD_DATA.
Lines 17-21
Build the data part of the new message.

This program publishes a series of ten XYZ_COORD_DATA messages.

Step 29

Compile the snd_umsg.java program

Compile the sending user-message program, snd_umsg.java, program using the command:

$ javac snd_umsg.java  

You now need a program to read and process the messages of the new XYZ_COORD_DATA type. This program also needs to create the message type. It also needs to define a process callback for the new message type. This is an example of the receiving user-message program, rcv_umsg.java program:

//----------------------------------------------------------------- 
// rcv_umsg.java -- display contents of received user-defined 
// messages (type XYZ_COORD_DATA) 
 
1 import java.io.*; 
2 import com.smartsockets.*; 
 
3 public class rcv_umsg { 
4   static final int XYZ_COORD_DATA = 1001; 
 
5    public class processXYZ implements TipcProcessCb { 
 
6      public void process(TipcMsg msg, Object arg) { 
7        System.out.println("Received XYZ_COORD_DATA message"); 
 
        // position the field ptr to the beginning of the message 
        try { 
8          msg.setCurrent(0); 
9       } catch (TipcException e) { 
10         Tut.fatal(e); 
       } // catch 
 
       // traverse message; print value from each field 
       try { 
11       int field_value = msg.nextInt4(); 
12       System.out.println("Field 1 Value = " + field_value); 
13       field_value = msg.nextInt4(); 
14       System.out.println("Field 2 Value = " + field_value); 
15       field_value = msg.nextInt4(); 
16       System.out.println("Field 3 Value = " + field_value); 
17     } catch (TipcException e) {  
18       Tut.warning("Expected 3 fields--bad XYZ_COORD_DATA!\n"); 
      } // catch 
    } // process 
  } // processXYZ 
 
19 public class processDefault implements TipcDefaultCb { 
 
20  public void handle(TipcMsg msg, Object arg) { 
21    System.out.println("Receive: unexpected message type name" + 
       " is <" + msg.getType().getName() + ">"); 
    } // handle 
   } // processDefault 
 
22 public rcv_umsg() { 
23  TipcMsg msg = null; 
 
    try { 
      // set the ss.project 
24    Tut.setOption("ss.project", "smartsockets"); 
 
      // get handle to the RTserver 
25    TipcSrv srv=TipcSvc.getSrv(); 
 
      // define new message type 
26    TipcMt mt = null; 
      try { 
27      mt = TipcSvc.createMt("xyz_coord_data", XYZ_COORD_DATA, 
                              "int4 int4 int4"); 
28      } catch (TipcAlreadyExistsException e) { 
29        Tut.exitFailure("Message type already exists!"); 
      } // catch 
 
        // create a new receive listener and register it 
30      processXYZ pcb = new processXYZ(); 
31      TipcCb ph = srv.addProcessCb(pcb, mt, srv); 
      // check the 'handle' returned for validity 
32    if (null == ph) { 
33      Tut.exitFailure("Couldn't register processXYZ listener!"); 
      } // if 
 
      // create and register default listener 
34    processDefault dcb = new processDefault(); 
35    TipcCb dh = srv.addDefaultCb(dcb, srv); 
 
      // check the 'handle' returned for validity 
36      if (null == dh) { 
37        Tut.exitFailure("Couldn't register default listener!"); 
      } // if 
 
      // connect to RTserver 
38      if (!srv.create()) { 
39        Tut.exitFailure("Couldn't connect to RTserver!"); 
      } // if 
   
       // subscribe to the appropriate subject 
40     srv.setSubjectSubscribe("/ss/tutorial/lesson4", true); 
 
       // read and process all incoming messages 
41     while (srv.mainLoop(TipcDefs.TIMEOUT_FOREVER)) { 
     } // while 
 
       // unregister the listeners for completeness 
42     srv.removeProcessCb(ph); 
43     srv.removeDefaultCb(dh); 
 
       // disconnect from RTserver 
44     srv.destroy(); 
45   } catch (TipcException e) { 
46     Tut.fatal(e); 
    } // catch 
  } // rcv_umsg (constructor) 
 
47 public static void main(String[] argv) { 
48  new rcv_umsg(); 
   } // main 
 } // rcv_umsg class 

Let’s examine the key lines of this program:

Line 4
Defines the unique number that identifies the new message type. This number must be used consistently in all programs that use the user-defined message type.
Line 27
Creates the new message type. This call to TipcMtCreate must be included in all programs that refer to the new message type.
Line 31
Registers the process callback to be used for messages of type XYZ_COORD_DATA.
Lines 6-18
This method is invoked when a message of type XYZ_COORD_DATA needs to be processed. It prints out the three numbers in the data part of the message.

Step 30

Compile the rcv_umsg.java program

Compile the rcv_umsg.java program using the command:

$ javac rcv_umsg.java 

Step 31

Start the receiving user-message program

Start the receiving user-message program in one window of your display using the command:

$ java rcv_umsg 

Step 32

Use the new sending user-message program to send messages

In another window, send a series of XYZ_COORD_DATA messages to the receiving user-message program, using the sending user-message program with the command:

$ java snd_umsg 

When you start the sending user-message program, this output is displayed in the window where the receiving user-message program is being run:

Received XYZ_COORD_DATA message 
Field 1 Value = 0 
Field 2 Value = 1 
Field 3 Value = 2 
Received XYZ_COORD_DATA message 
Field 1 Value = 3 
Field 2 Value = 4 
Field 3 Value = 5 
Received XYZ_COORD_DATA message 
Field 1 Value = 6 
Field 2 Value = 7 
Field 3 Value = 8 
. 
. 
. 
Received XYZ_COORD_DATA message 
Field 1 Value = 27 
Field 2 Value = 28 
Field 3 Value = 29 

When the sending user-message program has completed, notice that the receiving user-message program is still hanging. It is waiting for more messages.

Step 33

Interrupt the receiving user-message program

Type Ctrl-c to interrupt the receiving user-message program.


TIBCO SmartSockets™ Java Library User’s Guide and Tutorial
Software Release 6.8, July 2006
Copyright © TIBCO Software Inc. All rights reserved
www.tibco.com