Skip Navigation Links
Exit Print View
| Oracle Solaris Cluster Data Services Developer's Guide Oracle Solaris Cluster 4.1

Search Scope:

- This Document
- Entire Library

## Example of Creating a Java Application That Uses the CRNP

The following example illustrates how to develop a simple Java application named `CrnpClient` that uses the CRNP. The application registers for event callbacks with the CRNP server in the cluster, listens for the event callbacks, and processes the events by printing their contents. Before terminating, the application unregisters its request for event callbacks.

Note the following points when reviewing this example:

- The sample application generates and parses XML with the JAXP (Java API for XML Processing). This example does not show you how to use the JAXP. The JAXP is described in more detail at https://jaxp.dev.java.net/.

- This example presents pieces of an application, which can be found in its entirety in Appendix E, `CrnpClient.java` Application. To illustrate particular concepts more effectively, the example in this chapter differs slightly from the complete application that is presented in Appendix E, `CrnpClient.java` Application.

- For brevity, comments are excluded from the sample code in this chapter. The complete application in Appendix E, `CrnpClient.java` Application includes comments.

- The application that is shown in this example handles most error conditions by simply exiting the application. Your actual application needs to handle errors more robustly.

## How to Set Up Your Environment

1. Download and install JAXP and the correct version of the Java compiler and virtual machine.

   You can find instructions at https://jaxp.dev.java.net/.

   Note - This example requires at least Java 1.3.1.

2. From the directory in which your source file is located, type the following:

       % 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

   where jaxp-root is the absolute or relative path to the directory in which the JAXP jar files are located and source-filename is the name of your Java source file.

   A `classpath` in your compilation command line ensures that the compiler can find the JAXP classes.

3. When you run the application, specify the `classpath` so that the application can load the correct JAXP class files.

   Note that the first path in the `classpath` is the current directory.

       % 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

   Now that your environment is configured, you can develop your application.

## How to Start Developing Your Application

In this part of the example, you create a basic class called `CrnpClient`, with a main method that parses the command-line arguments and constructs a `CrnpClient` object. This object passes the command-line arguments to the class, waits for the user to terminate the application, calls `shutdown` on the `CrnpClient`, and exits.

The constructor of the `CrnpClient` class needs to execute the following tasks:

- Set up the XML processing objects.

- Create a thread that listens for event callbacks.

- Contact the CRNP server and register for event callbacks.

- Create the Java code that implements the preceding logic.

  The following example shows the skeleton code for the `CrnpClient` class. The implementations of the four helper methods that are referenced in the constructor and shutdown methods are shown later in this chapter. Note that the code that imports all the packages that you need is shown.

      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;
      }

  Member variables are discussed in more detail later in this chapter.

## How to Parse the Command-Line Arguments

- To parse the command-line arguments, see the code in Appendix E, `CrnpClient.java` Application.

## How to Define the Event Reception Thread

In the code, you need to ensure that event reception is performed in a separate thread so that your application can continue to do other work while the event thread blocks and waits for event callbacks.

Note - Setting up the XML is discussed later in this chapter.

1. In your code, define a `Thread` subclass called `EventReceptionThread` that creates a `ServerSocket` and waits for events to arrive on the socket.

   In this part of the example code, events are neither read nor processed. Reading and processing events are discussed later in this chapter. The `EventReceptionThread` creates a `ServerSocket` on a wildcard internet-working protocol address. `EventReceptionThread` also keeps a reference to the `CrnpClient` object so that `EventReceptionThread` can send events to the `CrnpClient` object to process.

       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;
       }

2. Construct a `createEvtRecepThr` object.

       private void createEvtRecepThr() throws Exception
       {
               evtThr = new EventReceptionThread(this);
               evtThr.start();
       }

## How to Register and Unregister Callbacks

The registration task involves the following actions:

- Opening a basic TCP socket to the registration internet-working protocol and port

- Constructing the XML registration message

- Sending the XML registration message on the socket

- Reading the XML reply message off the socket

- Closing the socket

1. Create the Java code that implements the preceding logic.

   The following example code shows the implementation of the `registerCallbacks` method of the `CrnpClient` class (which is called by the `CrnpClient` constructor). The calls to `createRegistrationString()` and `readRegistrationReply()` are described in more detail later in this chapter.

   `regIp` and `regPort` are object members that are set up by the constructor.

       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();
       }

2. Implement the `unregister` method.

   This method is called by the `shutdown` method of `CrnpClient`. The implementation of `createUnregistrationString` is described in more detail later in this chapter.

       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();
       }

## How to Generate the XML

Now that you have set up the structure of the application and have written all the networking code, you need to write the code that generates and parses the XML. Start by writing the code that generates the `SC_CALLBACK_REG` XML registration message.

An `SC_CALLBACK_REG` message consists of a registration type (`ADD_CLIENT`, `REMOVE_CLIENT`, `ADD_EVENTS`, or `REMOVE_EVENTS`), a callback port, and a list of events of interest. Each event consists of a class and a subclass, followed by a list of name and value pairs.

In this part of the example, you write a `CallbackReg` class that stores the registration type, callback port, and list of registration events. This class also can serialize itself to an `SC_CALLBACK_REG` XML message.

An interesting method of this class is the `convertToXml` method, which creates an `SC_CALLBACK_REG` XML message string from the class members. The JAXP documentation at https://jaxp.dev.java.net/ describes the code in this method in more detail.

The implementation of the `Event` class is shown in the following example code. Note that the `CallbackReg` class uses an `Event` class that stores one event and can convert that event to an XML `Element`.

1. Create the Java code that implements the preceding logic.

       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;
       }

2. Implement the `Event` and `NVPair` classes.

   Note that the `CallbackReg` class uses an `Event` class, which itself uses an `NVPair` class.

       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;
       }

## How to Create the Registration and Unregistration Messages

Now that you have created the helper classes that generate the XML messages, you can write the implementation of the `createRegistrationString` method. This method is called by the `registerCallbacks` method, which is described in How to Register and Unregister Callbacks.

`createRegistrationString` constructs a `CallbackReg` object and sets its registration type and port. Then, `createRegistrationString` constructs various events, by using the `createAllEvent`, `createMembershipEvent`, `createRgEvent`, and `createREvent` helper methods. Each event is added to the `CallbackReg` object after this object is created. Finally, `createRegistrationString` calls the `convertToXml` method on the `CallbackReg` object to retrieve the XML message in `String` form.

Note that the `regs` member variable stores the command-line arguments that a user provides to the application. The fifth and subsequent arguments specify the events for which the application should register. The fourth argument specifies the type of registration, but is ignored in this example. The complete code in Appendix E, `CrnpClient.java` Application shows how to use this fourth argument.

1. Create the Java code that implements the preceding logic.

       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);
       }

2. Create the unregistration string.

   Creating the unregistration string is easier than creating the registration string because you do not need to accommodate events.

       private String createUnregistrationString() throws Exception
       {
               CallbackReg cbReg = new CallbackReg();
               cbReg.setPort("" + localPort);
               cbReg.setRegType(CallbackReg.REMOVE_CLIENT);
               String xmlStr = cbReg.convertToXml();
               return (xmlStr);
       }

## How to Set Up the XML Parser

You have now created the networking and XML generation code for the application. The `CrnpClient` constructor calls a `setupXmlProcessing` method. This method creates a `DocumentBuilderFactory` object and sets various parsing properties on that object. The JAXP documentation describes this method in more detail. See https://jaxp.dev.java.net/.

- Create the Java code that implements the preceding logic.

      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);
      }

## How to Parse the Registration Reply

To parse the `SC_REPLY` XML message that the CRNP server sends in response to a registration or unregistration message, you need a `RegReply` helper class. You can construct this class from an XML document. This class provides accessors for the status code and status message. To parse the XML stream from the server, you need to create a new XML document and use that document's parse method. The JAXP documentation at https://jaxp.dev.java.net/ describes this method in more detail.

1. Create the Java code that implements the preceding logic.

   Note that the `readRegistrationReply` method uses the new `RegReply` class.

       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);
       }

2. Implement the `RegReply` class.

   Note that the `retrieveValues` method walks the DOM tree in the XML document and pulls out the status code and status message. The JAXP documentation at https://jaxp.dev.java.net/ contains more detail.

       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;
       }

## How to Parse the Callback Events

The final step is to parse and process the actual callback events. To aid in this task, you modify the `Event` class that you created in How to Generate the XML so that this class can construct an `Event` from an XML document and create an XML `Element`. This change requires an additional constructor (that takes an XML document), a `retrieveValues` method, the addition of two member variables (`vendor` and `publisher`), accessor methods for all fields, and finally, a print method.

1. Create the Java code that implements the preceding logic.

   Note that this code is similar to the code for the `RegReply` class that is described in How to Parse the Registration Reply.

       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;

2. Implement the additional constructors and methods for the `NVPair` class that support the XML parsing.

   The changes to the `Event` class that are shown in Step 1 require similar changes to the `NVPair` class.

       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);
               }
       }

3. Implement the `while` loop in `EventReceptionThread`, which waits for event callbacks.

   `EventReceptionThread` is described in How to Define the Event Reception Thread.

       while(true) {
                       Socket sock = listeningSock.accept();
                       Document doc = db.parse(sock.getInputStream());
                       Event event = new Event(doc);
                       client.processEvent(event);
                       sock.close();
               }

## How to Run the Application

1. Assume the `root` role that provides `solaris.cluster.modify` RBAC authorization.
2. Run your application.

       # java CrnpClient crnpHost crnpPort localPort ...

   The complete code for the `CrnpClient` application is listed in Appendix E, `CrnpClient.java` Application.

Copyright © 2000, 2012, Oracle and/or its affiliates. All rights reserved. Legal Notices |