Dieser Anhang enthält die vollständige CrnpClient.java-Anwendung, auf die in Kapitel 12 näher eingegangen wird.
/* * 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; }