Sun Cluster Entwicklerhandbuch Datendienste für Solaris OS

Erstellen einer Java-Anwendung, die CRNP verwendet

Das folgende Beispiel zeigt, wie eine einfache Java-Anwendung mit dem Namen CrnpClient, die das CRNP verwendet, entwickelt werden kann. Die Anwendung wird für Ereignisrückmeldungen bei dem CRNP-Server auf dem Cluster registriert, hört Ereignisrückmeldungen ab und verarbeitet die Ereignisse, indem sie deren Inhalt druckt. Vor der Beendigung deregistriert die Anwendung ihre Anforderung von Ereignisrückmeldungen.

Beachten Sie folgende Punkte beim Untersuchen des vorliegenden Beispiels.

Konfigurieren der Umgebung

Zunächst muss die Umgebung konfiguriert werden.

  1. Laden Sie JAXP und die richtige Version des Java-Compilers und der Virtual Machine herunter, und installieren Sie sie.

    Anweisungen hierzu finden Sie unter http://java.sun.com/xml/jaxp/index.html.


    Hinweis –

    Für dieses Beispiel ist Java 1.3.1 bzw. eine höhere Java-Version erforderlich.


  2. Vergewissern Sie sich, dass Sie einen classpath in der Kompilierungsbefehlszeile angegeben haben, damit der Compiler die JAXP-Klassen finden kann. Geben Sie vom Verzeichnis der Quelldatei aus Folgendes ein:


    % javac -classpath JAXP_ROOT/dom.jar:JAXP_ROOTjaxp-api. \
    jar:JAXP_ROOTsax.jar:JAXP_ROOTxalan.jar:JAXP_ROOT/xercesImpl \
    .jar:JAXP_ROOT/xsltc.jar -sourcepath . QUELL_DATEINAME.java
    

    wobei JAXP_ROOT der absolute bzw. relative Pfad zu dem Verzeichnis ist, in dem sich die JAXP-JAR-Dateien befinden und QUELL_DATEINAME der Name der Java-Quelldatei.

  3. Beim Ausführen der Anwendung geben Sie den classpath an, damit die Anwendung die richtigen JAXP-Klassendateien laden kann. Beachten Sie, dass der erste Pfad in classpath das aktuelle Verzeichnis ist:


    java -cp .:JAXP_ROOT/dom.jar:JAXP_ROOTjaxp-api. \
    jar:JAXP_ROOTsax.jar:JAXP_ROOTxalan.jar:JAXP_ROOT/xercesImpl \
    .jar:JAXP_ROOT/xsltc.jar QUELL_DATEINAME ARGUMENTE
    

    Damit ist die Umgebung konfiguriert, und Sie können die Anwendung entwickeln.

Erste Schritte

In diesem Teil des Beispiels erstellen Sie eine Basisklasse mit dem Namen CrnpClient, deren Hauptmethode die Befehlszeilenargumente analysiert und ein CrnpClient-Objekt erstellt. Dieses Objekt übergibt die Befehlszeilenargumente an die Klasse, wartet, bis der Benutzer die Anwendung beendet, ruft shutdown für CrnpClient auf und wird dann beendet.

Der Konstruktor der CrnpClient-Klasse muss folgende Aufgaben ausführen:

    Erstellen Sie den Java-Code, der die vorstehende Logik implementiert.

    Das folgende Beispiel zeigt den Hauptcode für die CrnpClient-Klasse. Die Implementierungen der vier Hilfsmethoden, die im Konstruktor referenziert werden, sowie die Methoden zum Herunterfahren werden später erläutert. Beachten Sie, dass der Code gezeigt wird, mit dem alle benötigten Pakete importiert werden.


    import javax.xml.parsers.*;
    import javax.xml.transform.*;
    import javax.xml.transform.dom.*;
    import javax.xml.transform.stream.*;
    import org.xml.sax.*;
    import org.xml.sax.helpers.*;
    import org.w3c.dom.*;
    
    import java.net.*;
    import java.io.*;
    import java.util.*;
    
    
    class CrnpClient
    {
            public static void main(String []args)
            {
                    InetAddress regIp = null;
                    int regPort = 0, localPort = 0;
    
                    try {
                            regIp = InetAddress.getByName(args[0]);
                            regPort = (new Integer(args[1])).intValue();
                            localPort = (new Integer(args[2])).intValue();
                    } catch (UnknownHostException e) {
                            System.out.println(e);
                            System.exit(1);
                    }
    
                    CrnpClient client = new CrnpClient(regIp, regPort, localPort,
                        args);
                    System.out.println("Drücken Sie die Eingabetaste, um die Demo zu beenden...");
                    try {
                            System.in.read();
                    } catch (IOException e) {
                            System.out.println(e.toString());
                    }
                    client.shutdown();
                    System.exit(0);
            }
    
            public CrnpClient(InetAddress regIpIn, int regPortIn, int localPortIn,
                String []clArgs)
            {
                    try {
                            regIp = regIpIn;
                            regPort = regPortIn;
                            localPort = localPortIn;
                            regs = clArgs;
    
                            setupXmlProcessing();
                            createEvtRecepThr();
                            registerCallbacks();
    
                    } catch (Exception e) {
                            System.out.println(e.toString());
                            System.exit(1);
                    }
            }
    
            public void shutdown()
            {
                    try {
                            unregister();
                    } catch (Exception e) {
                            System.out.println(e);
                            System.exit(1);
                    }
            }
    
            private InetAddress regIp;
            private int regPort;
            private EventReceptionThread evtThr;
            private String regs[];
    
            public int localPort;
            public DocumentBuilderFactory dbf;
    }

    Mitgliedsvariablen werden weiter unten detaillierter behandelt.

Analyse der Befehlszeilenargumente

    Anhand des Codes in Anhang G können Sie sehen, wie die Befehlszeilenargumente analysiert werden.

Definieren des Ereignisempfangs-Threads

Im Code müssen Sie sicherstellen, dass der Ereignisempfang über einen eigenen Thread ausgeführt wird, so dass die Anwendung anderweitig weiterarbeiten kann, wenn der Thread blockiert ist und auf Ereignisrückmeldungen wartet.


Hinweis –

Das Einrichten des XML wird weiter unten erläutert.


  1. Definieren Sie im Code eine Thread-Unterklasse mit dem Namen EventReceptionThread, die ein ServerSocket erstellt und die an dieses Socket ankommenden Ereignisse abwartet.

    In diesem Teil des Beispielcodes werden Ereignisse weder gelesen noch verarbeitet. Das Lesen und Verarbeiten von Ereignissen wird später behandelt. EventReceptionThread erstellt ein ServerSocket über eine Internetworking-Protokolladresse mit Platzhalter. EventReceptionThread ist auch mit dem CrnpClient-Objekt referenziert, so dass EventReceptionThread Ereignisse zur Verarbeitung an das CrnpClient-Objekt senden kann.


    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();
                                    // Ereignis aus sock-Strom erstellen und verarbeiten
                                    sock.close();
                            }
                            // UNERREICHBAR
    
                    } catch (Exception e) {
                            System.out.println(e);
                            System.exit(1);
                    }
            }
    
            /* private Mitgliedsvariablen */
            private ServerSocket listeningSock;
            private CrnpClient client;
    }

  2. Nachdem Sie nun gesehen haben, wie die EventReceptionThread-Klasse funktioniert, erstellen Sie ein createEvtRecepThr-Objekt:


    private void createEvtRecepThr() throws Exception
    {
            evtThr = new EventReceptionThread(this);
            evtThr.start();
    }

Registrieren und Deregistrieren von Rückmeldungen

Die Registrierung besteht aus folgenden Schritten:

  1. Erstellen Sie den Java-Code, der die vorstehende Logik implementiert.

    Das folgende Beispiel zeigt die Implementierung der registerCallbacks-Methode der CrnpClient-Klasse, die vom CrnpClient-Konstruktor aufgerufen wird. Die Aufrufe an createRegistrationString() und readRegistrationReply() werden später eingehender beschrieben.

    regIp und regPort sind Objektmitglieder, die vom Konstruktor konfiguriert werden.


    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();
    }

  2. Implementieren Sie die unregister-Methode. Diese Methode wird von der shutdown-Methode von CrnpClient aufgerufen. Die Implementierung von createUnregistrationString wird später eingehender beschrieben.


    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();
    }

Generieren des XML

Nach dem Konfigurieren der Anwendungsstruktur und Schreiben des gesamten Netzwerkcodes können Sie nun den Code schreiben, der XML generiert und analysiert. Schreiben Sie zunächst den Code, der die SC_CALLBACK_REG-XML-Registrierungsmeldung generiert.

Eine SC_CALLBACK_REG-Meldung besteht aus einem Registrierungstyp (ADD_CLIENT, REMOVE_CLIENT, ADD_EVENTS oder REMOVE_EVENTS), einem Rückmelde-Port und einer Liste der interessierenden Ereignisse. Jedes Ereignis besteht aus einer Klasse und einer Unterklasse, gefolgt von einer Liste der Namens- und Wertepaare.

In diesem Teil des Beispiels schreiben Sie eine CallbackReg-Klasse, die den Registrierungstyp, den Rückmelde-Port und die Liste der Registrierungsereignisse speichert. Diese Klasse kann sich auch an eine SC_CALLBACK_REG-XML-Meldung serialisieren.

Eine interessante Methode dieser Klasse ist die convertToXml-Methode, die eine SC_CALLBACK_REG-XML-Meldungszeichenkette aus den Klassenmitgliedern erstellt. Eine detailliertere Beschreibung des Codes dieser Methode finden Sie in der JAXP-Dokumentation unter http://java.sun.com/xml/jaxp/index.html.

Im Folgenden wird die Implementierung der Event-Klasse gezeigt. Beachten Sie, dass die CallbackReg-Klasse eine Event-Klasse verwendet, die ein Ereignis speichert und dieses Ereignis in ein XML-Element konvertieren kann.

  1. Erstellen Sie den Java-Code, der die vorstehende Logik implementiert.


    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("Fehler, ungültiger 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 mit angegebenen Optionen kann nicht erstellt werden
                            pce.printStackTrace();
                            System.exit(1);
                    }
    
                    // Root-Element erstellen
                    Element root = (Element) document.createElement(
                        "SC_CALLBACK_REG");
    
                    // Attribute hinzufügen
                    root.setAttribute("VERSION", "1.0");
                    root.setAttribute("PORT", port);
                    root.setAttribute("regType", regType);
    
                    // Ereignisse hinzufügen
                    for (int i = 0; i < regEvents.size(); i++) {
                            Event tempEvent = (Event)
                                (regEvents.elementAt(i));
                            root.appendChild(tempEvent.createXmlElement(
                                document));
                    }
                    document.appendChild(root);
    
                    // Das Ganze in eine Zeichenkette konvertieren
                    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;
    }

  2. Implementieren Sie die Event- und NVPair-Klassen.

    Beachten Sie, dass die CallbackReg-Klasse eine Event-Klasse verwendet, die wiederum eine NVPair-Klasse verwendet.


    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;
    }

Erstellen der Registrierungs- und Deregistrierungsmeldungen

Nach dem Erstellen der Helper-Klassen für die Generierung von XML-Meldungen können Sie die Implementierung der createRegistrationString-Methode schreiben. Diese Methode wird von der registerCallbacks-Methode aufgerufen (siehe Beschreibung unter Registrieren und Deregistrieren von Rückmeldungen).

createRegistrationString erstellt ein CallbackReg-Objekt und richtet dessen Registrierungstyp und Port ein. Danach erstellt createRegistrationString verschiedene Ereignisse unter Verwendung der Helper-Methoden createAllEvent, createMembershipEvent, createRgEvent und createREvent. Jedes Ereignis wird diesem Objekt nach Erstellung des CallbackReg-Objekts hinzugefügt. Zuletzt ruft createRegistrationString die convertToXml-Methode des CallbackReg-Objekts auf, um die XML-Meldung im String-Format abzurufen.

Beachten Sie, dass die regs-Mitgliedsvariable die Befehlszeilenargumente speichert, die der Benutzer der Anwendung angibt. Das fünfte und alle folgenden Argumente geben die Ereignisse an, für die eine Anwendung registriert werden soll. Das vierte Argument gibt den Registrierungstyp an; es wird in diesem Beispiel jedoch übergangen. Der vollständige Code in Anhang G zeigt die Verwendung dieses vierten Arguments.

  1. Erstellen Sie den Java-Code, der die vorstehende Logik implementiert.


    private String createRegistrationString() throws Exception
    {
            CallbackReg cbReg = new CallbackReg();
            cbReg.setPort("" + localPort);
    
            cbReg.setRegType(CallbackReg.ADD_CLIENT);
    
            // Ereignisse hinzufügen
            for (int i = 4; i < regs.length; i++) {
                    if (regs[i].equals("M")) {
                            cbReg.addRegEvent(
                                createMembershipEvent());
                    } else if (regs[i].equals("A")) {
                            cbReg.addRegEvent(
                                createAllEvent());
                    } else if (regs[i].substring(0,2).equals("RG")) {
                            cbReg.addRegEvent(createRgEvent(
                                regs[i].substring(3)));
                    } else if (regs[i].substring(0,1).equals("R")) {
                            cbReg.addRegEvent(createREvent(
                                regs[i].substring(2)));
                    }
            }
    
            String xmlStr = cbReg.convertToXml();
            return (xmlStr);
    }
    
    private Event createAllEvent()
    {
            Event allEvent = new Event();
            allEvent.setClass("EC_Cluster");
            return (allEvent);
    }
    
    private Event createMembershipEvent()
    {
            Event membershipEvent = new Event();
            membershipEvent.setClass("EC_Cluster");
            membershipEvent.setSubclass("ESC_cluster_membership");
            return (membershipEvent);
    }
    
    private Event createRgEvent(String rgname)
    {
            Event rgStateEvent = new Event();
            rgStateEvent.setClass("EC_Cluster");
            rgStateEvent.setSubclass("ESC_cluster_rg_state");
    
            NVPair rgNvpair = new NVPair();
            rgNvpair.setName("rg_name");
            rgNvpair.setValue(rgname);
            rgStateEvent.addNvpair(rgNvpair);
    
            return (rgStateEvent);
    }
    
    private Event createREvent(String rname)
    {
            Event rStateEvent = new Event();
            rStateEvent.setClass("EC_Cluster");
            rStateEvent.setSubclass("ESC_cluster_r_state");
    
            NVPair rNvpair = new NVPair();
            rNvpair.setName("r_name");
            rNvpair.setValue(rname);
            rStateEvent.addNvpair(rNvpair);
    
            return (rStateEvent);
    }

  2. Erstellen Sie die Deregistrierungs-Zeichenkette.

    Das Erstellen einer Deregistrierungs-Zeichenkette ist einfacher als das Erstellen der Registrierungszeichenkette, da keine Ereignisse berücksichtigt werden müssen:


    private String createUnregistrationString() throws Exception
    {
            CallbackReg cbReg = new CallbackReg();
            cbReg.setPort("" + localPort);
            cbReg.setRegType(CallbackReg.REMOVE_CLIENT);
            String xmlStr = cbReg.convertToXml();
            return (xmlStr);
    }

Konfigurieren des XML-Parsers

Bisher wurden der Netzwerk- und der XML-Generierungscode für die Anwendung erstellt. Der letzte Schritt besteht in der Analyse und Verarbeitung der Registrierungsantwort und der Ereignisrückmeldungen. Der CrnpClient-Konstruktor ruft eine setupXmlProcessing-Methode auf. Diese Methode erstellt ein DocumentBuilderFactory-Objekt und stellt verschiedene Analyseeigenschaften für dieses Objekt ein. Eine detailliertere Beschreibung dieser Methode finden Sie in der JAXP-Dokumentation unter http://java.sun.com/xml/jaxp/index.html.

    Erstellen Sie den Java-Code, der die vorstehende Logik implementiert.


    private void setupXmlProcessing() throws Exception
    {
            dbf = DocumentBuilderFactory.newInstance();
    
            // Eine Validierung ist nicht erforderlich.
            dbf.setValidating(false);
            dbf.setExpandEntityReferences(false);
    
            // Kommentare und Leerzeichen sollen ignoriert werden
            dbf.setIgnoringComments(true);
            dbf.setIgnoringElementContentWhitespace(true);
    
            // CDATA-Abschnitte mit TEXT-Knoten verbinden.
            dbf.setCoalescing(true);
    }

Analysieren der Registrierungsantwort

Für die Analyse der SC_REPLY-XML-Meldung, die der CRNP-Server als Antwort auf eine Registrierungs- bzw. Deregistrierungsmeldung sendet, benötigen Sie eine RegReply-Helper-Klasse. Diese Klasse kann aufbauend auf einem XML-Dokument erstellt werden. Die Klasse ermöglicht den Zugang zum Statuscode und zur Statusmeldung. Um den XML-Strom vom Server zu analysieren, müssen Sie ein neues XML-Dokument erstellen und die Analysemethode dieses Dokuments verwenden. Eine detailliertere Beschreibung dieser Methode finden Sie in der JAXP-Dokumentation unter http://java.sun.com/xml/jaxp/index.html.

  1. Erstellen Sie den Java-Code, der die vorstehende Logik implementiert.

    Beachten Sie, dass die readRegistrationReply-Methode die neue RegReply-Klasse verwendet.


    private void readRegistrationReply(InputStream stream) throws Exception
    {
            // Dokument-Builder erstellen
            DocumentBuilder db = dbf.newDocumentBuilder();
            db.setErrorHandler(new DefaultHandler());
    
            // Eingabedatei analysieren
            Document doc = db.parse(stream);
    
            RegReply reply = new RegReply(doc);
            reply.print(System.out);
    }

  2. Implementieren Sie die RegReply-Klasse.

    Beachten Sie, dass die retrieveValues-Methode der DOM-Struktur im XML-Dokument folgt und den Statuscode und die Statusmeldung abruft. Weitere Einzelheiten finden Sie in der JAXP-Dokumentation unter http://java.sun.com/xml/jaxp/index.html.


    class RegReply
    {
            public RegReply(Document doc)
            {
                    retrieveValues(doc);
            }
    
            public String getStatusCode()
            {
                    return (statusCode);
            }
    
            public String getStatusMsg()
            {
                    return (statusMsg);
            }
            public void print(PrintStream out)
            {
                    out.println(statusCode + ": " +
                        (statusMsg != null ? statusMsg : ""));
            }
    
            private void retrieveValues(Document doc)
            {
                    Node n;
                    NodeList nl;
                    String nodeName;
    
                    // SC_REPLY-Element suchen.
                    nl = doc.getElementsByTagName("SC_REPLY");
                    if (nl.getLength() != 1) {
                            System.out.println("Analysefehler:"
                                + "SC_REPLY-Knoten kann nicht gefunden werden.");
                            return;
                    }
    
                    n = nl.item(0);
    
                    // Wert des statusCode-Attributs abrufen
                    statusCode = ((Element)n).getAttribute("STATUS_CODE");
    
                    // SC_STATUS_MSG-Element suchen
                    nl = ((Element)n).getElementsByTagName("SC_STATUS_MSG");
                    if (nl.getLength() != 1) {
                            System.out.println("Analysefehler:  "
                                + "SC_STATUS_MSG-Knoten kann nicht gefunden werden.");
                            return;
                    }
                    // TEXT-Abschnitt abrufen, falls vorhanden.
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                    // Kein Fehler, falls nicht vorhanden; einfach stillschweigend zurückgehen.
                            return;
                    }
    
                    // Wert abrufen
                    statusMsg = n.getNodeValue();
            }
    
            private String statusCode;
            private String statusMsg;
    }

Analysieren der Rückmeldeereignisse

Der letzte Schritt besteht in der Analyse und Verarbeitung der Rückmeldeereignisse selbst. Um diese Aufgabe zu unterstützen, ändern Sie die Event-Klasse, die in Generieren des XML erstellt wurde, damit diese Klasse in der Lage ist, ein Event basierend auf einem XML-Dokument zu erstellen und ein XML-Element zu erstellen. Diese Änderung erfordert einen zusätzlichen Konstruktor (XML-Dokument), eine retrieveValues-Methode, das Hinzufügen zweier weiterer Mitgliedsvariablen (vendor und publisher), Zugangsmethoden für alle Felder und schließlich eine Druckmethode.

  1. Erstellen Sie den Java-Code, der die vorstehende Logik implementiert.

    Beachten Sie, dass dieser Code dem Code für die RegReply-Klasse ähnelt, die unter Analysieren der Registrierungsantwort beschrieben wurde.


            public Event(Document doc)
            {
                    nvpairs = new Vector();
                    retrieveValues(doc);
            }
            public void print(PrintStream out)
            {
                    out.println("\tCLASS=" + regClass);
                    out.println("\tSUBCLASS=" + regSubclass);
                    out.println("\tVENDOR=" + vendor);
                    out.println("\tPUBLISHER=" + publisher);
                    for (int i = 0; i < nvpairs.size(); i++) {
                            NVPair tempNv = (NVPair)
                                (nvpairs.elementAt(i));
                            out.print("\t\t");
                            tempNv.print(out);
                    }
            }
    
            private void retrieveValues(Document doc)
            {
                    Node n;
                    NodeList nl;
                    String nodeName;
    
                    // SC_EVENT-Element suchen.
                    nl = doc.getElementsByTagName("SC_EVENT");
                    if (nl.getLength() != 1) {
                       System.out.println("Analysefehler: "
                           + "SC_EVENT-Knoten kann nicht gefunden werden.");
                       return;
                    }
    
                    n = nl.item(0);
    
                    //
                    // Werte der Attribute CLASS, SUBCLASS,
                    // VENDOR und PUBLISHER abrufen.
                    //
                    regClass = ((Element)n).getAttribute("CLASS");
                    regSubclass = ((Element)n).getAttribute("SUBCLASS");
                    publisher = ((Element)n).getAttribute("PUBLISHER");
                    vendor = ((Element)n).getAttribute("VENDOR");
    
                    // Alle NW-Paare abrufen
                    for (Node child = n.getFirstChild(); child != null;
                        child = child.getNextSibling())
                    {
                           nvpairs.add(new NVPair((Element)child));
                    }
            }
    
            public String getRegClass()
            {
                    return (regClass);
            }
    
            public String getSubclass()
            {
                    return (regSubclass);
            }
    
            public String getVendor()
            {
                    return (vendor);
            }
    
            public String getPublisher()
            {
                    return (publisher);
            }
    
            public Vector getNvpairs()
            {
                    return (nvpairs);
            }
    
            private String vendor, publisher;

  2. Implementieren Sie die zusätzlichen Konstruktoren und Methoden für die NVPair-Klasse, welche die XML-Analyse unterstützen.

    Die Änderungen an der Event-Klasse, die in Schritt 1 gezeigt werden, machen vergleichbare Änderungen an der NVPair-Klasse erforderlich.


            public NVPair(Element elem)
            {
                    retrieveValues(elem);
            }
            public void print(PrintStream out)
            {
                    out.println("NAME=" + name + " VALUE=" + value);
            }
            private void retrieveValues(Element elem)
            {
                    Node n;
                    NodeList nl;
                    String nodeName;
    
                    // NAME-Element suchen
                    nl = elem.getElementsByTagName("NAME");
                    if (nl.getLength() != 1) {
                       System.out.println("Analysefehler: "
                           + "NAME-Knoten kann nicht gefunden werden.");
                       return;
                    }
                    // TEXT-Abschnitt abrufen
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                       System.out.println("Analysefehler: "
                           + "TEXT-Abschnitt konnte nicht gefunden werden.");
                       return;
                    }
    
                    // Wert abrufen
                    name = n.getNodeValue();
    
                    // Jetzt das Wertelement abrufen
                    nl = elem.getElementsByTagName("VALUE");
                    if (nl.getLength() != 1) {
                       System.out.println("Analysefehler: "
                           + "VALUE-Knoten konnte nicht gefunden werden.");
                       return;
                    }
                    // TEXT-Abschnitt abrufen
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                    System.out.println("Analysefehler "
                                + "TEXT-Abschnitt konnte nicht gefunden werden.");
                            return;
                    }
    
                    // Wert abrufen
                    value = n.getNodeValue();
                    }
    
            public String getName()
            {
                    return (name);
            }
    
            public String getValue()
            {
                    return (value);
            }
    }

  3. Implementieren Sie die while-Schleife in EventReceptionThread, die Rückmeldeereignisse abwartet (EventReceptionThread wird unter Definieren des Ereignisempfangs-Threads beschrieben).


    while(true) {
                    Socket sock = listeningSock.accept();
                    Document doc = db.parse(sock.getInputStream());
                    Event event = new Event(doc);
                    client.processEvent(event);
                    sock.close();
            }

Ausführen der Anwendung

    Führen Sie die Anwendung aus.


    # java CrnpClient crnpHost crnpPort localPort ...
    

    Der vollständige Code für die CrnpClient-Anwendung ist in Anhang G enthalten.