update core event protocol

buko [2003-10-28 00:13:05]
update core event protocol
Filename
aether2/core/aether-core.ipr
aether2/core/aether-core.iws
aether2/core/doc/todo.txt
aether2/core/src/java/aether/event/Event.java
aether2/core/src/java/aether/event/Request.java
aether2/core/src/java/aether/net/AbstractLink.java
aether2/core/src/java/aether/net/AbstractMonitor.java
aether2/core/src/java/aether/net/DefaultMulticastSocket.java
aether2/core/src/java/aether/net/DefaultServerSocket.java
aether2/core/src/java/aether/net/DefaultSocket.java
aether2/core/src/java/aether/net/Link.java
aether2/core/src/java/aether/net/Monitor.java
aether2/core/src/java/aether/net/MulticastSocket.java
aether2/core/src/java/aether/net/ServerSocket.java
aether2/core/src/java/aether/net/Socket.java
aether2/core/src/test/aether/net/DefaultLinkTest.java
aether2/core/src/test/aether/net/DefaultMonitorTest.java
aether2/hercules/doc/todo.txt
aether2/hercules/hercules.iws
aether2/hercules/src/java/aether/server/domain/DomainAgent.java
aether2/lib/aether-core-0.1.jar
diff --git a/aether2/core/aether-core.ipr b/aether2/core/aether-core.ipr
index 3369351..9d30759 100644
--- a/aether2/core/aether-core.ipr
+++ b/aether2/core/aether-core.ipr
@@ -76,7 +76,7 @@
       <maximumHeapSize value="128" />
       <viewClosedWhenNoErrors value="false" />
       <additionalClassPath>
-        <entry path="file://file://file://file://file://$PROJECT_DIR$/../../common-lib/junit.jar" />
+        <entry path="file://file://file://file://file://file://file://$PROJECT_DIR$/../../common-lib/junit.jar" />
       </additionalClassPath>
       <targetFilters>
         <filter targetName="init" isVisible="false" />
diff --git a/aether2/core/aether-core.iws b/aether2/core/aether-core.iws
index 3f96de0..ea32ac6 100644
--- a/aether2/core/aether-core.iws
+++ b/aether2/core/aether-core.iws
@@ -2,43 +2,44 @@
 <project version="3" relativePaths="true">
   <component name="FileEditorManager">
     <history>
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/event/BlockingEventQueue.java" line="11" column="13" vertical-scroll-proportion="0.33212996" horizontal-scroll-proportion="0.200883" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/AbstractConnection.java" line="2" column="26" vertical-scroll-proportion="0.07317073" horizontal-scroll-proportion="0.2524272" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/Link.java" line="53" column="54" vertical-scroll-proportion="0.4512195" horizontal-scroll-proportion="0.52427185" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/AbstractLink.java" line="252" column="51" vertical-scroll-proportion="0.9268293" horizontal-scroll-proportion="0.49514562" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/DefaultLink.java" line="15" column="13" vertical-scroll-proportion="0.5487805" horizontal-scroll-proportion="0.1262136" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/Connection.java" line="11" column="17" vertical-scroll-proportion="-0.10627177" horizontal-scroll-proportion="0.16504854" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/Publisher.java" line="12" column="17" vertical-scroll-proportion="0.36585367" horizontal-scroll-proportion="0.16504854" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/Monitor.java" line="91" column="0" vertical-scroll-proportion="0.9602888" horizontal-scroll-proportion="0.0" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/AbstractMonitor.java" line="260" column="40" vertical-scroll-proportion="0.9602888" horizontal-scroll-proportion="0.3883495" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/DefaultConnection.java" line="8" column="25" vertical-scroll-proportion="0.028880866" horizontal-scroll-proportion="0.24271844" />
-      <source-position-entry url="file://$PROJECT_DIR$/.cvsignore" line="6" column="15" vertical-scroll-proportion="0.22743683" horizontal-scroll-proportion="0.14563107" />
-      <source-position-entry url="file://$PROJECT_DIR$/build.xml" line="71" column="0" vertical-scroll-proportion="2.597561" horizontal-scroll-proportion="0.0" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/event/Message.java" line="1" column="92" vertical-scroll-proportion="0.036585364" horizontal-scroll-proportion="0.89196676" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/event/Request.java" line="48" column="0" vertical-scroll-proportion="0.8815331" horizontal-scroll-proportion="0.0" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/DefaultMonitor.java" line="78" column="36" vertical-scroll-proportion="0.8763066" horizontal-scroll-proportion="0.34903046" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/Connection.java" line="11" column="17" vertical-scroll-proportion="-0.902439" horizontal-scroll-proportion="0.16481994" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/AbstractConnection.java" line="14" column="13" vertical-scroll-proportion="-2.6585367" horizontal-scroll-proportion="0.12603877" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/event/Request.java" line="12" column="13" vertical-scroll-proportion="-0.5156794" horizontal-scroll-proportion="0.12603877" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/event/Message.java" line="63" column="31" vertical-scroll-proportion="0.33212996" horizontal-scroll-proportion="0.300554" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/event/Response.java" line="26" column="31" vertical-scroll-proportion="0.33275262" horizontal-scroll-proportion="0.300554" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/DefaultMulticastSocket.java" line="23" column="27" vertical-scroll-proportion="0.33212996" horizontal-scroll-proportion="0.26177284" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/DefaultServerSocket.java" line="17" column="25" vertical-scroll-proportion="0.33212996" horizontal-scroll-proportion="0.24238227">
+        <folding>
+          <element signature="imports" expanded="true" />
+        </folding>
+      </source-position-entry>
+      <source-position-entry url="file://$PROJECT_DIR$/doc/todo.txt" line="2" column="0" vertical-scroll-proportion="0.07317073" horizontal-scroll-proportion="0.0" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/DefaultSocket.java" line="21" column="13" vertical-scroll-proportion="0.33275262" horizontal-scroll-proportion="0.12603877" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/MulticastSocket.java" line="0" column="58" vertical-scroll-proportion="0.0" horizontal-scroll-proportion="0.56232685" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/Socket.java" line="14" column="17" vertical-scroll-proportion="-1.8623693" horizontal-scroll-proportion="0.16481994" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/ServerSocket.java" line="70" column="81" vertical-scroll-proportion="0.9425087" horizontal-scroll-proportion="0.78531855">
+        <folding>
+          <element signature="imports" expanded="true" />
+        </folding>
+      </source-position-entry>
     </history>
-    <open-files>
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/event/Message.java" line="1" column="92" vertical-scroll-proportion="0.036585364" horizontal-scroll-proportion="0.89196676" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/event/Request.java" line="48" column="0" vertical-scroll-proportion="0.8815331" horizontal-scroll-proportion="0.0" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/net/DefaultMonitor.java" line="78" column="36" vertical-scroll-proportion="0.8763066" horizontal-scroll-proportion="0.34903046" selected="true" />
-    </open-files>
+    <open-files />
   </component>
   <component name="ToolWindowManager">
-    <frame x="65" y="12" width="835" height="719" extended-state="0" />
-    <editor active="true" />
+    <frame x="21" y="11" width="835" height="719" extended-state="0" />
+    <editor active="false" />
     <layout>
-      <window_info id="Ant Build" active="false" anchor="right" auto_hide="true" internal_type="docked" type="docked" visible="false" weight="0.25" order="1" />
+      <window_info id="Ant Build" active="false" anchor="right" auto_hide="true" internal_type="docked" type="docked" visible="false" weight="0.24968314" order="1" />
       <window_info id="Cvs" active="false" anchor="bottom" auto_hide="true" internal_type="docked" type="docked" visible="false" weight="0.44585988" order="5" />
       <window_info id="Run" active="false" anchor="bottom" auto_hide="true" internal_type="docked" type="docked" visible="false" weight="0.32991204" order="2" />
       <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="docked" type="docked" visible="false" weight="0.25" order="2" />
       <window_info id="TODO" active="false" anchor="bottom" auto_hide="true" internal_type="docked" type="docked" visible="false" weight="0.32991204" order="7" />
       <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="sliding" type="sliding" visible="false" weight="0.4004065" order="0" />
-      <window_info id="Project" active="false" anchor="left" auto_hide="true" internal_type="docked" type="docked" visible="false" weight="0.33333334" order="0" />
+      <window_info id="Project" active="false" anchor="left" auto_hide="true" internal_type="docked" type="docked" visible="false" weight="0.41444868" order="0" />
       <window_info id="Debug" active="false" anchor="bottom" auto_hide="true" internal_type="docked" type="docked" visible="false" weight="0.40029326" order="3" />
       <window_info id="Structure" active="false" anchor="left" auto_hide="true" internal_type="docked" type="docked" visible="false" weight="0.25" order="1" />
       <window_info id="Find" active="false" anchor="bottom" auto_hide="true" internal_type="docked" type="docked" visible="false" weight="0.32961783" order="1" />
-      <window_info id="Messages" active="false" anchor="bottom" auto_hide="true" internal_type="sliding" type="sliding" visible="false" weight="0.51592356" order="8" />
+      <window_info id="Messages" active="true" anchor="bottom" auto_hide="true" internal_type="sliding" type="sliding" visible="true" weight="0.51592356" order="8" />
       <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="docked" type="docked" visible="false" weight="0.40029326" order="6" />
       <window_info id="Web" active="false" anchor="left" auto_hide="false" internal_type="docked" type="docked" visible="false" weight="0.25" order="2" />
       <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="docked" type="docked" visible="false" weight="0.33" order="0" />
@@ -186,7 +187,7 @@
     </Diff>
     <Add>
       <option name="ADD_AS_BINARY" value="false" />
-      <option name="LOG_MESSAGE" value="" />
+      <option name="LOG_MESSAGE" value="implementing core event protocol" />
     </Add>
     <Status>
       <option name="NON_RECURSIVE" value="false" />
@@ -248,10 +249,9 @@
     <navigator currentView="ProjectPane" flattenPackages="true" showMembers="false" showStructure="false" autoscrollToSource="false" splitterProportion="0.5" />
     <view id="ProjectPane">
       <expanded_node type="directory" url="file://$PROJECT_DIR$/src" />
+      <expanded_node type="directory" url="file://$PROJECT_DIR$/doc" />
       <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java" />
       <expanded_node type="directory" url="file://$PROJECT_DIR$" />
-      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/aether/event" />
-      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/aether/net" />
     </view>
     <view id="SourcepathPane" />
     <view id="ClasspathPane" />
diff --git a/aether2/core/doc/todo.txt b/aether2/core/doc/todo.txt
new file mode 100644
index 0000000..722cf69
--- /dev/null
+++ b/aether2/core/doc/todo.txt
@@ -0,0 +1,2 @@
+
+[ 10.28.2003 ]
diff --git a/aether2/core/src/java/aether/event/Event.java b/aether2/core/src/java/aether/event/Event.java
index 7fdfab6..248ca12 100644
--- a/aether2/core/src/java/aether/event/Event.java
+++ b/aether2/core/src/java/aether/event/Event.java
@@ -35,6 +35,7 @@ public abstract class Event implements Attribute.Event
         // create the unique event id and set the event type
         setEventID(GuidFactory.createId());
         setEventType(getEventType());
+        setTime(System.currentTimeMillis());
 	}

     /**
@@ -90,7 +91,7 @@ public abstract class Event implements Attribute.Event
 	 *
 	 * @param time time this event was sent
 	 */
-	public void setTime(long time)
+	private void setTime(long time)
 	{
 		notification.put(TIME, time);
 	}
diff --git a/aether2/core/src/java/aether/event/Request.java b/aether2/core/src/java/aether/event/Request.java
index 6918ed0..a0a562b 100644
--- a/aether2/core/src/java/aether/event/Request.java
+++ b/aether2/core/src/java/aether/event/Request.java
@@ -43,8 +43,6 @@ public class Request extends Message implements Attribute.Request
 		// source of the response is the GUID of the responder
 		resp.setSourceId(srcId);

-		resp.setTime(System.currentTimeMillis());
-
 		return resp;
 	}

diff --git a/aether2/core/src/java/aether/net/AbstractLink.java b/aether2/core/src/java/aether/net/AbstractLink.java
deleted file mode 100644
index 4697207..0000000
--- a/aether2/core/src/java/aether/net/AbstractLink.java
+++ /dev/null
@@ -1,252 +0,0 @@
-package aether.net;
-
-import aether.event.Event;
-import aether.event.EventException;
-import aether.event.Request;
-import aether.event.Response;
-import aether.util.GuidFactory;
-import org.apache.log4j.Logger;
-import org.elvin.je4.Consumer;
-import org.elvin.je4.Notification;
-import org.elvin.je4.NotificationListener;
-import org.elvin.je4.Subscription;
-
-import java.io.IOException;
-
-/**
- * Represents a conversation with a specific resource on an Aether host.
- *
- * @author Buko O. (buko@concedere.net)
- * @version 0.1
- **/
-public abstract class AbstractLink implements Link
-{
-	/**
-	 * GUID of the last component to send a response or the end point of this
-	 * link. This could also be a URL.
-	 */
-	protected String destination;
-
-	/**
-	 * Unique ID for this link.
-	 */
-	protected String linkId;
-
-	/**
-	 * True if this link is closed.
-	 */
-	protected boolean closed = true;
-
-	/**
-	 * Underlying Connection used to send and receive.
-	 */
-	protected Connection connection;
-
-
-	private Consumer consumer;
-	private Subscription subscription;
-	private Response response;
-	private boolean timedOut;
-	private NotificationListener notifListener =
-			new LinkNotificationListener();
-
-	private static final Logger logger = Logger.getLogger(AbstractLink.class);
-
-	public void connect() throws IOException
-	{
-     	if (!closed)
-		 {
-			 String msg = "link already connected";
-			 throw new IllegalStateException(msg);
-		 }
-
-		// open the connection if we have to
-		if (!connection.isOpen()) connection.open();
-
-		// calculate the link id
-		this.linkId = GuidFactory.createId();
-
-        // construct the subscription needed to listen for responses sent over
-		// this link
-		this.subscription = Response.createSubscriptionToReceive(linkId);
-		this.subscription.addNotificationListener(notifListener);
-
-		// now subscribe to all responses sent over this link
-        this.consumer = new Consumer(connection.elvinConnection());
-        this.consumer.addSubscription(subscription);
-		this.closed = false;
-	}
-
-	public synchronized void close() throws IOException
-	{
-		if (closed)
-		{
-			String msg = "session already closed";
-			throw new IllegalStateException(msg);
-		}
-
-        // unsubscribe from responses and close the consumer
-		consumer.removeSubscription(this.subscription);
-		consumer.close();
-
-		// free all resources. Note that the Connection is not closed here!
-		// it's the job of the subclass to close the connection
-        this.consumer = null;
-		this.subscription = null;
-		this.response = null;
-		closed = true;
-	}
-
-	public String getLinkId()
-	{
-		return linkId;
-	}
-
-	public String getDestination()
-	{
-		return destination;
-	}
-
-	public Request createRequest()
-    {
-		if (closed)
-		{
-			String msg = "link is closed";
-			throw new IllegalStateException(msg);
-		}
-
-		Request request = new Request();
-
-		// set the linkId, destination
-		request.setLink(this.linkId);
-		request.setDestination(this.destination);
-
-		return request;
-	}
-
-	public synchronized Response send(Request req) throws IOException
-	{
-		if (req == null)
-		{
-			String msg = "request can't be null";
-			throw new IllegalArgumentException(msg);
-		}
-
-		if (closed)
-		{
-			String msg = "link is closed";
-			throw new IllegalStateException(msg);
-		}
-
-        // make sure that this is a request that we created!!
-        if (!linkId.equals(req.getLink()))
-        {
-            String msg = "request wasn't created by this link!";
-            throw new IllegalArgumentException(msg);
-        }
-
-		// now send the request!!
-		connection.publish(req);
-
-		// now send the request and block until the response comes
-		return blockUntilResponse();
-	}
-
-	/**
-	 * After a request has been sent, the calling thread must be blocked
-	 * until a response event is received. This method causes the blocking to
-	 * occur.
-	 *
-	 * @return RESPONSE of the request
-	 * @throws IOException
-	 *         if something goes wrong
-	 */
-	protected synchronized Response blockUntilResponse()
-			throws IOException
-	{
-
-        // go into a spin block and just block until either a response comes
-		// or the request is timed out
-        try
-		{
-			while ((response == null) && (!timedOut))
-			{
-                this.wait();
-			}
-		}
-		catch (InterruptedException ie)
-		{
-			// should never happen
-			String msg = "internal error in " + getClass();
-			throw new Error(msg, ie);
-		}
-
-        // ok we've woken up! did we wake up because we timed out?
-		if (timedOut)
-		{
-            timedOut = false;
-            String msg = "request timed out";
-			throw new IOException(msg);
-		}
-
-        // otherwise, let's save the given response and send it while resetting
-		// te state of the connection
-        Response lastResponse = response;
-        this.response = null;
-        return lastResponse;
-	}
-
-	/**
-	 * Timeout this Link's most recent request/response transaction.
-	 */
-	public synchronized void timeOut()
-	{
-		if (closed)
-		{
-			String msg = "link is closed";
-			throw new IllegalStateException(msg);
-		}
-
-        timedOut = true;
-
-		// wake up any thread waiting on the connection
-		notify();
-	}
-
-	/**
-	 * A special NotificationListener that will allow us to process all
-	 * events sent to this AbstractLink.
-	 *
-	 * @author Buko O. (buko@concedere.net)
-	 * @version 0.1
-	 */
-	private class LinkNotificationListener implements NotificationListener
-	{
-		public void notificationAction(Notification notification)
-		{
-			// if this getNotification is a response  let's process it
-        	if (Event.isResponse(notification))
-			{
-				try
-				{
-					// obtain the lock on the outer object first!
-					synchronized (AbstractLink.this)
-					{
-            			response = new Response();
-                        response.parse(notification);
-
-						// wake up any threads sleeping on this object, waiting
-						// for a response
-						AbstractLink.this.notify();
-					}
-				}
-				catch (EventException me)
-				{
-                	// bad response data, let's log it and ignore it
-                    String msg = "receieved badly formed response";
-					throw new Error(msg, me);
-				}
-			}
-		}
-	}
-}
diff --git a/aether2/core/src/java/aether/net/AbstractMonitor.java b/aether2/core/src/java/aether/net/AbstractMonitor.java
deleted file mode 100644
index 8088a22..0000000
--- a/aether2/core/src/java/aether/net/AbstractMonitor.java
+++ /dev/null
@@ -1,263 +0,0 @@
-package aether.net;
-
-import aether.event.Event;
-import aether.event.EventException;
-import aether.event.EventHandler;
-import aether.event.Notice;
-import org.elvin.je4.Consumer;
-import org.elvin.je4.Notification;
-import org.elvin.je4.NotificationListener;
-import org.elvin.je4.Subscription;
-
-import javax.swing.event.EventListenerList;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * Provides the basic implementation of the Monitor interface.
- *
- * @author Buko O. (buko@concedere.net)
- * @version 0.1
- **/
-public class AbstractMonitor implements Monitor
-{
-    /**
-	 * List of listeners on this monitor.
-	 */
-	protected EventListenerList listenerList = new EventListenerList();
-
-	/**
-	 * Map to store the subscriptions we've created. Each Subscription is
-	 * mapped to the guid of the component being monitored.
-	 */
-	protected Map subscriptionMap = new HashMap();
-
-	/**
-	 * Map to store the subscriptions to topic. Each Subscription is mapped
-	 * to the topic subscribed to.
-	 */
-	protected Map topicMap = new HashMap();
-
-	/**
-	 * Consumer that actually adds and removes Subscriptions. Subclasses are
-	 * responsible for initializing this.
-	 */
-	protected Consumer consumer;
-
-	/**
-	 * Connection used to connect to the underlying network.
-	 */
-	protected Connection connection;
-
-	/**
-	 * Special NotificationListener that enqueues incoming Notices.
-	 */
-	protected NotificationListener queueListener =
-			new QueueNotificationListener();
-
-
-	public void subscribe(String topic) throws IOException
-	{
-		if (topic == null)
-		{
-			String msg = "no parameter can be null";
-			throw new IllegalArgumentException(msg);
-		}
-
-		if (!isOpen())
-		{
-			String msg = "monitor is closed";
-			throw new IllegalStateException(msg);
-		}
-
-        // have we already subscribed to this topic? if so, ignore it!
-		if (!topicMap.containsKey(topic))
-		{
-			// create the Subscription from the uri and add our listener to it
-			Subscription subscription = Notice.createTopicSubscription(topic);
-            subscription.addNotificationListener(queueListener);
-
-			// subscribe to it
-			consumer.addSubscription(subscription);
-
-			// put it in the map
-			topicMap.put(topic, subscription);
-		}
-	}
-
-	public void unsubscribe(String topic) throws IOException
-	{
-		if (topic == null)
-		{
-			String msg = "no parameter can be null";
-			throw new IllegalArgumentException(msg);
-		}
-
-		if (!isOpen())
-		{
-			String msg = "monitor is closed";
-			throw new IllegalStateException(msg);
-		}
-
-        // if subscribed to this guid, remove the subscription
-		if (topicMap.containsKey(topic))
-		{
-			Subscription sub = (Subscription) topicMap.remove(topic);
-			consumer.removeSubscription(sub);
-		}
-	}
-
-	public Connection getConnection()
-	{
-		return connection;
-	}
-
-	public synchronized void setConnection(Connection msgConn)
-	{
-        if (isOpen())
-		{
-            String msg = "monitor is open";
-			throw new IllegalStateException(msg);
-		}
-
-		if (msgConn == null)
-		{
-			String msg = "msgConn can't be null";
-			throw new IllegalArgumentException(msg);
-		}
-
-		this.connection = msgConn;
-	}
-
-	public void addNoticeListener(EventHandler handler)
-	{
-		if (handler != null)
-		{
-			listenerList.add(EventHandler.class, handler);
-		}
-	}
-
-	public void removeNoticeListener(EventHandler handler)
-	{
-		if (handler != null)
-		{
-			listenerList.remove(EventHandler.class, handler);
-		}
-	}
-
-	public synchronized boolean isOpen()
-	{
-		return (consumer != null);
-	}
-
-	public synchronized void open() throws IOException
-	{
-		if (isOpen())
-		{
-			String msg = "monitor already open";
-			throw new IllegalStateException(msg);
-		}
-
-		// open the event connection if it's not already open
-		if (!connection.isOpen()) connection.open();
-
-		// create the consumer
-		this.consumer = new Consumer(connection.elvinConnection());
-	}
-
-	/**
-	 * Unsubscribe from all the currently active subscriptions.
-	 *
-	 * @throws IOException
-	 *         if an unsubscription op fails
-	 */
-	protected synchronized void clearSubscriptions() throws IOException
-	{
-		if (!isOpen())
-		{
-			String msg = "monitor already closed";
-			throw new IllegalStateException(msg);
-		}
-
-		// unsubscribe from all subscription being monitored
-		for (Iterator iter = subscriptionMap.entrySet().iterator();
-			 iter.hasNext(); )
-		{
-			Subscription sub = (Subscription)
-					((Map.Entry) iter.next()).getValue();
-
-			consumer.removeSubscription(sub);
-
-			iter.remove();
-		}
-
-		// unsubscribe from all topics subscribed to
-        for (Iterator iter = topicMap.entrySet().iterator();
-			 iter.hasNext(); )
-		{
-			Subscription sub = (Subscription)
-					((Map.Entry) iter.next()).getValue();
-
-			consumer.removeSubscription(sub);
-
-			iter.remove();
-		}
-	}
-
-	public synchronized void close() throws IOException
-	{
-		clearSubscriptions();
-		connection.close();
-		connection = null;
-	}
-
-	/**
-	 * Fire an incoming NOTICE to all registered listeners.
-	 *
-	 * @param notice NOTICE to be delivered to all listeners
-	 */
-	protected void fireNoticeReceived(Notice notice)
-	{
-		Object[] listeners = listenerList.getListenerList();
-
-		for (int i = listeners.length - 2; i >= 0; i -= 2)
-		{
-			if (listeners[i] == EventHandler.class)
-			{
-				((EventHandler) listeners[i + 1]).handle(notice);
-			}
-		}
-	}
-
-	/**
-	 * NotificationListener that enqueues all incoming NOTICE objects.
-	 *
-	 * @author Buko O. (buko@concedere.net)
-	 * @version 0.1
-	 */
-	private class QueueNotificationListener implements NotificationListener
-	{
-		public void notificationAction(Notification notification)
-		{
-			if (Event.isNotice(notification))
-			{
-				try
-				{
-					Notice n = new Notice();
-					n.parse(notification);
-					fireNoticeReceived(n);
-				}
-				catch (EventException me)
-				{
-					String msg = "receieved bad getNotification!";
-					throw new Error(msg, me);
-				}
-			}
-		}
-
-	}
-
-}
-
diff --git a/aether2/core/src/java/aether/net/DefaultMulticastSocket.java b/aether2/core/src/java/aether/net/DefaultMulticastSocket.java
new file mode 100644
index 0000000..02e3161
--- /dev/null
+++ b/aether2/core/src/java/aether/net/DefaultMulticastSocket.java
@@ -0,0 +1,232 @@
+package aether.net;
+
+import aether.event.Event;
+import aether.event.EventException;
+import aether.event.EventHandler;
+import aether.event.Notice;
+import org.elvin.je4.Consumer;
+import org.elvin.je4.Notification;
+import org.elvin.je4.NotificationListener;
+import org.elvin.je4.Subscription;
+import org.apache.log4j.Logger;
+
+import javax.swing.event.EventListenerList;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Provides the basic implementation of the MulticastSocket interface.
+ *
+ * @author Buko O. (buko@concedere.net)
+ * @version 0.1
+ **/
+public class DefaultMulticastSocket implements MulticastSocket
+{
+    /**
+     * List of listeners on this monitor.
+     */
+    protected EventListenerList listenerList = new EventListenerList();
+
+    /**
+     * Map to store the subscriptions to topic. String topics are mapped to
+     * Subscription objects.
+     */
+    protected Map topicMap = new HashMap();
+
+    /**
+     * Open status of the monitor.
+     */
+    protected boolean open;
+
+    private NotificationListener queueListener;
+    private Connection connection;
+    private Consumer consumer;
+
+    private static final Logger log = Logger.getLogger(DefaultMulticastSocket.class);
+
+    /**
+     * Construct a new DefaultMulticastSocket.
+     *
+     * @param conn open connection to the event network
+     */
+    public DefaultMulticastSocket(Connection conn)
+    {
+        if (conn == null)
+        {
+            String msg = "no parameter can be null";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (!conn.isOpen())
+        {
+            String msg = "conn must be an open connection";
+            throw new IllegalArgumentException(msg);
+        }
+
+        this.connection = conn;
+    }
+
+    public synchronized void subscribe(String topic) throws IOException
+    {
+        if (topic == null)
+        {
+            String msg = "no parameter can be null";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (!isOpen())
+        {
+            String msg = "monitor isn't open";
+            throw new IllegalStateException(msg);
+        }
+
+        // have we already subscribed to this topic? if so, ignore it!
+        if (!topicMap.containsKey(topic))
+        {
+            // create the Subscription from the uri and add our listener to it
+            Subscription subscription = Notice.createTopicSubscription(topic);
+            subscription.addNotificationListener(queueListener);
+
+            // subscribe to it
+            consumer.addSubscription(subscription);
+
+            // put it in the map
+            topicMap.put(topic, subscription);
+        }
+    }
+
+    public synchronized void unsubscribe(String topic) throws IOException
+    {
+        if (topic == null)
+        {
+            String msg = "no parameter can be null";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (!isOpen())
+        {
+            String msg = "monitor isn't open";
+            throw new IllegalArgumentException(msg);
+        }
+
+        // if subscribed to this guid, remove the subscription
+        if (topicMap.containsKey(topic))
+        {
+            Subscription sub = (Subscription) topicMap.remove(topic);
+            consumer.removeSubscription(sub);
+        }
+    }
+
+    public void broadcast(Notice notice, String topic) throws IOException
+    {
+        if ((notice == null) || (topic == null))
+        {
+            String msg = "no parameter can be null";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (!isOpen())
+        {
+            String msg = "multicaster isn't open!";
+            throw new IllegalStateException(msg);
+        }
+
+        // setup the meta info
+        notice.setTopicId(topic);
+
+        connection.publish(notice);
+    }
+
+    public void addEventHandler(EventHandler handler)
+    {
+        if (handler != null)
+        {
+            listenerList.add(EventHandler.class, handler);
+        }
+    }
+
+    public void removeEventHandler(EventHandler handler)
+    {
+        if (handler != null)
+        {
+            listenerList.remove(EventHandler.class, handler);
+        }
+    }
+
+    public synchronized void open() throws IOException
+    {
+        if (isOpen())
+        {
+            String msg = "monitor already open";
+            throw new IllegalStateException(msg);
+        }
+
+        // create the consumer
+        this.consumer = new Consumer(connection.elvinConnection());
+        this.queueListener = new QueueNotificationListener();
+        open = true;
+    }
+
+    public synchronized void close() throws IOException
+    {
+        topicMap.clear();
+        consumer.close();
+        consumer = null;
+        queueListener = null;
+        open = false;
+    }
+
+    public boolean isOpen()
+    {
+        return open;
+    }
+
+    /**
+     * Fire an incoming Notice to all registered listeners.
+     *
+     * @param notice Notice to be delivered to all listeners
+     */
+    protected void fireNoticeReceived(Notice notice)
+    {
+        Object[] listeners = listenerList.getListenerList();
+
+        for (int i = listeners.length - 2; i >= 0; i -= 2)
+        {
+            if (listeners[i] == EventHandler.class)
+            {
+                ((EventHandler) listeners[i + 1]).handle(notice);
+            }
+        }
+    }
+
+    /**
+     * NotificationListener that enqueues all incoming NOTICE objects.
+     *
+     * @author Buko O. (buko@concedere.net)
+     * @version 0.1
+     */
+    private class QueueNotificationListener implements NotificationListener
+    {
+        public void notificationAction(Notification notification)
+        {
+            if (Event.isNotice(notification))
+            {
+                try
+                {
+                    Notice n = new Notice();
+                    n.parse(notification);
+                    fireNoticeReceived(n);
+                }
+                catch (EventException me)
+                {
+                    String msg = "receieved bad notification " + notification;
+                    log.warn(msg, me);
+                }
+            }
+        }
+
+    }
+
+}
+
diff --git a/aether2/core/src/java/aether/net/DefaultServerSocket.java b/aether2/core/src/java/aether/net/DefaultServerSocket.java
new file mode 100644
index 0000000..42782aa
--- /dev/null
+++ b/aether2/core/src/java/aether/net/DefaultServerSocket.java
@@ -0,0 +1,160 @@
+package aether.net;
+
+import org.elvin.je4.Consumer;
+import org.elvin.je4.Subscription;
+import org.elvin.je4.NotificationListener;
+import org.elvin.je4.Notification;
+import org.apache.log4j.Logger;
+import aether.event.*;
+
+import java.io.IOException;
+
+/**
+ * Base implementation of the {@link ServerSocket} interface.
+ *
+ * Buko O. (aso22@columbia.edu)
+ * @version 0.1
+ **/
+public class DefaultServerSocket implements ServerSocket
+{
+    /**
+     * URI of the destination.
+     */
+    protected String destination;
+
+    /**
+     * ID of the component generating responses.
+     */
+    protected String sourceID;
+
+    /**
+     * EventHandler to be notified of incoming requests.
+     */
+    protected EventHandler eventHandler;
+
+    private Consumer consumer;
+    private Subscription subscription;
+    private Connection connection;
+
+    private static final Logger log =
+            Logger.getLogger(DefaultServerSocket.class);
+
+    /**
+     * Construct a new DefaultServerSocket.
+     *
+     * @param dest  URI of the destination
+     * @param srcID ID of the component generating responses
+     * @param conn  Connection to the event network
+     */
+    public DefaultServerSocket(String dest, String srcID, Connection conn)
+    {
+        if ((dest == null) || (srcID == null) || (conn == null))
+        {
+            String msg = "no parameter can be null";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (!conn.isOpen())
+        {
+            String msg = "conn isn't an open connection";
+            throw new IllegalArgumentException(msg);
+        }
+
+        this.destination = dest;
+        this.sourceID = srcID;
+        this.connection = conn;
+    }
+
+    public String getDestination()
+    {
+        return destination;
+    }
+
+    public String getSourceId()
+    {
+        return sourceID;
+    }
+
+    public void setEventHandler(EventHandler handler)
+    {
+        this.eventHandler = handler;
+    }
+
+    public EventHandler getEventHandler()
+    {
+        return eventHandler;
+    }
+
+    public synchronized void bind() throws IOException
+    {
+        // construct the subscription to receive requests sent to the
+        // destination
+        this.subscription =
+                Message.createSubscriptionForDestination(destination);
+
+        // when a request comes in, just hand it off to the EventHandler
+        NotificationListener n = new NotificationListener()
+        {
+            public void notificationAction(Notification notification)
+            {
+                // make sure the notification is a request
+                if (!Event.isRequest(notification))
+                {
+                    log.warn("Received notification " + notification
+                             + " which isn't a request.");
+                    return;
+                }
+
+                // try to parse it as a request
+                Request request = new Request();
+                try
+                {
+                    request.parse(notification);
+                }
+                catch (EventException ee)
+                {
+                    log.warn("Failed to parse notification " + notification
+                             + "as a request.", ee);
+                    return;
+                }
+
+                // pass it to the event handler
+                eventHandler.handle(request);
+            }
+        };
+        subscription.addNotificationListener(n);
+
+        consumer = new Consumer(connection.elvinConnection());
+        consumer.addSubscription(subscription);
+    }
+
+    public synchronized void unbind() throws IOException
+    {
+        consumer.close();
+        consumer = null;
+        subscription = null;
+    }
+
+    public void sendResponse(Request request, Response response)
+            throws IOException
+    {
+        if ((request == null) || (response == null))
+        {
+            String msg = "no parameter can be null";
+            throw new IllegalArgumentException(msg);
+        }
+
+        // preserve the link ID from the request
+        response.setLink(request.getLink());
+
+        // destination of the response is the source of the request
+        response.setDestination(request.getSourceId());
+
+        // set the source ID for the response
+        response.setSourceId(sourceID);
+
+        // now send the response over the network
+        connection.publish(response);
+    }
+}
+
diff --git a/aether2/core/src/java/aether/net/DefaultSocket.java b/aether2/core/src/java/aether/net/DefaultSocket.java
new file mode 100644
index 0000000..33393b2
--- /dev/null
+++ b/aether2/core/src/java/aether/net/DefaultSocket.java
@@ -0,0 +1,255 @@
+package aether.net;
+
+import aether.event.Event;
+import aether.event.EventException;
+import aether.event.Request;
+import aether.event.Response;
+import aether.util.GuidFactory;
+import org.apache.log4j.Logger;
+import org.elvin.je4.Consumer;
+import org.elvin.je4.Notification;
+import org.elvin.je4.NotificationListener;
+import org.elvin.je4.Subscription;
+
+import java.io.IOException;
+
+/**
+ * Represents a conversation with a specific resource on an Aether host.
+ *
+ * @author Buko O. (buko@concedere.net)
+ * @version 0.1
+ **/
+public class DefaultSocket implements Socket
+{
+	/**
+	 * GUID of the last component to send a response or the end point of this
+	 * link. This could also be a URL.
+	 */
+	protected String destination;
+
+	/**
+	 * Unique ID for this link.
+	 */
+	protected String linkId;
+
+	/**
+	 * True if this link is closed.
+	 */
+	protected boolean disconnected = true;
+
+    /**
+     * Timeout time for send operations.
+     */
+    protected long timeOut = DEFAULT_TIMEOUT;
+
+	private Connection connection;
+	private Consumer consumer;
+	private Subscription subscription;
+	private Response response;
+	private NotificationListener notifListener;
+
+	private static final Logger logger = Logger.getLogger(DefaultSocket.class);
+
+     /**
+	 * Construct a new DefaultSocket to some responding component on the network.
+	 *
+	 * @param conn Connection to the underlying event network
+	 * @param dest destination to send requests to
+	 */
+	public DefaultSocket(Connection conn, String dest)
+	{
+        if ((conn == null) || (dest == null))
+        {
+            String msg = "no parameter can be null";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (!conn.isOpen())
+        {
+            String msg = "conn must be an open connection";
+            throw new IllegalArgumentException(msg);
+        }
+
+		this.connection = conn;
+		this.destination = dest;
+	}
+
+	public synchronized void connect() throws IOException
+	{
+     	if (!disconnected)
+		 {
+			 String msg = "link already connected";
+			 throw new IllegalStateException(msg);
+		 }
+
+		// calculate the link id
+		this.linkId = GuidFactory.createId();
+
+        // construct the subscription needed to listen for responses sent over
+		// this link
+		this.subscription = Response.createSubscriptionToReceive(linkId);
+        this.notifListener = new LinkNotificationListener();
+		this.subscription.addNotificationListener(notifListener);
+
+		// now subscribe to all responses sent over this link
+        this.consumer = new Consumer(connection.elvinConnection());
+        this.consumer.addSubscription(subscription);
+		this.disconnected = false;
+	}
+
+	public synchronized void disconnect() throws IOException
+	{
+		if (disconnected)
+		{
+			String msg = "link already closed";
+			throw new IllegalStateException(msg);
+		}
+
+        // unsubscribe from responses and close the consumer
+		consumer.close();
+
+		// free all resources
+        this.consumer = null;
+		this.subscription = null;
+        this.notifListener = null;
+		this.response = null;
+		disconnected = true;
+	}
+
+    public boolean isConnected()
+    {
+        return disconnected;
+    }
+
+	public String getLinkId()
+	{
+		return linkId;
+	}
+
+	public String getDestination()
+	{
+		return destination;
+	}
+
+    public void setTimeOut(long timeout)
+    {
+        this.timeOut = timeout;
+    }
+
+    public long getTimeOut()
+    {
+        return timeOut;
+    }
+
+	public synchronized Response send(Request request) throws IOException
+	{
+		if (request == null)
+		{
+			String msg = "request can't be null";
+			throw new IllegalArgumentException(msg);
+		}
+
+		if (disconnected)
+		{
+			String msg = "link is closed";
+			throw new IllegalStateException(msg);
+		}
+
+        // set the linkId, destination
+		request.setLink(this.linkId);
+		request.setDestination(this.destination);
+
+		// now send the request!!
+		connection.publish(request);
+
+		// now send the request and block until the response comes
+		return blockUntilResponse();
+	}
+
+	/**
+	 * After a request has been sent, the calling thread must be blocked
+	 * until a response event is received. This method causes the blocking to
+	 * occur.
+	 *
+	 * @return Response of the request
+	 * @throws IOException
+	 *         if something goes wrong
+	 */
+	protected synchronized Response blockUntilResponse()
+			throws IOException
+	{
+        // go into a spin block and just block until either a response comes
+		// or the request is timed out
+        try
+		{
+			while (response == null)
+			{
+                this.wait(timeOut);
+			}
+		}
+		catch (InterruptedException ie)
+		{
+			// should never happen
+			String msg = "internal error in " + getClass();
+			throw new Error(msg, ie);
+		}
+
+        // ok we've woken up! did we wake up because we timed out?
+		if (response == null)
+		{
+            String msg = "request timed out";
+			throw new IOException(msg);
+		}
+
+        // otherwise, let's save the given response and send it while resetting
+		// te state of the connection
+        Response lastResponse = response;
+        this.response = null;
+        return lastResponse;
+	}
+
+	/**
+	 * A special NotificationListener that will allow us to process all
+	 * events sent to this DefaultSocket.
+	 *
+	 * @version $Revision: 1.1 $
+	 */
+	private class LinkNotificationListener implements NotificationListener
+	{
+		public void notificationAction(Notification notification)
+		{
+			// if this getNotification is a response  let's process it
+        	if (Event.isResponse(notification))
+			{
+				try
+				{
+					// obtain the lock on the outer object first!
+					synchronized (DefaultSocket.this)
+					{
+            			response = new Response();
+                        response.parse(notification);
+
+                        // xxx: how do you know if the response received
+                        // --- corresponds to the last request sent? there
+                        // --- must be a way to match up responses to requests!
+
+						// wake up any threads sleeping on this object, waiting
+						// for a response
+						DefaultSocket.this.notify();
+					}
+				}
+				catch (EventException me)
+				{
+                	// bad response data, let's log it and ignore it
+                    String msg = "receieved badly formed response";
+					logger.warn(msg, me);
+				}
+			}
+            else
+            {
+                logger.warn("received notification " + notification
+                            + " which isn't a response");
+            }
+		}
+	}
+}
diff --git a/aether2/core/src/java/aether/net/Link.java b/aether2/core/src/java/aether/net/Link.java
deleted file mode 100644
index f2e7d7d..0000000
--- a/aether2/core/src/java/aether/net/Link.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package aether.net;
-
-import aether.event.Request;
-import aether.event.Response;
-
-import java.io.IOException;
-
-/**
- * A Link represents an established communication channel between a client
- * component and a server component. Once established, clients can send
- * requests over a link and receive responses.
- *
- * @author Buko O. (buko@concedere.net)
- * @version 0.1
- **/
-public interface Link
-{
-    /**
-	 * Connect to the destination of the link.
-	 *
-	 * @throws IOException
-	 *         if the link can't be established
-	 */
-	public void connect() throws IOException;
-
-    /**
-	 * Close the link.
-	 *
-	 * @throws IOException
-	 *         if the link isn't properly closed
-	 */
-	public void close() throws IOException;
-
-	/**
-	 * Get the unique link id.
-	 *
-	 * @return unique id of this link
-	 */
-	public String getLinkId();
-
-	/**
-	 * Get the GUID of the component which sent the most recent response
-	 * over this link. (It's possible for the component generating responses
-	 * to change over the lifetime of the link).
-	 *
-	 * @return GUID of the component that generated the response. This may be
-	 *         <code>null</code> until the first response is received
-	 */
-	public String getDestination();
-
-    /**
-	 * Construct a Request to be sent over this link.
-     *
-     * @return Request that may be sent over this Link
-	 */
-	public Request createRequest();
-
-	/**
-	 * Send a Request over this link.
-	 *
-	 * @param Request Request to send
-	 * @return Response to the given Request
-	 * @throws IOException
-	 *         if something goes wrong
-	 */
-	public Response send(Request Request) throws IOException;
-}
diff --git a/aether2/core/src/java/aether/net/Monitor.java b/aether2/core/src/java/aether/net/Monitor.java
deleted file mode 100644
index eca51bc..0000000
--- a/aether2/core/src/java/aether/net/Monitor.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package aether.net;
-
-import aether.event.EventHandler;
-
-import java.io.IOException;
-
-/**
- * Defines an object capable of monitoring a set of resources in the Aether
- * network.
- *
- * TODO: need a special MonitorListener because listeners should know if a
- * monitor is opening or closing?
- *
- * @author Buko O. (buko@concedere.net)
- * @version 0.1
- **/
-public interface Monitor
-{
-	/**
-	 * Subscribe to a topic in the Aether. Any Notices broadcast to the topic
-	 * will be received.
-	 *
-	 * @param topic topic to subscribe to
-	 * @throws IOException
-	 *         if the subscription fails
-	 */
-	public void subscribe(String topic) throws IOException;
-
-    /**
-	 * Unsubscribe from a topic in the Aether.
-	 *
-	 * @param topic name of the topic
-	 * @throws IOException
-	 *         if the unsubscription fails
-	 */
-	public void unsubscribe(String topic) throws IOException;
-
-	/**
-	 * Get the underlying Connection used by this Monitor to connect
-	 * to the event network.
-	 *
-	 * @return Connection used by this monitor to connect to the network
-	 */
-	public Connection getConnection();
-
-	/**
-	 * Set the underlying Connection used by this Monitor to connect
-	 * to the event network.
-	 *
-	 * @param msgConn Connection to connect to the event network
-	 */
-  	public void setConnection(Connection msgConn);
-
-	/**
-	 * Add a listener to the Monitor. Whenever a Monitor notices an event it'll
-	 * be passed to the given listener.
-	 *
-	 * @param listener listener to handle incoming events
-	 */
-	public void addNoticeListener(EventHandler listener);
-
-	/**
-	 * Remove a listener from the monitor.
-	 *
-	 * @param listener listener to unsubscribe
-	 */
-	public void removeNoticeListener(EventHandler listener);
-
-	/**
-	 * Determine if this Monitor is open.
-	 *
-	 * @return <code>true</code> if this Monitor is open
-	 */
-	public boolean isOpen();
-
-    /**
-	 * Open the Monitor and allocate any necessary resources.
-	 *
-	 * @throws IOException
-	 *         if the monitor fails to open
-	 */
-	public void open() throws IOException;
-
-	/**
-	 * Close the Monitor and ignore all further notices.
-	 *
-	 * @throws IOException
-	 *         if the monitor doesn't close successfully
-	 */
-	public void close() throws IOException;
-}
diff --git a/aether2/core/src/java/aether/net/MulticastSocket.java b/aether2/core/src/java/aether/net/MulticastSocket.java
new file mode 100644
index 0000000..6c9f6ba
--- /dev/null
+++ b/aether2/core/src/java/aether/net/MulticastSocket.java
@@ -0,0 +1,84 @@
+package aether.net;
+
+import aether.event.EventHandler;
+import aether.event.Notice;
+
+import java.io.IOException;
+
+/**
+ * A MulticastSocket provides the means to work with general topics (one-to-many
+ * channels) within the event network. Using a MulticastSocket it's possible to
+ * subscribe to topics and broadcast Notice objects over a topic.
+ *
+ * @author Buko O. (buko@concedere.net)
+ * @version 0.1
+ **/
+public interface MulticastSocket
+{
+	/**
+	 * Subscribe to a topic in the Aether. Any Notices broadcast to the topic
+	 * will be received.
+	 *
+	 * @param topic topic to subscribe to
+	 * @throws IOException
+	 *         if the subscription fails
+	 */
+	public void subscribe(String topic) throws IOException;
+
+    /**
+	 * Unsubscribe from a topic in the Aether.
+	 *
+	 * @param topic name of the topic
+	 * @throws IOException
+	 *         if the unsubscription fails
+	 */
+	public void unsubscribe(String topic) throws IOException;
+
+    /**
+     * Broadcast a Notice over a topic.
+     *
+     * @param notice notice to broadcast
+     * @param topic  topic to broadcast it over
+     * @throws IOException
+     *         if broadcast fails
+     */
+    public void broadcast(Notice notice, String topic) throws IOException;
+
+	/**
+	 * Add a listener to the MulticastSocket. Whenever a MulticastSocket
+     * notices an event it'll be passed to the given listener.
+	 *
+	 * @param listener listener to handle incoming events
+	 */
+	public void addEventHandler(EventHandler listener);
+
+	/**
+	 * Remove a listener from the monitor.
+	 *
+	 * @param listener listener to unsubscribe
+	 */
+	public void removeEventHandler(EventHandler listener);
+
+	/**
+	 * Determine if this MulticastSocket is open.
+	 *
+	 * @return <code>true</code> if this MulticastSocket is open
+	 */
+	public boolean isOpen();
+
+    /**
+	 * Open the MulticastSocket and allocate any necessary resources.
+	 *
+	 * @throws IOException
+	 *         if the monitor fails to open
+	 */
+	public void open() throws IOException;
+
+	/**
+	 * Close the MulticastSocket and ignore all further notices.
+	 *
+	 * @throws IOException
+	 *         if the monitor doesn't close successfully
+	 */
+	public void close() throws IOException;
+}
diff --git a/aether2/core/src/java/aether/net/ServerSocket.java b/aether2/core/src/java/aether/net/ServerSocket.java
new file mode 100644
index 0000000..c2b2a52
--- /dev/null
+++ b/aether2/core/src/java/aether/net/ServerSocket.java
@@ -0,0 +1,71 @@
+package aether.net;
+
+import aether.event.Response;
+import aether.event.Request;
+import aether.event.EventHandler;
+
+import java.io.IOException;
+
+/**
+ * Represents the destination of a socket to which clients may connect.
+ *
+ * Buko O. (aso22@columbia.edu)
+ * @version 0.1
+ **/
+public interface ServerSocket
+{
+    /**
+     * Get the URI that represents this destination.
+     *
+     * @return URI that represents this destination
+     */
+    public String getDestination();
+
+    /**
+     * Get the ID of the component generating the responses.
+     *
+     * @return ID of the component generating the responses
+     */
+    public String getSourceId();
+
+    /**
+     * Set the EventHandler that will be notified of incoming requests.
+     *
+     * @param handler handler to be notified of incoming requests
+     */
+    public void setEventHandler(EventHandler handler);
+
+    /**
+     * Get the EventHandler that's notified of incoming requests.
+     *
+     * @return EventHandler notified of incoming requests
+     */
+    public EventHandler getEventHandler();
+
+    /**
+     * Bind the link destination to being receiving requests.
+     *
+     * @throws IOException
+     *         if something goes wrong
+     */
+    public void bind() throws IOException;
+
+    /**
+     * Unbind the link destination.
+     *
+     * @throws IOException
+     *         if something goes wrong
+     */
+    public void unbind() throws IOException;
+
+    /**
+     * Send a response to an incoming Request.
+     *
+     * @param request  Request that arrived over the link
+     * @param response Response to the request
+     * @throws IOException
+     *         if the response send fails
+     */
+    public void sendResponse(Request request, Response response)
+            throws IOException;
+}
diff --git a/aether2/core/src/java/aether/net/Socket.java b/aether2/core/src/java/aether/net/Socket.java
new file mode 100644
index 0000000..780ea35
--- /dev/null
+++ b/aether2/core/src/java/aether/net/Socket.java
@@ -0,0 +1,87 @@
+package aether.net;
+
+import aether.event.Request;
+import aether.event.Response;
+
+import java.io.IOException;
+
+/**
+ * A Socket represents a stateful, synchronous communication channel between
+ * two components.
+ *
+ * @author Buko O. (buko@concedere.net)
+ * @version 0.1
+ **/
+public interface Socket
+{
+    /**
+     * Default timeout value of 30 seconds.
+     */
+    public static final long DEFAULT_TIMEOUT = 1000 * 30;
+
+    /**
+	 * Connect to the destination of the link.
+	 *
+	 * @throws IOException
+	 *         if the link can't be established
+	 */
+	public void connect() throws IOException;
+
+    /**
+	 * Close the link.
+	 *
+	 * @throws IOException
+	 *         if the link isn't properly closed
+	 */
+	public void disconnect() throws IOException;
+
+    /**
+     * Determine if the link is currently connected.
+     *
+     * @return <code>true</code> if the link is currently connected else
+     *         <code>false</code>
+     */
+    public boolean isConnected();
+
+	/**
+	 * Get the unique link id.
+	 *
+	 * @return unique id of this link
+	 */
+	public String getLinkId();
+
+	/**
+	 * Get the GUID of the component which sent the most recent response
+	 * over this link. (It's possible for the component generating responses
+	 * to change over the lifetime of the link).
+	 *
+	 * @return GUID of the component that generated the response. This may be
+	 *         <code>null</code> until the first response is received
+	 */
+	public String getDestination();
+
+    /**
+     * Set the max number of milliseconds that the <code>send</code> method
+     * may block while waiting for a response.
+     *
+     * @param timeout timeout to wait for a response
+     */
+    public void setTimeOut(long timeout);
+
+    /**
+     * Get the timeout time.
+     *
+     * @return timeout time
+     */
+    public long getTimeOut();
+
+	/**
+	 * Send a Request over this link.
+	 *
+	 * @param Request Request to send
+	 * @return Response to the given Request
+	 * @throws IOException
+	 *         if something goes wrong
+	 */
+	public Response send(Request Request) throws IOException;
+}
diff --git a/aether2/core/src/test/aether/net/DefaultLinkTest.java b/aether2/core/src/test/aether/net/DefaultLinkTest.java
index 50245d7..da33623 100644
--- a/aether2/core/src/test/aether/net/DefaultLinkTest.java
+++ b/aether2/core/src/test/aether/net/DefaultLinkTest.java
@@ -26,7 +26,7 @@ public class DefaultLinkTest extends AetherTestCase

 	public void testLink() throws Exception
 	{
-		Link link = new DefaultLink(getElvinHost(), getElvinPort(), "0");
+		Socket link = new DefaultSocket(getElvinHost(), getElvinPort(), "0");
         link.connect();

 		Request req = link.createRequest(Request.Get);
diff --git a/aether2/core/src/test/aether/net/DefaultMonitorTest.java b/aether2/core/src/test/aether/net/DefaultMonitorTest.java
index 1334eba..dda81e7 100644
--- a/aether2/core/src/test/aether/net/DefaultMonitorTest.java
+++ b/aether2/core/src/test/aether/net/DefaultMonitorTest.java
@@ -10,7 +10,7 @@ import aether.event.*;
  **/
 public class DefaultMonitorTest extends AetherTestCase
 {
-    private DefaultMonitor monitor;
+    private DefaultMulticastSocket monitor;
 	private EventQueue listQueue;
 	private EventHandler handler;

@@ -26,8 +26,8 @@ public class DefaultMonitorTest extends AetherTestCase
 			}
 		};

-		monitor = new DefaultMonitor(elvinHost, elvinPort);
-		monitor.addNoticeListener(handler);
+		monitor = new DefaultMulticastSocket(elvinHost, elvinPort);
+		monitor.addEventHandler(handler);
 		monitor.open();
 	}

@@ -68,10 +68,10 @@ public class DefaultMonitorTest extends AetherTestCase

 	public void testSubscribe() throws Exception
 	{
-   		Monitor mon = new DefaultMonitor(getElvinHost(), getElvinPort());
+   		MulticastSocket mon = new DefaultMulticastSocket(getElvinHost(), getElvinPort());
         mon.open();
 		final EventQueue queue = new SimpleEventQueue();
-		mon.addNoticeListener(new EventHandler()
+		mon.addEventHandler(new EventHandler()
 		{
 			public void handle(Event msg)
 			{
diff --git a/aether2/hercules/doc/todo.txt b/aether2/hercules/doc/todo.txt
index c0b9583..865fd3f 100644
--- a/aether2/hercules/doc/todo.txt
+++ b/aether2/hercules/doc/todo.txt
@@ -1,6 +1,8 @@

 [ 10.27.03 ]

+- Change the SwitchBoard framework to use the new LinkDestination classes
+
 - Fix up DomainAgent class. A DomainAgent shouldn't need to know its own GUID
 in order to broadcast notices. Instead, introduce another class, Broadcaster,
 which contains the GUID of the source and the topic to broadcast on. Then
diff --git a/aether2/hercules/hercules.iws b/aether2/hercules/hercules.iws
index 87446f1..b7d4aa9 100644
--- a/aether2/hercules/hercules.iws
+++ b/aether2/hercules/hercules.iws
@@ -10,30 +10,23 @@
       <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/responder/SwitchBoardListener.java" line="17" column="36" vertical-scroll-proportion="0.4512195" horizontal-scroll-proportion="0.34903046" />
       <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/responder/SwitchBoardEvent.java" line="10" column="13" vertical-scroll-proportion="-1.304878" horizontal-scroll-proportion="0.12603877" />
       <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/responder/RuntimeResponderException.java" line="9" column="13" vertical-scroll-proportion="0.101045296" horizontal-scroll-proportion="0.12603877" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/responder/Responder.java" line="32" column="34" vertical-scroll-proportion="0.6707317" horizontal-scroll-proportion="0.32963988">
-        <folding>
-          <element signature="imports" expanded="true" />
-        </folding>
-      </source-position-entry>
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/responder/Responder.java" line="32" column="34" vertical-scroll-proportion="0.6707317" horizontal-scroll-proportion="0.32963988" />
       <source-position-entry url="file://$PROJECT_DIR$/.cvsignore" line="0" column="0" vertical-scroll-proportion="0.0" horizontal-scroll-proportion="0.0" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/responder/DefaultSwitchBoard.java" line="1" column="39" vertical-scroll-proportion="0.036585364" horizontal-scroll-proportion="0.37811634">
-        <folding>
-          <element signature="imports" expanded="true" />
-        </folding>
-      </source-position-entry>
       <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/responder/SwitchBoard.java" line="11" column="17" vertical-scroll-proportion="-0.79268295" horizontal-scroll-proportion="0.16481994" />
       <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/framework/Advertising.java" line="11" column="17" vertical-scroll-proportion="0.33275262" horizontal-scroll-proportion="0.16481994" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/domain/DomainAgent.java" line="185" column="8" vertical-scroll-proportion="-3.7526133" horizontal-scroll-proportion="0.077562325" />
-      <source-position-entry url="file://$PROJECT_DIR$/doc/todo.txt" line="35" column="28" vertical-scroll-proportion="0.8902439" horizontal-scroll-proportion="0.27146813" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/domain/DomainAgent.java" line="131" column="19" vertical-scroll-proportion="0.12195122" horizontal-scroll-proportion="0.18421052" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/responder/DefaultSwitchBoard.java" line="349" column="98" vertical-scroll-proportion="0.33275262" horizontal-scroll-proportion="0.9501385" />
+      <source-position-entry url="file://$PROJECT_DIR$/doc/todo.txt" line="3" column="73" vertical-scroll-proportion="0.1097561" horizontal-scroll-proportion="0.7077562" />
     </history>
     <open-files>
       <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/framework/Advertising.java" line="11" column="17" vertical-scroll-proportion="0.33275262" horizontal-scroll-proportion="0.16481994" />
-      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/domain/DomainAgent.java" line="185" column="8" vertical-scroll-proportion="-3.7526133" horizontal-scroll-proportion="0.077562325" />
-      <source-position-entry url="file://$PROJECT_DIR$/doc/todo.txt" line="35" column="28" vertical-scroll-proportion="0.8902439" horizontal-scroll-proportion="0.27146813" selected="true" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/domain/DomainAgent.java" line="131" column="19" vertical-scroll-proportion="0.12195122" horizontal-scroll-proportion="0.18421052" />
+      <source-position-entry url="file://$PROJECT_DIR$/src/java/aether/server/responder/DefaultSwitchBoard.java" line="349" column="98" vertical-scroll-proportion="0.33275262" horizontal-scroll-proportion="0.9501385" />
+      <source-position-entry url="file://$PROJECT_DIR$/doc/todo.txt" line="3" column="73" vertical-scroll-proportion="0.1097561" horizontal-scroll-proportion="0.7077562" selected="true" />
     </open-files>
   </component>
   <component name="ToolWindowManager">
-    <frame x="155" y="9" width="835" height="719" extended-state="0" />
+    <frame x="126" y="11" width="835" height="719" extended-state="0" />
     <editor active="true" />
     <layout>
       <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="docked" type="docked" visible="false" weight="0.25" order="1" />
@@ -255,14 +248,17 @@
   <component name="ProjectViewSettings">
     <navigator currentView="ProjectPane" flattenPackages="false" showMembers="false" showStructure="false" autoscrollToSource="false" splitterProportion="0.5" />
     <view id="ProjectPane">
-      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java" />
-      <expanded_node type="directory" url="file://$PROJECT_DIR$/doc" />
-      <expanded_node type="directory" url="file://$PROJECT_DIR$" />
       <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/memento/world/model" />
-      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/memento" />
+      <expanded_node type="directory" url="file://$PROJECT_DIR$/doc" />
+      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/aether" />
       <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/memento/world" />
-      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/memento/world/manager" />
+      <expanded_node type="directory" url="file://$PROJECT_DIR$" />
       <expanded_node type="directory" url="file://$PROJECT_DIR$/src" />
+      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/memento/world/manager" />
+      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/aether/server/responder" />
+      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/aether/server" />
+      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java" />
+      <expanded_node type="directory" url="file://$PROJECT_DIR$/src/java/memento" />
     </view>
     <view id="SourcepathPane" />
     <view id="ClasspathPane" />
diff --git a/aether2/hercules/src/java/aether/server/domain/DomainAgent.java b/aether2/hercules/src/java/aether/server/domain/DomainAgent.java
index b429ab5..b4e53d7 100644
--- a/aether2/hercules/src/java/aether/server/domain/DomainAgent.java
+++ b/aether2/hercules/src/java/aether/server/domain/DomainAgent.java
@@ -15,10 +15,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.io.*;

-import aether.net.Publisher;
-import aether.net.Monitor;
-import aether.net.Connection;
-import aether.net.DefaultMonitor;
+import aether.net.*;
 import aether.server.framework.Advertising;
 import aether.server.framework.Identifiable;
 import aether.event.Notice;
@@ -39,72 +36,76 @@ public class DomainAgent extends BeanContextChildSupport
 {
 	private BeanContextMembershipListener bcml;
 	private EventHandler handler;
-	private String domainTopic;

+    private Broadcaster broadcaster;
 	private Monitor monitor;
-	private Connection connection;
+
 	private DomainInfo domainInfo;
 	private Map compMap = Collections.synchronizedMap(new HashMap());
 	private Map remoteMap = Collections.synchronizedMap(new HashMap());
-	private String guid;

 	private static final Logger log = Logger.getLogger(DomainAgent.class);

     /**
-     * Set the Connection to be used by the DomainAgent.
+     * Set the Monitor this DomainAgent may use to monitor component
+     * registrations on the network.
+     * <p />
+     * Note that this Monitor should already be open and subscribed to the
+     * domain topic.
      *
-     * @param conn Connection used to send events
+     * @param monitor monitor used to receive events from the domain topic
      */
-    public void setConnection(Connection conn)
+    public void setMonitor(Monitor monitor)
     {
-        if (conn == null)
+        if (monitor == null)
+        {
+            String msg = "monitor can't be null";
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (!monitor.isOpen())
         {
-            String msg = "conn can't be null";
+            String msg = "monitor must be open";
             throw new IllegalArgumentException(msg);
         }

-        this.connection = conn;
+        this.monitor = monitor;
     }

     /**
-     * Get the Connection to be used by the DomainAgent.
+     * Get the Monitor used to receive events from the domain topic.
      *
-     * @return Connection used to send/receive events.
+     * @return Monitor used to receive events from the domain topic
      */
-    public Connection getConnection()
+    public Monitor getMonitor()
     {
-        return connection;
+        return monitor;
     }

     /**
-	 * Get the domain topic on which domain notices are exchanged.
-	 *
-	 * @return domain topic on which domain notices are exchanged
-	 */
-	public String getDomainTopic()
-	{
-		return domainTopic;
-	}
+     * Set the Broadcaster used to announce new
+     * @param bcast
+     */
+    public void setBroadcaster(Broadcaster bcast)
+    {
+        if (bcast == null)
+        {
+            String msg = "bcast can't be null";
+            throw new IllegalArgumentException(msg);
+        }

-	/**
-	 * Set the domain topic on which domain notices are exchanged.
-	 *
-	 * @param domainTopic domain topic on which domain notices are exchanged
-	 */
-	public void setDomainTopic(String domainTopic)
-	{
-		this.domainTopic = domainTopic;
-	}
+        this.broadcaster = bcast;
+    }

-	/**
-	 * Get the info for the domain this agent is acting for.
-	 *
-	 * @return info for the domain this agent is acting for
-	 */
-	public DomainInfo getDomainInfo()
-	{
-		return domainInfo;
-	}
+    /**
+     * Get the Broadcaster used to announce component registrations.
+     *
+     * @return Broadcaster used to announce component registrations
+     */
+    public Broadcaster getBroadcaster()
+    {
+        return broadcaster;
+    }

 	/**
 	 * Set the info for the domain this agent will act for.
@@ -113,38 +114,39 @@ public class DomainAgent extends BeanContextChildSupport
 	 */
 	public void setDomainInfo(DomainInfo domainInfo)
 	{
+        if (domainInfo == null)
+        {
+            String msg = "domainInfo can't be null";
+            throw new IllegalArgumentException(msg);
+        }
 		this.domainInfo = domainInfo;
 	}

-	public void initialize() throws IOException
-	{
-        connection.open();
-		monitor = new DefaultMonitor(connection, false);
-        monitor.subscribe(getDomainTopic());
+    /**
+     * Get the DomainInfo for the Domain being managed.
+     *
+     * @return DomainInfo for domain being managed
+     */
+    public DomainInfo getDomainInfo()
+    {
+        return domainInfo;
+    }

+	public void initialize()
+	{
 		bcml = new DomainListener();
 		getBeanContext().addBeanContextMembershipListener(bcml);

 		handler = new DomainHandler();
-
-	    monitor.subscribe(getDomainTopic());
 		monitor.addNoticeListener(handler);
 	}

 	public void dispose()
 	{
-		try
-		{
-			monitor.removeNoticeListener(handler);
-			monitor.unsubscribe(this.getDomainTopic());
-			handler = null;
-		}
-		catch (IOException ioe)
-		{
-			log.warn("failed to unsubscribe from domain topic");
-		}
-
+	    monitor.removeNoticeListener(handler);
+		handler = null;
 		getBeanContext().removeBeanContextMembershipListener(bcml);
+        bcml = null;
 	}

 	private ComponentInfo createComponentInfo(Identifiable idf)
diff --git a/aether2/lib/aether-core-0.1.jar b/aether2/lib/aether-core-0.1.jar
index 593f4cc..ab36a15 100644
Binary files a/aether2/lib/aether-core-0.1.jar and b/aether2/lib/aether-core-0.1.jar differ