Transferring Complex Objects with Sockets

   

Java™ 2 Primer Plus
By Steven Haines, Steve Potts

Table of Contents
Chapter 20.  Network Programming


Sometimes we are given requirements to create a system that needs to have objects move from one computer to the other. One way to do this would be to turn the objects into String objects, send them via the socket to the other computer, then re-create the object on the other machine. This will work, but there is a better way.

Listings 20.3 and 20.4 used the ObjectInputStream and the ObjectOutputStream classes to transfer objects back and forth. The object being sent was just a String, however. You might be wondering how you would send a complex object using sockets. Listings 20.5, 20.6, and 20.7 show you a fairly complex set of objects that can be sent using these same streams.

Listing 20.5 The ComplexEmployee.java File
 /*   * ComplexEmployee.java   *   * Created on October 3, 2002, 3:42 PM   */  package ch20;  import java.io.*;  import java.util.*;  /**   *   * @author  Stephen Potts   */  public class ComplexEmployee implements Serializable  {      private String name;      private int salary;      /** Creates a new instance of ComplexEmployee */      public ComplexEmployee(String name, int salary)      {          this.name = name;          this.salary = salary;       }       public String getName()      {          return name;      }      public int getSalary()      {          return this.salary;      }  } 

This class is ordinary except for the fact that it is declared to be serializable. The serializability of this class is not hard to understand; its data consists of one String and one int, both of which are serializable. The Serializable interface does not require us to implement any special methods. It is what is called a marker interface. By implementing this interface, we are stating that moving this class from one machine to another will not break it because it contains no machine-specific data. An example of machine-specific data would be a handle to a Socket. The data in the Socket object pertains to addresses on this specific machine. Moving it to another machine would render the values in the object useless.

 public class ComplexEmployee implements Serializable 

Listing 20.6 contains the code for the ComplexDepartment class.

Listing 20.6 The ComplexDepartment.java File
 /*   * ComplexDepartment.java   *   * Created on October 3, 2002, 3:54 PM   */  package ch20;  import java.io.Serializable;  /**   *   * @author  Stephen Potts   */  public class ComplexDepartment implements Serializable  {      private String name;      private ComplexEmployee manager;      public ComplexDepartment(String name)      {          this.name = name;      }       public String getName()      {          return this.name;      }      public ComplexEmployee getManager()      {          return this.manager;      }      public void addManager(ComplexEmployee e)      {          manager = e;       }  } 

The only really interesting feature of this class is the fact that one of its private class-level variables is of type ComplexEmployee.

 private String name;  private ComplexEmployee manager; 

This was done to make the situation more difficult for the Java serialization mechanism to handle.

The third class that we will need for this experiment is called ComplexCompany. It is shown here in Listing 20.7.

Listing 20.7 The ComplexCompany Example
 /*   * ComplexCompany.java   *   * Created on October 3, 2002, 3:39 PM   */  package ch20;   /**   *   * @author  Stephen Potts   */  import java.util.Vector;  import java.util.Iterator;  import java.util.Set;  import java.io.Serializable;  public class ComplexCompany implements Serializable  {      private String name;      private ComplexEmployee president;      private Vector departments;       /** Creates new Company */      public ComplexCompany(String name)      {          this.name = name;          departments = new Vector();      }      public String getName()      {          return this.name;      }      public void addDepartment(ComplexDepartment dept)      {          departments.addElement(dept);      }      public ComplexEmployee getPresident()      {          return this.president;      }      public void addPresident(ComplexEmployee e)      {          this.president = e;      }      public Iterator getDepartmentIterator()      {          return departments.iterator();      }      public void printCompanyObject()      {          System.out.println("The company name is " + getName());          System.out.println("The company president is " +          getPresident().getName());          System.out.println(" ");          Iterator i = getDepartmentIterator();          while (i.hasNext())          {              ComplexDepartment d = (ComplexDepartment)i.next();              System.out.println("   The department name is " +              d.getName());              System.out.println("   The department manager is " +              d.getManager().getName());              System.out.println(" ");          }      }  } 

This class is designed specifically as a brain buster. It contains three different variables. The first one is a String, the second one is a ComplexEmployee, and the third is a Vector of ComplexDepartments.

 private String name;  private ComplexEmployee president;  private Vector departments; 

The Vector is the most interesting. We have placed it here to show how well the serialization mechanism in the JVM works. If it can serialize a Vector of class objects that is a member variable of another class properly, we can be duly impressed. Add to that the fact that the classes in the vector each contain a member variable that is a class, and you have a very good test of the strength of the serialization mechanism.

 /** Creates new Company */  public ComplexCompany(String name)  {      this.name = name;      departments = new Vector();  } 

The addElement() method is how you add objects to the vector.

 public void addDepartment(ComplexDepartment dept)  {      departments.addElement(dept);  } 

The recommended way to step through a Vector is by using the methods of the Iterator class. The responsibility for returning the Iterator is placed on the class that contains the vector.

 public Iterator getDepartmentIterator()  {      return departments.iterator();  } 

The ComplexCompany class knows how to print itself out to standard output for us to inspect.

 public void printCompanyObject()  {      System.out.println("The company name is " + getName());      System.out.println("The company president is " +      getPresident().getName());      System.out.println(" "); 

The department Vector must be stepped through and each item read to make sure that we have all the departments printed out.

 Iterator i = getDepartmentIterator();  while (i.hasNext())  { 

Notice the explicit cast that is done here. The Vector stored its members as being of type Object. You must perform a downcast to the correct datatype.

 ComplexDepartment d = (ComplexDepartment)i.next();  System.out.println("   The department name is " +  d.getName());  System.out.println("   The department manager is " +  d.getManager().getName()) 

The client class creates the object, opens a socket, and writes the object to the socket. Listing 20.8 shows this class.

Listing 20.8 The ComplexSocketClient.java File
 /*   * ComplexSocketClient.java   *   * Created on October 2, 2002, 5:34 PM   */  package ch20;  import java.net.*;  import java.io.*;  /**   *   * @author  Stephen Potts   */  public class ComplexSocketClient  {      Socket socket1;      int portNumber = 1777;      String str = "";      /** Creates a new instance of ComplexSocketClient */      public ComplexSocketClient()      {          try          {              socket1 = new Socket(InetAddress.getLocalHost(),              portNumber);              ObjectInputStream ois =              new ObjectInputStream(socket1.getInputStream());              ObjectOutputStream oos =              new ObjectOutputStream(socket1.getOutputStream());              ComplexCompany comp =                          new ComplexCompany("The Blazer Company");              ComplexEmployee emp0 =                              new ComplexEmployee("Leslie Waller", 1000);              comp.addPresident(emp0);               ComplexDepartment sales =                                   new ComplexDepartment("Sales");              ComplexEmployee emp1 =                              new ComplexEmployee("Grant Jackson", 1200);               sales.addManager(emp1);              comp.addDepartment(sales);              ComplexDepartment accounting =                               new ComplexDepartment("Accounting");              ComplexEmployee emp2 =                            new ComplexEmployee("Clay Cain", 1230);              accounting.addManager(emp2);              comp.addDepartment(accounting);              ComplexDepartment maintenance =                              new ComplexDepartment("Maintenance");              ComplexEmployee emp3 =                            new ComplexEmployee("Greg Hladlick", 1020);              maintenance.addManager(emp3);              comp.addDepartment(maintenance);              oos.writeObject(comp);              while ((str = (String) ois.readObject()) != null)              {                  System.out.println(str);                  oos.writeObject("bye");                  if (str.equals("bye bye"))                      break;              }              ois.close();              oos.close();              socket1.close();          } catch (Exception e)          {              System.out.println("Exception " + e);          }      }      public static void main(String args[])      {          ComplexSocketClient lsp = new ComplexSocketClient();      }  } 

We first create the ComplexCompany object.

 ComplexCompany comp =              new ComplexCompany("The Blazer Company"); 

Next, we add the president.

 ComplexEmployee emp0 =                  new ComplexEmployee("Leslie Waller", 1000);  comp.addPresident(emp0); 

Next, we add a department.

 ComplexDepartment sales =                       new ComplexDepartment("Sales");  ComplexEmployee emp1 =                  new ComplexEmployee("Grant Jackson", 1200); 

We add the department manager.

 sales.addManager(emp1); 

Then, we add the department to the company object. Following that, we add two more departments in the same fashion. Then, we write the object to the stream that is connected to the Socket.

 oos.writeObject(comp); 

Finally, we wait in a while loop for a response.

 while ((str = (String) ois.readObject()) != null)  {      System.out.println(str);      oos.writeObject("bye");      if (str.equals("bye bye"))          break;  } 

The server is fairly simple also. Listing 20.9 shows the code for this application.

Listing 20.9 The ComplexSocketServer.java File
 /*   * ComplexSocketServer.java   *   * Created on October 2, 2002, 5:24 PM   */  package ch20;  import java.net.*;  import java.io.*;  import java.util.*;  /**   *   * @author  Stephen Potts   */  public class ComplexSocketServer   {      ServerSocket servSocket;      Socket fromClientSocket;      int cTosPortNumber = 1777;      String str;      ComplexCompany comp;       /** Creates a new instance of ComplexSocketServer */      public ComplexSocketServer()      {          // Create ServerSocket to listen for connections          try          {              servSocket = new ServerSocket(cTosPortNumber);              // Wait for client to connnect, then get Socket              System.out.println("ServerSocket created");              System.out.println("Waiting for a connection on " +              cTosPortNumber);              fromClientSocket = servSocket.accept();              System.out.println("fromClientSocket accepted");              // Use ObjectOutputStream to send String to the client              ObjectOutputStream oos =              new ObjectOutputStream(fromClientSocket.getOutputStream());              //Use ObjectInputStream to get String from client              ObjectInputStream ois =              new ObjectInputStream(fromClientSocket.getInputStream());              while ((comp = (ComplexCompany) ois.readObject()) != null)              {                  comp.printCompanyObject();                  oos.writeObject("bye bye");                  break;              }              oos.close();              // Close Sockets              fromClientSocket.close();          } catch (Exception e)          {              System.out.println("Exception " + e);          }      }        public static void main(String args[])      {          ComplexSocketServer css = new ComplexSocketServer();      }  } 

The really amazing thing about this application is how little it does. All the work of turning the object into a stream, and then turning it back into an object again is done by the JVM.

After reading the object, it is cast to a handle of type ComplexCompany.

 while ((comp = (ComplexCompany) ois.readObject()) != null)  { 

We then use this handle to call the printCompanyObject() method. In a real-world application, we would obviously do more with this object.

 comp.printCompanyObject(); 

Following that, we write a message back to the client so that it will know that we got the objects and processed them.

The output from running client is shown here:

 Server returns initialize  bye bye 

The output from running the server is shown here.

 ServerSocket created  Waiting for a connection on 1777  fromClientSocket accepted  The company name is The Blazer Company  The company president is Leslie Waller     The department name is Sales     The department manager is Grant Jackson     The department name is Accounting     The department manager is Clay Cain     The department name is Maintenance     The department manager is Greg Hladlick 

Notice that the object contained all the information, including what was stored in the Vector.


       
    Top
     



    Java 2 Primer Plus
    Java 2 Primer Plus
    ISBN: 0672324156
    EAN: 2147483647
    Year: 2001
    Pages: 332

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net