//
// SocketDataServer.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.data;
import java.io.*;
import java.net.*;
import java.rmi.RemoteException;
import java.util.Vector;
import visad.*;
/**
* A class for exporting data to a socket stream. Whenever the given
* DataReference's data changes, it is sent across the socket to any clients
* that are listening.
*/
public class SocketDataServer {
/**
* The main socket for this SocketDataServer.
*/
protected ServerSocket socket;
/**
* List of client sockets listening to this SocketDataServer.
*/
protected Vector sockets = new Vector();
/**
* List of output streams for client sockets.
*/
protected Vector outs = new Vector();
/**
* The socket's port.
*/
protected int port;
/**
* DataReference whose data is linked to the socket stream.
*/
protected DataReferenceImpl ref;
/**
* Whether the server is still active.
*/
protected boolean alive = true;
/**
* Code for monitoring incoming clients.
*/
private Runnable connect = new Runnable() {
public void run() {
while (alive) {
try {
// wait for a new socket to connect
Socket s = socket.accept();
if (!alive) break;
synchronized (sockets) {
if (s != null) {
// add client to the list
sockets.add(s);
// add client's input and output streams to the list
ObjectOutputStream out =
new ObjectOutputStream(s.getOutputStream());
outs.add(out);
// send the current data to the client
Data data = SocketDataServer.this.ref.getData();
out.writeObject(data);
}
}
}
catch (IOException exc) { }
}
}
};
/**
* Cell for monitoring data changes.
*/
private CellImpl commCell = new CellImpl() {
public synchronized void doAction()
throws VisADException, RemoteException
{
// send new data to each client using its socket
synchronized (sockets) {
Data data = SocketDataServer.this.ref.getData();
int i = 0;
while (i < sockets.size()) {
Socket s = (Socket) sockets.elementAt(i);
ObjectOutputStream out = (ObjectOutputStream) outs.elementAt(i);
try {
out.writeObject(data);
i++;
}
catch (IOException exc) {
// something wrong with this socket; kill it
killSocket(i);
}
}
}
}
};
/**
* Construct a SocketDataServer with the given port and data reference.
*/
public SocketDataServer(int port, DataReferenceImpl ref)
throws VisADException, IOException
{
this.port = port;
this.ref = ref;
// create a server socket at the given port
socket = new ServerSocket(port);
// monitor incoming client socket connections
Thread connectThread = new Thread(connect);
connectThread.start();
// monitor data changes
commCell.addReference(ref);
}
/**
* Shut down the given socket, and removes it from the socket vector.
*/
private void killSocket(int i) {
ObjectOutputStream out = (ObjectOutputStream) outs.elementAt(i);
Socket s = (Socket) sockets.elementAt(i);
// shut down socket output stream
try {
out.close();
}
catch (IOException exc) { }
// shut down socket itself
try {
s.close();
}
catch (IOException exc) { }
// remove socket from socket vectors
sockets.remove(i);
outs.remove(i);
}
/** destroys this server and kills all associated threads */
public void killServer() {
// set flag to cause server's threads to stop running
alive = false;
// shut down all client sockets
synchronized (sockets) {
while (sockets.size() > 0) killSocket(0);
}
// shut down server socket
try {
socket.close();
}
catch (IOException exc) { }
}
}