L’exemple suivant montre comment développer une Java application appelée crnpclient utilisée par CRNP. L’application enregistre les rappel des événements avec le serveur CRNP du cluster, écoute les événements et traite ces événements en imprimant son contenu. Avant de finaliser, l’application annule l’enregistrement de votre demande de rappel d’événements.
Notez les points suivants lors de l’examen de cet exemple:
-
Cet exemple présente des parties d’une application, décrite intégralement en annexe. G, application crnpclient.java. Pour expliquer plus efficacement certains concepts, l’exemple de ce chapitre varie légèrement de la demande complète présentée à l’annexe G, CrnpClient.java Application.
-
Pour être plus concis, pas d’exemple de code Les délimiteurs ont été inclus dans ce chapitre. Pour les voir, reportez-vous à la demande complète à l’Annexe G, CrnpClient.java Application.
-
L’application qui apparaît dans cet exemple gère la plupart des conditions d’erreur en clôturant simplement l’application. L’application réelle doit traiter des erreurs plus fermement.
L’exemple de l’application génère et Analyses XML avec JAXP (API Java pour le traitement XML). Cet exemple ne montre pas comment utiliser JAXP. Cet outil est décrit plus en détail dans http://java.sun.com/xml/jaxp/index.html.
Comment configurer l’environnement
étapes
-
dans le répertoire dans lequel le fichier source est situé, tapez les éléments suivants:
% javac -classpath jaxp-root/dom.jar:jaxp-rootjaxp-api. \jar:jaxp-rootsax.jar:jaxp-rootxalan.jar:jaxp-root/xercesImpl \.jar:jaxp-root/xsltc.jar -sourcepath . source-filename.java
où Jaxp-root est la route absolue ou relative de l’annuaire où résident Jaxp et Source-FileName Files est le nom du fichier Java d’origine.
Si la classe de classe est incluse dans la ligne de commande de compilation, cela garantira que le compilateur peut trouver des classes JAXP.
-
exécutez l’application, spécifiez le chemin de classe dans la classe de classe afin que L’application peut exécuter les fichiers de classe JAXP corrects (Hold in Cuent À laquelle la première route de classe de classe pointe vers le répertoire actuel):
Maintenant que l’environnement a été configuré, vous pouvez développer l’application .
Téléchargez et installez JAXP et la version correcte de la machine virtuelle Java Compiler et Java.
Vous pouvez trouver des instructions sur http://java.sun.com/xml/jaxp/index.html Note – > Cet exemple nécessite au moins Java 1.3.1.
Comment commencer à développer l’application
Dans cette partie de l’exemple, vous devez créer une classe de base appelée crnpclient avec une méthode principale qui analyse Les arguments de la ligne de commande et construisent un objet CRNPCLIENT. Cet objet passe les arguments de la ligne de commande à la classe, attendez que l’utilisateur terminer l’application, l’arrêt de l’appel dans la classe CRNPCLIent et la vente.
Le constructeur de classe CRNPCLIENT doit exécuter les tâches suivantes:
-
configure les objets de processus XML.
-
Créer un sous-processus qui reçoit des réductions d’événements.
-
Contactez le serveur CRNP et enregistrez les recaissements des événements.
pas
Créer le code Java qui applique la logique précédente.
L’exemple suivant montre le code de la structure de base de la classe CRNPClient. Les implémentations des méthodes auxiliaires mentionnées dans les méthodes de clôture et le constructeur sont indiqués ci-dessous dans ce chapitre, gardez à l’esprit que le code qui compte tous les packages nécessaires est affiché.
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); regPort = (new Integer(args)).intValue(); localPort = (new Integer(args)).intValue(); } catch (UnknownHostException e) { System.out.println(e); System.exit(1); } CrnpClient client = new CrnpClient(regIp, regPort, localPort, args); System.out.println("Hit return to terminate demo..."); try { System.in.read(); } catch (IOException e) { System.out.println(e.toString()); } client.shutdown(); System.exit(0); } public CrnpClient(InetAddress regIpIn, int regPortIn, int localPortIn, String clArgs) { try { regIp = regIpIn; regPort = regPortIn; localPort = localPortIn; regs = clArgs; setupXmlProcessing(); createEvtRecepThr(); registerCallbacks(); } catch (Exception e) { System.out.println(e.toString()); System.exit(1); } } public void shutdown() { try { unregister(); } catch (Exception e) { System.out.println(e); System.exit(1); } } private InetAddress regIp; private int regPort; private EventReceptionThread evtThr; private String regs; public int localPort; public DocumentBuilderFactory dbf;}
Les variables de membre sont décrites plus loin dans ce chapitre.
Comment analyser les arguments de la ligne de commandes
STEP
Pour analyser les arguments de la ligne de commande, voir le code inclus dans l’application ANNEXE G, CRNPCLIENT.JAVA.
Comment définir l’événement recevant le sous-processus
dans le code, vous devez vérifier que la réception des événements est effectuée dans un thread séparé de sorte que l’application puisse continuer à effectuer les autres travaux, tandis que le sous-processus d’événement est bloqué. et recâts attendus d’événement.
Remarque –
La configuration XML est décrite plus loin dans ce chapitre.
étapes
-
Construisez un objet CreateeVTrecepth.
private void createEvtRecepThr() throws Exception{ evtThr = new EventReceptionThread(this); evtThr.start();}
dans le code, définissez La sous-classe de threads appelée EventReCeptionThread qui crée une prise, une boucherie et attend la réception des événements dans la prise.
Dans cette partie du code d’échantillon, les événements ne savent pas lire ou sont traités. La lecture et le traitement des événements sont décrits plus loin dans ce chapitre.EventReCeptionThread crée une prise, une conversation, une adresse de protocole d’intendance avec des caractères génériques. EventReceSepeterthread gère également une référence à l’objet CRNPCLIENT afin que l’éventuelleReCEptionThead puisse envoyer des événements à l’objet CRNPCLIENT pour le traitement.
class EventReceptionThread extends Thread{ public EventReceptionThread(CrnpClient clientIn) throws IOException { client = clientIn; listeningSock = new ServerSocket(client.localPort, 50, InetAddress.getLocalHost()); } public void run() { try { DocumentBuilder db = client.dbf.newDocumentBuilder(); db.setErrorHandler(new DefaultHandler()); while(true) { Socket sock = listeningSock.accept(); // Construct event from the sock stream and process it sock.close(); } // UNREACHABLE } catch (Exception e) { System.out.println(e); System.exit(1); } } /* private member variables */ private ServerSocket listeningSock; private CrnpClient client;}
Comment enregistrer ou annuler l’enregistrement
Le processus d’enregistrement implique les actions suivantes:
-
Ouvrez une prise TCP de base pour le port et l’enregistrement du protocole interred
-
Créer le message journal XML
-
Envoyez le message journal XML sur la prise
-
Lire le message de réponse XML hors de la prise
-
Fermer la prise
ÉTAPES
-
Créer le code Java qui applique la logique précédente.
Le code d’échantillon suivant affiche la mise en oeuvre de la méthode RegisterCallbacks de la classe CRNPClient (appelée par le constructeur CRNPCLIENT). Les appels vers CreaterGistroStrationsRing () et ReadregistrationReply () sont décrits plus détaillés plus loin dans ce chapitre.
RegIp et Report sont des objets membres configurés par le constructeur.
private void registerCallbacks() throws Exception{ Socket sock = new Socket(regIp, regPort); String xmlStr = createRegistrationString(); PrintStream ps = new PrintStream(sock.getOutputStream()); ps.print(xmlStr); readRegistrationReply(sock.getInputStream(); sock.close();}
-
Appliquez la méthode description.
La méthode d’arrêt de CrnpClient appelle cette méthode. La mise en œuvre de CreateEgistrationTring est décrite plus détaillée plus loin dans ce chapitre.
Comment générer xml
maintenant que la structure de l’application a été configurée et elle A été écrit tout le code de réseau, le code qui génère et analyse XML doit être écrit. Tout d’abord, écrivez le code qui génère le message de registre XML SC_CALLBACK_REG.
Un message SC_CALLBACK_REG est formé par un type d’enregistrement (add_client, retirer_client, add_events ou supprimer_events), un port de recomposition et une liste d’événements d’intérêt et une liste d’événements d’intérêt . Chaque événement consiste en une classe et une sous-classe, suivi d’une liste de noms de noms et de valeurs.
Dans cette partie de l’exemple, une classe Callbackreg est écrite qui enregistre le type d’enregistrement, le port de recomposition et la liste des événements d’inscription. Cette classe peut également être sérialisée pour un message XML SC_CALLBACK_REG.
Une méthode intéressante de cette classe est converttoxml, qui crée une chaîne de message XML SC_CALLBACK_REG des membres de la classe. La documentation JAXP située dans http://java.sun.com/xml/jaxp/index.html décrit plus détaillé le code de cette méthode plus détaillé.
La mise en œuvre de la classe d’événements est affichée dans le code d’échantillon suivant. Notez que la classe Callbackreg utilise une classe d’événements, ce qui vous permet de stocker un événement et de le convertir en un élément, élément, xml.
étapes
-
Implémentez les classes de l’événement et de la NVPAIR.
Notez que la classe Callbackreg utilise l’événement, que dans Tour utilise une classe NVPair.
class Event{ public Event() { regClass = regSubclass = null; nvpairs = new Vector(); } public void setClass(String classIn) { regClass = classIn; } public void setSubclass(String subclassIn) { regSubclass = subclassIn; } public void addNvpair(NVPair nvpair) { nvpairs.add(nvpair); } public Element createXmlElement(Document doc) { Element event = (Element) doc.createElement("SC_EVENT_REG"); event.setAttribute("CLASS", regClass); if (regSubclass != null) { event.setAttribute("SUBCLASS", regSubclass); } for (int i = 0; i < nvpairs.size(); i++) { NVPair tempNv = (NVPair) (nvpairs.elementAt(i)); event.appendChild(tempNv.createXmlElement(doc)); } return (event); } private String regClass, regSubclass; private Vector nvpairs;}class NVPair{ public NVPair() { name = value = null; } public void setName(String nameIn) { name = nameIn; } public void setValue(String valueIn) { value = valueIn; } public Element createXmlElement(Document doc) { Element nvpair = (Element) doc.createElement("NVPAIR"); Element eName = doc.createElement("NAME"); Node nameData = doc.createCDATASection(name); eName.appendChild(nameData); nvpair.appendChild(eName); Element eValue = doc.createElement("VALUE"); Node valueData = doc.createCDATASection(value); eValue.appendChild(valueData); nvpair.appendChild(eValue); return (nvpair); } private String name, value;}
créer Le code Java qui applique la logique précédente.
class CallbackReg{ public static final int ADD_CLIENT = 0; public static final int ADD_EVENTS = 1; public static final int REMOVE_EVENTS = 2; public static final int REMOVE_CLIENT = 3; public CallbackReg() { port = null; regType = null; regEvents = new Vector(); } public void setPort(String portIn) { port = portIn; } public void setRegType(int regTypeIn) { switch (regTypeIn) { case ADD_CLIENT: regType = "ADD_CLIENT"; break; case ADD_EVENTS: regType = "ADD_EVENTS"; break; case REMOVE_CLIENT: regType = "REMOVE_CLIENT"; break; case REMOVE_EVENTS: regType = "REMOVE_EVENTS"; break; default: System.out.println("Error, invalid regType " + regTypeIn); regType = "ADD_CLIENT"; break; } } public void addRegEvent(Event regEvent) { regEvents.add(regEvent); } public String convertToXml() { Document document = null; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.newDocument(); } catch (ParserConfigurationException pce) { // Parser with specified options can't be built pce.printStackTrace(); System.exit(1); } // Create the root element Element root = (Element) document.createElement("SC_CALLBACK_REG"); // Add the attributes root.setAttribute("VERSION", "1.0"); root.setAttribute("PORT", port); root.setAttribute("regType", regType); // Add the events for (int i = 0; i < regEvents.size(); i++) { Event tempEvent = (Event) (regEvents.elementAt(i)); root.appendChild(tempEvent.createXmlElement(document)); } document.appendChild(root); // Convert the whole thing to a string DOMSource domSource = new DOMSource(document); StringWriter strWrite = new StringWriter(); StreamResult streamResult = new StreamResult(strWrite); TransformerFactory tf = TransformerFactory.newInstance(); try { Transformer transformer = tf.newTransformer(); transformer.transform(domSource, streamResult); } catch (TransformerException e) { System.out.println(e.toString()); return (""); } return (strWrite.toString()); } private String port; private String regType; private Vector regEvents;}
Comment créer des messages de registre et des messages d’annulation
une fois les classes créées à partir des Auxiliaires Génération de messages XML, vous pouvez écrire la mise en œuvre de la méthode CreaterGistroStringString. RegisterCallbacks appelle cette méthode; Ce processus est décrit dans la procédure à suivre dans la réduction de la réduction ou de l’annulation du registre.
CrakeeGistroStringString crée un objet Callbackreg et définit son port et son type d’enregistrement. Ensuite, CreaterGistroStringString crée divers événements grâce aux méthodes de la création des ailiaires CreeAption, CreatememberbershipEvent, CreateSevent et CatteeePent. Chaque événement est ajouté à l’objet CallLbackreg après la création. Enfin, CreaterGistroStringString appelle la méthode Convertoxml dans l’objet Callbackreg pour extraire le message XML du formulaire de chaîne.
Notez que la variable de membre REGS stocke les arguments de la ligne de commande fournie par l’utilisateur pour l’application. La cinquième argument et suivant spécifier les événements pour lesquels la demande doit être enregistrée. Le quatrième argument spécifie le type d’enregistrement, mais est ignoré dans cet exemple. Le code complet inclus dans l’appendice G, CrnpClient.java Application montre comment utiliser ce quatrième argument.
étapes
-
Créer le code Java qui applique la logique précédente .
private String createRegistrationString() throws Exception{ CallbackReg cbReg = new CallbackReg(); cbReg.setPort("" + localPort); cbReg.setRegType(CallbackReg.ADD_CLIENT); // add the events for (int i = 4; i < regs.length; i++) { if (regs.equals("M")) { cbReg.addRegEvent(createMembershipEvent()); } else if (regs.equals("A")) { cbReg.addRegEvent(createAllEvent()); } else if (regs.substring(0,2).equals("RG")) { cbReg.addRegEvent(createRgEvent(regs.substring(3))); } else if (regs.substring(0,1).equals("R")) { cbReg.addRegEvent(createREvent(regs.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);}
-
Créer la chaîne d’annulation de l’enregistrement.
Création La chaîne d’annulation de l’enregistrement est un processus plus simple que le Création de la chaîne d’inscription, puisqu’elle n’est pas nécessaire d’adapter des événements.
private String createUnregistrationString() throws Exception{ CallbackReg cbReg = new CallbackReg(); cbReg.setPort("" + localPort); cbReg.setRegType(CallbackReg.REMOVE_CLIENT); String xmlStr = cbReg.convertToXml(); return (xmlStr);}
Comment configurer l’analyseur XML
Une fois le code de génération XML et du réseau pour l’application , le constructeur CRNPCLIENT appelle la méthode SetupxMlProcessing, qui crée un objet de document de documentation et établit plusieurs propriétés d’analyse dans cet objet. La documentation JAXP décrit cette méthode plus détaillée. Voir http://java.sun.com/xml/jaxp/index.html.
étape
Créer le code Java qui applique la logique précédente.
private void setupXmlProcessing() throws Exception{ dbf = DocumentBuilderFactory.newInstance(); // We don't need to bother validating dbf.setValidating(false); dbf.setExpandEntityReferences(false); // We want to ignore comments and whitespace dbf.setIgnoringComments(true); dbf.setIgnoringElementContentWhitespace(true); // Coalesce CDATA sections into TEXT nodes. dbf.setCoalescing(true);}
Comment analyser le message de réponse d’enregistrement
Pour analyser le message XML SC_ReSly que CRNP envoie en réponse à un Message d’inscription ou d’annulation, il est nécessaire d’avoir une classe auxiliaire regrewly, qui peut être construite à partir d’un document XML. Cette classe fournit des accesseurs pour le code d’état et le message d’état. Pour analyser la séquence XML du serveur, il est nécessaire de créer un nouveau document XML et d’utiliser votre méthode d’analyse. Documentation JAXP située dans http://java.sun.com/xml/jaxp/index.html décrit cette méthode plus détaillée.
étapes
-
Créer le code Java qui applique le code Java qui applique la Logique précédente.
Notez que la méthode ReadregistrationReply utilise la nouvelle classe regrewly.
-
Implémentez la classe regrewly.
Notez que la méthode RetrieveValues traverse l’arborescence DOM du document XML et extrait le code et le message d’état. La documentation JAXP située dans http://java.sun.com/xml/jaxp/index.html contient plus d’informations.
class RegReply{ public RegReply(Document doc) { retrieveValues(doc); } public String getStatusCode() { return (statusCode); } public String getStatusMsg() { return (statusMsg); } public void print(PrintStream out) { out.println(statusCode + ": " + (statusMsg != null ? statusMsg : "")); } private void retrieveValues(Document doc) { Node n; NodeList nl; String nodeName; // Find the SC_REPLY element. nl = doc.getElementsByTagName("SC_REPLY"); if (nl.getLength() != 1) { System.out.println("Error in parsing: can't find " + "SC_REPLY node."); return; } n = nl.item(0); // Retrieve the value of the statusCode attribute statusCode = ((Element)n).getAttribute("STATUS_CODE"); // Find the SC_STATUS_MSG element nl = ((Element)n).getElementsByTagName("SC_STATUS_MSG"); if (nl.getLength() != 1) { System.out.println("Error in parsing: can't find " + "SC_STATUS_MSG node."); return; } // Get the TEXT section, if there is one. n = nl.item(0).getFirstChild(); if (n == null || n.getNodeType() != Node.TEXT_NODE) { // Not an error if there isn't one, so we just silently return. return; } // Retrieve the value statusMsg = n.getNodeValue(); } private String statusCode; private String statusMsg;}
Comment analyser les événements de recomposition
La dernière étape consiste à analyser et à traiter les événements Réels de recomposition. Pour vous aider dans cette tâche, vous devez modifier la classe d’événement créée sur la manière de générer XML afin que cette classe puisse créer un événement, événement, à partir d’un document XML et créer un élément, élément, XML: ce changement nécessite un constructeur supplémentaire ( Cela inclut un document XML), une méthode de récupération, ajout de deux variables (fournisseur et éditeur), méthodes d’accès à tous les champs et, enfin, une méthode d’impression.
étapes
-
Créez le code Java qui applique la logique précédente.
Veuillez noter que ce code est similaire à celui de la classe Regreply, décrite sur la manière d’analyser le message de réponse d’enregistrement.
public Event(Document doc) { nvpairs = new Vector(); retrieveValues(doc); } public void print(PrintStream out) { out.println("\tCLASS=" + regClass); out.println("\tSUBCLASS=" + regSubclass); out.println("\tVENDOR=" + vendor); out.println("\tPUBLISHER=" + publisher); for (int i = 0; i < nvpairs.size(); i++) { NVPair tempNv = (NVPair) (nvpairs.elementAt(i)); out.print("\t\t"); tempNv.print(out); } } private void retrieveValues(Document doc) { Node n; NodeList nl; String nodeName; // Find the SC_EVENT element. nl = doc.getElementsByTagName("SC_EVENT"); if (nl.getLength() != 1) { System.out.println("Error in parsing: can't find " + "SC_EVENT node."); return; } n = nl.item(0); // // Retrieve the values of the CLASS, SUBCLASS, // VENDOR and PUBLISHER attributes. // regClass = ((Element)n).getAttribute("CLASS"); regSubclass = ((Element)n).getAttribute("SUBCLASS"); publisher = ((Element)n).getAttribute("PUBLISHER"); vendor = ((Element)n).getAttribute("VENDOR"); // Retrieve all the nv pairs for (Node child = n.getFirstChild(); child != null; child = child.getNextSibling()) { nvpairs.add(new NVPair((Element)child)); } } public String getRegClass() { return (regClass); } public String getSubclass() { return (regSubclass); } public String getVendor() { return (vendor); } public String getPublisher() { return (publisher); } public Vector getNvpairs() { return (nvpairs); } private String vendor, publisher;
-
Mise en œuvre des fabricants supplémentaires et des méthodes de la classe NVPAIR compatible avec l’analyse XML.
Les modifications apportées à l’événement montré à l’étape 1 doivent également être effectuées dans la classe NVPAIR.
public NVPair(Element elem) { retrieveValues(elem); } public void print(PrintStream out) { out.println("NAME=" + name + " VALUE=" + value); } private void retrieveValues(Element elem) { Node n; NodeList nl; String nodeName; // Find the NAME element nl = elem.getElementsByTagName("NAME"); if (nl.getLength() != 1) { System.out.println("Error in parsing: can't find " + "NAME node."); return; } // Get the TEXT section n = nl.item(0).getFirstChild(); if (n == null || n.getNodeType() != Node.TEXT_NODE) { System.out.println("Error in parsing: can't find " + "TEXT section."); return; } // Retrieve the value name = n.getNodeValue(); // Now get the value element nl = elem.getElementsByTagName("VALUE"); if (nl.getLength() != 1) { System.out.println("Error in parsing: can't find " + "VALUE node."); return; } // Get the TEXT section n = nl.item(0).getFirstChild(); if (n == null || n.getNodeType() != Node.TEXT_NODE) { System.out.println("Error in parsing: can't find " + "TEXT section."); return; } // Retrieve the value value = n.getNodeValue(); } public String getName() { return (name); } public String getValue() { return (value); }}
-
Implémentez la boucle tandis que la boucle de l’événement, qui attend les rappels des événements.
EventRecereptionthead est décrit sur la manière de définir le sous-processus de réception des événements.
while(true) { Socket sock = listeningSock.accept(); Document doc = db.parse(sock.getInputStream()); Event event = new Event(doc); client.processEvent(event); sock.close(); }
Comment exécuter l’application
étapes
-
Devenir superutilisateur ou supposez une fonction similaire.
-
exécuter l’application.
# java CrnpClient crnpHost crnpPort localPort ...
Le code complet de l’application CRNPCLIENT est affiché dans l’annexe G, application CRNPCLIENT.JAVA.