Sun Cluster: Guía del desarrollador de los servicios de datos del sistema operativo Solaris
Contenido de CrnpClient.java
/*
* CrnpClient.java
* ================
*
* Nota sobre el análisis de XML:
*
* Este programa usa la arquitectura Java de Sun para las API de procesos de XML (JAXP).
* Consulte http://java.sun.com/xml/jaxp/index.html para ver documentación sobre API y
* obtener información sobre la disponibilidad.
*
* Este programa se ha escrito para Java 1.3.1 o superior.
*
* Información general del programa:
*
* El subproceso principal del programa crea un objeto CrnpClient, espera que el
* usuario termine la demostración e invoca el cierre en el objeto CrnpClient
* y sale del programa.
*
* El constructor de CrnpClient crea un objeto EventReceptionThread, abre una
* conexión con el servidor CRNP (con el sistema y puerto especificados en la líne
* a de órdenes), construye un mensaje de registro (basado en las especificaciones
* de la línea de órdenes), envía el mensaje de registro y lee y analiza la respuesta.
*
* EventReceptionThread crea un zócalo de recepción vinculado al nombre de sistema
* de la máquina en la que se ejecuta el programa y el puerto especificado en la línea
* de órdenes. Espera una rellamada de evento entrante y, cuando la recibe, construye
* un documento XML desde el canal del zócalo de entrada, que se devuelve al objeto
* CrnpClient para ser procesado.
*
* El método de apagado de CrnpClient se limita a enviar un mensaje de cancelación
* de registro (REMOVE_CLIENT) SC_CALLBACK_REG al servidor crnp.
*
* Nota sobre el manejo de errores: en pro de la brevedad, este programa suele salir
* cuando se producen la mayoría de los errores. Obviamente, una aplicación real
* intentaría manejar algunos errores de formas diversas, por ejemplo, mediante
* reintentos cuando corresponda.
*/
// paquetes JAXP
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.*;
// paquetes estándar
import java.net.*;
import java.io.*;
import java.util.*;
/*
* clase CrnpClient
* -----------------
* Consulte los comentarios de cabecera de archivos anteriores.
*/
class CrnpClient
{
/*
* main
* ----
* El punto de entrada de la ejecución main, sólo verifica
* el número de argumentos de la línea de órdenes y construye
* una instancia de CrnpClient para que realice todo el trabajo.
*/
public static void main(String []args)
{
InetAddress regIp = null;
int regPort = 0, localPort = 0;
/* Verificar el número de argumentos de la línea de órdenes */
if (args.length < 4) {
System.out.println(
"Sintaxis: java CrnpClient sistemacrnp puertocrnp "
+ "puertolocal (-ac | -ae | -re) "
+ "[(M | A | RG=nombre | R=nombre) [...]]");
System.exit(1);
}
/*
* Se espera que la línea de órdenes contenga la IP/el puerto del
* servidor crnp, el puerto local en el que se debe recibir y
* argumentos que especifiquen el tipo de registro.
*/
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);
}
// Crear CrnpClient
CrnpClient client = new CrnpClient(regIp, regPort, localPort,
args);
// Esperar hasta que el usuario desee terminar el programa
System.out.println("Pulsar Retorno para terminar la demostración...");
// la lectura se bloquea hasta que el usuario escriba algo
try {
System.in.read();
} catch (IOException e) {
System.out.println(e.toString());
}
// apagar el cliente
client.shutdown();
System.exit(0);
}
/*
* ======================
* métodos públicos
* ======================
*/
/*
* constructor CrnpClient
* -----------------------
* Analiza los argumentos de la línea de órdenes para saber cómo contactar con
* el servidor crnp, crea el subproceso de recepción de eventos y lo pone
* en ejecución, crea el objeto XML DocumentBuilderFactory y, finalmente, se
* registra para recibir rellamadas en el servidor crnp.
*/
public CrnpClient(InetAddress regIpIn, int regPortIn, int localPortIn,
String []clArgs)
{
try {
regIp = regIpIn;
regPort = regPortIn;
localPort = localPortIn;
regs = clArgs;
/*
* Configurar el creador de documentos para
* el proceso de xml.
*/
setupXmlProcessing();
/*
* Crear EventReceptionThread, que crea
* ServerSocket y lo vincula a un puerto e ip local.
*/
createEvtRecepThr();
/*
* Registrar en el servidor crnp.
*/
registerCallbacks();
} catch (Exception e) {
System.out.println(e.toString());
System.exit(1);
}
}
/*
* processEvent
* ---------------
* Rellamada a CrnpClient, utilizada por EventReceptionThread
* cuando recibe rellamadas de eventos.
*/
public void processEvent(Event event)
{
/*
* Con fines demostrativos, imprima el evento en System.out.
* Por supuesto, una aplicación real utilizaría el evento
* de algún modo.
*/
event.print(System.out);
}
/*
* apagado
* --------
* Cancelar el registro del servidor CRNP.
*/
public void shutdown()
{
try {
/* Enviar un mensaje de cancelación de registro al servidor */
unregister();
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
}
/*
* ======================
* métodos de ayuda privados
* ======================
*/
/*
* setupXmlProcessing
* --------------------
* Crear el generador de documentos para
* analizar los eventos y respuestas de xml.
*/
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);
}
/*
* createEvtRecepThr
* -------------------
* Crea un objeto EventReceptionThread nuevo, guarda el ip
* y puerto al que está vinculado el zócalo receptor y
* pone el subproceso en ejecución.
*/
private void createEvtRecepThr() throws Exception
{
/* crear el objeto de subproceso */
evtThr = new EventReceptionThread(this);
/*
* Ahora, iniciar la ejecución del subproceso para empezar a
* recibir rellamadas de entrega de eventos.
*/
evtThr.start();
}
/*
* registerCallbacks
* ------------------
* Crea una conexión de zócalo al servidor crnp y envía
* un mensaje de registro de evento.
*/
private void registerCallbacks() throws Exception
{
System.out.println("Acerca del registro");
/*
* Crear un zócalo conectado al ip/puerto de registro
* del servidor crnp y enviar la información de registro.
*/
Socket sock = new Socket(regIp, regPort);
String xmlStr = createRegistrationString();
PrintStream ps = new PrintStream(sock.getOutputStream());
ps.print(xmlStr);
/*
* Leer la respuesta
*/
readRegistrationReply(sock.getInputStream());
/*
* Cerrar la conexión de zócalo.
*/
sock.close();
}
/*
* unregister
* ----------
* Al igual que en registerCallbacks, crear una conexión de zócalo al
* servidor crnp, enviar un mensaje de cancelación de registro, esperar
* la respuesta del servidor y cerrar el zócalo.
*/
private void unregister() throws Exception
{
System.out.println("Acerca de la cancelación del registro");
/*
* Crear un zócalo conectado al ip/puerto de registro del
* servidor crnp y enviar información de cancelación de registro
. */
Socket sock = new Socket(regIp, regPort);
String xmlStr = createUnregistrationString();
PrintStream ps = new PrintStream(sock.getOutputStream());
ps.print(xmlStr);
/*
* Leer la respuesta
*/
readRegistrationReply(sock.getInputStream());
/*
* Cerrar la conexión de zócalo.
*/
sock.close();
}
/*
* createRegistrationString
* ------------------
* Construye un objeto CallbackReg basado en los argumentos de la línea de
* órdenes de este programa; después, recupera la cadena XML del objeto
* CallbackReg.
*/
private String createRegistrationString() throws Exception
{
/*
* Crear la clase real de CallbackReg y establecer el puerto.
*/
CallbackReg cbReg = new CallbackReg();
cbReg.setPort("" + localPort);
// Establecer el tipo de registro
if (regs[3].equals("-ac")) {
cbReg.setRegType(CallbackReg.ADD_CLIENT);
} else if (regs[3].equals("-ae")) {
cbReg.setRegType(CallbackReg.ADD_EVENTS);
} else if (regs[3].equals("-re")) {
cbReg.setRegType(CallbackReg.REMOVE_EVENTS);
} else {
System.out.println("Tipo de registro no válido: " + regs[3]);
System.exit(1);
}
// Agregar los 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();
System.out.println(xmlStr);
return (xmlStr);
}
/*
* createAllEvent
* ----------------
* Crea un evento de registro de XML con clase EC_Cluster, y sin
* subclase.
*/
private Event createAllEvent()
{
Event allEvent = new Event();
allEvent.setClass("EC_Cluster");
return (allEvent);
}
/*
* createMembershipEvent
* ----------------------
* Crea un evento de registro de XML con EC_Cluster, subclase
* ESC_cluster_membership.
*/
private Event createMembershipEvent()
{
Event membershipEvent = new Event();
membershipEvent.setClass("EC_Cluster");
membershipEvent.setSubclass("ESC_cluster_membership");
return (membershipEvent);
}
/*
* createRgEvent
* ----------------
* Crea un evento de registro de XML con clase EC_Cluster,
* subclase ESC_cluster_rg_state y un nvpair "rg_name" (basado
* en parámetro de entrada).
*/
private Event createRgEvent(String rgname)
{
/*
* Crea un evento de cambio de estado de grupo de recursos para el
* grupo de recursos nombre_registro. Observar que se da
* un par nombre-valor (nvpair) para este tipo de evento para
* especificar el grupo de recursos que interesa.
*/
/*
* Construir el objeto de evento y fijar la clase y subclase.
*/
Event rgStateEvent = new Event();
rgStateEvent.setClass("EC_Cluster");
rgStateEvent.setSubclass("ESC_cluster_rg_state");
/*
* Crear el objeto nvpair y agregarlo al evento.
*/
NVPair rgNvpair = new NVPair();
rgNvpair.setName("rg_name");
rgNvpair.setValue(rgname);
rgStateEvent.addNvpair(rgNvpair);
return (rgStateEvent);
}
/*
* createREvent
* ----------------
* Crea un evento de registro de XML con clase EC_Cluster,
* subclase ESC_cluster_r_state y un nvpair "r_name" (basado
* en parámetro de entrada).
*/
private Event createREvent(String rname)
{
/*
* Crea un evento de cambio de estado de recurso para el
* recurso nombre_registro. Observar que se indica un par
* nombre-valor (nvpair) para este tipo de evento, para
* especificar el grupo de recursos que interesa.
*/
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);
}
/*
* createUnregistrationString
* ------------------
* Construye un objeto REMOVE_CLIENT CallbackReg, después recupera
* la cadena XML del objeto CallbackReg.
*/
private String createUnregistrationString() throws Exception
{
/*
* Crear objeto CallbackReg
*/
CallbackReg cbReg = new CallbackReg();
cbReg.setPort("" + localPort);
cbReg.setRegType(CallbackReg.REMOVE_CLIENT);
/*
* Se dirige el registro hacia OutputStream
*/
String xmlStr = cbReg.convertToXml();
// Imprimir la cadena para la depuración
System.out.println(xmlStr);
return (xmlStr);
}
/*
* readRegistrationReply
* ------------------------
* Analizar el xml en un documento, construir un objeto RegReply
* a partir del documento e imprimir el objeto RegReply. Observar
* que una aplicación real actuaría según el status_code
* del objeto RegReply.
*/
private void readRegistrationReply(InputStream stream)
throws Exception
{
// Crear el constructor de documento
DocumentBuilder db = dbf.newDocumentBuilder();
//
// Establecer ErrorHandler antes del análisis
// Utilizar el descriptor predeterminado.
//
db.setErrorHandler(new DefaultHandler());
// Analizar el archivo de entrada
Document doc = db.parse(stream);
RegReply reply = new RegReply(doc);
reply.print(System.out);
}
/* variables de miembro privado */
private InetAddress regIp;
private int regPort;
private EventReceptionThread evtThr;
private String regs[];
/* variables de miembro público */
public int localPort;
public DocumentBuilderFactory dbf;
}
/*
* clase EventReceptionThread
* ----------------------------
* Consultar los anteriores comentarios de cabecera del archivo.
*/
class EventReceptionThread extends Thread
{
/*
* constructor EventReceptionThread
* ----------------------------------
* Crea un ServerSocket nuevo, vinculado al nombre de sistema local y
* un puerto comodín.
*/
public EventReceptionThread(CrnpClient clientIn) throws IOException
{
/*
* mantener una referencia al cliente para que se pueda rellamar
* al recibir un evento.
*/
client = clientIn;
/*
* Especificar la IP al que se debería establecer el vínculo.
* Es sencillamente la ip del sistema local. Si hay más de una
* interfaz pública configurada en esta máquina, se irá a
* cualquiera que indique InetAddress.getLocalHost.
*
*/
listeningSock = new ServerSocket(client.localPort, 50,
InetAddress.getLocalHost());
System.out.println(listeningSock);
}
/*
* run
* ---
* Invocado por el método Thread.Start.
*
* Realiza un bucle infinito, a la espera de conexiones de entrada
* de ServerSocket.
*
* A medida que se acepta cada conexión entrante, se crea un objeto de
* de evento del canal de xml, que luego se pasa al objeto
* CrnpClient para su proceso.
*/
public void run()
{
/*
* Bucle infinito.
*/
try {
//
// Crea el generador de documento con el
// generador de documentos de CrnpClient.
//
DocumentBuilder db = client.dbf.newDocumentBuilder();
//
// Establecer un ErrorHandler antes de analizar
// Utilizar el descriptor predeterminado.
//
db.setErrorHandler(new DefaultHandler());
while(true) {
/* Esperar rellamada del servidor */
Socket sock = listeningSock.accept();
// Analizar el archivo de entrada
Document doc = db.parse(sock.getInputStream());
Event event = new Event(doc);
client.processEvent(event);
/* Cerrar el zócalo */
sock.close();
}
// INACCESIBLE
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
}
/* variables de miembro privado */
private ServerSocket listeningSock;
private CrnpClient client;
}
/*
* clase NVPair
* -----------
* Esta clase guarda un par de nombre-valor (ambas cadenas). Sabe como crear
* un mensaje XML NVPAIR desde sus miembros y cómo analizar un elemento
* XML NVPAIR en sus miembros.
*
* Observar que la especificación de formato de un NVPAIR permite varios
* valores. Se ha realizado la simplificación a un solo valor.
*/
class NVPair
{
/*
* Dos constructores: el primero crea un NVPair vacío; el segundo
* crea un NVPair a partir de un elemento XML NVPAIR.
*/
public NVPair()
{
name = value = null;
}
public NVPair(Element elem)
{
retrieveValues(elem);
}
/*
* Configuradores públicos.
*/
public void setName(String nameIn)
{
name = nameIn;
}
public void setValue(String valueIn)
{
value = valueIn;
}
/*
* Imprime el nombre y valor en una sola línea.
*/
public void print(PrintStream out)
{
out.println("NAME=" + name + " VALUE=" + value);
}
/*
* createXmlElement
* ------------------
* Construye un elemento XML NVPAIR a partir de las variables
* de miembro. Toma el documento como parámetro para que pueda
* crear el elemento.
*/
public Element createXmlElement(Document doc)
{
// Crear el elemento.
Element nvpair = (Element)
doc.createElement("NVPAIR");
//
// Agregar el nombre. Observar que el nombre real es
// una sección CDATA separada.
//
Element eName = doc.createElement("NAME");
Node nameData = doc.createCDATASection(name);
eName.appendChild(nameData);
nvpair.appendChild(eName);
//
// Agregar el valor. Observar que el valor real es
// una sección CDATA separada.
//
Element eValue = doc.createElement("VALUE");
Node valueData = doc.createCDATASection(value);
eValue.appendChild(valueData);
nvpair.appendChild(eValue);
return (nvpair);
}
/*
* retrieveValues
* ----------------
* Analizar el elemento XML para recuperar el nombre y valor.
*/
private void retrieveValues(Element elem)
{
Node n;
NodeList nl;
//
// 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();
//
// Ahora, obtener el elemento de 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();
}
/*
* Accesores públicos
*/
public String getName()
{
return (name);
}
public String getValue()
{
return (value);
}
// Variables de miembro privado
private String name, value;
}
/*
* class Event
* -----------
* Esta clase guarda un evento que consta de una clase, subclase, fabricante,
* editor y lista de pares de nombre-valor. Sabe cómo construir un elemento
* XML SC_EVENT_REG a partir de sus miembros y cómo analizar un elemento
* XML SC_EVENT en sus miembros. Observar que existe una asimetría aquí: se
* analizan los elementos SC_EVENT, pero se construyen elementos SC_EVENT_REG.
* Esto se debe a que los elementos SC_EVENT_REG se utilizan en los mensajes
* de registro (que hay que construir), en tanto que los elementos SC_EVENT se
* utilizan en la entrega de eventos (que hay que analizar). La única diferencia
* es que los elementos SC_EVENT_REG no tienen fabricante ni editor.
*/
class Event
{
/*
* Dos constructores: el primero crea un evento vacío; el segundo
* crea un evento a partir de un documento XML SC_EVENT.
*/
public Event()
{
regClass = regSubclass = null;
nvpairs = new Vector();
}
public Event(Document doc)
{
nvpairs = new Vector();
//
// Convertir el documento en una cadena para imprimir con fines
// de depuración.
//
DOMSource domSource = new DOMSource(doc);
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;
}
System.out.println(strWrite.toString());
// Realizar el análisis real.
retrieveValues(doc);
}
/*
* Configuradores públicos
*/
public void setClass(String classIn)
{
regClass = classIn;
}
public void setSubclass(String subclassIn)
{
regSubclass = subclassIn;
}
public void addNvpair(NVPair nvpair)
{
nvpairs.add(nvpair);
}
/*
* createXmlElement
* ------------------
* Construye un elemento XMl SC_EVENT_REG a partir de las variables de
* los miembros. Toma el documento como parámetro para que pueda crear
* el elemento. Depende de la capacidad del NVPair createXmlElement.
*/
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);
}
/*
* Imprime las variables de miembros en varias líneas.
*/
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);
}
}
/*
* retrieveValues
* ----------------
* Analizar el documento XML para recuperar la clase, subclase,
* fabricante, editor y pares nombre/valor.
*/
private void retrieveValues(Document doc)
{
Node n;
NodeList nl;
//
// 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));
}
}
/*
* Métodos de accesores públicos.
*/
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);
}
// Variables de miembro privado.
private String regClass, regSubclass;
private Vector nvpairs;
private String vendor, publisher;
}
/*
* class CallbackReg
* -----------
* Esta clase guarda un puerto y regType (ambas cadenas) y una lista de
* eventos. Sabe cómo construir un mensaje XML SC_CALLBACK_REG de sus
* miembros.
*
* Observar que esta clase no necesita poder analizar mensajes
* SC_CALLBACK_REG porque sólo el servidor CRNP debe analizar mensajes
* SC_CALLBACK_REG
*/
class CallbackReg
{
// Definiciones útiles para el método setRegType
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();
}
/*
* Configuradores públicos.
*/
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);
}
/*
* convertToXml
* ------------------
* Construye un documento XML SC_CALLBACK_REG a partir de variables
* de miembro. Depende de la capacidad del evento createXmlElement.
*/
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);
}
Element root = (Element) document.createElement(
"SC_CALLBACK_REG");
root.setAttribute("VERSION", "1.0");
root.setAttribute("PORT", port);
root.setAttribute("REG_TYPE", regType);
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());
}
// variables de miembro privado
private String port;
private String regType;
private Vector regEvents;
}
/*
* class RegReply
* -----------
* Esta clase guarda status_code y status_msg (ambas cadenas).
* Sabe cómo analizar un elemento XML SC_REPLY en sus miembros.
*/
class RegReply
{
/*
* El constructor único toma un documento XML y lo analiza.
*/
public RegReply(Document doc)
{
//
// Convertir el documento en cadena.
//
DOMSource domSource = new DOMSource(doc);
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;
}
System.out.println(strWrite.toString());
retrieveValues(doc);
}
/*
* Accesores públicos
*/
public String getStatusCode()
{
return (statusCode);
}
public String getStatusMsg()
{
return (statusMsg);
}
/*
* Imprime la información en una sola línea.
*/
public void print(PrintStream out)
{
out.println(statusCode + ": " +
(statusMsg != null ? statusMsg : ""));
}
/*
* retrieveValues
* ----------------
* Analiza el documento XML para recuperar statusCode y statusMsg.
*/
private void retrieveValues(Document doc)
{
Node n;
NodeList nl;
//
// 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.");
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();
}
// variables de miembro privado
private String statusCode;
private String statusMsg;
}