Bureaucracy review updates and hello world test

* Fleshed out client-side Agent class, made abstract
* Delegate the creation of the bureau director to subclasses of BureauClient
* Moved BureauDirector's BureauReceiver and Subscriber implementations to 
  anonymous classes that delegate to protected methods.
* Use SafeSubscriber
* Added new service method for notiyfing the server when the creation of an
  agent fails so that the registry is not perpetually waiting
* Made BureauCredentials more conformant
* Made BureauRegistry respond properly to client logging off
* Got rid of superfluous uses of safeToString
* Changed Launcher to CommandGenerator and now use ProcessBuilder and 
  copyMergedOutput
* Changed bureau process parameters to server name and port instead of URL


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5030 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Jamie Doornbos
2008-04-29 18:34:51 +00:00
parent 938d7f5994
commit f41233c5ac
12 changed files with 558 additions and 128 deletions
@@ -3,81 +3,31 @@ package com.threerings.bureau.client;
import com.threerings.presents.client.BasicDirector;
import com.threerings.presents.data.ClientObject;
import com.threerings.bureau.data.BureauCodes;
import com.samskivert.util.HashIntMap;
import com.samskivert.util.IntMap;
import com.samskivert.util.IntMaps;
import com.threerings.bureau.data.AgentObject;
import com.threerings.bureau.Log;
import com.threerings.bureau.util.BureauContext;
import com.threerings.presents.client.Client;
import com.threerings.presents.dobj.Subscriber;
import com.threerings.presents.util.SafeSubscriber;
import com.threerings.presents.dobj.ObjectAccessException;
/**
* Allows the server to create and destroy agents on a client.
* @see BureauRegistry
*/
public class BureauDirector extends BasicDirector
implements BureauReceiver, Subscriber<AgentObject>
public abstract class BureauDirector extends BasicDirector
{
/**
* Creates a new BureauDirector.
*/
public BureauDirector (BureauContext ctx)
{
super(ctx);
_ctx = ctx;
}
// from BureauReceiver
public synchronized void createAgent (int agentId)
{
_ctx.getDObjectManager().subscribeToObject(agentId, this);
}
// from BureauReceiver
public synchronized void destroyAgent (int agentId)
{
Agent agent = null;
try {
agent = _agents.remove(agentId);
// TODO: stop the agent somehow
}
catch (Throwable t) {
Log.warning("Could not create agent [id=" + agentId + "]");
Log.logStackTrace(t);
// TODO: failure notification?
return;
}
_ctx.getDObjectManager().unsubscribeFromObject(agentId, this);
doStopAgent(agent);
_bureauService.agentDestroyed(_ctx.getClient(), agentId);
}
// from Subscriber
public synchronized void objectAvailable (AgentObject agentObject)
{
int oid = agentObject.getOid();
try {
Agent agent = new Agent();
agent.agentObject = agentObject;
doStartAgent(agent);
_agents.put(oid, agent);
}
catch (Exception e) {
Log.warning("Could not create agent [obj=" + agentObject + "]");
Log.logStackTrace(e);
// TODO: failure notification?
return;
}
// TODO: post to runqueue?
_bureauService.agentCreated(_ctx.getClient(), oid);
}
// from Subscriber
public synchronized void requestFailed (int oid, ObjectAccessException cause)
{
Log.warning("Could not subscribe to agent [oid=" + oid + "]");
Log.logStackTrace(cause);
}
@Override // from BasicDirector
public void clientDidLogon (Client client)
{
@@ -85,6 +35,79 @@ public class BureauDirector extends BasicDirector
_bureauService.bureauInitialized(_ctx.getClient(), _ctx.getBureauId());
}
/**
* Creates a new agent when the server requests it.
*/
protected synchronized void createAgent (int agentId)
{
Subscriber<AgentObject> delegator = new Subscriber<AgentObject>() {
public void objectAvailable (AgentObject agentObject) {
BureauDirector.this.objectAvailable(agentObject);
}
public void requestFailed (int oid, ObjectAccessException cause) {
BureauDirector.this.requestFailed(oid, cause);
}
};
_subscriber = new SafeSubscriber<AgentObject>(agentId, delegator);
_subscriber.subscribe(_ctx.getDObjectManager());
}
/**
* Destroys an agent at the server's request.
*/
protected synchronized void destroyAgent (int agentId)
{
Agent agent = null;
agent = _agents.remove(agentId);
if (agent == null) {
}
else {
try {
agent.stop();
}
catch (Throwable t) {
Log.warning("Stopping an agent caused an exception");
Log.logStackTrace(t);
}
_subscriber.unsubscribe(_ctx.getDObjectManager());
_bureauService.agentDestroyed(_ctx.getClient(), agentId);
}
}
/**
* Callback for when the a request to subscribe to an object finishes and the object is available.
*/
protected synchronized void objectAvailable (AgentObject agentObject)
{
int oid = agentObject.getOid();
Agent agent;
try {
agent = createAgent(agentObject);
agent.init(agentObject);
agent.start();
}
catch (Throwable t) {
Log.warning("Could not create agent [obj=" + agentObject + "]");
Log.logStackTrace(t);
_bureauService.agentCreationFailed(_ctx.getClient(), oid);
return;
}
_agents.put(oid, agent);
_bureauService.agentCreated(_ctx.getClient(), oid);
}
/**
* Callback for when the a request to subscribe to an object fails.
*/
protected synchronized void requestFailed (int oid, ObjectAccessException cause)
{
Log.warning("Could not subscribe to agent [oid=" + oid + "]");
Log.logStackTrace(cause);
}
@Override // from BasicDirector
protected void registerServices (Client client)
{
@@ -95,8 +118,17 @@ public class BureauDirector extends BasicDirector
// Set up our decoder so we can receive method calls
// from the server
BureauReceiver receiver = new BureauReceiver () {
public void createAgent (int agentId) {
BureauDirector.this.createAgent(agentId);
}
public void destroyAgent (int agentId) {
BureauDirector.this.destroyAgent(agentId);
}
};
client.getInvocationDirector().
registerReceiver(new BureauDecoder(this));
registerReceiver(new BureauDecoder(receiver));
}
@Override // from BasicDirector
@@ -108,21 +140,16 @@ public class BureauDirector extends BasicDirector
}
/**
* Called when the agent object is ready and it is time to run his code.
* Called when it is time to create an Agent. Subclasses should read the
* <code>agentObject</code>'s type and/or properties to determine what kind of Agent to
* create.
* @param agentObj the distributed and object
* @return a new Agent that will govern the distributed object
*/
protected void doStartAgent (Agent agent)
{
}
/**
* Called when the agent object is being destroyed and the client code should stop
* processing.
*/
protected void doStopAgent (Agent agent)
{
}
protected abstract Agent createAgent (AgentObject agentObj);
protected BureauContext _ctx;
protected BureauService _bureauService;
protected HashIntMap<Agent> _agents = new HashIntMap<Agent>();
protected IntMap<Agent> _agents = IntMaps.newHashIntMap();
protected SafeSubscriber<AgentObject> _subscriber;
}