Inhalt von CrnpClient.java
/*
* CrnpClient.java
* ================
*
* Hinweis zur XML-Analyse:
*
* Dieses Programm verwendet die API der Sun Java-Architektur für XML-Verarbeitung (JAXP).
* Auf http://java.sun.com/xml/jaxp/index.html finden Sie API-Dokumentation und
* Verfügbarkeitsinformationen.
*
* Dieses Programm wurde für Java 1.3.1 oder höher geschrieben.
*
* Programmüberblick:
*
* Der Haupt-Thread des Programms erstellt ein CrnpClient-Objekt, wartet, bis der
* Benutzer die Demo beendet hat, und ruft das Herunterfahren für das CrnpClient-
* Objekt auf und beendet das Programm.
*
* Der CrnpClient-Konstruktor erstellt ein EventReceptionThread-Objekt,
* stellt eine Verbindung zum CRNP-Server her, wobei er den an der Befehlszeile
* angegebenen Host und Port verwendet, erstellt eine Registrierungsmeldung
* basierend auf den Befehlszeilenspezifikationen, sendet die
* Registrierungsmeldung und liest und analysiert die Antwort.
*
* Der EventReceptionThread erstellt ein Socket zum Abhören, das an den
* Hostnamen des Rechners gebunden ist, auf dem dieses Programm ausgeführt wird, sowie
* an den Port, der an der Befehlszeile angegeben wird. Er wartet auf eine eingehende
* Ereignisrückmeldung. Zu diesem Zeitpunkt erstellt er ein XML-Dokument aus dem
* eingehenden Socket-Strom, der dann zur Verarbeitung an das CrnpClient-Objekt
* zurückgegeben wird.
*
* Die Methode für das Herunterfahren im CrnpClient sendet einfach eine Deregistrierungsmeldung
* (REMOVE_CLIENT) SC_CALLBACK_REG an den CRNP-Server.
*
* Hinweis zur Fehlerbehandlung: Einfachheitshalber wird dieses Programm bei den
* meisten Fehlern einfach beendet. Natürlich würde eine reale Anwendung bei einigen
* Fehlern andere Lösungen suchen, wie z. B. gegebenenfalls ein erneuter Versuch.
*/
// JAXP-Pakete
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.*;
// Standard-Pakete
import java.net.*;
import java.io.*;
import java.util.*;
/*
* Klasse CrnpClient
* -----------------
* Siehe die obigen Dateiheader-Kommentare.
*/
class CrnpClient
{
/*
* main
* ----
* Als Eingangspunkt der Ausführung überprüft main lediglich die
* Anzahl der Befehlszeilenargumente und erstellt eine Instanz
* eines CrnpClient für alle Aufgaben.
*/
public static void main(String []args)
{
InetAddress regIp = null;
int regPort = 0, localPort = 0;
/* Anzahl der Befehlszeilenargumente überprüfen */
if (args.length < 4) {
System.out.println(
"Syntax: java CrnpClient crnpHost crnpPort "
+ "lokalerPort (-ac | -ae | -re) "
+ "[(M | A | RG=Name | R=Name) [...]]");
System.exit(1);
}
/*
* Die Befehlszeile soll IP/Port des CRNP-Servers, den
* lokalen abzuhörenden Port und die Argumente zur
* Angabe des Registrierungstyps enthalten.
*/
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 erstellen
CrnpClient client = new CrnpClient(regIp, regPort, localPort,
args);
// Warten, bis der Benutzer das Programm beenden möchte
System.out.println("Drücken Sie die Eingabetaste, um die Demo zu beenden...");
// Der Lesevorgang wird blockiert, bis der Benutzer etwas eingibt
try {
System.in.read();
} catch (IOException e) {
System.out.println(e.toString());
}
// Client herunterfahren
client.shutdown();
System.exit(0);
}
/*
* ======================
* Öffentliche Methoden
* ======================
*/
/*
* CrnpClient-Konstruktor
* -----------------------
* Analysiert die Befehlszeilenargumente, damit der Benutzer weiß, wie die
* Verbindung zum CRNP-Server hergestellt werden muss, erstellt den
* Ereignisempfangs-Thread und startet dessen Ausführung, erstellt das
* XML DocumentBuilderFactory-Objekt und registriert sich
* für Rückmeldungen beim CRNP-Server.
*/
public CrnpClient(InetAddress regIpIn, int regPortIn, int localPortIn,
String []clArgs)
{
try {
regIp = regIpIn;
regPort = regPortIn;
localPort = localPortIn;
regs = clArgs;
/*
* Document Builder Factory für die
* XML-Verarbeitung einrichten.
*/
setupXmlProcessing();
/*
* EventReceptionThread erstellen, der ein
* ServerSocket erstellt und an ein lokales IP und Port bindet.
*/
createEvtRecepThr();
/*
* Beim CRNP-Server registrieren.
*/
registerCallbacks();
} catch (Exception e) {
System.out.println(e.toString());
System.exit(1);
}
}
/*
* processEvent
* ---------------
* Rückmeldung an CrnpClient, verwendet von EventReceptionThread
* beim Empfangen von Ereignisrückmeldungen.
*/
public void processEvent(Event event)
{
/*
* Zu Demonstrationszwecken wird das Ereignis einfach an
* System.out gedruckt. Eine reale Anwendung würde das
* Ereignis zu einem bestimmten Zweck nutzen.
*/
event.print(System.out);
}
/*
* shutdown
* -------------
* Vom CRNP-Server deregistrieren.
*/
public void shutdown()
{
try {
/* Deregistrierungsmeldung an den Server senden */
unregister();
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
}
/*
* ======================
* Private Helper-Methoden
* ======================
*/
/*
* SetupXmlProcessing
* --------------------
* Erstellt Document Builder Factory zum
* Analysieren der XML-Antworten und -Ereignisse.
*/
private void setupXmlProcessing() throws Exception
{
dbf = DocumentBuilderFactory.newInstance();
// Eine Validierung ist nicht erforderlich.
dbf.setValidating(false);
dbf.setExpandEntityReferences(false);
// Kommentare und Leerzeichen sollen ignoriert werden
dbf.setIgnoringComments(true);
dbf.setIgnoringElementContentWhitespace(true);
// CDATA-Abschnitte mit TEXT-Knoten verbinden.
dbf.setCoalescing(true);
}
/*
* createEvtRecepThr
* -------------------
* Erstellt ein neues EventReceptionThread-Objekt, speichert IP und Port,
* an die das Abhör-Socket gebunden ist, und startet die
* Ausführung des Threads.
*/
private void createEvtRecepThr() throws Exception
{
/* Thread-Objekt erstellen */
evtThr = new EventReceptionThread(this);
/*
* Jetzt Ausführung des Threads starten,
* um mit dem Abhören für Ereigniszustellungsrückmeldungen
* zu beginnen.
*/
evtThr.start();
}
/*
* registerCallbacks
* ------------------
* Erstellt eine Socketverbindung zum CRNP-Server und sendet
* eine Ereignisregistrierungsmeldung.
*/
private void registerCallbacks() throws Exception
{
System.out.println("Registrierung wird eingeleitet");
/*
* Socketverbindung zum Registrierungs-IP/Port des CRNP-
* -Servers erstellen und Registrierungsinformationen senden.
*/
Socket sock = new Socket(regIp, regPort);
String xmlStr = createRegistrationString();
PrintStream ps = new PrintStream(sock.getOutputStream());
ps.print(xmlStr);
/*
* Antwort lesen
*/
readRegistrationReply(sock.getInputStream());
/*
* Socketverbindung beenden.
*/
sock.close();
}
/*
* unregister
* ----------
* Genau wie bei registerCallbacks wird eine Socketverbindung zum
* CRNP-Server hergestellt, die Deregistrierungsmeldung gesendet, auf die
* Antwort vom Server gewartet und das Socket geschlossen.
*/
private void unregister() throws Exception
{
System.out.println("Deregistrierung wird eingeleitet");
/*
* Socketverbindung zum Registrierungs-IP/Port des CRNP-
* Servers erstellen und Deregistrierungsinformationen senden.
*/
Socket sock = new Socket(regIp, regPort);
String xmlStr = createUnregistrationString();
PrintStream ps = new PrintStream(sock.getOutputStream());
ps.print(xmlStr);
/*
* Antwort lesen
*/
readRegistrationReply(sock.getInputStream());
/*
* Socketverbindung trennen.
*/
sock.close();
}
/*
* createRegistrationString
* ------------------
* Erstellt ein CallbackReg-Objekt basierend auf den Befehlszeilenargumenten
* für dieses Programm und ruft dann die XML-Zeichenkette aus dem
* CallbackReg-Objekt ab.
*/
private String createRegistrationString() throws Exception
{
/*
* CallbackReg-Klasse erstellen und Port einrichten.
*/
CallbackReg cbReg = new CallbackReg();
cbReg.setPort("" + localPort);
// Registrierungstyp einstellen
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("Ungültiger Reg.typ: " + regs[3]);
System.exit(1);
}
// Ereignisse hinzufügen
for (int i = 4; i < regs.length; i++) {
if (regs[i].equals("M")) {
cbReg.addRegEvent(
createMembershipEvent());
} else if (regs[i].equals("A")) {
cbReg.addRegEvent(
createAllEvent());
} else if (regs[i].substring(0,2).equals("RG")) {
cbReg.addRegEvent(createRgEvent(
regs[i].substring(3)));
} else if (regs[i].substring(0,1).equals("R")) {
cbReg.addRegEvent(createREvent(
regs[i].substring(2)));
}
}
String xmlStr = cbReg.convertToXml();
System.out.println(xmlStr);
return (xmlStr);
}
/*
* createAllEvent
* ----------------
* Erstellt ein XML-Registrierungsereignis mit Klasse EC_Cluster und ohne
* Unterklasse.
*/
private Event createAllEvent()
{
Event allEvent = new Event();
allEvent.setClass("EC_Cluster");
return (allEvent);
}
/*
* createMembershipEvent
* ----------------------
* Erstellt ein XML-Registrierungsereignis mit Klasse EC_Cluster, Unterklasse
* ESC_cluster_memberhip.
*/
private Event createMembershipEvent()
{
Event membershipEvent = new Event();
membershipEvent.setClass("EC_Cluster");
membershipEvent.setSubclass("ESC_cluster_membership");
return (membershipEvent);
}
/*
* createRgEvent
* ----------------
* Erstellt ein XML-Registrierungsereignis mit Klasse EC_Cluster,
* Unterklasse ESC_cluster_rg_state und einem "rg_name"-NW-Paar
* (basierend auf Eingabeparameter).
*/
private Event createRgEvent(String rgname)
{
/*
* Ein Ressourcengruppen-Zustandsänderungsereignis wird für die
* rgname-Ressourcengruppe erstellt. Beachten
* Sie, dass für diesen Ereignistyp ein Namens-/Wertepaar (NW-Paar) bereitgestellt
* wird, um anzugeben, an welcher Ressourcegruppe Interesse besteht.
*/
/*
* Ereignisobjekt erstellen und Klasse und Unterklasse einstellen.
*/
Event rgStateEvent = new Event();
rgStateEvent.setClass("EC_Cluster");
rgStateEvent.setSubclass("ESC_cluster_rg_state");
/*
*NW-Paar-Objekt erstellen und zum Ereignis hinzufügen.
*/
NVPair rgNvpair = new NVPair();
rgNvpair.setName("rg_name");
rgNvpair.setValue(rgname);
rgStateEvent.addNvpair(rgNvpair);
return (rgStateEvent);
}
/*
* createREvent
* ----------------
* Erstellt ein XML-Registrierungsereignis mit Klasse EC_Cluster,
* Unterklasse ESC_cluster_r_state und einem "r_name"-NW-Paar
* (basierend auf Eingabeparameter).
*/
private Event createREvent(String rname)
{
/*
* Ein Ressourcenzustandsereignis wird für die
* rgname-Ressource erstellt. Für
* diesen Ereignistyp wird ein Namens-/Wertepaar (NW-Paar) bereitgestellt,
* um anzugeben, an welcher Ressourcengruppe Interesse besteht.
*/
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
* ------------------
* Erstellt ein REMOVE_CLIENT CallbackReg-Objekt und ruft dann die
* XML-Zeichenkette aus dem CallbackReg-Objekt ab.
*/
private String createUnregistrationString() throws Exception
{
/*
* CallbackReg-Objekt erstellen.
*/
CallbackReg cbReg = new CallbackReg();
cbReg.setPort("" + localPort);
cbReg.setRegType(CallbackReg.REMOVE_CLIENT);
/*
* Die Registrierung wird zum OutputStream geleitet
*/
String xmlStr = cbReg.convertToXml();
// Zeichenkette zur Fehlerbehebung drucken
System.out.println(xmlStr);
return (xmlStr);
}
/*
* readRegistrationReply
* ------------------------
* Analysiert XML in einem Dokument, erstellt ein RegReply-Objekt
* basierend auf dem Dokument und druckt das RegReply-Objekt.
* Beachten Sie, dass eine echte Anwendung Aktionen basierend auf dem
* Status-Code des RegReply-Objekts ausführen würde.
*/
private void readRegistrationReply(InputStream stream)
throws Exception
{
// Document Builder erstellen
DocumentBuilder db = dbf.newDocumentBuilder();
//
// Vor Analyse ErrorHandler einrichten
// Standard-Handler verwenden.
//
db.setErrorHandler(new DefaultHandler());
//Eingabedatei analysieren
Document doc = db.parse(stream);
RegReply reply = new RegReply(doc);
reply.print(System.out);
}
/* Private Mitgliedsvariablen */
private InetAddress regIp;
private int regPort;
private EventReceptionThread evtThr;
private String regs[];
/* Öffentliche Mitgliedsvariablen */
public int localPort;
public DocumentBuilderFactory dbf;
}
/*
* class EventReceptionThread
* ----------------------------
* Siehe die obigen Dateiheader-Kommentare.
*/
class EventReceptionThread extends Thread
{
/*
* EventReceptionThread-Konstruktor
* ----------------------------------
* Erstellt ein neues ServerSocket, gebunden an den lokalen
* Hostnamen und einen Platzhalter-Port.
*/
public EventReceptionThread(CrnpClient clientIn) throws IOException
{
/*
* Verweis auf Client festhalten, damit bei Erhalt
* eines Ereignisses eine Rückmeldung erfolgen kann.
*/
client = clientIn;
/*
* IP angeben, an die gebunden werden soll. Dies ist
* die lokale Host-IP. Wenn mehr als eine öffentliche
* Schnittstelle auf diesem Rechner konfiguriert ist, wird
* diejenige verwendet, die von
* InetAddress.getLocalHost angegeben wird.
*
*/
listeningSock = new ServerSocket(client.localPort, 50,
InetAddress.getLocalHost());
System.out.println(listeningSock);
}
/*
* run
* ---
* Aufgerufen durch die Thread.Start-Methode.
*
* Bildet eine Endlosschleife und wartet auf eingehende Verbindungen auf
* dem ServerSocket.
*
* Bei Annahme der einzelnen eingehenden Verbindungen wird jeweils aus dem
* XML-Strom ein Ereignisobjekt erstellt, das an das CrnpClient-Objekt zur
* Verarbeitung zurückgegeben wird.
*/
public void run()
{
/*
* Endlosschleife.
*/
try {
//
// Document Builder unter Verwendung der Document
// Builder Factory im CrnpClient erstellen.
//
DocumentBuilder db = client.dbf.newDocumentBuilder();
//
// Vor der Analyse ErrorHandler einrichten
// Standard-Handler verwenden.
//
db.setErrorHandler(new DefaultHandler());
while(true) {
/* Auf Rückmeldung vom Server warten */
Socket sock = listeningSock.accept();
// Eingabedatei analysieren
Document doc = db.parse(sock.getInputStream());
Event event = new Event(doc);
client.processEvent(event);
/* Socket schließen */
sock.close();
}
// NICHT ERREICHBAR
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
}
/* private Mitgliedsvariablen */
private ServerSocket listeningSock;
private CrnpClient client;
}
/*
* Klasse NVPair
* -----------
* Diese Klasse speichert ein Namens-/Wertepaar (beides Zeichenketten). Sie kann
* eine NVPAIR XML-Meldung aus den Mitgliedern erstellen und ein
* NVPAIR XML-Element in den Mitgliedern analysieren
*
* Beachten Sie, dass die formale Spezifikation eines NVPAIR mehrere Werte zulässt.
* Der Einfachheit halber wird hier angenommen, dass nur ein Wert zulässig ist.
*/
class NVPair
{
/*
* Zwei Konstruktoren: Der erste erstellt ein leeres NVPair, der zweite
* erstellt ein NVPair aus einem NVPAIR XML-Element.
*/
public NVPair()
{
name = value = null;
}
public NVPair(Element elem)
{
retrieveValues(elem);
}
/*
* Öffentliche Setter.
*/
public void setName(String nameIn)
{
name = nameIn;
}
public void setValue(String valueIn)
{
value = valueIn;
}
/*
* Druckt den Namen und Wert in einer einzigen Zeile.
*/
public void print(PrintStream out)
{
out.println("NAME=" + name + " VALUE=" + value);
}
/*
* createXmlElement
* ------------------
* Erstellt ein NVPAIR XML-Element aus den Mitgliedsvariablen.
* Nimmt das Dokument als Parameter, um das Element
* erstellen zu können.
*/
public Element createXmlElement(Document doc)
{
// Element erstellen.
Element nvpair = (Element)
doc.createElement("NVPAIR");
//
// Namen hinzufügen. Beachten Sie, dass der tatsächliche
// Name ein eigener CDATA-Abschnitt ist.
//
Element eName = doc.createElement("NAME");
Node nameData = doc.createCDATASection(name);
eName.appendChild(nameData);
nvpair.appendChild(eName);
//
// Wert hinzufügen. Beachten Sie, dass der tatsächliche
// Wert ein eigener CDATA-Abschnitt ist.
//
Element eValue = doc.createElement("VALUE");
Node valueData = doc.createCDATASection(value);
eValue.appendChild(valueData);
nvpair.appendChild(eValue);
return (nvpair);
}
/*
* retrieveValues
* ----------------
* Analysiert das XML-Element, um Namen und Wert abzurufen.
*/
private void retrieveValues(Element elem)
{
Node n;
NodeList nl;
//
// NAME-Element suchen
//
nl = elem.getElementsByTagName("NAME");
if (nl.getLength() != 1) {
System.out.println("Analysefehler: "
+ "NAME-Knoten kann nicht gefunden werden.");
return;
}
//
// TEXT-Abschnitt abrufen
//
n = nl.item(0).getFirstChild();
if (n == null || n.getNodeType() != Node.TEXT_NODE) {
System.out.println("Analysefehler:"
+ "TEXT-Abschnitt kann nicht gefunden werden.");
return;
}
// Wert abrufen
name = n.getNodeValue();
//
// Jetzt Wertelement abrufen
//
nl = elem.getElementsByTagName("VALUE");
if (nl.getLength() != 1) {
System.out.println("Analysefehler: "
+ "VALUE-Knoten kann nicht gefunden werden.");
return;
}
//
// TEXT-Abschnitt abrufen
//
n = nl.item(0).getFirstChild();
if (n == null || n.getNodeType() != Node.TEXT_NODE) {
System.out.println("Analysefehler: "
+ "TEXT-Abschnitt kann nicht gefunden werden.");
return;
}
// Wert abrufen
value = n.getNodeValue();
}
/*
* Öffentlicher Zugang
*/
public String getName()
{
return (name);
}
public String getValue()
{
return (value);
}
// Private Mitgliedsvariablen
private String name, value;
}
/*
* Klasse Event
* -----------
* Diese Klasse speichert ein Ereignis, das aus Klasse, Unterklasse, Anbieter,
* Herausgeber und einer Liste der Namens-/Wertepaare besteht. Sie kann ein
* SC_EVENT_REG XML-Element aus den Mitgliedern erstellen und ein
* SC_EVENT XML-Element in den Mitgliedern analysieren. Beachten Sie die Assymetrie:
* SC_EVENT-Elemente werden analysiert, SC_EVENT_REG-Elemente dagegen erstellt.
* Das liegt daran, dass SC_EVENT_REG-Elemente in Registrierungsmeldungen verwendet
* werden, die erstellt werden müssen, während die SC_EVENT-Elemente für
* Ereigniszustellungen verwendet werden, die zu analysieren sind. Der einzige Unterschied
* besteht darin, dass SC_EVENT_REG-Elemente keinen Anbieter oder Herausgeber haben.
*/
class Event
{
/*
* Zwei Konstruktoren; Der erste erstellt ein leeres Ereignis, der zweite
* erstellt ein Ereignis anhand eines SC_EVENT XML-Dokuments.
*/
public Event()
{
regClass = regSubclass = null;
nvpairs = new Vector();
}
public Event(Document doc)
{
nvpairs = new Vector();
//
// Dokument für Fehlerbehebungszwecke in eine
// Zeichenkette konvertieren.
//
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());
// Analyse ausführen.
retrieveValues(doc);
}
/*
* Öffentliche Setter.
*/
public void setClass(String classIn)
{
regClass = classIn;
}
public void setSubclass(String subclassIn)
{
regSubclass = subclassIn;
}
public void addNvpair(NVPair nvpair)
{
nvpairs.add(nvpair);
}
/*
* createXmlElement
* ------------------
* Erstellt ein SC_EVENT_REG XML-Element aus den Mitgliedsvariablen.
* Verwendet das Dokument als Parameter, um das Element zu
* erstellen. Beruht auf der createXmlElement-Fähigkeit des NW-Paars.
*/
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);
}
/*
* Druckt die Mitgliedsvariablen in mehreren Zeilen.
*/
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
* ----------------
* Analysiert XML-Dokument, um Klasse, Unterklasse, Hersteller,
* Herausgeber und NW-Paare abzurufen.
*/
private void retrieveValues(Document doc)
{
Node n;
NodeList nl;
//
// SC_EVENT-Element suchen.
//
nl = doc.getElementsByTagName("SC_EVENT");
if (nl.getLength() != 1) {
System.out.println("Analysefehler "
+ "SC_EVENT-Knoten kann nicht gefunden werden.");
return;
}
n = nl.item(0);
//
// Werte der Attribute CLASS, SUBCLASS,
// VENDOR und PUBLISHER abrufen.
//
regClass = ((Element)n).getAttribute("CLASS");
regSubclass = ((Element)n).getAttribute("SUBCLASS");
publisher = ((Element)n).getAttribute("PUBLISHER");
vendor = ((Element)n).getAttribute("VENDOR");
//
// Alle NW-Paare abrufen
//
for (Node child = n.getFirstChild(); child != null;
child = child.getNextSibling())
{
nvpairs.add(new NVPair((Element)child));
}
}
/*
* Öffentliche Zugangsmethoden.
*/
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 Mitgliedsvariablen.
private String regClass, regSubclass;
private Vector nvpairs;
private String vendor, publisher;
}
/*
* class CallbackReg
* -----------
* Diese Klasse speichert einen Port und einen Reg.typ (beides Zeichenketten) sowie eine
* Ereignisliste. Sie kann eine SC_CALLBACK_REG XML-Meldung anhand ihrer Mitglieder erstellen.
*
* Beachten Sie, dass diese Klasse keine SC_CALLBACK_REG-Meldungen analysieren können muss,
* da nur der CRNP-Server SC_CALLBACK_REG-Meldungen analysieren muss.
*/
class CallbackReg
{
// Nützliche Definitionen für die setRegType-Methode
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();
}
/*
* Öffentliche Setter.
*/
public void setPort(String portIn)
{
port = portIn;
}
public void setRegType(int regTypeIn)
{
switch (regTypeIn) {
case ADD_CLIENT:
regType = "ADD_CLIENT";
break;
case ADD_EVENTS:
regType = "ADD_EVENTS";
break;
case REMOVE_CLIENT:
regType = "REMOVE_CLIENT";
break;
case REMOVE_EVENTS:
regType = "REMOVE_EVENTS";
break;
default:
System.out.println("Fehler, ungültiger regType " +
regTypeIn);
regType = "ADD_CLIENT";
break;
}
}
public void addRegEvent(Event regEvent)
{
regEvents.add(regEvent);
}
/*
* convertToXml
* ------------------
* Erstellt ein SC_CALLBACK_REG XML-Dokument anhand der
* Mitgliedsvariablen. Beruht auf der createXmlElement-Fähigkeit
* des Ereignisses.
*/
public String convertToXml()
{
Document document = null;
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.newDocument();
} catch (ParserConfigurationException pce) {
// Analysierer mit den angegebenen Optionen kann nicht erstellt werden
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);
//
// Jetzt Dokument in eine Zeichenkette konvertieren.
//
DOMSource domSource = new DOMSource(document);
StringWriter strWrite = new StringWriter();
StreamResult streamResult = new StreamResult(strWrite);
TransformerFactory tf = TransformerFactory.newInstance();
try {
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, streamResult);
} catch (TransformerException e) {
System.out.println(e.toString());
return ("");
}
return (strWrite.toString());
}
// private Mitgliedsvariablen
private String port;
private String regType;
private Vector regEvents;
}
/*
* class RegReply
* -----------
* Diese Klasse speichert einen status_code und status_msg (beides Zeichenketten).
* Sie kann ein SC_REPLY XML-Element mitsamt seinen Mitgliedern analysieren.
*/
class RegReply
{
/*
* Der einzige Konstruktor übernimmt ein XML-Dokument und analysiert es.
*/
public RegReply(Document doc)
{
//
// Jetzt Dokument in eine Zeichenkette konvertieren.
//
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);
}
/*
* Öffentlicher Zugang
*/
public String getStatusCode()
{
return (statusCode);
}
public String getStatusMsg()
{
return (statusMsg);
}
/*
* Druckt die Informationen in einer einzigen Zeile.
*/
public void print(PrintStream out)
{
out.println(statusCode + ": " +
(statusMsg != null ? statusMsg : ""));
}
/*
* retrieveValues
* ----------------
* Analysiert das XML-Dokument, um statusCode und statusMsg abzurufen.
*/
private void retrieveValues(Document doc)
{
Node n;
NodeList nl;
//
// SC_REPLY-Element suchen.
//
nl = doc.getElementsByTagName("SC_REPLY");
if (nl.getLength() != 1) {
System.out.println("Analysefehler: "
+ "SC_REPLY-Knoten kann nicht gefunden werden.");
return;
}
n = nl.item(0);
// Wert des STATUS_CODE-Attributs abrufen
statusCode = ((Element)n).getAttribute("STATUS_CODE");
//
// SC_STATUS_MSG-Element suchen
//
nl = ((Element)n).getElementsByTagName("SC_STATUS_MSG");
if (nl.getLength() != 1) {
System.out.println("Analysefehler"
+ "SC_STATUS_MSG-Knoten kann nicht gefunden werden.");
return;
}
//
// TEXT-Abschnitt abrufen, falls vorhanden.
//
n = nl.item(0).getFirstChild();
if (n == null || n.getNodeType() != Node.TEXT_NODE) {
// Kein Fehler, falls nicht vorhanden; einfach
// stillschweigend zurückkehren.
return;
}
// Wert abrufen
statusMsg = n.getNodeValue();
}
// private Mitgliedsvariablen
private String statusCode;
private String statusMsg;
}