Next, for each message block omnic generates a skeletal leaf
class consisting of nothing but an empty
run()
method. The
developer must modify the
run()
method to perform useful
and appropriate message handling. When a message is received on
an OmniSocket, the socket creates and runs a message object of the
corresponding type. Since the
run()
method is invoked in a
separate thread, you can do just about anything in the message
handler.
As a convenience to the developer, omnic also generates a
skeletal event handler class. The developer must modify the
event handler class file by implementing useful event
methods. The four events supported by the OmniSockets framework are:
socket connection, socket disconnect, message received,
unrecognizable message received. It is not required to implement
all four, you may choose to implement some and ignore others
(i.e. use the default event method implementations in the
OmniEventHandler superclass). If you really wish to do nothing
when an event type occurs, you should modify its event method to
just return.
The following example illustrates just about every feature of mdl.
The FooBar protocol contains just two message types, Foo and Bar.
When compiled with the command
``omnic.pl -l -e -c -f FooBar.mdl
'',
five Java source and 2 byte code files are generated. Byte code
is generated for the Foo and Bar base message classes, which are
ready to use without modification by the developer. The other 5
files are skeletal source code which the developer must edit to
perform useful and appropriate actions.
The first file is FooBase.java. The compiler generates import
statements as follows. First it copies all global import
statements (in this case there is a single global import,
java.net.*), then all local import statmements are copied (in
this case there is a single local import, java.util.BitSet),
then the omnisockets.OmniMessage class is imported automatically (do
not include a global or local import statement for
omnisockets.OmniMessage). Once the import statements are written,
omnic generates an abstract base class for message type Foo.
Data members seq, bitmap and url are written to FooBase.java,
public acccess methods are also written. Finally the
toString()
method is written.
/*
* This file was generated by omnic version 1.0.beta.1
* on Wed Dec 4 22:30:13 2002.
* Do not modify.
*/
import java.net.*;
import java.util.BitSet;
import omnisockets.OmniMessage;
public abstract class FooBase extends OmniMessage {
private int seq;
public int getSeq() { return seq; }
public void setSeq(int v) { seq = v; }
private BitSet bitmap;
public BitSet getBitmap() { return bitmap; }
public void setBitmap(BitSet v) { bitmap = v; }
private URL url;
public URL getUrl() { return url; }
public void setUrl(URL v) { url = v; }
public String toString() {
return "Foo[" + seq + ":" + bitmap + ":" + url + "]";
}
}
Figure 3. FooBase.java
Then omnic generates a skeletal Foo class consisting of nothing
but an empty
run()
method. You must modify the
run()
method of the Foo class to handle received messages of type
Foo. Note that when the compiler is invoked, it checks for the
existance of the Foo.java file, and if so won't overwrite it by
default. Thus, if you change the mdl file and rerun omnic, it
will not destroy any of your modified files. BTW, you can force
the compiler to overwrite leaf classes with the -f option.
/*
* This file was generated by omnic version 1.0.beta.1
* on Wed Dec 4 22:30:14 2002.
*/
import omnisockets.*;
public class Foo extends FooBase {
/**
* The OmniSocket runs this message handler in a thread
* when a message of type Foo
is received.
*/
public void run() {
}
}
Figure 4. Foo.java
The same procedure is repeated for the Bar message block.
First, file BarBase.java is created. Omnic copies the global
import java.net.* and the default import omnisockets.OmniMessage (there
are no local import statmements in the Bar block), then
generates an abstract FooBase class with data members flag and
inaddr, their public acccess methods, and a
toString()
method.
/*
* This file was generated by omnic version 1.0.beta.1
* on Wed Dec 4 23:22:53 2002.
* Do not modify.
*/
import java.net.*;
import omnisockets.OmniMessage;
public abstract class BarBase extends OmniMessage {
private boolean flag;
public boolean getFlag() { return flag; }
public void setFlag(boolean v) { flag = v; }
private InetAddress inaddr;
public InetAddress getInaddr() { return inaddr; }
public void setInaddr(InetAddress v) { inaddr = v; }
public String toString() {
return "Bar[" + flag + ":" + inaddr + "]";
}
}
Figure 5. BarBase.java
Then, omnic generates a skeletal Bar class,
which like Foo.java above, contains nothing by an empty
run()
method.
/*
* This file was generated by omnic version 1.0.beta.1
* on Wed Dec 4 22:30:15 2002.
*/
import omnisockets.*;
public class Bar extends BarBase {
/**
* The OmniSocket runs this message handler in a thread
* when a message of type Bar
is received.
*/
public void run() {
}
}
Figure 6. Bar.java
Lastly, omnic generates a skeletal FooBar event handler
class. Objects of this class are created and run by the OmniSockets
framework whenever a socket event occurs. The generated event
handler class consists of 7 methods. The
run()
method is first
invoked when the event handler thread is started. The
super.run()
method implemented in OmniEventHandler simply
switches on event code and calls one of four other
methods.
Connected()
,
disconnected()
,
message()
or
badMessage()
,
corresponding to generated events.
Connected()
and
disconnected()
methods are self explanatory.
The message()
method is called when any OmniMessage is received by an
OmniSocket; you probably don't want to place type specific code
here, rather any generic processing like message logging is
appropriate for this method. The
badMessage()
method is called when an unrecognizable message is received on
an OmniSocket. Your handler can obtain the source IP address and
port, but unfortunately bad message data is not available for
examination. The final two methods (the class constructor and
the clone()
method) must not by modified by the developer.
/*
* This file was generated by omnic version 1.0.beta.1
* on Wed Dec 4 23:22:54 2002.
*/
import omnisockets.*;
public class FooBarEventHandler extends OmniEventHandler {
/**
* The OmniSockets framework runs this event handler in
* a thread when an OmniSockets framework event occurs.
* You MAY modify or delete this method.
*/
public void run() {
super.run();
}
/**
* Overrides the default CONNECT event handler.
* You MAY modify or delete this method.
*/
public void connected() {
super.connected();
}
/**
* Overrides the default DISCONNECT event handler.
* You MAY modify or delete this method.
*/
public void disconnected() {
super.disconnected();
}
/**
* Overrides the default MESSAGE event handler.
* You MAY modify or delete this method.
*/
public void message() {
super.message();
}
/**
* Overrides the default BAD_MESSAGE event handler.
* You MAY modify or delete this method.
*/
public void badMessage() {
super.badMessage();
}
/**
* Constructs a new event handler.
* You MUST NOT modify this method.
*/
public FooBarEventHandler(Object cookie) {
super(cookie);
}
/**
* Clones an event handler.
* You MUST NOT modify this method.
*
* @return a duplicate FooBarEventHandler instance.
*/
public Object clone() {
return (Object) new FooBarEventHandler(getCookie());
}
}
Figure 7. FooBarEventHandler.java