다음 예에서는 CRNP를 사용하는 CrnpClient라는 간단한 Java 응용 프로그램을 개발하는 방법을 보여줍니다. 이 응용 프로그램은 클러스터의 CRNP 서버에 이벤트 콜백을 등록하고 이러한 이벤트 콜백을 수신하며 해당 내용을 인쇄하여 이벤트를 처리합니다. 종료하기 전에 이 응용 프로그램은 이벤트 콜백에 대한 요청을 등록 취소합니다.
다음 사항에 주의하면서 이 예를 검토합니다.
샘플 응용 프로그램은 JAXP(Java API for XML Processing)를 사용하여 XML을 생성하고 구문을 분석합니다. JAXP를 사용하는 방법은 이 예에서 다루지 않습니다. AXP에 대한 자세한 내용은 http://java.sun.com/xml/jaxp/index.html을 참조하십시오.
이 예에서는 전체 응용 프로그램의 일부를 제공하며 응용 프로그램의 전체 내용은 부록 G, CrnpClient.java 응용 프로그램에 나와 있습니다. 특정 개념을 보다 효율적으로 보여주기 위해 이 장에서 제공하는 예는 부록 G, CrnpClient.java 응용 프로그램에 나온 전체 응용 프로그램과 약간 다릅니다.
내용을 간단히 하기 위해 이 장의 예에서는 샘플 코드의 주석을 제외했습니다. 부록 G, CrnpClient.java 응용 프로그램의 전체 응용 프로그램에는 주석이 포함되어 있습니다.
이 예에 나온 응용 프로그램은 단순히 응용 프로그램을 종료하는 방법으로 대부분의 오류 상태를 처리합니다. 실제 응용 프로그램은 보다 안정적인 방법으로 오류를 처리해야 합니다.
JAXP와 올바른 버전의 Java 컴파일러 및 가상 머신을 다운로드하여 설치합니다.
http://java.sun.com/xml/jaxp/index.html에서 지침을 확인할 수 있습니다.
이 예를 사용하려면 Java 1.3.1 이상이 필요합니다.
소스 파일이 있는 디렉토리에서 다음을 입력합니다.
% 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 |
여기서 jaxp-root는 JAXP jar 파일이 있는 디렉토리의 절대 또는 상대 경로 이며 source-filename은 Java 소스 파일의 이름입니다.
컴파일러가 JAXP 클래스를 찾을 수 있도록 컴파일 명령줄에 classpath 를 지정해야 합니다.
응용 프로그램을 실행할 때 응용 프로그램이 적절한 JAXP 클래스 파일을 로드할 수 있도록 다음과 같이 classpath를 지정합니다. classpath의 첫 번째 경로는 현재 디렉토리입니다.
% java -cp .:jaxp-root/dom.jar:jaxp-rootjaxp-api. \ jar:jaxp-rootsax.jar:jaxp-rootxalan.jar:jaxp-root/xercesImpl \ .jar:jaxp-root/xsltc.jar source-filename arguments |
이제 환경이 구성되었으므로 응용 프로그램을 개발할 수 있습니다.
이 부분의 예에서는 명령줄 인자를 구문 분석하고 CrnpClient 객체를 생성하는 주 메소드를 가진 CrnpClient라는 기본 클래스를 만듭니다. 이 객체는 클래스에 명령줄 인자를 전달하고 사용자가 응용 프로그램을 종료하기를 기다렸다가 CrnpClient에서 shutdown을 호출한 다음 종료합니다.
CrnpClient 클래스의 구성자는 다음 작업을 실행해야 합니다.
XML 처리 객체를 설정합니다.
이벤트 콜백을 수신하는 스레드를 만듭니다.
CRNP 서버에 연결하고 이벤트 콜백을 등록합니다.
앞의 논리를 구현하는 Java 코드를 만듭니다.
다음 예에서는 CrnpClient 클래스의 스켈레톤 코드를 보여줍니다. 구성자 및 종료 메소드에서 참조되는 4개의 도우미 메소드에 대한 구현은 나중에 표시됩니다. 필요한 모든 패키지를 가져오는 코드가 표시됩니다.
import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.stream.*; import org.xml.sax.*; import org.xml.sax.helpers.*; import org.w3c.dom.*; import java.net.*; import java.io.*; import java.util.*; class CrnpClient { public static void main(String []args) { InetAddress regIp = null; int regPort = 0, localPort = 0; try { regIp = InetAddress.getByName(args[0]); regPort = (new Integer(args[1])).intValue(); localPort = (new Integer(args[2])).intValue(); } catch (UnknownHostException e) { System.out.println(e); System.exit(1); } CrnpClient client = new CrnpClient(regIp, regPort, localPort, args); System.out.println("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; }
구성원 변수에 대해서는 나중에 자세히 설명됩니다.
명령줄 인자를 구문 분석하려면 부록 G, CrnpClient.java 응용 프로그램의 코드를 참조하십시오.
이벤트 스레드가 차단되어 이벤트 콜백을 대기하는 동안 응용 프로그램에서 다른 작업을 계속할 수 있으려면 코드에서 이벤트 수신이 별도의 스레드에서 수행되도록 지정해야 합니다.
XML 설정에 대해서는 나중에 자세히 설명됩니다.
ServerSocket을 만들고 이 소켓에서 이벤트가 도착하기를 기다리는 EventReceptionThread라는 Thread 하위 클래스를 코드에 정의합니다.
이 코드 예 부분에서는 이벤트를 읽거나 처리하지 않습니다. 이벤트 읽기 및 처리에 대해서는 나중에 자세히 설명됩니다. EventReceptionThread는 와일드카드 인터네트워킹 프로토콜 주소에서 ServerSocket을 만듭니다. EventReceptionThread는 CrnpClient 객체에 대한 참조를 유지하므로 EventReceptionThread에서 처리할 CrnpClient 객체에 이벤트를 보낼 수 있습니다.
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; }
createEvtRecepThr 객체를 생성합니다.
private void createEvtRecepThr() throws Exception { evtThr = new EventReceptionThread(this); evtThr.start(); }
등록 작업은 다음과 같이 구성됩니다.
등록 인터네트워킹 프로토콜 및 포트에 대한 기본 TCP 소켓 열기
XML 등록 메시지 생성
소켓에서 XML 등록 메시지 보내기
소켓으로부터 XML 응답 메시지 읽기
소켓 닫기
앞의 논리를 구현하는 Java 코드를 만듭니다.
다음 예제 코드에서는 CrnpClient 구성자에 의해 호출되는 CrnpClient 클래스의 registerCallbacks 메소드에 대한 구현을 보여줍니다. createRegistrationString() 및 readRegistrationReply() 호출에 대해서는 나중에 자세히 설명됩니다.
regIp 및 regPort는 구성자에 의해 설정되는 객체 구성원입니다.
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(); }
unregister 메소드를 구현합니다.
이 메소드는 CrnpClient의 shutdown 메소드에 의해 호출됩니다. createUnregistrationString 구현에 대해서는 나중에 자세히 설명됩니다.
private void unregister() throws Exception { Socket sock = new Socket(regIp, regPort); String xmlStr = createUnregistrationString(); PrintStream ps = new PrintStream(sock.getOutputStream()); ps.print(xmlStr); readRegistrationReply(sock.getInputStream()); sock.close(); }
이제 응용 프로그램의 구조를 설정하고 모든 네트워킹 코드를 작성했으므로 XML을 생성 및 구문 분석하는 코드를 작성합니다. 먼저 SC_CALLBACK_REG XML 등록 메시지를 생성하는 코드를 작성합니다.
SC_CALLBACK_REG 메시지는 등록 유형(ADD_CLIENT, REMOVE_CLIENT, ADD_EVENTS 또는 REMOVE_EVENTS), 콜백 포트 및 원하는 이벤트 목록으로 구성됩니다. 각 이벤트는 클래스 및 하위 클래스로 구성되며 이름 및 값 쌍 목록이 그 뒤에 옵니다.
이 예 부분에서는 등록 유형, 콜백 포트 및 등록 이벤트 목록을 저장하는 CallbackReg 클래스를 작성합니다. 이 클래스는 또한 SC_CALLBACK_REG XML 메시지에 대해 자신을 일련화할 수 있습니다.
이 클래스에서 흥미로운 메소드는 클래스 구성원에서 SC_CALLBACK_REG XML 메시지 문자열을 만드는 convertToXml 메소드입니다. http://java.sun.com/xml/jaxp/index.html의 JAXP 설명서에는 이 메소드의 코드가 자세히 설명되어 있습니다.
다음 예제 코드에는 Event 클래스의 구현이 나와 있습니다. CallbackReg 클래스는 하나의 이벤트를 저장하고 이 이벤트를 XML Element로 변환할 수 있는 Event 클래스를 사용합니다.
앞의 논리를 구현하는 Java 코드를 만듭니다.
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; }
Event 및 NVPair 클래스를 구현합니다.
CallbackReg 클래스는 NVPair 클래스를 직접 사용하는 Event 클래스를 사용합니다.
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; }
이제 XML 메시지를 생성하는 도우미 클래스를 만들었으므로 createRegistrationString 메소드의 구현을 작성할 수 있습니다. 이 메소드는 콜백 등록 및 등록 취소 방법에 설명된 registerCallbacks 메소드에 의해 호출됩니다.
createRegistrationString은 CallbackReg 객체를 생성하고 해당 등록 유형 및 포트를 설정합니다. 그런 다음 createRegistrationString은 createAllEvent, createMembershipEvent, createRgEvent 및 createREvent 도우미 메소드를 사용하여 다양한 이벤트를 생성합니다. CallbackReg 객체가 만들어진 후에 각 이벤트는 이 객체에 추가됩니다. 마지막으로 createRegistrationString은 CallbackReg 객체에서 convertToXml 메소드를 호출하여 String 형태로 XML 메시지를 검색합니다.
regs 구성원 변수는 사용자가 응용 프로그램에 제공하는 명령줄 인자를 저장합니다. 다섯 번째 및 그 이후의 인자는 응용 프로그램이 등록해야 하는 이벤트를 지정합니다. 네 번째 인자는 등록 유형을 지정하지만 이 예에서는 무시됩니다. 부록 G, CrnpClient.java 응용 프로그램의 전체 코드에는 이 네 번째 인자를 사용하는 방법이 나와 있습니다.
앞의 논리를 구현하는 Java 코드를 만듭니다.
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[i].equals("M")) { cbReg.addRegEvent(createMembershipEvent()); } else if (regs[i].equals("A")) { cbReg.addRegEvent(createAllEvent()); } else if (regs[i].substring(0,2).equals("RG")) { cbReg.addRegEvent(createRgEvent(regs[i].substring(3))); } else if (regs[i].substring(0,1).equals("R")) { cbReg.addRegEvent(createREvent(regs[i].substring(2))); } } String xmlStr = cbReg.convertToXml(); return (xmlStr); } private Event createAllEvent() { Event allEvent = new Event(); allEvent.setClass("EC_Cluster"); return (allEvent); } private Event createMembershipEvent() { Event membershipEvent = new Event(); membershipEvent.setClass("EC_Cluster"); membershipEvent.setSubclass("ESC_cluster_membership"); return (membershipEvent); } private Event createRgEvent(String rgname) { Event rgStateEvent = new Event(); rgStateEvent.setClass("EC_Cluster"); rgStateEvent.setSubclass("ESC_cluster_rg_state"); NVPair rgNvpair = new NVPair(); rgNvpair.setName("rg_name"); rgNvpair.setValue(rgname); rgStateEvent.addNvpair(rgNvpair); return (rgStateEvent); } private Event createREvent(String rname) { Event rStateEvent = new Event(); rStateEvent.setClass("EC_Cluster"); rStateEvent.setSubclass("ESC_cluster_r_state"); NVPair rNvpair = new NVPair(); rNvpair.setName("r_name"); rNvpair.setValue(rname); rStateEvent.addNvpair(rNvpair); return (rStateEvent); }
등록 취소 문자열을 만듭니다.
등록 취소 문자열을 만드는 것은 이벤트를 수용할 필요가 없기 때문에 등록 문자열을 만드는 것보다 쉽습니다.
private String createUnregistrationString() throws Exception { CallbackReg cbReg = new CallbackReg(); cbReg.setPort("" + localPort); cbReg.setRegType(CallbackReg.REMOVE_CLIENT); String xmlStr = cbReg.convertToXml(); return (xmlStr); }
이제 응용 프로그램의 네트워킹 및 XML 생성 코드를 만들었습니다. CrnpClient 구성자는 setupXmlProcessing 메소드를 호출합니다. 이 메소드는 DocumentBuilderFactory 객체를 만들고 이 객체에 대한 다양한 구분 분석 등록 정보를 설정합니다. JAXP 설명서에 이 메소드가 자세히 설명되어 있습니다. http://java.sun.com/xml/jaxp/index.html을 참조하십시오.
앞의 논리를 구현하는 Java 코드를 만듭니다.
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); }
등록 또는 등록 취소 메시지에 응답하여 CRNP 서버가 보낸 SC_REPLY XML 메시지를 구분 분석하려면 RegReply 도우미 클래스가 필요합니다. 이 클래스는 XML 문서에서 생성할 수 있습니다. 이 클래스는 상태 코드와 상태 메시지에 대한 액세서를 제공합니다. 서버의 XML 스트림을 구문 분석하려면 새 XML 문서를 만들고 이 문서의 구문 분석 메소드를 사용해야 합니다. http://java.sun.com/xml/jaxp/index.html의 JAXP 설명서에 이 메소드가 자세히 설명되어 있습니다.
앞의 논리를 구현하는 Java 코드를 만듭니다.
readRegistrationReply 메소드는 새 RegReply 클래스를 사용한다는 점에 주의합니다.
private void readRegistrationReply(InputStream stream) throws Exception { // Create the document builder DocumentBuilder db = dbf.newDocumentBuilder(); db.setErrorHandler(new DefaultHandler()); //parse the input file Document doc = db.parse(stream); RegReply reply = new RegReply(doc); reply.print(System.out); }
RegReply 클래스를 구현합니다.
retrieveValues 메소드가 XML 문서의 DOM 트리를 통과하면서 상태 코드와 상태 메시지를 추출한다는 것에 주의합니다. http://java.sun.com/xml/jaxp/index.html의 JAXP 설명서에 자세한 내용 이 나와 있습니다.
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; }
마지막 단계는 실제 콜백 이벤트를 구분 분석 및 처리하는 것입니다. 이 작업을 지원하기 위해 XML 생성 방법에서 만든 Event 클래스를 수정하여 이 클래스가 XML 문서에서 Event를 생성하고 XML Element를 만들 수 있게 합니다. 이러한 변경 작업에는 XML 문서를 사용하는 추가 구성자, retrieveValues 메소드, 두 개의 추가 구성원 변수(vendor 및 publisher), 모든 필드에 대한 액세서 메소드 및 마지막으로 인쇄 메소드가 필요합니다.
앞의 논리를 구현하는 Java 코드를 만듭니다.
이 코드는 등록 응답 구문 분석 방법에 설명된 RegReply 클래스의 코드와 비슷합니다.
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;
XML 구문 분석을 지원하는 NVPair 클래스에 대한 추가 구성자와 메소드를 구현합니다.
단계 1에 표시된 것처럼 Event 클래스를 변경하려면 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); } }
이벤트 콜백을 대기하는 EventReceptionThread에서 while 루프를 구현합니다.
EventReceptionThread는 이벤트 수신 스레드 정의 방법에 설명되어 있습니다.
while(true) { Socket sock = listeningSock.accept(); Document doc = db.parse(sock.getInputStream()); Event event = new Event(doc); client.processEvent(event); sock.close(); }
수퍼유저가 되거나 동등한 역할을 맡습니다.
응용 프로그램을 실행합니다.
# java CrnpClient crnpHost crnpPort localPort ... |
CrnpClient 응용 프로그램의 전체 코드는 부록 G, CrnpClient.java 응용 프로그램에 나와 있습니다.