8afd0316ec
required some serious bending and folding of the generic type system, but for the most part we managed to avoid any mutilating. The gendobj task now generates properly typed "addToXXX" and "updateXXX" DSet methods based on the parameterized type of the DSet. This might cause unrecompiled code to break, but I don't think there are many cases in the base toolkit where people call DSet adders or updaters. We'll see and I'll add backwards compatibility versions for cases where we need them to support GG games (everything else we can just recompile). git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4245 542714f4-19e9-0310-aa3c-eee0fc999fb1
204 lines
6.6 KiB
Java
204 lines
6.6 KiB
Java
//
|
|
// $Id$
|
|
//
|
|
// Narya library - tools for developing networked games
|
|
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
|
// http://www.threerings.net/code/narya/
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License as published
|
|
// by the Free Software Foundation; either version 2.1 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
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser 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 com.threerings.presents.server;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import com.samskivert.util.Invoker;
|
|
import com.threerings.util.Name;
|
|
|
|
import com.threerings.presents.Log;
|
|
import com.threerings.presents.data.ClientObject;
|
|
import com.threerings.presents.dobj.DObject;
|
|
import com.threerings.presents.dobj.ObjectAccessException;
|
|
import com.threerings.presents.dobj.Subscriber;
|
|
|
|
/**
|
|
* Used to resolve client data when a user starts a session (or when some
|
|
* other entity needs access to a client object). Implementations will
|
|
* want to extend this class and override {@link #resolveClientData},
|
|
* making the necessary database calls and populating the client object
|
|
* appropriately.
|
|
*/
|
|
public class ClientResolver extends Invoker.Unit
|
|
implements Subscriber<ClientObject>
|
|
{
|
|
/**
|
|
* Initiailizes this instance.
|
|
*
|
|
* @param username the username of the user to be resolved.
|
|
*/
|
|
public void init (Name username)
|
|
{
|
|
_username = username;
|
|
}
|
|
|
|
/**
|
|
* Adds a resolution listener to this active resolver.
|
|
*/
|
|
public void addResolutionListener (ClientResolutionListener listener)
|
|
{
|
|
_listeners.add(listener);
|
|
}
|
|
|
|
/**
|
|
* Returns the {@link ClientObject} derived class that should be
|
|
* created to kick off the resolution process.
|
|
*/
|
|
public Class<? extends ClientObject> getClientObjectClass ()
|
|
{
|
|
return ClientObject.class;
|
|
}
|
|
|
|
// documentation inherited
|
|
public void objectAvailable (ClientObject object)
|
|
{
|
|
// we've got our object, so shunt ourselves over to the invoker
|
|
// thread to perform database loading
|
|
_clobj = object;
|
|
PresentsServer.invoker.postUnit(this);
|
|
|
|
// we no longer need to be a subscriber of the object now that it
|
|
// has been created
|
|
_clobj.removeSubscriber(this);
|
|
}
|
|
|
|
// documentation inherited
|
|
public void requestFailed (int oid, ObjectAccessException cause)
|
|
{
|
|
// pass the buck
|
|
reportFailure(cause);
|
|
}
|
|
|
|
// documentation inherited
|
|
public boolean invoke ()
|
|
{
|
|
try {
|
|
// allow our derived class to do its database loads
|
|
resolveClientData(_clobj);
|
|
} catch (Exception cause) {
|
|
// keep this around until we're back on the dobj thread
|
|
_failure = cause;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// documentation inherited
|
|
public void handleResult ()
|
|
{
|
|
// if we haven't failed, finish resolution on the dobj thread
|
|
if (_failure == null) {
|
|
try {
|
|
finishResolution(_clobj);
|
|
} catch (Exception e) {
|
|
_failure = e;
|
|
}
|
|
}
|
|
|
|
// if we still haven't failed, then we're good to go
|
|
if (_failure == null) {
|
|
// and let the listeners in on the secret as well
|
|
for (int ii = 0, ll = _listeners.size(); ii < ll; ii++) {
|
|
ClientResolutionListener crl = _listeners.get(ii);
|
|
try {
|
|
// add a reference for each listener
|
|
_clobj.reference();
|
|
crl.clientResolved(_username, _clobj);
|
|
} catch (Exception e) {
|
|
Log.warning("Client resolution listener choked during " +
|
|
"resolution notification [crl=" + crl +
|
|
", clobj=" + _clobj + "].");
|
|
Log.logStackTrace(e);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// destroy the dangling user object
|
|
PresentsServer.omgr.destroyObject(_clobj.getOid());
|
|
|
|
// let our listener know that we're hosed
|
|
reportFailure(_failure);
|
|
}
|
|
}
|
|
|
|
// documentation inherited
|
|
public String toString ()
|
|
{
|
|
return "ClientResolver:" + _username;
|
|
}
|
|
|
|
/**
|
|
* This method is called on the invoker thread which means that it can
|
|
* do things like blocking database requests and generally whatever is
|
|
* necessary to load up all the client data that is desired by the
|
|
* implentation system. Any exceptions that are thrown will be caught
|
|
* and reported as a failure to the client resolution listener.
|
|
*/
|
|
protected void resolveClientData (ClientObject clobj)
|
|
throws Exception
|
|
{
|
|
// nothing to do by default
|
|
}
|
|
|
|
/**
|
|
* This method is called on the dobj thread after resolveClientData
|
|
* returns normally, it should finish populating the client object
|
|
* with any data that is NOT loaded from a database.
|
|
*/
|
|
protected void finishResolution (ClientObject clobj)
|
|
{
|
|
// nothing to do by default
|
|
}
|
|
|
|
/**
|
|
* Reports failure to our resolution listeners.
|
|
*/
|
|
protected void reportFailure (Exception cause)
|
|
{
|
|
for (int ii = 0, ll = _listeners.size(); ii < ll; ii++) {
|
|
ClientResolutionListener crl = _listeners.get(ii);
|
|
try {
|
|
crl.resolutionFailed(_username, cause);
|
|
} catch (Exception e) {
|
|
Log.warning("Client resolution listener choked during " +
|
|
"failure notification [crl=" + crl +
|
|
", username=" + _username +
|
|
", cause=" + cause + "].");
|
|
Log.logStackTrace(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** The name of the user whose client object is being resolved. */
|
|
protected Name _username;
|
|
|
|
/** The entities to notify of success or failure. */
|
|
protected ArrayList<ClientResolutionListener> _listeners =
|
|
new ArrayList<ClientResolutionListener>();
|
|
|
|
/** The resolving client object. */
|
|
protected ClientObject _clobj;
|
|
|
|
/** A place to keep an exception around for a moment. */
|
|
protected Exception _failure;
|
|
}
|