I need two different answers for the following question.

Lab2: Digest Streams and Running Threads

The java.security package contains two filter streams that can calculate a message digest for a stream. They are DigestInputStream and DigestOutputStream. A message digest, represented in Java by the java.security.MessageDigest class, is a strong hash code for the stream; that is, it is a large integer (typically 20 bytes long in binary format) that can easily be calculated from a stream of any length in such a fashion that no information about the stream is available from the message digest. Message digests can be used for digital signatures and for detecting data that has been corrupted in transit across the network. In practice, the use of message digests in digital signatures is more important.


To calculate a digest for an output stream, you first construct a MessageDigest object that uses a particular algorithm, such as the Secure Hash Algorithm (SHA). You pass both the MessageDigest object and the stream you want to digest to the DigestOutputStream constructor. This chains the digest stream to the underlying output stream. Then you write data onto the stream as normal, flush it, close it, and invoke the getMessageDigest() method to retrieve the MessageDigest object. Finally you invoke the digest() method on the MessageDigest object to finish calculating the actual digest. For example:


MessageDigest sha = MessageDigest.getInstance(“SHA”);

DigestOutputStream dout = new DigestOutputStream(out, sha);

byte[] buffer = new byte[128];

while (true) {

int byteRead = in.read(buffer);

if (bytesRead < 0) break;

dout.write(buffer, 0, bytesRead);

}

dout.flush();

dout.close();

byte[] result = dout.getMessageDigest().digest();


Calculating the digest of an input stream you read is equally simple. It still isn’t quite as transparent as some of the other filter streams because you do need to be at least marginally conversant with the methods of the MessageDigest class.


Your lab assignment is to write a program that calculates the Secure Hash Algorithm (SHA) digest for many files. This is mostly an I/O bound program that is, it spends a lot of time to read in data from hard drive or actually wait for that data since hard drive is slow compared to cpu. This is characteristic of a lot of network programs; they tend to execute faster than the network can supply input. Consequently, they spend a lot of time blocked. This is time that other threads can use, either to process other input sources or to do something that doesn’t rely on slow input. Your assignment can be broken in two phases:

  1. You write a simple program with a single class that reads at least two file (more than one file) and calculates the SHA digest for each file. Then, it prints out the result (digest for each file) on the screen as the following:

annaresume.doc: -16 -110 38 30 -30 -128 -24 68 -101 -97 -113 -109 -27 0 76 -7 126 46 -92 16 sc190.doc: -40 52 65 77 78 116 -54 109 60 -127 -62 67 58 80 -83 5 -35 -1 -78 -40


  1. You modify the program such that it uses threads. The idea is to assign a separate thread to process each individual input file.

An example code segment for using a DigestInputStream is shown below (it assumes that an in input file stream (FileInputStream) is already created):


MessageDigest sha = MessageDigest.getInstance("SHA");

DigestInputStream din = new DigestInputStream(in, sha);

int b;

while ((b = din.read()) != -1) ;

din.close();

byte[] digest = sha.digest();


An example for Threads: a thread with a little t is a separate independent path of execution in the virtual machine. A Thread with a capital T is an instance of the java.lang.Thread class. There is a one-to-one relationship between threads executing in the virtual machine and Thread objects constructed by the virtual machine. Most of the time, it’s obvious from the context which is meant if the difference is really important. To start a new thread running in the virtual machine, you construct an instance of the Thread class and invoke its start() method, like this:


Thread t = new Thread();

t.start();


Of course, this thread isn’t very interesting because it doesn’t have anything to do. To give a thread something to do, you either subclass the Thread class and override its run() method, or implement the Runnable interface and pass the Runnable object to the Thread constructor. In both cases, the key is the run() method, which has this signature:


public void run()


You’re going to put all the work the thread does in this one method. This method may invoke other methods; it may construct other objects; it may even spawn other threads. However, the thread starts here and it stops here. When the run() method completes, the thread dies. In essence, the run() method is to a thread what the main() method is to a traditional nonthreaded program. A single-threaded program exits when the main() method returns. A multithreaded program exits when both the main() method and the run() methods of all nondaemon threads return. Here is an example thread program:


class CountingThread extends Thread {

public CountingThread(int x) {

this.x =x;

}

public void run() {

int i=0;

while (i<15) {

System.out.println(i);

i +=x;

}

}

private int x;

}



class CountingThreadExample {

public static void main(String a[]) {

CountingThread t1 = new CountingThread(2);

CountingThread t2 = new CountingThread(3);

t1.start();

t2.start();

}

}