Parse the Command Line Arguments
To see how to parse command line arguments, refer to the code in Appendix G, CrnpClient.java Application.
Define the Event Reception Thread
In the code, you need to ensure that event reception is performed in a separate thread so that your application can continue to do other work while the event thread blocks and waits for event callbacks.
Note - Setting up the XML is discussed later.
In your code, define a Thread subclass called EventReceptionThread that creates a ServerSocket and waits for events to arrive on the socket.
In this part of the example code, events are neither read nor processed. Reading and processing events are discussed later. The EventReceptionThread creates a ServerSocket on a wildcard internetworking protocol address. EventReceptionThread also keeps a reference to the CrnpClient object so that EventReceptionThread can send events to the CrnpClient object to process.
class EventReceptionThread extends Thread { public EventReceptionThread(CrnpClient clientIn) throws IOException { client = clientIn; listeningSock = new ServerSocket(client.localPort, 50, InetAddress.getLocalHost()); } public void run() { try { DocumentBuilder db = client.dbf.newDocumentBuilder(); db.setErrorHandler(new DefaultHandler()); while(true) { Socket sock = listeningSock.accept(); // Construct event from the sock stream and process it sock.close(); } // UNREACHABLE } catch (Exception e) { System.out.println(e); System.exit(1); } } /* private member variables */ private ServerSocket listeningSock; private CrnpClient client; }Now that you see how the EventReceptionThread class works, construct an createEvtRecepThr object:
private void createEvtRecepThr() throws Exception { evtThr = new EventReceptionThread(this); evtThr.start(); }
Register and Unregister Callbacks
The registration task consists of:
Opening a basic TCP socket to the registration internetworking protocol and port
Constructing the XML registration message
Sending the XML registration message on the socket
Reading the XML reply message off the socket
Closing the socket
Create the Java code that implements the preceding logic.
The following example shows the implementation of the registerCallbacks method of the CrnpClient class (which is called by the CrnpClient constructor). The calls to createRegistrationString() and readRegistrationReply() are described in more detail later.
regIp and regPort are object members that are set up by the constructor.
private void registerCallbacks() throws Exception { Socket sock = new Socket(regIp, regPort); String xmlStr = createRegistrationString(); PrintStream ps = new PrintStream(sock.getOutputStream()); ps.print(xmlStr); readRegistrationReply(sock.getInputStream(); sock.close(); }Implement the unregister method. This method is called by the shutdown method of CrnpClient. The implementation of createUnregistrationString is described in more detail later.
private void unregister() throws Exception { Socket sock = new Socket(regIp, regPort); String xmlStr = createUnregistrationString(); PrintStream ps = new PrintStream(sock.getOutputStream()); ps.print(xmlStr); readRegistrationReply(sock.getInputStream()); sock.close(); }
Generate the XML
Now that you have set up the structure of the application and have written all the networking code, you write the code that generates and parses the XML. Start by writing the code that generates the SC_CALLBACK_REG XML registration message.
An SC_CALLBACK_REG message consists of a registration type (ADD_CLIENT, REMOVE_CLIENT, ADD_EVENTS, or REMOVE_EVENTS), a callback port, and a list of events of interest. Each event consists of a class and a subclass, followed by a list of name and value pairs.
In this part of the example, you write a CallbackReg class that stores the registration type, callback port, and list of registration events. This class also can serialize itself to an SC_CALLBACK_REG XML message.
An interesting method of this class is the convertToXml method, which creates an SC_CALLBACK_REG XML message string from the class members. The JAXP documentation at http://java.sun.com/xml/jaxp/index.html describes the code in this method in more detail.
The implementation of the Event class is shown below. Note that the CallbackReg class uses an Event class that stores one event and can convert that event to an XML Element.
Create the Java code that implements the preceding logic.
class CallbackReg { public static final int ADD_CLIENT = 0; public static final int ADD_EVENTS = 1; public static final int REMOVE_EVENTS = 2; public static final int REMOVE_CLIENT = 3; public CallbackReg() { port = null; regType = null; regEvents = new Vector(); } public void setPort(String portIn) { port = portIn; } public void setRegType(int regTypeIn) { switch (regTypeIn) { case ADD_CLIENT: regType = "ADD_CLIENT"; break; case ADD_EVENTS: regType = "ADD_EVENTS"; break; case REMOVE_CLIENT: regType = "REMOVE_CLIENT"; break; case REMOVE_EVENTS: regType = "REMOVE_EVENTS"; break; default: System.out.println("Error, invalid regType " + regTypeIn); regType = "ADD_CLIENT"; break; } } public void addRegEvent(Event regEvent) { regEvents.add(regEvent); } public String convertToXml() { Document document = null; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.newDocument(); } catch (ParserConfigurationException pce) { // Parser with specified options can't be built pce.printStackTrace(); System.exit(1); } // Create the root element Element root = (Element) document.createElement( "SC_CALLBACK_REG"); // Add the attributes root.setAttribute("VERSION", "1.0"); root.setAttribute("PORT", port); root.setAttribute("regType", regType); // Add the events for (int i = 0; i < regEvents.size(); i++) { Event tempEvent = (Event) (regEvents.elementAt(i)); root.appendChild(tempEvent.createXmlElement( document)); } document.appendChild(root); // Convert the whole thing to a string DOMSource domSource = new DOMSource(document); StringWriter strWrite = new StringWriter(); StreamResult streamResult = new StreamResult(strWrite); TransformerFactory tf = TransformerFactory.newInstance(); try { Transformer transformer = tf.newTransformer(); transformer.transform(domSource, streamResult); } catch (TransformerException e) { System.out.println(e.toString()); return (""); } return (strWrite.toString()); } private String port; private String regType; private Vector regEvents; }Implement the Event and NVPair classes.
Note that the CallbackReg class uses an Event class, which itself uses an NVPair class.
class Event { public Event() { regClass = regSubclass = null; nvpairs = new Vector(); } public void setClass(String classIn) { regClass = classIn; } public void setSubclass(String subclassIn) { regSubclass = subclassIn; } public void addNvpair(NVPair nvpair) { nvpairs.add(nvpair); } public Element createXmlElement(Document doc) { Element event = (Element) doc.createElement("SC_EVENT_REG"); event.setAttribute("CLASS", regClass); if (regSubclass != null) { event.setAttribute("SUBCLASS", regSubclass); } for (int i = 0; i < nvpairs.size(); i++) { NVPair tempNv = (NVPair) (nvpairs.elementAt(i)); event.appendChild(tempNv.createXmlElement( doc)); } return (event); } private String regClass, regSubclass; private Vector nvpairs; } class NVPair { public NVPair() { name = value = null; } public void setName(String nameIn) { name = nameIn; } public void setValue(String valueIn) { value = valueIn; } public Element createXmlElement(Document doc) { Element nvpair = (Element) doc.createElement("NVPAIR"); Element eName = doc.createElement("NAME"); Node nameData = doc.createCDATASection(name); eName.appendChild(nameData); nvpair.appendChild(eName); Element eValue = doc.createElement("VALUE"); Node valueData = doc.createCDATASection(value); eValue.appendChild(valueData); nvpair.appendChild(eValue); return (nvpair); } private String name, value; }



