Sun Cluster 3.1 10/03: Guía del desarrollador de los servicios de datos

Creación de una aplicación Java que utilice CRNP

El ejemplo siguiente ilustra cómo se debe desarrollar una aplicación sencilla de Java, llamada CrnpClient, que utiliza CRNP. La aplicación se registra para rellamadas de eventos en el servidor CRNP del clúster, recibe las rellamadas de eventos y procesa éstos mediante la impresión del contenido. Antes de finalizar, la aplicación anula el registro de su solicitud de rellamadas de eventos.

Tenga los siguientes puntos presentes al revisar este ejemplo.

Configuración del entorno

En primer lugar hay que configurar el entorno.

  1. Descargue e instale JAXP y la versión correcta del compilador de Java y la máquina virtual Java.

    En http://java.sun.com/xml/jaxp/index.html encontrará instrucciones.


    Nota –

    Este ejemplo requiere la utilización de Java 1.3.1 o posterior.


  2. Asegúrese de que especifique una classpath en la línea de comandos de compilación para que el compilador pueda encontrar las clases de JAXP. Desde el directorio en el que se encuentra el archivo de origen, escriba:


    % javac -classpath RAÍZ_JAXP/dom.jar:RAÍZ_JAXPjaxp-api. \
    jar:RAÍZ_JAXPsax.jar:RAÍZ_JAXPxalan.jar:RAÍZ_JAXP/xercesImpl \
    .jar:RAÍZ_JAXP/xsltc.jar -sourcepath . NOMBRE_ARCHIVO_ORIGEN.java
    

    donde RAÍZ_JAXP es la ruta absoluta o relativa al directorio en el que se encuentran los archivos jar de JAXP y NOMBRE_ARCHIVO_ORIGEN es el nombre de su archivo de origen Java.

  3. Al ejecutar la aplicación, se debe especificar la classpath para que la aplicación pueda cargar los archivos de clase de JAXP adecuados (tenga presente que la primera ruta de classpath es el directorio actual):


    java -cp .:RAÍZ_JAXP/dom.jar:RAÍZ_JAXPjaxp-api. \
    jar:RAÍZ_JAXPsax.jar:RAÍZ_JAXPxalan.jar:RAÍZ_JAXP/xercesImpl \
    .jar:RAÍZ_JAXP/xsltc.jar NOMBRE_ARCHIVO_ORIGEN ARGUMENTOS
    

    Ahora que se ha configurado el entorno se puede desarrollar la aplicación.

Procedimientos iniciales

En esta parte del ejemplo, se crea una clase básica denominada CrnpClient, con un método principal que analiza los argumentos de la línea de comandos y construye un objeto CrnpClient. Este objeto pasa los argumentos de línea de comandos a la clase, espera a que el usuario termine la aplicación, invoca shutdown en la clase CrnpClient y sale.

El constructor de la clase CrnpClient debe ejecutar las siguientes tareas:

    Crear el código Java que aplica la lógica anterior.

    El ejemplo siguiente muestra el código de la estructura básica de la clase CrnpClient. Las implementaciones de los cuatro métodos propios a los que se hace referencia en los métodos de cierre y el constructor aparecen más adelante. Observe que se muestra el código que importa todos los paquetes necesarios.


    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("Pulsar Retorno para terminar la demostración...");
                    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;
    }

    Las variables de los miembros se explican con más detalle más adelante.

Análisis de los argumentos de la línea de comandos

    Para ver cómo analizar los argumentos de línea de comandos, consulte el código del Apéndice G.

Definición del subproceso de recepción de eventos

En el código, hay que comprobar que la recepción de eventos se realice en un subproceso aparte de forma que la aplicación pueda seguir realizando el otro trabajo, mientras el subproceso de evento se bloquea y espera rellamadas de eventos.


Nota –

La configuración del XML se detalla más adelante.


  1. En el código, defina una subclase de Thread llamada EventReceptionThread que cree ServerSocket y espere que lleguen eventos al zócalo.

    En esta parte del código de ejemplo, los eventos no se leen ni se procesan. La lectura y el procesamiento de eventos se explican más adelante. EventReceptionThread crea ServerSocket en una dirección comodín de protocolo de interred. EventReceptionThread mantiene también una referencia al objeto CrnpClient para que EventReceptionThread pueda enviar eventos al objeto CrnpClient para que los procese.


    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();
                                    // Construir un evento desde el flujo del zócalo y procesarlo
                                    sock.close();
                            }
                            // INACCESIBLE
    
                    } catch (Exception e) {
                            System.out.println(e);
                            System.exit(1);
                    }
            }
    
            /* variables privadas de miembro*/
            private ServerSocket listeningSock;
            private CrnpClient client;
    }

  2. Ahora que sabe cómo funciona la clase EventReceptionThread, cree un objeto createEvtRecepThr:


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

Registro y anulación del registro de rellamadas

La tarea de registro consiste en:

  1. Crear el código Java que aplica la lógica anterior.

    El ejemplo siguiente muestra la aplicación del método registerCallbacks de la clase CrnpClient (que invoca el constructor de CrnpClient). Las llamadas a createRegistrationString() y readRegistrationReply() se describen con más detalle más adelante.

    regIp y regPort son miembros objeto configurados por el 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();
    }

  2. Aplique el método unregister. Este método lo invoca el método shutdown de CrnpClient. La implementación de createUnregistrationString se describe más adelante con más detalle.


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

Generación de XML

Ahora que se ha configurado la estructura de la aplicación y ha escrito todo el código de conexión a red, es necesario escribir el código que genera y analiza el XML. Empiece escribiendo el código que genera el mensaje de registro de XML SC_CALLBACK_REG.

Un mensaje SC_CALLBACK_REG consiste en un tipo de registro (ADD_CLIENT, REMOVE_CLIENT, ADD_EVENTS o REMOVE_EVENTS), un puerto de rellamada y una lista de eventos de interés. Cada evento consta de una clase y una subclase, seguidos de una lista de pares de nombres y valores.

En esta parte del ejemplo, se escribe una clase CallbackReg que guarda el tipo de registro, el puerto de rellamada y la lista de eventos de registro. Esta clase también puede serializarse en un mensaje de XML SC_CALLBACK_REG.

Un método interesante de esta clase es el convertToXml, que crea una cadena de mensaje de XML SC_CALLBACK_REG a partir de los miembros de la clase. La documentación de JAXP de http://java.sun.com/xml/jaxp/index.html describe el código de este método con más detalle.

La aplicación de la clase Event se muestra a continuación. Observe que la clase CallbackReg utiliza una clase Event que almacena un evento y puede convertirlo en un Element de XML.

  1. Crear el código Java que aplica la lógica anterior.


    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, regType no válido " +
                                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) {
                            // No se puede crear el analizador con las opciones
                            // especificadas
                            pce.printStackTrace();
                            System.exit(1);
                    }
    
                    // Crear el elemento raíz
                    Element root = (Element) document.createElement(
                        "SC_CALLBACK_REG");
    
                    // Añadir los atributos
                    root.setAttribute("VERSION", "1.0");
                    root.setAttribute("PORT", port);
                    root.setAttribute("regType", regType);
    
                    // Añadir los eventos
                    for (int i = 0; i < regEvents.size(); i++) {
                            Event tempEvent = (Event)
                                (regEvents.elementAt(i));
                            root.appendChild(tempEvent.createXmlElement(
                                document));
                    }
                    document.appendChild(root);
    
                    // Ahora, convertir el documento en cadena.
                    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. Implementar las clases Event y NVPair.

    Observe que la clase CallbackReg utiliza una clase Event, que usa a su vez una clase 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;
    }

Creación de los mensajes de registro y de anulación de registro

Ahora que se han creado las clases propias que generan los mensajes de XML, se puede escribir la aplicación del método createRegistrationString. Este método lo invoca el método registerCallbacks, descrito en Registro y anulación del registro de rellamadas.

createRegistrationString construye un objeto CallbackReg y establece su puerto y tipo de registro. Después, createRegistrationString construye varios eventos, mediante los métodos propios createAllEvent, createMembershipEvent, createRgEvent y createREvent. Cada evento se agrega al objeto CallbackReg después de crearlo. Finalmente, createRegistrationString invoca el método convertToXml en el objeto CallbackReg para recuperar el mensaje de XML en la forma de String.

Observe que la variable de miembro regs almacena los argumentos de la línea de comandos que proporciona un usuario a la aplicación. El quinto argumento y siguientes especifican los eventos para los cuales debería registrarse la aplicación. El cuarto argumento especifica el tipo de registro, pero se ignora en este ejemplo. El código completo del Apéndice G muestra cómo utilizar este cuarto argumento.

  1. Crear el código Java que aplica la lógica anterior.


    private String createRegistrationString() throws Exception
    {
            CallbackReg cbReg = new CallbackReg();
            cbReg.setPort("" + localPort);
    
            cbReg.setRegType(CallbackReg.ADD_CLIENT);
    
            // añadir eventos
            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. Crear la cadena de anulación de registro.

    Crear la cadena de anulación de registro es más fácil que crear la de registro, porque no es necesario incorporar eventos:


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

Configuración del analizador de XML

Una vez creado el código de generación de XML y de red para la aplicación, el paso final es analizar y procesar la respuesta de registro y las rellamadas de eventos. El constructor CrnpClient invoca un método setupXmlProcessing que crea un objeto DocumentBuilderFactory y establece en él varias propiedades de análisis. La documentación JAXP de http://java.sun.com/xml/jaxp/index.html describe este método con más detalle.

    Crear el código Java que aplica la lógica anterior.


    private void setupXmlProcessing() throws Exception
    {
            dbf = DocumentBuilderFactory.newInstance();
    
            // No es necesario validar
            dbf.setValidating(false);
            dbf.setExpandEntityReferences(false);
    
            // Se desea ignorar comentarios y espacios en blanco
            dbf.setIgnoringComments(true);
            dbf.setIgnoringElementContentWhitespace(true);
    
            // Fusionar secciones CDATA en nodos de TEXT.
            dbf.setCoalescing(true);
    }

Analizar la respuesta de registro

Para analizar el mensaje de XML SC_REPLY que envía el servidor CRNP en respuesta a un mensaje de registro o anulación de registro, se necesita una clase propia RegReply que se puede construir a partir de un documento de XML. Esta clase proporciona accesores para el código de estado y el mensaje de estado. Para analizar el flujo de XML desde el servidor hay que crear un nuevo documento XML y utilizar el método de análisis del documento (la documentación de JAXP en http://java.sun.com/xml/jaxp/index.html describe el método con más detalle).

  1. Crear el código Java que aplica la lógica anterior.

    Observe que el método readRegistrationReply utiliza la nueva clase RegReply.


    private void readRegistrationReply(InputStream stream) throws Exception
    {
            // Crear el constructor de documento
            DocumentBuilder db = dbf.newDocumentBuilder();
            db.setErrorHandler(new DefaultHandler());
    
            //analizar el archivo de entrada
            Document doc = db.parse(stream);
    
            RegReply reply = new RegReply(doc);
            reply.print(System.out);
    }

  2. Implementar la clase RegReply.

    Observe que el método retrieveValues recorre el árbol DOM del documento XML y extrae el código y el mensaje de estado. La documentación de JAXP de http://java.sun.com/xml/jaxp/index.html ofrece más detalles.


    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;
    
                    // Buscar el elemento SC_REPLY.
                    nl = doc.getElementsByTagName("SC_REPLY");
                    if (nl.getLength() != 1) {
                            System.out.println("Error al analizar: "
                                " no se puede encontrar "
                                + "nodo SC_REPLY node.");
                            return;
                    }
    
                    n = nl.item(0);
    
                    // Recuperar el valor del atributo STATUS_CODE
                    statusCode = ((Element)n).getAttribute("STATUS_CODE");
    
                    // Buscar el elemento SC_STATUS_MSG
                    nl = ((Element)n).getElementsByTagName("SC_STATUS_MSG");
                    if (nl.getLength() != 1) {
                            System.out.println("Error al analizar: "
                                " no se puede encontrar "
                                + "nodo SC_STATUS_MSG.");
                            return;
                    }
                    // Obtener la sección TEXT, si la hubiera.
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                            // Sin error, si no lo hay
    			             // se retorna discretamente.
                            return;
                    }
    
                    // Recuperar el valor
                    statusMsg = n.getNodeValue();
            }
    
            private String statusCode;
            private String statusMsg;
    }

Análisis de los eventos de rellamada

El paso final consiste en analizar y procesar los eventos reales de rellamada. Para facilitar esta tarea, se debe modificar la clase Event creada en Generación de XML de modo que pueda construir un Event a partir de un documento de XML y crear un Element de XML. Este cambio requiere un constructor adicional (que acepte un documento XML), un método retrieveValues, la adición de dos variables de miembro (vendor y publisher), métodos de accesor para todos los campos y un método de impresión.

  1. Crear el código Java que aplica la lógica anterior.

    Observe que este código es similar al código de la clase RegReply descrito en Analizar la respuesta de registro.


            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;
    
                    // Buscar el elemento SC_EVENT.
                    nl = doc.getElementsByTagName("SC_EVENT");
                    if (nl.getLength() != 1) {
                            System.out.println("Error al analizar: "
                                " no se puede encontrar "
                                + "nodo SC_EVENT.");
                            return;
                    }
    
                    n = nl.item(0);
    
                    //
                    // Recuperar los valores de los atributos
                    // CLASS, SUBCLASS, VENDOR y PUBLISHER.
                    //
                    regClass = ((Element)n).getAttribute("CLASS");
                    regSubclass = ((Element)n).getAttribute("SUBCLASS");
                    publisher = ((Element)n).getAttribute("PUBLISHER");
                    vendor = ((Element)n).getAttribute("VENDOR");
    
                    // Recuperar todos los pares n-v
                    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. Implementar los métodos y constructores adicionales para la clase NVPair que admite el análisis de XML.

    Los cambios en la clase Event que se muestran en el Paso 1 requieren cambios similares en la clase NVPair.


            public NVPair(Element elem)
            {
                    retrieveValues(elem);
            }
            public void print(PrintStream out)
            {
                    out.println("NAME=" + nombre + " VALUE=" + valor);
            }
            private void retrieveValues(Element elem)
            {
                    Node n;
                    NodeList nl;
                    String nodeName;
                    // Buscar el elemento NAME
                    nl = elem.getElementsByTagName("NAME");
                    if (nl.getLength() != 1) {
                            System.out.println(""Error al analizar: "
                                " no se puede encontrar "
                                + "nodo NAME.");
                            return;
                    }
                    // Obtener la sección TEXT
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                            System.out.println(""Error al analizar: "
                                " no se puede encontrar "
                                + "sección TEXT.");
                            return;
                    }
    
                    // Recuperar el valor
                    name = n.getNodeValue();
    
                    // Obtener ahora el elemento valor
                    nl = elem.getElementsByTagName("VALUE");
                    if (nl.getLength() != 1) {
                            System.out.println(""Error al analizar: "
                                " no se puede encontrar "
                                + "nodo VALUE.");
                            return;
                    }
                    // Obtener la sección TEXT
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                    System.out.println(""Error al analizar: "
                                " no se puede encontrar "
                                + "sección TEXT.");
                            return;
                    }
    
                    // Recuperar el valor
                    value = n.getNodeValue();
                    }
    
            public String getName()
            {
                    return (name);
            }
    
            public String getValue()
            {
                    return (value);
            }
    }

  3. Implementar el bucle while en EventReceptionThread, que espera rellamadas de eventos (EventReceptionThread se describe en Definición del subproceso de recepción de eventos).


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

Ejecución de la aplicación

    Ejecutar la aplicación.


    # java CrnpClient sistema_crnp puerto_crnp puerto_local ...
    

    El código completo de la aplicación CrnpClient se puede consultar en el Apéndice G.