Wednesday, 24 September 2008

Java 2 Certification By Phillip Heller, Simon Roberts - Final Part

Couple Of Days back i started reading Complete Java 2 Certification Study Guide, 5th Edition By Phillip Heller, Simon Roberts.

I wanted to share few important quotations i found from the rest of the chapters from the book.

Great book written by Phillip Heller, Simon Roberts.

1) Streams, Readers, and Writers

Java’s stream, reader, and writer classes view input and output as ordered sequences of bytes.Of course, dealing strictly with bytes would be tremendously bothersome, because data appears sometimes as bytes, sometimes as ints, sometimes as floats, and so on. You have already seen how the RandomAccessFile class allows you to read and write all of Java’s primitive data types. The readInt() method, for example, reads four bytes from a file, pieces them together, and returns an int. Java’s general I/O classes provide a similar structured approach:

a) A low-level output stream receives bytes and writes bytes to an output device.
b) A high-level filter output stream receives general-format data, such as primitives, and writes bytes to a low-level output stream or to another filter output stream.
c) A writer is similar to a filter output stream but is specialized for writing Java strings in units of Unicode characters.
d) A low-level input stream reads bytes from an input device and returns bytes to its caller.
e) A high-level filter input stream reads bytes from a low-level input stream, or from another filter input stream, and returns general-format data to its caller.
f) A reader is similar to a filter input stream but is specialized for reading UTF strings in units of Unicode characters.

The stream, reader, and writer classes are not very complicated. The easiest way to review them is to begin with the low-level streams.

2) Object Streams and Serialization

data input and output streams allow you to read and write primitives and strings, rather than individual bytes. Object streams go one step beyond data streams by allowing you to read and write entire objects.

The process of writing an object is called serialization. To serialize an object, first create an instance of java.io.ObjectOutputStream. This class, like DataOutputStream, expects to be chained onto a lower-level byte-oriented stream such as a file output stream or a socket’s output stream. The method below uses an object stream to store a string buffer in a file named sbuf.ser.


void writeStringBuffer(StringBuffer writeMe)
throws IOException {
FileOutputStream fos = new FileOutputStrem(sbuf.ser);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(writeMe);
oos.close();
fos.close();


3) When we use object streams, it’s important to know what information gets serialized and what does not. It is only an object’s data that is serialized, not its class definition. Moreover, not all data is written. Static fields are not, because it would not be appropriate to change a static variable, which is shared by all instances of a class, just because one instance of the class got deserialized. (To deserialize is to convert a serialized representation into a replica of the original object.) Transient fields are also not serialized. This provides a level of security in situations where you are concerned that sensitive variable values, serialized onto the network or into a file, might be read by hostile parties. By declaring a variable to be transient, you tell the JVM not to serialize that variable.

Object streams pay no attention to access modes. All non-static non-transient fields are written to object output streams, regardless of whether they are public, private, default, or protected.

4) TCP: A Reliable Protocol

Computers communicate with one another by transmitting sequences of 0s and 1s. A protocol is an agreement among programmers concerning the meanings of different bit sequences and the appropriate responses to bit sequences. For example, HTTP describes the bit sequences that web clients should send to web servers in order to request web pages and other services; the protocol also describes the formats of all the various responses that web servers might issue.

TCP is a low-level protocol with a single goal: reliability. A reliable protocol is one in which every message sent from one computer to another is eventually received without any distortion or omission. Reliable protocols are necessary because most computer communication takes place over telephone lines, which are vulnerable to the environment in many ways.With TCP, the receiver of a message is given a lot of information regarding the message’s structure. If the message does not match the expected structure, the receiver can request that
part or all of the message be retransmitted. Of course, reliability has its price: verifying the structure of each message takes time.

5) Sockets and Ports
TCP uses two abstractions called sockets and ports. They are called abstractions because there are no actual physical sockets or ports involved. The names are just metaphors that do a moderately good job of describing how to use TCP.

From the point of view of writing Java code, you can think of a socket as being an object that knows how to exchange data with another computer, using TCP.

Servers are capable of offering a variety of services. For example, the two most commonly used services are e-mail and the World Wide Web. Servers keep track of the services they offer by associating each service with a number, known as the port number.A client that wants to make use of a server needs to know the desired port number, as well as the hostname or IP address of the server. For example, when you point your browser to
www.sybex.com , your computer connects to port 80 on server sybex.com (because 80 is the standard port number for web servers). Servers that exchange e-mail with sybex.com will connect to a different port (one that supports e-mail exchange) on the same server.

6) Client Sockets in Java
The java.net.Socket class contains code that knows how to find and communicate with a server. The communication uses TCP, so it is reliable. To create a socket instance, use one of the constructors described on the API page. By far the most useful form is

public Socket(String servername, int portNumber)

The constructor throws IOException if the connection cannot be made. Once the constructor returns, the socket is ready to communicate. You do not directly read from or write to a socket. Instead, the socket provides you with an input stream and an output stream, which can be used for reading and writing bytes.

The following code constructs a socket connected to port 1234 on a server named mangfalo,then reads and prints out a byte sent by the server, and then sends a byte to the server:


try {
// Make the socket.
Socket sock = new Socket("mangfalo", 1234);
// Get the streams.
OutputStream ostr = sock.getOutputStream();
InputStream istr = sock.getInputStream();
// Read & print.
System.out.println(istr.read());
// Transmit.
ostr.write(7);
// Clean up.
istr.close();
ostr.close();
sock.close();
}
catch (IOException x) {
System.out.println("Stress: " + x.getMessage());
}



7) Server Sockets in Java

From a programmer’s point of view, the main difference between a client and a server has to do with nitiation. A client always gets to assume that a server is available. You can see this assumption at work when you construct a Socket instance: the constructor automatically connects to the specified server’s specified port.
A server, on the other hand, makes itself available and then waits for clients to initiate connections.
This is done with an abstraction called a server socket , which in Java is represented by the java.net.ServerSocket class. The most useful form of the ServerSocket constructor is

public ServerSocket(int portNumber)

The constructor throws IOException if it gets into trouble. To make the new object available for client connections, call its accept() method, which returns an instance of Socket , as shown below:


try {
ServerSocket ss = new ServerSocket(1234);
Socket sock = ss.accept();
. . .
}
catch (IOException x) {
System.out.println("Stress: " + x.getMessage());
}



8) Object Streams and Serialization

As you have seen, data streams allow you to read and write primitives and strings, rather than individual bytes. Object streams go one step beyond data streams by allowing you to read and write entire objects.

The process of writing an object is called serialization. To serialize an object, first create an instance of java.io.ObjectOutputStream. This class, like DataOutputStream, expects to be chained onto a lower-level byte-oriented stream such as a file output stream or a socket’s output stream. The method below uses an object stream to store a string buffer in a file named sbuf.ser.


void writeStringBuffer(StringBuffer writeMe)
throws IOException {
FileOutputStream fos = new FileOutputStream(sbuf.ser);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(writeMe);
oos.close();
fos.close();
}



The .ser filename extension is conventional for files containing serialized objects.To read the stored object back into a program, you can do the following:


StringBuffer readStringBuffer()
throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream (sbuf.ser);
ObjectInputStream ois = new ObjectInputStream(fis);
StringBuffer sb = (StringBuffer)ois.readObject();
ois.close();
fis.close();
return sb;
}


Notice that the value returned by readObject() is of type Object, so it must be cast. The object read in is identical to the one that was written out in the previous code example.The ObjectOutputStream class has a writeUTF() method, as well as writeByte(),writeShort(), and all other write-primitive methods that also appear in data output streams.The ObjectInputStream class has corresponding reading methods. So if you want to create a file that contains serialized primitives and strings as well as serialized objects, you can do it with a
single output stream.

9) When you use object streams, it’s important to know what information gets serialized and what does not. It is only an object’s data that is serialized, not its class definition. Moreover, not all data is written. Static fields are not, because it would not be appropriate to change a static variable, which is shared by all instances of a class, just because one instance of the class got reserialized. Transient fields are also not serialized. This provides a level of security in situations where you are concerned that sensitive variable values, serialized onto the network or into a file,might be read by hostile parties. By declaring a variable to be transient, you tell the JVM not to serialize that variable.

You might expect that private data would not be serialized, but in fact object streams pay no attention to access modes. All non-static non-transient fields are written to object output streams,regardless of whether they are public, private, default, or protected.When an object is serialized, it will probably be deserialized by a different JVM. Any JVM that tries to deserialize an object must have access to that object’s class definition. In other words, if the class is not already loaded, its class file must appear in the new JVM’s classpath.If this is not the case, readObject() will throw an exception.

10) When an Object Output Stream serializes an object that contains references to another object,
every referenced object is serialized along with the original object. For example, consider a Vector
that contains bytes:


Vector<Byte> vec = new Vector<Byte>();
vec.add(new Byte("11"));
vec.add(new Byte("22"));
vec.add(new Byte("33"));


The Vector contains three references.When an Object Output Stream writes the Vector the three bytes are also serialized. If instead of bytes the Vector contained objects that had references to still other objects,
those other objects would also be serialized. In the terminology of serialization, when an object is
serialized, its entire graph is serialized. An object’s graph is the object itself, plus all the objects it
references, plus all the objects those objects reference, and so on. When an object input stream
deserializes an object, the entire graph is deserialized.

11) Serializable has a subinterface called Externalizable, which you can implement if you want to customize the way a class is serialized. Notice that since Externalizable extends Serializable, the implements Serializable precondition in writeObject() is met by any object that implements Externalizable.

Externalizable contains two method signatures:


void writeExternal(ObjectOutput out) throws IOException
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException


About the Authors

Philip Heller is a technical author, novelist, public speaker, and consultant. He has been instrumental in the creation and maintenance of the Java Programmer and Developer exams. His popular seminars on certification have been delivered internationally. He is also the author of Ground-Up Java (available from Sybex), which uses interactive animated illustrations to present fundamental concepts of Java programming to new programmers.

Simon Roberts worked for Sun Microsystems for nine years as an instructor, an authority on the Java language, and the key player in the development of the entire Java certification program. He is now a consultant and instructor, specializing in Java and security. He is also a flight instructor.

No comments: