Guide du développeur de services de données Sun Cluster pour SE Solaris

Exemple de création d'une application Java utilisant le protocole CRNP

L'exemple suivant montre comment développer une application Java simple nommée CrnpClient et qui utilise le protocole CRNP. Cette application enregistre le client, en vue de la réception de rappels d'événements, auprès du serveur CRNP sur le cluster ; elle écoute les rappels, puis traite les événements en imprimant leur contenu. Pour terminer, elle supprime les rappels d'événements.

Gardez ces informations à l'esprit lorsque vous étudiez cet exemple :

ProcedureConfiguration de l'environnement

Étapes
  1. Téléchargez puis installez JAXP ainsi que la version appropriée du compilateur Java et de la machine virtuelle.

    Vous trouverez des instructions à l'adresse http://java.sun.com/xml/jaxp/index.html.


    Remarque –

    Cet exemple requiert au minimum la version Java 1.3.1.


  2. Placez-vous dans le répertoire qui contient le fichier source et tapez les lignes suivantes :


    % 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 . source-filename.java
    

    jaxp-root est le chemin d'accès, absolu ou relatif, au répertoire contenant les fichiers jar de JAXP et source-filename est le nom de votre fichier source Java.

    Le fait de spécifier un classpath dans votre ligne de commande de compilation garantit que le programme de compilation trouvera les fichiers de classe JAXP.

  3. Lors de l'exécution de l'application, spécifiez le chemin classpath de manière à ce que l'application puisse charger les bons fichiers de classe JAXP (le premier chemin d'accès spécifié dans classpath correspond au répertoire actuel) :


    % java -cp .:jaxp-root/dom.jar:jaxp-rootjaxp-api. \
    jar:jaxp-rootsax.jar:jaxp-rootxalan.jar:jaxp-root/xercesImpl \
    .jar:jaxp-root/xsltc.jar source-filename arguments
    

    L'environnement est à présent configuré. Vous pouvez développer l'application.

ProcedurePremières étapes du développement de l'application

Dans cette partie de l'exemple, vous allez créer une classe de base appelée CrnpClient , avec une méthode principale qui analyse les arguments de ligne de commande et crée un objet CrnpClient. Cet objet transfère les arguments de la ligne de commande à la classe, attend que l'utilisateur arrête l'application, exécute la commande shutdown sur la classe CrnpClient, puis se déconnecte.

Le constructeur de la classe CrnpClient doit exécuter les tâches suivantes :

Étape

    Créez le code Java mettant en oeuvre la logique précédente.

    L'exemple suivant présente le code du squelette de la classe CrnpClient. Les mises en oeuvre des quatre méthodes d'assistant référencées dans les méthodes d'arrêt et du constructeur sont expliquées plus loin dans ce chapitre. Le code qui permet d'importer tous les packages requis est indiqué.

    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("Hit return to terminate demo...");
                    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;
    }

    Les variables membres sont traitées plus en détail ultérieurement.

ProcedureAnalyse des arguments de ligne de commande

Étape

    Pour savoir comment analyser les arguments de ligne de commande, reportez-vous au code à l'Annexe G, Application CrnpClient.java .

ProcedureDéfinition d'un thread de réception d'événements

Vous devez vous assurer, au niveau du code, que les événements sont reçus sur un thread distinct, afin que votre application puisse continuer d'exécuter d'autres tâches tandis que le thread d'événements attend la notification de rappel d'événements.


Remarque –

La configuration XML est abordée plus loin dans ce chapitre.


Étapes
  1. Dans votre code, définissez une sous-classe Thread appelée EventReceptionThread qui crée une classe ServerSocket et attend que les événements arrivent sur le socket.

    Dans cette partie du code, les événements ne sont ni lus ni traités. La lecture et le traitement des événements sont abordés plus loin dans ce chapitre. La classe EventReceptionThread crée une classe ServerSocket sur une adresse générique de protocole inter-réseau. EventReceptionThread conserve également l'objet CrnpClient en référence afin de pouvoir lui transmettre des événements à traiter.

    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;
    }
  2. Créez un objet createEvtRecepThr.

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

ProcedureEnregistrement et annulation de l'enregistrement aux rappels

L'enregistrement implique les opérations suivantes :

Étapes
  1. Créez le code Java mettant en oeuvre la logique précédente.

    L'exemple de code suivant présente la mise en oeuvre de la méthode registerCallbacks de la classe CrnpClient (qui est appelée par le constructeur CrnpClient). Les appels des fonctions createRegistrationString() et readRegistrationReply () sont décrits plus en détail ultérieurement.

    regIp et regPort sont des objets membres définis par le constructeur.

    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. Mettez en œuvre la méthode unregister.

    Cette méthode est appelée par la méthode shutdown de la classe CrnpClient. La mise en oeuvre de createUnregistrationString est présentée plus en détail plus loin dans ce chapitre.

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

ProcedureGénération du langage XML

Maintenant que vous avez défini la structure de l'application et que vous avez rédigé l'intégralité du code de mise en réseau, vous allez rédiger le code qui permet de générer et d'analyser le langage XML. Commencez par rédiger le code qui permet de générer le message de connexion XML SC_CALLBACK_REG.

Un message SC_CALLBACK_REG est constitué d'un type de connexion (ADD_CLIENT, REMOVE_CLIENT, ADD_EVENTS ou REMOVE_EVENTS), d'un port de rappel et d'une liste d'événements intéressants. Chaque événement comprend une classe et une sous-classe, suivies d'une liste de paires nom/valeurs.

Dans cette partie de l'exemple, vous rédigez une classe CallbackReg qui enregistre le type de connexion, le port de rappel et la liste des événements de connexion. Cette classe peut également se sérialiser en message XML SC_CALLBACK_REG.

Cette classe comprend la méthode convertToXml. Cette méthode intéressante crée une chaîne de message XML SC_CALLBACK_REG à partir des membres de la classe. La documentation JAXP disponible à l'adresse http://java.sun.com/xml/jaxp/index.html décrit le code de cette méthode plus en détail.

La mise en oeuvre de la classe Event est présentée dans l'exemple de code suivant. La classe CallbackReg utilise une classe Event qui mémorise un événement et peut le convertir en Element XML.

Étapes
  1. Créez le code Java mettant en oeuvre la logique précédente.

    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;
    }
  2. Mettez en oeuvre les classes Event et NVPair.

    La classe CallbackReg utilise une classe Event, qui elle-même utilise une classe NVPair .

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

ProcedureCréation des messages d'enregistrement et d'annulation de l'enregistrement

Maintenant que vous avez créé les classes d'assistant qui permettent de générer les messages XML, vous pouvez écrire la mise en oeuvre de la méthode createRegistrationString. Cette méthode est appelée par la méthode registerCallbacks, décrite à la section Enregistrement et annulation de l'enregistrement aux rappels.

createRegistrationString crée un objet CallbackReg et définit son type et son port de connexion. createRegistrationString crée ensuite plusieurs événements, à l'aide des méthodes d'assistant createAllEvent, createMembershipEvent, createRgEvent et createREvent . Chaque événement est ajouté à l'objet CallbackReg une fois cet objet créé. Enfin, createRegistrationString appelle la méthode convertToXml sur l'objet CallbackReg pour rechercher et extraire les messages XML au format String.

La variable membre regs enregistre les arguments de ligne de commande qu'un utilisateur fournit à l'application. Le cinquième argument et les arguments ultérieurs spécifient les événements pour lesquels l'application doit s'enregistrer. Le quatrième argument spécifie le type d'enregistrement, mais il est ignoré dans cet exemple. L'intégralité du code, que vous trouverez à l'Annexe G, Application CrnpClient.java explique comment utiliser ce quatrième argument.

Étapes
  1. Créez le code Java mettant en oeuvre la logique précédente.

    private String createRegistrationString() throws Exception
    {
            CallbackReg cbReg = new CallbackReg();
            cbReg.setPort("" + localPort);
    
            cbReg.setRegType(CallbackReg.ADD_CLIENT);
    
            // add the events
            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. Créez la chaîne de caractères d'annulation de l'enregistrement.

    Il est plus facile de créer une chaîne de caractères d'annulation d'enregistrement qu'une chaîne de caractères d'enregistrement, car vous n'avez pas à prendre en compte les événements.

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

ProcedureConfiguration de l'analyseur XML

Vous avez créé le code de génération XML et de gestion de réseaux de l'application. Le constructeur CrnpClient appelle une méthode setupXmlProcessing . Celle-ci crée un objet DocumentBuilderFactory et définit plusieurs propriétés d'analyse sur cet objet. Cette méthode est décrite plus en détail dans la documentation JAXP. Voir http://java.sun.com/xml/jaxp/index.html.

Étape

    Créez le code Java mettant en oeuvre la logique précédente.

    private void setupXmlProcessing() throws Exception
    {
            dbf = DocumentBuilderFactory.newInstance();
    
            // We don't need to bother validating
            dbf.setValidating(false);
            dbf.setExpandEntityReferences(false);
    
            // We want to ignore comments and whitespace
            dbf.setIgnoringComments(true);
            dbf.setIgnoringElementContentWhitespace(true);
    
            // Coalesce CDATA sections into TEXT nodes.
            dbf.setCoalescing(true);
    }

ProcedureAnalyse de la réponse d'enregistrement

Pour pouvoir analyser le message XML SC_REPLY que le serveur CRNP envoie en réponse à un message d'enregistrement ou d'annulation d'un enregistrement, vous avez besoin d'une classe d'assistant RegReply . Vous pouvez créer cette classe à partir d'un document XML. Elle propose les mécanismes d'accès du code et du message d'état. Pour analyser le flux XML du serveur, vous devez créer un nouveau document XML et utiliser la méthode d'analyse de ce document. Cette méthode est décrite plus en détail dans la documentation JAXP disponible à l'adresse http://java.sun.com/xml/jaxp/index.html.

Étapes
  1. Créez le code Java mettant en oeuvre la logique précédente.

    La méthode readRegistrationReply utilise la nouvelle classe RegReply.

    private void readRegistrationReply(InputStream stream) throws Exception
    {
            // Create the document builder
            DocumentBuilder db = dbf.newDocumentBuilder();
            db.setErrorHandler(new DefaultHandler());
    
            //parse the input file
            Document doc = db.parse(stream);
    
            RegReply reply = new RegReply(doc);
            reply.print(System.out);
    }
  2. Mettez en oeuvre la classe RegReply.

    La méthode retrieveValues parcourt l'arborescence DOM dans le document XML et extrait le code et le message d'état. Pour en savoir plus, consultez la documentation JAXP à l'adresse 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;
    
                    // Find the SC_REPLY element.
                    nl = doc.getElementsByTagName("SC_REPLY");
                    if (nl.getLength() != 1) {
                            System.out.println("Error in parsing: can't find "
                                + "SC_REPLY node.");
                            return;
                    }
    
                    n = nl.item(0);
    
                    // Retrieve the value of the statusCode attribute
                    statusCode = ((Element)n).getAttribute("STATUS_CODE");
    
                    // Find the SC_STATUS_MSG element
                    nl = ((Element)n).getElementsByTagName("SC_STATUS_MSG");
                    if (nl.getLength() != 1) {
                            System.out.println("Error in parsing: can't find "
                                + "SC_STATUS_MSG node.");
                            return;
                    }
                    // Get the TEXT section, if there is one.
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                    // Not an error if there isn't one, so we just silently return.
                            return;
                    }
    
                    // Retrieve the value
                    statusMsg = n.getNodeValue();
            }
    
            private String statusCode;
            private String statusMsg;
    }

ProcedureAnalyse des événements de rappel

L'étape finale consiste à analyser et traiter les événements de rappels réels. Pour faciliter cette tâche, modifiez la classe Event que vous avez créée à la section Génération du langage XML, afin qu'elle puisse créer un Event à partir d'un document XML et un Element XML. Pour effectuer cette modification, vous aurez besoin d'un constructeur supplémentaire (exécutant un document XML), une méthode retrieveValues, de l'ajout de deux variables membres (vendor et publisher), de méthodes de mécanisme d'accès à tous les champs et d'une méthode d'impression.

Étapes
  1. Créez le code Java mettant en oeuvre la logique précédente.

    Ce code est identique à celui de la classe RegReply décrit à la section Analyse de la réponse d'enregistrement.

    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;
    
                    // Find the SC_EVENT element.
                    nl = doc.getElementsByTagName("SC_EVENT");
                    if (nl.getLength() != 1) {
                       System.out.println("Error in parsing: can't find "
                           + "SC_EVENT node.");
                       return;
                    }
    
                    n = nl.item(0);
    
                    //
                    // Retrieve the values of the CLASS, SUBCLASS,
                    // VENDOR and PUBLISHER attributes.
                    //
                    regClass = ((Element)n).getAttribute("CLASS");
                    regSubclass = ((Element)n).getAttribute("SUBCLASS");
                    publisher = ((Element)n).getAttribute("PUBLISHER");
                    vendor = ((Element)n).getAttribute("VENDOR");
    
                    // Retrieve all the nv pairs
                    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. Mettez en oeuvre les autres constructeurs et méthodes de la classe NVPair qui prennent en charge l'analyse XML.

    Les modifications apportées à la classe Event (cf Étape 1) doivent être identiques à celles apportées à la classe NVPair.

    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;
    
                    // Find the NAME element
                    nl = elem.getElementsByTagName("NAME");
                    if (nl.getLength() != 1) {
                       System.out.println("Error in parsing: can't find "
                           + "NAME node.");
                       return;
                    }
                    // Get the TEXT section
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                       System.out.println("Error in parsing: can't find "
                           + "TEXT section.");
                       return;
                    }
    
                    // Retrieve the value
                    name = n.getNodeValue();
    
                    // Now get the value element
                    nl = elem.getElementsByTagName("VALUE");
                    if (nl.getLength() != 1) {
                       System.out.println("Error in parsing: can't find "
                           + "VALUE node.");
                       return;
                    }
                    // Get the TEXT section
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                    System.out.println("Error in parsing: can't find "
                                + "TEXT section.");
                            return;
                    }
    
                    // Retrieve the value
                    value = n.getNodeValue();
                    }
    
            public String getName()
            {
                    return (name);
            }
    
            public String getValue()
            {
                    return (value);
            }
    }
  3. Mettez en oeuvre la boucle while dans la classe EventReceptionThread qui attend les rappels d'événements.

    La classe EventReceptionThread est présentée à la section Définition d'un thread de réception d'événements.

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

ProcedureExécution de l'application

Étapes
  1. Connectez-vous en tant que superutilisateur ou prenez un rôle équivalent.

  2. Exécutez votre application.


    # java CrnpClient crnpHost crnpPort localPort ...
    

    L'intégralité du code de l'application CrnpClient est disponible à l'Annexe G, Application CrnpClient.java .