December 7, 2002
![]()
This week, I answer two questions concerning data compression in Java.
Question 1:
How can I zip something that isn't in a file?
Question 2:
I read with enthusiasm Todd Sundsted's "Zip Your Data and Improve the Performance of Your Network-Based Applications," (JavaWorld, November 1998) but I was a little disappointed.
When I read the title of the article, I was ecstatic. I thought I had finally found the solution for our problem.
At my company, we have been trying to improve the performance of an RMI (Remote Method Invocation) application that organizes data. The server does most of the process. We've made performance improvements in the past year and a half, but the bottleneck now is the data transfer. At any point in the day, we might be transferring thousands of records between the client and the server. As one possible solution, I proposed we compress the data before returning it to the client, a process I thought Todd's article would address. However, the example given in his article compresses files, not data, as we need.
On the RMI implementation, we get the results from the database, put them in a list, and return the list to the client, which in turn puts the results in a JTable. I would like to compress that list before sending it back to the client, decompress it at the client, then insert the data in the JTable.
Can this be done?
I've received several questions about Todd's article. Many readers seem confused because the article's examples were file
centric.
Note: You can download this article's source code from Resources.
In regards to question 1, nothing forces you to use files when you use ZipInputStream and ZipOutputStream. The only stipulation is that you convert your data to byte arrays.
Question 2, however, proves more involved because it requires a change in the way RMI communicates over the wire. In order to make RMI compress its data before sending it over the wire, you must create a new socket type that compresses the data. Then, once you have created the socket, you must tell RMI to use it.
"Creating a Custom RMI Socket Factory," a tutorial from Sun Microsystems, enumerates the steps necessary to create a new socket and get RMI to use it.
Briefly, to change RMI's socket type:
ServerSocket.
RMIClientSocketFactory.
RMIServerSocketFactory.
UnicastRemoteObject use the new factories.
Following the scenario outlined in question 2 above, let's go through each step for zip compression.
In the case of zip compression, create the following socket:
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import java.net.Socket;
public class ZipSocket extends Socket {
private InputStream in;
private OutputStream out;
public ZipSocket() { super(); }
public ZipSocket(String host, int port)
throws IOException {
super(host, port);
}
public InputStream getInputStream()
throws IOException {
if (in == null) {
in = new ZipInputStream(super.getInputStream());
}
return in;
}
public OutputStream getOutputStream()
throws IOException {
if (out == null) {
out = new ZipOutputStream(super.getOutputStream());
}
return out;
}
public synchronized void close() throws IOException {
OutputStream o = getOutputStream();
o.flush();
super.close();
}
}
Create the following server socket: