// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/link/LinkManager.java,v $
// $RCSfile: LinkManager.java,v $
// $Revision: 1.6 $
// $Date: 2004/10/14 18:05:56 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.layer.link;
import java.io.IOException;
import java.net.Socket;
import com.bbn.openmap.util.Debug;
/**
* The LinkManager..
*/
public class LinkManager {
protected String host;
protected int port;
protected boolean obeyCommandToExit;
/**
* volatile because we want internal methods to get the message
* that a link was nulled out.
*/
protected volatile ClientLink link;
/** Constructor. */
protected LinkManager() {}
/** Constructor. */
public LinkManager(String host, int port) {
this.host = host;
this.port = port;
}
public void setObeyCommandToExit(boolean value) {
obeyCommandToExit = value;
}
public boolean getObeyCommandToExit() {
return obeyCommandToExit;
}
/**
* This should be the only method a multi-threaded object uses to
* gain use of the thread, i.e., on the client side where a GUI
* can start a lot of requests. If the link was not able to be
* retained for the requestor, then null will be returned. Null
* should be tested for by the callers, so that they can handle
* the rejection properly.
*
* @param waitForLock if true, the caller will block in this
* method until the link has been locked for the caller. If
* false, a null will be returned if the lock on the link
* couldn't be set for the caller's use.
* @return a link if the link is locked for the caller's use, null
* if the link is not available.
*/
public ClientLink getLink(boolean waitForLock) throws java.io.IOException {
// NOTE: This should be the only place that the link
// object gets assigned. Otherwise, the layer can end up
// using two different links via different threads.
if (link == null) {
synchronized (this) {
if (link == null) {
link = getLink();
link.setObeyCommandToExit(obeyCommandToExit);
}
}
}
try {
while (!link.setLocked(true)) {
// This handles the case where we don't want to wait
// for the link to become available.
if (!waitForLock) {
return null;
}
// We will wait here for the link to not be in use.
// Catch a link == null in case the link was shut down
// in finLink() from another thread. IF we didn't
// catch the lock, we stay in the loop.
try {
Thread.sleep(300);
} catch (java.lang.InterruptedException ie) {
}
}
} catch (NullPointerException npe) {
// since probably means link is null, so just return null
// in case some other thread tries to do something
// tricky..
return null;
}
return link;
}
/**
* Called for a LayerListener that will not write to the Link,
* only read from it. Doesn't effect the lock.
*
* @return a link if the link is locked for the caller's use, null
* if the link is not available.
*/
protected ClientLink getLink(LinkListener ll) throws java.io.IOException {
// NOTE: This should be the only place that the link
// object gets assigned. Otherwise, the layer can end up
// using two different links via different threads.
if (link == null) {
synchronized (this) {
if (link == null) {
link = getLink();
link.setObeyCommandToExit(obeyCommandToExit);
}
}
}
return link;
}
/**
* Get the ClientLink however it is appropriate for this
* LinkManager. In this case, the LinkManager will just use the
* host and port assigned.
*/
protected ClientLink getLink() throws java.io.IOException {
ClientLink tmplink = null;
try {
if (Debug.debugging("link")) {
Debug.output("LinkManager.getLink(): establishing link to "
+ host + " on port " + port);
}
Socket socket = new Socket(host, port);
tmplink = new ClientLink(socket);
} catch (java.net.UnknownHostException uhe) {
Debug.error("LinkLayer: error trying to contact host:" + host);
tmplink = null;
throw new java.io.IOException("No Contact with host:" + host
+ " on port:" + port);
}
return tmplink;
}
/**
* When a getLink() is called, and the link is reserved for that
* caller, finLink() MUST be called to release the link for
* others. If it is not called, no one else will be able to use it.
*/
public void finLink() throws IOException {
if (link.isCloseLink()) {
Debug.message("link", "LinkManager.finLink: closing Link");
link.close();
link = null;
} else {
Debug.message("link", "LinkManager.finLink: releasing lock on Link");
link.setLocked(false);
}
}
/**
* Set the link to null.
*/
public void resetLink() {
if (link != null) {
try {
link.cleanUp();
link.close();
} catch (IOException ioe) {
// Nice try...
}
}
link = null;
}
}